diff -uNr --exclude=CVS linux-2.4.8-ac9/Documentation/Configure.help linuxppc64_2_4/Documentation/Configure.help
--- linux-2.4.8-ac9/Documentation/Configure.help Thu Aug 23 09:17:13 2001
+++ linuxppc64_2_4/Documentation/Configure.help Thu Aug 23 10:25:17 2001
@@ -179,6 +179,14 @@
from Motorola. The Linux PowerPC port has a home page at
.
+PowerPC64 processor
+CONFIG_PPC64
+ The PowerPC architecture was designed for both 32 bit and 64 bit
+ processor implementations. 64 bit PowerPC processors are in many
+ ways a superset of their 32 bit PowerPC cousins. Each 64 bit PowerPC
+ processor also has a 32 bit mode to allow for 32 bit compatibility.
+ The home of the PowerPC 64 Linux project is at
+
Motorola 68K processors
CONFIG_M68K
The Motorola 68K microprocessors are now obsolete, having been
@@ -19876,30 +19884,70 @@
machines: Apple Power Macintoshes and clones (such as the Motorola
Starmax series), PReP (PowerPC Reference Platform) machines such as
the Motorola PowerStack, CHRP (Common Hardware Reference Platform),
- the embedded MBX boards from Motorola and many others. Currently,
+ the embedded MBX boards from Motorola and many others. Currently,
the default option is to build a kernel which works on the first
three. Support for other machines is currently incomplete.
Select PowerMac/PReP/MTX/CHRP if configuring for any of the above.
Select Gemini if configuring for a Synergy Microsystems' Gemini
- series Single Board Computer. More information is available at:
- .
+ series Single Board Computer. More information is available at:
+
+
+ Select APUS if configuring for a PowerUP Amiga. More information is
+ available at:
+
+# Choice: i or p
+Platform support
+CONFIG_PPC_ISERIES
+ Linux runs on certain models of the IBM AS/400, now known as the
+ IBM iSeries. Generally if you can run LPAR (Logical Partitioning)
+ on your iSeries you can run Linux in a partition on your machine.
+
+ Linux also runs on most models of IBM pSeries hardware. (pSeries
+ used to be known as the RS/6000)
+
+ If you have an iSeries and want to run Linux in a partition,
+ select the iSeries option to build your kernel.
+
+ If you have a pSeries and want to run Linux, select pSeries
+ as the option to build your kernel.
+
+ See for exact model information to see what
+ can run the 64 bit PowerPC kernel.
- Select APUS if configuring for a PowerUP Amiga. More information is
- available at: .
+ iSeries Linux information from IBM can be found at:
+
+
+ pSeries Linux information from IBM can be found at:
+
+
+ Project information can be found at:
+
+
+
+Platform support
+CONFIG_PPC_PSERIES
+ Linux runs on most models of IBM pSeries hardware. (pSeries used
+ to be known as the RS/6000)
+
+ See for exact model information for the
+ 64 bit PowerPC kernel.
+
+ pSeries Linux information from IBM can be found at:
+
Synergy-Gemini
CONFIG_GEMINI
Select Gemini if configuring for a Synergy Microsystems' Gemini
series Single Board Computer. More information is available at:
- .
+
Amiga-Apus
CONFIG_APUS
Select APUS if configuring for a PowerUP Amiga.
More information is available at:
- .
+
Power management support for PowerBooks
CONFIG_PMAC_PBOOK
@@ -20095,26 +20143,33 @@
Support for EST8260
CONFIG_EST8260
The EST8260 is a single-board computer manufactured by Wind River
- Systems, Inc. (formerly Embedded Support Tools Corp.) and based on
- the MPC8260. Wind River Systems has a website at
- , but the EST8260 cannot be found on it
+ Systems Inc. (formerly Embedded Support Tools Corp.) and based
+ on the MPC8260. Wind River Systems has a website at
+ , but the EST8260 cannot be found on it
and has probably been discontinued or rebadged.
+Support for Large Memory
+CONFIG_MSCHUNKS
+ MsChunks stands for Main Store Chunks and specifically allows the
+ 64 bit PowerPC Linux kernel to optimize for machines with sparce
+ discontiguous memory. iSeries kernels need to have this on.
+ It is recommended that for pSeries hardware that you answer Y.
+
AltiVec support
CONFIG_ALTIVEC
Say Y here to compile in support for Motorola AltiVec boards. The
- AltiVec board is baced on the MPC7400 embedded version of the
- PowerPC and adds a SIMD vector-processing unit. Product information
+ AltiVec board is baced on the MPC7400 embedded version of the
+ PowerPC and adds a SIMD vector-processing unit. Product information
at .
ADB raw keycode support
CONFIG_MAC_ADBKEYCODES
This provides support for sending raw ADB keycodes to console
devices. This is the default up to 2.4.0, but in future this may be
- phased out in favor of generic Linux keycodes. If you say Y here,
+ phased out in favor of generic Linux keycodes. If you say Y here,
you can dynamically switch via the
/proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
- sysctl and with the "keyboard_sends_linux_keycodes=" kernel
+ sysctl and with the "keyboard_sends_linux_keycodes=" kernel
argument.
If unsure, say Y here.
@@ -20122,8 +20177,8 @@
Mouse button 2+3 emulation support
CONFIG_MAC_EMUMOUSEBTN
This provides generic support for emulating the 2nd and 3rd mouse
- button with keypresses. If you say Y here, the emulation is still
- disabled by default. The emulation is controlled by these sysctl
+ button with keypresses. If you say Y here, the emulation is still
+ disabled by default. The emulation is controlled by these sysctl
entries:
/proc/sys/dev/mac_hid/mouse_button_emulation
/proc/sys/dev/mac_hid/mouse_button2_keycode
@@ -22836,6 +22891,11 @@
CONFIG_XMON
Include in-kernel hooks for the xmon kernel monitor/debugger
supported by the PPC port.
+
+Include realtime debugging
+CONFIG_PPCDBG
+ Include in-kernel PowerPC 64 information hooks that may be turned on/off
+ in real time.
Include kgdb kernel debugger
CONFIG_KWDB
diff -uNr --exclude=CVS linux-2.4.8-ac9/MAINTAINERS linuxppc64_2_4/MAINTAINERS
--- linux-2.4.8-ac9/MAINTAINERS Thu Aug 23 09:17:14 2001
+++ linuxppc64_2_4/MAINTAINERS Thu Aug 23 10:25:17 2001
@@ -863,14 +863,10 @@
S: Maintained
LINUX FOR 64BIT POWERPC
-P: Tom Gall
-M: tom_gall@vnet.ibm.com
P: David Engebretsen
M: engebret@us.ibm.com
-P: Dwayne McConnell
-M: dwayne@austin.ibm.com
W: http://linuxppc64.org
-L: linuxppc64-dev@lists.linuxppc.porg
+L: linuxppc64-dev@lists.linuxppc.org
S: Supported
LOGICAL VOLUME MANAGER
diff -uNr --exclude=CVS linux-2.4.8-ac9/Makefile linuxppc64_2_4/Makefile
--- linux-2.4.8-ac9/Makefile Thu Aug 23 09:17:14 2001
+++ linuxppc64_2_4/Makefile Thu Aug 23 10:25:17 2001
@@ -10,11 +10,13 @@
# SUBARCH tells the usermode build what the underlying arch is. That is set
# first, and if a usermode build is happening, the "ARCH=um" on the command
# line overrides the setting of ARCH below. If a native build is happening,
-# then ARCH is assigned, getting whatever value it gets normally, and
+# then ARCH is assigned, getting whatever value it gets normally, and
# SUBARCH is subsequently ignored.
SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
-ARCH := $(SUBARCH)
+#ARCH := $(SUBARCH)
+
+ARCH := ppc64
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
@@ -27,7 +29,7 @@
HOSTCC = gcc
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
-CROSS_COMPILE =
+CROSS_COMPILE = /usr/local/ppc64-current3.0/bin/powerpc64-linux-
#
# Include the make variables (CC, etc...)
@@ -97,7 +99,7 @@
CPPFLAGS := -D__KERNEL__ -I$(HPATH)
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
- -fomit-frame-pointer -fno-strict-aliasing -fno-common
+ -fomit-frame-pointer -fno-strict-aliasing -fno-common
AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
#
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/Makefile linuxppc64_2_4/arch/ppc64/Makefile
--- linux-2.4.8-ac9/arch/ppc64/Makefile Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/Makefile Thu Aug 23 16:45:14 2001
@@ -19,13 +19,19 @@
CHECKS = checks
endif
+# Re: -DPPC64_32B_ADDR_SPACE in CPPLAGS/CFLAGS below.
+# For 64-bit apps, temporarily reduce the size of the address space
+# available to user application. This allow us to use strace without
+# having to compile a strace64 program. This shouldn't affect anyone
+# other than Steve Munroe, Peter Bergner. I will back this hack out
+# later... -Peter
+
ASFLAGS =
LINKFLAGS = -T arch/ppc64/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
-CPPFLAGS := $(CPPFLAGS) -D__powerpc__ -include $(TOPDIR)/arch/ppc64/mymacros.h
-CFLAGS := $(CFLAGS) -D__linux__ -D__powerpc__ -fsigned-char -Wa,-Saix \
+CPPFLAGS := $(CPPFLAGS) -D__powerpc__ -DPPC64_32B_ADDR_SPACE
+CFLAGS := $(CFLAGS) -D__linux__ -D__powerpc__ -fsigned-char \
-msoft-float -pipe -Wno-uninitialized $(PRINTK) \
- -include $(TOPDIR)/arch/ppc64/mymacros.h -mminimal-toc \
- -fno-builtin
+ -mminimal-toc -fno-builtin -DPPC64_32B_ADDR_SPACE
CPP = $(CC) -E $(CFLAGS)
@@ -52,8 +58,7 @@
BOOT_TARGETS = zImage znetboot.initrd zImage.initrd
-ifdef CONFIG_POWER3
-ifndef CONFIG_8260
+ifdef CONFIG_PPC_PSERIES
$(BOOT_TARGETS): $(CHECKS) vmlinux
@$(MAKEBOOT) $@
@@ -62,23 +67,9 @@
ifdef CONFIG_SMP
cp -f vmlinux /tftpboot/vmlinux.smp
else
- cp -f vmlinux /tftpboot/vmlinux
-endif
-endif
- @$(MAKEBOOT) $@
-else
-# 8260 is custom 6xx
-$(BOOT_TARGETS): $(CHECKS) vmlinux
- @$(MAKEMBXBOOT) $@
+ cp -f vmlinux /tftpboot/vmlinux.smp.64
endif
endif
-
-ifdef CONFIG_PPC64BRIDGE
-$(BOOT_TARGETS): $(CHECKS) vmlinux
- @$(MAKEBOOT) $@
-
-znetboot: $(CHECKS) vmlinux
- cp -f vmlinux /tftpboot/vmlinux.64
@$(MAKEBOOT) $@
endif
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/boot/Makefile linuxppc64_2_4/arch/ppc64/boot/Makefile
--- linux-2.4.8-ac9/arch/ppc64/boot/Makefile Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/boot/Makefile Thu Aug 16 14:57:25 2001
@@ -18,7 +18,7 @@
# compile for 32bit mode.
BOOTCC = $(HOSTCC)
-BOOTCFLAGS = $(HOSTCFLAGS)
+BOOTCFLAGS = $(HOSTCFLAGS) -I$(HPATH)
BOOTLD = ld
BOOTAS = as
BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS)
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/config.in linuxppc64_2_4/arch/ppc64/config.in
--- linux-2.4.8-ac9/arch/ppc64/config.in Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/config.in Thu Aug 23 19:48:56 2001
@@ -9,59 +9,23 @@
mainmenu_name "64 bit PowerPC Linux Kernel Configuration"
mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+ comment 'Code maturity level options'
+ bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Platform support'
define_bool CONFIG_PPC y
define_bool CONFIG_PPC64 y
-choice 'Processor Type' \
- "IStar CONFIG_ISTAR \
- iSeries CONFIG_PPC_ISERIES \
- POWER3 CONFIG_POWER3 \
- POWER4 CONFIG_POWER4 " POWER3
+define_bool CONFIG_ALL_PPC y
+define_bool CONFIG_SERIAL_CONSOLE y
-
-if [ "$CONFIG_ISTAR" = "y" -o "$CONFIG_POWER4" = "y" ]; then
- define_bool CONFIG_SERIAL_CONSOLE y
-fi
-
-
-if [ "$CONFIG_8xx" = "y" ]; then
- define_bool CONFIG_SERIAL_CONSOLE y
-
- choice 'Machine Type' \
- "RPX-Lite CONFIG_RPXLITE \
- RPX-Classic CONFIG_RPXCLASSIC \
- BSE-IP CONFIG_BSEIP \
- MBX CONFIG_MBX \
- WinCept CONFIG_WINCEPT" RPX-Lite
-fi
-if [ "$CONFIG_6xx" = "y" ]; then
- choice 'Machine Type' \
- "PowerMac/PReP/MTX/CHRP CONFIG_ALL_PPC \
- Gemini CONFIG_GEMINI \
- EST8260 CONFIG_EST8260 \
- APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP
-fi
-
-if [ "$CONFIG_POWER3" = "y" ]; then
- define_bool CONFIG_ALL_PPC y
-fi
-
-if [ "$CONFIG_POWER4" = "y" ]; then
- define_bool CONFIG_ALL_PPC y
-fi
-
-if [ "$CONFIG_ISTAR" = "y" ]; then
- define_bool CONFIG_ALL_PPC y
-fi
+choice 'Machine Type' \
+ "pSeries CONFIG_PPC_PSERIES \
+ iSeries CONFIG_PPC_ISERIES" CONFIG_PPC_PSERIES
if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
- define_bool CONFIG_ALL_PPC y
- define_bool CONFIG_MSCHUNKS y
+ define_bool CONFIG_MSCHUNKS y
fi
bool 'Symmetric multi-processing support' CONFIG_SMP
@@ -83,11 +47,9 @@
define_bool CONFIG_ISA n
define_bool CONFIG_SBUS n
-
-#Too many -o's for menuconfig
-#if [ "$CONFIG_POWER3" = "y" -o "$CONFIG_POWER4" = "y" -o "$CONFIG_ISTAR" ="y"]; then
- define_bool CONFIG_PCI y
-#fi
+define_bool CONFIG_MCA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_PCI y
bool 'Networking support' CONFIG_NET
bool 'Sysctl support' CONFIG_SYSCTL
@@ -99,17 +61,9 @@
define_bool CONFIG_KCORE_ELF y
fi
-#Commented By Adam. We must ask the question. Interactivity is the key :-)
-#define_bool CONFIG_BINFMT_ELF y
-#define_bool CONFIG_KERNEL_ELF y //WHAT IS THIS???//
-
bool 'Kernel Support for 64 bit ELF binaries' CONFIG_BINFMT_ELF
-
-#Too many -o 's for menuconfig
-#if [ "$CONFIG_POWER3" = "y" -o "$CONFIG_POWER4" = "y"-o"$CONFIG_ISTAR"="y"]; then
tristate 'Kernel support for 32 bit binaries' CONFIG_BINFMT_ELF32
-#fi
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
@@ -125,24 +79,11 @@
source drivers/parport/Config.in
-
if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
- if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then
- bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
- bool 'Support for frame buffer devices' CONFIG_FB
- if [ "$CONFIG_FB" = "y" ]; then
- bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
- fi
-
- bool 'Power management support for PowerBooks' CONFIG_PMAC_PBOOK
- tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
- if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
- bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
- fi
- bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
- bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
- bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
- fi
+ bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
+ bool 'Support for frame buffer devices' CONFIG_FB
+
+ bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
fi
endmenu
@@ -153,44 +94,34 @@
source drivers/md/Config.in
if [ "$CONFIG_NET" = "y" ]; then
- source net/Config.in
+ source net/Config.in
fi
-mainmenu_option next_comment
-comment 'ATA/IDE/MFM/RLL support'
-
-tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
-
-if [ "$CONFIG_IDE" != "n" ]; then
- source drivers/ide/Config.in
-else
- define_bool CONFIG_BLK_DEV_IDE_MODES n
- define_bool CONFIG_BLK_DEV_HD n
-fi
-endmenu
+define_bool CONFIG_BLK_DEV_IDE_MODES n
+define_bool CONFIG_BLK_DEV_HD n
mainmenu_option next_comment
comment 'SCSI support'
tristate 'SCSI support' CONFIG_SCSI
if [ "$CONFIG_SCSI" != "n" ]; then
- source drivers/scsi/Config.in
+ source drivers/scsi/Config.in
fi
endmenu
source drivers/ieee1394/Config.in
if [ "$CONFIG_NET" = "y" ]; then
- mainmenu_option next_comment
- comment 'Network device support'
+ mainmenu_option next_comment
+ comment 'Network device support'
- bool 'Network device support' CONFIG_NETDEVICES
- if [ "$CONFIG_NETDEVICES" = "y" ]; then
- source drivers/net/Config.in
- if [ "$CONFIG_ATM" = "y" ]; then
- source drivers/atm/Config.in
- fi
- fi
- endmenu
+ bool 'Network device support' CONFIG_NETDEVICES
+ if [ "$CONFIG_NETDEVICES" = "y" ]; then
+ source drivers/net/Config.in
+ if [ "$CONFIG_ATM" = "y" ]; then
+ source drivers/atm/Config.in
+ fi
+ fi
+ endmenu
fi
source net/ax25/Config.in
@@ -202,7 +133,7 @@
tristate 'ISDN support' CONFIG_ISDN
if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
+ source drivers/isdn/Config.in
fi
endmenu
@@ -211,7 +142,7 @@
bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
- source drivers/cdrom/Config.in
+ source drivers/cdrom/Config.in
fi
endmenu
@@ -227,16 +158,12 @@
comment 'Sound'
tristate 'Sound card support' CONFIG_SOUND
if [ "$CONFIG_SOUND" != "n" ]; then
- source drivers/sound/dmasound/Config.in
- source drivers/sound/Config.in
+ source drivers/sound/dmasound/Config.in
+ source drivers/sound/Config.in
fi
endmenu
-if [ "$CONFIG_8260" = "y" ]; then
-source arch/ppc/8260_io/Config.in
-fi
-
source drivers/usb/Config.in
mainmenu_option next_comment
@@ -245,10 +172,10 @@
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Include kgdb kernel debugger' CONFIG_KGDB
bool 'Include xmon kernel debugger' CONFIG_XMON
-bool 'Include kdb kernel debugger' CONFIG_KDB
-if [ "$CONFIG_KDB" = "y" ]; then
- bool ' KDB off by default' CONFIG_KDB_OFF
- define_bool CONFIG_KALLSYMS y
-fi
+#bool 'Include kdb kernel debugger' CONFIG_KDB
+#if [ "$CONFIG_KDB" = "y" ]; then
+# bool ' KDB off by default' CONFIG_KDB_OFF
+# define_bool CONFIG_KALLSYMS y
+#fi
bool 'Include PPCDBG realtime debugging' CONFIG_PPCDBG
endmenu
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/defconfig linuxppc64_2_4/arch/ppc64/defconfig
--- linux-2.4.8-ac9/arch/ppc64/defconfig Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/defconfig Mon Aug 20 14:07:04 2001
@@ -1,5 +1,5 @@
#
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
#
# CONFIG_UID16 is not set
# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
@@ -15,13 +15,12 @@
#
CONFIG_PPC=y
CONFIG_PPC64=y
-# CONFIG_ISTAR is not set
-# CONFIG_PPC_ISERIES is not set
-CONFIG_POWER3=y
-# CONFIG_POWER4 is not set
CONFIG_ALL_PPC=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_PPC_ISERIES is not set
+CONFIG_PPC_PSERIES=y
CONFIG_SMP=y
-# CONFIG_MSCHUNKS is not set
+CONFIG_MSCHUNKS=y
#
# Loadable module support
@@ -33,6 +32,8 @@
#
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_EISA is not set
CONFIG_PCI=y
CONFIG_NET=y
CONFIG_SYSCTL=y
@@ -50,13 +51,9 @@
# Parallel port support
#
# CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+# CONFIG_VGA_CONSOLE is not set
CONFIG_FB=y
-# CONFIG_FB_COMPAT_XPMAC is not set
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_SERIAL is not set
-CONFIG_PROC_DEVICETREE=y
-# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PROC_DEVICETREE is not set
# CONFIG_MOTOROLA_HOTSWAP is not set
#
@@ -75,7 +72,6 @@
# Block devices
#
CONFIG_BLK_DEV_FD=y
-# CONFIG_VIODASD is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
@@ -121,10 +117,6 @@
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
-
-#
-#
-#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
@@ -154,10 +146,6 @@
# SCSI support
#
CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
@@ -166,10 +154,6 @@
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_SR_EXTRA_DEVS=2
CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
@@ -186,6 +170,7 @@
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
@@ -414,7 +399,6 @@
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_VIOCONS is not set
#
# I2C support
@@ -441,10 +425,6 @@
# CONFIG_INPUT_EMU10K1 is not set
# CONFIG_INPUT_SERIO is not set
# CONFIG_INPUT_SERPORT is not set
-
-#
-# Joysticks
-#
# CONFIG_INPUT_ANALOG is not set
# CONFIG_INPUT_A3D is not set
# CONFIG_INPUT_ADI is not set
@@ -540,6 +520,7 @@
# Network File Systems
#
# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_ROOT_NFS is not set
@@ -618,17 +599,9 @@
# USB support
#
# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
# CONFIG_USB_UHCI is not set
# CONFIG_USB_UHCI_ALT is not set
# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
# CONFIG_USB_AUDIO is not set
# CONFIG_USB_BLUETOOTH is not set
# CONFIG_USB_STORAGE is not set
@@ -638,48 +611,28 @@
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
# CONFIG_USB_HID is not set
# CONFIG_USB_HIDDEV is not set
# CONFIG_USB_KBD is not set
# CONFIG_USB_MOUSE is not set
# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
# CONFIG_USB_DC2XX is not set
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_SCANNER is not set
# CONFIG_USB_MICROTEK is not set
# CONFIG_USB_HP5300 is not set
-
-#
-# USB Multimedia devices
-#
# CONFIG_USB_IBMCAM is not set
# CONFIG_USB_OV511 is not set
# CONFIG_USB_PWC is not set
# CONFIG_USB_SE401 is not set
# CONFIG_USB_DSBR is not set
# CONFIG_USB_DABUSB is not set
-
-#
-# USB Network adaptors
-#
# CONFIG_USB_PLUSB is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_CATC is not set
# CONFIG_USB_CDCETHER is not set
# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
# CONFIG_USB_USS720 is not set
#
@@ -707,10 +660,6 @@
# CONFIG_USB_SERIAL_PL2303 is not set
# CONFIG_USB_SERIAL_CYBERJACK is not set
# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# Miscellaneous USB drivers
-#
# CONFIG_USB_RIO500 is not set
#
@@ -719,5 +668,4 @@
CONFIG_MAGIC_SYSRQ=y
# CONFIG_KGDB is not set
CONFIG_XMON=y
-# CONFIG_KDB is not set
CONFIG_PPCDBG=y
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/HvLpConfig.c linuxppc64_2_4/arch/ppc64/kernel/HvLpConfig.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/HvLpConfig.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/kernel/HvLpConfig.c Tue Aug 21 22:09:44 2001
@@ -0,0 +1,63 @@
+/*
+ * HvLpConfig.c
+ * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _HVLPCONFIG_H
+#include
+#endif
+
+HvLpIndex HvLpConfig_getLpIndex_outline(void)
+{
+ return HvLpConfig_getLpIndex();
+}
+
+const HvLpIndexMap HvLpIndexMapDefault = (1 << (sizeof(HvLpIndexMap) * 8 - 1));
+const HvLpIndex HvHardcodedPrimaryLpIndex = 0;
+const HvLpIndex HvMaxArchitectedLps = HVMAXARCHITECTEDLPS;
+const HvLpVirtualLanIndex HvMaxArchitectedVirtualLans = 16;
+const HvLpSharedPoolIndex HvMaxArchitectedSharedPools = 16;
+const HvLpSharedPoolIndex HvMaxSupportedSharedPools = 1;
+const HvLpIndex HvMaxRuntimeLpsPreCondor = 12;
+const HvLpIndex HvMaxRuntimeLps = HVMAXARCHITECTEDLPS;
+const HvLpIndex HvLpIndexInvalid = 0xff;
+const u16 HvInvalidProcIndex = 0xffff;
+const u32 HvVirtualFlashSize = 0x200;
+const u32 HvMaxBusesPreCondor = 32;
+const u32 HvMaxBusesCondor = 256;
+const u32 HvMaxArchitectedBuses = 512;
+const HvLpBus HvCspBusNumber = 1;
+const u32 HvMaxSanHwSets = 16;
+const HvLpCard HvMaxSystemIops = 200;
+const HvLpCard HvMaxBusIops = 20;
+const u16 HvMaxUnitsPerIop = 100;
+const u64 HvPageSize = 4 * 1024;
+const u64 HvChunkSize = HVCHUNKSIZE;
+const u64 HvChunksPerMeg = HVCHUNKSPERMEG;
+const u64 HvPagesPerChunk = HVPAGESPERCHUNK;
+const u64 HvPagesPerMeg = HVPAGESPERMEG;
+const u64 HvLpMinMegsPrimary = HVLPMINMEGSPRIMARY;
+const u64 HvLpMinMegsSecondary = HVLPMINMEGSSECONDARY;
+const u64 HvLpMinChunksPrimary = HVLPMINMEGSPRIMARY * HVCHUNKSPERMEG;
+const u64 HvLpMinChunksSecondary = HVLPMINMEGSSECONDARY * HVCHUNKSPERMEG;
+const u64 HvLpMinPagesPrimary = HVLPMINMEGSPRIMARY * HVPAGESPERMEG;
+const u64 HvLpMinPagesSecondary = HVLPMINMEGSSECONDARY * HVPAGESPERMEG;
+const u8 HvLpMinProcs = 1;
+const u8 HvLpConfigMinInteract = 1;
+const u16 HvLpMinSharedProcUnitsX100 = 10;
+const u16 HvLpMaxSharedProcUnitsX100 = 100;
+const HvLpSharedPoolIndex HvLpSharedPoolIndexInvalid = 0xff;
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/Makefile linuxppc64_2_4/arch/ppc64/kernel/Makefile
--- linux-2.4.8-ac9/arch/ppc64/kernel/Makefile Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/Makefile Tue Aug 14 23:13:12 2001
@@ -26,12 +26,12 @@
ioctl32.o ptrace32.o signal32.o open_pic.o xics.o \
pmc.o mf_proc.o proc_pmc.o iSeries_setup.o \
ItLpQueue.o hvCall.o mf.o viopath.o HvLpEvent.o \
- iSeries_proc.o HvCall.o flight_recorder.o
+ iSeries_proc.o HvCall.o flight_recorder.o HvLpConfig.o
obj-$(CONFIG_PCI) += pci.o
ifeq ($(CONFIG_PPC_ISERIES),y)
-obj-$(CONFIG_PCI) += iSeries_dma.o iSeries_rtc.o
+obj-$(CONFIG_PCI) += iSeries_dma.o iSeries_rtc.o proc_pcifr.o
else
obj-$(CONFIG_PCI) += pci_dma.o proc_pcifr.o
endif
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/entry.S linuxppc64_2_4/arch/ppc64/kernel/entry.S
--- linux-2.4.8-ac9/arch/ppc64/kernel/entry.S Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/entry.S Fri Aug 24 07:02:12 2001
@@ -306,10 +306,10 @@
mtmsrd r6 /* Update machine state */
ld r6,_MSR(r1)
- mtspr SRR0,r7
- mtspr SRR1,r6
ld r2,GPR2(r1)
ld r1,GPR1(r1)
+ mtspr SRR0,r7
+ mtspr SRR1,r6
/* sync required to force memory operations on this processor */
/* to complete before the current thread gives up control. */
@@ -334,33 +334,20 @@
ld r5,_MSR(r1)
andi. r5,r5,MSR_EE
beq 2f
-
-_GLOBAL(lost_irq_ret)
-3: LOADBASE(r4,ppc_n_lost_interrupts)
- lwz r4,ppc_n_lost_interrupts@l(r4)
- cmpi 0,r4,0
- bne- 1f /* do_IRQ if lost interrupts */
+irq_recheck:
+ mfmsr r5
+ andi. r5,r5,MSR_EE
+ bne 4f
/*
- * Check for pending I/O events (iSeries)
- * If no I/O events pending then CR0 = "eq" and r4 = 0
- * (kills registers r5 and r6)
+ * Check for pending interrupts (iSeries)
*/
- CHECKLPQUEUE(r4,r5,r6)
- beq+ 4f /* skip do_IRQ if no events */
-1:
+ CHECKANYINT(r4,r5)
+ beq+ 4f /* skip do_IRQ if no interrupts */
+
addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_IRQ
- b 3b /* loop back and handle more */
+ b irq_recheck /* loop back and handle more */
4:
- /*
- * Check for lost decrementer interrupts.
- * (If decrementer popped while we were in the hypervisor)
- */
- CHECKDECR(r4,r5)
- beq+ 5f
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl .timer_interrupt
-5:
LOADADDR(r4,irq_stat)
#ifdef CONFIG_SMP
/* get processor # */
@@ -388,7 +375,6 @@
/* NEED_RESCHED is a volatile long (64-bits) */
mfspr r4,SPRG3 /* current task's PACA */
ld r4,PACACURRENT(r4) /* Get 'current' */
-
ld r3,NEED_RESCHED(r4)
cmpi 0,r3,0 /* check need_resched flag */
beq+ 7f
@@ -423,17 +409,26 @@
rldicl r0,r0,48,1
rldicl r0,r0,16,0 /* clear MSR_EE */
mtmsrd r0 /* Update machine state */
+
+ ld r0,_MSR(r1)
+ andi. r3,r0,MSR_EE
+ beq+ 1f
+
+ CHECKANYINT(r4,r3)
+ bne- irq_recheck
- /* if returning to user mode, set new sprg3 and save kernel SP */
+1:
+ stdcx. r0,0,r1 /* to clear the reservation */
+
+ /* if returning to user mode, save kernel SP */
ld r0,_MSR(r1)
andi. r0,r0,MSR_PR
beq+ 1f
addi r0,r1,INT_FRAME_SIZE /* size of frame */
mfspr r4,SPRG3 /* current task's PACA */
- ld r4,PACACURRENT(r4) /* Get 'current' */
- std r0,THREAD+KSP(r4) /* save kernel stack pointer */
- mfspr r2,SPRG3 /* Get Paca */
- std r1,PACAKSAVE(r2) /* save exception stack pointer */
+ ld r2,PACACURRENT(r4) /* Get 'current' */
+ std r0,THREAD+KSP(r2) /* save kernel stack pointer */
+ std r1,PACAKSAVE(r4) /* save exception stack pointer */
1:
ld r0,_MSR(r1)
mtspr SRR1,r0
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/head.S linuxppc64_2_4/arch/ppc64/kernel/head.S
--- linux-2.4.8-ac9/arch/ppc64/kernel/head.S Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/head.S Fri Aug 24 07:02:12 2001
@@ -26,6 +26,8 @@
*
*/
+#define SECONDARY_PROCESSORS
+
#include "ppc_asm.h"
#include "ppc_defs.h"
#include
@@ -326,22 +328,32 @@
.globl SystemReset_Iseries
SystemReset_Iseries:
- mfspr r3,SPRG3 /* Get Paca address */
- lhz r24,PACAPACAINDEX(r3) /* Get processor # */
+ mfspr 25,SPRG3 /* Get Paca address */
+ lhz r24,PACAPACAINDEX(r25) /* Get processor # */
cmpi 0,r24,0 /* Are we processor 0? */
beq .__start_initialization_iSeries /* Start up the first processor */
mfspr r4,CTRLF
li r5,RUNLATCH /* Turn off the run light */
andc r4,r4,r5
mtspr CTRLT,r4
+
1:
HMT_LOW
#ifdef CONFIG_SMP
- lbz r23,PACAPROCSTART(r3) /* Test if this processor
+ lbz r23,PACAPROCSTART(r25) /* Test if this processor
* should start */
+ sync
+ LOADADDR(r3,current_set)
+ sldi r28,r24,4 /* get current_set[cpu#] */
+ ldx r3,r3,r28
+ addi r1,r3,TASK_UNION_SIZE
+ subi r1,r1,STACK_FRAME_OVERHEAD
+
cmpi 0,r23,0
beq iseries_secondary_smp_loop /* Loop until told to go */
+#ifdef SECONDARY_PROCESSORS
bne .__secondary_start /* Loop until told to go */
+#endif
iseries_secondary_smp_loop:
/* Let the Hypervisor know we are alive */
/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
@@ -354,13 +366,13 @@
which are running on multi-threaded machines. */
lis r3,0x8000
rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */
- addi r3,r3,18 /* r3 = -x8000000000000012 which is "yield" */
+ addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */
li r4,0 /* "yield timed" */
li r5,-1 /* "yield forever" */
#endif /* CONFIG_SMP */
li r0,-1 /* r0=-1 indicates a Hypervisor call */
sc /* Invoke the hypervisor via a system call */
- mfspr r3,SPRG3 /* Put r3 back */
+ mfspr r25,SPRG3 /* Put r25 back ???? */
b 1b /* If SMP not configured, secondaries
* loop forever */
@@ -368,7 +380,6 @@
STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
STD_EXCEPTION_COMMON( 0x200, MachineCheck, .MachineCheckException )
- STD_EXCEPTION_COMMON( 0x500, HardwareInterrupt, .do_IRQ )
STD_EXCEPTION_COMMON( 0x900, Decrementer, .timer_interrupt )
STD_EXCEPTION_COMMON( 0xa00, Trap_0a, .UnknownException )
STD_EXCEPTION_COMMON( 0xb00, Trap_0b, .UnknownException )
@@ -376,8 +387,21 @@
STD_EXCEPTION_COMMON( 0xe00, Trap_0e, .UnknownException )
STD_EXCEPTION_COMMON( 0xf00, PerformanceMonitor, .PerformanceMonitorException )
+/* r20 is in SPRG2,
+ r21 is in the PACA
+*/
.globl DataAccess_common
DataAccess_common:
+ mfcr r20
+ mfspr r21,DAR
+ srdi r21,r21,60
+ cmpi 0,r21,0xc
+ bne 3f
+
+ /* Segment faulted on a bolted segment. Go off and map that segment. */
+ b .do_stab_bolted
+
+3: mtcr r20
EXCEPTION_PROLOG_COMMON
mfspr r20,DSISR
std r20,_DSISR(r21)
@@ -520,6 +544,17 @@
.llong .do_page_fault
.llong .ret_from_except
+ .globl HardwareInterrupt_common
+HardwareInterrupt_common:
+ EXCEPTION_PROLOG_COMMON
+HardwareInterrupt_entry:
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ SET_REG_TO_CONST(r20, MSR_KERNEL)
+ li r6,0x500
+ bl .transfer_to_handler
+ .llong .do_IRQ
+ .llong .ret_from_except
+
.globl Alignment_common
Alignment_common:
EXCEPTION_PROLOG_COMMON
@@ -559,6 +594,11 @@
.globl SystemCall_common
SystemCall_common:
EXCEPTION_PROLOG_COMMON
+ cmpi 0,r0,0x5555 /* Special syscall to handle pending */
+ bne+ 1f /* interrupts */
+ andi. r6,r23,MSR_PR /* Only allowed from kernel */
+ beq+ HardwareInterrupt_entry
+1:
std r3,ORIG_GPR3(r21)
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
@@ -612,6 +652,124 @@
ld r21,GPR21(r21)
rfid
+/* orig r20 is in SPRG2,
+ orig r21 is in the PACA
+ r20 contains CCR
+
+ r22 needs to be saved
+ r1 needs to be saved
+ CCR needs to be saved
+*/
+_GLOBAL(do_stab_bolted)
+ mfsprg r21,3
+ std r22,PACAR22(r21)
+ std r1,PACAR1(r21)
+ stw r20,PACACCR(r21)
+ mfspr r21,DAR
+
+ /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
+ rldicl r20,r21,36,32 /* Permits a full 32b of ESID */
+ rldicr r20,r20,15,48
+ rldicl r21,r21,4,60
+ or r20,r20,r21
+
+ li r21,9 /* VSID_RANDOMIZER */
+ rldicr r21,r21,32,31
+ oris r21,r21,58231
+ ori r21,r21,39831
+
+ mulld r20,r20,r21
+ clrldi r20,r20,28 /* r20 = vsid */
+
+ mfsprg r21,3
+ ld r21,PACASTABVIRT(r21)
+
+ /* Hash to the primary group */
+ mfspr r22,DAR
+ rldicl r22,r22,36,59
+ rldicr r22,r22,7,56
+ or r21,r21,r22 /* r21 = first ste of the group */
+
+ /* Search the primary group for a free entry */
+ li r22,0
+1:
+ ld r1,0(r21) /* Test valid bit of the current ste */
+ rldicl r1,r1,57,63
+ cmpwi r1,0
+ bne 2f
+ ld r1,8(r21) /* Get the current vsid part of the ste */
+ rldimi r1,r20,12,0 /* Insert the new vsid value */
+ std r1,8(r21) /* Put new entry back into the stab */
+ eieio /* Order vsid update */
+ ld r1,0(r21) /* Get the esid part of the ste */
+ mfspr r20,DAR /* Get the new esid */
+ rldicl r20,r20,36,28 /* Permits a full 36b of ESID */
+ rldimi r1,r20,28,0 /* Insert the new esid value */
+ ori r1,r1,144 /* Turn on valid and kp */
+ std r1,0(r21) /* Put new entry back into the stab */
+ sync /* Order the update */
+ b 3f
+2:
+ addi r22,r22,1
+ addi r21,r21,16
+ cmpldi r22,7
+ ble 1b
+
+ /* Stick for only searching the primary group for now. */
+ /* At least for now, we use a very simple random castout scheme */
+ /* Use the TB as a random number ; OR in 1 to avoid entry 0 */
+ mftb r22
+ andi. r22,r22,7
+ ori r22,r22,1
+ sldi r22,r22,4
+
+ /* r21 currently points to and ste one past the group of interest */
+ /* make it point to the randomly selected entry */
+ subi r21,r21,128
+ ori r21,r21,r22 /* r21 is the entry to invalidate */
+
+ isync /* mark the entry invalid */
+ ld r1,0(r21)
+ li r22,-129
+ and r1,r1,r22
+ std r1,0(r21)
+ sync
+
+ ld r1,8(r21)
+ rldimi r1,r20,12,0
+ std r1,8(r21)
+ eieio
+
+ ld r1,0(r21) /* Get the esid part of the ste */
+ mr r22,r1
+ mfspr r20,DAR /* Get the new esid */
+ rldicl r20,r20,36,32 /* Permits a full 32b of ESID */
+ rldimi r1,r20,28,0 /* Insert the new esid value */
+ ori r1,r1,144 /* Turn on valid and kp */
+ std r1,0(r21) /* Put new entry back into the stab */
+
+ rldicl r22,r22,36,28
+ rldicr r22,r22,28,35
+ slbie r22
+ sync
+
+3:
+ /* All done -- return from exception. */
+ mfsprg r20,3 /* Load the PACA pointer */
+
+ ld r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */
+ ld r21,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */
+ mtspr SRR1,r21
+ mtspr SRR0,r22
+
+ lwz r21,PACACCR(r20) /* Restore the clobbered regs */
+ mtcr r21
+ ld r1, PACAR1(r20)
+ ld r21,PACAR21(r20)
+ ld r22,PACAR22(r20)
+ mfspr r20,SPRG2
+ rfid
+
_GLOBAL(do_stab_SI)
mflr r21 /* Save LR in r21 */
/* r21 restored later from r1 */
@@ -670,17 +828,14 @@
SAVE_4GPRS(16, r21)
SAVE_8GPRS(24, r21)
/*
- * Clear any reservation, and clear the RESULT field
+ * Clear the RESULT field
*/
- li r22,RESULT
- stdcx. r22,r22,r21 /* to clear the reservation */
li r22,0
std r22,RESULT(r21)
/*
* Test if from user state; result will be tested later
*/
- andi. r23,r23,MSR_PR /* Set CR for later branch */
- /* SPRG3 -> PACA */
+ andi. r23,r23,MSR_PR /* Set CR for later branch */
/*
* Indicate that r1 contains the kernel stack and
* get the Kernel TOC and CURRENT pointers from the Paca
@@ -696,7 +851,6 @@
addi r24,r1,STACK_FRAME_OVERHEAD
std r24,THREAD+PT_REGS(r22)
2:
-
/*
* Since we store 'current' in the PACA now, we don't need to
* set it here. When r2 was used as 'current' it had to be
@@ -733,27 +887,37 @@
* At entry, r3 = this processor's number (in Linux terms, not hardware).
*/
_GLOBAL(pseries_secondary_smp_init)
+
+ /* turn on 64-bit mode */
+ bl .enable_64b_mode
+ isync
+
/* Set up a Paca value for this processor. */
LOADADDR(r24, xPaca) /* Get base vaddr of Paca array */
mulli r25,r3,PACA_SIZE /* Calculate vaddr of right Paca */
add r25,r25,r24 /* for this processor. */
- SET_REG_TO_CONST(r26,KERNELBASE) /* Calculate raddr of the Paca */
- sub r26,r25,r26
-
mtspr SPRG3,r25 /* Save vaddr of Paca in SPRG3 */
mr r24,r3 /* __secondary_start needs cpu# */
1:
HMT_LOW
- lbz r23,PACAPROCSTART(r26) /* Test if this processor should */
+ lbz r23,PACAPROCSTART(r25) /* Test if this processor should */
/* start. */
+ sync
+ LOADADDR(r3,current_set)
+ addi r3,r3,8
+ sldi r28,r24,4 /* get current_set[cpu#] */
+ ldx r1,r3,r28
+
cmpi 0,r23,0
#ifdef CONFIG_SMP
- bne .__secondary_start /* Loop until told to go. */
+#ifdef SECONDARY_PROCESSORS
+ bne .__secondary_start
#endif
- b 1b
-
+#endif
+ b 1b /* Loop until told to go */
+
_GLOBAL(__start_initialization_iSeries)
LOADADDR(r1,init_task_union)
@@ -1071,68 +1235,57 @@
* On entry the following are set:
* r24 = cpu# (in Linux terms)
* r25 = Paca virtual address
- * r26 = Paca physical address
* SPRG3 = Paca virtual address
*/
_GLOBAL(__secondary_start)
- /* turn on 64 bit mode */
- bl .enable_64b_mode
- isync
-
- /* get our current offset. */
- SET_REG_TO_CONST(r27, KERNELBASE)
HMT_MEDIUM /* Set thread priority to MEDIUM */
- /* get a virtual pointer to current */
- LOADADDR(r3,current_set)
- sub r3,r3,r27
- addi r3,r3,8
- sldi r28,r24,4 /* get current_set[cpu#] */
- ldx r1,r3,r28
-
/* set up the TOC (virtual address) */
LOADADDR(r2,__toc_start)
addi r2,r2,0x4000
addi r2,r2,0x4000
- std r2,PACATOC(r26)
+ std r2,PACATOC(r25)
li r6,0
- std r6,PACAKSAVE(r26)
+ std r6,PACAKSAVE(r25)
#ifndef CONFIG_PPC_ISERIES
/* Initialize the page table pointer register. */
- LOADADDR(r6,_SDR1)
- sub r6,r6,r27
+ LOADADDR(r6,_SDR1)
ld r6,0(r6) /* get the value of _SDR1 */
mtspr SDR1,r6 /* set the htab location */
#endif
/* Initialize the segment table subsystem. */
- ld r4,PACASTABREAL(r26) /* get raddr of segment table */
- ori r3,r4,1 /* turn on valid bit */
- mtasr r3 /* set the stab location */
+ ld r4,PACASTABVIRT(r25) /* get addr of segment table */
li r3,0 /* 0 -> include esid 0xC00000000 */
- slbia
+ std r3,0(r1) /* Zero the stack frame pointer */
bl .stab_initialize
- /* get a virtual pointer to current */
- SET_REG_TO_CONST(r27, KERNELBASE)
LOADADDR(r3,current_set)
- sub r3,r3,r27
sldi r28,r24,4 /* get current_set[cpu#] */
ldx r6,r3,r28
+ std r6,PACACURRENT(r25)
addi r1,r6,TASK_UNION_SIZE
subi r1,r1,STACK_FRAME_OVERHEAD
- addi r3,r3,8
- ld r3,0(r3)
+ ld r3,PACASTABREAL(r25) /* get raddr of segment table */
+ ori r4,r3,1 /* turn on valid bit */
+
+#ifdef CONFIG_PPC_ISERIES
+ li r0,-1 /* hypervisor call */
+ li r3,1
+ sldi r3,r3,63 /* 0x8000000000000000 */
+ ori r3,r3,4 /* 0x8000000000000004 */
+ sc /* HvCall_setASR */
+#else
+ mtasr r4 /* set the stab location */
+#endif
+ slbia
+
li r7,0
- std r7,0(r3)
mtlr r7
- mfspr r4,SPRG3
- std r6,PACACURRENT(r4)
-
/* enable MMU and jump to start_secondary */
LOADADDR(r3,.start_secondary)
SET_REG_TO_CONST(r4, MSR_KERNEL)
@@ -1356,6 +1509,10 @@
bolted_dir:
.space 4096
+/* 4096 * 31 bytes of storage */
+ .globl stab_array
+stab_array:
+ .space 131072
/*
* This space gets a copy of optional info passed to us by the bootstrap
* Used to pass parameters into the kernel like root=/dev/sda1, etc.
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/htab.c linuxppc64_2_4/arch/ppc64/kernel/htab.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/htab.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/htab.c Tue Aug 21 14:49:26 2001
@@ -82,6 +82,22 @@
#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) + offset))
#define RELOC(x) (*PTRRELOC(&(x)))
+extern unsigned long htab_size( unsigned long );
+
+static inline void
+create_pte_mapping(unsigned long start, unsigned long end,
+ unsigned long mode, unsigned long mask)
+{
+ unsigned long addr, offset = reloc_offset();
+ HTAB *_htab_data = PTRRELOC(&htab_data);
+ HPTE *htab = (HPTE *)__v2a(_htab_data->htab);
+
+ for (addr=start; addr < end ;addr+=0x1000) {
+ unsigned long vsid = get_kernel_vsid(addr);
+ unsigned long va = (vsid << 28) | (addr & 0xfffffff);
+ make_pte(htab, va, (unsigned long)__v2a(addr), mode, mask);
+ }
+}
void
htab_initialize(void)
@@ -125,11 +141,18 @@
* (addr & KERNELBASE) == 0 (ie they are disjoint).
* We also assume that the va is <= 64 bits.
*/
- create_pte_mapping(_stext, __start_naca, mode_ro, mask);
- create_pte_mapping(__start_naca, __end_stab, mode_rw, mask);
- create_pte_mapping(__end_stab, _etext, mode_ro, mask);
- create_pte_mapping(_etext, RELOC(klimit), mode_rw, mask);
- create_pte_mapping(__a2v(table), __a2v(table+htab_size_bytes), mode_rw, mask);
+#if 0
+ create_pte_mapping((unsigned long)_stext, (unsigned long)__start_naca, mode_ro, mask);
+ create_pte_mapping((unsigned long)__start_naca, (unsigned long)__end_stab, mode_rw, mask);
+ create_pte_mapping((unsigned long)__end_stab, (unsigned long)_etext, mode_ro, mask);
+ create_pte_mapping((unsigned long)_etext, RELOC(klimit), mode_rw, mask);
+ create_pte_mapping((unsigned long)__a2v(table), (unsigned long)__a2v(table+htab_size_bytes), mode_rw, mask);
+#else
+ create_pte_mapping((unsigned long)KERNELBASE,
+ KERNELBASE+(_naca->physicalMemorySize),
+ mode_rw, mask);
+#endif
+
}
static inline unsigned long hpt_hash( unsigned long vpn )
@@ -150,6 +173,7 @@
{
HPTE *hptep;
unsigned long hash, i;
+ volatile unsigned long x = 1;
hash = hpt_hash( va >> 12 );
@@ -162,9 +186,12 @@
hptep->dw0.dw0.avpn = va >> 23;
hptep->dw0.dw0.bolted = 1; /* bolted */
hptep->dw0.dw0.v = 1; /* make valid */
- break;
+ return;
}
}
+
+ /* We should _never_ get here and too early to call xmon. */
+ for(;x;x|=1);
}
void invalidate_hpte( unsigned long slot )
@@ -318,6 +345,69 @@
return 0;
}
+static unsigned long get_hpte0( unsigned long slot )
+{
+ unsigned long dword0;
+
+ if ( _machine == _MACH_iSeries ) {
+ HPTE hpte;
+ HvCallHpt_get( &hpte, slot );
+ dword0 = hpte.dw0.dword0;
+ }
+ else {
+ HPTE * hptep = htab_data.htab + slot;
+ dword0 = hptep->dw0.dword0;
+ }
+
+ return dword0;
+}
+
+long find_hpte( unsigned long vpn )
+{
+ HPTE hpte;
+ long slot;
+
+ if ( _machine == _MACH_iSeries ) {
+ slot = HvCallHpt_findValid( &hpte, vpn );
+ if ( hpte.dw0.dw0.v ) {
+ if ( slot < 0 ) {
+ slot &= 0x7fffffffffffffff;
+ slot = -slot;
+ }
+ }
+ else
+ slot = -1;
+ }
+ else {
+ union {
+ unsigned long d;
+ Hpte_dword0 h;
+ } hpte_dw0;
+ unsigned long hash;
+ unsigned long i,j;
+
+ hash = hpt_hash( vpn );
+ for ( j=0; j<2; ++j ) {
+ slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+ for ( i=0; i> 11 ) ) &&
+ ( hpte_dw0.h.v ) &&
+ ( hpte_dw0.h.h == j ) ) {
+ /* HPTE matches */
+ if ( j )
+ slot = -slot;
+ return slot;
+ }
+ ++slot;
+ }
+ hash = ~hash;
+ }
+ slot = -1;
+ }
+ return slot;
+}
+
/* This function is called by btmalloc to bolt an entry in the hpt */
void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
pte_t * ptep, unsigned hpteflags, unsigned bolted )
@@ -474,23 +564,6 @@
1 ) );
}
-static unsigned long get_hpte0( unsigned long slot )
-{
- unsigned long dword0;
-
- if ( _machine == _MACH_iSeries ) {
- HPTE hpte;
- HvCallHpt_get( &hpte, slot );
- dword0 = hpte.dw0.dword0;
- }
- else {
- HPTE * hptep = htab_data.htab + slot;
- dword0 = hptep->dw0.dword0;
- }
-
- return dword0;
-}
-
static void updateHptePP( long slot, unsigned long newpp, unsigned long va )
{
if ( _machine == _MACH_iSeries ) {
@@ -552,6 +625,7 @@
long slot;
struct mm_struct * mm;
pte_t old_pte, new_pte, *ptep;
+ volatile unsigned long x = 1;
/* Check for invalid addresses. */
if (!IS_VALID_EA(ea)) {
@@ -561,6 +635,14 @@
regionid = REGION_ID(ea);
switch ( regionid ) {
case KERNEL_REGION_ID:
+
+ /* As htab_initialize is now, we shouldn't ever get here since
+ * we're bolting the entire 0xC0... region.
+ */
+ udbg_printf("Doh!!! hash_page saw a kernel address...\n");
+ xmon(0);
+ for(;x;x|=1);
+
vsid = get_kernel_vsid( ea );
va = ( vsid << 28 ) | ( ea & 0x0fffffff );
vpn = va >> PAGE_SHIFT;
@@ -568,7 +650,7 @@
pte_val(old_pte) = ((__pa(ea)&PAGE_MASK)<<(PTE_SHIFT-PAGE_SHIFT)) |
_PAGE_PRESENT | _PAGE_ACCESSED |
_PAGE_SHARED | _PAGE_RW | _PAGE_COHERENT |
- _PAGE_DIRTY | _PAGE_HASHPTE;
+ _PAGE_DIRTY | _PAGE_HPTENOIX;
spin_lock( &hash_table_lock );
break;
case VMALLOC_REGION_ID:
@@ -669,6 +751,24 @@
access |= _PAGE_PRESENT;
if ( 0 == ( access & ~(pte_val(old_pte)) ) ) {
+ /*
+ * Check if pte might have an hpte, but we have
+ * no slot information
+ */
+ if ( pte_val(old_pte) & _PAGE_HPTENOIX ) {
+ unsigned long slot;
+ pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
+ slot = find_hpte( vpn );
+ if ( slot != -1 ) {
+ if ( slot < 0 ) {
+ pte_val(old_pte) |= _PAGE_SECONDARY;
+ slot = -slot;
+ }
+ pte_val(old_pte) |= ((slot << 12) & _PAGE_GROUP_IX) | _PAGE_HASHPTE;
+
+ }
+ }
+
/* User has appropriate access rights. */
new_pte = old_pte;
/* If the attempted access was a store */
@@ -848,6 +948,25 @@
/* HPTE matches */
invalidate_hpte( slot );
}
+ else {
+ unsigned k;
+ /* Temporarily lets check for the hpte in all possible slots */
+ for ( secondary = 0; secondary < 2; ++secondary ) {
+ hash = hpt_hash( vpn );
+ if ( secondary )
+ hash = ~hash;
+ slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+ for ( k=0; k<8; ++k ) {
+ hpte_dw0.d = get_hpte0( slot+k );
+ if ( ( hpte_dw0.h.avpn == (vpn >> 11) ) &&
+ ( hpte_dw0.h.v ) &&
+ ( hpte_dw0.h.h == secondary ) ) {
+ while (1) ;
+ }
+ }
+ }
+
+ }
spin_unlock_irqrestore( &hash_table_lock, flags );
}
@@ -1042,20 +1161,5 @@
pteg_count >>= 3;
}
return (pteg_count << 7); /* pteg_count*128B/PTEG */
-}
-
-static inline void
-create_pte_mapping(unsigned long start, unsigned long end,
- unsigned long mode, unsigned long mask)
-{
- unsigned long addr, offset = reloc_offset();
- HTAB *_htab_data = PTRRELOC(&htab_data);
- HPTE *htab = (HPTE *)__v2a(_htab_data->htab);
-
- for (addr=start; addr < end ;addr+=0x1000) {
- unsigned long vsid = get_kernel_vsid(addr);
- unsigned long va = (vsid << 28) | (addr & 0xfffffff);
- make_pte(htab, va, __v2a(addr), mode, mask);
- }
}
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_IoMmTable.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_IoMmTable.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.c Fri Aug 24 06:41:08 2001
@@ -0,0 +1,187 @@
+/************************************************************************/
+/* This module supports the iSeries I/O Address translation mapping */
+/* Copyright (C) 20yy */
+/* */
+/* 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. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the: */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, */
+/* Boston, MA 02111-1307 USA */
+/************************************************************************/
+/* Change Activity: */
+/* Created, December 14, 2000 */
+/* Added Bar table for IoMm performance. */
+/* End Change Activity */
+/************************************************************************/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "iSeries_IoMmTable.h"
+#include "pci.h"
+
+void iSeries_allocateDeviceBars(struct pci_dev* PciDevPtr);
+/*******************************************************************/
+/* Table defines */
+/* Entry size is 4 MB * 1024 Entries = 4GB. */
+/*******************************************************************/
+#define iSeries_IoMmTable_Entry_Size 0x00400000
+#define iSeries_IoMmTable_Size 1024
+#define iSeries_Base_Io_Memory 0xFFFFFFFF
+
+/*******************************************************************/
+/* Static and Global variables */
+/*******************************************************************/
+struct pci_dev* iSeries_IoMmTable[iSeries_IoMmTable_Size];
+u8 iSeries_IoBarTable[iSeries_IoMmTable_Size];
+static int iSeries_CurrentIndex;
+static char* iSeriesPciIoText = "iSeries PCI I/O";
+static spinlock_t iSeriesIoMmTableLock = SPIN_LOCK_UNLOCKED;
+/*******************************************************************/
+/* iSeries_IoMmTable_Initialize */
+/*******************************************************************/
+/* - Initalizes the Address Translation Table and get it ready for */
+/* use. Must be called before any client calls any of the other */
+/* methods. */
+/*******************************************************************/
+void iSeries_IoMmTable_Initialize(void) {
+ int Index;
+ spin_lock(&iSeriesIoMmTableLock);
+ for(Index=0;Indexresource[BarNumber];
+ iSeries_IoMmTable_AllocateEntry(PciDev, BarNumber);
+ }
+}
+
+/*******************************************************************/
+/* iSeries_IoMmTable_AllocateEntry */
+/*******************************************************************/
+/* Adds pci_dev entry in address translation table */
+/*******************************************************************/
+/* - Allocates the number of entries required in table base on BAR */
+/* size. */
+/* - This version, allocates top down, starting at 4GB. */
+/* - The size is round up to be a multiple of entry size. */
+/* - CurrentIndex is decremented to keep track of the last entry. */
+/* - Builds the resource entry for allocated BARs. */
+/*******************************************************************/
+void iSeries_IoMmTable_AllocateEntry(struct pci_dev* PciDev, int BarNumber) {
+ struct resource* BarResource = &PciDev->resource[BarNumber];
+ int BarSize = BarResource->end - BarResource->start;
+ unsigned long BarStartAddr;
+ unsigned long BarEndAddr;
+ /***************************************************************/
+ /* No space to allocate, skip Allocation. */
+ /***************************************************************/
+ if(BarSize == 0) return; /* Quick stage exit */
+
+ /***************************************************************/
+ /* Allocate the table entries needed. */
+ /***************************************************************/
+ spin_lock(&iSeriesIoMmTableLock);
+ while(BarSize > 0) {
+ iSeries_IoMmTable[iSeries_CurrentIndex] = PciDev;
+ iSeries_IoBarTable[iSeries_CurrentIndex] = BarNumber;
+ BarSize -= iSeries_IoMmTable_Entry_Size;
+ --iSeries_CurrentIndex; /* Next Free entry */
+ }
+ spin_unlock(&iSeriesIoMmTableLock);
+ BarStartAddr = iSeries_IoMmTable_Entry_Size*(iSeries_CurrentIndex+1);
+ BarEndAddr = BarStartAddr + (BarResource->end - BarResource->start);
+ /***************************************************************/
+ /* Build Resource info */
+ /***************************************************************/
+ BarResource->name = iSeriesPciIoText;
+ BarResource->start = (long)BarStartAddr;
+ BarResource->end = (long)BarEndAddr;
+
+ PPCDBG(PPCDBG_BUSWALK,"BarAloc %04X-%016LX\n",iSeries_CurrentIndex+1,BarStartAddr);
+}
+/*******************************************************************/
+/* Translates an I/O Memory address to pci_dev* */
+/*******************************************************************/
+struct pci_dev* iSeries_xlateIoMmAddress(unsigned long* IoAddress) {
+ int PciDevIndex = (unsigned long)IoAddress/iSeries_IoMmTable_Entry_Size;
+ struct pci_dev* PciDev = iSeries_IoMmTable[PciDevIndex];
+ if(PciDev == 0) {
+ printk("PCI: Invalid I/O Address: 0x%016LX\n",IoAddress);
+ PCIFR("Invalid MMIO Address 0x%016LX",(unsigned long)IoAddress);
+ }
+ return PciDev;
+}
+/************************************************************************/
+/* Returns the Bar number of Address */
+/************************************************************************/
+int iSeries_IoMmTable_Bar(unsigned long* IoAddress) {
+ int BarIndex = (unsigned long)IoAddress/iSeries_IoMmTable_Entry_Size;
+ int BarNumber = iSeries_IoBarTable[BarIndex];
+ return BarNumber;
+}
+/************************************************************************/
+/* Return the Bar Base Address or 0. */
+/************************************************************************/
+unsigned long* iSeries_IoMmTable_BarBase(unsigned long* IoAddress) {
+ unsigned long BaseAddr = 0;
+ struct pci_dev* PciDev = iSeries_xlateIoMmAddress(IoAddress);
+ if(PciDev != NULL) {
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ if(BarNumber != -1) {
+ BaseAddr = PciDev->resource[BarNumber].start;
+ }
+ }
+ return (unsigned long*)BaseAddr;
+}
+/************************************************************************/
+/* Return the Bar offset within the Bar Space */
+/* Note: Assumes that address is valid. */
+/************************************************************************/
+unsigned long iSeries_IoMmTable_BarOffset(unsigned long* IoAddress) {
+ return (unsigned long)IoAddress-(unsigned long)iSeries_IoMmTable_BarBase(IoAddress);
+}
+/************************************************************************/
+/* Return 0 if Address is valid I/O Address */
+/************************************************************************/
+int iSeries_Is_IoMmAddress(unsigned long* IoAddress) {
+ if( iSeries_xlateIoMmAddress(IoAddress) == NULL) return 1;
+ else return 0;
+}
+
+
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_IoMmTable.h linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.h
--- linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_IoMmTable.h Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.h Fri Aug 24 06:41:08 2001
@@ -0,0 +1,99 @@
+#ifndef _ISERIES_IOMMTABLE_H
+#define _ISERIES_IOMMTABLE_H
+/************************************************************************/
+/* File iSeries_IoMmTable.h created by Allan Trautman on Dec 12 2001. */
+/************************************************************************/
+/* Interfaces for the write/read Io address translation table. */
+/* Copyright (C) 20yy Allan H Trautman, IBM Corporation */
+/* */
+/* 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. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the: */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, */
+/* Boston, MA 02111-1307 USA */
+/************************************************************************/
+/* Change Activity: */
+/* Created December 12, 2000 */
+/* End Change Activity */
+/************************************************************************/
+
+/************************************************************************/
+/* iSeries_IoMmTable_Initialize */
+/************************************************************************/
+/* - Initalizes the Address Translation Table and get it ready for use. */
+/* Must be called before any client calls any of the other methods. */
+/* */
+/* Parameters: None. */
+/* */
+/* Return: None. */
+/************************************************************************/
+extern void iSeries_IoMmTable_Initialize(void);
+
+/************************************************************************/
+/* iSeries_allocateDeviceBars */
+/************************************************************************/
+/* - Allocates ALL pci_dev BAR's and updates the resources with the BAR */
+/* value. BARS with zero length will not have the resources. The */
+/* HvCallPci_getBarParms is used to get the size of the BAR space. */
+/* It calls as400_IoMmTable_AllocateEntry to allocate each entry. */
+/* */
+/* Parameters: */
+/* pci_dev = Pointer to pci_dev structure that will be mapped to pseudo */
+/* I/O Address. */
+/* */
+/* Return: */
+/* The pci_dev I/O resources updated with pseudo I/O Addresses. */
+/************************************************************************/
+extern void iSeries_allocateDeviceBars(struct pci_dev* );
+
+/************************************************************************/
+/* iSeries_IoMmTable_AllocateEntry */
+/************************************************************************/
+/* - Allocates(adds) the pci_dev entry in the Address Translation Table */
+/* and updates the Resources for the device. */
+/* */
+/* Parameters: */
+/* pci_dev = Pointer to pci_dev structure that will be mapped to pseudo */
+/* I/O Address. */
+/* */
+/* BarNumber = Which Bar to be allocated. */
+/* */
+/* Return: */
+/* The pseudo I/O Address in the resources that will map to the */
+/* pci_dev on iSeries_xlateIoMmAddress call. */
+/************************************************************************/
+extern void iSeries_IoMmTable_AllocateEntry(struct pci_dev* , int BarNumber);
+
+/************************************************************************/
+/* iSeries_xlateIoMmAddress */
+/************************************************************************/
+/* - Translates an I/O Memory address to pci_dev that has been allocated*/
+/* the psuedo I/O Address. */
+/* */
+/* Parameters: */
+/* IoAddress = I/O Memory Address. */
+/* */
+/* Return: */
+/* A pci_dev pointer to the device mapped to the I/O address. */
+/************************************************************************/
+extern struct pci_dev* iSeries_xlateIoMmAddress(unsigned long* IoAddress);
+
+/************************************************************************/
+/* Helper Methods */
+/************************************************************************/
+extern int iSeries_IoMmTable_Bar(unsigned long *IoAddress);
+extern unsigned long* iSeries_IoMmTable_BarBase(unsigned long* IoAddress);
+extern unsigned long iSeries_IoMmTable_BarOffset(unsigned long* IoAddress);
+extern int iSeries_Is_IoMmAddress(unsigned long* IoAddress);
+
+#endif /* _ISERIES_IOMMTABLE_H */
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_VpdInfo.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_VpdInfo.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_VpdInfo.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_VpdInfo.c Fri Aug 24 06:41:08 2001
@@ -0,0 +1,360 @@
+/************************************************************************/
+/* File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. */
+/************************************************************************/
+/* This code gets the card location of the hardware */
+/* Copyright (C) 20yy */
+/* */
+/* 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. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the: */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, */
+/* Boston, MA 02111-1307 USA */
+/************************************************************************/
+/* Change Activity: */
+/* Created, Feb 2, 2001 */
+/* Ported to ppc64, August 20, 2001 */
+/* End Change Activity */
+/************************************************************************/
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "pci.h"
+
+/************************************************/
+/* Size of Bus VPD data */
+/************************************************/
+#define BUS_VPDSIZE 1024
+/************************************************/
+/* Bus Vpd Tags */
+/************************************************/
+#define VpdEndOfDataTag 0x78
+#define VpdEndOfAreaTag 0x79
+#define VpdIdStringTag 0x82
+#define VpdVendorAreaTag 0x84
+/************************************************/
+/* Mfg Area Tags */
+/************************************************/
+#define VpdAsmPartNumber 0x504E // "PN"
+#define VpdFruFlag 0x4647 // "FG"
+#define VpdFruLocation 0x464C // "FL"
+#define VpdFruFrameId 0x4649 // "FI"
+#define VpdFruPartNumber 0x464E // "FN"
+#define VpdFruPowerData 0x5052 // "PR"
+#define VpdFruSerial 0x534E // "SN"
+#define VpdFruType 0x4343 // "CC"
+#define VpdFruCcinExt 0x4345 // "CE"
+#define VpdFruRevision 0x5256 // "RV"
+#define VpdSlotMapFormat 0x4D46 // "MF"
+#define VpdSlotMap 0x534D // "SM"
+
+/************************************************/
+/* Structures of the areas */
+/************************************************/
+struct BusVpdAreaStruct {
+ u8 Tag;
+ u8 LowLength;
+ u8 HighLength;
+};
+typedef struct BusVpdAreaStruct BusVpdArea;
+#define BUS_ENTRY_SIZE 3
+
+struct MfgVpdAreaStruct {
+ u16 Tag;
+ u8 TagLength;
+};
+typedef struct MfgVpdAreaStruct MfgVpdArea;
+#define MFG_ENTRY_SIZE 3
+
+struct SlotMapFormatStruct {
+ u16 Tag;
+ u8 TagLength;
+ u16 Format;
+};
+
+struct FrameIdMapStruct{
+ u16 Tag;
+ u8 TagLength;
+ u8 FrameId;
+};
+typedef struct FrameIdMapStruct FrameIdMap;
+
+struct SlotMapStruct {
+ u8 AgentId;
+ u8 SecondaryAgentId;
+ u8 PhbId;
+ char CardLocation[3];
+ char Parms[8];
+ char Reserved[2];
+};
+typedef struct SlotMapStruct SlotMap;
+#define SLOT_ENTRY_SIZE 16
+
+/****************************************************************/
+/* Prototypes */
+/****************************************************************/
+static void iSeries_Parse_Vpd(BusVpdArea*, int, LocationData*);
+static void iSeries_Parse_MfgArea(MfgVpdArea*,int, LocationData*);
+static void iSeries_Parse_SlotArea(SlotMap*, int, LocationData*);
+static void iSeries_Parse_PhbId(BusVpdArea*, int, LocationData*);
+
+/****************************************************************
+ * iSeries_loc-code(struct pci_dev* PciDev) *
+ * *
+ * Gets the frame and card location of the pci_dev device. The *
+ * return is a kmalloc string. The user must free this string *
+ * when they are done. This is specifically for the device tree*
+ * *
+ * Returns: *
+ * "Frame 1, Card C10" *
+ ****************************************************************/
+char* iSeries_Location_Code(struct pci_dev* PciDev) {
+ char TempBuffer[128];
+ LocationData* LocationPtr = iSeries_GetLocationData(PciDev);
+ int LineLen = sprintf(TempBuffer," Frame%3d, Card %4s ",
+ LocationPtr->FrameId,LocationPtr->CardLocation);
+ char* RtnString = kmalloc(LineLen+7,GFP_KERNEL);
+ strcpy(RtnString,TempBuffer);
+ kfree(LocationPtr);
+ return RtnString;
+}
+/****************************************************************/
+/* */
+/* */
+/* */
+/****************************************************************/
+LocationData* iSeries_GetLocationData(struct pci_dev* PciDev) {
+ LocationData* LocationPtr = 0;
+ BusVpdArea* BusVpdPtr = 0;
+ int BusVpdLen = 0;
+ BusVpdPtr = (BusVpdArea*)kmalloc(BUS_VPDSIZE, GFP_KERNEL);
+ BusVpdLen = HvCallPci_getBusVpd(PciDev->bus->number,REALADDR(BusVpdPtr),BUS_VPDSIZE);
+ /* printk("PCI: VpdBuffer 0x%08X \n",(int)BusVpdPtr); */
+ /***************************************************************/
+ /* Need to set Agent Id, Bus in location info before the call */
+ /***************************************************************/
+ LocationPtr = (LocationData*)kmalloc(LOCATION_DATA_SIZE, GFP_KERNEL);
+ LocationPtr->Bus = PciDev->bus->number;
+ LocationPtr->Board = 0;
+ LocationPtr->FrameId = 0;
+ iSeries_Parse_PhbId(BusVpdPtr,BusVpdLen,LocationPtr);
+ LocationPtr->Card = PCI_SLOT(PciDev->devfn);
+ strcpy(LocationPtr->CardLocation,"Cxx");
+ LocationPtr->AgentId = ISERIES_DECODE_DEVICE(PciDev->devfn);
+ LocationPtr->SecondaryAgentId = 0x10;
+ /* And for Reference only. */
+ LocationPtr->LinuxBus = PciDev->bus->number;
+ LocationPtr->LinuxDevFn = PciDev->devfn;
+ /***************************************************************/
+ /* Any data to process? */
+ /***************************************************************/
+ if(BusVpdLen > 0) {
+ iSeries_Parse_Vpd(BusVpdPtr, BUS_VPDSIZE, LocationPtr);
+ }
+ else {
+ PCIFR("No VPD Data....");
+ }
+ kfree(BusVpdPtr);
+
+ return LocationPtr;
+}
+/****************************************************************/
+/* */
+/****************************************************************/
+void iSeries_Parse_Vpd(BusVpdArea* VpdData,int VpdLen, LocationData* LocationPtr) {
+ MfgVpdArea* MfgVpdPtr = 0;
+ int BusTagLen = 0;
+ BusVpdArea* BusVpdPtr = VpdData;
+ int BusVpdLen = VpdLen;
+ /*************************************************************/
+ /* Make sure this is what I think it is */
+ /*************************************************************/
+ if(BusVpdPtr->Tag != VpdIdStringTag) { /*0x82 */
+ PCIFR("Not 0x82 start of VPD.");
+ return;
+ }
+ BusTagLen = (BusVpdPtr->HighLength*256)+BusVpdPtr->LowLength;
+ BusTagLen += BUS_ENTRY_SIZE;
+ BusVpdPtr = (BusVpdArea*)((u32)BusVpdPtr+BusTagLen);
+ BusVpdLen -= BusTagLen;
+ /*************************************************************/
+ /* Parse the Data */
+ /*************************************************************/
+ while(BusVpdLen > 0 ) {
+ BusTagLen = (BusVpdPtr->HighLength*256)+BusVpdPtr->LowLength;
+ /*********************************************************/
+ /* End of data Found */
+ /*********************************************************/
+ if(BusVpdPtr->Tag == VpdEndOfAreaTag) {
+ BusVpdLen = 0; /* Done, Make sure */
+ }
+ /*********************************************************/
+ /* Was Mfg Data Found */
+ /*********************************************************/
+ else if(BusVpdPtr->Tag == VpdVendorAreaTag) {
+ MfgVpdPtr = (MfgVpdArea*)((u32)BusVpdPtr+BUS_ENTRY_SIZE);
+ iSeries_Parse_MfgArea(MfgVpdPtr,BusTagLen,LocationPtr);
+ }
+ /********************************************************/
+ /* On to the next tag. */
+ /********************************************************/
+ if(BusVpdLen > 0) {
+ BusTagLen += BUS_ENTRY_SIZE;
+ BusVpdPtr = (BusVpdArea*)((u32)BusVpdPtr+BusTagLen);
+ BusVpdLen -= BusTagLen;
+ }
+ }
+}
+
+/*****************************************************************/
+/* Parse the Mfg Area */
+/*****************************************************************/
+void iSeries_Parse_MfgArea(MfgVpdArea* VpdDataPtr,int VpdLen, LocationData* LocationPtr) {
+ SlotMap* SlotMapPtr = 0;
+ u16 SlotMapFmt = 0;
+ int MfgTagLen = 0;
+ MfgVpdArea* MfgVpdPtr = VpdDataPtr;
+ int MfgVpdLen = VpdLen;
+
+ /*************************************************************/
+ /* Parse Mfg Data */
+ /*************************************************************/
+ while(MfgVpdLen > 0) {
+ MfgTagLen = MfgVpdPtr->TagLength;
+ if (MfgVpdPtr->Tag == VpdFruFlag) {} /* FG */
+ else if(MfgVpdPtr->Tag == VpdFruSerial) {} /* SN */
+ else if(MfgVpdPtr->Tag == VpdAsmPartNumber){} /* PN */
+ /*********************************************************/
+ /* Frame ID */
+ /*********************************************************/
+ if(MfgVpdPtr->Tag == VpdFruFrameId) { /* FI */
+ LocationPtr->FrameId = ((FrameIdMap*)MfgVpdPtr)->FrameId;
+ }
+ /*********************************************************/
+ /* Slot Map Format */
+ /*********************************************************/
+ else if(MfgVpdPtr->Tag == VpdSlotMapFormat){ /* MF */
+ SlotMapFmt = ((struct SlotMapFormatStruct*)MfgVpdPtr)->Format;
+ }
+ /*********************************************************/
+ /* Slot Labels */
+ /*********************************************************/
+ else if(MfgVpdPtr->Tag == VpdSlotMap){ /* SM */
+ if(SlotMapFmt == 0x1004) SlotMapPtr = (SlotMap*)((u32)MfgVpdPtr+MFG_ENTRY_SIZE+1);
+ else SlotMapPtr = (SlotMap*)((u32)MfgVpdPtr+MFG_ENTRY_SIZE);
+ iSeries_Parse_SlotArea(SlotMapPtr,MfgTagLen, LocationPtr);
+ }
+ /*********************************************************/
+ /* Point to the next Mfg Area */
+ /* Use defined size, sizeof give wrong answer */
+ /*********************************************************/
+ MfgTagLen += MFG_ENTRY_SIZE;
+ MfgVpdPtr = (MfgVpdArea*)( (u32)MfgVpdPtr + MfgTagLen);
+ MfgVpdLen -= MfgTagLen;
+ }
+}
+/*****************************************************************/
+/* Look for "BUS" Tag to set the PhbId. */
+/*****************************************************************/
+void iSeries_Parse_PhbId(BusVpdArea* VpdData,int VpdLen,LocationData* LocationPtr) {
+ int PhbId = 0xff; /* Not found flag */
+ char* PhbPtr = (char*)VpdData+3; /* Skip over 82 tag */
+ int DataLen = VpdLen;
+ while(DataLen > 0) {
+ if(*PhbPtr == 'B' && *(PhbPtr+1) == 'U' && *(PhbPtr+2) == 'S') {
+ if(*(PhbPtr+3) == ' ') PhbPtr += 4;/* Skip white spac*/
+ else PhbPtr += 3;
+ if (*PhbPtr == '0') PhbId = 0; /* Don't convert, */
+ else if(*PhbPtr == '1') PhbId = 1; /* Sanity check */
+ else if(*PhbPtr == '2') PhbId = 2; /* values */
+ DataLen = 0; /* Exit loop. */
+ }
+ ++PhbPtr;
+ --DataLen;
+ }
+ LocationPtr->PhbId = PhbId;
+}
+/*****************************************************************/
+/* Parse the Slot Area */
+/*****************************************************************/
+void iSeries_Parse_SlotArea(SlotMap* MapPtr,int MapLen, LocationData* LocationPtr) {
+ int SlotMapLen = MapLen;
+ SlotMap* SlotMapPtr = MapPtr;
+ /*************************************************************/
+ /* Parse Slot label until we find the one requrested */
+ /*************************************************************/
+ while(SlotMapLen > 0) {
+ if(SlotMapPtr->AgentId == LocationPtr->AgentId &&
+ SlotMapPtr->SecondaryAgentId == LocationPtr->SecondaryAgentId) {
+ /*****************************************************/
+ /* If Phb wasn't found, grab the first one found. */
+ /*****************************************************/
+ if(LocationPtr->PhbId == 0xff) LocationPtr->PhbId = SlotMapPtr->PhbId;
+ if( SlotMapPtr->PhbId == LocationPtr->PhbId ) {
+ /*****************************************************/
+ /* Found what we were looking for, extract the data. */
+ /*****************************************************/
+ memcpy(&LocationPtr->CardLocation,&SlotMapPtr->CardLocation,3);
+ LocationPtr->CardLocation[3] = 0; /* Null terminate*/
+ SlotMapLen = 0; /* We are done */
+ }
+ }
+ /*********************************************************/
+ /* Point to the next Slot */
+ /* Use defined size, sizeof may give wrong answer */
+ /*********************************************************/
+ SlotMapLen -= SLOT_ENTRY_SIZE;
+ SlotMapPtr = (SlotMap*)((u32)SlotMapPtr+SLOT_ENTRY_SIZE);
+ }
+}
+/************************************************************************/
+/* Formats the device information. */
+/* - Pass in pci_dev* pointer to the device. */
+/* - Pass in buffer to place the data. Danger here is the buffer must */
+/* be as big as the client says it is. Should be at least 128 bytes.*/
+/* Return will the length of the string data put in the buffer. */
+/* Format: */
+/* PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet */
+/* controller */
+/************************************************************************/
+int iSeries_Device_Information(struct pci_dev* PciDev,char* Buffer, int BufferSize) {
+ LocationData* LocationPtr; /* VPD Information */
+ char* BufPtr = Buffer;
+ int LineLen = 0;
+ if(BufferSize >= 128) {
+ LineLen = sprintf(BufPtr+LineLen,"PCI: Bus%3d, Device%3d, Vendor %04X ",
+ PciDev->bus->number, PCI_SLOT(PciDev->devfn),PciDev->vendor);
+
+ LocationPtr = iSeries_GetLocationData(PciDev);
+ LineLen += sprintf(BufPtr+LineLen," Frame%3d, Card %4s ",
+ LocationPtr->FrameId,LocationPtr->CardLocation);
+ kfree(LocationPtr);
+
+ if(pci_class_name(PciDev->class >> 8) == 0) {
+ LineLen += sprintf(BufPtr+LineLen,"0x%04X ",(int)(PciDev->class >> 8));
+ }
+ else {
+ LineLen += sprintf(BufPtr+LineLen,"%s",pci_class_name(PciDev->class >> 8) );
+ }
+ }
+ return LineLen;
+}
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_setup.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/iSeries_setup.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_setup.c Fri Aug 24 09:49:43 2001
@@ -54,7 +54,7 @@
extern void abort(void);
static void build_iSeries_Memory_Map( void );
static void setup_iSeries_cache_sizes( void );
-static void iSeries_bolt_kernel( unsigned long pages_to_bolt );
+static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
extern void ppcdbg_initialize(void);
/* Global Variables */
@@ -92,7 +92,7 @@
*/
if ( naca->xRamDisk ) {
- initrd_start = __va(naca->xRamDisk);
+ initrd_start = (unsigned long)__va(naca->xRamDisk);
initrd_end = initrd_start + naca->xRamDiskSize * PAGE_SIZE;
initrd_below_start_ok = 1; // ramdisk in kernel space
ROOT_DEV = MKDEV( RAMDISK_MAJOR, 0 );
@@ -243,7 +243,7 @@
loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
loadAreaSize = itLpNaca.xLoadAreaChunks;
-
+
/* Only add the pages already mapped here.
* Otherwise we might add the hpt pages
* The rest of the pages of the load area
@@ -256,7 +256,7 @@
loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;
printk( "Mapping load area - physical addr = 0000000000000000\n"
- " absolute addr = %016x\n",
+ " absolute addr = %016lx\n",
chunk_to_addr(loadAreaFirstChunk) );
printk( "Load area size %dK\n", loadAreaSize*256 );
@@ -275,7 +275,7 @@
hptSizeChunks = hptSizePages >> (msChunks.chunk_shift-PAGE_SHIFT);
hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
- printk( "HPT absolute addr = %016x, size = %dK\n",
+ printk( "HPT absolute addr = %016lx, size = %dK\n",
chunk_to_addr(hptFirstChunk), hptSizeChunks*256 );
/* Fill in the htab_data structure */
@@ -289,7 +289,7 @@
htab_data.htab = NULL;
/* Update the page table to bolt the kernel */
- iSeries_bolt_kernel( __pa(((unsigned long)_end + PAGE_SIZE) & ~PAGE_SIZE) >> PAGE_SHIFT );
+ iSeries_bolt_kernel( 0, __pa(PAGE_ALIGN((unsigned long)_end)) );
/* Determine if absolute memory has any
* holes so that we can interpret the
@@ -357,6 +357,13 @@
* nextPhysChunk
*/
naca->physicalMemorySize = chunk_to_addr(nextPhysChunk);
+
+ iSeries_bolt_kernel( __pa(PAGE_ALIGN((unsigned long)_end)), naca->physicalMemorySize );
+
+ lmb_init();
+ lmb_add( 0, naca->physicalMemorySize );
+ lmb_reserve( 0, __pa(klimit));
+
}
/*
@@ -390,22 +397,27 @@
}
/*
- * Bolt the kernel (text and data) into the HPT
+ * Bolt the kernel addr space into the HPT
*/
-static void __init iSeries_bolt_kernel( unsigned long pages_to_bolt )
+static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
{
- unsigned long vsid, va, vpn, slot, i;
+ unsigned long pa;
+ unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
HPTE hpte;
- for ( i=0; i> PAGE_SHIFT;
- slot = HvCallHpt_findValid( &hpte, vpn );
+ for (pa=saddr; pa < eaddr ;pa+=PAGE_SIZE) {
+ unsigned long ea = __va(pa);
+ unsigned long vsid = get_kernel_vsid( ea );
+ unsigned long va = ( vsid << 28 ) | ( pa & 0xfffffff );
+ unsigned long vpn = va >> PAGE_SHIFT;
+ unsigned long slot = HvCallHpt_findValid( &hpte, vpn );
if ( hpte.dw0.dw0.v ) {
- /* Mark the page as bolted */
+ /* HPTE exists, so just bolt it */
HvCallHpt_setSwBits( slot, 0x10, 0 );
+ } else {
+ /* No HPTE exists, so create a new bolted one */
+ build_valid_hpte(vsid, ea, pa, NULL, mode_rw, 1);
}
}
}
@@ -502,6 +514,77 @@
return (len);
}
+#ifdef CONFIG_SMP
+void iSeries_spin_lock(spinlock_t *lock)
+{
+ int i;
+ for (;;) {
+ for (i=1024; i>0; --i) {
+ HMT_low();
+ if ( lock->lock == 0 ) {
+ HMT_medium();
+ if ( __spin_trylock(lock) )
+ return;
+ }
+ }
+ HMT_medium();
+ HvCallCfg_getLps();
+ }
+}
+
+void iSeries_read_lock(__rwlock_t *rw)
+{
+ int i;
+ for (;;) {
+ for (i=1024; i>0; --i) {
+ HMT_low();
+ if ( rw->lock >= 0 ) {
+ HMT_medium();
+ if ( __read_trylock(rw) )
+ return;
+ }
+ }
+ HMT_medium();
+ HvCallCfg_getLps();
+ }
+}
+
+void iSeries_write_lock(__rwlock_t *rw)
+{
+ int i;
+ for (;;) {
+ for (i=1024; i>0; --i) {
+ HMT_low();
+ if ( rw->lock == 0 ) {
+ HMT_medium();
+ if ( __write_trylock(rw) )
+ return;
+ }
+ }
+ HMT_medium();
+ HvCallCfg_getLps();
+ }
+}
+
+void iSeries_brlock_spin( spinlock_t *lock )
+{
+ int i;
+ for(;;) {
+ for (i=1024; i>0; --i) {
+ HMT_low();
+ if (lock->lock == 0) {
+ HMT_medium();
+ return;
+ }
+
+ }
+ HMT_medium();
+ HvCallCfg_getLps();
+ }
+}
+
+#endif /* CONFIG_SMP */
+
int iSeries_get_cpuinfo(char *buffer)
{
int len = 0;
@@ -605,7 +688,7 @@
* Set the RTC in the virtual service processor
* This requires flowing LpEvents to the primary partition
*/
-int __init
+int
iSeries_set_rtc_time(unsigned long time)
{
mf_setRtcTime(time);
@@ -616,7 +699,7 @@
* Get the RTC from the virtual service processor
* This requires flowing LpEvents to the primary partition
*/
-unsigned long __init
+unsigned long
iSeries_get_rtc_time(void)
{
unsigned long time;
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/idle.c linuxppc64_2_4/arch/ppc64/kernel/idle.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/idle.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/idle.c Wed Aug 15 08:37:55 2001
@@ -31,41 +31,91 @@
#include
#include
-static void power_save(void)
+#include
+#include
+#include
+
+unsigned long maxYieldTime = 0;
+unsigned long minYieldTime = 0xffffffffffffffffUL;
+
+static void yield_shared_processor(void)
{
- /* Implement me */ ;
+ struct Paca *paca;
+ unsigned long tb;
+ unsigned long yieldTime;
+
+ /* Turn off the run light */
+ unsigned long CTRL;
+ CTRL = mfspr(CTRLF);
+ CTRL &= ~RUNLATCH;
+ mtspr(CTRLT, CTRL);
+
+ HMT_low();
+
+ paca = (struct Paca *)mfspr(SPRG3);
+ HvCall_setEnabledInterrupts( HvCall_MaskIPI |
+ HvCall_MaskLpEvent |
+ HvCall_MaskLpProd |
+ HvCall_MaskTimeout );
+
+ __cli();
+ __sti();
+ tb = get_tb();
+ /* Compute future tb value when yield should expire */
+ HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
+
+ yieldTime = get_tb() - tb;
+ if ( yieldTime > maxYieldTime )
+ maxYieldTime = yieldTime;
+
+ if ( yieldTime < minYieldTime )
+ minYieldTime = yieldTime;
+
+ /*
+ * disable/enable will force any pending interrupts
+ * to be seen.
+ */
+ __cli();
+ /*
+ * The decrementer stops during the yield. Just force
+ * a fake decrementer now and the timer interrupt code
+ * will straighten it all out. We have to do this
+ * while disabled so we don't do it between where it is
+ * checked and where it is reset.
+ */
+
+ paca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+ __sti();
}
int idled(void)
{
- int do_power_save = 0;
+ struct Paca *paca;
+ long oldval;
/* endless loop with no priority at all */
current->nice = 20;
current->counter = -100;
init_idle();
- for (;;) {
-#ifdef CONFIG_SMP
- int oldval;
+ paca = (struct Paca *)mfspr(SPRG3);
- if (!do_power_save) {
- /*
- * Deal with another CPU just having chosen a thread to
- * run here:
- */
+ for (;;) {
+
+ if ( paca->xLpPaca.xSharedProc ) {
+ if ( !current->need_resched )
+ yield_shared_processor();
+ }
+ else {
+ /* Avoid an IPI by setting need_resched */
oldval = xchg(¤t->need_resched, -1);
-
if (!oldval) {
while(current->need_resched == -1)
- ; /* Do Nothing */
+ HMT_low();
}
}
-#endif
- if (do_power_save && !current->need_resched)
- power_save();
-
if (current->need_resched) {
+ HMT_medium();
schedule();
check_pgt_cache();
}
@@ -82,3 +132,5 @@
idled();
return 0;
}
+
+
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/irq.c linuxppc64_2_4/arch/ppc64/kernel/irq.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/irq.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/irq.c Mon Aug 13 10:40:21 2001
@@ -526,7 +526,8 @@
{
int cpu = smp_processor_id();
int irq;
- unsigned long flags;
+ struct Paca * paca;
+ struct ItLpQueue * lpq;
/* if(cpu) udbg_printf("Entering do_IRQ\n"); */
@@ -556,23 +557,23 @@
}
/* if on iSeries partition */
else {
+ paca = (struct Paca *)mfspr(SPRG3);
#ifdef CONFIG_SMP
- if ( xPaca[cpu].xLpPacaPtr->xIpiCnt ) {
- xPaca[cpu].xLpPacaPtr->xIpiCnt = 0;
+ if ( paca->xLpPaca.xIntDword.xFields.xIpiCnt ) {
+ paca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
iSeries_smp_message_recv( regs );
}
#endif /* CONFIG_SMP */
- __no_use_save_flags( &flags );
- __no_use_cli();
- lpEvent_count += ItLpQueue_process( &xItLpQueue, regs );
- __no_lpq_restore_flags( flags );
+ lpq = paca->lpQueuePtr;
+ if ( lpq )
+ lpEvent_count += ItLpQueue_process( lpq, regs );
}
irq_exit(cpu);
if ( _machine == _MACH_iSeries ) {
- if ( xPaca[cpu].xLpPacaPtr->xDecrInt ) {
- xPaca[cpu].xLpPacaPtr->xDecrInt = 0;
+ if ( paca->xLpPaca.xIntDword.xFields.xDecrInt ) {
+ paca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
/* Signal a fake decrementer interrupt */
timer_interrupt( regs );
}
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/lmb.c linuxppc64_2_4/arch/ppc64/kernel/lmb.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/lmb.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/lmb.c Wed Aug 15 15:36:41 2001
@@ -21,7 +21,8 @@
extern unsigned long klimit;
extern unsigned long reloc_offset(void);
-static long lmb_add_region(struct lmb_region *, unsigned long, unsigned long);
+
+static long lmb_add_region(struct lmb_region *, unsigned long, unsigned long, unsigned long);
struct lmb lmb = {
0,
@@ -39,7 +40,9 @@
rgn->region[r1].size += rgn->region[r2].size;
for(i=r2; i < rgn->cnt-1 ;i++) {
rgn->region[i].base = rgn->region[i+1].base;
+ rgn->region[i].physbase = rgn->region[i+1].physbase;
rgn->region[i].size = rgn->region[i+1].size;
+ rgn->region[i].type = rgn->region[i+1].type;
}
rgn->cnt--;
}
@@ -57,11 +60,13 @@
*/
_lmb->memory.region[0].base = 0;
_lmb->memory.region[0].size = 0;
+ _lmb->memory.region[0].type = LMB_MEMORY_AREA;
_lmb->memory.cnt = 1;
/* Ditto. */
_lmb->reserved.region[0].base = 0;
_lmb->reserved.region[0].size = 0;
+ _lmb->reserved.region[0].type = LMB_MEMORY_AREA;
_lmb->reserved.cnt = 1;
}
@@ -69,14 +74,20 @@
void
lmb_analyze(void)
{
- unsigned long i;
- unsigned long size_mask = 0;
+ unsigned long i, physbase = 0;
unsigned long total_size = 0;
+ unsigned long size_mask = 0;
unsigned long offset = reloc_offset();
struct lmb *_lmb = PTRRELOC(&lmb);
for(i=0; i < _lmb->memory.cnt ;i++) {
unsigned long lmb_size = _lmb->memory.region[i].size;
+#ifdef CONFIG_MSCHUNKS
+ _lmb->memory.region[i].physbase = physbase;
+ physbase += lmb_size;
+#else
+ _lmb->memory.region[i].physbase = _lmb->memory.region[i].base;
+#endif
total_size += lmb_size;
size_mask |= lmb_size;
}
@@ -92,7 +103,20 @@
struct lmb *_lmb = PTRRELOC(&lmb);
struct lmb_region *_rgn = &(_lmb->memory);
- return lmb_add_region(_rgn, base, size);
+ return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA);
+
+}
+
+/* This routine called with relocation disabled. */
+long
+lmb_add_io(unsigned long base, unsigned long size)
+{
+ unsigned long offset = reloc_offset();
+ struct lmb *_lmb = PTRRELOC(&lmb);
+ struct lmb_region *_rgn = &(_lmb->memory);
+
+ return lmb_add_region(_rgn, base, size, LMB_IO_AREA);
+
}
long
@@ -102,20 +126,27 @@
struct lmb *_lmb = PTRRELOC(&lmb);
struct lmb_region *_rgn = &(_lmb->reserved);
- return lmb_add_region(_rgn, base, size);
+ return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA);
}
/* This routine called with relocation disabled. */
static long
-lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
+lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size,
+ unsigned long type)
{
unsigned long i, coalesced = 0;
+ long adjacent;
/* First try and coalesce this LMB with another. */
for(i=0; i < rgn->cnt ;i++) {
unsigned long rgnbase = rgn->region[i].base;
unsigned long rgnsize = rgn->region[i].size;
- long adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
+ unsigned long rgntype = rgn->region[i].type;
+
+ if ( rgntype != type )
+ continue;
+
+ adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
if ( adjacent > 0 ) {
rgn->region[i].base -= size;
rgn->region[i].physbase -= size;
@@ -147,10 +178,12 @@
rgn->region[i+1].base = rgn->region[i].base;
rgn->region[i+1].physbase = rgn->region[i].physbase;
rgn->region[i+1].size = rgn->region[i].size;
+ rgn->region[i+1].type = rgn->region[i].type;
} else {
rgn->region[i+1].base = base;
rgn->region[i+1].physbase = lmb_abs_to_phys(base);
rgn->region[i+1].size = size;
+ rgn->region[i+1].type = type;
break;
}
}
@@ -181,15 +214,19 @@
{
long i, j;
unsigned long base;
- unsigned long lmbbase, lmbsize;
unsigned long offset = reloc_offset();
struct lmb *_lmb = PTRRELOC(&lmb);
struct lmb_region *_mem = &(_lmb->memory);
struct lmb_region *_rsv = &(_lmb->reserved);
for(i=_mem->cnt-1; i >= 0 ;i--) {
- lmbbase = _mem->region[i].base;
- lmbsize = _mem->region[i].size;
+ unsigned long lmbbase = _mem->region[i].base;
+ unsigned long lmbsize = _mem->region[i].size;
+ unsigned long lmbtype = _mem->region[i].type;
+
+ if ( lmbtype != LMB_MEMORY_AREA )
+ continue;
+
base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
while ( (lmbbase <= base) &&
@@ -201,16 +238,28 @@
break;
}
- if ( i < 0 ) {
+ if ( i < 0 )
return 0;
- }
- lmb_add_region(_rsv, base, size);
+ lmb_add_region(_rsv, base, size, LMB_MEMORY_AREA);
return base;
}
unsigned long
+lmb_phys_mem_size(void)
+{
+ unsigned long offset = reloc_offset();
+ struct lmb *_lmb = PTRRELOC(&lmb);
+ struct lmb_region *_mem = &(_lmb->memory);
+ unsigned long idx = _mem->cnt-1;
+ unsigned long lastbase = _mem->region[idx].physbase;
+ unsigned long lastsize = _mem->region[idx].size;
+
+ return (lastbase + lastsize);
+}
+
+unsigned long
lmb_end_of_DRAM(void)
{
unsigned long offset = reloc_offset();
@@ -248,4 +297,46 @@
return pa;
}
+void
+lmb_dump(char *str)
+{
+ unsigned long i;
+
+ udbg_printf("\nlmb_dump: %s\n", str);
+ udbg_printf(" debug = %s\n",
+ (lmb.debug) ? "TRUE" : "FALSE");
+ udbg_printf(" memory.cnt = %d\n",
+ lmb.memory.cnt);
+ udbg_printf(" memory.size = 0x%lx\n",
+ lmb.memory.size);
+ udbg_printf(" memory.lcd_size = 0x%lx\n",
+ lmb.memory.lcd_size);
+ for(i=0; i < lmb.memory.cnt ;i++) {
+ udbg_printf(" memory.region[%d].base = 0x%lx\n",
+ i, lmb.memory.region[i].base);
+ udbg_printf(" .physbase = 0x%lx\n",
+ lmb.memory.region[i].physbase);
+ udbg_printf(" .size = 0x%lx\n",
+ lmb.memory.region[i].size);
+ udbg_printf(" .type = 0x%lx\n",
+ lmb.memory.region[i].type);
+ }
+ udbg_printf("\n");
+ udbg_printf(" reserved.cnt = %d\n",
+ lmb.reserved.cnt);
+ udbg_printf(" reserved.size = 0x%lx\n",
+ lmb.reserved.size);
+ udbg_printf(" reserved.lcd_size = 0x%lx\n",
+ lmb.reserved.lcd_size);
+ for(i=0; i < lmb.reserved.cnt ;i++) {
+ udbg_printf(" reserved.region[%d].base = 0x%lx\n",
+ i, lmb.reserved.region[i].base);
+ udbg_printf(" .physbase = 0x%lx\n",
+ lmb.reserved.region[i].physbase);
+ udbg_printf(" .size = 0x%lx\n",
+ lmb.reserved.region[i].size);
+ udbg_printf(" .type = 0x%lx\n",
+ lmb.reserved.region[i].type);
+ }
+}
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/mf.c linuxppc64_2_4/arch/ppc64/kernel/mf.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/mf.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/mf.c Wed Aug 15 08:38:20 2001
@@ -1019,45 +1019,6 @@
int mf_setRtcTime(unsigned long time)
{
-/*
- char ceTime[12] = "\x00\x00\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00";
- int rc = 0;
- struct rtc_time tm;
- u16 year;
- u8 day, mon, hour, min, sec, y1, y2;
-
- to_tm(time, &tm);
-
- year = tm.tm_year;
- y1 = (year >> 8) & 0x00FF;
- y2 = year & 0x00FF;
-
- 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(y1);
- BIN_TO_BCD(y2);
-
- year = y1 * 100 + y2;
- day = tm.tm_mday;
- mon = tm.tm_mon;
- hour = tm.tm_hour;
- min = tm.tm_min;
- sec = tm.tm_sec;
-
- memcpy(ceTime + 4, &year, 2);
- memcpy(ceTime + 6, &sec, 1);
- memcpy(ceTime + 7, &min, 1);
- memcpy(ceTime + 8, &hour, 1);
- memcpy(ceTime + 10, &day, 1);
- memcpy(ceTime + 11, &mon, 1);
-
- rc = signalCEMsg( ceTime, NULL );
-
- return rc;
-*/
struct rtc_time tm;
to_tm(time, &tm);
@@ -1067,7 +1028,7 @@
struct RtcTimeData
{
- volatile int xDone;
+ struct semaphore *xSemaphore;
struct CeMsgData xCeMsg;
int xRc;
};
@@ -1079,7 +1040,7 @@
memcpy(&(rtc->xCeMsg), ceMsg, sizeof(rtc->xCeMsg));
rtc->xRc = 0;
- rtc->xDone = 1;
+ up(rtc->xSemaphore);
}
static unsigned long lastsec = 1;
@@ -1129,14 +1090,16 @@
int mf_getRtc( struct rtc_time * tm )
{
-
struct CeMsgCompleteData ceComplete;
struct RtcTimeData rtcData;
int rc = 0;
+ DECLARE_MUTEX_LOCKED(Semaphore);
memset(&ceComplete, 0, sizeof(ceComplete));
memset(&rtcData, 0, sizeof(rtcData));
+ rtcData.xSemaphore = &Semaphore;
+
ceComplete.xHdlr = &getRtcTimeComplete;
ceComplete.xToken = (void *)&rtcData;
@@ -1144,13 +1107,22 @@
if ( rc == 0 )
{
- while( rtcData.xDone != 1 )
- {
- udelay(10);
- }
+ down(&Semaphore);
if ( rtcData.xRc == 0)
{
+ if ( ( rtcData.xCeMsg.xCEMsg[2] == 0xa9 ) ||
+ ( rtcData.xCeMsg.xCEMsg[2] == 0xaf ) ) {
+ /* TOD clock is not set */
+ tm->tm_sec = 1;
+ tm->tm_min = 1;
+ tm->tm_hour = 1;
+ tm->tm_mday = 10;
+ tm->tm_mon = 8;
+ tm->tm_year = 71;
+ mf_setRtc( tm );
+ }
+ {
u32 dataWord1 = *((u32 *)(rtcData.xCeMsg.xCEMsg+4));
u32 dataWord2 = *((u32 *)(rtcData.xCeMsg.xCEMsg+8));
u8 year = (dataWord1 >> 16 ) & 0x000000FF;
@@ -1176,7 +1148,7 @@
tm->tm_mday = day;
tm->tm_mon = mon;
tm->tm_year = year;
-
+ }
}
else
{
@@ -1189,6 +1161,10 @@
tm->tm_year = 52;
}
+ tm->tm_wday = 0;
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
}
return rc;
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/misc.S linuxppc64_2_4/arch/ppc64/kernel/misc.S
--- linux-2.4.8-ac9/arch/ppc64/kernel/misc.S Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/misc.S Tue Aug 14 23:24:17 2001
@@ -101,24 +101,22 @@
/* are we enabling interrupts? */
rlwinm. r0,r3,0,16,16
beq 1f
- /* if so, check if there are any lost interrupts */
- LOADBASE(r7,ppc_n_lost_interrupts)
- lwz r7,ppc_n_lost_interrupts@l(r7)
- cmpi 0,r7,0 /* lost interrupts to process first? */
- bne- .do_lost_interrupts
- /* Check for lost decrementer interrupts.
- * (If decrementer popped while we were in the hypervisor)
- * (calls timer_interrupt if so)
+ /* Check pending interrupts
+ * A decrementer, IPI or PMC interrupt may have occurred
+ * while we were in the hypervisor (which enables)
*/
- CHECKDECR(r4,r5)
- bne- .do_fake_decrementer
- /* Check for pending I/O Events. If no I/O events pending,
- * then CR0 = "eq" and r4 == 0
- * (kills registers r5 and r6)
+ CHECKANYINT(r4,r5)
+ beq+ 1f
+
+ /*
+ * Handle pending interrupts in interrupt context
*/
- CHECKLPQUEUE(r4,r5,r6)
- bne- .do_lost_interrupts
-1: sync
+ mtmsrd r3
+ li r0,0x5555
+ sc
+ blr
+1:
+ sync
mtmsrd r3
isync
blr
@@ -150,23 +148,22 @@
_GLOBAL(__no_use_sti)
mfmsr r3 /* Get current state */
ori r3,r3,MSR_EE /* Turn on 'EE' bit */
- LOADBASE(r4,ppc_n_lost_interrupts)
- lwz r4,ppc_n_lost_interrupts@l(r4)
- cmpi 0,r4,0 /* lost interrupts to process first? */
- bne- .do_lost_interrupts
- /* Check for lost decrementer interrupts.
- * (If decrementer popped while we were in the hypervisor)
- * (calls timer_interrupt if so)
+ /* Check for pending interrupts
+ * A decrementer, IPI or PMC interrupt may have occurred
+ * while we were in the hypervisor (which enables)
*/
- CHECKDECR(r4,r5)
- bne- .do_fake_decrementer
- /* Check for pending I/O events. If no I/O events pending,
- * then CR0 = "eq" and R4 = 0
- * (kills registers r5 and r6)
+ CHECKANYINT(r4,r5)
+ beq+ 1f
+
+ /*
+ * Handle pending interrupts in interrupt context
*/
- CHECKLPQUEUE(r4,r5,r6)
- bne- .do_lost_interrupts
+ mtmsrd r3
+ li r0,0x5555
+ sc
+ blr
+1:
sync /* Some chip revs have problems here... */
mtmsrd r3 /* Update machine state */
blr
@@ -175,21 +172,17 @@
* We were about to enable interrupts but we have to simulate
* some interrupts that were lost by enable_irq first.
*/
-_GLOBAL(do_lost_interrupts)
+_GLOBAL(do_fake_interrupt)
mflr r0
std r0,16(r1)
std r3,-8(r1)
stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1)
1: bl .fake_interrupt
- LOADBASE(r4,ppc_n_lost_interrupts)
- lwz r4,ppc_n_lost_interrupts@l(r4)
- cmpi 0,r4,0
- bne- 1b
- /* Check for pending I/O events. If no I/O events pending,
- * then CR0 = "eq" and R4 = 0
- * (kills registers r5 and r6)
+ /* Check for pending interrupt
+ * A decrementer, IPI or PMC interrupt may have occurred
+ * while we were in the hypervisor (which enables)
*/
- CHECKLPQUEUE(r4,r5,r6)
+ CHECKANYINT(r4,r5)
bne- 1b
addi r1,r1,STACK_FRAME_OVERHEAD+16
ld r3,-8(r1)
@@ -198,6 +191,7 @@
mtmsrd r3
blr
+#if 0
_GLOBAL(do_fake_decrementer)
mflr r0
std r0,16(r1)
@@ -212,6 +206,7 @@
bne- .do_lost_interrupts
mtmsrd r3
blr
+#endif
/*
* complement mask on the msr then "or" some values on.
@@ -252,7 +247,6 @@
/*
* Write any modified data cache blocks out to memory
* and invalidate the corresponding instruction cache blocks.
- * This is a no-op on the 601.
*
* flush_icache_range(unsigned long start, unsigned long stop)
*
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/mk_defs.c linuxppc64_2_4/arch/ppc64/kernel/mk_defs.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/mk_defs.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/mk_defs.c Mon Aug 13 10:16:24 2001
@@ -93,6 +93,7 @@
DEFINE(PACAR1, offsetof(struct Paca, xR1));
DEFINE(PACAR21, offsetof(struct Paca, xR21));
DEFINE(PACAR22, offsetof(struct Paca, xR22));
+ DEFINE(PACACCR, offsetof(struct Paca, xCCR));
DEFINE(PACALPQUEUE, offsetof(struct Paca, lpQueuePtr));
DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca));
DEFINE(PACATOC, offsetof(struct Paca, xTOC));
@@ -100,8 +101,9 @@
DEFINE(LPREGSAV, offsetof(struct Paca, xRegSav));
DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
- DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xDecrInt));
- DEFINE(LPPACAIPIINT, offsetof(struct ItLpPaca, xIpiCnt));
+ DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
+ DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
+ DEFINE(LPPACAIPIINT, offsetof(struct ItLpPaca, xIntDword.xFields.xIpiCnt));
DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/pacaData.c linuxppc64_2_4/arch/ppc64/kernel/pacaData.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/pacaData.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pacaData.c Tue Aug 21 14:49:35 2001
@@ -39,8 +39,7 @@
0, /* Kernel stack addr save */ \
(number), /* Paca Index */ \
0, /* HW Proc Number */ \
- (start), /* Processor start */ \
- {0,0,0}, /* Resv */ \
+ 0, /* CCR Save */ \
0, /* MSR Save */ \
0, /* LR Save */ \
0, /* Pointer to thread */ \
@@ -52,21 +51,33 @@
0, /* R1 Save */ \
(lpq), /* &xItLpQueue, */ \
{0,0,0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, SPIN_LOCK_UNLOCKED, 0}, /*xRtas */ \
- {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /* Resv */ \
+ (start), /* Processor start */ \
+ {0,0,0,0,0,0,0}, /* Resv */ \
+ 0, /* next_jiffy_update_tb */ \
+ {0,0,0,0,0,0,0,0,0,0,0,0}, /* Resv */ \
{ /* LpPaca */ \
xDesc: 0xd397d781, /* "LpPa" */ \
xSize: sizeof(struct ItLpPaca), /* */ \
+ xFPRegsInUse: 1, \
+ xDynProcStatus: 2, \
xEndOfQuantum: 0xffffffffffffffff /* */ \
}, \
{ /* LpRegSave */ \
0xd397d9e2, /* "LpRS" */ \
sizeof(struct ItLpRegSave) /* */ \
- } \
+ }, \
+ 0, /* pvr */ \
+ 0, /* pgd_cache */ \
+ 0, /* pmd_cache */ \
+ 0, /* pte_cache */ \
+ 0, /* pgtable_cache_sz */ \
+ 0, /* prof_multiplier */ \
+ 0 /* prof_counter */ \
}
-struct Paca xPaca[maxPacas] = {
+struct Paca xPaca[maxPacas] __page_aligned = {
#ifdef CONFIG_PPC_ISERIES
- PACAINITDATA( 0, 1, &xItLpQueue, 0x5000, 0xc000000000005000),
+ PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000),
#else
PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000),
#endif
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/pmc.c linuxppc64_2_4/arch/ppc64/kernel/pmc.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/pmc.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pmc.c Tue Aug 14 14:55:53 2001
@@ -22,10 +22,7 @@
* End Change Activity
*/
-#ifndef _PMC_PROC_H
-#include
-#endif
-
+#include
#include
#include
#include
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/pmc_proc.c linuxppc64_2_4/arch/ppc64/kernel/pmc_proc.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/pmc_proc.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pmc_proc.c Wed Dec 31 18:00:00 1969
@@ -1,650 +0,0 @@
-/*
- * pmc_proc.c
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-/* Change Activity: */
-/* End Change Activity */
-
-#ifndef _PMC_PROC_H
-#include
-#endif
-
-#include
-#include
-#include
-#include
-
-#define MMCR0 795
-#define MMCR1 798
-#define MMCRA 786
-#define PMC1 787
-#define PMC2 788
-#define PMC3 789
-#define PMC4 790
-#define PMC5 791
-#define PMC6 792
-#define PMC7 793
-#define PMC8 794
-
-static int proc_pmc_control_mode = 0;
-#define PMC_CONTROL_CPI 1
-#define PMC_CONTROL_TLB 2
-
-static struct proc_dir_entry *pmc_proc_root = NULL;
-
-int proc_get_lpevents( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data);
-
-int proc_pmc_get_control( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_mmcr0( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_mmcr1( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_mmcra( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc1( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc2( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc3( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc4( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc5( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc6( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc7( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_pmc_get_pmc8( char *page, char **start, off_t off, int count, int *eof, void *data);
-
-int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data);
-
-void pmc_proc_init(struct proc_dir_entry *iSeries_proc)
-{
- struct proc_dir_entry *ent = NULL;
-
- ent = create_proc_entry("lpevents", S_IFREG|S_IRUGO, iSeries_proc);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_get_lpevents;
- ent->write_proc = proc_reset_lpevents;
-
- pmc_proc_root = proc_mkdir("pmc", iSeries_proc);
- if (!pmc_proc_root) return;
-
- ent = create_proc_entry("control", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_control;
- ent->write_proc = proc_pmc_set_control;
-
- ent = create_proc_entry("mmcr0", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_mmcr0;
- ent->write_proc = proc_pmc_set_mmcr0;
-
- ent = create_proc_entry("mmcr1", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_mmcr1;
- ent->write_proc = proc_pmc_set_mmcr1;
-
- ent = create_proc_entry("mmcra", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_mmcra;
- ent->write_proc = proc_pmc_set_mmcra;
-
- ent = create_proc_entry("pmc1", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc1;
- ent->write_proc = proc_pmc_set_pmc1;
-
- ent = create_proc_entry("pmc2", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc2;
- ent->write_proc = proc_pmc_set_pmc2;
-
- ent = create_proc_entry("pmc3", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc3;
- ent->write_proc = proc_pmc_set_pmc3;
-
- ent = create_proc_entry("pmc4", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc4;
- ent->write_proc = proc_pmc_set_pmc4;
-
- ent = create_proc_entry("pmc5", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc5;
- ent->write_proc = proc_pmc_set_pmc5;
-
- ent = create_proc_entry("pmc6", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc6;
- ent->write_proc = proc_pmc_set_pmc6;
-
- ent = create_proc_entry("pmc7", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc7;
- ent->write_proc = proc_pmc_set_pmc7;
-
- ent = create_proc_entry("pmc8", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
- if (!ent) return;
- ent->nlink = 1;
- ent->data = (void *)0;
- ent->read_proc = proc_pmc_get_pmc8;
- ent->write_proc = proc_pmc_set_pmc8;
-
-
-}
-
-static int pmc_calc_metrics( char *page, char **start, off_t off, int count, int *eof, int len)
-{
- if ( len <= off+count)
- *eof = 1;
- *start = page+off;
- len -= off;
- if ( len > count )
- len = count;
- if ( len < 0 )
- len = 0;
- return len;
-}
-
-static char * lpEventTypes[9] = {
- "Hypervisor\t\t",
- "Machine Facilities\t",
- "Session Manager\t",
- "SPD I/O\t\t",
- "Virtual Bus\t\t",
- "PCI I/O\t\t",
- "RIO I/O\t\t",
- "Virtual Lan\t\t",
- "Virtual I/O\t\t"
- };
-
-
-int proc_get_lpevents
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- unsigned i;
- int len = 0;
-
- len += sprintf( page+len, "LpEventQueue 0\n" );
- len += sprintf( page+len, " events processed:\t%lu\n",
- (unsigned long)xItLpQueue.xLpIntCount );
- for (i=0; i<9; ++i) {
- len += sprintf( page+len, " %s %10lu\n",
- lpEventTypes[i],
- (unsigned long)xItLpQueue.xLpIntCountByType[i] );
- }
- return pmc_calc_metrics( page, start, off, count, eof, len );
-
-}
-
-int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- return count;
-}
-
-int proc_pmc_get_control
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = 0;
-
- if ( proc_pmc_control_mode == PMC_CONTROL_CPI ) {
- unsigned long mach_cycles = mfspr( PMC5 );
- unsigned long inst_complete = mfspr( PMC4 );
- unsigned long inst_dispatch = mfspr( PMC3 );
- unsigned long thread_active_run = mfspr( PMC1 );
- unsigned long thread_active = mfspr( PMC2 );
- unsigned long cpi = 0;
- unsigned long cpithou = 0;
- unsigned long remain;
-
- if ( inst_complete ) {
- cpi = thread_active_run / inst_complete;
- remain = thread_active_run % inst_complete;
- if ( inst_complete > 1000000 )
- cpithou = remain / ( inst_complete / 1000 );
- else
- cpithou = ( remain * 1000 ) / inst_complete;
- }
- len += sprintf( page+len, "PMC CPI Mode\nRaw Counts\n" );
- len += sprintf( page+len, "machine cycles : %12lu\n", mach_cycles );
- len += sprintf( page+len, "thread active cycles : %12lu\n\n", thread_active );
-
- len += sprintf( page+len, "instructions completed : %12lu\n", inst_complete );
- len += sprintf( page+len, "instructions dispatched : %12lu\n", inst_dispatch );
- len += sprintf( page+len, "thread active run cycles : %12lu\n", thread_active_run );
-
- len += sprintf( page+len, "thread active run cycles/instructions completed\n" );
- len += sprintf( page+len, "CPI = %lu.%03lu\n", cpi, cpithou );
-
- }
- else if ( proc_pmc_control_mode == PMC_CONTROL_TLB ) {
- len += sprintf( page+len, "PMC TLB Mode\n" );
- len += sprintf( page+len, "I-miss count : %12lu\n", mfspr( PMC1 ) );
- len += sprintf( page+len, "I-miss latency : %12lu\n", mfspr( PMC2 ) );
- len += sprintf( page+len, "D-miss count : %12lu\n", mfspr( PMC3 ) );
- len += sprintf( page+len, "D-miss latency : %12lu\n", mfspr( PMC4 ) );
- len += sprintf( page+len, "IERAT miss count : %12lu\n", mfspr( PMC5 ) );
- len += sprintf( page+len, "D-reference count : %12lu\n", mfspr( PMC6 ) );
- len += sprintf( page+len, "miss PTEs searched : %12lu\n", mfspr( PMC7 ) );
- len += sprintf( page+len, "miss >8 PTEs searched : %12lu\n", mfspr( PMC8 ) );
- }
- /* IMPLEMENT ME */
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_mmcr0
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(MMCR0) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_mmcr1
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(MMCR1) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_mmcra
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(MMCRA) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc1
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC1) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc2
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC2) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc3
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC3) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc4
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC4) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc5
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC5) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc6
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC6) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc7
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC7) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-int proc_pmc_get_pmc8
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = sprintf( page, "0x%08lx", mfspr(PMC8) );
- return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-unsigned long proc_pmc_conv_int( const char *buf, unsigned count )
-{
- const char * p;
- char b0, b1;
- unsigned v, multiplier, mult, i;
- unsigned long val;
- multiplier = 10;
- p = buf;
- if ( count >= 3 ) {
- b0 = buf[0];
- b1 = buf[1];
- if ( ( b0 == '0' ) &&
- ( ( b1 == 'x' ) || ( b1 == 'X' ) ) ) {
- p = buf + 2;
- count -= 2;
- multiplier = 16;
- }
-
- }
- val = 0;
- for ( i=0; i= '0' ) && ( b0 <= '9' ) )
- v = b0 - '0';
- else if ( multiplier == 16 ) {
- if ( ( b0 >= 'a' ) && ( b0 <= 'f' ) )
- v = b0 - 'a' + 10;
- else if ( ( b0 >= 'A' ) && ( b0 <= 'F' ) )
- v = b0 - 'A' + 10;
- else
- mult = 1;
- }
- else
- mult = 1;
- val *= mult;
- val += v;
- }
-
- return val;
-
-}
-
-static inline void proc_pmc_stop(void)
-{
- /* Freeze all counters, leave everything else alone */
- mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
-}
-
-static inline void proc_pmc_start(void)
-{
- /* Unfreeze all counters, leave everything else alone */
- mtspr( MMCR0, mfspr( MMCR0 ) & ~0x80000000 );
-
-}
-
-static inline void proc_pmc_reset(void)
-{
- /* Clear all the PMCs to zeros
- * Assume a "stop" has already frozen the counters
- * Clear all the PMCs
- */
- mtspr( PMC1, 0 );
- mtspr( PMC2, 0 );
- mtspr( PMC3, 0 );
- mtspr( PMC4, 0 );
- mtspr( PMC5, 0 );
- mtspr( PMC6, 0 );
- mtspr( PMC7, 0 );
- mtspr( PMC8, 0 );
-
-}
-
-static inline void proc_pmc_cpi(void)
-{
- /* Configure the PMC registers to count cycles and instructions */
- /* so we can compute cpi */
- /*
- * MMCRA[30] = 1 Don't count in wait state (CTRL[31]=0)
- * MMCR0[6] = 1 Freeze counters when any overflow
- * MMCR0[19:25] = 0x01 PMC1 counts Thread Active Run Cycles
- * MMCR0[26:31] = 0x05 PMC2 counts Thread Active Cycles
- * MMCR1[0:4] = 0x07 PMC3 counts Instructions Dispatched
- * MMCR1[5:9] = 0x03 PMC4 counts Instructions Completed
- * MMCR1[10:14] = 0x06 PMC5 counts Machine Cycles
- *
- */
-
- proc_pmc_control_mode = PMC_CONTROL_CPI;
-
- // Indicate to hypervisor that we are using the PMCs
- ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
-
- // Freeze all counters
- mtspr( MMCR0, 0x80000000 );
- mtspr( MMCR1, 0x00000000 );
-
- // Clear all the PMCs
- mtspr( PMC1, 0 );
- mtspr( PMC2, 0 );
- mtspr( PMC3, 0 );
- mtspr( PMC4, 0 );
- mtspr( PMC5, 0 );
- mtspr( PMC6, 0 );
- mtspr( PMC7, 0 );
- mtspr( PMC8, 0 );
-
- /* Freeze counters in Wait State (CTRL[31]=0) */
- mtspr( MMCRA, 0x00000002 );
-
- /* PMC3<-0x07, PMC4<-0x03, PMC5<-0x06 */
- mtspr( MMCR1, 0x38cc0000 );
-
- mb();
-
- /* PMC1<-0x01, PMC2<-0x05
- * Start all counters
- */
- mtspr( MMCR0, 0x02000045 );
-
-}
-
-static inline void proc_pmc_tlb(void)
-{
- /* Configure the PMC registers to count tlb misses */
- /*
- * MMCR0[6] = 1 Freeze counters when any overflow
- * MMCR0[19:25] = 0x55 Group count
- * PMC1 counts I misses
- * PMC2 counts I miss duration (latency)
- * PMC3 counts D misses
- * PMC4 counts D miss duration (latency)
- * PMC5 counts IERAT misses
- * PMC6 counts D references (including PMC7)
- * PMC7 counts miss PTEs searched
- * PMC8 counts miss >8 PTEs searched
- *
- */
-
- proc_pmc_control_mode = PMC_CONTROL_TLB;
-
- /* Indicate to hypervisor that we are using the PMCs */
- ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
-
- /* Freeze all counters */
- mtspr( MMCR0, 0x80000000 );
- mtspr( MMCR1, 0x00000000 );
-
- /* Clear all the PMCs */
- mtspr( PMC1, 0 );
- mtspr( PMC2, 0 );
- mtspr( PMC3, 0 );
- mtspr( PMC4, 0 );
- mtspr( PMC5, 0 );
- mtspr( PMC6, 0 );
- mtspr( PMC7, 0 );
- mtspr( PMC8, 0 );
-
- mtspr( MMCRA, 0x00000000 );
-
- mb();
-
- /* PMC1<-0x55
- * Start all counters
- */
- mtspr( MMCR0, 0x02001540 );
-
-}
-
-int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- if ( ! strncmp( buffer, "stop", 4 ) )
- proc_pmc_stop();
- else if ( ! strncmp( buffer, "start", 5 ) )
- proc_pmc_start();
- else if ( ! strncmp( buffer, "reset", 5 ) )
- proc_pmc_reset();
- else if ( ! strncmp( buffer, "cpi", 3 ) )
- proc_pmc_cpi();
- else if ( ! strncmp( buffer, "tlb", 3 ) )
- proc_pmc_tlb();
-
- /* IMPLEMENT ME */
- return count;
-}
-
-int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- v = v & ~0x04000000; /* Don't allow interrupts for now */
- if ( v & ~0x80000000 ) /* Inform hypervisor we are using PMCs */
- ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
- else
- ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 0;
- mtspr( MMCR0, v );
-
- return count;
-}
-
-int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( MMCR1, v );
-
- return count;
-}
-
-int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- v = v & ~0x00008000; /* Don't allow interrupts for now */
- mtspr( MMCRA, v );
-
- return count;
-}
-
-
-int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC1, v );
-
- return count;
-}
-
-int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC2, v );
-
- return count;
-}
-
-int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC3, v );
-
- return count;
-}
-
-int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC4, v );
-
- return count;
-}
-
-int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC5, v );
-
- return count;
-}
-
-int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC6, v );
-
- return count;
-}
-
-int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC7, v );
-
- return count;
-}
-
-int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data )
-{
- unsigned long v;
- v = proc_pmc_conv_int( buffer, count );
- mtspr( PMC8, v );
-
- return count;
-}
-
-
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/ppc_asm.h linuxppc64_2_4/arch/ppc64/kernel/ppc_asm.h
--- linux-2.4.8-ac9/arch/ppc64/kernel/ppc_asm.h Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/ppc_asm.h Mon Aug 13 10:14:50 2001
@@ -72,6 +72,10 @@
stb ra,PACALPPACA+LPPACADECRINT(rb); /* Clear DECR int flag */\
99:
+#define CHECKANYINT(ra,rb) \
+ mfspr rb,SPRG3; /* Get Paca address */\
+ ld ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\
+ cmpldi 0,ra,0;
/* Macros to adjust thread priority for Iseries hardware multithreading */
#define HMT_LOW or 1,1,1
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/ppc_defs.h linuxppc64_2_4/arch/ppc64/kernel/ppc_defs.h
--- linux-2.4.8-ac9/arch/ppc64/kernel/ppc_defs.h Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/ppc_defs.h Wed Dec 31 18:00:00 1969
@@ -1,116 +0,0 @@
-/* The source for this file is automatically generated. Do not edit! */
-#define STATE 0
-#define NEXT_TASK 136
-#define COUNTER 64
-#define PROCESSOR 100
-#define SIGPENDING 16
-#define THREAD 1448
-#define MM 88
-#define ACTIVE_MM 152
-#define TASK_STRUCT_SIZE 1904
-#define KSP 0
-#define PACA 24
-#define PACA_SIZE 2080
-#define RTAS_ARGS_SIZE 88
-#define ITLPPACA_SIZE 640
-#define ITLPREGSAVE_SIZE 1024
-#define DCACHEL1LINESIZE 42
-#define DCACHEL1LOGLINESIZE 44
-#define DCACHEL1LINESPERPAGE 46
-#define ICACHEL1LINESIZE 48
-#define ICACHEL1LOGLINESIZE 50
-#define ICACHEL1LINESPERPAGE 52
-#define PHYSICALMEMORYSIZE 56
-#define PACAPACAINDEX 48
-#define PACAPROCSTART 52
-#define PACAKSAVE 40
-#define PACATHREAD 72
-#define PACACURRENT 16
-#define PACASAVEDMSR 56
-#define PACASAVEDLR 64
-#define PACASTABREAL 80
-#define PACASTABVIRT 88
-#define PACAR1 120
-#define PACAR21 24
-#define PACAR22 32
-#define PACALPQUEUE 128
-#define PACALPPACA 376
-#define PACATOC 112
-#define LPPACA 376
-#define LPREGSAV 1016
-#define LPPACASRR0 144
-#define LPPACASRR1 152
-#define LPPACADECRINT 132
-#define LPPACAIPIINT 131
-#define LPQCUREVENTPTR 16
-#define LPQOVERFLOW 0
-#define LPEVENTFLAGS 0
-#define PROMENTRY 0
-#define PROMARGS 32
-#define RTASBASE 8
-#define RTASENTRY 0
-#define RTASSIZE 16
-#define PGDIR 24
-#define LAST_SYSCALL 32
-#define PT_REGS 8
-#define PT_TRACESYS 2
-#define TASK_FLAGS 8
-#define TASK_PTRACE 48
-#define TASK_PERSONALITY 184
-#define NEED_RESCHED 40
-#define THREAD_FPR0 52
-#define THREAD_FPSCR 320
-#define THREAD_FLAGS 40
-#define PPC_FLAG_32BIT 1
-#define TASK_UNION_SIZE 16384
-#define STACK_FRAME_OVERHEAD 112
-#define INT_FRAME_SIZE 752
-#define GPR0 112
-#define GPR1 120
-#define GPR2 128
-#define GPR3 136
-#define GPR4 144
-#define GPR5 152
-#define GPR6 160
-#define GPR7 168
-#define GPR8 176
-#define GPR9 184
-#define GPR10 192
-#define GPR11 200
-#define GPR12 208
-#define GPR13 216
-#define GPR14 224
-#define GPR15 232
-#define GPR16 240
-#define GPR17 248
-#define GPR18 256
-#define GPR19 264
-#define GPR20 272
-#define GPR21 280
-#define GPR22 288
-#define GPR23 296
-#define GPR24 304
-#define GPR25 312
-#define GPR26 320
-#define GPR27 328
-#define GPR28 336
-#define GPR29 344
-#define GPR30 352
-#define GPR31 360
-#define _NIP 368
-#define _MSR 376
-#define _CTR 392
-#define _LINK 400
-#define _CCR 416
-#define _MQ 424
-#define _XER 408
-#define _DAR 440
-#define _DSISR 448
-#define _DEAR 440
-#define _ESR 448
-#define ORIG_GPR3 384
-#define RESULT 456
-#define TRAP 432
-#define CLONE_VM 256
-#define IRQ_CPUSTAT_SHIFT 7
-#define SOFTIRQ_PENDING 0
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/ppc_ksyms.c linuxppc64_2_4/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/ppc_ksyms.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/ppc_ksyms.c Tue Aug 21 22:52:27 2001
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
@@ -45,7 +46,6 @@
#ifdef CONFIG_SMP
#include
#endif /* CONFIG_SMP */
-//#include
/* Tell string.h we don't want memcpy etc. as cpp defines */
#define EXPORT_SYMTAB_STROPS
@@ -59,7 +59,6 @@
extern void ProgramCheckException(struct pt_regs *regs);
extern void SingleStepException(struct pt_regs *regs);
extern int sys_sigreturn(struct pt_regs *regs);
-extern void do_lost_interrupts(unsigned long);
extern int do_signal(sigset_t *, struct pt_regs *);
long long __ashrdi3(long long, int);
@@ -68,7 +67,9 @@
int abs(int);
extern unsigned long ret_to_user_hook;
+#if 0 /* Add back in when we fix clear_page */
EXPORT_SYMBOL(clear_page);
+#endif
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(syscall_trace);
EXPORT_SYMBOL(transfer_to_handler);
@@ -79,25 +80,17 @@
EXPORT_SYMBOL(ProgramCheckException);
EXPORT_SYMBOL(SingleStepException);
EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(ppc_n_lost_interrupts);
-EXPORT_SYMBOL(ppc_lost_interrupts);
-EXPORT_SYMBOL(do_lost_interrupts);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(disable_irq_nosync);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(synchronize_irq);
#endif /* CONFIG_SMP */
EXPORT_SYMBOL(isa_io_base);
EXPORT_SYMBOL(isa_mem_base);
EXPORT_SYMBOL(pci_dram_offset);
-EXPORT_SYMBOL(DMA_MODE_READ);
-EXPORT_SYMBOL(DMA_MODE_WRITE);
-#if defined(CONFIG_ALL_PPC)
-EXPORT_SYMBOL(_prep_type);
-EXPORT_SYMBOL(ucSystemType);
-#endif
#if !__INLINE_BITOPS
EXPORT_SYMBOL(set_bit);
@@ -168,6 +161,10 @@
#ifdef CONFIG_PCI
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_unmap_sg);
#endif /* CONFIG_PCI */
EXPORT_SYMBOL(start_thread);
@@ -178,19 +175,11 @@
EXPORT_SYMBOL(giveup_fpu);
EXPORT_SYMBOL(enable_kernel_fp);
EXPORT_SYMBOL(flush_icache_range);
-EXPORT_SYMBOL(xchg_u32);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(_spin_lock);
-EXPORT_SYMBOL(_spin_unlock);
-EXPORT_SYMBOL(spin_trylock);
-EXPORT_SYMBOL(_read_lock);
-EXPORT_SYMBOL(_read_unlock);
-EXPORT_SYMBOL(_write_lock);
-EXPORT_SYMBOL(_write_unlock);
#endif
#ifndef CONFIG_MACH_SPECIFIC
@@ -198,7 +187,6 @@
#endif
EXPORT_SYMBOL(ppc_md);
-#if defined(CONFIG_ALL_PPC)
EXPORT_SYMBOL(find_devices);
EXPORT_SYMBOL(find_type_devices);
EXPORT_SYMBOL(find_compatible_devices);
@@ -209,12 +197,7 @@
EXPORT_SYMBOL(find_pci_device_OFnode);
EXPORT_SYMBOL(find_all_nodes);
EXPORT_SYMBOL(get_property);
-EXPORT_SYMBOL(pci_io_base);
-EXPORT_SYMBOL(pci_device_loc);
-#endif /* defined(CONFIG_ALL_PPC) */
-#if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC)
-EXPORT_SYMBOL(note_scsi_host);
-#endif
+
EXPORT_SYMBOL(kd_mksound);
EXPORT_SYMBOL_NOVERS(sys_ctrler); /* tibit */
#ifdef CONFIG_NVRAM
@@ -237,21 +220,15 @@
EXPORT_SYMBOL(screen_info);
#endif
-EXPORT_SYMBOL(int_control);
-EXPORT_SYMBOL(timer_interrupt_intercept);
EXPORT_SYMBOL(timer_interrupt);
-EXPORT_SYMBOL(do_IRQ_intercept);
EXPORT_SYMBOL(irq_desc);
void ppc_irq_dispatch_handler(struct pt_regs *, int);
EXPORT_SYMBOL(ppc_irq_dispatch_handler);
-EXPORT_SYMBOL(decrementer_count);
EXPORT_SYMBOL(get_wchan);
EXPORT_SYMBOL(console_drivers);
-EXPORT_SYMBOL(console_lock);
#ifdef CONFIG_XMON
EXPORT_SYMBOL(xmon);
#endif
-EXPORT_SYMBOL(down_read_failed);
#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
extern void (*debugger)(struct pt_regs *regs);
@@ -270,4 +247,5 @@
#endif
EXPORT_SYMBOL(ret_to_user_hook);
-EXPORT_SYMBOL(do_softirq);
+
+EXPORT_SYMBOL(tb_ticks_per_usec);
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/proc_pmc.c linuxppc64_2_4/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/proc_pmc.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/proc_pmc.c Tue Aug 14 14:55:53 2001
@@ -25,10 +25,7 @@
* End Change Activity
*/
-#ifndef _PMC_PROC_H
-#include
-#endif
-
+#include
#include
#include
#include
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/prom.c linuxppc64_2_4/arch/ppc64/kernel/prom.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/prom.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/prom.c Wed Aug 15 15:36:50 2001
@@ -425,7 +425,7 @@
if ( (_naca->processorCount = num_cpus) < 1 )
PROM_BUG();
- _naca->physicalMemorySize = _lmb->memory.size;
+ _naca->physicalMemorySize = lmb_phys_mem_size();
/*
* Hardcode to GP size. I am not sure where to get this info
@@ -491,9 +491,20 @@
unsigned long i, offset = reloc_offset();
struct prom_t *_prom = PTRRELOC(&prom);
union lmb_reg_property reg;
- unsigned long lmb_base, lmb_size;
+ unsigned long mem_size, lmb_base, lmb_size;
unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
+#if 1
+ /* Fix me: 630 3G-4G IO hack here... -Peter (PPPBBB) */
+ unsigned long io_base = 3UL<<30;
+ unsigned long io_size = 1UL<<30;
+ unsigned long have_630 = 1; /* assume we have a 630 */
+
+#else
+ unsigned long io_base = ;
+ unsigned long io_size = ;
+#endif
+
lmb_init();
for (node = 0; prom_next_node(&node); ) {
@@ -516,11 +527,23 @@
lmb_size = reg.addr64[i].size;
}
+ if ( lmb_addrs_overlap(lmb_base,lmb_size,
+ io_base,io_size) ) {
+ /* If we really have dram here, then we don't
+ * have a 630! -Peter
+ */
+ have_630 = 0;
+ }
if ( lmb_add(lmb_base, lmb_size) < 0 )
prom_print(RELOC("Too many LMB's, discarding this one...\n"));
+ else
+ mem_size =+ lmb_size;
}
}
+
+ if ( have_630 && lmb_addrs_overlap(0,mem_size,io_base,io_size) )
+ lmb_add_io(io_base, io_size);
lmb_analyze();
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/ptrace.c linuxppc64_2_4/arch/ppc64/kernel/ptrace.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/ptrace.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/ptrace.c Tue Aug 21 22:54:49 2001
@@ -110,32 +110,7 @@
goto out_tsk;
if (request == PTRACE_ATTACH) {
- if (child == current)
- goto out_tsk;
- if (((current->uid != child->euid) ||
- (current->uid != child->suid) ||
- (current->uid != child->uid) ||
- (current->gid != child->egid) ||
- (current->gid != child->sgid) ||
- (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
- (current->gid != child->gid))
- && !capable(CAP_SYS_PTRACE))
- goto out_tsk;
- /* the same process cannot be attached many times */
- if (child->ptrace & PT_PTRACED)
- goto out_tsk;
- child->ptrace |= PT_PTRACED;
-
- write_lock_irq(&tasklist_lock);
- if (child->p_pptr != current) {
- REMOVE_LINKS(child);
- child->p_pptr = current;
- SET_LINKS(child);
- }
- write_unlock_irq(&tasklist_lock);
-
- send_sig(SIGSTOP, child, 1);
- ret = 0;
+ ret = ptrace_attach(child);
goto out_tsk;
}
ret = -ESRCH;
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/ptrace32.c linuxppc64_2_4/arch/ppc64/kernel/ptrace32.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/ptrace32.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/ptrace32.c Tue Aug 21 22:54:49 2001
@@ -110,32 +110,7 @@
goto out_tsk;
if (request == PTRACE_ATTACH) {
- if (child == current)
- goto out_tsk;
- if (((current->uid != child->euid) ||
- (current->uid != child->suid) ||
- (current->uid != child->uid) ||
- (current->gid != child->egid) ||
- (current->gid != child->sgid) ||
- (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
- (current->gid != child->gid))
- && !capable(CAP_SYS_PTRACE))
- goto out_tsk;
- /* the same process cannot be attached many times */
- if (child->ptrace & PT_PTRACED)
- goto out_tsk;
- child->ptrace |= PT_PTRACED;
-
- write_lock_irq(&tasklist_lock);
- if (child->p_pptr != current) {
- REMOVE_LINKS(child);
- child->p_pptr = current;
- SET_LINKS(child);
- }
- write_unlock_irq(&tasklist_lock);
-
- send_sig(SIGSTOP, child, 1);
- ret = 0;
+ ret = ptrace_attach(child);
goto out_tsk;
}
ret = -ESRCH;
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/rtas-eventscan.c linuxppc64_2_4/arch/ppc64/kernel/rtas-eventscan.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/rtas-eventscan.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/rtas-eventscan.c Wed Aug 22 10:51:36 2001
@@ -9,6 +9,7 @@
*/
#include
+#include
#include /* for ppc_md */
#include
@@ -31,14 +32,17 @@
do { /* implement me */ } while(0)
/* ****************************************************************** */
+char rtas_event_buffer[NR_CPUS][1024];
long
rtas_event_scan(void)
{
struct rtas_error_log *log = rtas.event_scan.log;
unsigned long size = rtas.event_scan.log_size;
- char buf[1024];
long cnt = 0;
+ char *buf;
+
+ buf = rtas_event_buffer[smp_processor_id()];
for(;;) {
long status = 1;
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/smp.c linuxppc64_2_4/arch/ppc64/kernel/smp.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/smp.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/smp.c Tue Aug 14 23:18:46 2001
@@ -45,6 +45,7 @@
#include
#include
#include
+#include
#include
#include
#include "open_pic.h"
@@ -71,6 +72,8 @@
volatile unsigned long __initdata tb_sync_flag = 0;
volatile unsigned long __initdata tb_offset = 0;
+extern unsigned char stab_array[];
+
int start_secondary(void *);
extern int cpu_idle(void *unused);
void smp_call_function_interrupt(void);
@@ -93,7 +96,8 @@
static void smp_xics_message_pass(int target, int msg, unsigned long data, int wait);
static int smp_xics_probe(void);
-/* static void smp_xics_setup_cpu(int cpu_nr); */
+void xics_setup_cpu(void);
+void xics_cause_IPI(int cpu);
/*
* XICS only has a single IPI, so encode the messages per CPU
@@ -187,8 +191,10 @@
np = 0;
for (i=0; i < maxPacas; ++i) {
lpPaca = xPaca[i].xLpPacaPtr;
- if ( lpPaca->xDynProcStatus < 2 )
+ if ( lpPaca->xDynProcStatus < 2 ) {
++np;
+ last_jiffy_stamp(i) = last_jiffy_stamp(0);
+ }
}
smp_tb_synchronized = 1;
@@ -472,19 +478,26 @@
/* Wait for response */
timeout = 8000000;
while (atomic_read(&data.started) != cpus) {
+ HMT_low();
if (--timeout == 0) {
printk("smp_call_function on cpu %d: other cpus not responding (%d)\n",
smp_processor_id(), atomic_read(&data.started));
+#ifdef CONFIG_XMON
xmon(0);
+#endif
goto out;
}
barrier();
udelay(1);
+#ifdef CONFIG_PPC_ISERIES
+ HvCallCfg_getLps();
+#endif
}
if (wait) {
timeout = 1000000;
while (atomic_read(&data.finished) != cpus) {
+ HMT_low();
if (--timeout == 0) {
printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n",
smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started));
@@ -492,11 +505,15 @@
}
barrier();
udelay(1);
+#ifdef CONFIG_PPC_ISERIES
+ HvCallCfg_getLps();
+#endif
}
}
ret = 0;
out:
+ HMT_medium();
spin_unlock_bh(&call_lock);
return ret;
}
@@ -528,6 +545,7 @@
int i, cpu_nr;
struct task_struct *p;
unsigned long sp;
+ unsigned long arpn;
printk("Entering SMP Mode...\n");
PPCDBG(PPCDBG_SMP, "smp_boot_cpus: start. NR_CPUS = 0x%lx\n", NR_CPUS);
@@ -560,11 +578,12 @@
* Other processor's tables are created and
* initialized here.
*/
- paca->xStab_data.virt =
- (unsigned long)btmalloc(PAGE_SIZE);
- paca->xStab_data.real = ___pa(paca->xStab_data.virt);
+
+ paca->xStab_data.virt = (unsigned long)&stab_array[PAGE_SIZE * (i-1)];
+ arpn = physRpn_to_absRpn(___pa(paca->xStab_data.virt) >> 12);
+ paca->xStab_data.real = arpn << 12;
paca->xHwProcNum = smp_hw_index[i];
- memset(paca->xStab_data.virt, 0, PAGE_SIZE);
+ memset((void *)paca->xStab_data.virt, 0, PAGE_SIZE);
}
PPCDBG(PPCDBG_SMP,
"\tProcessor %d, stab virt = 0x%lx, stab real = 0x%lx\n",
@@ -596,12 +615,17 @@
/* Probe arch for CPUs */
cpu_nr = smp_ops->probe();
+ printk("Probe found %d CPUs\n", cpu_nr);
+
/*
* only check for cpus we know exist. We keep the callin map
* with cpus at the bottom -- Cort
*/
if (cpu_nr > max_cpus)
cpu_nr = max_cpus;
+
+ printk("Waiting for %d CPUs\n", cpu_nr-1);
+
for ( i = 1 ; i < cpu_nr; i++ ) {
int c;
struct pt_regs regs;
@@ -640,7 +664,7 @@
sp = ((unsigned long)p) + sizeof(union task_union)
- STACK_FRAME_OVERHEAD;
PPCDBG(PPCDBG_SMP, "\tstack pointer virt = 0x%lx\n", sp);
- current_set[i].sp_real = ___pa(sp);
+ current_set[i].sp_real = (void *)___pa(sp);
PPCDBG(PPCDBG_SMP,"\tstack pointer real = 0x%lx\n",
current_set[i].sp_real);
@@ -652,8 +676,12 @@
* use this value that I found through experimentation.
* -- Cort
*/
- for ( c = 5000; c && !cpu_callin_map[i] ; c-- )
+ for ( c = 5000; c && !cpu_callin_map[i] ; c-- ) {
+#ifdef CONFIG_PPC_ISERIES
+ HvCallCfg_getLps();
+#endif
udelay(100);
+ }
if ( cpu_callin_map[i] )
{
@@ -705,8 +733,12 @@
*/
cpu_callin_map[cpu] = 1;
- while(!smp_commenced)
+ while(!smp_commenced) {
+#ifdef CONFIG_PPC_ISERIES
+ HvCallCfg_getLps();
+#endif
barrier();
+ }
__sti();
}
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/stab.c linuxppc64_2_4/arch/ppc64/kernel/stab.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/stab.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/stab.c Mon Aug 20 08:53:38 2001
@@ -44,8 +44,12 @@
if ( skip_esid_c )
esid += (REGION_STRIDE >> SID_SHIFT);
- last_esid = GET_ESID(KERNELBASE) +
- ((REGION_COUNT - 2) * (REGION_STRIDE >> SID_SHIFT));
+ /*
+ * Put entries into the STAB for the first segment of the 4 kernel
+ * regions (0xC - 0xF). These are left in the table during flush.
+ * All other kernel segments (including bolted) are demand faulted.
+ */
+ last_esid = GET_ESID(KERNELBASE) + (2 * (REGION_STRIDE >> SID_SHIFT));
for (; esid <= last_esid; esid += (REGION_STRIDE >> SID_SHIFT)) {
/* Map the esid to an EA & find the vsid we need. */
@@ -116,9 +120,10 @@
castout_ste = ste + (castout_entry - 8);
}
- if(REGION_ID((castout_ste->dw0.dw0.esid) << SID_SHIFT) ==
- USER_REGION_ID) {
- /* Found a non-kernel entry to castout */
+ if((((castout_ste->dw0.dw0.esid) >> 32) == 0) ||
+ (((castout_ste->dw0.dw0.esid) & 0xffffffff) > 0)) {
+ /* Found an entry to castout. It is either a user */
+ /* region, or a secondary kernel segment. */
break;
}
@@ -295,10 +300,7 @@
if(!__is_processor(PV_POWER4)) {
unsigned long entry;
- STE *ste = stab;
-
- /* Never flush the first four entries (kernel segments) */
- ste += (REGION_COUNT-1);
+ STE *ste;
/* Force previous translations to complete. DRENG */
__asm__ __volatile__ ("isync" : : : "memory");
@@ -311,10 +313,12 @@
PMC_SW_PROCESSOR(stab_invalidations);
}
} else {
- /* Invalidate all entries except the four
- * kernel segments.
- */
- for(entry = REGION_COUNT - 1;
+ /* Invalidate all entries. */
+ ste = stab;
+
+ /* Never flush the first four entries. */
+ ste += 4;
+ for(entry = 4;
entry < (PAGE_SIZE / sizeof(STE));
entry++, ste++) {
ste->dw0.dw0.v = 0;
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/kernel/time.c linuxppc64_2_4/arch/ppc64/kernel/time.c
--- linux-2.4.8-ac9/arch/ppc64/kernel/time.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/time.c Fri Aug 17 12:56:41 2001
@@ -79,13 +79,14 @@
extern rwlock_t xtime_lock;
extern int piranha_simulator;
-unsigned long tb_ticks_per_jiffy;
-unsigned long tb_ticks_per_usec;
+unsigned long tb_ticks_per_jiffy = 5000000; /* initial sane values */
+unsigned long tb_ticks_per_usec = 500;
unsigned long tb_to_us;
unsigned long tb_last_stamp;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
extern unsigned long wall_jiffies;
+extern unsigned long lpEvent_count;
static long time_offset = 0;
@@ -152,6 +153,9 @@
unsigned long cpu = smp_processor_id();
unsigned long jiffy_stamp = last_jiffy_stamp(cpu);
+ struct Paca * paca;
+ struct ItLpQueue * lpq;
+
irq_enter(cpu);
if (!user_mode(regs))
@@ -203,6 +207,12 @@
if (ppc_md.heartbeat && !ppc_md.heartbeat_count--)
ppc_md.heartbeat();
+
+ paca = (struct Paca *)mfspr(SPRG3);
+ paca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
+ lpq = paca->lpQueuePtr;
+ if ( lpq )
+ lpEvent_count += ItLpQueue_process( lpq, regs );
irq_exit(cpu);
return 1; /* lets ret_from_int know we can do checks */
@@ -223,6 +233,12 @@
* during a decrementer interrupt on processor 0
*/
delta = tb_ticks_since(tb_last_stamp);
+
+#if CONFIG_PPC_ISERIES
+ /* Temporary hack to fix timer problems. MIKEC */
+ delta = 0;
+#endif
+
#ifdef CONFIG_SMP
/* As long as timebases are not in sync, gettimeofday can only
* have jiffy resolution on SMP. (except iSeries where the
@@ -271,6 +287,12 @@
*/
tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id()));
tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
+
+#if CONFIG_PPC_ISERIES
+ /* Temporary hack to fix timer problems. MIKEC */
+ tb_delta = 0;
+#endif
+
new_sec = tv->tv_sec;
new_usec = tv->tv_usec - tb_delta / tb_ticks_per_usec;
/* new_usec = tv->tv_usec - mulhwu(tb_to_us, tb_delta); */
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/mm/btmalloc.c linuxppc64_2_4/arch/ppc64/mm/btmalloc.c
--- linux-2.4.8-ac9/arch/ppc64/mm/btmalloc.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/mm/btmalloc.c Fri Aug 17 14:32:14 2001
@@ -15,14 +15,11 @@
#include
#include
+unsigned long btmalloc_debug = 0;
+unsigned long btmalloc_highwater = 0;
+
extern pgd_t *bolted_pgd;
-extern struct vmalloc_struct btmalloc_ops;
-extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
- struct vmalloc_struct *v);
extern pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea);
-extern void build_valid_hpte(unsigned long vsid, unsigned long ea,
- unsigned long pa, pte_t *ptep, unsigned hpteflags,
- unsigned bolted );
/*
* This lock guarantees that only one task will be attempting
@@ -30,158 +27,133 @@
*/
static spinlock_t bolted_pte_lock = SPIN_LOCK_UNLOCKED;
-pmd_t *pmd_alloc_b(pgd_t *pgd, unsigned long address)
-{
- pmd_t *pmd;
- void *page;
- unsigned long ea, pa, vsid;
- struct vm_struct *area;
+/* This lock protects the btmlist and serializes the removal
+ * of entries from the bolted page table
+ */
+rwlock_t btmlist_lock = RW_LOCK_UNLOCKED;
- if (!pgd_present(*pgd)) {
- spin_unlock(&bolted_pte_lock);
- page = (void *)__get_free_page(GFP_KERNEL);
- spin_lock(&bolted_pte_lock);
- if (!page)
- return NULL;
+struct vm_struct * btmlist = NULL;
- /*
- * Because we dropped the lock, we should re-check the
- * entry, as somebody else could have populated it..
- */
- if (pgd_present(*pgd)) {
- __free_pages(page, 0);
- goto out;
- }
+struct vm_struct *get_btm_area(unsigned long size, unsigned long flags);
+long btmallocread(char *buf, char *addr, unsigned long count);
- clear_page(page);
- /* allocate space in the bolted address range */
- area = __get_vm_area(PAGE_SIZE, 0, &btmalloc_ops);
- ea = (unsigned long)area->addr;
- pa = __pa(page);
- vsid = get_kernel_vsid(ea);
- build_valid_hpte(vsid, ea, pa, NULL,
- _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX, 1);
- pmd = (pmd_t *)ea;
- pgd_set(pgd, pmd);
- }
-out:
- return pmd_offset(pgd, address);
-}
+extern void build_valid_hpte(unsigned long vsid, unsigned long ea,
+ unsigned long pa, pte_t * ptep,
+ unsigned hpteflags, unsigned bolted );
-pte_t *pte_alloc_b(pmd_t *pmd, unsigned long address)
+void* get_free_bolted_pages(int gfp_mask, unsigned long order)
{
- pte_t *pte;
void *page;
- struct vm_struct *area;
- unsigned long ea, pa, vsid;
-
- if (!pmd_present(*pmd)) {
- spin_unlock(&bolted_pte_lock);
- page = (void *)__get_free_page(GFP_KERNEL);
- spin_lock(&bolted_pte_lock);
- if (!page)
- return NULL;
-
- /*
- * Because we dropped the lock, we should re-check the
- * entry, as somebody else could have populated it..
- */
- if (pmd_present(*pmd)) {
- __free_pages(page, 0);
- goto out;
- }
-
- clear_page(page);
- /* allocate space in the bolted address range */
- area = __get_vm_area(PAGE_SIZE, 0, &btmalloc_ops);
- ea = (unsigned long)area->addr;
- pa = __pa(page);
- vsid = get_kernel_vsid(ea);
- build_valid_hpte(vsid, ea, pa, NULL,
- _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX, 1);
- pte = (pte_t *)ea;
- pmd_set(pmd, pte);
- }
-out:
- return pte_offset(pmd, address);
-}
-
-static unsigned long btmalloc_start(void)
-{
- return BTMALLOC_START;
-}
-static unsigned long btmalloc_end(void)
-{
- return BTMALLOC_END;
+ page = btmalloc(PAGE_SIZE * (1 << order));
+ return(page);
}
-static int btmalloc_area_pages(unsigned long address, unsigned long size,
- int gfp_mask, pgprot_t prot);
-static void btfree_area_pages(unsigned long address, unsigned long size);
-
-struct vmalloc_struct btmalloc_ops = {
- lock: RW_LOCK_UNLOCKED,
- start: btmalloc_start,
- end: btmalloc_end,
- alloc_area_pages: btmalloc_area_pages,
- free_area_pages: btfree_area_pages,
-};
-
-static void btfree_area_pages(unsigned long address, unsigned long size)
+static int local_free_bolted_pages(void* page, unsigned long num)
{
- pte_t *ptep;
- pte_t pte;
- unsigned long num;
-
- num = (size >> PAGE_SHIFT);
-
- while(num--) {
- ptep = find_linux_pte(bolted_pgd, address);
- if (!ptep) {
- write_unlock(&btmalloc_ops.lock);
- panic("btfree_area_pages - page being freed (%016lx) is not bolted", address);
- }
- pte = *ptep;
- pte_clear(ptep);
- flush_hash_page( 0, address, pte );
- __free_pages(pte_page(pte), 0);
- address += PAGE_SIZE;
+ int rc = 0;
+ u32 cntr = 0;
+ char* pageAddr = (char*)page;
+ pte_t * ptep, pte;
+
+ /* Need to find the memmap array entry for the first real page of
+ * the range (this is where the reference count is maintained).
+ * It is assumed that the btmlist_lock is held to prevent changes
+ * to the bolted area page table while we search it
+ */
+ ptep = find_linux_pte( bolted_pgd, (unsigned long)pageAddr );
+
+ if ( !ptep ) {
+ write_unlock(&btmlist_lock);
+ panic("free_bolted_pages - bolted page is NOT in the bolted page table");
+ }
+
+ /* find_linux_pte has assured us that the pte is PRESENT
+ * Check the page reference count on the first page of the range
+ * to insure that we only free the range when the last reference
+ * is freed.
+ */
+ if ( page_count(pte_page(*ptep)) == 1 ) {
+ /* we are the last user of this range of pages - actually free the pages. */
+ for (cntr=0; cntrcount));
+ /* put_page_testzero(pte_page(pte)); */
+ }
+
+ return rc;
}
-static int btmalloc_area_pages(unsigned long address, unsigned long size,
- int gfp_mask, pgprot_t prot)
+void* btmalloc (unsigned long size)
{
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
- unsigned long eaddr;
+
+ unsigned long ea, eaddr;
+ struct vm_struct *area;
unsigned long pa, vsid, pg_count, page;
-
- pg_count = (size >> PAGE_SHIFT);
+
+ size = PAGE_ALIGN(size);
+ if (!size || (size >> PAGE_SHIFT) > num_physpages) {
+ BUG();
+ return NULL;
+ }
+
+ /* Get a virtual address region in the bolted space */
+ area = get_btm_area(size, 0);
+ if (!area) {
+ BUG();
+ return NULL;
+ }
+
+ ea = (unsigned long) area->addr;
+ pg_count = (size >> PAGE_SHIFT);
/* Create a Linux page table entry and an HPTE for each page */
- for(page = 0; page < pg_count; page++) {
- pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET;
- eaddr = address + (page * PAGE_SIZE);
+ for(page = 0; page < pg_count; page++) {
+
+ pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET;
- /*
- * We need a lock here to avoid multiple tasks doing
+ eaddr = ea + (page * PAGE_SIZE);
+
+ /* We need a lock here to avoid multiple tasks doing
* pmd_alloc_b and/or pte_alloc_b simultaneously
*/
spin_lock(&bolted_pte_lock);
-
- /*
- * Get a pointer to the linux page table entry for this page
+ /* Get a pointer to the linux page table entry for this page
* allocating pmd or pte pages along the way as needed
*/
pgdp = pgd_offset_b(eaddr);
pmdp = pmd_alloc_b(pgdp, eaddr);
ptep = pte_alloc_b(pmdp, eaddr);
-
- /*
- * At this point we are done allocating any new pmd/pte pages
+ /* At this point we are done allocating any new pmd/pte pages
* We own the pte (ptep) by nature of owning the eaddr so we
* no longer need the lock
*/
@@ -190,26 +162,256 @@
/* Clear any old hpte and set the new linux pte */
set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, PAGE_KERNEL));
+ PPCDBG(PPCDBG_MM, "In btmalloc: ea = %lx, pa = %lx\n", eaddr, pa);
+
vsid = get_kernel_vsid(eaddr);
- build_valid_hpte(vsid, eaddr, pa, ptep,
- _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX, 1);
+ build_valid_hpte( vsid, eaddr, pa, ptep,
+ _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX, 1 );
+ }
+
+ if(ea > btmalloc_highwater) btmalloc_highwater = ea;
+ if(btmalloc_debug) {
+ udbg_printf("btmalloc : 0x%lx (0x%lx) 0x%lx\n",
+ ea, ___pa(ea), size);
+ if(btmalloc_debug > 1) xmon(0);
+ }
+
+ return (void*)ea;
+}
+
+/*
+ * get_btm_area
+ *
+ * Get a virtual region in the bolted space
+ *
+ * This function is also called when allocating pages
+ * for pmd's/pte's for the bolted page table itself.
+ *
+ */
+struct vm_struct *get_btm_area(unsigned long size, unsigned long flags)
+{
+ unsigned long addr;
+ struct vm_struct **p, *tmp, *area;
+
+ area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
+ return NULL;
+
+ write_lock(&btmlist_lock);
+
+ addr = BTMALLOC_START;
+ for (p = &btmlist; (tmp = *p) ; p = &tmp->next) {
+ if (size + addr < (unsigned long) tmp->addr)
+ break;
+ addr = tmp->size + (unsigned long) tmp->addr;
+ if (addr > BTMALLOC_END-size) {
+ write_unlock(&btmlist_lock);
+ kfree(area);
+ return NULL;
+ }
+ }
+
+ area->flags = flags;
+ area->addr = (void *)addr;
+ area->size = size;
+ area->next = *p;
+ *p = area;
+ write_unlock(&btmlist_lock);
+ return area;
+}
+
+/*
+ * Free a range of bolted pages that were allocated with btmalloc
+ */
+char btfree_dummy;
+extern void * _get_SP(void);
+
+void btfree(void * addr) {
+
+ struct vm_struct **p, *tmp;
+ unsigned long size;
+
+ if ( !addr ) {
+ udbg_printf("btfree - bad address, returning w/o freeing - bad address=%p\n", addr);
+ return;
+ }
+
+ if ( ( PAGE_SIZE-1 ) & (unsigned long)addr ) {
+ udbg_printf("btfree - trying to btfree() bad address=%p\n", addr);
+ printk(KERN_ERR "Trying to btfree() bad address (%p)\n", addr);
+ return;
+ }
+
+ size = 0;
+
+ write_lock( &btmlist_lock );
+
+ /* Scan the bolted memory list for an entry matching
+ * the address to be freed, get the size (in bytes)
+ * and free the entry. The list lock is not dropped
+ * until the page table entries are removed.
+ */
+ for ( p = &btmlist; (tmp = *p); p = &tmp->next ) {
+ if ( tmp->addr == addr ) {
+ size = tmp->size;
+ /* *p = tmp->next;
+ kfree(tmp);
+ */
+ break;
+ }
+ }
+
+ /* If no entry found, it is an error */
+ if ( !size ) {
+ write_unlock(&btmlist_lock);
+ udbg_printf("no entry found for 0x%lx\n", addr);
+ printk(KERN_ERR "Trying to btfree() bad address (%p)\n", addr );
+ btfree_dummy = *((char *)0);
+ return;
+ }
+
+ if(btmalloc_debug) {
+ udbg_printf("btfree : 0x%lx (0x%lx) 0x%lx\n",
+ addr, ___pa(addr), size);
+ if(btmalloc_debug > 1) xmon(0);
+ }
+
+ /* Free up the bolted pages and remove the page table entries */
+ if ( local_free_bolted_pages( addr, size >> PAGE_SHIFT ) ) {
+ /* if we actually freed the pages (not just decremented use count)
+ * then free the list entry
+ */
+ *p = tmp->next;
+ kfree(tmp);
+ }
+
+ write_unlock(&btmlist_lock);
+}
+
+long btmallocread(char *buf, char *addr, unsigned long count) {
+ struct vm_struct *tmp;
+ char *vaddr, *buf_start = buf;
+ unsigned long n;
+
+ /* Don't allow overflow */
+ if ((unsigned long) addr + count < count)
+ count = -(unsigned long) addr;
+
+ read_lock(&btmlist_lock);
+ for (tmp = btmlist; tmp; tmp = tmp->next) {
+ vaddr = (char *) tmp->addr;
+ if (addr >= vaddr + tmp->size - PAGE_SIZE)
+ continue;
+ while (addr < vaddr) {
+ if (count == 0)
+ goto finished;
+ *buf = '\0';
+ buf++;
+ addr++;
+ count--;
+ }
+ n = vaddr + tmp->size - PAGE_SIZE - addr;
+ do {
+ if (count == 0)
+ goto finished;
+ *buf = *addr;
+ buf++;
+ addr++;
+ count--;
+ } while (--n > 0);
}
+ finished:
+ read_unlock(&btmlist_lock);
+ return buf - buf_start;
+}
- return 0;
+
+pmd_t *pmd_alloc_b(pgd_t *pgd, unsigned long address)
+{
+ pmd_t *pmd;
+ void *page;
+ unsigned long ea, pa, vsid;
+ struct vm_struct *area;
+
+ address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+ if (pgd_none(*pgd)) {
+ // allocate space in the bolted address range
+ area = get_btm_area( 4096, 0 );
+ ea = (unsigned long)area->addr;
+ page = (void *)__get_free_page(GFP_KERNEL);
+ clear_page(page);
+ pa = ((unsigned long)page - PAGE_OFFSET );
+ vsid = get_kernel_vsid( ea );
+
+ build_valid_hpte( vsid, ea, pa, NULL,
+ _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX, 1 );
+ pmd = (pmd_t *)ea;
+ pgd_set(pgd, pmd);
+ return pmd + address;
+ }
+ if (pgd_bad(*pgd)) {
+ __bad_pmd(pgd);
+ return NULL;
+ }
+ return (pmd_t *) pgd_page(*pgd) + address;
}
-void btfree(void *addr)
+pte_t *pte_alloc_b(pmd_t *pmd, unsigned long address)
{
- __vfree(addr, &btmalloc_ops);
+ pte_t *pte;
+ void *page;
+ struct vm_struct *area;
+ unsigned long ea, pa, vsid;
+
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ // allocate space in the bolted address range
+ area = get_btm_area( 4096, 0 );
+ ea = (unsigned long)area->addr;
+ page = (void *)__get_free_page(GFP_KERNEL);
+ clear_page(page);
+ pa = ((unsigned long)page - PAGE_OFFSET );
+ vsid = get_kernel_vsid( ea );
+
+ build_valid_hpte( vsid, ea, pa, NULL,
+ _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX, 1 );
+ pte = (pte_t *)ea;
+ pmd_set(pmd, pte);
+ return pte + address;
+ }
+ if (pmd_bad(*pmd)) {
+ __bad_pte(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + address;
}
-void *btmalloc(unsigned long size)
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+pte_t *empty_bad_page_table;
+
+pte_t * __bad_pagetable(void)
{
- return ___vmalloc(size, 0, 0, &btmalloc_ops);
+ clear_page(empty_bad_page_table);
+ return empty_bad_page_table;
}
-long btread(char *buf, char *addr, unsigned long count)
+void *empty_bad_page;
+
+pte_t __bad_page(void)
{
- return __vread(buf, addr, count, &btmalloc_ops);
+ clear_page(empty_bad_page);
+ return pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
}
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/mm/init.c linuxppc64_2_4/arch/ppc64/mm/init.c
--- linux-2.4.8-ac9/arch/ppc64/mm/init.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/mm/init.c Mon Aug 20 08:54:55 2001
@@ -119,20 +119,18 @@
int do_check_pgt_cache(int low, int high)
{
int freed = 0;
- if(pgtable_cache_size > high) {
+
+ if (pgtable_cache_size > high) {
do {
- if(pgd_quicklist)
- free_pgd_slow(get_pgd_fast()), freed++;
- if(pmd_quicklist)
- free_pmd_slow(get_pmd_fast()), freed++;
- if(pte_quicklist)
- {
- free_pte_slow(pte_alloc_one_fast(NULL,0));
- freed++;
- }
- } while(pgtable_cache_size > low);
+ if (pgd_quicklist)
+ free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed;
+ if (pmd_quicklist)
+ free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed;
+ if (pte_quicklist)
+ free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed;
+ } while (pgtable_cache_size > low);
}
- return freed;
+ return freed;
}
void show_mem(void)
@@ -277,8 +275,8 @@
ea = (unsigned long)(area->addr);
}
else {
- ea = ioremap_bot;
- ioremap_bot += size;
+ ea = ioremap_bot;
+ ioremap_bot += size;
}
if ((flags & _PAGE_PRESENT) == 0)
@@ -329,33 +327,33 @@
pte_t *ptep;
unsigned long vsid;
- if(mem_init_done) {
- spin_lock(&init_mm.page_table_lock);
- pgdp = pgd_offset_i(ea);
- pmdp = pmd_alloc(&init_mm, pgdp, ea);
- ptep = pte_alloc(&init_mm, pmdp, ea);
- set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
- spin_unlock(&init_mm.page_table_lock);
- } else {
- /* If the mm subsystem is not fully up, we cannot create a linux
- * page table entry for this mapping. Simply bolt an entry in the
- * hardware page table.
- */
- vsid = get_kernel_vsid(ea);
- make_pte(htab_data.htab,
- (vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea)
- pa,
- _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX,
- htab_data.htab_hash_mask);
- }
+ if (mem_init_done) {
+ spin_lock(&init_mm.page_table_lock);
+ pgdp = pgd_offset_i(ea);
+ pmdp = pmd_alloc(&init_mm, pgdp, ea);
+ ptep = pte_alloc(&init_mm, pmdp, ea);
+ set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
+ spin_unlock(&init_mm.page_table_lock);
+ } else {
+ /* If the mm subsystem is not fully up, we cannot create a
+ * linux page table entry for this mapping. Simply bolt an
+ * entry in the hardware page table.
+ */
+ vsid = get_kernel_vsid(ea);
+ make_pte(htab_data.htab,
+ (vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea)
+ pa,
+ _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX,
+ htab_data.htab_hash_mask);
+ }
}
void
local_flush_tlb_all(void)
{
-/*
- * Implemented to just flush the vmalloc area. vmalloc is the only user of flush_tlb_all
- */
+ /* Implemented to just flush the vmalloc area.
+ * vmalloc is the only user of flush_tlb_all.
+ */
local_flush_tlb_range( NULL, VMALLOC_START, VMALLOC_END );
}
@@ -367,7 +365,7 @@
for ( mp = mm->mmap; mp != NULL; mp = mp->vm_next )
local_flush_tlb_range( mm, mp->vm_start, mp->vm_end );
}
- else
+ else /* MIKEC: It is not clear why this is needed */
local_flush_tlb_range( mm, USER_START, USER_END );
}
@@ -428,10 +426,10 @@
unsigned long context;
if ( start >= end )
- return;
+ panic("flush_tlb_range: start (%016lx) greater than end (%016lx)\n", start, end );
if ( REGION_ID(start) != REGION_ID(end) )
- panic("flush_tlb_range start (%016lx) and end (%016lx) not in same region\n", start, end );
+ panic("flush_tlb_range: start (%016lx) and end (%016lx) not in same region\n", start, end );
context = 0;
@@ -450,7 +448,7 @@
context = mm->context;
break;
default:
- return;
+ panic("flush_tlb_range: invalid region for start (%016lx) and end (%016lx)\n", start, end);
}
@@ -577,7 +575,7 @@
*/
bootmap_pages = bootmem_bootmap_pages(total_pages);
- start = __a2p(lmb_alloc(bootmap_pages<
- * Changes to accomodate Power Macintoshes.
- * Cort Dougan
- * Rewrites.
- * Grant Erickson
- * General rework and split from mm/init.c.
- * Dave Engebretsen
- * PPC 64b rework.
- *
- * Module name: mem_pieces.c
- *
- * Description:
- * Routines and data structures for manipulating and representing
- * phyiscal memory extents (i.e. address/length pairs).
- *
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "mem_pieces.h"
-
-#include
-
-extern struct mem_pieces phys_avail;
-
-void mem_pieces_print(struct mem_pieces *);
-
-/*
- * Scan a region for a piece of a given size with the required alignment.
- */
-void __init *
-mem_pieces_find(unsigned long size, unsigned int align)
-{
- long i;
- unsigned long a, e;
- struct mem_pieces *mp = &phys_avail;
-
- for (i = 0; i < mp->n_regions; ++i) {
- a = mp->regions[i].address;
- e = a + mp->regions[i].size;
- a = (a + align - 1) & -align;
- if (a + size <= e) {
- mem_pieces_remove(mp, a, size, 1);
- return __va(a);
- }
- }
- panic("Couldn't find %lu bytes at %u alignment\n", size, align);
-
- return NULL;
-}
-
-/*
- * Remove some memory from an array of pieces
- */
-void __init
-mem_pieces_remove(struct mem_pieces *mp,
- unsigned long start,
- unsigned long size,
- int must_exist)
-{
- long i, j;
- unsigned long end, rs, re;
- struct reg_property *rp;
-
- end = start + size;
- for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
- if (end > rp->address && start < rp->address + rp->size)
- break;
- }
- if (i >= mp->n_regions) {
- if (must_exist)
- printk("mem_pieces_remove: [%lx,%lx] not in any region\n", start, end);
- return;
- }
- for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
- rs = rp->address;
- re = rs + rp->size;
- if (must_exist && (start < rs || end > re)) {
- printk("mem_pieces_remove: bad overlap [%lx,%lx] with",
- start, end);
- mem_pieces_print(mp);
- must_exist = 0;
- }
- if (start > rs) {
- rp->size = start - rs;
- if (end < re) {
- /* need to split this entry */
- if (mp->n_regions >= MEM_PIECES_MAX)
- panic("eek... mem_pieces overflow");
- for (j = mp->n_regions; j > i + 1; --j)
- mp->regions[j] = mp->regions[j-1];
- ++mp->n_regions;
- rp[1].address = end;
- rp[1].size = re - end;
- }
- } else {
- if (end < re) {
- rp->address = end;
- rp->size = re - end;
- } else {
- /* need to delete this entry */
- for (j = i; j < mp->n_regions - 1; ++j)
- mp->regions[j] = mp->regions[j+1];
- --mp->n_regions;
- --i;
- --rp;
- }
- }
- }
-}
-
-void __init
-mem_pieces_print(struct mem_pieces *mp)
-{
- int i;
-
- PPCDBG(PPCDBG_MMINIT, "\tmem_pieces_print\n");
-
- for (i = 0; i < mp->n_regions; ++i) {
- PPCDBG(PPCDBG_MMINIT, "\t\t[0x%lx, 0x%lx)\n",
- mp->regions[i].address,
- mp->regions[i].address + mp->regions[i].size);
- }
-}
-
-/*
- * Add some memory to an array of pieces
- */
-void __init
-mem_pieces_append(struct mem_pieces *mp,
- unsigned long start,
- unsigned long size)
-{
- struct reg_property *rp;
-
- if (mp->n_regions >= MEM_PIECES_MAX)
- return;
- rp = &mp->regions[mp->n_regions++];
- rp->address = start;
- rp->size = size;
-}
-
-void __init
-mem_pieces_sort(struct mem_pieces *mp)
-{
- unsigned long a, s;
- long i, j;
-
- for (i = 1; i < mp->n_regions; ++i) {
- a = mp->regions[i].address;
- s = mp->regions[i].size;
- for (j = i - 1; j >= 0; --j) {
- if (a >= mp->regions[j].address)
- break;
- mp->regions[j+1] = mp->regions[j];
- }
- mp->regions[j+1].address = a;
- mp->regions[j+1].size = s;
- }
-}
-
-void __init
-mem_pieces_coalesce(struct mem_pieces *mp)
-{
- unsigned long a, s, ns;
- long i, j, d;
-
- d = 0;
- for (i = 0; i < mp->n_regions; i = j) {
- a = mp->regions[i].address;
- s = mp->regions[i].size;
- for (j = i + 1; j < mp->n_regions
- && mp->regions[j].address - a <= s; ++j) {
- ns = mp->regions[j].address + mp->regions[j].size - a;
- if (ns > s)
- s = ns;
- }
- mp->regions[d].address = a;
- mp->regions[d].size = s;
- ++d;
- }
- mp->n_regions = d;
-}
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/mm/mem_pieces.h linuxppc64_2_4/arch/ppc64/mm/mem_pieces.h
--- linux-2.4.8-ac9/arch/ppc64/mm/mem_pieces.h Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/mm/mem_pieces.h Wed Dec 31 18:00:00 1969
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 1996 Paul Mackerras
- * Changes to accomodate Power Macintoshes.
- * Cort Dougan
- * Rewrites.
- * Grant Erickson
- * General rework and split from mm/init.c.
- * Dave Engebretsen
- * PPC 64b rework.
- *
- * Module name: mem_pieces.h
- *
- * Description:
- * Routines and data structures for manipulating and representing
- * phyiscal memory extents (i.e. address/length pairs).
- *
- */
-
-#ifndef __MEM_PIECES_H__
-#define __MEM_PIECES_H__
-
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Type Definitions */
-
-#define MEM_PIECES_MAX 32
-
-struct mem_pieces {
- int n_regions;
- struct reg_property regions[MEM_PIECES_MAX];
-};
-
-/* Function Prototypes */
-
-extern void *mem_pieces_find(unsigned long size, unsigned int align);
-extern void mem_pieces_remove(struct mem_pieces *mp, unsigned long start,
- unsigned long size, int must_exist);
-extern void mem_pieces_append(struct mem_pieces *mp, unsigned long start,
- unsigned long size);
-extern void mem_pieces_coalesce(struct mem_pieces *mp);
-extern void mem_pieces_sort(struct mem_pieces *mp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEM_PIECES_H__ */
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/mymacros.h linuxppc64_2_4/arch/ppc64/mymacros.h
--- linux-2.4.8-ac9/arch/ppc64/mymacros.h Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/mymacros.h Wed Dec 31 18:00:00 1969
@@ -1,39 +0,0 @@
-
-#undef PPC64_ELF_SECTIONS
-#ifndef PPC64_ELF_SECTIONS
-
-/* The toolchain cannot handle this yet, so comment them *all* out. */
-#ifdef __section__
-# undef __section__
-# define __section__(X)
-#endif
-
-#if 0
- /* These are commented out in asm-ppc64/init.h
- * These will/may go back in once we get ELF named
- * sections in gcc 3.X -Peter.
- */
- __chrp, __chrpdata, __chrpfunc(x), __openfirmware,
- __openfirmwaredata, __openfirmwarefunc(x)
-#endif
-
-#endif /* PPC64_ELF_SECTIONS */
-
-#define DEBUG_DELAY
-#if 0
-#define PIRANHA
-#define DEBUG_YABOOT
-#define DEBUG_PROM
-#endif
-
-
-#if 1
-/* For 64-bit apps, temporarily reduce the size of the address space
- * available to user application. This allow us to use strace without
- * having to compile a strace64 program. This shouldn't affect anyone
- * other than Steve Munroe, Peter Bergner. I will back this hack out
- * later... -Peter
- */
-#define PPC64_32B_ADDR_SPACE
-#endif
-
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/vmlinux.lds linuxppc64_2_4/arch/ppc64/vmlinux.lds
--- linux-2.4.8-ac9/arch/ppc64/vmlinux.lds Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/vmlinux.lds Tue Aug 21 14:47:57 2001
@@ -69,8 +69,15 @@
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
+ __start___kallsyms = .; /* All kernel symbols */
+ __kallsyms : { *(__kallsyms) }
+ __stop___kallsyms = .;
- . = ALIGN(32);
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.page_aligned) }
+
+ . = ALIGN(128);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
. = ALIGN(4096);
@@ -121,6 +128,7 @@
. = ALIGN(4096);
__toc_end = .;
+ . = ALIGN(4096);
__bss_start = .;
.bss :
{
diff -uNr --exclude=CVS linux-2.4.8-ac9/arch/ppc64/xmon/xmon.c linuxppc64_2_4/arch/ppc64/xmon/xmon.c
--- linux-2.4.8-ac9/arch/ppc64/xmon/xmon.c Thu Aug 23 09:17:16 2001
+++ linuxppc64_2_4/arch/ppc64/xmon/xmon.c Fri Aug 17 13:55:51 2001
@@ -942,7 +942,6 @@
#if 0
|| stack[2] == (unsigned) &ret_from_intercept
|| stack[2] == (unsigned) &ret_from_syscall_2
- || stack[2] == (unsigned) &lost_irq_ret
|| stack[2] == (unsigned) &do_bottom_half_ret
|| stack[2] == (unsigned) &do_signal_ret
#endif
@@ -961,6 +960,11 @@
printf(" %s+0x%x", tab.name, delta);
}
printf("\n");
+ if (regs.gpr[1] < sp) {
+ printf("\n", regs.gpr[1]);
+ break;
+ }
+
sp = regs.gpr[1];
if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
break;
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/block/Config.in linuxppc64_2_4/drivers/block/Config.in
--- linux-2.4.8-ac9/drivers/block/Config.in Thu Aug 23 09:17:18 2001
+++ linuxppc64_2_4/drivers/block/Config.in Fri Aug 17 13:03:16 2001
@@ -28,6 +28,12 @@
tristate ' Atari SLM laser printer support' CONFIG_ATARI_SLM
fi
fi
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+ dep_tristate 'iSeries Virtual I/O disk support' CONFIG_VIODASD $CONFIG_PPC_ISERIES
+ if [ "$CONFIG_VIODASD" = "y" -o "$CONFIG_VIODASD" = "m" ]; then
+ bool 'iSeries Virtual disk IDE emulation' CONFIG_VIODASD_IDE
+ fi
+fi
dep_tristate 'XT hard disk support' CONFIG_BLK_DEV_XD $CONFIG_ISA
dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT
if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/block/Makefile linuxppc64_2_4/drivers/block/Makefile
--- linux-2.4.8-ac9/drivers/block/Makefile Thu Aug 23 09:17:18 2001
+++ linuxppc64_2_4/drivers/block/Makefile Mon Jun 18 18:18:47 2001
@@ -20,6 +20,7 @@
obj-$(CONFIG_BLK_DEV_FD) += floppy.o
obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o
obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
+obj-$(CONFIG_VIODASD) += viodasd.o
obj-$(CONFIG_BLK_DEV_SWIM_IOP) += swim_iop.o
obj-$(CONFIG_ATARI_ACSI) += acsi.o
obj-$(CONFIG_ATARI_SLM) += acsi_slm.o
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/block/genhd.c linuxppc64_2_4/drivers/block/genhd.c
--- linux-2.4.8-ac9/drivers/block/genhd.c Thu Jul 19 19:48:15 2001
+++ linuxppc64_2_4/drivers/block/genhd.c Mon Jun 18 18:18:47 2001
@@ -30,6 +30,7 @@
extern int atmdev_init(void);
extern int i2o_init(void);
extern int cpqarray_init(void);
+extern void ieee1394_init(void);
int __init device_init(void)
{
@@ -48,6 +49,9 @@
/* This has to be done before scsi_dev_init */
soc_probe();
#endif
+#ifdef CONFIG_IEEE1394
+ ieee1394_init();
+#endif
#ifdef CONFIG_BLK_CPQ_DA
cpqarray_init();
#endif
@@ -59,6 +63,9 @@
#endif
#ifdef CONFIG_VT
console_map_init();
+#endif
+#ifdef CONFIG_VIODASD
+ viodasd_init();
#endif
return 0;
}
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/block/ll_rw_blk.c linuxppc64_2_4/drivers/block/ll_rw_blk.c
--- linux-2.4.8-ac9/drivers/block/ll_rw_blk.c Thu Aug 23 09:17:19 2001
+++ linuxppc64_2_4/drivers/block/ll_rw_blk.c Fri Aug 10 13:08:53 2001
@@ -1229,6 +1229,9 @@
#ifdef CONFIG_BLK_DEV_XD
xd_init();
#endif
+#ifdef CONFIG_VIOCD
+ viocd_init();
+#endif
#ifdef CONFIG_BLK_DEV_MFM
mfm_init();
#endif
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/block/viodasd.c linuxppc64_2_4/drivers/block/viodasd.c
--- linux-2.4.8-ac9/drivers/block/viodasd.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/block/viodasd.c Fri Aug 24 10:28:37 2001
@@ -0,0 +1,1356 @@
+/*
+ * viodasd.c
+ * Copyright (C) 2001 Dave Boutcher IBM Corporation
+ ***************************************************************************
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ***************************************************************************
+ * This routine provides access to disk space (termed "DASD" in historical
+ * IBM terms) owned and managed by an OS/400 partition running on the
+ * same box as this Linux partition.
+ *
+ * All disk operations are performed by sending messages back and forth to
+ * the OS/400 partition. The format of the messages is defined in
+ * include/asm-ppc/iSeries/vio.h
+ *
+ * This device driver can either use it's own major number, or it can
+ * pretend to be an IDE drive (Major #3). Currently it doesn't
+ * emulate all the other IDE majors. This is controlled with a
+ * CONFIG option. You can either call this an elegant solution to the
+ * fact that a lot of software doesn't recognize a new disk major number...
+ * or you can call this a really ugly hack. Your choice.
+ */
+
+#include
+#include
+
+/***************************************************************************
+ * Decide if we are using our own major or pretending to be an IDE drive
+ *
+ * If we are using our own majors, we only support 3 partitions per physical
+ * disk....so with minor numbers 0-255 we get a maximum of 64 disks. If we
+ * are emulating IDE, we get 16 partitions per disk, with a maximum of 16
+ * disks
+ ***************************************************************************/
+#ifdef CONFIG_VIODASD_IDE
+#define MAJOR_NR IDE0_MAJOR
+#define PARTITION_SHIFT 6
+#define do_viodasd_request do_hd_request
+static int numdsk = 16;
+static int viodasd_max_disk = 16;
+#define VIOD_DEVICE_NAME "hd"
+#define VIOD_GENHD_NAME "hd"
+#else
+#define MAJOR_NR VIODASD_MAJOR
+#define PARTITION_SHIFT 3
+static int numdsk = 32;
+static int viodasd_max_disk = 32;
+#define VIOD_DEVICE_NAME "viod"
+#ifdef CONFIG_DEVFS_FS
+#define VIOD_GENHD_NAME "viod"
+#else
+#define VIOD_GENHD_NAME "iSeries/vd"
+#endif /* CONFIG_DEVFS */
+#endif /* CONFIG_VIODASD_IDE */
+
+
+#define VIODASD_VERS "1.02"
+#define LOCAL_END_REQUEST
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifndef _HVTYPES_H
+#include
+#endif
+#ifndef _HVLPEVENT_H
+#include
+#endif
+#ifndef _HVLPCONFIG_H
+#include
+#endif
+#ifndef _VIO_H
+#include "asm/iSeries/vio.h"
+#endif
+#ifndef _ISERIES_PROC_H
+#include
+#endif
+
+MODULE_DESCRIPTION("iSeries Virtual DASD");
+MODULE_AUTHOR("Dave Boutcher");
+
+/***************************************************************************
+ * In a perfect world we will perform better if we get page-aligned I/O
+ * requests, in multiples of pages. At least peg our block size fo the
+ * actual page size.
+ ***************************************************************************/
+static int blksize = HVPAGESIZE; /* in bytes */
+
+static DECLARE_WAIT_QUEUE_HEAD(viodasd_wait);
+struct viodasd_waitevent {
+ struct semaphore *sem;
+ int rc;
+ int changed; /* Used only for check_change */
+};
+
+/***************************************************************************
+ * All our disk-related global structures
+ ***************************************************************************/
+static struct hd_struct *viodasd_partitions;
+static int *viodasd_sizes;
+static int *viodasd_sectsizes;
+static int *viodasd_maxsectors;
+extern struct gendisk viodasd_gendsk;
+
+/***************************************************************************
+ * Figure out the biggest I/O request (in sectors) we can accept
+ ***************************************************************************/
+#define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA)
+
+/***************************************************************************
+ * Keep some statistics on what's happening for the PROC file system
+ ***************************************************************************/
+static struct {
+ long tot;
+ long nobh;
+ long ntce[VIOMAXBLOCKDMA];
+} viod_stats[64][2];
+
+/***************************************************************************
+ * Number of disk I/O requests we've sent to OS/400
+ ***************************************************************************/
+static int numReqOut;
+
+/***************************************************************************
+ * Our internal printk macro
+ ***************************************************************************/
+#define err_printk(fmt, args...) \
+printk(KERN_ERR "(%s:%3.3d) ERR: " fmt, __FILE__, __LINE__ , ## args)
+
+/***************************************************************************
+ * This is our internal structure for keeping track of disk devices
+ ***************************************************************************/
+struct viodasd_device {
+ int useCount;
+ u16 cylinders;
+ u16 tracks;
+ u16 sectors;
+ u16 bytesPerSector;
+ u64 size;
+ int readOnly;
+} *viodasd_devices;
+
+/***************************************************************************
+ * When we get a disk I/O request we take it off the general request queue
+ * and put it here.
+ ***************************************************************************/
+static LIST_HEAD(reqlist);
+
+/***************************************************************************
+ ***************************************************************************
+ * CODE STARTS HERE
+ ***************************************************************************
+ ***************************************************************************/
+
+/***************************************************************************
+ * Handle reads from the proc file system
+ ***************************************************************************/
+static int proc_read(char *buf, char **start, off_t offset,
+ int blen, int *eof, void *data)
+{
+ int len = 0;
+ int i;
+ int j;
+
+#if defined(MODULE)
+ len += sprintf(buf+len,"viod Module opened %d times. Major number %d\n",
+ MOD_IN_USE,
+ MAJOR_NR);
+#endif
+ len += sprintf(buf+len,"viod %d devices\n",
+ numdsk);
+
+ for (i=0; i<16; i++)
+ {
+ if (viod_stats[i][0].tot || viod_stats[i][1].tot)
+ {
+ len += sprintf(buf+len,"DISK %2.2d: rd %-10.10ld wr %-10.10ld (no buffer list rd %-10.10ld wr %-10.10ld\n",
+ i, viod_stats[i][0].tot,viod_stats[i][1].tot,viod_stats[i][0].nobh,viod_stats[i][1].nobh);
+
+ len += sprintf(buf+len,"rd DMA: ");
+
+ for (j=0; jnlink = 1;
+ ent->data = NULL;
+ ent->read_proc = proc_read;
+ ent->write_proc = proc_write;
+}
+
+/***************************************************************************
+ * clean up our proc file system entries
+ ***************************************************************************/
+void viodasd_proc_delete(struct proc_dir_entry *iSeries_proc)
+{
+ remove_proc_entry("viodasd", iSeries_proc);
+}
+
+/***************************************************************************
+ * End a request
+ ***************************************************************************/
+static void viodasd_end_request(struct request *req, int uptodate) {
+
+ if (end_that_request_first(req, uptodate, VIOD_DEVICE_NAME))
+ return;
+
+ end_that_request_last(req);
+}
+
+/***************************************************************************
+ * This rebuilds the partition information for a single disk device
+ ***************************************************************************/
+static int viodasd_revalidate(kdev_t dev)
+{
+ int i;
+ int device_no = DEVICE_NR(dev);
+ int part0 = (device_no << PARTITION_SHIFT);
+ int npart = (1<=0;i--)
+ {
+ minor = part0 +i;
+
+ if (viodasd_partitions[minor].nr_sects != 0)
+ {
+ devp = MKDEV(MAJOR_NR, minor);
+ fsync_dev(devp);
+
+ sb = get_super(devp);
+ if (sb) invalidate_inodes(sb);
+
+ invalidate_buffers(devp);
+ }
+
+ viodasd_partitions[minor].start_sect = 0;
+ viodasd_partitions[minor].nr_sects = 0;
+ }
+
+ grok_partitions(&viodasd_gendsk, device_no, npart, viodasd_devices[device_no].size>>9);
+
+ return 0;
+}
+
+/***************************************************************************
+ * This is the actual open code. It gets called from the external
+ * open entry point, as well as from the init code when we're figuring
+ * out what disks we have
+ ***************************************************************************/
+static int internal_open(int device_no)
+{
+ int i;
+ struct viodasd_waitevent we;
+
+ HvLpEvent_Rc hvrc;
+ /* This semaphore is raised in the interrupt handler */
+ DECLARE_MUTEX_LOCKED(Semaphore);
+
+ /* Check that we are dealing with a valid hosting partition */
+ if (viopath_hostLp == HvLpIndexInvalid)
+ {
+ err_printk("Invalid hosting partition\n");
+ return -EIO;
+ }
+
+ we.sem = &Semaphore;
+
+ /* Send the open event to OS/400 */
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_blockio | vioblockopen,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(unsigned long)&we,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ 0, 0, 0);
+
+ if (hvrc != 0)
+ {
+ err_printk("bad rc on signalLpEvent %d\n",(int)hvrc);
+ return -EIO;
+ }
+
+ /* Wait for the interrupt handler to get the response */
+ down(&Semaphore);
+
+ /* Check the return code */
+ if (we.rc != 0)
+ {
+ err_printk("bad rc opening disk: %d\n",(int)we.rc);
+ return we.rc;
+ }
+
+ /* If this is the first open of this device, update the device information */
+ /* If this is NOT the first open, assume that it isn't changing */
+ if (viodasd_devices[device_no].useCount == 0)
+ {
+ if (viodasd_devices[device_no].size > 0)
+ {
+ /* divide by 512 */
+ u64 tmpint = viodasd_devices[device_no].size >> 9;
+ viodasd_partitions[device_no << PARTITION_SHIFT].nr_sects = tmpint;
+ /* Now the value divided by 1024 */
+ tmpint = tmpint >> 1;
+ viodasd_sizes[device_no << PARTITION_SHIFT] = tmpint;
+
+ for (i = (device_no << PARTITION_SHIFT);
+ i < ((device_no+1) << PARTITION_SHIFT);
+ i++)
+ viodasd_sectsizes[i] = viodasd_devices[device_no].bytesPerSector;
+
+ }
+ }
+ else
+ {
+ /* If the size of the device changed, wierd things are happening! */
+ if (viodasd_sizes[device_no<> 10)
+ {
+ err_printk("disk size change (%dK to %dK) for device %d\n",
+ viodasd_sizes[device_no<> 10,
+ device_no);
+ }
+ }
+
+ /* Bump the use count */
+ viodasd_devices[device_no].useCount++;
+
+ return 0;
+}
+
+/***************************************************************************
+ * This is the actual release code. It gets called from the external
+ * release entry point, as well as from the init code when we're figuring
+ * out what disks we have
+ ***************************************************************************/
+static int internal_release(int device_no)
+{
+
+ /* Send the event to OS/400. We DON'T expect a response */
+ HvLpEvent_Rc hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_blockio | vioblockclose,
+ HvLpEvent_AckInd_NoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ 0,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ 0, 0, 0);
+
+ viodasd_devices[device_no].useCount--;
+
+ if (hvrc != 0)
+ {
+ err_printk("bad rc on signalLpEvent %d\n",(int)hvrc);
+ return -EIO;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ * External open entry point.
+ ***************************************************************************/
+static int viodasd_open(struct inode *ino, struct file *fil)
+{
+ int device_no;
+
+ /* Do a bunch of sanity checks */
+ if (!ino)
+ {
+ err_printk("no inode provided in open\n");
+ return -ENODEV;
+ }
+
+ if (MAJOR(ino->i_rdev) != MAJOR_NR)
+ {
+ err_printk("Wierd error...wrong major number on open\n");
+ return -ENODEV;
+ }
+
+ device_no = DEVICE_NR(ino->i_rdev);
+ if (device_no > numdsk)
+ {
+ err_printk("Invalid minor device number %d in open\n",device_no);
+ return -ENODEV;
+ }
+
+ /* Call the actual open code */
+ if (internal_open(device_no) == 0)
+ {
+ if (fil && fil->f_mode)
+ {
+ if (fil->f_mode & 2)
+ {
+ if (viodasd_devices[device_no].readOnly) {
+ internal_release( device_no );
+ return -EROFS;
+ }
+ }
+ }
+ MOD_INC_USE_COUNT;
+ return 0;
+ }
+ else
+ {
+ return -EIO;
+ }
+}
+
+/***************************************************************************
+ * External release entry point.
+ ***************************************************************************/
+static int viodasd_release(struct inode *ino, struct file *fil)
+{
+ int device_no;
+
+ /* Do a bunch of sanity checks */
+ if (!ino)
+ {
+ err_printk("no inode provided in release\n");
+ return -ENODEV;
+ }
+
+ if (MAJOR(ino->i_rdev) != MAJOR_NR)
+ {
+ err_printk("Wierd error...wrong major number on release\n");
+ return -ENODEV;
+ }
+
+ device_no = DEVICE_NR(ino->i_rdev);
+ if (device_no > numdsk)
+ {
+ return -ENODEV;
+ }
+
+ /* Just to be paranoid, sync the device */
+ fsync_dev(ino->i_rdev);
+
+ /* Call the actual release code */
+ internal_release(device_no);
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/***************************************************************************
+ * External ioctl entry point.
+ ***************************************************************************/
+static int viodasd_ioctl(struct inode *ino, struct file *fil, unsigned int cmd, unsigned long arg)
+{
+ int device_no;
+ int err;
+ HvLpEvent_Rc hvrc;
+ DECLARE_MUTEX_LOCKED(Semaphore);
+
+ /* Sanity checks */
+ if (!ino)
+ {
+ err_printk("no inode provided in ioctl\n");
+ return -ENODEV;
+ }
+
+ if (MAJOR(ino->i_rdev) != MAJOR_NR)
+ {
+ err_printk("Wierd error...wrong major number on ioctl\n");
+ return -ENODEV;
+ }
+
+ device_no = DEVICE_NR(ino->i_rdev);
+ if (device_no > numdsk)
+ {
+ err_printk("Invalid minor device number %d in ioctl\n",device_no);
+ return -ENODEV;
+ }
+
+ switch(cmd) {
+ case BLKGETSIZE:
+ /* return the device size in sectors */
+ if (!arg) return -EINVAL;
+ err = verify_area(VERIFY_WRITE, (long *)arg, sizeof(long));
+ if (err) return err;
+
+ put_user(viodasd_partitions[MINOR(ino->i_rdev)].nr_sects, (long *)arg);
+ return 0;
+
+ case FDFLUSH:
+ case BLKFLSBUF:
+ if (!suser()) return -EACCES;
+ fsync_dev(ino->i_rdev);
+ invalidate_buffers(ino->i_rdev);
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_blockio | vioblockflush,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(unsigned long)&Semaphore,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ 0, 0, 0);
+
+
+ if (hvrc != 0)
+ {
+ err_printk("bad rc on sync signalLpEvent %d\n",(int)hvrc);
+ return -EIO;
+ }
+
+ down(&Semaphore);
+
+ return 0;
+
+ case BLKRAGET:
+ if (!arg) return -EINVAL;
+ err = verify_area(VERIFY_WRITE, (long *)arg, sizeof(long));
+ if (err) return err;
+ put_user(read_ahead[MAJOR_NR], (long *)arg);
+ return 0;
+
+ case BLKRASET:
+ if (!suser()) return -EACCES;
+ if (arg > 0x00ff) return -EINVAL;
+ read_ahead[MAJOR_NR] = arg;
+ return 0;
+
+ case BLKRRPART:
+ viodasd_revalidate(ino->i_rdev);
+ return 0;
+
+ case HDIO_GETGEO:
+ {
+ unsigned char sectors;
+ unsigned char heads;
+ unsigned short cylinders;
+
+ struct hd_geometry *geo = (struct hd_geometry *)arg;
+ if (geo == NULL) return -EINVAL;
+
+ err = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
+ if (err) return err;
+
+ sectors = viodasd_devices[device_no].sectors;
+ if (sectors == 0)
+ sectors = 32;
+
+ heads = viodasd_devices[device_no].tracks;
+ if (heads == 0)
+ heads = 64;
+
+ cylinders = viodasd_devices[device_no].cylinders;
+ if (cylinders == 0)
+ cylinders = viodasd_partitions[MINOR(ino->i_rdev)].nr_sects / (sectors * heads);
+
+ put_user(sectors , &geo->sectors );
+ put_user(heads , &geo->heads );
+ put_user(cylinders, &geo->cylinders);
+
+ put_user(viodasd_partitions[MINOR(ino->i_rdev)].start_sect,(long *)&geo->start);
+
+ return 0;
+ }
+
+#define PRTIOC(x) case x: err_printk("got unsupported FD ioctl " #x "\n"); \
+ return -EINVAL;
+
+ PRTIOC(FDCLRPRM);
+ PRTIOC(FDSETPRM);
+ PRTIOC(FDDEFPRM);
+ PRTIOC(FDGETPRM);
+ PRTIOC(FDMSGON);
+ PRTIOC(FDMSGOFF);
+ PRTIOC(FDFMTBEG);
+ PRTIOC(FDFMTTRK);
+ PRTIOC(FDFMTEND);
+ PRTIOC(FDSETEMSGTRESH);
+ PRTIOC(FDSETMAXERRS);
+ PRTIOC(FDGETMAXERRS);
+ PRTIOC(FDGETDRVTYP);
+ PRTIOC(FDSETDRVPRM);
+ PRTIOC(FDGETDRVPRM);
+ PRTIOC(FDGETDRVSTAT);
+ PRTIOC(FDPOLLDRVSTAT);
+ PRTIOC(FDRESET);
+ PRTIOC(FDGETFDCSTAT);
+ PRTIOC(FDWERRORCLR);
+ PRTIOC(FDWERRORGET);
+ PRTIOC(FDRAWCMD);
+ PRTIOC(FDEJECT);
+ PRTIOC(FDTWADDLE);
+
+ }
+
+ return -EINVAL;
+}
+
+/***************************************************************************
+ * Send an actual I/O request to OS/400
+ ***************************************************************************/
+static int send_request(struct request *req)
+{
+ u64 sect_size;
+ u64 start;
+ u64 len;
+ int direction;
+ int nsg;
+ u16 viocmd;
+ HvLpEvent_Rc hvrc;
+ struct vioblocklpevent *bevent = (struct vioblocklpevent *)vio_block_event_buffer;
+ struct scatterlist sg[VIOMAXBLOCKDMA];
+ struct buffer_head *bh;
+ int sgindex;
+ int device_no = DEVICE_NR(req->rq_dev);
+ int statindex;
+
+ /* Note that this SHOULD always be 512...but lets be architecturally correct */
+ sect_size = hardsect_size[MAJOR_NR][device_no];
+
+ /* Figure out teh starting sector and length */
+ start = (req->sector + viodasd_partitions[MINOR(req->rq_dev)].start_sect) * sect_size;
+ len = req->nr_sectors * sect_size;
+
+ /* More paranoia checks */
+ if ((req->sector + req->nr_sectors) >
+ (viodasd_partitions[MINOR(req->rq_dev)].start_sect +
+ viodasd_partitions[MINOR(req->rq_dev)].nr_sects))
+ {
+ err_printk("Invalid request offset & length\n");
+ err_printk("req->sector: %ld, req->nr_sectors: %ld\n", req->sector, req->nr_sectors);
+ err_printk("RQ_DEV: %d, minor: %d\n", req->rq_dev, MINOR(req->rq_dev));
+ return -1;
+ }
+
+ if (req->cmd == READ)
+ {
+ direction = PCI_DMA_FROMDEVICE;
+ viocmd = viomajorsubtype_blockio | vioblockread;
+ statindex = 0;
+ }
+ else
+ {
+ direction = PCI_DMA_TODEVICE;
+ viocmd = viomajorsubtype_blockio | vioblockwrite;
+ statindex = 1;
+ }
+
+ /* Update totals */
+ viod_stats[device_no][statindex].tot++;
+
+ /* Now build the scatter-gather list */
+ memset(&sg, 0x00, sizeof(sg));
+ sgindex = 0;
+
+ /* See if this is a swap I/O (without a bh pointer) or a regular I/O */
+ if (req->bh)
+ {
+ /* OK...this loop takes buffers from the request and adds them to the SG
+ until we're done, or until we hit a maximum. If we hit a maximum we'll
+ just finish this request later */
+ bh = req->bh;
+ while ((bh) && (sgindex < VIOMAXBLOCKDMA))
+ {
+ sg[sgindex].address = bh->b_data;
+ sg[sgindex].length = bh->b_size;
+
+ sgindex++;
+ bh = bh->b_reqnext;
+ }
+ nsg = pci_map_sg(NULL, sg, sgindex, direction);
+ if ((nsg == 0) || (sg[0].dma_length == 0) || (sg[0].dma_address == 0xFFFFFFFF))
+ {
+ err_printk("error getting sg tces\n");
+ return -1;
+ }
+
+ }
+ else
+ {
+ /* Update stats */
+ viod_stats[device_no][statindex].nobh++;
+
+ sg[0].dma_address = pci_map_single(NULL, req->buffer,
+ len,
+ direction);
+ if (sg[0].dma_address == 0xFFFFFFFF)
+ {
+ err_printk("error allocating tce for address %p len %ld\n",
+ req->buffer,
+ (long)len);
+ return -1;
+ }
+ sg[0].dma_length = len;
+ nsg = 1;
+ }
+
+ /* Update stats */
+ viod_stats[device_no][statindex].ntce[sgindex]++;
+
+ /* This optimization handles a single DMA block */
+ if (sgindex == 1)
+ {
+ /* Send the open event to OS/400 */
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_blockio | viocmd,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(unsigned long)req->buffer,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ start,
+ ((u64)sg[0].dma_address)<<32,
+ sg[0].dma_length);
+ }
+ else
+ {
+ /* Now build up the actual request. Note that we store the pointer */
+ /* to the request buffer in the correlation token so we can match */
+ /* this response up later */
+ memset(bevent,0x00,sizeof(struct vioblocklpevent));
+ bevent->event.xFlags.xValid = 1;
+ bevent->event.xFlags.xFunction = HvLpEvent_Function_Int;
+ bevent->event.xFlags.xAckInd = HvLpEvent_AckInd_DoAck;
+ bevent->event.xFlags.xAckType = HvLpEvent_AckType_ImmediateAck;
+ bevent->event.xType = HvLpEvent_Type_VirtualIo;
+ bevent->event.xSubtype = viocmd;
+ bevent->event.xSourceLp = HvLpConfig_getLpIndex();
+ bevent->event.xTargetLp = viopath_hostLp;
+ bevent->event.xSizeMinus1 = offsetof(struct vioblocklpevent,
+ u.rwData.dmaInfo) +
+ (sizeof(bevent->u.rwData.dmaInfo[0])*(sgindex))-1;
+ bevent->event.xSizeMinus1 = sizeof(struct vioblocklpevent)-1;
+ bevent->event.xSourceInstanceId = viopath_sourceinst(viopath_hostLp);
+ bevent->event.xTargetInstanceId = viopath_targetinst(viopath_hostLp);
+ bevent->event.xCorrelationToken = (u64)(unsigned long)req->buffer;
+ bevent->mVersion = VIOVERSION;
+ bevent->mDisk = device_no;
+ bevent->u.rwData.mOffset = start;
+
+ /* Copy just the dma information from the sg list into the request */
+ for (sgindex = 0; sgindex < nsg; sgindex++)
+ {
+ bevent->u.rwData.dmaInfo[sgindex].mToken = sg[sgindex].dma_address;
+ bevent->u.rwData.dmaInfo[sgindex].mLen = sg[sgindex].dma_length;
+ }
+
+ /* Send the request */
+ hvrc = HvCallEvent_signalLpEvent(&bevent->event);
+ }
+
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ err_printk("hv error on op %d\n",(int)hvrc);
+ return -1;
+ }
+ else
+ {
+ /* If the request was successful, bump the number of outstanding */
+ numReqOut++;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ * This is the external request processing routine
+ ***************************************************************************/
+static void do_viodasd_request(request_queue_t *q)
+{
+ int device_no;
+ struct request *req;
+ for (;;) {
+
+ INIT_REQUEST;
+
+ device_no = CURRENT_DEV;
+ if (device_no > numdsk)
+ {
+ err_printk("Invalid device # %d\n",CURRENT_DEV);
+ viodasd_end_request(CURRENT, 0);
+ continue;
+ }
+
+ if (viodasd_gendsk.sizes == NULL)
+ {
+ err_printk("Ouch! viodasd_gendsk.sizes is NULL\n");
+ viodasd_end_request(CURRENT, 0);
+ continue;
+ }
+
+ /* If the queue is plugged, don't dequeue anything right now */
+ if ((q) && (q->plugged))
+ {
+ return;
+ }
+
+ /* If we already have the maximum number of requests outstanding to OS/400
+ just bail out. We'll come back later */
+ if (numReqOut >= VIOMAXREQ)
+ return;
+
+ /* get the current request, then dequeue it from the queue */
+ req = CURRENT;
+ blkdev_dequeue_request(req);
+
+ /* Try sending the request */
+ if (send_request(req) == 0)
+ {
+ list_add_tail(&req->queue, &reqlist);
+ }
+ else
+ {
+ viodasd_end_request(req, 0);
+ }
+ }
+}
+
+/***************************************************************************
+ * Check for changed disks
+ ***************************************************************************/
+static int viodasd_check_change(kdev_t dev)
+{
+ struct viodasd_waitevent we;
+ HvLpEvent_Rc hvrc;
+ int device_no = DEVICE_NR(dev);
+
+ /* This semaphore is raised in the interrupt handler */
+ DECLARE_MUTEX_LOCKED(Semaphore);
+
+ /* Check that we are dealing with a valid hosting partition */
+ if (viopath_hostLp == HvLpIndexInvalid)
+ {
+ err_printk("Invalid hosting partition\n");
+ return -EIO;
+ }
+
+
+ we.sem = &Semaphore;
+
+ /* Send the open event to OS/400 */
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_blockio | vioblockcheck,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(unsigned long)&we,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ 0, 0, 0);
+
+ if (hvrc != 0)
+ {
+ err_printk("bad rc on signalLpEvent %d\n",(int)hvrc);
+ return -EIO;
+ }
+
+ /* Wait for the interrupt handler to get the response */
+ down(&Semaphore);
+
+ /* Check the return code. If bad, assume no change */
+ if (we.rc != 0)
+ {
+ err_printk("bad rc on check_change. Assuming no change\n");
+ return 0;
+ }
+
+ return we.changed;
+}
+
+/***************************************************************************
+ * Our file operations table
+ ***************************************************************************/
+static struct block_device_operations viodasd_fops = {
+ open: viodasd_open,
+ release: viodasd_release,
+ ioctl: viodasd_ioctl,
+ check_media_change: viodasd_check_change,
+ revalidate: viodasd_revalidate
+};
+
+/***************************************************************************
+ * Our gendisk table
+ ***************************************************************************/
+struct gendisk viodasd_gendsk = {
+ 0, /* major - fill in later */
+ "viodasd",
+ PARTITION_SHIFT,
+ 1<xFlags.xFunction == HvLpEvent_Function_Int)
+ {
+ err_printk("Yikes! got an int in viodasd event handler!\n");
+ if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
+ {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ }
+
+ switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK)
+ {
+
+ /* Handle a response to an open request. We get all the disk information
+ * in the response, so update it. The correlation token contains a pointer to
+ * a waitevent structure that has a semaphore in it. update the return code
+ * in the waitevent structure and post the semaphore to wake up the guy who
+ * sent the request */
+ case vioblockopen:
+ pwe = (struct viodasd_waitevent *)(unsigned long)event->xCorrelationToken;
+ pwe->rc = event->xRc;
+ if (event->xRc == HvLpEvent_Rc_Good)
+ {
+ viodasd_devices[bevent->mDisk].size = bevent->u.openData.mDiskLen;
+ viodasd_devices[bevent->mDisk].cylinders = bevent->u.openData.mCylinders;
+ viodasd_devices[bevent->mDisk].tracks = bevent->u.openData.mTracks;
+ viodasd_devices[bevent->mDisk].sectors = bevent->u.openData.mSectors;
+ viodasd_devices[bevent->mDisk].bytesPerSector = bevent->u.openData.mBytesPerSector;
+ viodasd_devices[bevent->mDisk].readOnly = bevent->mFlags & vioblockflags_ro;
+
+ if (viodasd_max_disk != bevent->u.openData.mMaxDisks)
+ {
+ viodasd_max_disk = bevent->u.openData.mMaxDisks;
+ }
+ }
+ up(pwe->sem);
+ break;
+
+ case vioblockclose:
+ break;
+
+ /* For read and write requests, decrement the number of outstanding requests,
+ * Free the DMA buffers we allocated, and find the matching request by
+ * using the buffer pointer we stored in the correlation token.
+ */
+ case vioblockread:
+ case vioblockwrite:
+
+ /* Free the DMA buffers */
+ i = 0;
+ nsect = 0;
+ memset(sg, 0x00, sizeof(sg));
+
+ maxsg = (((bevent->event.xSizeMinus1 + 1) -
+ offsetof(struct vioblocklpevent,
+ u.rwData.dmaInfo)) /
+ sizeof(bevent->u.rwData.dmaInfo[0]));
+
+
+ while ((iu.rwData.dmaInfo[i].mLen > 0) &&
+ (i < VIOMAXBLOCKDMA))
+ {
+ sg[i].dma_address = bevent->u.rwData.dmaInfo[i].mToken;
+ sg[i].dma_length = bevent->u.rwData.dmaInfo[i].mLen;
+ nsect += bevent->u.rwData.dmaInfo[i].mLen;
+ i++;
+ }
+
+ pci_unmap_sg(NULL,
+ sg,
+ i,
+ (bevent->event.xSubtype == (viomajorsubtype_blockio | vioblockread)) ?
+ PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+
+
+ /* Since this is running in interrupt mode, we need to make sure we're not
+ * stepping on any global I/O operations
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ /* Decrement the number of outstanding requests */
+ numReqOut--;
+
+ /* Now find the matching request in OUR list (remember we moved the request
+ * from the global list to our list when we got it)
+ */
+ req = blkdev_entry_to_request(reqlist.next);
+ while ((&req->queue != &reqlist) &&
+ ((u64)(unsigned long)req->buffer != bevent->event.xCorrelationToken))
+ req = blkdev_entry_to_request(req->queue.next);
+
+ if (&req->queue == &reqlist)
+ {
+ err_printk("Yikes! Could not find matching buffer %p in reqlist\n",
+ req->buffer);
+ break;
+ }
+
+ /* Remove the request from our list */
+ list_del(&req->queue);
+
+ /* Calculate the number of sectors from the length in bytes */
+ nsect = nsect >> 9;
+ if (!req->bh) {
+ if (event->xRc != HvLpEvent_Rc_Good)
+ {
+ err_printk("rw error %d:%d\n",event->xRc,bevent->mSubTypeRc);
+ viodasd_end_request(req,0);
+ }
+ else
+ {
+ if (nsect != req->current_nr_sectors)
+ {
+ err_printk("Yikes...non bh i/o # sect doesn't match!!!\n");
+ }
+ viodasd_end_request(req, 1);
+ }
+ }
+ else {
+ while ((nsect > 0) && (req->bh))
+ {
+ nsect -= req->current_nr_sectors;
+ viodasd_end_request(req, 1);
+ }
+ if (nsect)
+ {
+ err_printk("Yikes...sectors left over on a request!!!\n");
+ }
+
+ /* If the original request could not handle all the buffers, re-send
+ * the request
+ */
+ if (req->bh)
+ {
+ if (send_request(req) == 0)
+ {
+ list_add_tail(&req->queue, &reqlist);
+ }
+ else
+ {
+ viodasd_end_request(req, 0);
+ }
+ }
+
+ }
+
+ /* Finally, send more requests */
+ do_viodasd_request(NULL);
+
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ break;
+
+ case vioblockflush:
+ up((void*)(unsigned long)event->xCorrelationToken);
+ break;
+
+ case vioblockcheck:
+ pwe = (struct viodasd_waitevent *)(unsigned long)event->xCorrelationToken;
+ pwe->rc = event->xRc;
+ pwe->changed = bevent->u.check.changed;
+ up(pwe->sem);
+ break;
+
+ default:
+ err_printk("invalid subtype!");
+ if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
+ {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ }
+}
+
+/***************************************************************************
+ * This routine tries to clean up anything we allocated/registered
+ ***************************************************************************/
+static void cleanup2(void)
+{
+ int i;
+
+#define CLEANIT(x) if (x) {kfree(x); x=NULL;}
+
+ for (i=0; i
+ * (C) Copyright 2000 IBM Corporation
+ *
+ * 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) anyu later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ***************************************************************************
+ * This routine provides access to CD ROM drives owned and managed by an
+ * OS/400 partition running on the same box as this Linux partition.
+ *
+ * All operations are performed by sending messages back and forth to
+ * the OS/400 partition. The format of the messages is defined in
+ * include/asm-ppc/iSeries/vio.h
+ *
+ * This device driver can either use it's own major number, or it can
+ * pretend to be an AZTECH drive. This is controlled with a
+ * CONFIG option. You can either call this an elegant solution to the
+ * fact that a lot of software doesn't recognize a new CD major number...
+ * or you can call this a really ugly hack. Your choice.
+ *
+ */
+
+/*
+Changelog (absent entries indicate repeats):
+ Ver Date Who What
+ ==== =========== =================== ==============================
+ 2001 Jul 12 devilbis@us.ibm.com moved unitinfo to kernel mem for pci
+ 1.03 2001 Jul 13 added viopath_close on exit
+ successfully used as a module
+ added MOD_(INC|DEC)_USE_COUNT
+ set version to 1.03
+ 2001 Jul 23 restructured do_viocd_request
+ asynchronous request support:
+ request queue
+ by-request end_request
+ 1.04 2001 Aug 01 multiple concurrent CD requests
+ upped version to 1.04
+*/
+
+#include
+#include
+
+/***************************************************************************
+ * Decide if we are using our own major or pretending to be an AZTECH drive
+ ***************************************************************************/
+#ifdef CONFIG_VIOCD_AZTECH
+#define MAJOR_NR AZTECH_CDROM_MAJOR
+#define do_viocd_request do_aztcd_request
+#else
+#define MAJOR_NR VIOCD_MAJOR
+#endif
+
+#define VIOCD_VERS "1.04"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef _HVTYPES_H
+#include
+#endif
+#ifndef _HVLPEVENT_H
+#include
+#endif
+#ifndef _VIO_H
+#include "asm/iSeries/vio.h"
+#endif
+#ifndef _ISERIES_PROC_H
+#include
+#endif
+
+/***************************************************************************
+ * Our internal printk macro
+ ***************************************************************************/
+#define err_printk(fmt, args...) \
+printk(KERN_ERR "(%s:%3.3d) ERR: " fmt, __FILE__, __LINE__ , ## args)
+
+/***************************************************************************
+ * Should probably make this a module parameter....sigh
+ ***************************************************************************/
+#define VIOCD_MAX_CD 8
+int viocd_blocksizes[VIOCD_MAX_CD];
+
+/***************************************************************************
+ * This is the structure we use to exchange info between driver and interrupt
+ * handler
+ ***************************************************************************/
+struct viocd_waitevent {
+ struct semaphore *sem;
+ int rc;
+ int changed;
+};
+
+/***************************************************************************
+ * These are our internal structures for keeping track of devices
+ ***************************************************************************/
+static int viocd_numdev;
+
+struct cdrom_info {
+ char rsrcname[10];
+ char type[4];
+ char model[3];
+};
+static struct cdrom_info *viocd_unitinfo = NULL;
+
+static struct {
+ u32 useCount;
+ u32 blocksize;
+ u32 mediasize;
+} viocd_diskinfo[VIOCD_MAX_CD];
+
+static struct cdrom_device_info viocd_info[VIOCD_MAX_CD];
+
+static spinlock_t viocd_lock = SPIN_LOCK_UNLOCKED;
+
+#define MAX_CD_REQ 1
+static LIST_HEAD(reqlist);
+
+/***************************************************************************
+ ***************************************************************************
+ * CODE STARTS HERE
+ ***************************************************************************
+ ***************************************************************************/
+
+/***************************************************************************
+ * End a request
+ ***************************************************************************/
+static int viocd_end_request(struct request *req, int uptodate) {
+ if (end_that_request_first(req, uptodate, DEVICE_NAME))
+ {
+ /* printk("we weren't really done with %p\n", req); */
+ return 0;
+ }
+ end_that_request_last(req);
+ return 1;
+}
+
+
+/***************************************************************************
+ * Get info on CD devices from OS/400
+ ***************************************************************************/
+static void get_viocd_info(void)
+{
+ dma_addr_t dmaaddr;
+ HvLpEvent_Rc hvrc;
+ int i;
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ struct viocd_waitevent we;
+
+ // If we don't have a host, bail out
+ if (viopath_hostLp == HvLpIndexInvalid)
+ return;
+
+ if (viocd_unitinfo == NULL)
+ viocd_unitinfo = kmalloc(sizeof(struct cdrom_info) * VIOCD_MAX_CD, GFP_KERNEL);
+
+ memset(viocd_unitinfo, 0x00, sizeof(struct cdrom_info) * VIOCD_MAX_CD);
+
+ dmaaddr = pci_map_single(NULL, viocd_unitinfo,
+ sizeof(struct cdrom_info) * VIOCD_MAX_CD,
+ PCI_DMA_FROMDEVICE);
+ if (dmaaddr == 0xFFFFFFFF)
+ {
+ err_printk("error allocating tce\n");
+ return;
+ }
+
+ we.sem = &Semaphore;
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_cdio | viocdgetinfo,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)&we,
+ VIOVERSION << 16,
+ dmaaddr,
+ 0,
+ sizeof(struct cdrom_info) * VIOCD_MAX_CD,
+ 0);
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ err_printk("hv error on op %d\n", (int)hvrc);
+ return;
+ }
+
+ down(&Semaphore);
+
+ if (we.rc)
+ {
+ err_printk("bad rc %d on getinfo\n", we.rc);
+ return;
+ }
+
+
+ for (i=0;
+ ((i < VIOCD_MAX_CD) && (viocd_unitinfo[i].rsrcname[0]));
+ i++)
+ {
+ viocd_numdev++;
+ }
+}
+
+/***************************************************************************
+ * Open a device
+ ***************************************************************************/
+static int viocd_open(struct cdrom_device_info * cdi, int purpose)
+{
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ int device_no = MINOR(cdi->dev);
+ HvLpEvent_Rc hvrc;
+ struct viocd_waitevent we;
+
+ // If we don't have a host, bail out
+ if (viopath_hostLp == HvLpIndexInvalid)
+ return -ENODEV;
+
+ if (device_no >= viocd_numdev)
+ return -ENODEV;
+
+ we.sem = &Semaphore;
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_cdio | viocdopen,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)&we,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ 0, 0, 0);
+ if (hvrc != 0)
+ {
+ err_printk("bad rc on signalLpEvent %d\n", (int)hvrc);
+ return -EIO;
+ }
+
+ down(&Semaphore);
+
+ if (we.rc)
+ return -EIO;
+
+ if (viocd_diskinfo[device_no].useCount == 0)
+ {
+ if (viocd_diskinfo[device_no].blocksize > 0)
+ {
+ viocd_blocksizes[device_no] = viocd_diskinfo[device_no].blocksize;
+ }
+ }
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+/***************************************************************************
+ * Release a device
+ ***************************************************************************/
+static void viocd_release(struct cdrom_device_info * cdi)
+{
+ int device_no = MINOR(cdi->dev);
+ HvLpEvent_Rc hvrc;
+
+ // If we don't have a host, bail out
+ if (viopath_hostLp == HvLpIndexInvalid || device_no >= viocd_numdev)
+ return;
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_cdio | viocdclose,
+ HvLpEvent_AckInd_NoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ 0,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ 0, 0, 0);
+ if (hvrc != 0)
+ {
+ err_printk("bad rc on signalLpEvent %d\n", (int)hvrc);
+ return;
+ }
+
+ MOD_DEC_USE_COUNT;
+}
+
+/***************************************************************************
+ * Send a read or write request to OS/400
+ ***************************************************************************/
+static int send_request(struct request *req)
+{
+ HvLpEvent_Rc hvrc;
+ dma_addr_t dmaaddr;
+ int device_no = DEVICE_NR(req->rq_dev);
+ long start = req->sector * 512,
+ len = req->current_nr_sectors * 512;
+ char reading = req->cmd == READ;
+
+ dmaaddr = pci_map_single(NULL, req->buffer, len,
+ reading ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+ if (dmaaddr == 0xFFFFFFFF)
+ {
+ err_printk("error allocating tce for address %p len %ld\n",
+ req->buffer, len);
+ return -1;
+ }
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_cdio |
+ /* FIXME: add viocdwrite */ (reading ? viocdread : viocdread),
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)req->buffer,
+ VIOVERSION << 16,
+ ((u64)device_no << 48) |
+ dmaaddr,
+ start,
+ len,
+ 0);
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ err_printk("hv error on op %d\n", (int)hvrc);
+ return -1;
+ }
+ return 0;
+}
+
+
+/***************************************************************************
+ * Do a request
+ ***************************************************************************/
+static int rwreq;
+static void do_viocd_request(request_queue_t *q)
+{
+ for (;;) {
+ struct request *req;
+ char err_str[80] = "";
+ int device_no;
+
+ INIT_REQUEST;
+ if (rwreq >= MAX_CD_REQ) {
+ /* printk("viocd: already %d requests--no more\n", rwreq); */
+ return;
+ }
+
+ device_no = CURRENT_DEV;
+
+ /* remove the current request from the queue */
+ req = CURRENT;
+ blkdev_dequeue_request(req);
+
+ /* check for any kind of error */
+ if (req->cmd != READ)
+ strcpy(err_str, "Invalid write request for CD");
+ else if (device_no > viocd_numdev)
+ sprintf(err_str, "Invalid device number %d", device_no);
+/*
+ else if (rwreq > 0)
+ strcpy(err_str, "multiple r/w req!");
+*/
+ else if(send_request(req) < 0)
+ strcpy(err_str, "unable to send message to OS/400!");
+
+ /* if we had any sort of error, log it and cancel the request */
+ if (*err_str)
+ {
+ err_printk("%s\n", err_str);
+ viocd_end_request(req, 0);
+ }
+ else
+ {
+ spin_lock(&viocd_lock);
+ list_add_tail(&req->queue, &reqlist);
+ ++rwreq;
+ /* printk("enqueued req %p for total of %d\n", req->buffer, rwreq); */
+ spin_unlock(&viocd_lock);
+ }
+ }
+}
+
+/***************************************************************************
+ * Check if the CD changed
+ ***************************************************************************/
+static int viocd_media_changed(struct cdrom_device_info * cdi, int disc_nr)
+{
+ struct viocd_waitevent we;
+ HvLpEvent_Rc hvrc;
+ int device_no = MINOR(cdi->dev);
+
+ /* This semaphore is raised in the interrupt handler */
+ DECLARE_MUTEX_LOCKED(Semaphore);
+
+ /* Check that we are dealing with a valid hosting partition */
+ if (viopath_hostLp == HvLpIndexInvalid)
+ {
+ err_printk("Invalid hosting partition\n");
+ return -EIO;
+ }
+
+ we.sem = &Semaphore;
+
+ /* Send the open event to OS/400 */
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_cdio | viocdcheck,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)&we,
+ VIOVERSION << 16,
+ ((u64)device_no << 48),
+ 0, 0, 0);
+
+ if (hvrc != 0)
+ {
+ err_printk("bad rc on signalLpEvent %d\n", (int)hvrc);
+ return -EIO;
+ }
+
+ /* Wait for the interrupt handler to get the response */
+ down(&Semaphore);
+
+ /* Check the return code. If bad, assume no change */
+ if (we.rc != 0)
+ {
+ err_printk("bad rc on check_change. Assuming no change\n");
+ return 0;
+ }
+
+ return we.changed;
+}
+
+/***************************************************************************
+ * This routine handles incoming CD LP events
+ ***************************************************************************/
+static void vioHandleCDEvent(struct HvLpEvent *event)
+{
+ struct viocdlpevent *bevent = (struct viocdlpevent *)event;
+ struct viocd_waitevent *pwe;
+
+ if (event == NULL)
+ {
+ /* Notification that a partition went away! */
+ return;
+ }
+
+ // First, we should NEVER get an int here...only acks
+ if (event->xFlags.xFunction == HvLpEvent_Function_Int)
+ {
+ err_printk("Yikes! got an int in viocd event handler!\n");
+ if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
+ {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ }
+
+ switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK)
+ {
+ case viocdgetinfo:
+ case viocdopen:
+ pwe = (struct viocd_waitevent *)(u32)event->xCorrelationToken;
+ pwe->rc = event->xRc;
+ viocd_diskinfo[bevent->mDisk].blocksize = bevent->mBlockSize;
+ viocd_diskinfo[bevent->mDisk].mediasize = bevent->mMediaSize;
+
+ up(pwe->sem);
+ break;
+
+ case viocdclose:
+ break;
+
+ case viocdread: {
+ int flags;
+ struct request *req = blkdev_entry_to_request(reqlist.next);
+
+ /* Since this is running in interrupt mode, we need to make sure we're not
+ * stepping on any global I/O operations
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
+
+
+ pci_unmap_single(NULL,
+ bevent->mToken,
+ bevent->mLen,
+ PCI_DMA_FROMDEVICE);
+
+ /* find the event to which this is a response */
+ while ((&req->queue != &reqlist) &&
+ ((u64)(u32)req->buffer != bevent->event.xCorrelationToken))
+ req = blkdev_entry_to_request(req->queue.next);
+
+ /* if the event was not there, then what are we responding to?? */
+ if(&req->queue == &reqlist)
+ {
+ err_printk("Yikes! we didn't ever enqueue this guy!\n");
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ break;
+ }
+
+ /* we don't need to keep it around anymore... */
+ spin_lock(&viocd_lock);
+ list_del(&req->queue);
+ --rwreq;
+ /* printk("down requests to %d (dequeued req %p)\n", rwreq, req->buffer); */
+ spin_unlock(&viocd_lock);
+
+ {
+ char stat = event->xRc == HvLpEvent_Rc_Good;
+ int nsect = bevent->mLen >> 9;
+
+ if(!stat)
+ err_printk("request %p failed with rc %d:0x%08x\n", req->buffer, event->xRc, bevent->mSubTypeRc);
+ while((nsect > 0) && (req->bh))
+ {
+ nsect -= req->current_nr_sectors;
+ viocd_end_request(req, stat);
+ }
+ /* we weren't done yet */
+ if(req->bh)
+ {
+ if(send_request(req) < 0)
+ {
+ err_printk("couldn't re-submit req %p\n", req->buffer);
+ viocd_end_request(req, 0);
+ }
+ else
+ {
+ spin_lock(&viocd_lock);
+ list_add_tail(&req->queue, &reqlist);
+ ++rwreq;
+ /* printk("re-enqueued req %p for %d total\n", req->buffer, rwreq); */
+ spin_unlock(&viocd_lock);
+ }
+ }
+ }
+
+ /* FIXME: why is this here?? */
+ do_viocd_request(NULL);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ break;
+ }
+ case viocdcheck:
+ pwe = (struct viocd_waitevent *)(u32)event->xCorrelationToken;
+ pwe->rc = event->xRc;
+ pwe->changed = bevent->mFlags;
+ up(pwe->sem);
+ break;
+
+ default:
+ err_printk("invalid subtype!");
+ if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
+ {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ }
+}
+
+/***************************************************************************
+ * Our file operations table
+ ***************************************************************************/
+static struct cdrom_device_ops viocd_dops = {
+ open: viocd_open,
+ release: viocd_release,
+ media_changed: viocd_media_changed,
+ capability: CDC_CD_R
+};
+
+/***************************************************************************
+ * Handle reads from the proc file system
+ ***************************************************************************/
+static int proc_read(char *buf, char **start, off_t offset,
+ int blen, int *eof, void *data)
+{
+ int len = 0;
+ int i;
+
+ for (i=0; inlink = 1;
+ ent->data = NULL;
+ ent->read_proc = proc_read;
+}
+
+/***************************************************************************
+ * clean up our proc file system entries
+ ***************************************************************************/
+void viocd_proc_delete(struct proc_dir_entry *iSeries_proc)
+{
+ remove_proc_entry("viocd", iSeries_proc);
+}
+
+/***************************************************************************
+ * Initialize the whole device driver. Handle module and non-module
+ * versions
+ ***************************************************************************/
+__init int viocd_init(void)
+{
+ int i;
+ int rc;
+
+ // If we don't have a host, bail out
+ if (viopath_hostLp == HvLpIndexInvalid)
+ return -ENODEV;
+
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_cdio);
+ if (rc)
+ {
+ err_printk("error opening path to host partition %d\n", viopath_hostLp);
+ return rc;
+ }
+
+ /*
+ * Initialize our request handler
+ */
+ rwreq = 0;
+ vio_setCDHandler(vioHandleCDEvent);
+
+/* memset(viocd_unitinfo, 0x00, sizeof(struct cdrom_info) * VIOCD_MAX_CD); */
+ memset(viocd_diskinfo, 0x00, sizeof(viocd_diskinfo));
+
+ get_viocd_info();
+
+ if (viocd_numdev == 0)
+ {
+ viopath_close(viopath_hostLp, viomajorsubtype_cdio);
+ return 0;
+ }
+
+ printk("%s: iSeries Virtual CD vers %s, major %d, max disks %d, hosting partition %d\n",
+ DEVICE_NAME, VIOCD_VERS, MAJOR_NR, VIOCD_MAX_CD, viopath_hostLp);
+
+ if (devfs_register_blkdev(MAJOR_NR, "viocd", &cdrom_fops) != 0)
+ {
+ printk("Unable to get major %d for viocd CD-ROM\n",
+ MAJOR_NR);
+ return -EIO;
+ }
+
+ blksize_size[MAJOR_NR] = viocd_blocksizes;
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+ read_ahead[MAJOR_NR] = 4;
+
+ memset(&viocd_info, 0x00, sizeof(viocd_info));
+ for (i=0; iprocess_char_map) || tty->lnext) {
+ if (!test_bit(c, tty->process_char_map) || tty->lnext) {
finish_erasing(tty);
tty->lnext = 0;
if (L_ECHO(tty)) {
@@ -659,7 +659,7 @@
handle_newline:
spin_lock_irqsave(&tty->read_lock, flags);
- set_bit(tty->read_head, &tty->read_flags);
+ set_bit(tty->read_head, tty->read_flags);
put_tty_queue_nolock(c, tty);
tty->canon_head = tty->read_head;
tty->canon_data++;
@@ -811,38 +811,38 @@
memset(tty->process_char_map, 0, 256/8);
if (I_IGNCR(tty) || I_ICRNL(tty))
- set_bit('\r', &tty->process_char_map);
+ set_bit('\r', tty->process_char_map);
if (I_INLCR(tty))
- set_bit('\n', &tty->process_char_map);
+ set_bit('\n', tty->process_char_map);
if (L_ICANON(tty)) {
- set_bit(ERASE_CHAR(tty), &tty->process_char_map);
- set_bit(KILL_CHAR(tty), &tty->process_char_map);
- set_bit(EOF_CHAR(tty), &tty->process_char_map);
- set_bit('\n', &tty->process_char_map);
- set_bit(EOL_CHAR(tty), &tty->process_char_map);
+ set_bit(ERASE_CHAR(tty), tty->process_char_map);
+ set_bit(KILL_CHAR(tty), tty->process_char_map);
+ set_bit(EOF_CHAR(tty), tty->process_char_map);
+ set_bit('\n', tty->process_char_map);
+ set_bit(EOL_CHAR(tty), tty->process_char_map);
if (L_IEXTEN(tty)) {
set_bit(WERASE_CHAR(tty),
- &tty->process_char_map);
+ tty->process_char_map);
set_bit(LNEXT_CHAR(tty),
- &tty->process_char_map);
+ tty->process_char_map);
set_bit(EOL2_CHAR(tty),
- &tty->process_char_map);
+ tty->process_char_map);
if (L_ECHO(tty))
set_bit(REPRINT_CHAR(tty),
- &tty->process_char_map);
+ tty->process_char_map);
}
}
if (I_IXON(tty)) {
- set_bit(START_CHAR(tty), &tty->process_char_map);
- set_bit(STOP_CHAR(tty), &tty->process_char_map);
+ set_bit(START_CHAR(tty), tty->process_char_map);
+ set_bit(STOP_CHAR(tty), tty->process_char_map);
}
if (L_ISIG(tty)) {
- set_bit(INTR_CHAR(tty), &tty->process_char_map);
- set_bit(QUIT_CHAR(tty), &tty->process_char_map);
- set_bit(SUSP_CHAR(tty), &tty->process_char_map);
+ set_bit(INTR_CHAR(tty), tty->process_char_map);
+ set_bit(QUIT_CHAR(tty), tty->process_char_map);
+ set_bit(SUSP_CHAR(tty), tty->process_char_map);
}
- clear_bit(__DISABLED_CHAR, &tty->process_char_map);
+ clear_bit(__DISABLED_CHAR, tty->process_char_map);
sti();
tty->raw = 0;
tty->real_raw = 0;
@@ -1058,7 +1058,7 @@
int eol;
eol = test_and_clear_bit(tty->read_tail,
- &tty->read_flags);
+ tty->read_flags);
c = tty->read_buf[tty->read_tail];
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = ((tty->read_tail+1) &
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/char/tty_io.c linuxppc64_2_4/drivers/char/tty_io.c
--- linux-2.4.8-ac9/drivers/char/tty_io.c Thu Aug 23 09:17:21 2001
+++ linuxppc64_2_4/drivers/char/tty_io.c Fri Aug 10 13:08:57 2001
@@ -2237,6 +2237,11 @@
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
+
+#ifdef CONFIG_VIOCONS
+ viocons_init();
+#endif
+
#ifdef CONFIG_VT
con_init();
#endif
@@ -2334,6 +2339,10 @@
/* console calls tty_register_driver() before kmalloc() works.
* Thus, we can't devfs_register() then. Do so now, instead.
*/
+#ifdef CONFIG_VIOCONS
+ viocons_init2();
+#endif
+
#ifdef CONFIG_VT
con_init_devfs();
#endif
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/char/viocons.c linuxppc64_2_4/drivers/char/viocons.c
--- linux-2.4.8-ac9/drivers/char/viocons.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/char/viocons.c Thu Jul 19 14:02:56 2001
@@ -0,0 +1,1407 @@
+/*
+ * drivers/char/viocons.c
+ *
+ * iSeries Virtual Terminal
+ *
+ * Author: Dave Boutcher
+ * (C) Copyright 2000 IBM Corporation
+ *
+ * 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) anyu later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef _VIO_H
+#include "asm/iSeries/vio.h"
+#endif
+
+#ifndef _HVLPEVENT_H
+#include
+#endif
+
+#ifndef _HVCALLEVENT_H
+#include "asm/iSeries/HvCallEvent.h"
+#endif
+#ifndef _HVLPCONFIG_H
+#include "asm/iSeries/HvLpConfig.h"
+#endif
+#include "asm/iSeries/HvCall.h"
+#ifndef _ISERIES_PROC_H
+#include
+#endif
+
+/***************************************************************************
+ * Check that the tty_driver_data actually points to our stuff
+ ***************************************************************************/
+#define VIOTTY_PARANOIA_CHECK 1
+#define VIOTTY_MAGIC (0x0DCB)
+
+static int debug;
+
+static DECLARE_WAIT_QUEUE_HEAD(viocons_wait_queue);
+
+static int viotty_major = 229;
+
+#define VTTY_PORTS 10
+#define VIOTTY_SERIAL_START 65
+
+static u64 sndMsgSeq[VTTY_PORTS];
+static u64 sndMsgAck[VTTY_PORTS];
+
+static spinlock_t consolelock;
+
+/***************************************************************************
+ * When we get writes faster than we can send it to the partition,
+ * buffer the data here. There is one set of buffers for each virtual
+ * port.
+ ***************************************************************************/
+/* Note that bufferUsed is a bit map of used buffers.
+ * It had better have enough bits to hold NUM_BUF
+ * the bitops assume it is a multiple of unsigned long
+ */
+#define NUM_BUF (8)
+#define OVERFLOW_SIZE VIOCHAR_MAX_DATA
+
+static struct overflowBuffers {
+ unsigned long bufferUsed;
+ u8 *buffer[NUM_BUF];
+ int bufferBytes[NUM_BUF];
+ int curbuf;
+ int bufferOverflow;
+ int overflowMessage;
+} overflow[VTTY_PORTS];
+
+static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp);
+
+static struct tty_driver viotty_driver;
+static struct tty_driver viottyS_driver;
+static int viotty_refcount;
+
+static struct tty_struct *viotty_table[VTTY_PORTS];
+static struct tty_struct *viottyS_table[VTTY_PORTS];
+static struct termios *viotty_termios[VTTY_PORTS];
+static struct termios *viottyS_termios[VTTY_PORTS];
+static struct termios *viotty_termios_locked[VTTY_PORTS];
+static struct termios *viottyS_termios_locked[VTTY_PORTS];
+
+void hvlog(char *fmt, ...)
+{
+ int i;
+ static char buf[256];
+ va_list args;
+ va_start(args, fmt);
+ i = vsprintf(buf, fmt, args);
+ va_end(args);
+ HvCall_writeLogBuffer(buf, i);
+ HvCall_writeLogBuffer("\r",1);
+
+}
+
+/***************************************************************************
+ * Our port information. We store a pointer to one entry in the
+ * tty_driver_data
+ ***************************************************************************/
+static struct port_info_tag {
+ int magic;
+ struct tty_struct *tty;
+ HvLpIndex lp;
+ u8 vcons;
+ u8 port;
+} port_info[VTTY_PORTS];
+
+/***************************************************************************
+ * Make sure we're pointing to a valid port_info structure. Shamelessly
+ * plagerized from serial.c
+ ***************************************************************************/
+static inline int viotty_paranoia_check(struct port_info_tag *pi,
+ kdev_t device, const char *routine)
+{
+#ifdef VIOTTY_PARANOIA_CHECK
+ static const char *badmagic =
+ "Warning: bad magic number for port_info struct (%s) in %s\n";
+ static const char *badinfo =
+ "Warning: null port_info for (%s) in %s\n";
+
+ if (!pi) {
+ printk(badinfo, kdevname(device), routine);
+ return 1;
+ }
+ if (pi->magic != VIOTTY_MAGIC) {
+ printk(badmagic, kdevname(device), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/***************************************************************************
+ * Handle reads from the proc file system. Right now we just dump the
+ * state of the first TTY
+ ***************************************************************************/
+static int proc_read(char *buf, char **start, off_t offset,
+ int blen, int *eof, void *data)
+{
+ int len = 0;
+ struct tty_struct *tty = viotty_table[0];
+ struct termios *termios;
+ if (tty == NULL)
+ {
+ len += sprintf(buf+len,"no tty\n");
+ *eof = 1;
+ return len;
+ }
+
+ len += sprintf(buf+len,"tty info: COOK_OUT %ld COOK_IN %ld, NO_WRITE_SPLIT %ld\n",
+ tty->flags & TTY_HW_COOK_OUT,
+ tty->flags & TTY_HW_COOK_IN,
+ tty->flags & TTY_NO_WRITE_SPLIT);
+
+ termios = tty->termios;
+ if (termios == NULL)
+ {
+ len += sprintf(buf+len,"no termios\n");
+ *eof = 1;
+ return len;
+ }
+len+= sprintf(buf+len,"INTR_CHAR %2.2x\n",INTR_CHAR(tty));
+len+= sprintf(buf+len,"QUIT_CHAR %2.2x\n",QUIT_CHAR(tty));
+len+= sprintf(buf+len,"ERASE_CHAR %2.2x\n",ERASE_CHAR(tty));
+len+= sprintf(buf+len,"KILL_CHAR %2.2x\n",KILL_CHAR(tty));
+len+= sprintf(buf+len,"EOF_CHAR %2.2x\n",EOF_CHAR(tty));
+len+= sprintf(buf+len,"TIME_CHAR %2.2x\n",TIME_CHAR(tty));
+len+= sprintf(buf+len,"MIN_CHAR %2.2x\n",MIN_CHAR(tty));
+len+= sprintf(buf+len,"SWTC_CHAR %2.2x\n",SWTC_CHAR(tty));
+len+= sprintf(buf+len,"START_CHAR %2.2x\n",START_CHAR(tty));
+len+= sprintf(buf+len,"STOP_CHAR %2.2x\n",STOP_CHAR(tty));
+len+= sprintf(buf+len,"SUSP_CHAR %2.2x\n",SUSP_CHAR(tty));
+len+= sprintf(buf+len,"EOL_CHAR %2.2x\n",EOL_CHAR(tty));
+len+= sprintf(buf+len,"REPRINT_CHAR %2.2x\n",REPRINT_CHAR(tty));
+len+= sprintf(buf+len,"DISCARD_CHAR %2.2x\n",DISCARD_CHAR(tty));
+len+= sprintf(buf+len,"WERASE_CHAR %2.2x\n",WERASE_CHAR(tty));
+len+= sprintf(buf+len,"LNEXT_CHAR %2.2x\n",LNEXT_CHAR(tty));
+len+= sprintf(buf+len,"EOL2_CHAR %2.2x\n",EOL2_CHAR(tty));
+
+len+= sprintf(buf+len,"I_IGNBRK %4.4x\n",I_IGNBRK(tty));
+len+= sprintf(buf+len,"I_BRKINT %4.4x\n",I_BRKINT(tty));
+len+= sprintf(buf+len,"I_IGNPAR %4.4x\n",I_IGNPAR(tty));
+len+= sprintf(buf+len,"I_PARMRK %4.4x\n",I_PARMRK(tty));
+len+= sprintf(buf+len,"I_INPCK %4.4x\n",I_INPCK(tty));
+len+= sprintf(buf+len,"I_ISTRIP %4.4x\n",I_ISTRIP(tty));
+len+= sprintf(buf+len,"I_INLCR %4.4x\n",I_INLCR(tty));
+len+= sprintf(buf+len,"I_IGNCR %4.4x\n",I_IGNCR(tty));
+len+= sprintf(buf+len,"I_ICRNL %4.4x\n",I_ICRNL(tty));
+len+= sprintf(buf+len,"I_IUCLC %4.4x\n",I_IUCLC(tty));
+len+= sprintf(buf+len,"I_IXON %4.4x\n",I_IXON(tty));
+len+= sprintf(buf+len,"I_IXANY %4.4x\n",I_IXANY(tty));
+len+= sprintf(buf+len,"I_IXOFF %4.4x\n",I_IXOFF(tty));
+len+= sprintf(buf+len,"I_IMAXBEL %4.4x\n",I_IMAXBEL(tty));
+
+len+= sprintf(buf+len,"O_OPOST %4.4x\n",O_OPOST(tty));
+len+= sprintf(buf+len,"O_OLCUC %4.4x\n",O_OLCUC(tty));
+len+= sprintf(buf+len,"O_ONLCR %4.4x\n",O_ONLCR(tty));
+len+= sprintf(buf+len,"O_OCRNL %4.4x\n",O_OCRNL(tty));
+len+= sprintf(buf+len,"O_ONOCR %4.4x\n",O_ONOCR(tty));
+len+= sprintf(buf+len,"O_ONLRET %4.4x\n",O_ONLRET(tty));
+len+= sprintf(buf+len,"O_OFILL %4.4x\n",O_OFILL(tty));
+len+= sprintf(buf+len,"O_OFDEL %4.4x\n",O_OFDEL(tty));
+len+= sprintf(buf+len,"O_NLDLY %4.4x\n",O_NLDLY(tty));
+len+= sprintf(buf+len,"O_CRDLY %4.4x\n",O_CRDLY(tty));
+len+= sprintf(buf+len,"O_TABDLY %4.4x\n",O_TABDLY(tty));
+len+= sprintf(buf+len,"O_BSDLY %4.4x\n",O_BSDLY(tty));
+len+= sprintf(buf+len,"O_VTDLY %4.4x\n",O_VTDLY(tty));
+len+= sprintf(buf+len,"O_FFDLY %4.4x\n",O_FFDLY(tty));
+
+len+= sprintf(buf+len,"C_BAUD %4.4x\n",C_BAUD(tty));
+len+= sprintf(buf+len,"C_CSIZE %4.4x\n",C_CSIZE(tty));
+len+= sprintf(buf+len,"C_CSTOPB %4.4x\n",C_CSTOPB(tty));
+len+= sprintf(buf+len,"C_CREAD %4.4x\n",C_CREAD(tty));
+len+= sprintf(buf+len,"C_PARENB %4.4x\n",C_PARENB(tty));
+len+= sprintf(buf+len,"C_PARODD %4.4x\n",C_PARODD(tty));
+len+= sprintf(buf+len,"C_HUPCL %4.4x\n",C_HUPCL(tty));
+len+= sprintf(buf+len,"C_CLOCAL %4.4x\n",C_CLOCAL(tty));
+len+= sprintf(buf+len,"C_CRTSCTS %4.4x\n",C_CRTSCTS(tty));
+
+len+= sprintf(buf+len,"L_ISIG %4.4x\n",L_ISIG(tty));
+len+= sprintf(buf+len,"L_ICANON %4.4x\n",L_ICANON(tty));
+len+= sprintf(buf+len,"L_XCASE %4.4x\n",L_XCASE(tty));
+len+= sprintf(buf+len,"L_ECHO %4.4x\n",L_ECHO(tty));
+len+= sprintf(buf+len,"L_ECHOE %4.4x\n",L_ECHOE(tty));
+len+= sprintf(buf+len,"L_ECHOK %4.4x\n",L_ECHOK(tty));
+len+= sprintf(buf+len,"L_ECHONL %4.4x\n",L_ECHONL(tty));
+len+= sprintf(buf+len,"L_NOFLSH %4.4x\n",L_NOFLSH(tty));
+len+= sprintf(buf+len,"L_TOSTOP %4.4x\n",L_TOSTOP(tty));
+len+= sprintf(buf+len,"L_ECHOCTL %4.4x\n",L_ECHOCTL(tty));
+len+= sprintf(buf+len,"L_ECHOPRT %4.4x\n",L_ECHOPRT(tty));
+len+= sprintf(buf+len,"L_ECHOKE %4.4x\n",L_ECHOKE(tty));
+len+= sprintf(buf+len,"L_FLUSHO %4.4x\n",L_FLUSHO(tty));
+len+= sprintf(buf+len,"L_PENDIN %4.4x\n",L_PENDIN(tty));
+len+= sprintf(buf+len,"L_IEXTEN %4.4x\n",L_IEXTEN(tty));
+
+ *eof = 1;
+ return len;
+}
+
+/***************************************************************************
+ * Handle writes to our proc file system. Right now just turns on and off
+ * our debug flag
+ ***************************************************************************/
+static int proc_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ if (count)
+ {
+ if (buffer[0] == '1')
+ {
+ printk("viocons: debugging on\n");
+ debug = 1;
+ }
+ else
+ {
+ printk("viocons: debugging off\n");
+ debug = 0;
+ }
+ }
+ return count;
+}
+
+/***************************************************************************
+ * setup our proc file system entries
+ ***************************************************************************/
+void viocons_proc_init(struct proc_dir_entry *iSeries_proc)
+{
+ struct proc_dir_entry *ent;
+ ent = create_proc_entry("viocons", S_IFREG|S_IRUSR, iSeries_proc);
+ if (!ent) return;
+ ent->nlink = 1;
+ ent->data = NULL;
+ ent->read_proc = proc_read;
+ ent->write_proc = proc_write;
+}
+
+/***************************************************************************
+ * clean up our proc file system entries
+ ***************************************************************************/
+void viocons_proc_delete(struct proc_dir_entry *iSeries_proc)
+{
+ remove_proc_entry("viocons", iSeries_proc);
+}
+
+/***************************************************************************
+ * Add data to our pending-send buffers
+ ***************************************************************************/
+static int bufferAdd(u8 port, const char *buf, size_t len, int userFlag)
+{
+ size_t bleft = len;
+ size_t curlen;
+ char *cbuf = (char *)buf;
+ int nextbuf;
+ struct overflowBuffers *pov = &overflow[port];
+ while (bleft > 0)
+ {
+ /*
+ * If there is no space left in the current buffer, we have
+ * filled everything up, so return. If we filled the previous
+ * buffer we would already have moved to the next one.
+ */
+ if (pov->bufferBytes[pov->curbuf] == OVERFLOW_SIZE)
+ {
+ hvlog("buffer %d full. no more space\n",pov->curbuf);
+ pov->bufferOverflow++;
+ pov->overflowMessage = 1;
+ return len - bleft;
+ }
+
+ /*
+ * Turn on the "used" bit for this buffer. If it's already on, that's
+ * fine.
+ */
+ set_bit(pov->curbuf,&pov->bufferUsed);
+
+ /*
+ * See if this buffer has been allocated. If not, allocate it
+ */
+ if (pov->buffer[pov->curbuf] == NULL)
+ pov->buffer[pov->curbuf] =
+ kmalloc(OVERFLOW_SIZE, GFP_ATOMIC);
+
+ /*
+ * Figure out how much we can copy into this buffer
+ */
+ if (bleft < (OVERFLOW_SIZE - pov->bufferBytes[pov->curbuf]))
+ curlen = bleft;
+ else
+ curlen = OVERFLOW_SIZE - pov->bufferBytes[pov->curbuf];
+
+ /*
+ * Copy the data into the buffer
+ */
+ if (userFlag)
+ copy_from_user(pov->buffer[pov->curbuf]+
+ pov->bufferBytes[pov->curbuf],cbuf,curlen);
+ else
+ memcpy(pov->buffer[pov->curbuf]+
+ pov->bufferBytes[pov->curbuf],cbuf,curlen);
+
+ pov->bufferBytes[pov->curbuf] += curlen;
+ cbuf += curlen;
+ bleft -= curlen;
+
+ /*
+ * Now see if we've filled this buffer
+ */
+ if (pov->bufferBytes[pov->curbuf] == OVERFLOW_SIZE)
+ {
+ nextbuf = (pov->curbuf+1)%NUM_BUF;
+
+ /*
+ * Move to the next buffer if it hasn't been used yet
+ */
+ if (test_bit(nextbuf,&pov->bufferUsed) == 0)
+ {
+ pov->curbuf = nextbuf;
+ }
+ }
+ }
+ return len;
+}
+
+/***************************************************************************
+ * Send pending data
+ ***************************************************************************/
+void sendBuffers(u8 port, HvLpIndex lp)
+{
+ HvLpEvent_Rc hvrc;
+ int nextbuf;
+ struct viocharlpevent *viochar = (struct viocharlpevent *)vio_char_event_buffer;
+ int flags;
+ struct overflowBuffers *pov = &overflow[port];
+
+ spin_lock_irqsave(&consolelock,
+ flags);
+
+ if (pov->bufferUsed == 0)
+ {
+ hvlog("in sendbuffers, but no buffers used\n");
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ return;
+ }
+
+ /*
+ * curbuf points to the buffer we're filling. We want to start sending AFTER
+ * this one.
+ */
+ nextbuf = (pov->curbuf + 1) % NUM_BUF;
+
+ /*
+ * Loop until we find a buffer with the bufferUsed bit on
+ */
+ while (test_bit(nextbuf,&pov->bufferUsed) == 0)
+ nextbuf = (nextbuf + 1) % NUM_BUF;
+
+ initDataEvent(viochar, lp);
+
+ /*
+ * While we have buffers with data, and our send window is open, send them
+ */
+ while ((test_bit(nextbuf, &pov->bufferUsed)) &&
+ ((sndMsgSeq[port] - sndMsgAck[port]) immediateDataLen = pov->bufferBytes[nextbuf];
+ viochar->event.xCorrelationToken = sndMsgSeq[port]++;
+ viochar->event.xSizeMinus1 = offsetof(struct viocharlpevent, immediateData) +
+ viochar->immediateDataLen;
+
+ memcpy(viochar->immediateData,pov->buffer[nextbuf],viochar->immediateDataLen);
+
+ hvrc = HvCallEvent_signalLpEvent(&viochar->event);
+ if (hvrc)
+ {
+ /*
+ * MUST unlock the spinlock before doing a printk
+ */
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ printk("viocons: error sending event! %d\n",(int)hvrc);
+ return;
+ }
+
+ /*
+ * clear the bufferUsed bit, zero the number of bytes in this buffer,
+ * and move to the next buffer
+ */
+ clear_bit(nextbuf, &pov->bufferUsed);
+ pov->bufferBytes[nextbuf] = 0;
+ nextbuf = (nextbuf + 1) % NUM_BUF;
+ }
+
+
+ /*
+ * If we have emptied all the buffers, start at 0 again.
+ * this will re-use any allocated buffers
+ */
+ if (pov->bufferUsed == 0)
+ {
+ pov->curbuf = 0;
+
+ if (pov->overflowMessage)
+ pov->overflowMessage = 0;
+
+ if (port_info[port].tty)
+ {
+ if ((port_info[port].tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ (port_info[port].tty->ldisc.write_wakeup))
+ (port_info[port].tty->ldisc.write_wakeup) (port_info[port].tty);
+ wake_up_interruptible(&port_info[port].tty->write_wait);
+ }
+ }
+
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+}
+
+/***************************************************************************
+ * Our internal writer. Gets called both from the console device and
+ * the tty device. the tty pointer will be NULL if called from the console.
+ ***************************************************************************/
+static int internal_write(struct tty_struct * tty, const char *buf, size_t len, int userFlag)
+{
+ HvLpEvent_Rc hvrc;
+ size_t bleft = len;
+ size_t curlen;
+ const char *curbuf = buf;
+ struct viocharlpevent *viochar = (struct viocharlpevent *)vio_char_event_buffer;
+ unsigned long flags;
+ struct port_info_tag * pi = NULL;
+ HvLpIndex lp;
+ u8 port;
+
+ if (tty)
+ {
+ pi = (struct port_info_tag *)tty->driver_data;
+
+ if (!pi || viotty_paranoia_check(pi, tty->device, "viotty_internal_write"))
+ return -ENODEV;
+
+ lp = pi->lp;
+ port = pi->port;
+ }
+ else
+ {
+ /*
+ * If this is the console device, use the lp from the first port entry
+ */
+ port = 0;
+ lp = port_info[0].lp;
+ }
+
+ /*
+ * Always put console output in the hypervisor console log
+ */
+ if (port == 0)
+ HvCall_writeLogBuffer(buf, len);
+
+ /*
+ * If the path to this LP is closed, don't bother doing anything more.
+ * just dump the data on the floor
+ */
+ if (!viopath_isactive(lp))
+ return len;
+
+ /*
+ * If there is already data queued for this port, send it
+ */
+ if (overflow[port].bufferUsed)
+ sendBuffers(port, lp);
+
+ spin_lock_irqsave(&consolelock,
+ flags);
+
+ initDataEvent(viochar, lp);
+
+ /* Got the lock, don't cause console output */
+ while ((bleft > 0) &&
+ (overflow[port].bufferUsed == 0) &&
+ ((sndMsgSeq[port] - sndMsgAck[port]) VIOCHAR_MAX_DATA)
+ curlen = VIOCHAR_MAX_DATA;
+ else
+ curlen = bleft;
+
+ viochar->immediateDataLen = curlen;
+ viochar->event.xCorrelationToken = sndMsgSeq[port]++;
+
+ if (userFlag)
+ copy_from_user(viochar->immediateData,curbuf,curlen);
+ else
+ memcpy(viochar->immediateData,curbuf,curlen);
+
+ viochar->event.xSizeMinus1 = offsetof(struct viocharlpevent, immediateData) +
+ curlen;
+
+ hvrc = HvCallEvent_signalLpEvent(&viochar->event);
+ if (hvrc)
+ {
+ /*
+ * MUST unlock the spinlock before doing a printk
+ */
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ printk("viocons: error sending event! %d\n",(int)hvrc);
+ return len - bleft;
+ }
+
+ curbuf += curlen;
+ bleft -= curlen;
+ }
+
+ /*
+ * If we didn't send it all, buffer it
+ */
+ if (bleft > 0)
+ {
+ bleft -= bufferAdd(port, curbuf,bleft, userFlag);
+ }
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ return len - bleft;
+}
+
+/***************************************************************************
+ * Initialize the common fields in a charLpEvent
+ ***************************************************************************/
+static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp)
+{
+ memset(viochar, 0x00, sizeof(struct viocharlpevent));
+
+ viochar->event.xFlags.xValid = 1;
+ viochar->event.xFlags.xFunction = HvLpEvent_Function_Int;
+ viochar->event.xFlags.xAckInd = HvLpEvent_AckInd_NoAck;
+ viochar->event.xFlags.xAckType = HvLpEvent_AckType_DeferredAck;
+ viochar->event.xType = HvLpEvent_Type_VirtualIo;
+ viochar->event.xSubtype = viomajorsubtype_chario | viochardata;
+ viochar->event.xSourceLp = HvLpConfig_getLpIndex();
+ viochar->event.xTargetLp = lp;
+ viochar->event.xSizeMinus1 = sizeof(struct viocharlpevent);
+ viochar->event.xSourceInstanceId = viopath_sourceinst(lp);
+ viochar->event.xTargetInstanceId = viopath_targetinst(lp);
+}
+
+
+/***************************************************************************
+ * console device write
+ ***************************************************************************/
+static void viocons_write(struct console *co, const char *s,
+ unsigned count)
+{
+ /*** Ryan S. Arnold : ryanarn@us.ibm.com *** 05/03/2001 ***********************
+ * This parser will ensure that all single instances of either \n or \r are
+ * matched into carriage return/line feed combinations. It also allows for
+ * instances where there already exist \n\r combinations as well as the
+ * reverse, \r\n combinations.
+ */
+
+ int index;
+ char charptr[1];
+ int foundcr;
+ int slicebegin;
+ int sliceend;
+
+ foundcr = 0;
+ slicebegin = 0;
+ sliceend = 0;
+
+ for ( index = 0; index < count; index++ )
+ {
+ if( !foundcr && s[index] == 0x0a )
+ {
+ if ( (slicebegin - sliceend > 0) && sliceend < count )
+ {
+ internal_write(NULL, &s[slicebegin],sliceend - slicebegin, 0 );
+ slicebegin = sliceend;
+ }
+ charptr[0] = '\r';
+ internal_write(NULL, charptr, 1, 0);
+ }
+ if( foundcr && s[index] != 0x0a )
+ {
+ if ( ( index - 2 ) >= 0 )
+ {
+ if ( s[index - 2] != 0x0a )
+ {
+ internal_write(NULL, &s[slicebegin],sliceend - slicebegin, 0 );
+ slicebegin = sliceend;
+ charptr[0] = '\n';
+ internal_write(NULL, charptr, 1, 0);
+ }
+ }
+ }
+ sliceend++;
+
+ if( s[index] == 0x0d )
+ foundcr = 1;
+ else
+ foundcr = 0;
+ }
+
+ internal_write(NULL, &s[slicebegin], sliceend - slicebegin, 0 );
+
+ if ( count > 1)
+ {
+ if ( foundcr == 1 && s[count-1] != 0x0a )
+ {
+ charptr[0] = '\n';
+ internal_write(NULL, charptr, 1, 0);
+ }
+ else if ( s[count-1] == 0x0a && s[count-2] != 0x0d )
+ {
+
+ charptr[0] = '\r';
+ internal_write(NULL, charptr, 1, 0);
+ }
+ }
+}
+
+/***************************************************************************
+ * Work out a the device associate with this console
+ ***************************************************************************/
+static kdev_t viocons_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, c->index + viotty_driver.minor_start);
+}
+
+/***************************************************************************
+ * console device read method
+ ***************************************************************************/
+static int viocons_read( struct console *co, const char *s,
+ unsigned count )
+{
+ printk("In viocons_read\n");
+ // Implement me
+ interruptible_sleep_on( &viocons_wait_queue );
+ return 0;
+}
+
+/***************************************************************************
+ * console device wait until a key is pressed
+ ***************************************************************************/
+static int viocons_wait_key( struct console *co )
+{
+ printk("In viocons_wait_key\n");
+ // Implement me
+ interruptible_sleep_on( &viocons_wait_queue );
+ return 0;
+}
+
+/***************************************************************************
+ * Do console device setup
+ ***************************************************************************/
+static int __init viocons_setup(struct console *co, char *options)
+{
+ printk("viocons: in viocons_setup\n");
+ spin_lock_init(&consolelock);
+ return 0;
+}
+
+/***************************************************************************
+ * console device I/O methods
+ ***************************************************************************/
+static struct console viocons = {
+ name: "ttyS",
+ write: viocons_write,
+ read: viocons_read,
+ device: viocons_device,
+ wait_key: viocons_wait_key,
+ setup: viocons_setup,
+ flags: CON_PRINTBUFFER,
+};
+
+
+/***************************************************************************
+ * TTY Open method
+ ***************************************************************************/
+static int viotty_open(struct tty_struct *tty, struct file * filp)
+{
+ int port;
+ unsigned long flags;
+ MOD_INC_USE_COUNT;
+ port = MINOR(tty->device) - tty->driver.minor_start;
+
+ if (port >= VIOTTY_SERIAL_START)
+ port -= VIOTTY_SERIAL_START;
+
+ if ((port < 0) || (port >= VTTY_PORTS)) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+ spin_lock_irqsave(&consolelock,
+ flags);
+
+ /*
+ * If some other TTY is already connected here, reject the open
+ */
+ if ((port_info[port].tty) &&
+ (port_info[port].tty != tty))
+ {
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+ MOD_DEC_USE_COUNT;
+ printk("viocons: attempt to open device twice from different ttys\n");
+ return -EBUSY;
+ }
+ tty->driver_data = &port_info[port];
+ port_info[port].tty = tty;
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ return 0;
+}
+
+/***************************************************************************
+ * TTY Close method
+ ***************************************************************************/
+static void viotty_close(struct tty_struct *tty, struct file * filp)
+{
+ unsigned long flags;
+ struct port_info_tag * pi = (struct port_info_tag *)tty->driver_data;
+
+ if (!pi || viotty_paranoia_check(pi, tty->device, "viotty_close"))
+ return;
+
+ spin_lock_irqsave(&consolelock,
+ flags);
+ if (tty->count == 1)
+ {
+ pi->tty = NULL;
+ }
+
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ MOD_DEC_USE_COUNT;
+}
+
+/***************************************************************************
+ * TTY Write method
+ ***************************************************************************/
+static int viotty_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ return internal_write(tty, buf, count, from_user);
+}
+
+/***************************************************************************
+ * TTY put_char method
+ ***************************************************************************/
+static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ internal_write(tty, &ch, 1, 0);
+}
+
+/***************************************************************************
+ * TTY flush_chars method
+ ***************************************************************************/
+static void viotty_flush_chars(struct tty_struct *tty)
+{
+}
+
+/***************************************************************************
+ * TTY write_room method
+ ***************************************************************************/
+static int viotty_write_room(struct tty_struct *tty)
+{
+ int i;
+ int room = 0;
+ struct port_info_tag * pi = (struct port_info_tag *)tty->driver_data;
+
+ if (!pi || viotty_paranoia_check(pi, tty->device, "viotty_sendbuffers"))
+ return 0;
+
+ // If no buffers are used, return the max size
+ if (overflow[pi->port].bufferUsed == 0)
+ return VIOCHAR_MAX_DATA * NUM_BUF;
+
+ for (i=0; ((iport].bufferBytes[i]);
+ }
+
+ if (room > VIOCHAR_MAX_DATA)
+ return VIOCHAR_MAX_DATA;
+ else
+ return room;
+}
+
+/***************************************************************************
+ * TTY chars_in_buffer_room method
+ ***************************************************************************/
+static int viotty_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0;
+}
+
+static void viotty_flush_buffer(struct tty_struct *tty)
+{
+}
+
+static int viotty_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd)
+ {
+ /* the ioctls below read/set the flags usually shown in the leds */
+ /* don't use them - they will go away without warning */
+ case KDGETLED:
+ case KDGKBLED:
+ return put_user(0, (char*)arg);
+
+ case KDSKBLED:
+ return 0;
+ }
+
+ return n_tty_ioctl(tty,file,cmd,arg);
+}
+
+static void viotty_throttle(struct tty_struct * tty)
+{
+}
+
+static void viotty_unthrottle(struct tty_struct * tty)
+{
+}
+
+static void viotty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+}
+
+static void viotty_stop(struct tty_struct *tty)
+{
+}
+
+static void viotty_start(struct tty_struct *tty)
+{
+}
+
+static void viotty_hangup(struct tty_struct *tty)
+{
+}
+
+static void viotty_break(struct tty_struct *tty, int break_state)
+{
+}
+
+static void viotty_send_xchar(struct tty_struct *tty, char ch)
+{
+}
+
+static void viotty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+}
+
+/***************************************************************************
+ * Handle an open charLpEvent. Could be either interrupt or ack
+ ***************************************************************************/
+static void vioHandleOpenEvent(struct HvLpEvent *event)
+{
+ unsigned long flags;
+ u8 eventRc;
+ u16 eventSubtypeRc;
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ u8 port = cevent->virtualDevice;
+
+ if (event->xFlags.xFunction == HvLpEvent_Function_Ack)
+ {
+ if (port >= VTTY_PORTS)
+ return;
+
+ spin_lock_irqsave(&consolelock,
+ flags);
+ /* Got the lock, don't cause console output */
+
+ if (event->xRc == HvLpEvent_Rc_Good)
+ {
+ sndMsgSeq[port] = sndMsgAck[port] = 0;
+ }
+
+ port_info[port].lp = event->xTargetLp;
+
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ if(event->xCorrelationToken != 0)
+ {
+ unsigned long semptr = event->xCorrelationToken;
+ up((struct semaphore *)semptr);
+ }
+ else
+ printk("viocons: wierd...got open ack without semaphore\n");
+ }
+ else
+ {
+ /* This had better require an ack, otherwise complain
+ */
+ if (event->xFlags.xAckInd != HvLpEvent_AckInd_DoAck)
+ {
+ printk("viocons: viocharopen without ack bit!\n");
+ return;
+ }
+
+ spin_lock_irqsave(&consolelock,
+ flags);
+ /* Got the lock, don't cause console output */
+
+ /* Make sure this is a good virtual tty */
+ if (port >= VTTY_PORTS)
+ {
+ eventRc = HvLpEvent_Rc_SubtypeError;
+ eventSubtypeRc = viorc_openRejected;
+ }
+
+ /* If this is tty is already connected to a different
+ partition, fail */
+ else if ((port_info[port].lp != HvLpIndexInvalid) &&
+ (port_info[port].lp != event->xSourceLp))
+ {
+ eventRc = HvLpEvent_Rc_SubtypeError;
+ eventSubtypeRc = viorc_openRejected;
+ }
+ else
+ {
+ port_info[port].lp = event->xSourceLp;
+ eventRc = HvLpEvent_Rc_Good;
+ eventSubtypeRc = viorc_good;
+ sndMsgSeq[port] = sndMsgAck[port] = 0;
+ }
+
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ /* Return the acknowledgement */
+ HvCallEvent_ackLpEvent(event);
+ }
+}
+
+/***************************************************************************
+ * Handle a close open charLpEvent. Could be either interrupt or ack
+ ***************************************************************************/
+static void vioHandleCloseEvent(struct HvLpEvent *event)
+{
+ unsigned long flags;
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ u8 port = cevent->virtualDevice;
+
+ if (event->xFlags.xFunction == HvLpEvent_Function_Int)
+ {
+ if (port >= VTTY_PORTS)
+ return;
+
+ /* For closes, just mark the console partition invalid */
+ spin_lock_irqsave(&consolelock,
+ flags);
+ /* Got the lock, don't cause console output */
+
+ if (port_info[port].lp == event->xSourceLp)
+ port_info[port].lp = HvLpIndexInvalid;
+
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+ printk("viocons: console close from %d\n", event->xSourceLp);
+ }
+ else
+ {
+ printk("viocons: got unexpected close ack\n");
+ }
+}
+
+/***************************************************************************
+ * Handle a config charLpEvent. Could be either interrupt or ack
+ ***************************************************************************/
+static void vioHandleConfig( struct HvLpEvent *event )
+{
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ int len;
+
+ len = cevent->immediateDataLen;
+ HvCall_writeLogBuffer(cevent->immediateData, cevent->immediateDataLen);
+
+ if ( cevent->immediateData[0] == 0x01 )
+ {
+ printk("viocons: window resized to %d: %d: %d: %d\n",
+ cevent->immediateData[1],
+ cevent->immediateData[2],
+ cevent->immediateData[3],
+ cevent->immediateData[4]);
+ }
+ else
+ {
+ printk("viocons: unknown config event\n");
+ }
+ return;
+}
+
+/***************************************************************************
+ * Handle a data charLpEvent.
+ ***************************************************************************/
+static void vioHandleData(struct HvLpEvent *event)
+{
+ struct tty_struct *tty;
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ struct port_info_tag * pi;
+ int len;
+ u8 port = cevent->virtualDevice;
+
+ if (port >= VTTY_PORTS)
+ {
+ printk("viocons: data on invalid virtual device %d\n",port);
+ return;
+ }
+
+ tty = port_info[port].tty;
+
+ if (tty == NULL)
+ {
+ printk("viocons: no tty for virtual device %d\n",port);
+ return;
+ }
+
+ if (tty->magic != TTY_MAGIC)
+ {
+ printk("viocons: tty bad magic\n");
+ return;
+ }
+
+ /*
+ * Just to be paranoid, make sure the tty points back to this port
+ */
+ pi = (struct port_info_tag *)tty->driver_data;
+
+ if (!pi || viotty_paranoia_check(pi, tty->device, "vioHandleData"))
+ return;
+
+ len = cevent->immediateDataLen;
+
+ if (len == 0)
+ return;
+
+ /*
+ * Log port 0 data to the hypervisor log
+ */
+ if (port == 0)
+ HvCall_writeLogBuffer(cevent->immediateData, cevent->immediateDataLen);
+
+ /* Don't copy more bytes than there is room for in the buffer */
+ if (tty->flip.count + len > TTY_FLIPBUF_SIZE)
+ {
+ len = TTY_FLIPBUF_SIZE - tty->flip.count;
+ printk("viocons: flip buffer overflow!\n");
+ }
+
+ memcpy (tty->flip.char_buf_ptr,
+ cevent->immediateData,
+ len);
+ memset(tty->flip.flag_buf_ptr, TTY_NORMAL, len);
+
+ /* Update the kernel buffer end */
+ tty->flip.count += len;
+ tty->flip.char_buf_ptr += len;
+
+ tty->flip.flag_buf_ptr += len;
+
+ tty_flip_buffer_push (tty);
+}
+
+/***************************************************************************
+ * Handle an ack charLpEvent.
+ ***************************************************************************/
+static void vioHandleAck(struct HvLpEvent *event)
+{
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ unsigned long flags;
+ u8 port = cevent->virtualDevice;
+
+ if (port >= VTTY_PORTS)
+ {
+ printk("viocons: data on invalid virtual device\n");
+ return;
+ }
+
+ spin_lock_irqsave(&consolelock,
+ flags);
+ sndMsgAck[port] = event->xCorrelationToken;
+ spin_unlock_irqrestore(&consolelock,
+ flags);
+
+ if (overflow[port].bufferUsed)
+ sendBuffers(port, port_info[port].lp);
+}
+
+/***************************************************************************
+ * Handle charLpEvents and route to the appropriate routine
+ ***************************************************************************/
+static void vioHandleCharEvent(struct HvLpEvent *event)
+{
+ int charminor;
+
+ if (event == NULL)
+ {
+ return;
+ }
+ charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
+ switch (charminor)
+ {
+ case viocharopen:
+ vioHandleOpenEvent(event);
+ break;
+ case viocharclose:
+ vioHandleCloseEvent(event);
+ break;
+ case viochardata:
+ vioHandleData(event);
+ break;
+ case viocharack:
+ vioHandleAck(event);
+ break;
+ case viocharconfig:
+ vioHandleConfig(event);
+ break;
+ default:
+ }
+}
+
+/***************************************************************************
+ * Send an open event
+ ***************************************************************************/
+static int viocons_sendOpen(HvLpIndex remoteLp, u8 port, void *sem)
+{
+ return HvCallEvent_signalLpEventFast(remoteLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_chario | viocharopen,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(remoteLp),
+ viopath_targetinst(remoteLp),
+ (u64)(unsigned long)sem,
+ VIOVERSION << 16,
+ ((u64)port << 48),
+ 0, 0, 0);
+
+}
+
+int __init viocons_init2(void)
+{
+// extern char saved_command_line[];
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ int rc;
+
+ /*
+ * Now open to the primary LP
+ */
+ printk("viocons: init2 - open path to primary\n");
+ rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), viomajorsubtype_chario);
+ if (rc)
+ {
+ printk("viocons: error on viopath_open to primary %d\n",rc);
+ }
+
+ /*
+ * And if the primary is not the same as the hosting LP, open to the
+ * hosting lp
+ */
+ if ((viopath_hostLp != HvLpIndexInvalid) &&
+ (viopath_hostLp != HvLpConfig_getPrimaryLpIndex()))
+ {
+ printk("viocons: init2 - open path to hosting (%d) (%d)\n",
+ viopath_hostLp, HvLpConfig_getPrimaryLpIndex());
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_chario);
+ if (rc)
+ {
+ printk("viocons: error on viopath_open to hostlp %d\n",rc);
+ }
+ }
+
+ vio_setCharHandler(vioHandleCharEvent);
+
+ printk("viocons major is %d\n",TTY_MAJOR);
+
+ /* First, try to open the console to the hosting lp.
+ * Wait on a semaphore for the response.
+ */
+ if ((viopath_isactive(viopath_hostLp)) &&
+ (viocons_sendOpen(viopath_hostLp, 0, &Semaphore) == 0))
+ {
+ printk("viocons: init2 - open cons to hosting\n");
+ down(&Semaphore);
+ }
+
+ /*
+ * If we don't have an active console, try the primary
+ */
+ if ((!viopath_isactive(port_info[0].lp)) &&
+ (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
+ (viocons_sendOpen(HvLpConfig_getPrimaryLpIndex(), 0, &Semaphore) == 0))
+ {
+ printk("viocons: init2 - open cons to primary\n");
+ down(&Semaphore);
+ }
+
+ printk("viocons: init2 - initializing tty\n");
+
+ /* Initialize the tty_driver structure */
+ memset(&viotty_driver, 0, sizeof(struct tty_driver));
+ viotty_driver.magic = TTY_DRIVER_MAGIC;
+ viotty_driver.driver_name = "vioconsole";
+#if defined(CONFIG_DEVFS_FS)
+ viotty_driver.name = "tty%d";
+#else
+ viotty_driver.name = "tty";
+#endif
+ viotty_driver.major = TTY_MAJOR;
+ viotty_driver.minor_start = 1;
+ viotty_driver.name_base = 1;
+ viotty_driver.num = VTTY_PORTS;
+ viotty_driver.type = TTY_DRIVER_TYPE_CONSOLE;
+ viotty_driver.subtype = 1;
+ viotty_driver.init_termios = tty_std_termios;
+ viotty_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+ viotty_driver.refcount = &viotty_refcount;
+ viotty_driver.table = viotty_table;
+ viotty_driver.termios = viotty_termios;
+ viotty_driver.termios_locked = viotty_termios_locked;
+
+ viotty_driver.open = viotty_open;
+ viotty_driver.close = viotty_close;
+ viotty_driver.write = viotty_write;
+ viotty_driver.put_char = viotty_put_char;
+ viotty_driver.flush_chars = viotty_flush_chars;
+ viotty_driver.write_room = viotty_write_room;
+ viotty_driver.chars_in_buffer = viotty_chars_in_buffer;
+ viotty_driver.flush_buffer = viotty_flush_buffer;
+ viotty_driver.ioctl = viotty_ioctl;
+ viotty_driver.throttle = viotty_throttle;
+ viotty_driver.unthrottle = viotty_unthrottle;
+ viotty_driver.set_termios = viotty_set_termios;
+ viotty_driver.stop = viotty_stop;
+ viotty_driver.start = viotty_start;
+ viotty_driver.hangup = viotty_hangup;
+ viotty_driver.break_ctl = viotty_break;
+ viotty_driver.send_xchar = viotty_send_xchar;
+ viotty_driver.wait_until_sent = viotty_wait_until_sent;
+
+ viottyS_driver = viotty_driver;
+#if defined(CONFIG_DEVFS_FS)
+ viottyS_driver.name = "ttyS%d";
+#else
+ viottyS_driver.name = "ttyS";
+#endif
+ viottyS_driver.major = TTY_MAJOR;
+ viottyS_driver.minor_start = VIOTTY_SERIAL_START;
+ viottyS_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ viottyS_driver.table = viottyS_table;
+ viottyS_driver.termios = viottyS_termios;
+ viottyS_driver.termios_locked = viottyS_termios_locked;
+
+ if (tty_register_driver(&viotty_driver))
+ {
+ printk("Couldn't register viotty driver\n");
+ }
+
+ if (tty_register_driver(&viottyS_driver))
+ {
+ printk("Couldn't register viottyS driver\n");
+ }
+
+ // Now create the vcs and vcsa devfs entries so mingetty works
+#if defined(CONFIG_DEVFS_FS)
+ {
+ struct tty_driver temp_driver = viotty_driver;
+ int i;
+
+ temp_driver.name = "vcs%d";
+ for (i = 0; i < VTTY_PORTS; i++)
+ tty_register_devfs (&temp_driver,
+ 0,
+ i + temp_driver.minor_start);
+
+ temp_driver.name = "vcsa%d";
+ for (i = 0; i < VTTY_PORTS; i++)
+ tty_register_devfs (&temp_driver,
+ 0,
+ i + temp_driver.minor_start);
+
+ // For compatibility with some earlier code only!
+ // This will go away!!!
+ temp_driver.name = "viocons/%d";
+ temp_driver.name_base = 0;
+ for (i = 0; i < VTTY_PORTS; i++)
+ tty_register_devfs (&temp_driver,
+ 0,
+ i + temp_driver.minor_start);
+ }
+#endif
+
+ /*
+ * Create the proc entry
+ */
+ iSeries_proc_callback(&viocons_proc_init);
+
+ return 0;
+}
+
+void __init viocons_init(void)
+{
+ int i;
+ printk("viocons registering console\n");
+
+ memset(&port_info, 0x00, sizeof(port_info));
+ for (i=0; i
+ * (C) Copyright 2000 IBM Corporation
+ *
+ * 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) anyu later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ ***************************************************************************
+ * This routine provides access to tape drives owned and managed by an OS/400
+ * partition running on the same box as this Linux partition.
+ *
+ * All tape operations are performed by sending messages back and forth to
+ * the OS/400 partition. The format of the messages is defined in
+ * include/asm-ppc/iSeries/vio.h
+ *
+ */
+
+/*
+Changelog (absent entries indicate repeats):
+ Ver Date Who What
+ ==== =========== =================== ==============================
+ 2001 Jul 03 devilbis@us.ibm.com fix nvt vs vt bug
+ add automatic WEOF
+ 1.0 2001 Jul 05 add version number
+ set version to 1.0
+ 2001 Jul 11 moved viotape_unitinfo to kernel mem
+ successfully loaded as a module
+ unregistered device in viotap_exit
+ 2002 Jul 12 unregistered proc entry on exit
+ unregistered individual tapes on exit
+ 1.1 2002 Jul 13 added viopath_close on exit
+ added MOD_(INC|DEC)_USE_COUNT
+ set version to 1.1
+*/
+
+#undef VIOT_DEBUG
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef _VIO_H
+#include "asm/iSeries/vio.h"
+#endif
+
+#ifndef _HVLPEVENT_H
+#include
+#endif
+
+#ifndef _HVCALLEVENT_H
+#include "asm/iSeries/HvCallEvent.h"
+#endif
+#ifndef _HVLPCONFIG_H
+#include "asm/iSeries/HvLpConfig.h"
+#endif
+#ifndef _ISERIES_PROC_H
+#include
+#endif
+
+static int viotape_major = 230;
+static int viotape_numdev = 0;
+
+/* version number for viotape driver */
+static unsigned int version_major = 1;
+static unsigned int version_minor = 0;
+
+static u64 sndMsgSeq;
+static u64 sndMsgAck;
+static u64 rcvMsgSeq;
+static u64 rcvMsgAck;
+
+/***************************************************************************
+ * The minor number follows the conventions of the SCSI tape drives. The
+ * rewind and mode are encoded in the minor #. We use this struct to break
+ * them out
+ ***************************************************************************/
+struct viot_devinfo_struct {
+ int major;
+ int minor;
+ int devno;
+ int mode;
+ int rewind;
+};
+
+/***************************************************************************
+ * Maximum # tapes we support
+ ***************************************************************************/
+#define VIOTAPE_MAX_TAPE 8
+#define MAX_PARTITIONS 4
+
+/* defines for current tape state */
+#define VIOT_IDLE 0
+#define VIOT_READING 1
+#define VIOT_WRITING 2
+
+/***************************************************************************
+ * Our info on the tapes
+ ***************************************************************************/
+struct tape_descr {
+ char rsrcname[10];
+ char type[4];
+ char model[3];
+};
+
+static struct tape_descr *viotape_unitinfo = NULL;
+
+static char *lasterr[VIOTAPE_MAX_TAPE];
+
+static struct mtget viomtget[VIOTAPE_MAX_TAPE];
+
+/* maintain the current state of each tape (and partition)
+ so that we know when to write EOF marks.
+*/
+static struct {
+ unsigned char cur_part;
+ devfs_handle_t dev_handle;
+ struct {
+ unsigned char rwi;
+ } part_stat[MAX_PARTITIONS];
+} state[VIOTAPE_MAX_TAPE];
+
+/***************************************************************************
+ * We single-thread
+ ***************************************************************************/
+static struct semaphore reqSem;
+
+/***************************************************************************
+ * When we send a request, we use this struct to get the response back
+ * from the interrupt handler
+ ***************************************************************************/
+struct opStruct {
+ void *buffer;
+ dma_addr_t dmaaddr;
+ size_t count;
+ int rc;
+ struct semaphore *sem;
+ struct opStruct *free;
+};
+
+static spinlock_t opStructListLock;
+static struct opStruct *opStructList;
+
+/***************************************************************************
+ ***************************************************************************
+ * CODE STARTS HERE
+ ***************************************************************************
+ ***************************************************************************/
+
+/* forward declaration to resolve interdependence */
+static int chg_state(int index, unsigned char new_state, struct file *file);
+
+/***************************************************************************
+ * Decode the kdev_t into its parts
+ ***************************************************************************/
+void getDevInfo(kdev_t dev, struct viot_devinfo_struct *devi)
+{
+ devi->major = MAJOR(dev);
+ devi->minor = MINOR(dev);
+ devi->devno = devi->minor & 0x1F;
+ devi->mode = (devi->minor & 0x60) >> 5;
+/* if bit is set in the minor, do _not_ rewind automatically */
+ devi->rewind = !(devi->minor & 0x80);
+}
+
+
+/***************************************************************************
+ * Allocate an op structure from our pool
+ ***************************************************************************/
+static struct opStruct *getOpStruct(void)
+{
+ struct opStruct *newOpStruct;
+ spin_lock(&opStructListLock);
+
+ if (opStructList == NULL)
+ {
+ newOpStruct = kmalloc(sizeof(struct opStruct), GFP_KERNEL);
+ }
+ else
+ {
+ newOpStruct = opStructList;
+ opStructList = opStructList->free;
+ }
+
+ if (newOpStruct)
+ memset(newOpStruct,0x00,sizeof(struct opStruct));
+
+ spin_unlock(&opStructListLock);
+
+ return newOpStruct;
+}
+
+/***************************************************************************
+ * Return an op structure to our pool
+ ***************************************************************************/
+static void freeOpStruct(struct opStruct *opStruct)
+{
+ spin_lock(&opStructListLock);
+ opStruct->free = opStructList;
+ opStructList = opStruct;
+ spin_unlock(&opStructListLock);
+}
+
+/***************************************************************************
+ * Map our tape return codes to errno values
+ ***************************************************************************/
+int tapeRcToErrno(int tapeRc, char *operation, int tapeno)
+{
+ int terrno;
+ char *tmsg;
+
+ switch (tapeRc)
+ {
+ case 0: return 0;
+ case viotape_InvalidRange: terrno=EIO; tmsg = "Internal error"; break;
+ case viotape_InvalidToken: terrno=EIO; tmsg = "Internal error"; break;
+ case viotape_DMAError: terrno=EIO; tmsg = "DMA error"; break;
+ case viotape_UseError: terrno=EIO; tmsg = "Internal error"; break;
+ case viotape_ReleaseError: terrno=EIO; tmsg = "Internal error"; break;
+ case viotape_InvalidTape: terrno=EIO; tmsg = "Invalid tape device"; break;
+ case viotape_InvalidOp: terrno=EIO; tmsg = "Invalid operation"; break;
+ case viotape_TapeErr: terrno=EIO; tmsg = "Tape error"; break;
+
+ case viotape_AllocTimedOut: terrno=EBUSY; tmsg = "Allocate timed out"; break;
+ case viotape_BOTEnc: terrno=EIO; tmsg = "Beginning of tape encountered"; break;
+ case viotape_BlankTape: terrno=EIO; tmsg = "Blank tape"; break;
+ case viotape_BufferEmpty: terrno=EIO; tmsg = "Buffer empty"; break;
+ case viotape_CleanCartFound: terrno=ENOMEDIUM; tmsg = "Cleaning cartridge found"; break;
+ case viotape_CmdNotAllowed: terrno=EIO; tmsg = "Command not allowed"; break;
+ case viotape_CmdNotSupported: terrno=EIO; tmsg = "Command not supported"; break;
+ case viotape_DataCheck: terrno=EIO; tmsg = "Data check"; break;
+ case viotape_DecompressErr: terrno=EIO; tmsg = "Decompression error"; break;
+ case viotape_DeviceTimeout: terrno=EBUSY; tmsg = "Device timeout"; break;
+ case viotape_DeviceUnavail: terrno=EIO; tmsg = "Device unavailable"; break;
+ case viotape_DeviceBusy: terrno=EBUSY; tmsg = "Device busy"; break;
+ case viotape_EndOfMedia: terrno=ENOSPC; tmsg = "End of media"; break;
+ case viotape_EndOfTape: terrno=ENOSPC; tmsg = "End of tape"; break;
+ case viotape_EquipCheck: terrno=EIO; tmsg = "Equipment check"; break;
+ case viotape_InsufficientRs: terrno=EOVERFLOW; tmsg = "Insufficient tape resources"; break;
+ case viotape_InvalidLogBlk: terrno=EIO; tmsg = "Invalid logical block location"; break;
+ case viotape_LengthError: terrno=EOVERFLOW; tmsg = "Length error"; break;
+ case viotape_LibDoorOpen: terrno=EBUSY; tmsg = "Door open"; break;
+ case viotape_LoadFailure: terrno=ENOMEDIUM; tmsg = "Load failure"; break;
+ case viotape_NotCapable: terrno=EIO; tmsg = "Not capable"; break;
+ case viotape_NotOperational: terrno=EIO; tmsg = "Not operational"; break;
+ case viotape_NotReady: terrno=EIO; tmsg = "Not ready"; break;
+ case viotape_OpCancelled: terrno=EIO; tmsg = "Operation cancelled"; break;
+ case viotape_PhyLinkErr: terrno=EIO; tmsg = "Physical link error"; break;
+ case viotape_RdyNotBOT: terrno=EIO; tmsg = "Ready but not beginning of tape"; break;
+ case viotape_TapeMark: terrno=EIO; tmsg = "Tape mark"; break;
+ case viotape_WriteProt: terrno=EROFS; tmsg = "Write protection error"; break;
+ default:
+ terrno = EIO; tmsg = "I/O error";
+ }
+
+ printk("viotape error on Device %d (%10.10s): %s\n",
+ tapeno,
+ viotape_unitinfo[tapeno].rsrcname,
+ tmsg);
+
+ lasterr[tapeno] = tmsg;
+
+ return -terrno;
+}
+
+/***************************************************************************
+ * Handle reads from the proc file system.
+ ***************************************************************************/
+static int proc_read(char *buf, char **start, off_t offset,
+ int blen, int *eof, void *data)
+{
+ int len = 0;
+ int i;
+
+ len += sprintf(buf+len, "viotape driver version %d.%d\n",
+ version_major, version_minor);
+
+ for (i=0; inlink = 1;
+ ent->data = NULL;
+ ent->read_proc = proc_read;
+}
+
+/***************************************************************************
+ * clean up our proc file system entries
+ ***************************************************************************/
+void viotape_proc_delete(struct proc_dir_entry *iSeries_proc)
+{
+ remove_proc_entry("viotape", iSeries_proc);
+}
+
+
+/***************************************************************************
+ * Get info on all tapes from OS/400
+ ***************************************************************************/
+static void get_viotape_info(void)
+{
+ dma_addr_t dmaaddr;
+ HvLpEvent_Rc hvrc;
+ int i;
+ struct opStruct *op = getOpStruct();
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ if (op == NULL)
+ return;
+
+ if (viotape_unitinfo == NULL) {
+#ifdef VIOT_DEBUG
+ printk("viotape: trying to allocate pci buffer\n");
+#endif
+ viotape_unitinfo = kmalloc(sizeof(struct tape_descr) * VIOTAPE_MAX_TAPE, GFP_KERNEL);
+ }
+#ifdef VIOT_DEBUG
+ printk("viotape: trying to clear pci buffer\n");
+#endif
+ memset(viotape_unitinfo, 0x00, sizeof(struct tape_descr) * VIOTAPE_MAX_TAPE);
+ memset(lasterr, 0x00, sizeof(lasterr));
+
+ op->sem = &Semaphore;
+
+ dmaaddr = pci_map_single(NULL, viotape_unitinfo,
+ sizeof(struct tape_descr) * VIOTAPE_MAX_TAPE,
+ PCI_DMA_FROMDEVICE);
+ if (dmaaddr == 0xFFFFFFFF)
+ {
+ printk("viotape error allocating tce\n");
+ return;
+ }
+
+#ifdef VIOT_DEBUG
+ printk("viotape: trying to request information\n");
+#endif
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapegetinfo,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ dmaaddr,
+ sizeof(struct tape_descr) * VIOTAPE_MAX_TAPE,
+ 0,
+ 0);
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ printk("viotape hv error on op %d\n",(int)hvrc);
+ }
+
+ down(&Semaphore);
+
+ freeOpStruct(op);
+
+#ifdef VIOT_DEBUG
+ printk("viotape: checking pci buffer for information\n");
+#endif
+
+ for (i=0;
+ ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0]));
+ i++)
+ {
+ printk("found a tape %10.10s\n",viotape_unitinfo[i].rsrcname);
+ viotape_numdev++;
+ }
+}
+
+/***************************************************************************
+ * Don't support seek
+ ***************************************************************************/
+static long long viotap_llseek(struct file *file, long long offset, int origin)
+{
+ printk("viotape_llseek: not supported\n");
+ return -EINVAL; /* not supported */
+}
+
+/***************************************************************************
+ * Write
+ ***************************************************************************/
+static ssize_t viotap_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ HvLpEvent_Rc hvrc;
+ kdev_t dev = file->f_dentry->d_inode->i_rdev;
+ unsigned short flags = file->f_flags;
+ struct opStruct *op = getOpStruct();
+ int noblock = ((flags & O_NONBLOCK) != 0);
+ int err;
+ struct viot_devinfo_struct devi;
+ DECLARE_MUTEX_LOCKED(Semaphore);
+
+#ifdef VIOT_DEBUG
+ printk("viotape: tried to call write\n");
+#endif
+
+ if (op == NULL)
+ return -ENOMEM;
+
+ getDevInfo(dev, &devi);
+
+ /* We need to make sure we can send a request. We use
+ * a semaphore to keep track of # requests in use. If
+ * we are non-blocking, make sure we don't block on the
+ * semaphore
+ */
+ if (noblock)
+ {
+ if (down_trylock(&reqSem))
+ {
+ freeOpStruct(op);
+ return -EWOULDBLOCK;
+ }
+ }
+ else
+ {
+ down(&reqSem);
+ }
+
+ /* Allocate a DMA buffer */
+ op->buffer = pci_alloc_consistent(NULL,
+ count,
+ &op->dmaaddr);
+
+ if ((op->dmaaddr == 0xFFFFFFFF) || (op->buffer == NULL))
+ {
+ printk("viotape error allocating dma buffer for len %d\n",
+ count);
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EFAULT;
+ }
+
+ op->count = count;
+
+ /* Copy the data into the buffer */
+ err = copy_from_user( op->buffer, (const void *) buf, count);
+ if (err)
+ {
+ printk("viotape: error on copy from user\n");
+ pci_free_consistent(NULL, count, op->buffer, op->dmaaddr);
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EFAULT;
+ }
+
+ if (noblock)
+ {
+ op->sem = NULL;
+ }
+ else
+ {
+ op->sem = &Semaphore;
+ }
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapewrite,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ ((u64)devi.devno << 48) |
+ op->dmaaddr,
+ count,
+ 0,
+ 0);
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ printk("viotape hv error on op %d\n",(int)hvrc);
+ pci_free_consistent(NULL, count, op->buffer, op->dmaaddr);
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EIO;
+ }
+
+ if (noblock)
+ return count;
+
+ down(&Semaphore);
+
+ err = op->rc;
+
+ /* Free the buffer */
+ pci_free_consistent(NULL, count, op->buffer, op->dmaaddr);
+
+ count = op->count;
+
+ freeOpStruct(op);
+ up(&reqSem);
+ if (err)
+ return tapeRcToErrno(err, "write", devi.devno);
+ else
+ {
+ chg_state(devi.devno, VIOT_WRITING, file);
+ return count;
+ }
+}
+
+/***************************************************************************
+ * read
+ ***************************************************************************/
+static ssize_t viotap_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+ HvLpEvent_Rc hvrc;
+ kdev_t dev = file->f_dentry->d_inode->i_rdev;
+ unsigned short flags = file->f_flags;
+ struct opStruct *op = getOpStruct();
+ int noblock = ((flags & O_NONBLOCK) != 0);
+ int err;
+ struct viot_devinfo_struct devi;
+ DECLARE_MUTEX_LOCKED(Semaphore);
+
+#ifdef VIOT_DEBUG
+ printk("viotape: tried to call read\n");
+#endif
+
+ if (op == NULL)
+ return -ENOMEM;
+
+ getDevInfo(dev, &devi);
+
+ /* We need to make sure we can send a request. We use
+ * a semaphore to keep track of # requests in use. If
+ * we are non-blocking, make sure we don't block on the
+ * semaphore
+ */
+ if (noblock)
+ {
+ if (down_trylock(&reqSem))
+ {
+ freeOpStruct(op);
+ return -EWOULDBLOCK;
+ }
+ }
+ else
+ {
+ down(&reqSem);
+ }
+
+ chg_state(devi.devno, VIOT_READING, file);
+
+ /* Allocate a DMA buffer */
+ op->buffer = pci_alloc_consistent(NULL,
+ count,
+ &op->dmaaddr);
+
+ if ((op->dmaaddr == 0xFFFFFFFF) || (op->buffer == NULL))
+ {
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EFAULT;
+ }
+
+ op->count = count;
+
+ op->sem = &Semaphore;
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotaperead,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ ((u64)devi.devno << 48) |
+ op->dmaaddr,
+ count,
+ 0,
+ 0);
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ printk("viotape hv error on op %d\n",(int)hvrc);
+ pci_free_consistent(NULL, count, op->buffer, op->dmaaddr);
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EIO;
+ }
+
+ down(&Semaphore);
+
+ if (op->rc == 0)
+ {
+ /* If we got data back */
+ if (op->count)
+ {
+ /* Copy the data into the buffer */
+ err = copy_to_user( buf, op->buffer, count);
+ if (err)
+ {
+ printk("error on copy_to_user\n");
+ pci_free_consistent(NULL, count, op->buffer, op->dmaaddr);
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EFAULT;
+ }
+ }
+ }
+
+ err = op->rc;
+
+ /* Free the buffer */
+ pci_free_consistent(NULL, count, op->buffer, op->dmaaddr);
+
+ count = op->count;
+
+ freeOpStruct(op);
+ up(&reqSem);
+ if (err)
+ return tapeRcToErrno(err, "read", devi.devno);
+ else
+ return count;
+}
+
+/***************************************************************************
+ * read
+ ***************************************************************************/
+static int viotap_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ HvLpEvent_Rc hvrc;
+ int err;
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ kdev_t dev = file->f_dentry->d_inode->i_rdev;
+ struct opStruct *op = getOpStruct();
+ struct viot_devinfo_struct devi;
+ if (op == NULL)
+ return -ENOMEM;
+
+#ifdef VIOT_DEBUG
+ printk("viotape: tried to call ioctl\n");
+#endif
+
+ getDevInfo(dev, &devi);
+
+ down(&reqSem);
+
+ switch (cmd)
+ {
+ case MTIOCTOP:
+ {
+ struct mtop mtc;
+ u32 myOp;
+
+ /* inode is null if and only if we (the kernel) made the request */
+ if(inode == NULL)
+ memcpy(&mtc, (void *)arg, sizeof(struct mtop));
+ else if (copy_from_user((char *) &mtc, (char *) arg, sizeof(struct mtop)))
+ {
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EFAULT;
+ }
+
+ switch(mtc.mt_op)
+ {
+ case MTRESET: myOp = VIOTAPOP_RESET; break;
+ case MTFSF: myOp = VIOTAPOP_FSF; break;
+ case MTBSF: myOp = VIOTAPOP_BSF; break;
+ case MTFSR: myOp = VIOTAPOP_FSR; break;
+ case MTBSR: myOp = VIOTAPOP_BSR; break;
+ case MTWEOF: myOp = VIOTAPOP_WEOF; break;
+ case MTREW: myOp = VIOTAPOP_REW; break;
+ case MTNOP: myOp = VIOTAPOP_NOP; break;
+ case MTEOM: myOp = VIOTAPOP_EOM; break;
+ case MTERASE: myOp = VIOTAPOP_ERASE; break;
+ case MTSETBLK: myOp = VIOTAPOP_SETBLK; break;
+ case MTSETDENSITY: myOp = VIOTAPOP_SETDENSITY; break;
+ case MTTELL: myOp = VIOTAPOP_GETPOS; break;
+ case MTSEEK: myOp = VIOTAPOP_SETPOS; break;
+ case MTSETPART: myOp = VIOTAPOP_SETPART; break;
+ default:
+ return -EIO;
+ }
+
+/* if we moved the head, we are no longer reading or writing */
+ switch(mtc.mt_op)
+ {
+ case MTFSF:
+ case MTBSF:
+ case MTFSR:
+ case MTBSR:
+ case MTTELL:
+ case MTSEEK:
+ case MTREW:
+ chg_state(devi.devno, VIOT_IDLE, file);
+ }
+
+ op->sem = &Semaphore;
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapeop,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ ((u64)devi.devno << 48),
+ 0,
+ (((u64)myOp) << 32) | mtc.mt_count,
+ 0);
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ printk("viotape hv error on op %d\n",(int)hvrc);
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EIO;
+ }
+ down(&Semaphore);
+
+ if (op->rc)
+ {
+ freeOpStruct(op);
+ up(&reqSem);
+ return tapeRcToErrno(op->rc, "tape operation", devi.devno);
+ }
+ else
+ {
+ freeOpStruct(op);
+ up(&reqSem);
+ return 0;
+ }
+ break;
+ }
+
+ case MTIOCGET:
+ op->sem = &Semaphore;
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapegetstatus ,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ ((u64)devi.devno << 48),
+ 0, 0, 0);
+ if (hvrc != HvLpEvent_Rc_Good)
+ {
+ printk("viotape hv error on op %d\n",(int)hvrc);
+ freeOpStruct(op);
+ up(&reqSem);
+ return -EIO;
+ }
+ down(&Semaphore);
+ up(&reqSem);
+ if (op->rc)
+ {
+ freeOpStruct(op);
+ return tapeRcToErrno(op->rc, "get status", devi.devno);
+ }
+ else
+ {
+ freeOpStruct(op);
+ err = copy_to_user((void *)arg, &viomtget[dev], sizeof(viomtget[0]));
+ if (err)
+ {
+ freeOpStruct(op);
+ return -EFAULT;
+ }
+ return 0;
+ }
+ break;
+ case MTIOCPOS:
+ printk("Got an MTIOCPOS\n");
+ default:
+ return -ENOSYS;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ * Open
+ ***************************************************************************/
+static int viotap_open(struct inode *inode, struct file *file)
+{
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ kdev_t dev = file->f_dentry->d_inode->i_rdev;
+ HvLpEvent_Rc hvrc;
+ struct opStruct *op = getOpStruct();
+ struct viot_devinfo_struct devi;
+ if (op == NULL)
+ return -ENOMEM;
+
+#ifdef VIOT_DEBUG
+ printk("viotape: tried to call open\n");
+#endif
+
+ getDevInfo(dev, &devi);
+
+ // Note: We currently only support one mode!
+ if ((devi.devno >= viotape_numdev) ||
+ (devi.mode))
+ {
+#ifdef VIOT_DEBUG
+ printk("viotape: invalid devno %d or mode %d\n", devi.devno, devi.mode);
+#endif
+ freeOpStruct(op);
+ return -ENODEV;
+ }
+
+ op->sem = &Semaphore;
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapeopen,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ ((u64)devi.devno << 48),
+ 0, 0, 0);
+
+
+ if (hvrc != 0)
+ {
+ printk("viotape bad rc on signalLpEvent %d\n",(int)hvrc);
+ freeOpStruct(op);
+ return -EIO;
+ }
+
+ down(&Semaphore);
+
+ if (op->rc)
+ {
+#ifdef VIOT_DEBUG
+ printk("viotape: bad return code in viotapopen: %d", op->rc);
+#endif
+ freeOpStruct(op);
+ return tapeRcToErrno(op->rc, "open", devi.devno);
+ }
+ else
+ {
+ freeOpStruct(op);
+ MOD_INC_USE_COUNT;
+ return 0;
+ }
+}
+
+
+/***************************************************************************
+ * Release
+ ***************************************************************************/
+static int viotap_release(struct inode *inode, struct file *file)
+{
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ kdev_t dev = file->f_dentry->d_inode->i_rdev;
+ HvLpEvent_Rc hvrc;
+ struct viot_devinfo_struct devi;
+ struct opStruct *op = getOpStruct();
+
+#ifdef VIOT_DEBUG
+ printk("viotape: tried to call release\n");
+#endif
+
+ if (op == NULL)
+ return -ENOMEM;
+ op->sem = &Semaphore;
+
+ getDevInfo(dev, &devi);
+
+ if (devi.devno >= viotape_numdev)
+ {
+ freeOpStruct(op);
+ return -ENODEV;
+ }
+
+ chg_state(devi.devno, VIOT_IDLE, file);
+
+ if (devi.rewind)
+ {
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapeop,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ ((u64)devi.devno << 48),
+ 0,
+ ((u64)VIOTAPOP_REW) << 32,
+ 0);
+ down(&Semaphore);
+
+ if (op->rc)
+ {
+ tapeRcToErrno(op->rc, "rewind", devi.devno);
+ }
+ }
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapeclose,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(u32)op,
+ VIOVERSION << 16,
+ ((u64)devi.devno << 48),
+ 0, 0, 0);
+
+
+ if (hvrc != 0)
+ {
+ printk("viotape: bad rc on signalLpEvent %d\n",(int)hvrc);
+ return -EIO;
+ }
+
+ down(&Semaphore);
+
+ if (op->rc)
+ {
+ printk("viotape: close failed\n");
+ }
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+struct file_operations viotap_fops = {
+ owner: THIS_MODULE,
+ llseek: viotap_llseek,
+ read: viotap_read,
+ write: viotap_write,
+ ioctl: viotap_ioctl,
+ open: viotap_open,
+ release: viotap_release,
+};
+
+/***************************************************************************
+ * Handle interrupt events for tape
+ ***************************************************************************/
+static void vioHandleTapeEvent(struct HvLpEvent *event)
+{
+ int tapeminor;
+ struct opStruct *op;
+ struct viotapelpevent *tevent = (struct viotapelpevent *)event;
+
+ if (event == NULL)
+ {
+ /* Notification that a partition went away! */
+ if (!viopath_isactive(viopath_hostLp))
+ {
+ /* TODO! Clean up */
+ }
+ return;
+ }
+
+ tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
+ switch (tapeminor)
+ {
+ case viotapegetinfo:
+ case viotapeopen:
+ case viotapeclose:
+ op = (struct opStruct *)(u32)event->xCorrelationToken;
+ op->rc = tevent->mSubTypeRc;
+ up(op->sem);
+ break;
+ case viotaperead:
+ case viotapewrite:
+ op = (struct opStruct *)(u32)event->xCorrelationToken;
+ op->rc = tevent->mSubTypeRc;;
+ op->count = tevent->mLen;
+
+ if (op->sem)
+ {
+ up(op->sem);
+ }
+ else
+ {
+ freeOpStruct(op);
+ up(&reqSem);
+ }
+ break;
+ case viotapeop:
+ case viotapegetpos:
+ case viotapesetpos:
+ case viotapegetstatus:
+ op = (struct opStruct *)(u32)event->xCorrelationToken;
+ if (op)
+ {
+ op->count = tevent->u.tapeOp.mCount;
+ op->rc = tevent->mSubTypeRc;;
+
+ if (op->sem)
+ {
+ up(op->sem);
+ }
+ }
+ break;
+ default:
+ printk("viotape: wierd ack\n");
+ }
+}
+
+
+/***************************************************************************
+ * Do initialization
+ ***************************************************************************/
+int __init viotap_init(void)
+{
+ DECLARE_MUTEX_LOCKED(Semaphore);
+ int rc;
+ char tapename[32];
+ int i;
+
+ printk("viotape driver version %d.%d\n", version_major, version_minor);
+
+ sndMsgSeq = sndMsgAck = 0;
+ rcvMsgSeq = rcvMsgAck = 0;
+ opStructList = NULL;
+ spin_lock_init(&opStructListLock);
+
+ sema_init(&reqSem, VIOTAPE_MAXREQ);
+
+ /*
+ * Open to our hosting lp
+ */
+ if (viopath_hostLp == HvLpIndexInvalid)
+ return -1;
+
+ printk("viotape: init - open path to hosting (%d)\n", viopath_hostLp);
+
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_tape);
+ if (rc)
+ {
+ printk("viotape: error on viopath_open to hostlp %d\n",rc);
+ }
+
+ vio_setTapeHandler(vioHandleTapeEvent);
+
+ printk("viotape major is %d\n",viotape_major);
+
+ get_viotape_info();
+
+ if (devfs_register_chrdev(viotape_major, "viotape", &viotap_fops))
+ {
+ printk("Error registering viotape device\n");
+ return -1;
+ }
+
+ for (i=0; i= 0x20400
-static struct pci_device_id acenic_pci_tbl[] __initdata = {
- { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
- { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C985,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
- { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
- { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
- /*
- * Farallon used the DEC vendor ID on their cards incorrectly.
- */
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
- { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
- { }
-};
-MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
-#endif
-
#ifndef wmb
#define wmb() mb()
@@ -521,230 +497,188 @@
"acenic.c: v0.81 04/20/2001 Jes Sorensen, linux-acenic@SunSITE.dk\n"
" http://home.cern.ch/~jes/gige/acenic.html\n";
-static struct net_device *root_dev;
-
-static int probed __initdata = 0;
-
-
-int __devinit acenic_probe (ACE_PROBE_ARG)
+static int __devinit acenic_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
-#ifdef NEW_NETINIT
struct net_device *dev;
-#endif
-
struct ace_private *ap;
- struct pci_dev *pdev = NULL;
int boards_found = 0;
int version_disp;
- if (probed)
- return -ENODEV;
- probed++;
-
if (!pci_present()) /* is PCI support present? */
return -ENODEV;
version_disp = 0;
- while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
+ dev = init_etherdev(NULL, sizeof(struct ace_private));
- if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
- ((pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE) ||
- (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_COPPER)))&&
- !((pdev->vendor == PCI_VENDOR_ID_3COM) &&
- (pdev->device == PCI_DEVICE_ID_3COM_3C985)) &&
- !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) &&
- ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) ||
- (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) &&
- /*
- * Farallon used the DEC vendor ID on their cards by
- * mistake for a while
- */
- !((pdev->vendor == PCI_VENDOR_ID_DEC) &&
- (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) &&
- !((pdev->vendor == PCI_VENDOR_ID_SGI) &&
- (pdev->device == PCI_DEVICE_ID_SGI_ACENIC)))
- continue;
-
- dev = init_etherdev(NULL, sizeof(struct ace_private));
-
- if (dev == NULL) {
- printk(KERN_ERR "acenic: Unable to allocate "
- "net_device structure!\n");
- break;
- }
+ if (dev == NULL) {
+ printk(KERN_ERR "acenic: Unable to allocate "
+ "net_device structure!\n");
+ return -ENODEV;
+ }
- SET_MODULE_OWNER(dev);
+ SET_MODULE_OWNER(dev);
- if (!dev->priv)
- dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL);
- if (!dev->priv) {
- printk(KERN_ERR "acenic: Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- ap = dev->priv;
- ap->pdev = pdev;
-
- dev->irq = pdev->irq;
- dev->open = &ace_open;
- dev->hard_start_xmit = &ace_start_xmit;
- dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
- if (1) {
- static void ace_watchdog(struct net_device *dev);
- dev->tx_timeout = &ace_watchdog;
- dev->watchdog_timeo = 5*HZ;
- }
- dev->stop = &ace_close;
- dev->get_stats = &ace_get_stats;
- dev->set_multicast_list = &ace_set_multicast_list;
- dev->do_ioctl = &ace_ioctl;
- dev->set_mac_address = &ace_set_mac_addr;
- dev->change_mtu = &ace_change_mtu;
+ if (!dev->priv)
+ dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL);
+ if (!dev->priv) {
+ printk(KERN_ERR "acenic: Unable to allocate memory\n");
+ return -ENOMEM;
+ }
- /* display version info if adapter is found */
- if (!version_disp)
- {
- /* set display flag to TRUE so that */
- /* we only display this string ONCE */
- version_disp = 1;
- printk(version);
- }
+ ap = dev->priv;
+ ap->pdev = pdev;
- /*
- * Enable master mode before we start playing with the
- * pci_command word since pci_set_master() will modify
- * it.
- */
- pci_set_master(pdev);
+ dev->irq = pdev->irq;
+ dev->open = &ace_open;
+ dev->hard_start_xmit = &ace_start_xmit;
+ dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
+ if (1) {
+ static void ace_watchdog(struct net_device *dev);
+ dev->tx_timeout = &ace_watchdog;
+ dev->watchdog_timeo = 5*HZ;
+ }
+ dev->stop = &ace_close;
+ dev->get_stats = &ace_get_stats;
+ dev->set_multicast_list = &ace_set_multicast_list;
+ dev->do_ioctl = &ace_ioctl;
+ dev->set_mac_address = &ace_set_mac_addr;
+ dev->change_mtu = &ace_change_mtu;
- pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
+ /* display version info if adapter is found */
+ if (!version_disp)
+ {
+ /* set display flag to TRUE so that */
+ /* we only display this string ONCE */
+ version_disp = 1;
+ printk(version);
+ }
- /* OpenFirmware on Mac's does not set this - DOH.. */
- if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
- printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
- "access - was not enabled by BIOS/Firmware\n",
- dev->name);
- ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
- pci_write_config_word(ap->pdev, PCI_COMMAND,
- ap->pci_command);
- wmb();
- }
+ /*
+ * Enable master mode before we start playing with the
+ * pci_command word since pci_set_master() will modify
+ * it.
+ */
+ pci_set_master(pdev);
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
- &ap->pci_latency);
- if (ap->pci_latency <= 0x40) {
- ap->pci_latency = 0x40;
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
- ap->pci_latency);
- }
+ pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
- /*
- * Remap the regs into kernel space - this is abuse of
- * dev->base_addr since it was means for I/O port
- * addresses but who gives a damn.
- */
- dev->base_addr = pci_resource_start(pdev, 0);
- ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
- if (!ap->regs) {
- printk(KERN_ERR "%s: Unable to map I/O register, "
- "AceNIC %i will be disabled.\n",
- dev->name, boards_found);
- break;
- }
+ /* OpenFirmware on Mac's does not set this - DOH.. */
+ if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
+ printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
+ "access - was not enabled by BIOS/Firmware\n",
+ dev->name);
+ ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
+ pci_write_config_word(ap->pdev, PCI_COMMAND,
+ ap->pci_command);
+ wmb();
+ }
- switch(pdev->vendor) {
- case PCI_VENDOR_ID_ALTEON:
- strncpy(ap->name, "AceNIC Gigabit Ethernet",
- sizeof (ap->name));
- printk(KERN_INFO "%s: Alteon AceNIC ", dev->name);
- break;
- case PCI_VENDOR_ID_3COM:
- strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
- sizeof (ap->name));
- printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
- break;
- case PCI_VENDOR_ID_NETGEAR:
- strncpy(ap->name, "NetGear GA620 Gigabit Ethernet",
- sizeof (ap->name));
- printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
- break;
- case PCI_VENDOR_ID_DEC:
- if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
- strncpy(ap->name, "Farallon PN9000-SX "
- "Gigabit Ethernet", sizeof (ap->name));
- printk(KERN_INFO "%s: Farallon PN9000-SX ",
- dev->name);
- break;
- }
- case PCI_VENDOR_ID_SGI:
- strncpy(ap->name, "SGI AceNIC Gigabit Ethernet",
- sizeof (ap->name));
- printk(KERN_INFO "%s: SGI AceNIC ", dev->name);
- break;
- default:
- strncpy(ap->name, "Unknown AceNIC based Gigabit "
- "Ethernet", sizeof (ap->name));
- printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
+ &ap->pci_latency);
+ if (ap->pci_latency <= 0x40) {
+ ap->pci_latency = 0x40;
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
+ ap->pci_latency);
+ }
+
+ /*
+ * Remap the regs into kernel space - this is abuse of
+ * dev->base_addr since it was means for I/O port
+ * addresses but who gives a damn.
+ */
+ dev->base_addr = pci_resource_start(pdev, 0);
+ ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
+ if (!ap->regs) {
+ printk(KERN_ERR "%s: Unable to map I/O register, "
+ "AceNIC %i will be disabled.\n",
+ dev->name, boards_found);
+ return -ENODEV;
+ }
+
+ switch(pdev->vendor) {
+ case PCI_VENDOR_ID_ALTEON:
+ strncpy(ap->name, "AceNIC Gigabit Ethernet",
+ sizeof (ap->name));
+ printk(KERN_INFO "%s: Alteon AceNIC ", dev->name);
+ break;
+ case PCI_VENDOR_ID_3COM:
+ strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
+ sizeof (ap->name));
+ printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
+ break;
+ case PCI_VENDOR_ID_NETGEAR:
+ strncpy(ap->name, "NetGear GA620 Gigabit Ethernet",
+ sizeof (ap->name));
+ printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
+ break;
+ case PCI_VENDOR_ID_DEC:
+ if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
+ strncpy(ap->name, "Farallon PN9000-SX "
+ "Gigabit Ethernet", sizeof (ap->name));
+ printk(KERN_INFO "%s: Farallon PN9000-SX ",
+ dev->name);
break;
}
- ap->name [sizeof (ap->name) - 1] = '\0';
- printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
+ case PCI_VENDOR_ID_SGI:
+ strncpy(ap->name, "SGI AceNIC Gigabit Ethernet",
+ sizeof (ap->name));
+ printk(KERN_INFO "%s: SGI AceNIC ", dev->name);
+ break;
+ default:
+ strncpy(ap->name, "Unknown AceNIC based Gigabit "
+ "Ethernet", sizeof (ap->name));
+ printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
+ break;
+ }
+ ap->name [sizeof (ap->name) - 1] = '\0';
+ printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
#ifdef __sparc__
- printk("irq %s\n", __irq_itoa(dev->irq));
+ printk("irq %s\n", __irq_itoa(dev->irq));
#else
- printk("irq %i\n", dev->irq);
+ printk("irq %i\n", dev->irq);
#endif
#ifdef CONFIG_ACENIC_OMIT_TIGON_I
- if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
- printk(KERN_ERR "%s: Driver compiled without Tigon I"
- " support - NIC disabled\n", dev->name);
- ace_init_cleanup(dev);
- kfree(dev);
- continue;
- }
+ if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
+ printk(KERN_ERR "%s: Driver compiled without Tigon I"
+ " support - NIC disabled\n", dev->name);
+ ace_init_cleanup(dev);
+ kfree(dev);
+ return -ENODEV;
+ }
#endif
- if (ace_allocate_descriptors(dev)) {
- /*
- * ace_allocate_descriptors() calls
- * ace_init_cleanup() on error.
- */
- kfree(dev);
- continue;
- }
+ if (ace_allocate_descriptors(dev)) {
+ /*
+ * ace_allocate_descriptors() calls
+ * ace_init_cleanup() on error.
+ */
+ kfree(dev);
+ return -ENODEV;
+ }
#ifdef MODULE
- if (boards_found >= ACE_MAX_MOD_PARMS)
- ap->board_idx = BOARD_IDX_OVERFLOW;
- else
- ap->board_idx = boards_found;
+ if (boards_found >= ACE_MAX_MOD_PARMS)
+ ap->board_idx = BOARD_IDX_OVERFLOW;
+ else
+ ap->board_idx = boards_found;
#else
- ap->board_idx = BOARD_IDX_STATIC;
+ ap->board_idx = BOARD_IDX_STATIC;
#endif
- if (ace_init(dev)) {
- /*
- * ace_init() calls ace_init_cleanup() on error.
- */
- kfree(dev);
- continue;
- }
+ pdev->driver_data = dev;
- boards_found++;
+ if (ace_init(dev)) {
+ /*
+ * ace_init() calls ace_init_cleanup() on error.
+ */
+ kfree(dev);
+ return -ENODEV;
}
- /*
- * If we're at this point we're going through ace_probe() for
- * the first time. Return success (0) if we've initialized 1
- * or more boards. Otherwise, return failure (-ENODEV).
- */
-
- if (boards_found > 0)
- return 0;
- else
- return -ENODEV;
+ return 0;
}
@@ -759,136 +693,95 @@
MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
#endif
-
-static void __exit ace_module_cleanup(void)
+static void __devexit acenic_remove_one(struct pci_dev *pdev)
{
+ struct net_device *dev = pdev->driver_data;
struct ace_private *ap;
struct ace_regs *regs;
- struct net_device *next;
short i;
- while (root_dev) {
- ap = root_dev->priv;
- next = ap->next;
-
- regs = ap->regs;
+ ap = dev->priv;
+ regs = ap->regs;
- writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl);
- if (ap->version >= 2)
- writel(readl(®s->CpuBCtrl) | CPU_HALT,
- ®s->CpuBCtrl);
- /*
- * This clears any pending interrupts
- */
- writel(1, ®s->Mb0Lo);
+ writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl);
+ if (ap->version >= 2)
+ writel(readl(®s->CpuBCtrl) | CPU_HALT,
+ ®s->CpuBCtrl);
+ /*
+ * This clears any pending interrupts
+ */
+ writel(1, ®s->Mb0Lo);
- /*
- * Make sure no other CPUs are processing interrupts
- * on the card before the buffers are being released.
- * Otherwise one might experience some `interesting'
- * effects.
- *
- * Then release the RX buffers - jumbo buffers were
- * already released in ace_close().
- */
- synchronize_irq();
+ /*
+ * Make sure no other CPUs are processing interrupts
+ * on the card before the buffers are being released.
+ * Otherwise one might experience some `interesting'
+ * effects.
+ *
+ * Then release the RX buffers - jumbo buffers were
+ * already released in ace_close().
+ */
+ synchronize_irq();
- for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
- struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
+ for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
+ struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
- if (skb) {
+ if (skb) {
#ifndef DUMMY_PCI_UNMAP
- dma_addr_t mapping;
+ dma_addr_t mapping;
- mapping = ap->skb->rx_std_skbuff[i].mapping;
- pci_unmap_single(ap->pdev, mapping,
- ACE_STD_BUFSIZE - (2 + 16),
- PCI_DMA_FROMDEVICE);
+ mapping = ap->skb->rx_std_skbuff[i].mapping;
+ pci_unmap_single(ap->pdev, mapping,
+ ACE_STD_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
#endif
- ap->rx_std_ring[i].size = 0;
- ap->skb->rx_std_skbuff[i].skb = NULL;
- dev_kfree_skb(skb);
- }
+ ap->rx_std_ring[i].size = 0;
+ ap->skb->rx_std_skbuff[i].skb = NULL;
+ dev_kfree_skb(skb);
}
- if (ap->version >= 2) {
- for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
- struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
-
- if (skb) {
-#ifndef DUMMY_PCI_UNMAP
- dma_addr_t mapping;
+ }
+ if (ap->version >= 2) {
+ for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
+ struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
- mapping = ap->skb->rx_mini_skbuff[i].mapping;
- pci_unmap_single(ap->pdev, mapping,
- ACE_MINI_BUFSIZE - (2 + 16),
- PCI_DMA_FROMDEVICE);
-#endif
- ap->rx_mini_ring[i].size = 0;
- ap->skb->rx_mini_skbuff[i].skb = NULL;
- dev_kfree_skb(skb);
- }
- }
- }
- for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
- struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
if (skb) {
#ifndef DUMMY_PCI_UNMAP
dma_addr_t mapping;
- mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
+ mapping = ap->skb->rx_mini_skbuff[i].mapping;
pci_unmap_single(ap->pdev, mapping,
- ACE_JUMBO_BUFSIZE - (2 + 16),
+ ACE_MINI_BUFSIZE - (2 + 16),
PCI_DMA_FROMDEVICE);
#endif
-
- ap->rx_jumbo_ring[i].size = 0;
- ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+ ap->rx_mini_ring[i].size = 0;
+ ap->skb->rx_mini_skbuff[i].skb = NULL;
dev_kfree_skb(skb);
}
}
-
- ace_init_cleanup(root_dev);
- kfree(root_dev);
- root_dev = next;
}
-}
-
-
-int __init ace_module_init(void)
-{
- int status;
-
- root_dev = NULL;
+ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
+ struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
+ if (skb) {
+#ifndef DUMMY_PCI_UNMAP
+ dma_addr_t mapping;
-#ifdef NEW_NETINIT
- status = acenic_probe();
-#else
- status = acenic_probe(NULL);
+ mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
+ pci_unmap_single(ap->pdev, mapping,
+ ACE_JUMBO_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
#endif
- return status;
-}
+ ap->rx_jumbo_ring[i].size = 0;
+ ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+ dev_kfree_skb(skb);
+ }
+ }
-#if (LINUX_VERSION_CODE < 0x02032a)
-#ifdef MODULE
-int init_module(void)
-{
- return ace_module_init();
+ ace_init_cleanup(dev);
+ kfree(dev);
}
-
-void cleanup_module(void)
-{
- ace_module_cleanup();
-}
-#endif
-#else
-module_init(ace_module_init);
-module_exit(ace_module_cleanup);
-#endif
-
-
static void ace_free_descriptors(struct net_device *dev)
{
struct ace_private *ap = dev->priv;
@@ -1324,13 +1217,6 @@
goto init_error;
}
- /*
- * Register the device here to be able to catch allocated
- * interrupt handlers in case the firmware doesn't come up.
- */
- ap->next = root_dev;
- root_dev = dev;
-
#ifdef INDEX_DEBUG
spin_lock_init(&ap->debug_lock);
ap->last_tx = TX_RING_ENTRIES - 1;
@@ -2525,7 +2411,7 @@
#if defined(CONFIG_X86)
#define DMAADDR_OFFSET 0
typedef unsigned long long dmaaddr_high_t;
-#elif defined(CONFIG_PPC)
+#elif defined(CONFIG_PPC32)
#define DMAADDR_OFFSET PCI_DRAM_OFFSET
typedef unsigned long dmaaddr_high_t;
#endif
@@ -3338,3 +3224,45 @@
* compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c"
* End:
*/
+
+static struct pci_device_id acenic_pci_tbl[] __initdata = {
+ { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+ { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+ { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C985,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+ { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+ { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+ /*
+ * Farallon used the DEC vendor ID on their cards incorrectly.
+ */
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
+
+static struct pci_driver acenic_driver = {
+ name: "acenic",
+ id_table: acenic_pci_tbl,
+ probe: acenic_init_one,
+ remove: acenic_remove_one,
+};
+
+static int __init acenic_init_module(void)
+{
+ return pci_module_init(&acenic_driver);
+}
+
+static void __exit acenic_cleanup_module(void)
+{
+ pci_unregister_driver(&acenic_driver);
+}
+
+module_init(acenic_init_module);
+module_exit(acenic_cleanup_module);
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/net/acenic.h linuxppc64_2_4/drivers/net/acenic.h
--- linux-2.4.8-ac9/drivers/net/acenic.h Thu Jun 28 16:47:10 2001
+++ linuxppc64_2_4/drivers/net/acenic.h Wed Aug 22 08:27:45 2001
@@ -582,7 +582,7 @@
aceaddr stats2_ptr;
};
-#if defined(CONFIG_X86) || defined(CONFIG_PPC)
+#if defined(CONFIG_X86) || defined(CONFIG_PPC32)
/* Intel has null pci_unmap_single, no reasons to remember mapping. */
#define DUMMY_PCI_UNMAP
#endif
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/net/pcnet32.c linuxppc64_2_4/drivers/net/pcnet32.c
--- linux-2.4.8-ac9/drivers/net/pcnet32.c Thu Aug 23 09:17:27 2001
+++ linuxppc64_2_4/drivers/net/pcnet32.c Thu Aug 16 08:50:26 2001
@@ -294,7 +294,7 @@
static int pcnet32_probe_vlbus(int cards_found);
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
-static int pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *);
+static int pcnet32_probe1(unsigned long, unsigned int, int, int, struct pci_dev *);
static int pcnet32_open(struct net_device *);
static int pcnet32_init_ring(struct net_device *);
static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
@@ -317,7 +317,7 @@
const char *name;
u16 vendor_id, device_id, svid, sdid, flags;
int io_size;
- int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *);
+ int (*probe1) (unsigned long, unsigned int, int, int, struct pci_dev *);
};
@@ -440,7 +440,9 @@
static int __init pcnet32_probe_vlbus(int cards_found)
{
unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0;
+#ifndef __powerpc__
unsigned int irq_line = 0; // FIXME dev ? dev->irq : 0;
+#endif
int *port;
printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found);
@@ -508,7 +510,7 @@
* pdev will be NULL when called from pcnet32_probe_vlbus.
*/
static int __devinit
-pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev)
+pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, int card_idx, struct pci_dev *pdev)
{
struct pcnet32_private *lp;
struct resource *res;
@@ -527,12 +529,13 @@
pcnet32_dwio_reset(ioaddr);
pcnet32_wio_reset(ioaddr);
- /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */
- if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
- a = &pcnet32_wio;
+ /* Important to do the check for dwio mode first. */
+ if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+ a = &pcnet32_dwio;
} else {
- if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
- a = &pcnet32_dwio;
+ if (pcnet32_wio_read_csr(ioaddr, 0) == 4 &&
+ pcnet32_wio_check(ioaddr)) {
+ a = &pcnet32_wio;
} else
return -ENODEV;
}
@@ -643,19 +646,31 @@
for (i = 0; i < 6; i++) {
promaddr[i] = inb(ioaddr + i);
}
+ printk("csraddr: ");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", dev->dev_addr[i] );
+ printk("\npromaddr: ");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", promaddr[i] );
+ printk("\n");
if( memcmp( promaddr, dev->dev_addr, 6) )
- {
- printk(" warning PROM address does not match CSR address\n");
-#if defined(__i386__)
- printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name);
- memcpy(dev->dev_addr, promaddr, 6);
-#endif
- }
+ printk(" warning: PROM address does not match CSR address\n");
+ if( !is_valid_ether_addr(dev->dev_addr) ) {
+ printk("bad csr addr\n");
+ if (!is_valid_ether_addr(promaddr)) {
+ printk("bad promaddr\n");
+ /* if neither ethernet address is not valid, force to 00:00:00:00:00:00 */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i]=0;
+ }
+ else
+ {
+ printk(" warning: Using PROM address\n");
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i]=promaddr[i];
+ }
+ }
}
- /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
- if( !is_valid_ether_addr(dev->dev_addr) )
- for (i = 0; i < 6; i++)
- dev->dev_addr[i]=0;
for (i = 0; i < 6; i++)
printk(" %2.2x", dev->dev_addr[i] );
@@ -885,7 +900,7 @@
lp->init_block.filter[1] = 0x00000000;
if (pcnet32_init_ring(dev))
return -ENOMEM;
-
+
/* Re-initialize the PCNET32, and start it when done. */
lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) &0xffff);
lp->a.write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16);
@@ -967,7 +982,7 @@
}
skb_reserve (rx_skbuff, 2);
}
- lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE);
+ lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
lp->rx_ring[i].status = le16_to_cpu(0x8000);
@@ -1301,7 +1316,8 @@
skb_put (skb, pkt_len);
lp->rx_skbuff[entry] = newskb;
newskb->dev = dev;
- lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE);
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
+ lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
rx_in_place = 1;
} else
@@ -1387,7 +1403,7 @@
for (i = 0; i < RX_RING_SIZE; i++) {
lp->rx_ring[i].status = 0;
if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE);
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
dev_kfree_skb(lp->rx_skbuff[i]);
}
lp->rx_skbuff[i] = NULL;
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/net/veth-proc.c linuxppc64_2_4/drivers/net/veth-proc.c
--- linux-2.4.8-ac9/drivers/net/veth-proc.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/net/veth-proc.c Fri May 4 17:12:47 2001
@@ -0,0 +1,73 @@
+/* File veth-proc.c created by Kyle A. Lucke on Wed Oct 18 2000. */
+
+/* Change Activity: */
+/* End Change Activity */
+
+#ifndef _VETH_PROC_H
+#include
+#endif
+#ifndef _HVTYPES_H
+#include
+#endif
+#ifndef _HVLPCONFIG_H
+#include
+#endif
+#ifndef _VETH_H
+#include "veth.h"
+#endif
+
+
+static struct proc_dir_entry * veth_proc_root = NULL;
+
+void veth_proc_init(struct proc_dir_entry *iSeries_proc)
+{
+ long i=0;
+ HvLpIndex thisLp = HvLpConfig_getLpIndex();
+ u16 vlanMap = HvLpConfig_getVirtualLanIndexMap();
+ long vlanIndex = 0;
+
+
+ veth_proc_root = proc_mkdir("veth", iSeries_proc);
+ if (!veth_proc_root) return;
+
+ for (i=0; i < HvMaxArchitectedLps; ++i)
+ {
+ if (i != thisLp)
+ {
+ if (HvLpConfig_doLpsCommunicateOnVirtualLan(thisLp, i))
+ {
+ struct proc_dir_entry *ent;
+ char name[10] = "";
+ sprintf(name, "lp%ld", i);
+ ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root);
+ if (!ent) return;
+ ent->nlink = 1;
+ ent->data = (void *)i;
+ ent->read_proc = proc_veth_dump_connection;
+ ent->write_proc = NULL;
+ }
+ }
+ }
+
+ while (vlanMap != 0)
+ {
+ int bitOn = vlanMap & 0x8000;
+
+ if (bitOn)
+ {
+ struct proc_dir_entry *ent;
+ char name[10] = "";
+ sprintf(name, "veth%ld", vlanIndex);
+ ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root);
+ if (!ent) return;
+ ent->nlink = 1;
+ ent->data = (void *)vlanIndex;
+ ent->read_proc = proc_veth_dump_port;
+ ent->write_proc = NULL;
+ }
+
+ ++vlanIndex;
+ vlanMap = vlanMap << 1;
+ }
+}
+
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/net/veth.c linuxppc64_2_4/drivers/net/veth.c
--- linux-2.4.8-ac9/drivers/net/veth.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/net/veth.c Fri Aug 17 13:03:16 2001
@@ -0,0 +1,1720 @@
+/* File veth.c created by Kyle A. Lucke on Mon Aug 7 2000. */
+
+/**************************************************************************/
+/* */
+/* IBM eServer iSeries Virtual Ethernet Device Driver */
+/* Copyright (C) 2001 Kyle A. Lucke (klucke@raleigh.ibm.com), IBM Corp. */
+/* */
+/* 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. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 */
+/* USA */
+/* */
+/* This module contains the implementation of a virtual ethernet device */
+/* for use with iSeries LPAR Linux. It utilizes low-level message passing*/
+/* provided by the hypervisor to enable an ethernet-like network device */
+/* that can be used to enable inter-partition communications on the same */
+/* physical iSeries. */
+/* */
+/* The iSeries LPAR hypervisor has currently defined the ability for a */
+/* partition to communicate on up to 16 different virtual ethernets, all */
+/* dynamically configurable, at least for an OS/400 partition. The */
+/* dynamic nature is not supported for Linux yet. */
+/* */
+/* Each virtual ethernet a given Linux partition participates in will */
+/* cause a network device with the form vethXX to be created, where XX is */
+/* a decimal number from 0 to 15, corresponding to the virtual ethernet */
+/* the given netdevice talks on. This is slightly different from the */
+/* standard eth0, eth1, etc. way of naming network devices, but without */
+/* this little naming convention, it would not be as easy to configure */
+/* the tcpip interfaces to a given veth device, and if the partition */
+/* was configured to use a new virtual ethernet at some point, the devices*/
+/* would most likely get renumbered. */
+/* */
+/* This driver (and others like it on other partitions) is responsible */
+/* routing packets to and from other partitions. The MAC addresses used */
+/* by the virtual ethernets contain meaning, and should not be modified. */
+/* Doing so could disable the ability of your Linux partition to */
+/* communicate with the other OS/400 partitions on your physical iSeries. */
+/* Similarly, setting the MAC address to something other than the */
+/* "virtual burned-in" address is not allowed, for the same reason. */
+/* */
+/* Notes: */
+/* */
+/* 1. Although there is the capability to talk on multiple shared */
+/* ethernets to communicate to the same partition, each shared */
+/* ethernet to a given partition X will use a finite, shared amount */
+/* of hypervisor messages to do the communication. So having 2 shared */
+/* ethernets to the same remote partition DOES NOT double the */
+/* available bandwidth. Each of the 2 shared ethernets will share the */
+/* same bandwidth available to another. */
+/* */
+/* 2. It is allowed to have a virtual ethernet that does not communicate */
+/* with any other partition. It won't do anything, but it's allowed. */
+/* */
+/* 3. There is no "loopback" mode for a virtual ethernet device. If you */
+/* send a packet to your own mac address, it will just be dropped, you */
+/* won't get it on the receive side. Such a thing could be done, */
+/* but my default driver DOES NOT do so. */
+/* */
+/* 4. Multicast addressing is implemented via broadcasting the multicast */
+/* frames to other partitions. It is the responsibility of the */
+/* receiving partition to filter the addresses desired. */
+/* */
+/* 5. This module utilizes several different bottom half handlers for */
+/* non-high-use path function (setup, error handling, etc.). Multiple */
+/* bottom halves were used because only one would not keep up to the */
+/* much faster iSeries device drivers this Linux driver is talking to. */
+/* All hi-priority work (receiving frames, handling frame acks) is done*/
+/* in the interrupt handler for maximum performance. */
+/* */
+/* Tunable parameters: */
+/* */
+/* VethBuffersToAllocate: This compile time option defaults to 120. It can*/
+/* be safely changed to something greater or less than the default. It */
+/* controls how much memory Linux will allocate per remote partition it is*/
+/* communicating with. The user can play with this to see how it affects */
+/* performance, packets dropped, etc. Without trying to understand the */
+/* complete driver, it can be thought of as the maximum number of packets */
+/* outstanding to a remote partition at a time. */
+/* */
+/**************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef _VETH_H
+#include "veth.h"
+#endif
+#ifndef _HVLPCONFIG_H
+#include
+#endif
+#ifndef _VETH_PROC_H
+#include
+#endif
+#ifndef _HVTYPES_H
+#include
+#endif
+#ifndef _ISERIES_PROC_H
+#include
+#endif
+#include
+#include
+
+
+#define veth_printk(fmt, args...) \
+printk(KERN_INFO "%s: " fmt, __FILE__, ## args)
+
+#define veth_error_printk(fmt, args...) \
+printk(KERN_ERR "(%s:%3.3d) ERROR: " fmt, __FILE__, __LINE__ , ## args)
+
+static const char __initdata *version =
+"v0.9 02/15/2001 Kyle Lucke, klucke@raleigh.ibm.com, klucke@us.ibm.com\n";
+
+static int probed __initdata = 0;
+#define VethBuffersToAllocate 120
+
+static struct VethFabricMgr *mFabricMgr = NULL;
+static struct proc_dir_entry * veth_proc_root = NULL;
+
+DECLARE_MUTEX_LOCKED(VethProcSemaphore);
+
+static int veth_open(struct net_device *dev);
+static int veth_close(struct net_device *dev);
+static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static void veth_handleEvent(struct HvLpEvent *, struct pt_regs *);
+static void veth_handleAck(struct HvLpEvent *);
+static void veth_handleInt(struct HvLpEvent *);
+static void veth_openConnections(void);
+static void veth_openConnection(u8, int lockMe);
+static void veth_closeConnection(u8, int lockMe);
+static void veth_intFinishOpeningConnections(void *, int number);
+static void veth_finishOpeningConnections(void *);
+static void veth_finishOpeningConnectionsLocked(struct VethLpConnection *);
+static int veth_multicast_wanted(struct VethPort *port, u64 dest);
+static void veth_set_multicast_list(struct net_device *dev);
+
+static void veth_sendCap(struct VethLpConnection *);
+static void veth_sendMonitor(struct VethLpConnection *);
+static void veth_takeCap(struct VethLpConnection *, struct VethLpEvent *);
+static void veth_takeCapAck(struct VethLpConnection *, struct VethLpEvent *);
+static void veth_takeMonitorAck(struct VethLpConnection *, struct VethLpEvent *);
+static void veth_msgsInit(struct VethLpConnection *connection);
+static void veth_recycleMsg(struct VethLpConnection *, u16);
+static void veth_capBh(struct VethLpConnection *);
+static void veth_capAckBh(struct VethLpConnection *);
+static void veth_monitorAckBh(struct VethLpConnection *);
+static void veth_takeFrames(struct VethLpConnection *, struct VethLpEvent *);
+static void veth_pTransmit(struct sk_buff *skb, HvLpIndex remoteLp, struct net_device *dev);
+static struct net_device_stats *veth_get_stats(struct net_device *dev);
+static void veth_intFinishMsgsInit(void *, int);
+static void veth_finishMsgsInit(struct VethLpConnection *connection);
+static void veth_intFinishCapBh(void *, int);
+static void veth_finishCapBh(struct VethLpConnection *connection);
+static void veth_finishCapBhLocked(struct VethLpConnection *connection);
+static void veth_finishSendCap(struct VethLpConnection *connection);
+static void veth_timedAck(unsigned long connectionPtr);
+#ifdef MODULE
+static void veth_waitForEnd(void);
+#endif
+static void veth_failMe(struct VethLpConnection *connection);
+
+int __init veth_probe(void)
+{
+ struct net_device *dev= NULL;
+ struct VethPort *port = NULL;
+ int vlansFound = 0;
+ int displayVersion = 0;
+
+ u16 vlanMap = HvLpConfig_getVirtualLanIndexMap();
+ int vlanIndex = 0;
+
+ if (probed)
+ return -ENODEV;
+ probed = 1;
+
+ while (vlanMap != 0)
+ {
+ int bitOn = vlanMap & 0x8000;
+
+ if (bitOn)
+ {
+ vlansFound++;
+
+ dev = init_vethdev(NULL, sizeof(struct VethPort), vlanIndex);
+
+ if (dev == NULL) {
+ veth_error_printk("Unable to allocate net_device structure!\n");
+ break;
+ }
+
+ if (!dev->priv)
+ dev->priv = kmalloc(sizeof(struct VethPort), GFP_KERNEL);
+ if (!dev->priv) {
+ veth_error_printk("Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ veth_printk("Found an ethernet device %s (veth=%d) (addr=%p)\n", dev->name, vlanIndex, dev);
+ port = mFabricMgr->mPorts[vlanIndex] = (struct VethPort *)dev->priv;
+ memset(port, 0, sizeof(struct VethPort));
+ rwlock_init(&(port->mMcastGate));
+ mFabricMgr->mPorts[vlanIndex]->mDev = dev;
+
+ dev->dev_addr[0] = 0x02;
+ dev->dev_addr[1] = 0x01;
+ dev->dev_addr[2] = 0xFF;
+ dev->dev_addr[3] = vlanIndex;
+ dev->dev_addr[4] = 0xFF;
+ dev->dev_addr[5] = HvLpConfig_getLpIndex_outline();
+ dev->mtu = 9000;
+
+ memcpy(&(port->mMyAddress), dev->dev_addr, 6);
+
+ dev->open = &veth_open;
+ dev->hard_start_xmit = &veth_start_xmit;
+ dev->stop = &veth_close;
+ dev->get_stats = veth_get_stats;
+ dev->set_multicast_list = &veth_set_multicast_list;
+ dev->do_ioctl = &veth_ioctl;
+
+ /* display version info if adapter is found */
+ if (!displayVersion)
+ {
+ /* set display flag to TRUE so that */
+ /* we only display this string ONCE */
+ displayVersion = 1;
+ veth_printk("%s", version);
+ }
+
+ }
+
+ ++vlanIndex;
+ vlanMap = vlanMap << 1;
+ }
+
+ if (vlansFound > 0)
+ return 0;
+ else
+ return -ENODEV;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Kyle Lucke , ");
+MODULE_DESCRIPTION("iSeries Virtual ethernet driver");
+
+DECLARE_MUTEX_LOCKED(VethModuleBhDone);
+int VethModuleReopen = 1;
+
+void veth_proc_delete(struct proc_dir_entry *iSeries_proc)
+{
+ int i=0;
+ HvLpIndex thisLp = HvLpConfig_getLpIndex_outline();
+ u16 vlanMap = HvLpConfig_getVirtualLanIndexMap();
+ int vlanIndex = 0;
+
+ for (i=0; i < HvMaxArchitectedLps; ++i)
+ {
+ if (i != thisLp)
+ {
+ if (HvLpConfig_doLpsCommunicateOnVirtualLan(thisLp, i))
+ {
+ char name[10] = "";
+ sprintf(name, "lp%d", i);
+ remove_proc_entry(name, veth_proc_root);
+ }
+ }
+ }
+
+ while (vlanMap != 0)
+ {
+ int bitOn = vlanMap & 0x8000;
+
+ if (bitOn)
+ {
+ char name[10] = "";
+ sprintf(name, "veth%d", vlanIndex);
+ remove_proc_entry(name, veth_proc_root);
+ }
+
+ ++vlanIndex;
+ vlanMap = vlanMap << 1;
+ }
+
+ remove_proc_entry("veth", iSeries_proc);
+
+ up(&VethProcSemaphore);
+}
+
+void veth_waitForEnd(void)
+{
+ up(&VethModuleBhDone);
+}
+
+void __exit veth_module_cleanup(void)
+{
+ int i;
+ struct VethFabricMgr *myFm = mFabricMgr;
+ struct tq_struct myBottomHalf;
+ struct net_device *thisOne = NULL;
+
+ VethModuleReopen = 0;
+
+ for (i = 0; i < HvMaxArchitectedLps; ++i)
+ {
+ veth_closeConnection(i, 1);
+ }
+
+ myBottomHalf.routine = (void *)(void *)veth_waitForEnd;
+
+ queue_task(&myBottomHalf, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ down(&VethModuleBhDone);
+
+ HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
+
+ mb();
+ mFabricMgr = NULL;
+ mb();
+
+ down(&VethProcSemaphore);
+
+ iSeries_proc_callback(&veth_proc_delete);
+
+ down(&VethProcSemaphore);
+
+ for (i = 0; i < HvMaxArchitectedLps; ++i)
+ {
+ if (myFm->mConnection[i].mNumberAllocated + myFm->mConnection[i].mNumberRcvMsgs > 0)
+ {
+ mf_deallocateLpEvents(myFm->mConnection[i].mRemoteLp,
+ HvLpEvent_Type_VirtualLan,
+ myFm->mConnection[i].mNumberAllocated + myFm->mConnection[i].mNumberRcvMsgs,
+ NULL,
+ NULL);
+ }
+
+ if (myFm->mConnection[i].mMsgs != NULL)
+ {
+ kfree(myFm->mConnection[i].mMsgs);
+ }
+ }
+
+ for (i = 0; i < HvMaxArchitectedVirtualLans; ++i)
+ {
+ if (myFm->mPorts[i] != NULL)
+ {
+ thisOne = myFm->mPorts[i]->mDev;
+ myFm->mPorts[i] = NULL;
+
+ mb();
+
+ if (thisOne != NULL)
+ {
+ veth_printk("Unregistering %s (veth=%d)\n", thisOne->name, i);
+ unregister_netdev(thisOne);
+ }
+ }
+ }
+
+ kfree(myFm);
+}
+
+module_exit(veth_module_cleanup);
+#endif
+
+
+void veth_proc_init(struct proc_dir_entry *iSeries_proc)
+{
+ int i=0;
+ HvLpIndex thisLp = HvLpConfig_getLpIndex_outline();
+ u16 vlanMap = HvLpConfig_getVirtualLanIndexMap();
+ int vlanIndex = 0;
+
+
+ veth_proc_root = proc_mkdir("veth", iSeries_proc);
+ if (!veth_proc_root) return;
+
+ for (i=0; i < HvMaxArchitectedLps; ++i)
+ {
+ if (i != thisLp)
+ {
+ if (HvLpConfig_doLpsCommunicateOnVirtualLan(thisLp, i))
+ {
+ struct proc_dir_entry *ent;
+ char name[10] = "";
+ sprintf(name, "lpar%d", i);
+ ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root);
+ if (!ent) return;
+ ent->nlink = 1;
+ ent->data = (void *)i;
+ ent->read_proc = proc_veth_dump_connection;
+ ent->write_proc = NULL;
+ }
+ }
+ }
+
+ while (vlanMap != 0)
+ {
+ int bitOn = vlanMap & 0x8000;
+
+ if (bitOn)
+ {
+ struct proc_dir_entry *ent;
+ char name[10] = "";
+ sprintf(name, "veth%d", vlanIndex);
+ ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root);
+ if (!ent) return;
+ ent->nlink = 1;
+ ent->data = (void *)vlanIndex;
+ ent->read_proc = proc_veth_dump_port;
+ ent->write_proc = NULL;
+ }
+
+ ++vlanIndex;
+ vlanMap = vlanMap << 1;
+ }
+
+ up(&VethProcSemaphore);
+}
+
+int __init veth_module_init(void)
+{
+ int status;
+ int i;
+
+ mFabricMgr = kmalloc(sizeof(struct VethFabricMgr), GFP_KERNEL);
+ memset(mFabricMgr, 0, sizeof(struct VethFabricMgr));
+ veth_printk("Initializing veth module, fabric mgr (address=%p)\n", mFabricMgr);
+
+ mFabricMgr->mEyecatcher = 0x56455448464D4752ULL;
+ mFabricMgr->mThisLp = HvLpConfig_getLpIndex_outline();
+
+ for (i=0; i < HvMaxArchitectedLps; ++i)
+ {
+ mFabricMgr->mConnection[i].mEyecatcher = 0x564554484C50434EULL;
+ veth_failMe(mFabricMgr->mConnection+i);
+ spin_lock_init(&mFabricMgr->mConnection[i].mAckGate);
+ spin_lock_init(&mFabricMgr->mConnection[i].mStatusGate);
+ }
+
+ status = veth_probe();
+
+ if (status == 0)
+ {
+ veth_openConnections();
+ }
+
+ iSeries_proc_callback(&veth_proc_init);
+
+ return status;
+}
+
+module_init(veth_module_init);
+
+static void veth_failMe(struct VethLpConnection *connection)
+{
+ connection->mConnectionStatus.mSentCap = 0;
+ connection->mConnectionStatus.mCapAcked = 0;
+ connection->mConnectionStatus.mGotCap = 0;
+ connection->mConnectionStatus.mGotCapAcked = 0;
+ connection->mConnectionStatus.mSentMonitor = 0;
+ connection->mConnectionStatus.mFailed = 1;
+}
+
+static int veth_open(struct net_device *dev)
+{
+ struct VethPort *port = (struct VethPort *)dev->priv;
+
+ memset(&port->mStats, 0, sizeof(port->mStats));
+ MOD_INC_USE_COUNT;
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int veth_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static struct net_device_stats *veth_get_stats(struct net_device *dev)
+{
+ struct VethPort *port = (struct VethPort *)dev->priv;
+
+ return(&port->mStats);
+}
+
+
+static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned char *frame = skb->data;
+ HvLpIndex remoteLp = frame[5];
+ int i = 0;
+ int clone = 0;
+
+ if (mFabricMgr == NULL)
+ {
+ veth_error_printk("NULL fabric manager with active ports!\n");
+ netif_stop_queue(dev);
+ return 1;
+ }
+
+ mb();
+
+ if ((*frame & 0x01) != 0x01) /* broadcast or multicast */
+ {
+ if ((remoteLp != mFabricMgr->mThisLp) &&
+ (HvLpConfig_doLpsCommunicateOnVirtualLan(mFabricMgr->mThisLp, remoteLp)))
+ veth_pTransmit(skb, remoteLp, dev);
+ }
+ else
+ {
+ for (i=0; i < HvMaxArchitectedLps; ++i)
+ {
+ if (i != mFabricMgr->mThisLp)
+ {
+ if (clone)
+ skb = skb_clone(skb, GFP_ATOMIC);
+ else
+ clone = 1;
+
+ if (HvLpConfig_doLpsCommunicateOnVirtualLan(mFabricMgr->mThisLp, i))
+ {
+ /* the ack handles deleting the skb */
+ veth_pTransmit(skb, i, dev);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void veth_pTransmit(struct sk_buff *skb, HvLpIndex remoteLp, struct net_device *dev)
+{
+ struct VethLpConnection *connection = mFabricMgr->mConnection + remoteLp;
+ HvLpEvent_Rc returnCode;
+
+ if (connection->mConnectionStatus.mFailed != 1)
+ {
+ struct VethMsg *msg = NULL;
+ VETHSTACKPOP(&(connection->mMsgStack), msg);
+
+ if (msg != NULL)
+ {
+ if ((skb->len > 14) &&
+ (skb->len <= 9018))
+ {
+ dma_addr_t dma_addr = pci_map_single(NULL,
+ skb->data,
+ skb->len,
+ PCI_DMA_TODEVICE);
+
+ if (dma_addr != -1)
+ {
+ msg->mSkb = skb;
+ msg->mEvent.mSendData.mAddress[0] = dma_addr;
+ msg->mEvent.mSendData.mLength[0] = skb->len;
+ msg->mEvent.mSendData.mEofMask = 0xFFFFFFFFUL;
+
+ test_and_set_bit(0, &(msg->mInUse));
+
+ returnCode = HvCallEvent_signalLpEventFast(remoteLp,
+ HvLpEvent_Type_VirtualLan,
+ VethEventTypeFrames,
+ HvLpEvent_AckInd_NoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ connection->mSourceInst,
+ connection->mTargetInst,
+ msg->mIndex,
+ msg->mEvent.mFpData.mData1,
+ msg->mEvent.mFpData.mData2,
+ msg->mEvent.mFpData.mData3,
+ msg->mEvent.mFpData.mData4,
+ msg->mEvent.mFpData.mData5);
+ }
+ else
+ {
+ returnCode = -1; /* Bad return code */
+ }
+
+ if (returnCode != HvLpEvent_Rc_Good)
+ {
+ struct VethPort *port = (struct VethPort *)dev->priv;
+
+ if (msg->mEvent.mSendData.mAddress[0])
+ {
+ pci_unmap_single(NULL, dma_addr, skb->len, PCI_DMA_TODEVICE);
+ }
+
+ dev_kfree_skb_irq(skb);
+
+ msg->mSkb = NULL;
+ memset(&(msg->mEvent.mSendData), 0, sizeof(struct VethFramesData));
+ VETHSTACKPUSH(&(connection->mMsgStack), msg);
+ port->mStats.tx_dropped++;
+ }
+ else
+ {
+ struct VethPort *port = (struct VethPort *)dev->priv;
+ port->mStats.tx_packets++;
+ port->mStats.tx_bytes += skb->len;
+ }
+ }
+ }
+ else
+ {
+ struct VethPort *port = (struct VethPort *)dev->priv;
+ port->mStats.tx_dropped++;
+ }
+ }
+ else
+ {
+ struct VethPort *port = (struct VethPort *)dev->priv;
+ port->mStats.tx_dropped++;
+ }
+}
+
+static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+
+ return -EOPNOTSUPP;
+}
+
+static void veth_set_multicast_list(struct net_device *dev)
+{
+ char *addrs;
+ struct VethPort *port = (struct VethPort *)dev->priv;
+ u64 newAddress = 0;
+ unsigned long flags;
+
+ write_lock_irqsave(&port->mMcastGate, flags);
+
+ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
+ port->mPromiscuous = 1;
+ } else {
+ struct dev_mc_list *dmi = dev->mc_list;
+
+ if (dev->flags & IFF_ALLMULTI) {
+ port->mAllMcast = 1;
+ } else {
+ int i;
+ /* Update table */
+ port->mNumAddrs = 0;
+
+ for (i = 0; ((i < dev->mc_count) && (i < 12)); i++) { /* for each address in the list */
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+ if ((*addrs & 0x01) == 1) { /* multicast address? */
+ memcpy(&newAddress, addrs, 6);
+ newAddress &= 0xFFFFFFFFFFFF0000;
+
+ port->mMcasts[port->mNumAddrs] = newAddress;
+ mb();
+ port->mNumAddrs = port->mNumAddrs + 1;
+ }
+ }
+ }
+ }
+
+ write_unlock_irqrestore(&port->mMcastGate, flags);
+}
+
+
+static void veth_handleEvent(struct HvLpEvent *event, struct pt_regs *regs)
+{
+ if (event->xFlags.xFunction == HvLpEvent_Function_Ack)
+ {
+ veth_handleAck(event);
+ }
+ else if (event->xFlags.xFunction == HvLpEvent_Function_Int)
+ {
+ veth_handleInt(event);
+ }
+}
+
+static void veth_handleAck(struct HvLpEvent *event)
+{
+ struct VethLpConnection *connection = &(mFabricMgr->mConnection[event->xTargetLp]);
+ struct VethLpEvent *vethEvent = (struct VethLpEvent *)event;
+
+ switch(event->xSubtype)
+ {
+ case VethEventTypeCap:
+ {
+ veth_takeCapAck(connection, vethEvent);
+ break;
+ }
+ case VethEventTypeMonitor:
+ {
+ veth_takeMonitorAck(connection, vethEvent);
+ break;
+ }
+ default:
+ {
+ veth_error_printk("Unknown ack type %d from lpar %d\n", event->xSubtype, connection->mRemoteLp);
+ }
+ };
+}
+
+static void veth_handleInt(struct HvLpEvent *event)
+{
+ int i=0;
+ struct VethLpConnection *connection = &(mFabricMgr->mConnection[event->xSourceLp]);
+ struct VethLpEvent *vethEvent = (struct VethLpEvent *)event;
+
+ switch(event->xSubtype)
+ {
+ case VethEventTypeCap:
+ {
+ veth_takeCap(connection, vethEvent);
+ break;
+ }
+ case VethEventTypeMonitor:
+ {
+ /* do nothing... this'll hang out here til we're dead, and the hypervisor will return it for us. */
+ break;
+ }
+ case VethEventTypeFramesAck:
+ {
+ for (i=0; i < VethMaxFramesMsgsAcked; ++i)
+ {
+ u16 msg = vethEvent->mDerivedData.mFramesAckData.mToken[i];
+ veth_recycleMsg(connection, msg);
+ }
+ break;
+ }
+ case VethEventTypeFrames:
+ {
+ veth_takeFrames(connection, vethEvent);
+ break;
+ }
+ default:
+ {
+ veth_error_printk("Unknown interrupt type %d from lpar %d\n", event->xSubtype, connection->mRemoteLp);
+ }
+ };
+}
+
+static void veth_openConnections()
+{
+ int i=0;
+
+ HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan, &veth_handleEvent);
+
+ /* Now I need to run through the active lps and open connections to the ones I'm supposed to
+ open to. */
+
+ for (i=HvMaxArchitectedLps-1; i >=0; --i)
+ {
+ if (i != mFabricMgr->mThisLp)
+ {
+ if (HvLpConfig_doLpsCommunicateOnVirtualLan(mFabricMgr->mThisLp, i))
+ {
+ veth_openConnection(i, 1);
+ }
+ else
+ {
+ veth_closeConnection(i, 1);
+ }
+ }
+ }
+}
+
+static void veth_intFinishOpeningConnections(void *parm, int number)
+{
+ struct VethLpConnection *connection = (struct VethLpConnection *)parm;
+ connection->mAllocBhTq.data = parm;
+ connection->mNumberAllocated = number;
+ queue_task(&connection->mAllocBhTq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void veth_finishOpeningConnections(void *parm)
+{
+ unsigned long flags;
+ struct VethLpConnection *connection = (struct VethLpConnection *)parm;
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+ veth_finishOpeningConnectionsLocked(connection);
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_finishOpeningConnectionsLocked(struct VethLpConnection *connection)
+{
+ if (connection->mNumberAllocated >= 2)
+ {
+ connection->mConnectionStatus.mCapMonAlloced = 1;
+ veth_sendCap(connection);
+ }
+ else
+ {
+ veth_error_printk("Couldn't allocate base msgs for lpar %d, only got %d\n", connection->mRemoteLp, connection->mNumberAllocated);
+ veth_failMe(connection);
+ }
+}
+
+static void veth_openConnection(u8 remoteLp, int lockMe)
+{
+ unsigned long flags;
+ unsigned long flags2;
+ HvLpInstanceId source;
+ HvLpInstanceId target;
+ u64 i = 0;
+ struct VethLpConnection *connection = &(mFabricMgr->mConnection[remoteLp]);
+
+ memset(&connection->mCapBhTq, 0, sizeof(connection->mCapBhTq));
+ connection->mCapBhTq.routine = (void *)(void *)veth_capBh;
+
+ memset(&connection->mCapAckBhTq, 0, sizeof(connection->mCapAckBhTq));
+ connection->mCapAckBhTq.routine = (void *)(void *)veth_capAckBh;
+
+ memset(&connection->mMonitorAckBhTq, 0, sizeof(connection->mMonitorAckBhTq));
+ connection->mMonitorAckBhTq.routine = (void *)(void *)veth_monitorAckBh;
+
+ memset(&connection->mAllocBhTq, 0, sizeof(connection->mAllocBhTq));
+ connection->mAllocBhTq.routine = (void *)(void *)veth_finishOpeningConnections;
+
+ if (lockMe)
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+
+ connection->mRemoteLp = remoteLp;
+
+ spin_lock_irqsave(&connection->mAckGate, flags2);
+
+ memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData));
+ connection->mNumAcks = 0;
+
+ HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualLan);
+
+ /* clean up non-acked msgs */
+ for (i=0; i < connection->mNumMsgs; ++i)
+ {
+ veth_recycleMsg(connection, i);
+ }
+
+ connection->mConnectionStatus.mOpen = 1;
+
+ source = connection->mSourceInst = HvCallEvent_getSourceLpInstanceId(remoteLp, HvLpEvent_Type_VirtualLan);
+ target = connection->mTargetInst = HvCallEvent_getTargetLpInstanceId(remoteLp, HvLpEvent_Type_VirtualLan);
+
+ if (connection->mConnectionStatus.mCapMonAlloced != 1)
+ {
+ connection->mAllocBhTq.routine = (void *)(void *)veth_finishOpeningConnections;
+ mf_allocateLpEvents(remoteLp,
+ HvLpEvent_Type_VirtualLan,
+ sizeof(struct VethLpEvent),
+ 2,
+ &veth_intFinishOpeningConnections,
+ connection);
+ }
+ else
+ {
+ veth_finishOpeningConnectionsLocked(connection);
+ }
+
+ spin_unlock_irqrestore(&connection->mAckGate, flags2);
+
+ if (lockMe)
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_closeConnection(u8 remoteLp, int lockMe)
+{
+ struct VethLpConnection *connection = &(mFabricMgr->mConnection[remoteLp]);
+ unsigned long flags;
+ unsigned long flags2;
+ if (lockMe)
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+
+ del_timer(&connection->mAckTimer);
+
+ if (connection->mConnectionStatus.mOpen == 1)
+ {
+ HvCallEvent_closeLpEventPath(remoteLp, HvLpEvent_Type_VirtualLan);
+ connection->mConnectionStatus.mOpen = 0;
+ veth_failMe(connection);
+
+ /* reset ack data */
+ spin_lock_irqsave(&connection->mAckGate, flags2);
+
+ memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData));
+ connection->mNumAcks = 0;
+
+ spin_unlock_irqrestore(&connection->mAckGate, flags2);
+ }
+
+ if (lockMe)
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_msgsInit(struct VethLpConnection *connection)
+{
+ connection->mAllocBhTq.routine = (void *)(void *)veth_finishMsgsInit;
+ mf_allocateLpEvents(connection->mRemoteLp,
+ HvLpEvent_Type_VirtualLan,
+ sizeof(struct VethLpEvent),
+ connection->mMyCap.mUnionData.mFields.mNumberBuffers,
+ &veth_intFinishMsgsInit,
+ connection);
+}
+
+static void veth_intFinishMsgsInit(void *parm, int number)
+{
+ struct VethLpConnection *connection = (struct VethLpConnection *)parm;
+ connection->mAllocBhTq.data = parm;
+ connection->mNumberRcvMsgs = number;
+ queue_task(&connection->mAllocBhTq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void veth_intFinishCapBh(void *parm, int number)
+{
+ struct VethLpConnection *connection = (struct VethLpConnection *)parm;
+ connection->mAllocBhTq.data = parm;
+ if (number > 0)
+ connection->mNumberLpAcksAlloced += number;
+
+ queue_task(&connection->mAllocBhTq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void veth_finishMsgsInit(struct VethLpConnection *connection)
+{
+ int i=0;
+ unsigned int numberGotten = 0;
+ u64 amountOfHeapToGet = connection->mMyCap.mUnionData.mFields.mNumberBuffers * sizeof(struct VethMsg);
+ char *msgs = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+
+ if (connection->mNumberRcvMsgs >= connection->mMyCap.mUnionData.mFields.mNumberBuffers)
+ {
+ msgs = kmalloc(amountOfHeapToGet, GFP_ATOMIC);
+
+ connection->mMsgs = (struct VethMsg *)msgs;
+
+ if (msgs != NULL)
+ {
+ memset(msgs, 0, amountOfHeapToGet);
+
+ for (i=0; i < connection->mMyCap.mUnionData.mFields.mNumberBuffers; ++i)
+ {
+ connection->mMsgs[i].mIndex = i;
+ ++numberGotten;
+ VETHSTACKPUSH(&(connection->mMsgStack), (connection->mMsgs+i));
+ }
+ if (numberGotten > 0)
+ {
+ connection->mNumMsgs = numberGotten;
+ }
+ }
+ else
+ {
+ kfree(msgs);
+ connection->mMsgs = NULL;
+ }
+ }
+
+ connection->mMyCap.mUnionData.mFields.mNumberBuffers = connection->mNumMsgs;
+
+ if (connection->mNumMsgs < 10)
+ connection->mMyCap.mUnionData.mFields.mThreshold = 1;
+ else if (connection->mNumMsgs < 20)
+ connection->mMyCap.mUnionData.mFields.mThreshold = 4;
+ else if (connection->mNumMsgs < 40)
+ connection->mMyCap.mUnionData.mFields.mThreshold = 10;
+ else
+ connection->mMyCap.mUnionData.mFields.mThreshold = 20;
+
+ connection->mMyCap.mUnionData.mFields.mTimer = VethAckTimeoutUsec;
+
+ veth_finishSendCap(connection);
+
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_sendCap(struct VethLpConnection *connection)
+{
+ if (connection->mMsgs == NULL)
+ {
+ connection->mMyCap.mUnionData.mFields.mNumberBuffers = VethBuffersToAllocate;
+ veth_msgsInit(connection);
+ }
+ else
+ {
+ veth_finishSendCap(connection);
+ }
+}
+
+static void veth_finishSendCap(struct VethLpConnection *connection)
+{
+ HvLpEvent_Rc returnCode = HvCallEvent_signalLpEventFast(connection->mRemoteLp,
+ HvLpEvent_Type_VirtualLan,
+ VethEventTypeCap,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ connection->mSourceInst,
+ connection->mTargetInst,
+ 0,
+ connection->mMyCap.mUnionData.mNoFields.mReserved1,
+ connection->mMyCap.mUnionData.mNoFields.mReserved2,
+ connection->mMyCap.mUnionData.mNoFields.mReserved3,
+ connection->mMyCap.mUnionData.mNoFields.mReserved4,
+ connection->mMyCap.mUnionData.mNoFields.mReserved5);
+
+ if ((returnCode == HvLpEvent_Rc_PartitionDead) ||
+ (returnCode == HvLpEvent_Rc_PathClosed))
+ {
+ connection->mConnectionStatus.mSentCap = 0;
+ }
+ else if (returnCode != HvLpEvent_Rc_Good)
+ {
+ veth_error_printk("Couldn't send cap to lpar %d, rc %Lx\n", connection->mRemoteLp, returnCode);
+ veth_failMe(connection);
+ }
+ else
+ {
+ connection->mConnectionStatus.mSentCap = 1;
+ }
+}
+
+static void veth_takeCap(struct VethLpConnection *connection, struct VethLpEvent *event)
+{
+ if (!test_and_set_bit(0,&(connection->mCapBhPending)))
+ {
+ connection->mCapBhTq.data = connection;
+ memcpy(&connection->mCapEvent, event, sizeof(connection->mCapEvent));
+ queue_task(&connection->mCapBhTq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ else
+ {
+ veth_error_printk("Received a capabilities from lpar %d while already processing one\n", connection->mRemoteLp);
+ event->mBaseEvent.xRc = HvLpEvent_Rc_BufferNotAvailable;
+ HvCallEvent_ackLpEvent((struct HvLpEvent *)event);
+ }
+}
+
+static void veth_takeCapAck(struct VethLpConnection *connection, struct VethLpEvent *event)
+{
+ if (!test_and_set_bit(0,&(connection->mCapAckBhPending)))
+ {
+ connection->mCapAckBhTq.data = connection;
+ memcpy(&connection->mCapAckEvent, event, sizeof(connection->mCapAckEvent));
+ queue_task(&connection->mCapAckBhTq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ else
+ {
+ veth_error_printk("Received a capabilities ack from lpar %d while already processing one\n", connection->mRemoteLp);
+ }
+}
+
+static void veth_takeMonitorAck(struct VethLpConnection *connection, struct VethLpEvent *event)
+{
+ if (!test_and_set_bit(0,&(connection->mMonitorAckBhPending)))
+ {
+ connection->mMonitorAckBhTq.data = connection;
+ memcpy(&connection->mMonitorAckEvent, event, sizeof(connection->mMonitorAckEvent));
+ queue_task(&connection->mMonitorAckBhTq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ else
+ {
+ veth_error_printk("Received a monitor ack from lpar %d while already processing one\n", connection->mRemoteLp);
+ }
+}
+
+static void veth_recycleMsg(struct VethLpConnection *connection, u16 msg)
+{
+ if (msg < connection->mNumMsgs)
+ {
+ struct VethMsg *myMsg = connection->mMsgs + msg;
+ if (test_and_clear_bit(0, &(myMsg->mInUse)))
+ {
+ pci_unmap_single(NULL,
+ myMsg->mEvent.mSendData.mAddress[0],
+ myMsg->mEvent.mSendData.mLength[0],
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(myMsg->mSkb);
+
+ myMsg->mSkb = NULL;
+ memset(&(myMsg->mEvent.mSendData), 0, sizeof(struct VethFramesData));
+ VETHSTACKPUSH(&connection->mMsgStack, myMsg);
+ }
+ else
+ {
+ if (connection->mConnectionStatus.mOpen)
+ {
+ veth_error_printk("Received a frames ack for msg %d from lpar %d while not outstanding\n", msg, connection->mRemoteLp);
+ }
+ }
+ }
+}
+
+static void veth_capBh(struct VethLpConnection *connection)
+{
+ struct VethLpEvent *event = &connection->mCapEvent;
+ unsigned long flags;
+ struct VethCapData *remoteCap = &(connection->mRemoteCap);
+ u64 numAcks = 0;
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+ connection->mConnectionStatus.mGotCap = 1;
+
+ memcpy(remoteCap, &(event->mDerivedData.mCapabilitiesData), sizeof(connection->mRemoteCap));
+
+ if ((remoteCap->mUnionData.mFields.mNumberBuffers <= VethMaxFramesMsgs) &&
+ (remoteCap->mUnionData.mFields.mNumberBuffers != 0) &&
+ (remoteCap->mUnionData.mFields.mThreshold <= VethMaxFramesMsgsAcked) &&
+ (remoteCap->mUnionData.mFields.mThreshold != 0))
+ {
+ numAcks = (remoteCap->mUnionData.mFields.mNumberBuffers / remoteCap->mUnionData.mFields.mThreshold) + 1;
+
+ if (connection->mNumberLpAcksAlloced < numAcks)
+ {
+ numAcks = numAcks - connection->mNumberLpAcksAlloced;
+ connection->mAllocBhTq.routine = (void *)(void *)veth_finishCapBh;
+ mf_allocateLpEvents(connection->mRemoteLp,
+ HvLpEvent_Type_VirtualLan,
+ sizeof(struct VethLpEvent),
+ numAcks,
+ &veth_intFinishCapBh,
+ connection);
+ }
+ else
+ veth_finishCapBhLocked(connection);
+ }
+ else
+ {
+ veth_error_printk("Received incompatible capabilities from lpar %d\n", connection->mRemoteLp);
+ event->mBaseEvent.xRc = HvLpEvent_Rc_InvalidSubtypeData;
+ HvCallEvent_ackLpEvent((struct HvLpEvent *)event);
+ }
+
+ clear_bit(0,&(connection->mCapBhPending));
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_capAckBh(struct VethLpConnection *connection)
+{
+ struct VethLpEvent *event = &connection->mCapAckEvent;
+ unsigned long flags;
+
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+
+ if (event->mBaseEvent.xRc == HvLpEvent_Rc_Good)
+ {
+ connection->mConnectionStatus.mCapAcked = 1;
+
+ if ((connection->mConnectionStatus.mGotCap == 1) &&
+ (connection->mConnectionStatus.mGotCapAcked == 1))
+ {
+ if (connection->mConnectionStatus.mSentMonitor != 1)
+ veth_sendMonitor(connection);
+ }
+ }
+ else
+ {
+ veth_error_printk("Bad rc(%d) from lpar %d on capabilities\n", event->mBaseEvent.xRc, connection->mRemoteLp);
+ veth_failMe(connection);
+ }
+
+ clear_bit(0,&(connection->mCapAckBhPending));
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_monitorAckBh(struct VethLpConnection *connection)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+
+ veth_failMe(connection);
+
+ veth_printk("Monitor ack returned for lpar %d\n", connection->mRemoteLp);
+
+ if (connection->mConnectionStatus.mOpen)
+ {
+ veth_closeConnection(connection->mRemoteLp, 0);
+
+ udelay(100);
+
+ queue_task(&connection->mMonitorAckBhTq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ else
+ {
+#ifdef MODULE
+ if (VethModuleReopen)
+#endif
+ veth_openConnection(connection->mRemoteLp, 0);
+#ifdef MODULE
+ else
+ {
+ int i=0;
+
+ for (i=0; i < connection->mNumMsgs; ++i)
+ {
+ veth_recycleMsg(connection, i);
+ }
+ }
+#endif
+ clear_bit(0,&(connection->mMonitorAckBhPending));
+ }
+
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_takeFrames(struct VethLpConnection *connection, struct VethLpEvent *event)
+{
+ int i;
+ struct VethPort *port = NULL;
+
+ for (i=0; i < VethMaxFramesPerMsg; ++i)
+ {
+ u16 length = event->mDerivedData.mSendData.mLength[i];
+ u64 address = event->mDerivedData.mSendData.mAddress[i];
+ if ((address != 0) &&
+ (length <= 9018) &&
+ (length > 14))
+ {
+ struct sk_buff *skb = alloc_skb(event->mDerivedData.mSendData.mLength[i], GFP_ATOMIC);
+
+ if (skb != NULL)
+ {
+ dma_addr_t toAddress = -1;
+ HvLpDma_Rc returnCode = HvLpDma_Rc_Good;
+ toAddress = pci_map_single(NULL, skb->data,
+ length,
+ PCI_DMA_FROMDEVICE);
+
+ if (toAddress != -1)
+ {
+ returnCode = HvCallEvent_dmaSingle(HvLpEvent_Type_VirtualLan,
+ event->mBaseEvent.xSourceLp,
+ HvLpDma_Direction_RemoteToLocal,
+ connection->mSourceInst,
+ connection->mTargetInst,
+ HvLpDma_AddressType_TceIndex,
+ HvLpDma_AddressType_TceIndex,
+ toAddress,
+ address,
+ length);
+
+ if (returnCode == HvLpDma_Rc_Good)
+ {
+ HvLpVirtualLanIndex vlan = skb->data[9];
+ u64 dest = *((u64 *)skb->data) & 0xFFFFFFFFFFFF0000;
+ port = mFabricMgr->mPorts[vlan];
+
+ if (((vlan < HvMaxArchitectedVirtualLans) &&
+ (port != NULL)) &&
+ ((dest == port->mMyAddress) || /* it's for me */
+ (dest == 0xFFFFFFFFFFFF0000) || /* it's a broadcast */
+ (veth_multicast_wanted(port, dest)) || /* it's one of my multicasts */
+ (port->mPromiscuous == 1))) /* I'm promiscuous */
+ {
+ skb_put(skb, length);
+ skb->dev = mFabricMgr->mPorts[vlan]->mDev;
+ skb->protocol = eth_type_trans(skb, mFabricMgr->mPorts[vlan]->mDev);
+ skb->ip_summed = CHECKSUM_NONE;
+ netif_rx(skb); /* send it up */
+ port->mStats.rx_packets++;
+ port->mStats.rx_bytes += length;
+
+ }
+ else
+ {
+ dev_kfree_skb_irq(skb);
+ }
+ }
+ else
+ {
+ dev_kfree_skb_irq(skb);
+ }
+
+ pci_unmap_single(NULL,
+ toAddress,
+ length,
+ PCI_DMA_FROMDEVICE);
+ }
+ else
+ {
+ dev_kfree_skb_irq(skb);
+ }
+ }
+ }
+ }
+ /* Ack it */
+
+ {
+ unsigned long flags;
+ spin_lock_irqsave(&connection->mAckGate, flags);
+
+ if (connection->mNumAcks < VethMaxFramesMsgsAcked)
+ {
+ connection->mEventData.mAckData.mToken[connection->mNumAcks] = event->mBaseEvent.xCorrelationToken;
+ ++connection->mNumAcks;
+
+ if (connection->mNumAcks == connection->mRemoteCap.mUnionData.mFields.mThreshold)
+ {
+ HvLpEvent_Rc rc = HvCallEvent_signalLpEventFast(connection->mRemoteLp,
+ HvLpEvent_Type_VirtualLan,
+ VethEventTypeFramesAck,
+ HvLpEvent_AckInd_NoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ connection->mSourceInst,
+ connection->mTargetInst,
+ 0,
+ connection->mEventData.mFpData.mData1,
+ connection->mEventData.mFpData.mData2,
+ connection->mEventData.mFpData.mData3,
+ connection->mEventData.mFpData.mData4,
+ connection->mEventData.mFpData.mData5);
+
+ if (rc != HvLpEvent_Rc_Good)
+ {
+ veth_error_printk("Bad lp event return code(%Lx) acking frames from lpar %d\n", rc, connection->mRemoteLp);
+ }
+
+ connection->mNumAcks = 0;
+
+ memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData));
+ }
+
+ }
+
+ spin_unlock_irqrestore(&connection->mAckGate, flags);
+ }
+}
+
+static void veth_timedAck(unsigned long connectionPtr)
+{
+ unsigned long flags;
+ HvLpEvent_Rc rc;
+ struct VethLpConnection *connection = (struct VethLpConnection *) connectionPtr;
+ /* Ack all the events */
+ spin_lock_irqsave(&connection->mAckGate, flags);
+
+ if (connection->mNumAcks > 0)
+ {
+ rc = HvCallEvent_signalLpEventFast(connection->mRemoteLp,
+ HvLpEvent_Type_VirtualLan,
+ VethEventTypeFramesAck,
+ HvLpEvent_AckInd_NoAck,
+ HvLpEvent_AckType_ImmediateAck,
+ connection->mSourceInst,
+ connection->mTargetInst,
+ 0,
+ connection->mEventData.mFpData.mData1,
+ connection->mEventData.mFpData.mData2,
+ connection->mEventData.mFpData.mData3,
+ connection->mEventData.mFpData.mData4,
+ connection->mEventData.mFpData.mData5);
+
+ if (rc != HvLpEvent_Rc_Good)
+ {
+ veth_error_printk("Bad lp event return code(%Lx) acking frames from lpar %d!\n", rc, connection->mRemoteLp);
+ }
+
+ connection->mNumAcks = 0;
+
+ memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData));
+ }
+
+ spin_unlock_irqrestore(&connection->mAckGate, flags);
+
+ /* Reschedule the timer */
+ connection->mAckTimer.expires = jiffies + connection->mTimeout;
+ add_timer(&connection->mAckTimer);
+}
+
+static int veth_multicast_wanted(struct VethPort *port, u64 thatAddr)
+{
+ int returnParm = 0;
+ int i;
+ unsigned long flags;
+
+ if ((*((char *)&thatAddr) & 0x01) != 1)
+ return 0;
+
+ read_lock_irqsave(&port->mMcastGate, flags);
+ if (port->mAllMcast)
+ return 1;
+
+ for (i=0; i < port->mNumAddrs; ++i)
+ {
+ u64 thisAddr = port->mMcasts[i];
+
+ if (thisAddr == thatAddr)
+ {
+ returnParm = 1;
+ break;
+ }
+ }
+ read_unlock_irqrestore(&port->mMcastGate, flags);
+
+ return returnParm;
+}
+
+static void veth_sendMonitor(struct VethLpConnection *connection)
+{
+ HvLpEvent_Rc returnCode = HvCallEvent_signalLpEventFast(connection->mRemoteLp,
+ HvLpEvent_Type_VirtualLan,
+ VethEventTypeMonitor,
+ HvLpEvent_AckInd_DoAck,
+ HvLpEvent_AckType_DeferredAck,
+ connection->mSourceInst,
+ connection->mTargetInst,
+ 0, 0, 0, 0, 0, 0);
+
+ if (returnCode == HvLpEvent_Rc_Good)
+ {
+ connection->mConnectionStatus.mSentMonitor = 1;
+ connection->mConnectionStatus.mFailed = 0;
+
+ /* Start the ACK timer */
+ init_timer(&connection->mAckTimer);
+ connection->mAckTimer.function = veth_timedAck;
+ connection->mAckTimer.data = (unsigned long) connection;
+ connection->mAckTimer.expires = jiffies + connection->mTimeout;
+ add_timer(&connection->mAckTimer);
+
+ }
+ else
+ {
+ veth_error_printk("Monitor send to lpar %d failed with rc %Lx\n", connection->mRemoteLp, returnCode);
+ veth_failMe(connection);
+ }
+}
+
+static void veth_finishCapBh(struct VethLpConnection *connection)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&connection->mStatusGate, flags);
+ veth_finishCapBhLocked(connection);
+ spin_unlock_irqrestore(&connection->mStatusGate, flags);
+}
+
+static void veth_finishCapBhLocked(struct VethLpConnection *connection)
+{
+ struct VethLpEvent *event = &connection->mCapEvent;
+ struct VethCapData *remoteCap = &(connection->mRemoteCap);
+ int numAcks = (remoteCap->mUnionData.mFields.mNumberBuffers / remoteCap->mUnionData.mFields.mThreshold) + 1;
+
+ /* Convert timer to jiffies */
+ if (connection->mMyCap.mUnionData.mFields.mTimer)
+ connection->mTimeout = remoteCap->mUnionData.mFields.mTimer * HZ / 1000000;
+ else
+ connection->mTimeout = VethAckTimeoutUsec * HZ / 1000000;
+
+ if (connection->mNumberLpAcksAlloced >= numAcks)
+ {
+ HvLpEvent_Rc returnCode = HvCallEvent_ackLpEvent((struct HvLpEvent *)event);
+
+ if (returnCode == HvLpEvent_Rc_Good)
+ {
+ connection->mConnectionStatus.mGotCapAcked = 1;
+
+ if (connection->mConnectionStatus.mSentCap != 1)
+ {
+ connection->mTargetInst = HvCallEvent_getTargetLpInstanceId(connection->mRemoteLp, HvLpEvent_Type_VirtualLan);
+
+ veth_sendCap(connection);
+ }
+ else if (connection->mConnectionStatus.mCapAcked == 1)
+ {
+ if (connection->mConnectionStatus.mSentMonitor != 1)
+ veth_sendMonitor(connection);
+ }
+ }
+ else
+ {
+ veth_error_printk("Failed to ack remote cap for lpar %d with rc %Lx\n", connection->mRemoteLp, returnCode);
+ veth_failMe(connection);
+ }
+ }
+ else
+ {
+ veth_error_printk("Couldn't allocate all the frames ack events for lpar %d\n", connection->mRemoteLp);
+ event->mBaseEvent.xRc = HvLpEvent_Rc_BufferNotAvailable;
+ HvCallEvent_ackLpEvent((struct HvLpEvent *)event);
+ }
+}
+
+int proc_veth_dump_connection
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ char *out = page;
+ int whichConnection = (int) data;
+ int len = 0;
+ struct VethLpConnection *connection = NULL;
+
+ if ((whichConnection < 0) || (whichConnection > HvMaxArchitectedLps) || (mFabricMgr == NULL))
+ {
+ veth_error_printk("Got bad data from /proc file system\n");
+ len = sprintf(page, "ERROR\n");
+ }
+ else
+ {
+ int thereWasStuffBefore = 0;
+ connection = &(mFabricMgr->mConnection[whichConnection]);
+
+ out += sprintf(out, "Remote Lp:\t%d\n", connection->mRemoteLp);
+ out += sprintf(out, "Source Inst:\t%04X\n", connection->mSourceInst);
+ out += sprintf(out, "Target Inst:\t%04X\n", connection->mTargetInst);
+ out += sprintf(out, "Num Msgs:\t%d\n", connection->mNumMsgs);
+ out += sprintf(out, "Num Lp Acks:\t%d\n", connection->mNumberLpAcksAlloced);
+ out += sprintf(out, "Num Acks:\t%d\n", connection->mNumAcks);
+
+ if (connection->mConnectionStatus.mOpen)
+ {
+ out += sprintf(out, "mConnectionStatus.mCapMonAlloced)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "CapMonAlloced");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mBaseMsgsAlloced)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "BaseMsgsAlloced");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mSentCap)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "SentCap");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mCapAcked)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "CapAcked");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mGotCap)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "GotCap");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mGotCapAcked)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "GotCapAcked");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mSentMonitor)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "SentMonitor");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mPopulatedRings)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "PopulatedRings");
+ thereWasStuffBefore = 1;
+ }
+
+ if (connection->mConnectionStatus.mFailed)
+ {
+ if (thereWasStuffBefore)
+ out += sprintf(out,"/");
+ else
+ out += sprintf(out,"<");
+ out += sprintf(out, "Failed");
+ thereWasStuffBefore = 1;
+ }
+
+ if (thereWasStuffBefore)
+ out += sprintf(out, ">");
+
+ out += sprintf(out, "\n");
+
+ out += sprintf(out, "Capabilities (System:):\n");
+ out += sprintf(out, "\tLocal:<");
+ out += sprintf(out, "%d/%d/%d/%d>\n",
+ connection->mMyCap.mUnionData.mFields.mVersion,
+ connection->mMyCap.mUnionData.mFields.mNumberBuffers,
+ connection->mMyCap.mUnionData.mFields.mThreshold,
+ connection->mMyCap.mUnionData.mFields.mTimer);
+ out += sprintf(out, "\tRemote:<");
+ out += sprintf(out, "%d/%d/%d/%d>\n",
+ connection->mRemoteCap.mUnionData.mFields.mVersion,
+ connection->mRemoteCap.mUnionData.mFields.mNumberBuffers,
+ connection->mRemoteCap.mUnionData.mFields.mThreshold,
+ connection->mRemoteCap.mUnionData.mFields.mTimer);
+ len = out - page;
+ }
+ len -= off;
+ if (len < count) {
+ *eof = 1;
+ if (len <= 0)
+ return 0;
+ } else
+ len = count;
+ *start = page + off;
+ return len;
+}
+
+int proc_veth_dump_port
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ char *out = page;
+ int whichPort = (int) data;
+ int len = 0;
+ struct VethPort *port = NULL;
+
+ if ((whichPort < 0) || (whichPort > HvMaxArchitectedVirtualLans) || (mFabricMgr == NULL))
+ len = sprintf(page, "Virtual ethernet is not configured.\n");
+ else
+ {
+ int i=0;
+ u32 *myAddr;
+ u16 *myEndAddr;
+ port = mFabricMgr->mPorts[whichPort];
+
+ if (port != NULL)
+ {
+ myAddr = (u32 *)&(port->mMyAddress);
+ myEndAddr = (u16 *)(myAddr + 1);
+ out += sprintf(out, "Net device:\t%p\n", port->mDev);
+ out += sprintf(out, "Address:\t%08X%04X\n", myAddr[0], myEndAddr[0]);
+ out += sprintf(out, "Promiscuous:\t%d\n", port->mPromiscuous);
+ out += sprintf(out, "All multicast:\t%d\n", port->mAllMcast);
+ out += sprintf(out, "Number multicast:\t%d\n", port->mNumAddrs);
+
+ for (i=0; i < port->mNumAddrs; ++i)
+ {
+ u32 *multi = (u32 *)&(port->mMcasts[i]);
+ u16 *multiEnd = (u16 *)(multi + 1);
+ out += sprintf(out, " %08X%04X\n", multi[0], multiEnd[0]);
+ }
+ }
+ else
+ {
+ out += sprintf(page, "veth%d is not configured.\n", whichPort);
+ }
+
+ len = out - page;
+ }
+ len -= off;
+ if (len < count) {
+ *eof = 1;
+ if (len <= 0)
+ return 0;
+ } else
+ len = count;
+ *start = page + off;
+ return len;
+}
+
+
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/net/veth.h linuxppc64_2_4/drivers/net/veth.h
--- linux-2.4.8-ac9/drivers/net/veth.h Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/net/veth.h Fri May 4 17:12:47 2001
@@ -0,0 +1,255 @@
+/* File veth.h created by Kyle A. Lucke on Mon Aug 7 2000. */
+
+/* Change Activity: */
+/* End Change Activity */
+
+#ifndef _VETH_H
+#define _VETH_H
+
+#ifndef _HVTYPES_H
+#include
+#endif
+#ifndef _HVLPEVENT_H
+#include
+#endif
+#include
+
+#define VethEventNumTypes (4)
+#define VethEventTypeCap (0)
+#define VethEventTypeFrames (1)
+#define VethEventTypeMonitor (2)
+#define VethEventTypeFramesAck (3)
+
+#define VethMaxFramesMsgsAcked (20)
+#define VethMaxFramesMsgs (0xFFFF)
+#define VethMaxFramesPerMsg (6)
+#define VethAckTimeoutUsec (1000000)
+
+#define VETHSTACKTYPE(T) struct VethStack##T
+#define VETHSTACK(T) \
+VETHSTACKTYPE(T) \
+{ \
+struct T *head; \
+spinlock_t lock; \
+}
+#define VETHSTACKCTOR(s) do { (s)->head = NULL; spin_lock_init(&(s)->lock); } while(0)
+#define VETHSTACKPUSH(s, p) \
+do { \
+unsigned long flags; \
+spin_lock_irqsave(&(s)->lock,flags); \
+(p)->next = (s)->head; \
+(s)->head = (p); \
+spin_unlock_irqrestore(&(s)->lock, flags); \
+} while(0)
+
+#define VETHSTACKPOP(s,p) \
+do { \
+unsigned long flags; \
+spin_lock_irqsave(&(s)->lock,flags); \
+(p) = (s)->head; \
+if ((s)->head != NULL) \
+{ \
+(s)->head = (s)->head->next; \
+} \
+spin_unlock_irqrestore(&(s)->lock, flags); \
+} while(0)
+
+#define VETHQUEUE(T) \
+struct VethQueue##T \
+{ \
+T *head; \
+T *tail; \
+spinlock_t lock; \
+}
+#define VETHQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; spin_lock_init(&(q)->lock); } while(0)
+#define VETHQUEUEENQ(q, p) \
+do { \
+unsigned long flags; \
+spin_lock_irqsave(&(q)->lock,flags); \
+(p)->next = NULL; \
+if ((q)->head != NULL) \
+{ \
+(q)->head->next = (p); \
+(q)->head = (p); \
+} \
+else \
+{ \
+(q)->tail = (q)->head = (p); \
+} \
+spin_unlock_irqrestore(&(q)->lock, flags); \
+} while(0)
+
+#define VETHQUEUEDEQ(q,p) \
+do { \
+unsigned long flags; \
+spin_lock_irqsave(&(q)->lock,flags); \
+(p) = (q)->tail; \
+if ((p) != NULL) \
+{ \
+(q)->tail = (p)->next; \
+(p)->next = NULL; \
+} \
+if ((q)->tail == NULL) \
+(q)->head = NULL; \
+spin_unlock_irqrestore(&(q)->lock, flags); \
+} while(0)
+
+struct VethFramesData
+{
+ u32 mAddress[6];
+ u16 mLength[6];
+ u32 mEofMask;
+};
+
+struct VethFramesAckData
+{
+ u16 mToken[VethMaxFramesMsgsAcked];
+};
+
+struct VethCapData
+{
+ union
+ {
+ struct Fields
+ {
+ u8 mVersion;
+ u8 mReserved1;
+ u16 mNumberBuffers;
+ u16 mThreshold;
+ u16 mReserved2;
+ u32 mTimer;
+ u32 mReserved3;
+ u64 mReserved4;
+ u64 mReserved5;
+ u64 mReserved6;
+ } mFields;
+ struct NoFields
+ {
+ u64 mReserved1;
+ u64 mReserved2;
+ u64 mReserved3;
+ u64 mReserved4;
+ u64 mReserved5;
+ } mNoFields;
+ } mUnionData;
+};
+
+struct VethFastPathData
+{
+ u64 mData1;
+ u64 mData2;
+ u64 mData3;
+ u64 mData4;
+ u64 mData5;
+};
+
+struct VethLpEvent
+{
+ struct HvLpEvent mBaseEvent;
+ union {
+ struct VethFramesData mSendData;
+ struct VethCapData mCapabilitiesData;
+ struct VethFramesAckData mFramesAckData;
+ struct VethFastPathData mFastPathData;
+ } mDerivedData;
+
+};
+
+struct VethMsg
+{
+ struct VethMsg *next;
+ union {
+ struct VethFramesData mSendData;
+ struct VethFastPathData mFpData;
+ } mEvent;
+ int mIndex;
+ unsigned long mInUse;
+ struct sk_buff *mSkb;
+};
+
+
+struct VethControlBlock
+{
+ struct net_device *mDev;
+ struct VethControlBlock *mNext;
+ HvLpVirtualLanIndex mVlanId;
+};
+
+struct VethLpConnection
+{
+ u64 mEyecatcher;
+ HvLpIndex mRemoteLp;
+ HvLpInstanceId mSourceInst;
+ HvLpInstanceId mTargetInst;
+ u32 mNumMsgs;
+ struct VethMsg *mMsgs;
+ int mNumberRcvMsgs;
+ int mNumberLpAcksAlloced;
+ union
+ {
+ struct VethFramesAckData mAckData;
+ struct VethFastPathData mFpData;
+ } mEventData;
+ spinlock_t mAckGate;
+ u32 mNumAcks;
+ spinlock_t mStatusGate;
+ struct
+ {
+ u64 mOpen : 1;
+ u64 mCapMonAlloced : 1;
+ u64 mBaseMsgsAlloced : 1;
+ u64 mSentCap : 1;
+ u64 mCapAcked : 1;
+ u64 mGotCap : 1;
+ u64 mGotCapAcked : 1;
+ u64 mSentMonitor : 1;
+ u64 mPopulatedRings : 1;
+ u64 mReserved : 54;
+ u64 mFailed : 1;
+ } mConnectionStatus;
+ struct VethCapData mMyCap;
+ struct VethCapData mRemoteCap;
+ unsigned long mCapAckBhPending;
+ struct tq_struct mCapAckBhTq;
+ struct VethLpEvent mCapAckEvent;
+ unsigned long mCapBhPending;
+ struct tq_struct mCapBhTq;
+ struct VethLpEvent mCapEvent;
+ unsigned long mMonitorAckBhPending;
+ struct tq_struct mMonitorAckBhTq;
+ struct VethLpEvent mMonitorAckEvent;
+ unsigned long mAllocBhPending;
+ struct tq_struct mAllocBhTq;
+ int mNumberAllocated;
+ struct timer_list mAckTimer;
+ u32 mTimeout;
+ VETHSTACK(VethMsg) mMsgStack;
+};
+#define HVMAXARCHITECTEDVIRTUALLANS 16
+struct VethPort
+{
+ struct net_device *mDev;
+ struct net_device_stats mStats;
+ int mLock;
+ u64 mMyAddress;
+ int mPromiscuous;
+ int mAllMcast;
+ rwlock_t mMcastGate;
+ int mNumAddrs;
+ u64 mMcasts[12];
+};
+
+struct VethFabricMgr
+{
+ u64 mEyecatcher;
+ HvLpIndex mThisLp;
+ struct VethLpConnection mConnection[HVMAXARCHITECTEDLPS];
+ spinlock_t mPortListGate;
+ u64 mNumPorts;
+ struct VethPort *mPorts[HVMAXARCHITECTEDVIRTUALLANS];
+};
+
+int proc_veth_dump_connection(char *page, char **start, off_t off, int count, int *eof, void *data);
+int proc_veth_dump_port(char *page, char **start, off_t off, int count, int *eof, void *data);
+
+#endif /* _VETH_H */
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/pci/pci.c linuxppc64_2_4/drivers/pci/pci.c
--- linux-2.4.8-ac9/drivers/pci/pci.c Thu Aug 23 09:17:28 2001
+++ linuxppc64_2_4/drivers/pci/pci.c Thu Aug 23 10:25:19 2001
@@ -1,5 +1,5 @@
/*
- * $Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $
+ *
*
* PCI Bus Services, see include/linux/pci.h for further explanation.
*
@@ -876,6 +876,14 @@
u32 l, sz;
struct resource *res;
+ /************************************************************
+ * Check for architecture dependant call to read the BARs.
+ ************************************************************/
+ if( dev->bus->ops->pci_read_bases != NULL) {
+ dev->bus->ops->pci_read_bases(dev, howmany, rom);
+ return;
+ }
+
for(pos=0; posresource[pos];
@@ -1157,6 +1165,14 @@
static void pci_read_irq(struct pci_dev *dev)
{
unsigned char irq;
+
+ /************************************************************
+ * Check for architecture dependant call to read and set irg
+ ************************************************************/
+ if(dev->bus->ops->pci_read_irq != NULL) {
+ dev->bus->ops->pci_read_irq(dev);
+ return;
+ }
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
if (irq)
@@ -1178,7 +1194,17 @@
{
u32 class;
- sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ /* sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); */
+
+
+ /********************************************************************
+ * Prefix the bus number with the phb number for large(>256 bus) systems.
+ ********************************************************************/
+ sprintf(dev->slot_name, "%4x%02x:%02x.%1x",
+ ( (dev->bus->number>>8) &0xFF0000),
+ ( dev->bus->number&0x0000FF),
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+
sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
@@ -1225,6 +1251,14 @@
printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
dev->slot_name, class, dev->hdr_type);
dev->class = PCI_CLASS_NOT_DEFINED;
+ }
+
+
+ /*********************************************************************
+ * Give the architure code a chance to fix up/tweak the devices.
+ *********************************************************************/
+ if(dev->bus->ops->pci_fixup_registers != NULL) {
+ dev->bus->ops->pci_fixup_registers(dev);
}
/* We found a fine healthy device, go go go... */
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/scsi/osst.c linuxppc64_2_4/drivers/scsi/osst.c
--- linux-2.4.8-ac9/drivers/scsi/osst.c Thu Jul 19 23:18:15 2001
+++ linuxppc64_2_4/drivers/scsi/osst.c Fri Aug 10 13:09:19 2001
@@ -31,6 +31,7 @@
#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
+#include
#include
#include
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/scsi/scsi_scan.c linuxppc64_2_4/drivers/scsi/scsi_scan.c
--- linux-2.4.8-ac9/drivers/scsi/scsi_scan.c Thu Jul 5 13:28:17 2001
+++ linuxppc64_2_4/drivers/scsi/scsi_scan.c Tue Aug 14 14:55:53 2001
@@ -301,8 +301,9 @@
scsi_initialize_queue(SDpnt, shpnt);
SDpnt->request_queue.queuedata = (void *) SDpnt;
/* Make sure we have something that is valid for DMA purposes */
- scsi_result = ((!shpnt->unchecked_isa_dma)
- ? &scsi_result0[0] : kmalloc(512, GFP_DMA));
+
+ scsi_result = kmalloc(512, (shpnt->unchecked_isa_dma)?GFP_KERNEL:GFP_DMA);
+
}
if (scsi_result == NULL) {
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/scsi/sr_ioctl.c linuxppc64_2_4/drivers/scsi/sr_ioctl.c
--- linux-2.4.8-ac9/drivers/scsi/sr_ioctl.c Thu Aug 23 09:17:30 2001
+++ linuxppc64_2_4/drivers/scsi/sr_ioctl.c Mon Aug 20 16:07:10 2001
@@ -107,7 +107,6 @@
if (!scsi_block_when_processing_errors(SDev))
return -ENODEV;
-
scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength,
IOCTL_TIMEOUT, IOCTL_RETRIES);
@@ -334,7 +333,12 @@
{
u_char sr_cmd[10];
int result, target = MINOR(cdi->dev);
- unsigned char buffer[32];
+ unsigned char *buffer = scsi_malloc(512);
+
+ if (buffer == NULL) {
+ printk("SCSI DMA pool exhausted.");
+ return -ENOMEM;
+ }
memset(sr_cmd, 0, sizeof(sr_cmd));
@@ -407,6 +411,7 @@
return -EINVAL;
}
+ scsi_free(buffer, 512);
#if 0
if (result)
printk("DEBUG: sr_audio: result for ioctl %x: %x\n", cmd, result);
diff -uNr --exclude=CVS linux-2.4.8-ac9/drivers/video/offb.c linuxppc64_2_4/drivers/video/offb.c
--- linux-2.4.8-ac9/drivers/video/offb.c Thu Aug 23 09:17:34 2001
+++ linuxppc64_2_4/drivers/video/offb.c Wed Aug 1 15:55:58 2001
@@ -32,7 +32,9 @@
#endif
#include
#include
+#ifndef CONFIG_PPC64
#include
+#endif
#include