diff -uNr --exclude=CVS linux/Documentation/Configure.help linuxppc64_2_4/Documentation/Configure.help
--- linux/Documentation/Configure.help Mon Sep 10 14:37:36 2001
+++ linuxppc64_2_4/Documentation/Configure.help Mon Sep 10 11:06:35 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
@@ -19954,23 +19962,63 @@
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:
- .
+
AltiVec Kernel Support
CONFIG_ALTIVEC
@@ -20213,19 +20261,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
+ 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.
@@ -20233,8 +20295,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
@@ -22955,6 +23017,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/Documentation/cachetlb.txt linuxppc64_2_4/Documentation/cachetlb.txt
--- linux/Documentation/cachetlb.txt Sun Mar 25 20:14:20 2001
+++ linuxppc64_2_4/Documentation/cachetlb.txt Fri Sep 7 06:23:33 2001
@@ -260,8 +260,9 @@
Here is the new interface:
- void copy_user_page(void *to, void *from, unsigned long address)
- void clear_user_page(void *to, unsigned long address)
+ void copy_user_page(struct page *to, struct page *from,
+ unsigned long address)
+ void clear_user_page(struct page *to, unsigned long address)
These two routines store data in user anonymous or COW
pages. It allows a port to efficiently avoid D-cache alias
@@ -279,6 +280,11 @@
If D-cache aliasing is not an issue, these two routines may
simply call memcpy/memset directly and do nothing more.
+
+ There are default versions of these procedures supplied in
+ include/linux/highmem.h. If a port does not want to use the
+ default versions it should declare them and define the symbol
+ __HAVE_ARCH_USER_PAGE in include/asm/page.h.
void flush_dcache_page(struct page *page)
diff -uNr --exclude=CVS linux/MAINTAINERS linuxppc64_2_4/MAINTAINERS
--- linux/MAINTAINERS Mon Sep 10 14:37:37 2001
+++ linuxppc64_2_4/MAINTAINERS Mon Sep 10 11:06:34 2001
@@ -869,14 +869,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 DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks)
diff -uNr --exclude=CVS linux/Makefile linuxppc64_2_4/Makefile
--- linux/Makefile Mon Sep 10 14:37:37 2001
+++ linuxppc64_2_4/Makefile Mon Sep 10 11:06:34 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/arch/ppc64/Makefile linuxppc64_2_4/arch/ppc64/Makefile
--- linux/arch/ppc64/Makefile Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/Makefile Wed Aug 29 10:47:12 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)
diff -uNr --exclude=CVS linux/arch/ppc64/boot/main.c linuxppc64_2_4/arch/ppc64/boot/main.c
--- linux/arch/ppc64/boot/main.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/boot/main.c Wed Sep 5 13:56:40 2001
@@ -136,7 +136,7 @@
rec = (struct bi_record *)((unsigned long)rec + rec->size);
rec->tag = BI_MACHTYPE;
- rec->data[0] = _MACH_chrp;
+ rec->data[0] = _MACH_pSeries;
rec->data[1] = 1;
rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
rec = (struct bi_record *)((unsigned long)rec + rec->size);
diff -uNr --exclude=CVS linux/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig linuxppc64_2_4/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig
--- linux/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig Wed Sep 5 14:51:30 2001
@@ -0,0 +1,573 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_ALL_PPC=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_PPC_PSERIES is not set
+CONFIG_PPC_ISERIES=y
+CONFIG_SMP=y
+CONFIG_MSCHUNKS=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# General setup
+#
+# 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
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_ELF32=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_VIODASD=y
+CONFIG_VIODASD_IDE=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=64000
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+CONFIG_BLK_DEV_LVM=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_LARGE_TABLES=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# 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
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_OAKNET is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+CONFIG_VETH=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+CONFIG_CD_NO_IDESCSI=y
+# CONFIG_AZTCD is not set
+# CONFIG_GSCD is not set
+# CONFIG_SBPCD is not set
+# CONFIG_MCD is not set
+# CONFIG_MCDX is not set
+# CONFIG_OPTCD is not set
+# CONFIG_CM206 is not set
+# CONFIG_SJCD is not set
+# CONFIG_ISP16_CDI is not set
+# CONFIG_CDU31A is not set
+# CONFIG_CDU535 is not set
+CONFIG_VIOCD=y
+# CONFIG_VIOCD_AZTECH is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=1024
+CONFIG_VIOCONS=y
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+CONFIG_VIOTAPE=y
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_SONYPI is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# File systems
+#
+CONFIG_QUOTA=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_CMS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_FREEVXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=y
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# 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
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_NCP_FS=y
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# 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
+# 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_HPUSBSCSI is not set
+# 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
+# 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
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_ID75 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_PPCDBG is not set
diff -uNr --exclude=CVS linux/arch/ppc64/defconfig linuxppc64_2_4/arch/ppc64/defconfig
--- linux/arch/ppc64/defconfig Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/defconfig Fri Aug 31 15:48:52 2001
@@ -26,6 +26,9 @@
# Loadable module support
#
CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
#
# General setup
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/Makefile linuxppc64_2_4/arch/ppc64/kernel/Makefile
--- linux/arch/ppc64/kernel/Makefile Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/Makefile Mon Sep 10 14:27:51 2001
@@ -25,15 +25,16 @@
LparData.o udbg.o binfmt_elf32.o sys_ppc32.o sys32.o \
ioctl32.o ptrace32.o signal32.o open_pic.o xics.o \
pmc.o mf_proc.o proc_pmc.o proc_pcifr.o iSeries_setup.o \
- ItLpQueue.o hvCall.o mf.o viopath.o HvLpEvent.o \
+ ItLpQueue.o hvCall.o mf.o HvLpEvent.o \
iSeries_proc.o HvCall.o flight_recorder.o HvLpConfig.o
-obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_PCI) += pci.o pci_dn.o pci_dma.o
ifeq ($(CONFIG_PPC_ISERIES),y)
-obj-$(CONFIG_PCI) += iSeries_dma.o iSeries_rtc.o
-else
-obj-$(CONFIG_PCI) += pci_dma.o
+obj-$(CONFIG_PCI) += iSeries_rtc.o iSeries_pci.o iSeries_IoMmTable.o iSeries_irq.o XmPciLpEvent.o
+endif
+ifeq ($(CONFIG_PPC_PSERIES),y)
+obj-$(CONFIG_PCI) += pSeries_pci.o
endif
obj-$(CONFIG_KGDB) += ppc-stub.o
@@ -47,7 +48,7 @@
ifeq ($(CONFIG_ALL_PPC),y)
obj-y += prom.o lmb.o rtas.o rtas-eventscan.o rtas-proc.o chrp_setup.o \
- chrp_time.o pSeries_pci.o i8259.o
+ chrp_time.o i8259.o
endif
include $(TOPDIR)/Rules.make
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/XmPciLpEvent.c linuxppc64_2_4/arch/ppc64/kernel/XmPciLpEvent.c
--- linux/arch/ppc64/kernel/XmPciLpEvent.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/kernel/XmPciLpEvent.c Mon Aug 27 17:30:33 2001
@@ -0,0 +1,150 @@
+/*
+ * File XmPciLpEvent.h created by Wayne Holm on Mon Jan 15 2001.
+ *
+ * This module handles PCI interrupt events sent by the AS400 Hypervisor.
+*/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+enum XmPciLpEvent_Subtype {
+ XmPciLpEvent_BusCreated = 0, // PHB has been created
+ XmPciLpEvent_BusFailed = 1, // PHB has failed
+ XmPciLpEvent_BusRecovered = 12, // PHB has been recovered
+ XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed
+ XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered
+ XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt
+};
+
+struct XmPciLpEvent_BusInterrupt {
+ HvBusNumber busNumber;
+ HvSubBusNumber subBusNumber;
+};
+
+struct XmPciLpEvent_NodeInterrupt {
+ HvBusNumber busNumber;
+ HvSubBusNumber subBusNumber;
+ HvAgentId deviceId;
+};
+
+struct XmPciLpEvent {
+ struct HvLpEvent hvLpEvent;
+
+ union {
+ u64 alignData; // Align on an 8-byte boundary
+
+ struct {
+ u32 fisr;
+ HvBusNumber busNumber;
+ HvSubBusNumber subBusNumber;
+ HvAgentId deviceId;
+ } slotInterrupt;
+
+ struct XmPciLpEvent_BusInterrupt busFailed;
+ struct XmPciLpEvent_BusInterrupt busRecovered;
+ struct XmPciLpEvent_BusInterrupt busCreated;
+
+ struct XmPciLpEvent_NodeInterrupt nodeFailed;
+ struct XmPciLpEvent_NodeInterrupt nodeRecovered;
+
+ } eventData;
+
+};
+
+static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm);
+
+static void XmPciLpEvent_handler( struct HvLpEvent* eventParm, struct pt_regs* regsParm) {
+ if (eventParm && eventParm->xType == HvLpEvent_Type_PciIo) {
+ switch( eventParm->xFlags.xFunction ) {
+ case HvLpEvent_Function_Int:
+ intReceived( (struct XmPciLpEvent*)eventParm, regsParm );
+ break;
+ case HvLpEvent_Function_Ack:
+ printk(KERN_ERR "XmPciLpEvent.c: unexpected ack received\n");
+ break;
+ default:
+ printk(KERN_ERR "XmPciLpEvent.c: unexpected event function %d\n",
+ (int)eventParm->xFlags.xFunction);
+ break;
+ };
+ }
+ else {
+ if (event) {
+ printk(KERN_ERR "XmPciLpEvent.c: unrecognized event type 0x%x\n",
+ (int)eventParm->xType);
+ }
+ else {
+ printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n");
+ }
+ }
+}
+
+static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm) {
+ int irq;
+
+ switch (eventParm->hvLpEvent.xSubtype) {
+ case XmPciLpEvent_SlotInterrupt:
+ irq = eventParm->hvLpEvent.xCorrelationToken;
+ /* Dispatch the interrupt handlers for this irq */
+ ppc_irq_dispatch_handler(regsParm, irq);
+ HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
+ eventParm->eventData.slotInterrupt.subBusNumber,
+ eventParm->eventData.slotInterrupt.deviceId);
+ break;
+ /* Ignore error recovery events for now */
+ case XmPciLpEvent_BusCreated:
+ printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", eventParm->eventData.busCreated.busNumber);
+ break;
+ case XmPciLpEvent_BusFailed:
+ printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", eventParm->eventData.busFailed.busNumber);
+ break;
+ case XmPciLpEvent_BusRecovered:
+ printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", eventParm->eventData.busRecovered.busNumber);
+ break;
+ case XmPciLpEvent_NodeFailed:
+ printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", eventParm->eventData.nodeFailed.busNumber, eventParm->eventData.nodeFailed.subBusNumber, eventParm->eventData.nodeFailed.deviceId);
+ break;
+ case XmPciLpEvent_NodeRecovered:
+ printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", eventParm->eventData.nodeRecovered.busNumber, eventParm->eventData.nodeRecovered.subBusNumber, eventParm->eventData.nodeRecovered.deviceId);
+ break;
+ default:
+ printk(KERN_ERR "XmPciLpEvent.c: unrecognized event subtype 0x%x\n",
+ eventParm->hvLpEvent.xSubtype);
+ break;
+ };
+}
+
+
+/* This should be called sometime prior to buswalk (init_IRQ would be good) */
+int XmPciLpEvent_init() {
+ int xRc;
+
+ xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, &XmPciLpEvent_handler);
+ if (xRc == 0) {
+ xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+ if (xRc != 0) {
+ printk(KERN_ERR "XmPciLpEvent.c: open event path failed with rc 0x%x\n", xRc);
+ }
+ }
+ else {
+ printk(KERN_ERR "XmPciLpEvent.c: register handler failed with rc 0x%x\n", xRc);
+ }
+
+ return xRc;
+}
+
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/chrp_setup.c linuxppc64_2_4/arch/ppc64/kernel/chrp_setup.c
--- linux/arch/ppc64/kernel/chrp_setup.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/chrp_setup.c Wed Sep 5 13:56:40 2001
@@ -83,7 +83,6 @@
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
-extern int pckbd_rate(struct kbd_repeat *rep);
extern void pckbd_init_hw(void);
extern unsigned char pckbd_sysrq_xlate[128];
extern void openpic_init_IRQ(void);
@@ -100,8 +99,6 @@
extern int probingmem;
extern unsigned long loops_per_jiffy;
-extern void *comport1;
-
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
@@ -254,6 +251,41 @@
ppc_md.progress(UTS_RELEASE, 0x7777);
}
+
+/* Early initialization. Relocation is on but do not reference unbolted pages */
+void __init pSeries_init_early(void)
+{
+ void *comport;
+
+ htpe_init_pSeries();
+ tce_init_pSeries();
+
+#ifdef CONFIG_VT
+ ppc_md.kbd_setkeycode = pckbd_setkeycode;
+ ppc_md.kbd_getkeycode = pckbd_getkeycode;
+ ppc_md.kbd_translate = pckbd_translate;
+ ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+ ppc_md.kbd_leds = pckbd_leds;
+ ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x63; /* Print Screen */
+#endif
+#endif
+
+#ifdef CONFIG_SMP
+ smp_init_pSeries();
+#endif
+
+ /* Map the uart for udbg. */
+ comport = (void *)ioremap(naca->serialPortAddr, 16);
+ udbg_init_uart(comport);
+
+ ppc_md.udbg_putc = udbg_putc;
+ ppc_md.udbg_getc = udbg_getc;
+ ppc_md.udbg_getc_poll = udbg_getc_poll;
+}
+
void __init
chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
@@ -267,8 +299,6 @@
}
#endif /* CONFIG_BLK_DEV_INITRD */
- /* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */
-
ppc_md.ppc_machine = _machine;
ppc_md.setup_arch = chrp_setup_arch;
@@ -303,20 +333,6 @@
ppc_md.get_rtc_time = chrp_get_rtc_time;
ppc_md.calibrate_decr = chrp_calibrate_decr;
-#ifdef CONFIG_VT
- ppc_md.kbd_setkeycode = pckbd_setkeycode;
- ppc_md.kbd_getkeycode = pckbd_getkeycode;
- ppc_md.kbd_translate = pckbd_translate;
- ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
- ppc_md.kbd_leds = pckbd_leds;
- ppc_md.kbd_init_hw = pckbd_init_hw;
- ppc_md.kbd_rate = pckbd_rate;
-#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
- SYSRQ_KEY = 0x63; /* Print Screen */
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_VT */
-
ppc_md.progress = chrp_progress;
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
@@ -332,6 +348,7 @@
ppc_ide_md.io_base = _IO_BASE;
#endif
+
ppc_md.progress("Linux ppc64\n", 0x0);
}
@@ -343,12 +360,12 @@
char *os;
static int max_width;
- if ( (_machine != _MACH_chrp) || !rtas.base )
- return;
-
if (hex)
udbg_printf(" %s\n", s);
+ if (!rtas.base || (_machine != _MACH_pSeries))
+ return;
+
if (max_width == 0) {
if ( (root = find_path_device("/rtas")) &&
(p = (unsigned int *)get_property(root,
@@ -385,10 +402,3 @@
while ( width-- > 0 )
call_rtas( "display-character", 1, 1, NULL, ' ' );
}
-
-void chrp_init_map_io_space(void)
-{
- /* naca->serialPortAddr is initialized earlier in prom.c */
- comport1 = (void *)ioremap(naca->serialPortAddr, PAGE_SIZE);
-}
-
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/head.S linuxppc64_2_4/arch/ppc64/kernel/head.S
--- linux/arch/ppc64/kernel/head.S Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/head.S Fri Sep 7 07:59:15 2001
@@ -47,6 +47,17 @@
*/
/*
+ * SPRG Usage
+ *
+ * Register Definition
+ *
+ * SPRG0 reserved for hypervisor
+ * SPRG1 temp - used to save gpr
+ * SPRG2 temp - used to save gpr
+ * SPRG3 virt addr of Paca
+ */
+
+/*
* Entering into this code we make the following assumptions:
* For pSeries:
* 1. The MMU is off & open firmware is running in real mode.
@@ -135,72 +146,112 @@
* This is the start of the interrupt handlers for Pseries
* This code runs with relocation off.
*/
+#define EXCEPTION_PROLOG_PSERIES(label) \
+ mtspr SPRG2,r20; /* use SPRG2 as scratch reg */ \
+ mtspr SPRG1,r21; /* save r21 */ \
+ mfspr r20,SPRG3; /* get Paca virt addr */ \
+ clrldi r20,r20,12; /* convert virt to real addr */ \
+ ld r21,PACAEXCSP(r20); /* get exception stack ptr */ \
+ addi r21,r21,-EXC_FRAME_SIZE; /* make exception frame */ \
+ std r21,PACAEXCSP(r20); /* update exception stack ptr */ \
+ clrldi r20,r21,12; /* convert virt to real addr */ \
+ std r22,32(r20); /* Save r22 in exc. frame */ \
+ std r23,40(r20); /* Save r23 in exc. frame */ \
+ mfspr r22,SRR0; /* EA of interrupted instr */ \
+ std r22,0(r20); /* Save SRR0 in exc. frame */ \
+ mfspr r23,SRR1; /* machine state at interrupt */ \
+ std r23,8(r20); /* Save SRR1 in exc. frame */ \
+ mfspr r22,SPRG2; \
+ std r22,16(r20); /* Save r20 in exc. frame */ \
+ mfspr r23,SPRG1; \
+ std r23,24(r20); /* Save r21 in exc. frame */ \
+ mfspr r20,SPRG3; /* get Paca virt addr again */ \
+ SET_REG_TO_LABEL(r22,label); /* Get addr to branch to */ \
+ mfmsr r23; \
+ rotldi r23,r23,4; \
+ ori r23,r23,0x32B; /* Set IR, DR, RI, SF, ISF, HV*/ \
+ rotldi r23,r23,60; /* for generic handlers */ \
+ mtspr SRR0,r22; \
+ mtspr SRR1,r23; \
+ mfcr r23; /* save CR in r23 */ \
+ rfid
-#define EXCEPTION_PROLOG_PSERIES(label) \
- mtspr SPRG2,r20; /* use SPRG2 as scratch reg */ \
- mfspr r20,SPRG3; /* get Paca virt addr */ \
- clrldi r20,r20,12; /* convert virt to real addr */ \
- std r21,PACAR21(r20); /* Save GPR21 in Paca */ \
- mfspr r21,SRR0; /* EA of interrupted instr */ \
- std r21,LPPACA+LPPACASRR0(r20); /* Set SRR0 in ItLpPaca */ \
- mfspr r21,SRR1; /* machine state at interrupt */ \
- std r21,LPPACA+LPPACASRR1(r20); /* Set SRR1 in ItLpPaca */ \
- SET_REG_TO_LABEL(r21,label); /* Get addr to branch to */ \
- mtspr SRR0,r21; \
- li r20,0x5; /* Turn on 64b, 64bints */ \
- sldi r20,r20,61; \
- ori r20,r20,0x30; /* for generic handlers */ \
- mfmsr r21; /* Turn on IR & DR */ \
- or r21,r21,r20; /* for generic handlers */ \
- mtspr SRR1,r21; \
- rfid /* Jump to generic handlers */
/*
* This is the start of the interrupt handlers for i_series
* This code runs with relocation on.
*/
-
#define EXCEPTION_PROLOG_ISERIES \
- mtspr SPRG2,r20; /* use SPRG2 as scratch reg */\
- mfspr r20,SPRG3; /* get Paca */\
- std r21,PACAR21(r20) /* Save GPR21 in Paca */
-
-#define EXCEPTION_PROLOG_COMMON \
- mfspr r20,SPRG3; /* get Paca virt addr */ \
- std r22,PACAR22(r20); /* Save GPR22 in Paca */\
- mfcr r22; \
- ld r21,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */ \
- andi. r21,r21,MSR_PR; /* Set CR for later branch */ \
- beq+ 1f; \
- ld r21,PACAKSAVE(r20); /* exception stack to use */\
- b 2f; \
-1: \
- subi r21,r1,INT_FRAME_SIZE;/* alloc exc. frame */ \
-2: \
- std r22,_CCR(r21); /* save CR in stackframe */\
- ld r22,PACAR21(r20); /* Get GPR21 from Paca */\
- std r22,GPR21(r21); /* Save GPR21 in stackframe */\
- ld r22,PACAR22(r20); /* Get GPR22 from Paca */\
- std r22,GPR22(r21); /* Save GPR22 in stackframe */\
- std r23,GPR23(r21); /* Save GPR23 in stackframe */\
- mfspr r22,SPRG2; /* Get GPR20 from SPRG2 */\
- std r22,GPR20(r21); /* Save GPR20 in stackframe */\
- mflr r22; \
- std r22,_LINK(r21); \
- mfctr r22; \
- std r22,_CTR(r21); \
- mfspr r22,XER; \
- std r22,_XER(r21); \
- ld r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */\
- ld r23,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */\
- SAVE_8GPRS(0, r21); \
- SAVE_4GPRS(8, r21); \
- SAVE_2GPRS(12, r21); \
- ld r2,PACATOC(r20); \
- std r1,0(r21); \
- mr r1,r21
+ mtspr SPRG2,r20; /* use SPRG2 as scratch reg */\
+ mtspr SPRG1,r21; /* save r21 */\
+ mfspr r20,SPRG3; /* get Paca */\
+ ld r21,PACAEXCSP(r20); /* get exception stack ptr */\
+ addi r21,r21,-EXC_FRAME_SIZE; /* make exception frame */\
+ std r21,PACAEXCSP(r20); /* update exception stack ptr */\
+ std r22,32(r21); /* save r22 on exception frame */\
+ std r23,40(r21); /* Save r23 in exc. frame */\
+ ld r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */\
+ std r22,0(r21); /* save SRR0 in exc. frame */\
+ ld r23,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */\
+ std r23,8(r21); /* save SRR1 in exc. frame */\
+ mfspr r22,SPRG2; \
+ std r22,16(r21); /* Save r20 in exc. frame */\
+ mfspr r23,SPRG1; \
+ std r23,24(r21); /* Save r21 in exc. frame */\
+ mfcr r23; /* save CR in r23 */
+
+/*
+ * The common exception prolog is used for all except a few exceptions
+ * such as a segment miss on a kernel address. We have to be prepared
+ * to take another exception from the point where we first touch the
+ * kernel stack onwards.
+ *
+ * On entry r20 points to the paca and r21 points to the exception
+ * frame on entry, r23 contains the saved CR, and relocation is on.
+ */
+#define EXCEPTION_PROLOG_COMMON \
+ mfspr r22,DAR; /* Save DAR in exc. frame */ \
+ std r22,48(r21); \
+ mfspr r22,DSISR; /* Save DSISR in exc. frame */ \
+ std r22,56(r21); \
+ ld r22,8(r21); /* Get SRR1 from exc. frame */ \
+ andi. r22,r22,MSR_PR; /* Set CR for later branch */ \
+ mr r22,r1; /* Save r1 */ \
+ subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \
+ beq- 1f; \
+ ld r1,PACAKSAVE(r20); /* kernel stack to use */ \
+1: std r22,GPR1(r1); /* save r1 in stackframe */ \
+ std r22,0(r1); /* make stack chain pointer */ \
+ std r23,_CCR(r1); /* save CR in stackframe */ \
+ ld r22,16(r21); /* move r20 to stackframe */ \
+ std r22,GPR20(r1); \
+ ld r23,24(r21); /* move r21 to stackframe */ \
+ std r23,GPR21(r1); \
+ ld r22,32(r21); /* move r22 to stackframe */ \
+ std r22,GPR22(r1); \
+ ld r23,40(r21); /* move r23 to stackframe */ \
+ std r23,GPR23(r1); \
+ mflr r22; /* save LR in stackframe */ \
+ std r22,_LINK(r1); \
+ mfctr r23; /* save CTR in stackframe */ \
+ std r23,_CTR(r1); \
+ mfspr r22,XER; /* save XER in stackframe */ \
+ std r22,_XER(r1); \
+ ld r23,48(r21); /* move DAR to stackframe */ \
+ std r23,_DAR(r1); \
+ ld r22,56(r21); /* move DSISR to stackframe */ \
+ std r22,_DSISR(r1); \
+ ld r22,0(r21); /* get SRR0 from exc. frame */ \
+ ld r23,8(r21); /* get SRR1 from exc. frame */ \
+ addi r21,r21,EXC_FRAME_SIZE;/* pop off exception frame */ \
+ std r21,PACAEXCSP(r20); \
+ SAVE_GPR(0, r1); /* save r0 in stackframe */ \
+ SAVE_8GPRS(2, r1); /* save r2 - r13 in stackframe */ \
+ SAVE_4GPRS(10, r1); \
+ ld r2,PACATOC(r20)
+
/*
* Note: code which follows this uses cr0.eq (set if from kernel),
- * r21, r22 (SRR0), and r23 (SRR1).
+ * r1, r22 (SRR0), and r23 (SRR1).
*/
/*
@@ -225,9 +276,9 @@
addi r3,r1,STACK_FRAME_OVERHEAD; \
SET_REG_TO_CONST(r20, MSR_KERNEL); \
li r6,trap; \
- bl .transfer_to_handler; \
- .llong hdlr; \
- .llong .ret_from_except
+ bl .save_remaining_regs; \
+ bl hdlr; \
+ b .ret_from_except
/*
* Start of pSeries system interrupt routines
@@ -253,6 +304,7 @@
STD_EXCEPTION_PSERIES( 0xd00, SingleStep )
STD_EXCEPTION_PSERIES( 0xe00, Trap_0e )
STD_EXCEPTION_PSERIES( 0xf00, PerformanceMonitor )
+ STD_EXCEPTION_PSERIES( 0x1300, InstructionBreakpoint )
. = 0x4000
.globl __end_interupts
@@ -390,29 +442,51 @@
STD_EXCEPTION_COMMON( 0xd00, SingleStep, .SingleStepException )
STD_EXCEPTION_COMMON( 0xe00, Trap_0e, .UnknownException )
STD_EXCEPTION_COMMON( 0xf00, PerformanceMonitor, .PerformanceMonitorException )
+ STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .InstructionBreakpointException )
-/* r20 is in SPRG2,
- r21 is in the PACA
-*/
+/*
+ * Return from an exception which is handled without calling
+ * save_remaining_regs. The caller is assumed to have done
+ * EXCEPTION_PROLOG_COMMON.
+ */
+fast_exception_return:
+ ld r3,_CCR(r1)
+ ld r4,_LINK(r1)
+ ld r5,_CTR(r1)
+ ld r6,_XER(r1)
+ mtcr r3
+ mtlr r4
+ mtctr r5
+ mtspr XER,r6
+ REST_GPR(0, r1)
+ REST_8GPRS(2, r1)
+ REST_4GPRS(10, r1)
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_4GPRS(20, r1)
+ ld r1,GPR1(r1)
+ rfid
+
+
+/*
+ * Here r20 points to the PACA, r21 to the exception frame,
+ * r23 contains the saved CR.
+ * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
+ */
.globl DataAccess_common
DataAccess_common:
- mfcr r20
- mfspr r21,DAR
- srdi r21,r21,60
- cmpi 0,r21,0xc
- bne 3f
+ mfspr r22,DAR
+ srdi r22,r22,60
+ cmpi 0,r22,0xc
/* Segment faulted on a bolted segment. Go off and map that segment. */
- b .do_stab_bolted
+ beq .do_stab_bolted
-3: mtcr r20
EXCEPTION_PROLOG_COMMON
- mfspr r20,DSISR
- std r20,_DSISR(r21)
+ ld r20,_DSISR(r1)
andis. r0,r20,0xa450 /* weird error? */
bne 1f /* if not, try to put a PTE */
- mfspr r3,DAR /* into the hash table */
- std r3,_DAR(r21)
+ ld r3,_DAR(r1) /* into the hash table */
rlwinm r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
andis. r0,r20,0x0020 /* Is it a page table fault? */
@@ -423,60 +497,33 @@
2: bl .do_hash_page_DSI /* Try to handle as hpte fault */
1:
- ld r4,_DAR(r21)
- ld r5,_DSISR(r21)
+ ld r4,_DAR(r1)
+ ld r5,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
li r6,0x300
- bl .transfer_to_handler
- .llong .do_page_fault
- .llong .ret_from_except
+ bl .save_remaining_regs
+ bl .do_page_fault
+ b .ret_from_except
.globl DataAccessSLB_common
DataAccessSLB_common:
EXCEPTION_PROLOG_COMMON
- mfspr r3,DAR
+ ld r3,_DAR(r1)
li r4,0x380 /* Exception vector */
bl .ste_allocate
or. r3,r3,r3 /* Check return code */
- bne 1f /* Branch on failure */
-
- /* SLB Allocation success - Return. */
- ld r3,_CCR(r21)
- ld r4,_LINK(r21)
- ld r5,_CTR(r21)
- ld r6,_XER(r21)
-
- mtcrf 0xff,r3
- mtlr r4
- mtctr r5
- mtspr XER,r6
- REST_8GPRS(0,r21)
- REST_4GPRS(8,r21)
- REST_2GPRS(12,r21)
- mtspr SRR1,r23
- mtspr SRR0,r22
- ld r20,GPR20(r21)
- ld r22,GPR22(r21)
- ld r23,GPR23(r21)
- ld r21,GPR21(r21)
- RFID
-
-1:
- mfspr r4,DAR
- std r4,_DAR(r21)
- mfspr r5,DSISR
- std r5,_DSISR(r21)
+ beq fast_exception_return /* Return if we succeeded */
addi r3,r1,STACK_FRAME_OVERHEAD
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
li r6,0x380
- bl .transfer_to_handler
- .llong .do_page_fault
- .llong .ret_from_except
+ bl .save_remaining_regs
+ bl .do_page_fault
+ b .ret_from_except
.globl InstructionAccess_common
InstructionAccess_common:
@@ -500,9 +547,9 @@
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
li r6,0x400
- bl .transfer_to_handler
- .llong .do_page_fault
- .llong .ret_from_except
+ bl .save_remaining_regs
+ bl .do_page_fault
+ b .ret_from_except
.globl InstructionAccessSLB_common
InstructionAccessSLB_common:
@@ -511,42 +558,16 @@
li r4,0x480 /* Exception vector */
bl .ste_allocate
or. r3,r3,r3 /* Check return code */
- bne 1f /* Branch on failure */
-
- /* SLB Allocation success - Return. */
- ld r3,_CCR(r21)
- ld r4,_LINK(r21)
- ld r5,_CTR(r21)
- ld r6,_XER(r21)
-
- mtcrf 0xff,r3
- mtlr r4
- mtctr r5
- mtspr XER,r6
- REST_8GPRS(0,r21)
- REST_4GPRS(8,r21)
- REST_2GPRS(12,r21)
- mtspr SRR1,r23
- mtspr SRR0,r22
- ld r20,GPR20(r21)
- ld r22,GPR22(r21)
- ld r23,GPR23(r21)
- ld r21,GPR21(r21)
- RFID
+ beq fast_exception_return /* Return if we succeeded */
-1:
- mfspr r4,DAR
- std r4,_DAR(r21)
- mfspr r5,DSISR
- std r5,_DSISR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
li r6,0x380
- bl .transfer_to_handler
- .llong .do_page_fault
- .llong .ret_from_except
+ bl .save_remaining_regs
+ bl .do_page_fault
+ b .ret_from_except
.globl HardwareInterrupt_common
HardwareInterrupt_common:
@@ -555,24 +576,20 @@
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
+ bl .save_remaining_regs
+ bl .do_IRQ
+ b .ret_from_except
.globl Alignment_common
Alignment_common:
EXCEPTION_PROLOG_COMMON
- mfspr r4,DAR
- std r4,_DAR(r21)
- mfspr r5,DSISR
- std r5,_DSISR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
li r6,0x600
- bl .transfer_to_handler
- .llong .AlignmentException
- .llong .ret_from_except
+ bl .save_remaining_regs
+ bl .AlignmentException
+ b .ret_from_except
.globl ProgramCheck_common
ProgramCheck_common:
@@ -581,9 +598,9 @@
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
li r6,0x700
- bl .transfer_to_handler
- .llong .ProgramCheckException
- .llong .ret_from_except
+ bl .save_remaining_regs
+ bl .ProgramCheckException
+ b .ret_from_except
.globl FPUnavailable_common
FPUnavailable_common:
@@ -591,9 +608,9 @@
bne .load_up_fpu /* if from user, just load it up */
SET_REG_TO_CONST(r20, MSR_KERNEL)
li r6,0x800
- bl .transfer_to_handler /* if from kernel, take a trap */
- .llong .KernelFP
- .llong .ret_from_except
+ bl .save_remaining_regs /* if from kernel, take a trap */
+ bl .KernelFP
+ b .ret_from_except
.globl SystemCall_common
SystemCall_common:
@@ -605,13 +622,13 @@
beq+ HardwareInterrupt_entry
1:
#endif
- std r3,ORIG_GPR3(r21)
+ std r3,ORIG_GPR3(r1)
SET_REG_TO_CONST(r20, MSR_KERNEL)
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
li r6,0xC00
- bl .transfer_to_handler
- .llong .DoSyscall
- .llong .ret_from_except
+ bl .save_remaining_regs
+ bl .DoSyscall
+ b .ret_from_except
_GLOBAL(do_hash_page_ISI)
li r4,0
@@ -620,7 +637,7 @@
ori r4,r4,1 /* add _PAGE_PRESENT */
mflr r21 /* Save LR in r21 */
- /* r21 restored later from r1 */
+
/*
* r3 contains the faulting address
* r4 contains the required access permissions
@@ -629,58 +646,31 @@
*/
bl .hash_page /* build HPTE if possible */
- mtlr r21 /* restore LR */
- mr r21,r1 /* restore r21 */
or. r3,r3,r3 /* Check return code */
- bnelr /* Return to DSI or ISI on failure */
+ beq fast_exception_return /* Return from exception on success */
- /*
- * The HPTE has been created/updated. Restore and retry the faulting inst
- */
+ mtlr r21 /* restore LR */
+ blr /* Return to DSI or ISI on failure */
- ld r3,_CCR(r21)
- ld r4,_LINK(r21)
- ld r5,_CTR(r21)
- ld r6,_XER(r21)
- mtcrf 0xff,r3
- mtlr r4
- mtctr r5
- mtspr XER,r6
- REST_8GPRS(0,r21)
- REST_4GPRS(8,r21)
- REST_2GPRS(12,r21)
- mtspr SRR1,r23
- mtspr SRR0,r22
- ld r20,GPR20(r21)
- ld r22,GPR22(r21)
- ld r23,GPR23(r21)
- 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
-*/
+/*
+ * r20 points to the PACA, r21 to the exception frame,
+ * r23 contains the saved CR.
+ * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
+ * We assume we aren't going to take any exceptions during this procedure.
+ */
_GLOBAL(do_stab_bolted)
- mfsprg r21,3
- std r22,PACAR22(r21)
- std r1,PACAR1(r21)
- stw r20,PACACCR(r21)
- mfspr r21,DAR
+ std r23,48(r21) /* save CR in exc. frame */
/* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
+ mfspr r21,DAR
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
+ sldi r21,r21,32
oris r21,r21,58231
ori r21,r21,39831
@@ -699,20 +689,20 @@
/* 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
+ ld r23,0(r21) /* Test valid bit of the current ste */
+ rldicl r23,r23,57,63
+ cmpwi r23,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 */
+ ld r23,8(r21) /* Get the current vsid part of the ste */
+ rldimi r23,r20,12,0 /* Insert the new vsid value */
+ std r23,8(r21) /* Put new entry back into the stab */
eieio /* Order vsid update */
- ld r1,0(r21) /* Get the esid part of the ste */
+ ld r23,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 */
+ rldimi r23,r20,28,0 /* Insert the new esid value */
+ ori r23,r23,144 /* Turn on valid and kp */
+ std r23,0(r21) /* Put new entry back into the stab */
sync /* Order the update */
b 3f
2:
@@ -732,27 +722,27 @@
/* 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 */
+ or r21,r21,r22 /* r21 is the entry to invalidate */
isync /* mark the entry invalid */
- ld r1,0(r21)
+ ld r23,0(r21)
li r22,-129
- and r1,r1,r22
- std r1,0(r21)
+ and r23,r23,r22
+ std r23,0(r21)
sync
- ld r1,8(r21)
- rldimi r1,r20,12,0
- std r1,8(r21)
+ ld r23,8(r21)
+ rldimi r23,r20,12,0
+ std r23,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 */
+ ld r23,0(r21) /* Get the esid part of the ste */
+ mr r22,r23
+ mfspr r20,DAR /* Get the new esid */
+ rldicl r20,r20,36,32 /* Permits a full 32b of ESID */
+ rldimi r23,r20,28,0 /* Insert the new esid value */
+ ori r23,r23,144 /* Turn on valid and kp */
+ std r23,0(r21) /* Put new entry back into the stab */
rldicl r22,r22,36,28
rldicr r22,r22,28,35
@@ -761,24 +751,26 @@
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
+ mfsprg r20,3 /* Load the PACA pointer */
+ ld r21,PACAEXCSP(r20) /* Get the exception frame pointer */
+ addi r22,r21,EXC_FRAME_SIZE
+ ld r23,48(r21) /* get saved CR */
+ std r22,PACAEXCSP(r20) /* pop off the exception frame */
+ mtcr r23 /* restore CR */
+ ld r22,0(r21) /* Get SRR0 from exc. frame */
+ ld r23,8(r21) /* Get SRR1 from exc. frame */
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
+ mtspr SRR1,r23
+ ld r20,16(r21) /* restore r20 from exc. frame */
+ ld r22,32(r21) /* restore r22 and r23 */
+ ld r23,40(r21)
+ ld r21,24(r21) /* restore r21 last */
rfid
_GLOBAL(do_stab_SI)
mflr r21 /* Save LR in r21 */
- /* r21 restored later from r1 */
+
/*
* r3 contains the faulting address
* r4 contains the required access permissions
@@ -787,108 +779,72 @@
*/
bl .ste_allocate /* build STE if possible */
- mtlr r21 /* restore LR */
- mr r21,r1 /* restore r21 */
-
or. r3,r3,r3 /* Check return code */
- bnelr /* Return to DSI or ISI on failure */
+ beq fast_exception_return /* Return from exception on success */
+ mtlr r21 /* restore LR */
+ blr /* Return to DSI or ISI on failure */
- /*
- * The STE has been created/updated. Restore and retry the faulting inst
- */
-
- ld r3,_CCR(r21)
- ld r4,_LINK(r21)
- ld r5,_CTR(r21)
- ld r6,_XER(r21)
-
- mtcrf 0xff,r3
- mtlr r4
- mtctr r5
- mtspr XER,r6
- REST_8GPRS(0,r21)
- REST_4GPRS(8,r21)
- REST_2GPRS(12,r21)
- mtspr SRR1,r23
- mtspr SRR0,r22
- ld r20,GPR20(r21)
- ld r22,GPR22(r21)
- ld r23,GPR23(r21)
- ld r21,GPR21(r21)
- rfid
-
-/*
- * This code finishes saving the registers to the exception frame
- * and jumps to the appropriate handler for the exception. Address
- * translation is already on.
- */
-_GLOBAL(transfer_to_handler)
-/*
- * Save the rest of the registers into the pt_regs structure
- */
- std r22,_NIP(r21)
- std r23,_MSR(r21)
- std r6,TRAP(r21)
- ld r6,GPR6(r21)
- SAVE_2GPRS(14, r21)
- SAVE_4GPRS(16, r21)
- SAVE_8GPRS(24, r21)
/*
- * Clear the RESULT field
+ * This code finishes saving the registers to the exception frame.
+ * Address translation is already on.
*/
+_GLOBAL(save_remaining_regs)
+ /*
+ * Save the rest of the registers into the pt_regs structure
+ */
+ std r22,_NIP(r1)
+ std r23,_MSR(r1)
+ std r6,TRAP(r1)
+ ld r6,GPR6(r1)
+ SAVE_2GPRS(14, r1)
+ SAVE_4GPRS(16, r1)
+ SAVE_8GPRS(24, r1)
+
+ /*
+ * Clear the RESULT field
+ */
li r22,0
- std r22,RESULT(r21)
-/*
- * Test if from user state; result will be tested later
- */
+ std r22,RESULT(r1)
+
+ /*
+ * Test if from user state; result will be tested later
+ */
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
- */
+
+ /*
+ * Indicate that r1 contains the kernel stack and
+ * get the Kernel TOC and CURRENT pointers from the Paca
+ */
mfspr r23,SPRG3 /* Get PACA */
std r22,PACAKSAVE(r23) /* r1 is now kernel sp */
ld r2,PACATOC(r23) /* Get Kernel TOC pointer */
ld r22,PACACURRENT(r23) /* Get CURRENT */
-/*
- * If from user state, update THREAD.regs
- */
+
+ /*
+ * If from user state, update THREAD.regs
+ */
beq 2f /* Modify THREAD.regs if from user */
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
- * set here because it could have been changed by the user.
- */
+ /*
+ * 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
+ * set here because it could have been changed by the user.
+ */
-/*
- * Check for kernel stack overflow
- */
+ /*
+ * Check for kernel stack overflow
+ */
addi r24,r22,TASK_STRUCT_SIZE /* check for kernel stack overflow */
cmpld 0,r1,r22
cmpld 1,r1,r24
crand 1,1,4
- bgt- .stack_ovf /* if r22 < r1 < r22+TASK_STRUCT_SIZE */
+ bgt- .stack_ovf /* if r22
#include
#include
+#include
#include
/* For iSeries */
@@ -113,24 +114,36 @@
* Calculate the required size of the htab. We want the number of
* PTEGs to equal one half the number of real pages.
*/
- htab_size_bytes = htab_size(_naca->physicalMemorySize);
+ htab_size_bytes = 1UL << _naca->pftSize;
pteg_count = htab_size_bytes >> 7;
- _htab_data->htab_num_ptegs = pteg_count;
- _htab_data->htab_hash_mask = pteg_count - 1;
- /* Find storage for the HPT. Must be contiguous in
- * the absolute address space.
- */
- table = lmb_alloc(htab_size_bytes, htab_size_bytes);
- if ( !table )
- panic("ERROR, cannot find space for HPTE\n");
- _htab_data->htab = (HPTE *)__a2v(table);
+ /* For debug, make the HTAB 1/8 as big as it normally would be. */
+ ifppcdebug(PPCDBG_HTABSIZE) {
+ pteg_count >>= 3;
+ htab_size_bytes = pteg_count << 7;
+ }
- /* htab absolute addr + encoded htabsize */
- RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;
+ _htab_data->htab_num_ptegs = pteg_count;
+ _htab_data->htab_hash_mask = pteg_count - 1;
- /* Initialize the HPT with no entries */
- cacheable_memzero((void *)table, htab_size_bytes);
+ if(_machine == _MACH_pSeries) {
+ /* Find storage for the HPT. Must be contiguous in
+ * the absolute address space.
+ */
+ table = lmb_alloc(htab_size_bytes, htab_size_bytes);
+ if ( !table )
+ panic("ERROR, cannot find space for HPTE\n");
+ _htab_data->htab = (HPTE *)__a2v(table);
+
+ /* htab absolute addr + encoded htabsize */
+ RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;
+
+ /* Initialize the HPT with no entries */
+ cacheable_memzero((void *)table, htab_size_bytes);
+ } else {
+ _htab_data->htab = NULL;
+ RELOC(_SDR1) = 0;
+ }
mode_ro = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RXRX;
mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
@@ -194,44 +207,42 @@
for(;x;x|=1);
}
-void invalidate_hpte( unsigned long slot )
+/* Functions to invalidate a HPTE */
+static void hpte_invalidate_iSeries( unsigned long slot )
{
+ HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 );
+}
- /* Invalidate the HPTE */
-
- if ( _machine == _MACH_iSeries ) {
- HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 );
- }
- else {
- /* Local copy of the first doubleword of the HPTE */
- union {
- unsigned long d;
- Hpte_dword0 h;
- } hpte_dw0;
+static void hpte_invalidate_pSeries( unsigned long slot )
+{
+ /* Local copy of the first doubleword of the HPTE */
+ union {
+ unsigned long d;
+ Hpte_dword0 h;
+ } hpte_dw0;
- /* Locate the HPTE */
- HPTE * hptep = htab_data.htab + slot;
+ /* Locate the HPTE */
+ HPTE * hptep = htab_data.htab + slot;
- /* Get the first doubleword of the HPTE */
- hpte_dw0.d = hptep->dw0.dword0;
-
- /* Invalidate the hpte */
- hptep->dw0.dword0 = 0;
+ /* Get the first doubleword of the HPTE */
+ hpte_dw0.d = hptep->dw0.dword0;
- /* Invalidate the tlb */
- {
- unsigned long vsid, group, pi, pi_high;
-
- vsid = hpte_dw0.h.avpn >> 5;
- group = slot >> 3;
- if(hpte_dw0.h.h) {
- group = ~group;
- }
- pi = (vsid ^ group) & 0x7ff;
- pi_high = (hpte_dw0.h.avpn & 0x1f) << 11;
- pi |= pi_high;
- _tlbie(pi << 12);
- }
+ /* Invalidate the hpte */
+ hptep->dw0.dword0 = 0;
+
+ /* Invalidate the tlb */
+ {
+ unsigned long vsid, group, pi, pi_high;
+
+ vsid = hpte_dw0.h.avpn >> 5;
+ group = slot >> 3;
+ if(hpte_dw0.h.h) {
+ group = ~group;
+ }
+ pi = (vsid ^ group) & 0x7ff;
+ pi_high = (hpte_dw0.h.avpn & 0x1f) << 11;
+ pi |= pi_high;
+ _tlbie(pi << 12);
}
}
@@ -240,48 +251,48 @@
* return slot index (if in primary group)
* return -slot index (if in secondary group)
*/
-long select_hpte_slot( unsigned long vpn )
+static long hpte_selectslot_iSeries( unsigned long vpn )
{
-
-/****** Add code for iSeries ******/
-
- HPTE * hptep;
HPTE hpte;
- unsigned long primary_hash;
- unsigned long hpteg_slot;
long ret_slot, orig_slot;
- unsigned i, k;
-
- if ( _machine == _MACH_iSeries ) {
- ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn );
- if ( hpte.dw0.dw0.v ) { /* If valid ...what do we do now? */
- udbg_printf( "select_hpte_slot: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot );
- udbg_printf( "select_hpte_slot: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 );
- return (0x8000000000000000);
-/* panic("select_hpte_slot found entry already valid\n"); */
- }
- if ( ret_slot == -1 ) { /* -1 indicates no available slots */
- /*
- * Eventually we will have a hypervisor call which will allow us to conditionally
- * invalidate an hpte depending on whether it is bolted. For now, we need to look
- * each entry to see if it is bolted before we invalidate it.
- */
+ ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn );
+ if ( hpte.dw0.dw0.v ) { /* If valid ...what do we do now? */
+ udbg_printf( "hpte_selectslot_iSeries: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot );
+ udbg_printf( "hpte_selectslot_iSeries: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 );
+
+ return (0x8000000000000000);
+ /* panic("select_hpte_slot found entry already valid\n"); */
+ }
+ if ( ret_slot == -1 ) { /* -1 indicates no available slots */
+ /*
+ * Eventually we will have a hypervisor call which will allow us to conditionally
+ * invalidate an hpte depending on whether it is bolted. For now, we need to look
+ * each entry to see if it is bolted before we invalidate it.
+ */
- /* ADD CODE HERE */
- /* add code to cast out a non-bolted hpte */
- }
- else {
- if ( ret_slot < 0 ) {
- ret_slot &= 0x7fffffffffffffff;
- ret_slot = -ret_slot;
- }
+ /* ADD CODE HERE */
+ /* add code to cast out a non-bolted hpte */
+ }
+ else {
+ if ( ret_slot < 0 ) {
+ ret_slot &= 0x7fffffffffffffff;
+ ret_slot = -ret_slot;
}
- PPCDBG(PPCDBG_MM, "select_hpte_slot: vpn=0x%016lx, orig_slot=0x%016lx, ret_slot=0x%016lx \n",
- vpn, orig_slot, ret_slot );
- return ret_slot;
}
+ PPCDBG(PPCDBG_MM, "hpte_selectslot_iSeries: vpn=0x%016lx, orig_slot=0x%016lx, ret_slot=0x%016lx \n",
+ vpn, orig_slot, ret_slot );
+ return ret_slot;
+}
+
+static long hpte_selectslot_pSeries(unsigned long vpn)
+{
+ HPTE * hptep;
+ unsigned long primary_hash;
+ unsigned long hpteg_slot;
+ unsigned i, k;
+
/* Search the primary group for an available slot */
primary_hash = hpt_hash( vpn );
@@ -330,14 +341,14 @@
if (!hptep[k].dw0.dw0.bolted) {
hpteg_slot += k;
/* Invalidate the current entry */
- invalidate_hpte(hpteg_slot);
+ ppc_md.hpte_invalidate(hpteg_slot);
return hpteg_slot;
}
++k;
}
/* No non-bolted entry found in primary group - time to panic */
- udbg_printf("select_hpte_slot - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
+ udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
/* xmon(0); */
panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
@@ -345,67 +356,70 @@
return 0;
}
-static unsigned long get_hpte0( unsigned long slot )
+unsigned long hpte_getword0_iSeries( 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;
- }
+ HPTE hpte;
+ HvCallHpt_get( &hpte, slot );
+ dword0 = hpte.dw0.dword0;
+
+ return dword0;
+}
+
+unsigned long hpte_getword0_pSeries( unsigned long slot )
+{
+ unsigned long dword0;
+ HPTE * hptep = htab_data.htab + slot;
+ dword0 = hptep->dw0.dword0;
return dword0;
}
-long find_hpte( unsigned long vpn )
+static long hpte_find_iSeries(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;
- }
+ 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;
+ } else
+ slot = -1;
+ return slot;
+}
- 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;
+static long hpte_find_pSeries(unsigned long vpn)
+{
+ union {
+ unsigned long d;
+ Hpte_dword0 h;
+ } hpte_dw0;
+ long slot;
+ 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;
}
- hash = ~hash;
+ ++slot;
}
- slot = -1;
+ hash = ~hash;
}
- return slot;
+ return -1;
}
/* This function is called by btmalloc to bolt an entry in the hpt */
@@ -421,7 +435,7 @@
spin_lock_irqsave( &hash_table_lock, flags );
- hpte_slot = select_hpte_slot( vpn );
+ hpte_slot = ppc_md.hpte_selectslot( vpn );
hash = 0;
if ( hpte_slot < 0 ) {
if ( hpte_slot == 0x8000000000000000 ) {
@@ -434,7 +448,7 @@
hash = 1;
hpte_slot = -hpte_slot;
}
- create_valid_hpte( hpte_slot, vpn, pa >> 12, hash, ptep,
+ ppc_md.hpte_create_valid( hpte_slot, vpn, pa >> 12, hash, ptep,
hpteflags, bolted );
if ( ptep ) {
@@ -465,10 +479,10 @@
* The HPTE is set with the vpn, rpn (converted to absolute)
* and flags
*/
-void create_valid_hpte(unsigned long slot, unsigned long vpn,
- unsigned long prpn, unsigned hash,
- void * ptep, unsigned hpteflags,
- unsigned bolted )
+static void hpte_create_valid_iSeries(unsigned long slot, unsigned long vpn,
+ unsigned long prpn, unsigned hash,
+ void * ptep, unsigned hpteflags,
+ unsigned bolted )
{
/* Local copy of HPTE */
struct {
@@ -500,33 +514,64 @@
lhpte.dw0.h.v = 1;
/* Now fill in the actual HPTE */
+ HvCallHpt_addValidate( slot, hash, (HPTE *)&lhpte );
+}
- PPCDBG(PPCDBG_MM, "create_valid_hpte: slot=0x%lx, hash=%d, hpte=0x%016lx 0x%016lx\n", slot, hash, lhpte.dw0.d, lhpte.dw1.d );
+static void hpte_create_valid_pSeries(unsigned long slot, unsigned long vpn,
+ unsigned long prpn, unsigned hash,
+ void * ptep, unsigned hpteflags,
+ unsigned bolted)
+{
+ /* Local copy of HPTE */
+ struct {
+ /* Local copy of first doubleword of HPTE */
+ union {
+ unsigned long d;
+ Hpte_dword0 h;
+ } dw0;
+ /* Local copy of second doubleword of HPTE */
+ union {
+ unsigned long d;
+ Hpte_dword1 h;
+ Hpte_dword1_flags f;
+ } dw1;
+ } lhpte;
- if ( _machine == _MACH_iSeries ) {
- HvCallHpt_addValidate( slot, hash, (HPTE *)&lhpte );
- }
- else {
- HPTE * hptep = htab_data.htab + slot;
+ unsigned long avpn = vpn >> 11;
+ unsigned long arpn = physRpn_to_absRpn( prpn );
- /* Set the second dword first so that the valid bit
- * is the last thing set
- */
+ HPTE *hptep;
- hptep->dw1.dword1 = lhpte.dw1.d;
+ /* Fill in the local HPTE with absolute rpn, avpn and flags */
+ lhpte.dw1.d = 0;
+ lhpte.dw1.h.rpn = arpn;
+ lhpte.dw1.f.flags = hpteflags;
- /* Guarantee the second dword is visible before
- * the valid bit
- */
+ lhpte.dw0.d = 0;
+ lhpte.dw0.h.avpn = avpn;
+ lhpte.dw0.h.h = hash;
+ lhpte.dw0.h.bolted = bolted;
+ lhpte.dw0.h.v = 1;
- __asm__ __volatile__ ("eieio" : : : "memory");
+ /* Now fill in the actual HPTE */
+ hptep = htab_data.htab + slot;
+
+ /* Set the second dword first so that the valid bit
+ * is the last thing set
+ */
+
+ hptep->dw1.dword1 = lhpte.dw1.d;
- /* Now set the first dword including the valid bit */
- hptep->dw0.dword0 = lhpte.dw0.d;
+ /* Guarantee the second dword is visible before
+ * the valid bit
+ */
+
+ __asm__ __volatile__ ("eieio" : : : "memory");
- __asm__ __volatile__ ("ptesync" : : : "memory");
+ /* Now set the first dword including the valid bit */
+ hptep->dw0.dword0 = lhpte.dw0.d;
- }
+ __asm__ __volatile__ ("ptesync" : : : "memory");
}
/* find_linux_pte returns the address of a linux pte for a given
@@ -564,49 +609,69 @@
1 ) );
}
-static void updateHptePP( long slot, unsigned long newpp, unsigned long va )
+static void hpte_updatepp_iSeries(long slot, unsigned long newpp, unsigned long va)
{
- if ( _machine == _MACH_iSeries ) {
- HvCallHpt_setPp( slot, newpp );
- }
- else {
- /* Local copy of first doubleword of HPTE */
- union {
- unsigned long d;
- Hpte_dword0 h;
- } hpte_dw0;
-
- /* Local copy of second doubleword of HPTE */
- union {
- unsigned long d;
- Hpte_dword1 h;
- Hpte_dword1_flags f;
- } hpte_dw1;
-
- HPTE * hptep = htab_data.htab + slot;
-
- /* Turn off valid bit in HPTE */
- hpte_dw0.d = hptep->dw0.dword0;
- hpte_dw0.h.v = 0;
- hptep->dw0.dword0 = hpte_dw0.d;
-
- /* Ensure it is out of the tlb too */
- _tlbie( va );
-
- /* Insert the new pp bits into the HPTE */
- hpte_dw1.d = hptep->dw1.dword1;
- hpte_dw1.h.pp = newpp;
- hptep->dw1.dword1 = hpte_dw1.d;
-
- /* Ensure it is visible before validating */
- __asm__ __volatile__ ("eieio" : : : "memory");
-
- /* Turn the valid bit back on in HPTE */
- hpte_dw0.h.v = 1;
- hptep->dw0.dword0 = hpte_dw0.d;
+ HvCallHpt_setPp( slot, newpp );
+}
- __asm__ __volatile__ ("ptesync" : : : "memory");
- }
+static void hpte_updatepp_pSeries(long slot, unsigned long newpp, unsigned long va)
+{
+ /* Local copy of first doubleword of HPTE */
+ union {
+ unsigned long d;
+ Hpte_dword0 h;
+ } hpte_dw0;
+
+ /* Local copy of second doubleword of HPTE */
+ union {
+ unsigned long d;
+ Hpte_dword1 h;
+ Hpte_dword1_flags f;
+ } hpte_dw1;
+
+ HPTE * hptep = htab_data.htab + slot;
+
+ /* Turn off valid bit in HPTE */
+ hpte_dw0.d = hptep->dw0.dword0;
+ hpte_dw0.h.v = 0;
+ hptep->dw0.dword0 = hpte_dw0.d;
+
+ /* Ensure it is out of the tlb too */
+ _tlbie( va );
+
+ /* Insert the new pp bits into the HPTE */
+ hpte_dw1.d = hptep->dw1.dword1;
+ hpte_dw1.h.pp = newpp;
+ hptep->dw1.dword1 = hpte_dw1.d;
+
+ /* Ensure it is visible before validating */
+ __asm__ __volatile__ ("eieio" : : : "memory");
+
+ /* Turn the valid bit back on in HPTE */
+ hpte_dw0.h.v = 1;
+ hptep->dw0.dword0 = hpte_dw0.d;
+
+ __asm__ __volatile__ ("ptesync" : : : "memory");
+}
+
+/* This is called very early. */
+void htpe_init_iSeries(void)
+{
+ ppc_md.hpte_invalidate = hpte_invalidate_iSeries;
+ ppc_md.hpte_updatepp = hpte_updatepp_iSeries;
+ ppc_md.hpte_getword0 = hpte_getword0_iSeries;
+ ppc_md.hpte_selectslot = hpte_selectslot_iSeries;
+ ppc_md.hpte_create_valid = hpte_create_valid_iSeries;
+ ppc_md.hpte_find = hpte_find_iSeries;
+}
+void htpe_init_pSeries(void)
+{
+ ppc_md.hpte_invalidate = hpte_invalidate_pSeries;
+ ppc_md.hpte_updatepp = hpte_updatepp_pSeries;
+ ppc_md.hpte_getword0 = hpte_getword0_pSeries;
+ ppc_md.hpte_selectslot = hpte_selectslot_pSeries;
+ ppc_md.hpte_create_valid = hpte_create_valid_pSeries;
+ ppc_md.hpte_find = hpte_find_pSeries;
}
/* Handle a fault by adding an HPTE
@@ -640,9 +705,7 @@
* we're bolting the entire 0xC0... region.
*/
udbg_printf("Doh!!! hash_page saw a kernel address...\n");
-#if defined(CONFIG_XMON)
- xmon(0);
-#endif
+ PPCDBG_ENTER_DEBUGGER();
for(;x;x|=1);
vsid = get_kernel_vsid( ea );
@@ -760,7 +823,7 @@
if ( pte_val(old_pte) & _PAGE_HPTENOIX ) {
unsigned long slot;
pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
- slot = find_hpte( vpn );
+ slot = ppc_md.hpte_find( vpn );
if ( slot != -1 ) {
if ( slot < 0 ) {
pte_val(old_pte) |= _PAGE_SECONDARY;
@@ -800,12 +863,12 @@
slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
/* If there is an HPTE for this page it is indexed by slot */
- hpte_dw0.d = get_hpte0( slot );
+ hpte_dw0.d = ppc_md.hpte_getword0( slot );
if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
(hpte_dw0.h.v) &&
(hpte_dw0.h.h == secondary ) ){
/* HPTE matches */
- updateHptePP( slot, newpp, va );
+ ppc_md.hpte_updatepp( slot, newpp, va );
if ( !pte_same( old_pte, new_pte ) )
*ptep = new_pte;
}
@@ -822,7 +885,7 @@
*
* Find an available HPTE slot
*/
- slot = select_hpte_slot( vpn );
+ slot = ppc_md.hpte_selectslot( vpn );
/* Debug code */
if ( slot == 0x8000000000000000 ) {
@@ -865,7 +928,7 @@
hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
/* Create the HPTE */
- create_valid_hpte( slot, vpn, prpn, hash_ind, ptep, hpteflags, 0 );
+ ppc_md.hpte_create_valid( slot, vpn, prpn, hash_ind, ptep, hpteflags, 0 );
}
@@ -943,12 +1006,12 @@
/* If there is an HPTE for this page it is indexed by slot */
spin_lock_irqsave( &hash_table_lock, flags);
- hpte_dw0.d = get_hpte0( slot );
+ hpte_dw0.d = ppc_md.hpte_getword0( slot );
if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
(hpte_dw0.h.v) &&
(hpte_dw0.h.h == secondary ) ){
/* HPTE matches */
- invalidate_hpte( slot );
+ ppc_md.hpte_invalidate( slot );
}
else {
unsigned k;
@@ -959,7 +1022,7 @@
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 );
+ hpte_dw0.d = ppc_md.hpte_getword0( slot+k );
if ( ( hpte_dw0.h.avpn == (vpn >> 11) ) &&
( hpte_dw0.h.v ) &&
( hpte_dw0.h.h == secondary ) ) {
@@ -1138,30 +1201,50 @@
return -EINVAL;
}
-/* round mem size up to next power of 2 -- htab size must be a power of 2 */
-unsigned long
-rounded_mem_size(unsigned long mem_size)
+/*
+ * Update the page protection bits. Intended to be used to create
+ * guard pages for kernel data structures on pages which are bolted
+ * in the HPT. Assumes pages being operated on will not be stolen.
+ */
+void updateBoltedHptePP( unsigned long newpp, unsigned long ea )
{
- unsigned long rnd_mem_size;
+ unsigned long vsid,va,vpn;
+ long slot;
- rnd_mem_size = 1UL << (unsigned long)__ilog2(mem_size);
- if ( rnd_mem_size < mem_size )
- rnd_mem_size <<= 1;
+
+ vsid = get_kernel_vsid( ea );
+ va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+ vpn = va >> PAGE_SHIFT;
- return rnd_mem_size;
-}
+ slot = ppc_md.hpte_find( vpn );
+
+ if ( _machine == _MACH_iSeries ) {
+ HvCallHpt_setPp( slot, newpp );
+ } else {
+ HPTE * hptep = htab_data.htab + slot;
+
+ set_pp_bit(newpp , hptep );
-unsigned long
-htab_size(unsigned long mem_size)
-{
- unsigned long offset = reloc_offset();
- struct Naca *_naca = RELOC(naca);
- unsigned long rnd_mem_size = rounded_mem_size(mem_size);
- unsigned long pteg_count = (rnd_mem_size >> (12 + 1)); /* #pages/2 */
- /* For debug, make the HTAB 1/8 as big as it normally would be. */
- if(_naca->debug_switch & PPCDBG_HTABSIZE) {
- pteg_count >>= 3;
+ /* Ensure it is out of the tlb too */
+ _tlbie( va );
+
+ /* Ensure it is visible before validating */
+ __asm__ __volatile__ ("eieio" : : : "memory");
+ __asm__ __volatile__ ("ptesync" : : : "memory");
}
- return (pteg_count << 7); /* pteg_count*128B/PTEG */
}
+static __inline__ void set_pp_bit(unsigned long pp, HPTE *addr)
+{
+ unsigned long old;
+ unsigned long *p = (unsigned long *)(&(addr->dw1));
+
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%3\n\
+ rldimi %0,%2,0,62\n\
+ stdcx. %0,0,%3\n\
+ bne 1b"
+ : "=&r" (old), "=m" (*p)
+ : "r" (pp), "r" (p), "m" (*p)
+ : "cc");
+}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/iSeries_IoMmTable.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.c
--- linux/arch/ppc64/kernel/iSeries_IoMmTable.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.c Sat Sep 1 15:32:42 2001
@@ -34,23 +34,27 @@
#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
+unsigned long iSeries_IoMmTable_Entry_Size = 0x0000000000400000;
+unsigned long iSeries_Base_Io_Memory = 0xE000000000000000;
+
+/*******************************************************************/
+/* Lookup Tables. */
+/*******************************************************************/
+struct pci_dev* iSeries_IoMmTable[iSeries_IoMmTable_Size];
+u8 iSeries_IoBarTable[iSeries_IoMmTable_Size];
/*******************************************************************/
/* Static and Global variables */
/*******************************************************************/
-struct pci_dev* iSeries_IoMmTable[iSeries_IoMmTable_Size];
-u8 iSeries_IoBarTable[iSeries_IoMmTable_Size];
-static int iSeries_CurrentIndex;
+static long iSeries_CurrentIndex;
static char* iSeriesPciIoText = "iSeries PCI I/O";
static spinlock_t iSeriesIoMmTableLock = SPIN_LOCK_UNLOCKED;
+
/*******************************************************************/
/* iSeries_IoMmTable_Initialize */
/*******************************************************************/
@@ -59,15 +63,16 @@
/* methods. */
/*******************************************************************/
void iSeries_IoMmTable_Initialize(void) {
- int Index;
+ int Index = 0;
spin_lock(&iSeriesIoMmTableLock);
- for(Index=0;Indexresource[BarNumber];
iSeries_IoMmTable_AllocateEntry(PciDev, BarNumber);
@@ -98,90 +102,96 @@
/*******************************************************************/
/* - Allocates the number of entries required in table base on BAR */
/* size. */
-/* - This version, allocates top down, starting at 4GB. */
+/* - This version, allocates starting at iSeries_Base_Io_Memory and*/
+/* allocate up. */
/* - The size is round up to be a multiple of entry size. */
-/* - CurrentIndex is decremented to keep track of the last entry. */
+/* - CurrentIndex is incremented 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. */
- /***************************************************************/
+ struct resource* BarResource = &PciDev->resource[BarNumber];
+ long BarSize = pci_resource_len(PciDev,BarNumber);
+ /***************************************************************
+ * No space to allocate, quick exit, skip Allocation. *
+ ***************************************************************/
+ if(BarSize == 0) return;
+ //PPCDBG(PPCDBG_BUSWALK,"iSeries_IoMmTable_AllocateEntry Bar:%2d Index:0x%08X\n",BarNumber,iSeries_CurrentIndex);
+ /**************************************************************
+ * Set Resource values. *
+ ***************************************************************/
+ BarResource->name = iSeriesPciIoText;
+ BarResource->start = iSeries_IoMmTable_Entry_Size*(iSeries_CurrentIndex);
+ BarResource->start+= iSeries_Base_Io_Memory;
+ BarResource->end = BarResource->start+BarSize-1;
+ /**************************************************************
+ * Allocate the number of table entries needed. *
+ ***************************************************************/
spin_lock(&iSeriesIoMmTableLock);
- while(BarSize > 0) {
- iSeries_IoMmTable[iSeries_CurrentIndex] = PciDev;
+ while(BarSize > 0 ) {
+ iSeries_IoMmTable [iSeries_CurrentIndex] = PciDev;
iSeries_IoBarTable[iSeries_CurrentIndex] = BarNumber;
BarSize -= iSeries_IoMmTable_Entry_Size;
- --iSeries_CurrentIndex; /* Next Free entry */
+ ++iSeries_CurrentIndex;
}
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);
+struct pci_dev* iSeries_xlateIoMmAddress(void* IoAddress) {
+ long TableIndex = ((unsigned long)IoAddress-iSeries_Base_Io_Memory)/iSeries_IoMmTable_Entry_Size;
+ struct pci_dev* PciDev = iSeries_IoMmTable[TableIndex];
+ if(PciDev == NULL) {
+ printk("PCI: Invalid I/O Address: 0x%016lX\n",(unsigned long)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;
+int iSeries_IoMmTable_Bar(void* IoAddress) {
+ long TableIndex = ((unsigned long)IoAddress-iSeries_Base_Io_Memory)/iSeries_IoMmTable_Entry_Size;
+ return iSeries_IoBarTable[TableIndex];
}
/************************************************************************/
-/* 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 the Bar Base Address or NULL */
+/************************************************************************/
+void* iSeries_IoMmTable_BarBase(void* IoAddress) {
+ long TableIndex = ((unsigned long)IoAddress-iSeries_Base_Io_Memory)/iSeries_IoMmTable_Entry_Size;
+ struct pci_dev* PciDev = iSeries_IoMmTable[TableIndex];
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ if(PciDev == NULL || BarNumber == 0xFF) {
+ return NULL;
}
- return (unsigned long*)BaseAddr;
+ return (void*)(pci_resource_start(PciDev,BarNumber));
}
/************************************************************************/
/* Return the Bar offset within the Bar Space */
/* Note: Assumes that address is valid. */
/************************************************************************/
-unsigned long iSeries_IoMmTable_BarOffset(unsigned long* IoAddress) {
+unsigned long iSeries_IoMmTable_BarOffset(void* 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;
+/************************************************************************
+ * List the table entries out.
+ ************************************************************************/
+void iSeries_IoMmTable_Status(void) {
+ int Loop = 0;
+ struct pci_dev* PciDev = NULL;
+ int BarMinNumber = 0;
+
+ for(Loop = 0;Loop < iSeries_CurrentIndex;++Loop) {
+ if (PciDev != iSeries_IoMmTable[Loop] ) {
+ PciDev = iSeries_IoMmTable[Loop] ;
+ BarMinNumber = iSeries_IoBarTable[Loop];
+ printk("\nPCI: %3d. PciDev: 0x%016lX Bar %2d,",Loop,(unsigned long)PciDev,BarMinNumber);
+ }
+ if(BarMinNumber != iSeries_IoBarTable[Loop] ) {
+ BarMinNumber = iSeries_IoBarTable[Loop];
+ printk("%2d,",BarMinNumber);
+ }
+ }
+ printk("\nPci: %3d. Max Entries = %d\n",Loop, (int)(Loop*sizeof(void*)) );
}
-
-
+
\ No newline at end of file
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/iSeries_IoMmTable.h linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.h
--- linux/arch/ppc64/kernel/iSeries_IoMmTable.h Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.h Sat Sep 1 14:30:51 2001
@@ -24,9 +24,12 @@
/************************************************************************/
/* Change Activity: */
/* Created December 12, 2000 */
+/* Ported to ppc64, August 30, 2001 */
/* End Change Activity */
/************************************************************************/
+struct pci_dev;
+
/************************************************************************/
/* iSeries_IoMmTable_Initialize */
/************************************************************************/
@@ -45,7 +48,7 @@
/* - 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. */
+/* It calls iSeries_IoMmTable_AllocateEntry to allocate each entry. */
/* */
/* Parameters: */
/* pci_dev = Pointer to pci_dev structure that will be mapped to pseudo */
@@ -77,23 +80,22 @@
/************************************************************************/
/* iSeries_xlateIoMmAddress */
/************************************************************************/
-/* - Translates an I/O Memory address to pci_dev that has been allocated*/
-/* the psuedo I/O Address. */
+/* - Translates an I/O Memory address to Device Node that has been the */
+/* 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. */
+/* A pci_dev to the device mapped to the I/O address. */
/************************************************************************/
-extern struct pci_dev* iSeries_xlateIoMmAddress(unsigned long* IoAddress);
+extern struct pci_dev* iSeries_xlateIoMmAddress(void* 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);
-
+extern int iSeries_IoMmTable_Bar(void* IoAddress);
+extern void* iSeries_IoMmTable_BarBase(void* IoAddress);
+extern unsigned long iSeries_IoMmTable_BarOffset(void* IoAddress);
+extern void iSeries_IoMmTable_Status(void);
#endif /* _ISERIES_IOMMTABLE_H */
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/iSeries_VpdInfo.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_VpdInfo.c
--- linux/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/arch/ppc64/kernel/iSeries_dma.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_dma.c
--- linux/arch/ppc64/kernel/iSeries_dma.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_dma.c Wed Dec 31 18:00:00 1969
@@ -1,1121 +0,0 @@
-/*
- * iSeries_dma.c
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * Dynamic DMA mapping support.
- *
- * Manages the TCE space assigned to this partition
- *
- * modeled from pci-dma.c
- *
- * 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
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-/*#define DEBUG_TCE 1 */
-
-/*HACK HACK HACK */
-
-u8 iSeries_Get_Bus( struct pci_dev * dv )
-{
- return 0;
-}
-
-/* HACK HACK HACK */
-
-unsigned long phb_tce_table_init( void * x )
-{
- return (unsigned long)x;
-}
-
-
-struct TceTable virtBusTceTable; /* Tce table for virtual bus */
-
-struct TceTable * tceTables[256]; /* Tce tables for 256 busses
- * Bus 255 is the virtual bus
- * zero indicates no bus defined
- */
- /* allocates a contiguous range of tces (power-of-2 size) */
-static long alloc_tce_range( struct TceTable *,
- unsigned order );
- /* allocates a contiguous range of tces (power-of-2 size)
- * assumes lock already held
- */
-static long alloc_tce_range_nolock( struct TceTable *,
- unsigned order );
- /* frees a contiguous range of tces (power-of-2 size) */
-static void free_tce_range( struct TceTable *,
- long tcenum,
- unsigned order );
- /* frees a contiguous rnage of tces (power-of-2 size)
- * assumes lock already held
- */
-static void free_tce_range_nolock( struct TceTable *,
- long tcenum,
- unsigned order );
- /* allocates a range of tces and sets them to the pages */
-static dma_addr_t get_tces( struct TceTable *,
- unsigned order,
- void *page,
- unsigned numPages,
- int tceType,
- int direction );
-static void free_tces( struct TceTable *,
- dma_addr_t tce,
- unsigned order,
- unsigned numPages );
-static long test_tce_range( struct TceTable *,
- long tcenum,
- unsigned order );
-
-static unsigned fill_scatterlist_sg( struct scatterlist *sg, int nents,
- dma_addr_t dma_addr, unsigned long numTces );
-
-static unsigned long num_tces_sg( struct scatterlist *sg,
- int nents );
-
-static dma_addr_t create_tces_sg( struct TceTable *tbl,
- struct scatterlist *sg,
- int nents,
- unsigned numTces,
- int tceType,
- int direction );
-
-static unsigned __inline__ count_leading_zeros32( unsigned long x )
-{
- unsigned lz;
- asm("cntlzw %0,%1" : "=r"(lz) : "r"(x));
- return lz;
-}
-
-static void __inline__ build_tce( struct TceTable * tbl, long tcenum,
- unsigned long uaddr, int tceType, int direction )
-{
- u64 setTceRc;
- union Tce tce;
-
- tce.wholeTce = 0;
- tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
- /* If for virtual bus */
- if ( tceType == TCE_VB ) {
- tce.tceBits.valid = 1;
- tce.tceBits.allIo = 1;
- if ( direction != PCI_DMA_TODEVICE )
- tce.tceBits.readWrite = 1;
- }
- /* If for PCI bus */
- else {
- tce.tceBits.readWrite = 1; // Read allowed
- if ( direction != PCI_DMA_TODEVICE )
- tce.tceBits.pciWrite = 1;
- }
- setTceRc = HvCallXm_setTce( (u64)tbl->index, (u64)tcenum, tce.wholeTce );
- if ( setTceRc ) {
- printk("build_tce: HvCallXm_setTce failed, rc=%ld, index=%ld, tcenum=%0lx, tce=%016lx\n",
- setTceRc, (u64)tbl->index, (u64)tcenum, tce.wholeTce );
- }
-
-}
-
-
-
-/* Build a TceTable structure. This contains a multi-level bit map which
- * is used to manage allocation of the tce space.
- */
-
-struct TceTable * build_tce_table( struct HvTceTableManagerCB * tceTableParms,
- struct TceTable * tbl )
-{
- unsigned long bits, bytes, totalBytes;
- unsigned long numBits[NUM_TCE_LEVELS], numBytes[NUM_TCE_LEVELS];
- unsigned i, k, m;
- unsigned char * pos, * p, b;
-
- tbl->size = tceTableParms->size;
- tbl->busNumber = tceTableParms->busNumber;
- tbl->startOffset = tceTableParms->startOffset;
- tbl->index = tceTableParms->index;
- spin_lock_init( &(tbl->lock) );
-
- tbl->mlbm.maxLevel = 0;
-
- /* Compute number of bits and bytes for each level of the
- * multi-level bit map
- */
- totalBytes = 0;
- bits = tbl->size * (PAGE_SIZE / sizeof( union Tce ));
-
- for ( i=0; imlbm.level[i].map = pos;
- tbl->mlbm.maxLevel = i;
-
- if ( numBits[i] & 1 ) {
- p = pos + numBytes[i] - 1;
- m = (( numBits[i] % 8) - 1) & 7;
- *p = 0x80 >> m;
-#ifdef DEBUG_TCE
- printk("build_tce_table: level %d last bit %x\n", i, 0x80>>m );
-#endif
- }
- }
- else
- tbl->mlbm.level[i].map = 0;
- pos += numBytes[i];
- /* see the comment up above on the totalBytes calculation
- * for why we do this. */
- pos += ((numBytes[i] + 7) / 8) * 8;
-
- tbl->mlbm.level[i].numBits = numBits[i];
- tbl->mlbm.level[i].numBytes = numBytes[i];
-
- }
-
- /* For the highest level, turn on all the bits */
-
- i = tbl->mlbm.maxLevel;
- p = tbl->mlbm.level[i].map;
- m = numBits[i];
-#ifdef DEBUG_TCE
- printk("build_tce_table: highest level (%d) has all bits set\n", i);
-#endif
- for (k=0; k= 8 ) {
- /* handle full bytes */
- *p++ = 0xff;
- m -= 8;
- }
- else {
- /* handle the last partial byte */
- b = 0x80;
- *p = 0;
- while (m) {
- *p |= b;
- b >>= 1;
- --m;
- }
- }
- }
-
- return tbl;
-
-}
-
-static long alloc_tce_range( struct TceTable *tbl, unsigned order )
-{
- long retval;
- unsigned long flags;
-
- /* Lock the tce allocation bitmap */
- spin_lock_irqsave( &(tbl->lock), flags );
-
- /* Do the actual work */
- retval = alloc_tce_range_nolock( tbl, order );
-
- /* Unlock the tce allocation bitmap */
- spin_unlock_irqrestore( &(tbl->lock), flags );
-
- return retval;
-}
-
-static long alloc_tce_range_nolock( struct TceTable *tbl, unsigned order )
-{
- unsigned long numBits, numBytes;
- unsigned long i, bit, block, mask;
- long tcenum;
- u32 * map;
-
- /* If the order (power of 2 size) requested is larger than our
- * biggest, indicate failure
- */
- if ( order > tbl->mlbm.maxLevel ) {
- printk("alloc_tce_range_nolock: invalid order requested, order = %d\n", order );
- return -1;
- }
-
- numBits = tbl->mlbm.level[order].numBits;
- numBytes = tbl->mlbm.level[order].numBytes;
- map = (u32 *)(tbl->mlbm.level[order].map);
-
- /* Initialize return value to -1 (failure) */
- tcenum = -1;
-
- /* Loop through the bytes of the bitmap */
- for (i=0; i> bit);
- *map &= mask;
- /* compute the index into our tce table for
- * the first tce in the block
- */
-#ifdef DEBUG_TCE
- printk("alloc_tce_range_nolock: allocating block %ld, (byte=%ld, bit=%ld) order %d\n", block, i, bit, order );
-#endif
- tcenum = block << order;
- break;
- }
- ++map;
- }
-
-#ifdef DEBUG_TCE
- if ( tcenum == -1 ) {
- printk("alloc_tce_range_nolock: no available blocks of order = %d\n", order );
- if ( order < tbl->mlbm.maxLevel )
- printk("alloc_tce_range_nolock: trying next bigger size\n" );
- else
- printk("alloc_tce_range_nolock: maximum size reached...failing\n");
- }
-#endif
-
- /* If no block of the requested size was found, try the next
- * size bigger. If one of those is found, return the second
- * half of the block to freespace and keep the first half
- */
- if ( ( tcenum == -1 ) && ( order < tbl->mlbm.maxLevel ) ) {
- tcenum = alloc_tce_range_nolock( tbl, order+1 );
- if ( tcenum != -1 ) {
- free_tce_range_nolock( tbl, tcenum+(1<lock), flags );
-
- /* Do the actual work */
- free_tce_range_nolock( tbl, tcenum, order );
-
- /* Unlock the tce allocation bitmap */
- spin_unlock_irqrestore( &(tbl->lock), flags );
-
-}
-
-static void free_tce_range_nolock( struct TceTable *tbl, long tcenum, unsigned order )
-{
- unsigned long block;
- unsigned byte, bit, mask, b;
- unsigned char * map, * bytep;
-
- if ( order > tbl->mlbm.maxLevel ) {
- printk("free_tce_range: order too large, order = %d, tcenum = %ld\n", order, tcenum );
- return;
- }
-
- block = tcenum >> order;
- if ( tcenum != (block << order ) ) {
- printk("free_tce_range: tcenum %lx is not on appropriate boundary for order %x\n", tcenum, order );
- return;
- }
- if ( block >= tbl->mlbm.level[order].numBits ) {
- printk("free_tce_range: tcenum %lx is outside the range of this map (order %x, numBits %lx\n", tcenum, order, tbl->mlbm.level[order].numBits );
- return;
- }
-#ifdef DEBUG_TCE
- if ( test_tce_range( tbl, tcenum, order ) ) {
- printk("free_tce_range: freeing range not completely allocated.\n");
- printk("free_tce_range: TceTable %p, tcenum %lx, order %x\n", tbl, tcenum, order );
- }
-#endif
- map = tbl->mlbm.level[order].map;
- byte = block / 8;
- bit = block % 8;
- mask = 0x80 >> bit;
- bytep = map + byte;
-#ifdef DEBUG_TCE
- printk("free_tce_range_nolock: freeing block %ld (byte=%d, bit=%d) of order %d\n",block, byte, bit, order);
- if ( *bytep & mask )
- printk("free_tce_range: already free: TceTable %p, tcenum %lx, order %x\n", tbl, tcenum, order );
-#endif
- *bytep |= mask;
-
- /* If there is a higher level in the bit map than this we may be
- * able to buddy up this block with its partner.
- * If this is the highest level we can't buddy up
- * If this level has an odd number of bits and
- * we are freeing the last block we can't buddy up
- */
- if ( ( order < tbl->mlbm.maxLevel ) &&
- ( ( 0 == ( tbl->mlbm.level[order].numBits & 1 ) ) ||
- ( block < tbl->mlbm.level[order].numBits-1 ) ) ) {
-
- /* See if we can buddy up the block we just freed */
- bit &= 6; /* get to the first of the buddy bits */
- mask = 0xc0 >> bit; /* build two bit mask */
- b = *bytep & mask; /* Get the two bits */
- if ( 0 == (b ^ mask) ) { /* If both bits are on */
- /* both of the buddy blocks are free we can combine them */
- *bytep ^= mask; /* turn off the two bits */
- block = ( byte * 8 ) + bit; /* block of first of buddies */
- tcenum = block << order;
- /* free the buddied block */
-#ifdef DEBUG_TCE
- printk("free_tce_range: buddying up block %ld and block %ld\n", block, block+1);
-#endif
- free_tce_range_nolock( tbl, tcenum, order+1 );
- }
- }
-}
-
-static long test_tce_range( struct TceTable *tbl, long tcenum, unsigned order )
-{
- unsigned long block;
- unsigned byte, bit, mask, b;
- long retval, retLeft, retRight;
- unsigned char * map;
-
- map = tbl->mlbm.level[order].map;
- block = tcenum >> order;
- byte = block / 8; /* Byte within bitmap */
- bit = block % 8; /* Bit within byte */
- mask = 0x80 >> bit;
- b = (*(map+byte) & mask ); /* 0 if block is allocated, else free */
- if ( b )
- retval = 1; /* 1 == block is free */
- else
- retval = 0; /* 0 == block is allocated */
- /* Test bits at all levels below this to ensure that all agree */
-
- if (order) {
- retLeft = test_tce_range( tbl, tcenum, order-1 );
- retRight = test_tce_range( tbl, tcenum+(1<<(order-1)), order-1 );
- if ( retLeft || retRight ) {
- retval = 2;
- }
- }
-
- /* Test bits at all levels above this to ensure that all agree */
-
- return retval;
-}
-
-static dma_addr_t get_tces( struct TceTable *tbl, unsigned order, void *page, unsigned numPages, int tceType, int direction )
-{
- long tcenum;
- unsigned long uaddr;
- unsigned i;
- dma_addr_t retTce = NO_TCE;
-
- uaddr = (unsigned long)page & PAGE_MASK;
-
- /* Allocate a range of tces */
- tcenum = alloc_tce_range( tbl, order );
- if ( tcenum != -1 ) {
- /* We got the tces we wanted */
- tcenum += tbl->startOffset; /* Offset into real TCE table */
- retTce = tcenum << PAGE_SHIFT; /* Set the return dma address */
- /* Setup a tce for each page */
- for (i=0; isize * (PAGE_SIZE / sizeof(union Tce))) - 1;
-
- tcenum = dma_addr >> PAGE_SHIFT;
- tcenum -= tbl->startOffset;
-
- if ( tcenum > maxTcenum ) {
- printk("free_tces: tcenum > maxTcenum, tcenum = %ld, maxTcenum = %ld\n",
- tcenum, maxTcenum );
- printk("free_tces: TCE Table at %16lx\n", (unsigned long)tbl );
- printk("free_tces: bus# %lu\n", (unsigned long)tbl->busNumber );
- printk("free_tces: size %lu\n", (unsigned long)tbl->size );
- printk("free_tces: startOff %lu\n", (unsigned long)tbl->startOffset );
- printk("free_tces: index %lu\n", (unsigned long)tbl->index );
- return;
- }
-
- freeTce = tcenum;
-
- for (i=0; iindex, (u64)tcenum, tce.wholeTce );
- if ( setTceRc ) {
- printk("free_tces: HvCallXm_setTce failed, rc=%ld, index=%ld, tcenum=%0lx, tce=%016lx\n",
- setTceRc, (u64)tbl->index, (u64)tcenum, tce.wholeTce );
- }
-
- ++tcenum;
- }
-
- free_tce_range( tbl, freeTce, order );
-
-}
-
-void __init create_virtual_bus_tce_table(void)
-{
- struct TceTable * t;
- struct HvTceTableManagerCB virtBusTceTableParms;
- u64 absParmsPtr;
-
- virtBusTceTableParms.busNumber = 255; /* Bus 255 is the virtual bus */
- virtBusTceTableParms.virtualBusFlag = 0xff; /* Ask for virtual bus */
-
- absParmsPtr = virt_to_absolute( (u64)&virtBusTceTableParms );
- HvCallXm_getTceTableParms( absParmsPtr );
-
- t = build_tce_table( &virtBusTceTableParms, &virtBusTceTable );
- if ( t ) {
- tceTables[255] = t;
- printk("Virtual Bus TCE table built successfully.\n");
- printk(" TCE table size = %ld entries\n",
- (unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) );
- printk(" TCE table token = %d\n",
- (unsigned)t->index );
- printk(" TCE table start entry = 0x%lx\n",
- (unsigned long)t->startOffset );
- }
- else
- printk("Virtual Bus TCE table failed.\n");
-}
-
-void __init create_pci_bus_tce_table( unsigned busNumber )
-{
- struct TceTable * t;
- struct TceTable * newTceTable;
- struct HvTceTableManagerCB pciBusTceTableParms;
- u64 absParmsPtr;
- unsigned i;
-
- if ( busNumber > 254 ) {
- printk("PCI Bus TCE table failed.\n");
- printk(" Invalid bus number %u\n", busNumber );
- return;
- }
-
- newTceTable = kmalloc( sizeof(struct TceTable), GFP_KERNEL );
-
- pciBusTceTableParms.busNumber = busNumber;
- pciBusTceTableParms.virtualBusFlag = 0;
-
- absParmsPtr = virt_to_absolute( (u64)&pciBusTceTableParms );
- HvCallXm_getTceTableParms( absParmsPtr );
-
- /* Determine if the table identified by the index and startOffset
- * returned by the hypervisor for this bus has already been created.
- */
-
- for ( i=0; i<255; ++i ) {
- t = tceTables[i];
- if ( t ) {
- if ( ( t->index == pciBusTceTableParms.index ) &&
- ( t->startOffset == pciBusTceTableParms.startOffset ) ) {
- if ( t->size != pciBusTceTableParms.size )
- printk("PCI Bus %d Shares a TCE table with Bus %d, but sizes differ\n", busNumber, i );
- else
- printk("PCI Bus %d Shares a TCE table with Bus %d\n", busNumber, i );
- tceTables[busNumber] = t;
- break;
- }
- }
- }
-
- if ( ! tceTables[busNumber] ) {
- t = build_tce_table( &pciBusTceTableParms, newTceTable );
- if ( t ) {
- tceTables[busNumber] = t;
- printk("PCI Bus TCE table built successfully.\n");
- printk(" TCE table size = %ld entries\n",
- (unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) );
- printk(" TCE table token = %d\n",
- (unsigned)t->index );
- printk(" TCE table start entry = 0x%lx\n",
- (unsigned long)t->startOffset );
- }
- else {
- kfree( newTceTable );
- printk("PCI Bus TCE table failed.\n");
- }
- }
-}
-
-
-/* Allocates a contiguous real buffer and creates TCEs over it.
- * Returns the virtual address of the buffer and sets dma_handle
- * to the dma address (tce) of the first page.
- */
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t *dma_handle)
-{
- struct TceTable * tbl;
- void *ret = NULL;
- unsigned order, nPages, bus;
- dma_addr_t tce;
- int tceType;
-
- size = PAGE_ALIGN(size);
- order = get_order(size);
- nPages = 1 << order;
-
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL ) {
- bus = 255;
- tceType = TCE_VB;
- }
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = ISERIES_GET_BUS( hwdev );
- tceType = TCE_PCI;
-#else
- BUG();
- return NULL;
-#endif /* CONFIG_PCI */
- }
-
- tbl = tceTables[bus];
- if ( tbl ) {
- /* Alloc enough pages (and possibly more) */
- ret = (void *)__get_free_pages( GFP_ATOMIC, order );
- if ( ret ) {
- /* Page allocation succeeded */
- memset(ret, 0, nPages << PAGE_SHIFT);
- /* Set up tces to cover the allocated range */
- tce = get_tces( tbl, order, ret, nPages, tceType,
- PCI_DMA_BIDIRECTIONAL );
- if ( tce == NO_TCE ) {
-/*#ifdef DEBUG_TCE */
- printk("pci_alloc_consistent: get_tces failed\n" );
-/*#endif */
- free_pages( (unsigned long)ret, order );
- ret = NULL;
- }
- else
- {
- *dma_handle = tce;
- }
- }
-/*#ifdef DEBUG_TCE */
- else
- printk("pci_alloc_consistent: __get_free_pages failed for order = %d\n", order);
-/*#endif*/
- }
-
- return ret;
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- struct TceTable * tbl;
- unsigned order, nPages, bus;
-
- size = PAGE_ALIGN(size);
- order = get_order(size);
- nPages = 1 << order;
-
- if ( order > 10 )
- printk("pci_free_consistent: order=%d, size=%ld, nPages=%d, dma_handle=%016lx, vaddr=%016lx\n",
- order, size, nPages, (unsigned long)dma_handle, (unsigned long)vaddr );
-
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL )
- bus = 255;
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = ISERIES_GET_BUS( hwdev );
-#else
- BUG();
- return;
-#endif /* CONFIG_PCI */
- }
-
- if ( bus > 255 ) {
- printk("pci_free_consistent: invalid bus # %d\n", bus );
- printk("pci_free_consistent: hwdev = %08lx\n", (unsigned long)hwdev );
- }
-
- tbl = tceTables[bus];
-
- if ( tbl ) {
- free_tces( tbl, dma_handle, order, nPages );
- free_pages( (unsigned long)vaddr, order );
- }
-}
-
-/* Creates TCEs for a user provided buffer. The user buffer must be
- * contiguous real kernel storage (not vmalloc). The address of the buffer
- * passed here is the kernel (virtual) address of the buffer. The buffer
- * need not be page aligned, the dma_addr_t returned will point to the same
- * byte within the page as vaddr.
- */
-dma_addr_t pci_map_single( struct pci_dev *hwdev, void *vaddr, size_t size, int direction )
-{
- struct TceTable * tbl;
- dma_addr_t dma_handle;
- unsigned long uaddr;
- unsigned order, nPages, bus;
- int tceType;
-
- if ( direction == PCI_DMA_NONE )
- BUG();
-
- dma_handle = NO_TCE;
-
- uaddr = (unsigned long)vaddr;
- nPages = PAGE_ALIGN( uaddr + size ) - ( uaddr & PAGE_MASK );
- order = get_order( nPages & PAGE_MASK );
- nPages >>= PAGE_SHIFT;
-
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL ) {
- bus = 255;
- tceType = TCE_VB;
- }
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = ISERIES_GET_BUS( hwdev );
- tceType = TCE_PCI;
-#else
- BUG();
- return NO_TCE;
-#endif /* CONFIG_PCI */
-
- }
-
- tbl = tceTables[bus];
-
- if ( tbl ) {
- dma_handle = get_tces( tbl, order, vaddr, nPages, tceType,
- direction );
- dma_handle |= ( uaddr & ~PAGE_MASK );
- }
-
- return dma_handle;
-}
-
-void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction )
-{
- struct TceTable * tbl;
- unsigned order, nPages, bus;
-
- if ( direction == PCI_DMA_NONE )
- BUG();
-
- nPages = PAGE_ALIGN( dma_handle + size ) - ( dma_handle & PAGE_MASK );
- order = get_order( nPages & PAGE_MASK );
- nPages >>= PAGE_SHIFT;
-
- if ( order > 10 )
- printk("pci_unmap_single: order=%d, size=%ld, nPages=%d, dma_handle=%016lx\n",
- order, size, nPages, (unsigned long)dma_handle );
-
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL )
- bus = 255;
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = ISERIES_GET_BUS( hwdev );
-#else
- BUG();
- return;
-#endif /* CONFIG_PCI */
- }
-
- if ( bus > 255 ) {
- printk("pci_unmap_single: invalid bus # %d\n", bus );
- printk("pci_unmap_single: hwdev = %08lx\n", (unsigned long)hwdev );
- }
-
- tbl = tceTables[bus];
-
- if ( tbl )
- free_tces( tbl, dma_handle, order, nPages );
-
-}
-
-/* Figure out how many TCEs are actually going to be required
- * to map this scatterlist. This code is not optimal. It
- * takes into account the case where entry n ends in the same
- * page in which entry n+1 starts. It does not handle the
- * general case of entry n ending in the same page in which
- * entry m starts.
- */
-static unsigned long num_tces_sg( struct scatterlist *sg, int nents )
-{
- unsigned long nTces, numPages, startPage, endPage, prevEndPage;
- unsigned i;
-
- prevEndPage = 0;
- nTces = 0;
-
- for (i=0; iaddress >> PAGE_SHIFT;
- endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT;
- numPages = endPage - startPage + 1;
- /* Simple optimization: if the previous entry ended
- * in the same page in which this entry starts
- * then we can reduce the required pages by one.
- * This matches assumptions in fill_scatterlist_sg and
- * create_tces_sg
- */
- if ( startPage == prevEndPage )
- --numPages;
- nTces += numPages;
- prevEndPage = endPage;
- sg++;
- }
- return nTces;
-}
-
-/* Fill in the dma data in the scatterlist
- * return the number of dma sg entries created
- */
-static unsigned fill_scatterlist_sg( struct scatterlist *sg, int nents,
- dma_addr_t dma_addr , unsigned long numTces)
-{
- struct scatterlist *dma_sg;
- u32 cur_start_dma;
- unsigned long cur_len_dma, cur_end_virt, uaddr;
- unsigned num_dma_ents;
-
- dma_sg = sg;
- num_dma_ents = 1;
-
- /* Process the first sg entry */
- cur_start_dma = dma_addr + ((unsigned long)sg->address & (~PAGE_MASK));
- cur_len_dma = sg->length;
- /* cur_end_virt holds the address of the byte immediately after the
- * end of the current buffer.
- */
- cur_end_virt = (unsigned long)sg->address + cur_len_dma;
- /* Later code assumes that unused sg->dma_address and sg->dma_length
- * fields will be zero. Other archs seem to assume that the user
- * (device driver) guarantees that...I don't want to depend on that
- */
- sg->dma_address = sg->dma_length = 0;
-
- /* Process the rest of the sg entries */
- while (--nents) {
- ++sg;
- /* Clear possibly unused fields. Note: sg >= dma_sg so
- * this can't be clearing a field we've already set
- */
- sg->dma_address = sg->dma_length = 0;
-
- /* Check if it is possible to make this next entry
- * contiguous (in dma space) with the previous entry.
- */
-
- /* The entries can be contiguous in dma space if
- * the previous entry ends immediately before the
- * start of the current entry (in virtual space)
- * or if the previous entry ends at a page boundary
- * and the current entry starts at a page boundary.
- */
- uaddr = (unsigned long)sg->address;
- if ( ( uaddr != cur_end_virt ) &&
- ( ( ( uaddr | cur_end_virt ) & (~PAGE_MASK) ) ||
- ( ( uaddr & PAGE_MASK ) == ( ( cur_end_virt-1 ) & PAGE_MASK ) ) ) ) {
- /* This entry can not be contiguous in dma space.
- * save the previous dma entry and start a new one
- */
- dma_sg->dma_address = cur_start_dma;
- dma_sg->dma_length = cur_len_dma;
-
- ++dma_sg;
- ++num_dma_ents;
-
- cur_start_dma += cur_len_dma-1;
- /* If the previous entry ends and this entry starts
- * in the same page then they share a tce. In that
- * case don't bump cur_start_dma to the next page
- * in dma space. This matches assumptions made in
- * num_tces_sg and create_tces_sg.
- */
- if ((uaddr & PAGE_MASK) == ((cur_end_virt-1) & PAGE_MASK))
- cur_start_dma &= PAGE_MASK;
- else
- cur_start_dma = PAGE_ALIGN(cur_start_dma+1);
- cur_start_dma += ( uaddr & (~PAGE_MASK) );
- cur_len_dma = 0;
- }
- /* Accumulate the length of this entry for the next
- * dma entry
- */
- cur_len_dma += sg->length;
- cur_end_virt = uaddr + sg->length;
- }
- /* Fill in the last dma entry */
- dma_sg->dma_address = cur_start_dma;
- dma_sg->dma_length = cur_len_dma;
-
- if ((((cur_start_dma +cur_len_dma - 1)>> PAGE_SHIFT) - (dma_addr >> PAGE_SHIFT) + 1) != numTces)
- {
- printk("fill_scatterlist_sg: numTces %ld, used tces %d\n",
- numTces,
- (unsigned)(((cur_start_dma + cur_len_dma - 1) >> PAGE_SHIFT) - (dma_addr >> PAGE_SHIFT) + 1));
- }
-
-
- return num_dma_ents;
-}
-
-/* Call the hypervisor to create the TCE entries.
- * return the number of TCEs created
- */
-static dma_addr_t create_tces_sg( struct TceTable *tbl, struct scatterlist *sg,
- int nents, unsigned numTces, int tceType, int direction )
-{
- unsigned order, i, j;
- unsigned long startPage, endPage, prevEndPage, numPages, uaddr;
- long tcenum, starttcenum;
- dma_addr_t dmaAddr;
-
- dmaAddr = NO_TCE;
-
- order = get_order( numTces << PAGE_SHIFT );
- /* allocate a block of tces */
- tcenum = alloc_tce_range( tbl, order );
- if ( tcenum != -1 ) {
- tcenum += tbl->startOffset;
- starttcenum = tcenum;
- dmaAddr = tcenum << PAGE_SHIFT;
- prevEndPage = 0;
- for (j=0; jaddress >> PAGE_SHIFT;
- endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT;
- numPages = endPage - startPage + 1;
-
- uaddr = (unsigned long)sg->address;
-
- /* If the previous entry ended in the same page that
- * the current page starts then they share that
- * tce and we reduce the number of tces we need
- * by one. This matches assumptions made in
- * num_tces_sg and fill_scatterlist_sg
- */
- if ( startPage == prevEndPage ) {
- --numPages;
- uaddr += PAGE_SIZE;
- }
-
- for (i=0; idma_address = pci_map_single( hwdev, sg->address,
- sg->length, direction );
- sg->dma_length = sg->length;
- return 1;
- }
-
- if ( direction == PCI_DMA_NONE )
- BUG();
-
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL ) {
- bus = 255;
- tceType = TCE_VB;
- }
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = ISERIES_GET_BUS( hwdev );
- tceType = TCE_PCI;
-#else
- BUG();
- return 0;
-#endif /* CONFIG_PCI */
- }
-
- tbl = tceTables[bus];
-
- if ( tbl ) {
- /* Compute the number of tces required */
- numTces = num_tces_sg( sg, nents );
- /* Create the tces and get the dma address */
- dma_handle = create_tces_sg( tbl, sg, nents, numTces,
- tceType, direction );
-
- /* Fill in the dma scatterlist */
- num_dma = fill_scatterlist_sg( sg, nents, dma_handle, numTces );
- }
-
- return num_dma;
-}
-
-void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int direction )
-{
- struct TceTable * tbl;
- unsigned order, numTces, bus, i;
- dma_addr_t dma_end_page, dma_start_page;
-
- if ( direction == PCI_DMA_NONE )
- BUG();
-
- dma_start_page = sg->dma_address & PAGE_MASK;
- for ( i=nelms; i>0; --i ) {
- unsigned k = i - 1;
- if ( sg[k].dma_length ) {
- dma_end_page = ( sg[k].dma_address +
- sg[k].dma_length - 1 ) & PAGE_MASK;
- break;
- }
- }
-
- numTces = ((dma_end_page - dma_start_page ) >> PAGE_SHIFT) + 1;
- order = get_order( numTces << PAGE_SHIFT );
-
- if ( order > 10 )
- printk("pci_unmap_sg: order=%d, numTces=%d, nelms=%d, dma_start_page=%016lx, dma_end_page=%016lx\n",
- order, numTces, nelms, (unsigned long)dma_start_page, (unsigned long)dma_end_page );
-
-
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL )
- bus = 255;
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = ISERIES_GET_BUS( hwdev );
-#else
- BUG();
- return;
-#endif /* CONFIG_PCI */
- }
-
- if ( bus > 255 ) {
- printk("pci_unmap_sg: invalid bus # %d\n", bus );
- printk("pci_unmap_sg: hwdev = %08lx\n", (unsigned long)hwdev );
- }
-
-
- tbl = tceTables[bus];
-
- if ( tbl )
- free_tces( tbl, dma_start_page, order, numTces );
-
-}
-
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/iSeries_irq.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_irq.c
--- linux/arch/ppc64/kernel/iSeries_irq.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_irq.c Fri Aug 24 17:23:13 2001
@@ -0,0 +1,256 @@
+/************************************************************************/
+/* This module supports the iSeries PCI bus interrupt handling */
+/* 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 13, 2000 by Wayne Holm */
+/* End Change Activity */
+/************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+//#include
+
+#include
+#include
+#include
+//#include
+
+
+hw_irq_controller iSeries_IRQ_handler = {
+ "iSeries irq controller",
+ iSeries_startup_IRQ, /* startup */
+ iSeries_shutdown_IRQ, /* shutdown */
+ iSeries_enable_IRQ, /* enable */
+ iSeries_disable_IRQ, /* disable */
+ NULL, /* ack */
+ iSeries_end_IRQ, /* end */
+ NULL /* set_affinity */
+};
+
+
+struct iSeries_irqEntry {
+ u32 dsa;
+ struct iSeries_irqEntry* next;
+};
+
+struct iSeries_irqAnchor {
+ u8 valid : 1;
+ u8 reserved : 7;
+ u16 entryCount;
+ struct iSeries_irqEntry* head;
+};
+
+struct iSeries_irqAnchor iSeries_irqMap[NR_IRQS];
+
+void iSeries_init_irqMap(int irq);
+
+/* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c */
+void __init iSeries_init_IRQ(void)
+{
+
+ int i;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc[i].handler = &iSeries_IRQ_handler;
+ irq_desc[i].status = 0;
+ irq_desc[i].status |= IRQ_DISABLED;
+ irq_desc[i].depth = 1;
+ iSeries_init_irqMap(i);
+ }
+
+ /* Register PCI event handler and open an event path */
+ XmPciLpEvent_init();
+
+ return;
+}
+
+/* Called by iSeries_init_IRQ */
+void __init iSeries_init_irqMap(int irq) {
+ /* Prevent IRQs 0 and 255 from being used. IRQ 0 appears in
+ uninitialized devices. IRQ 255 appears in the PCI interrupt
+ line register if a PCI error occurs */
+ iSeries_irqMap[irq].valid = (irq == 0 || irq == 255)? 0 : 1;
+ iSeries_irqMap[irq].entryCount = 0;
+ iSeries_irqMap[irq].head = NULL;
+}
+
+/* This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot */
+int __init iSeries_allocate_IRQ(HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId) {
+
+ u8 idsel = (deviceId >> 4);
+ u8 function = deviceId & 0x0F;
+ int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 254) + 1;
+ return irq;
+}
+
+/* This is called out of iSeries_scan_slot to assign the EADS slot to its IRQ number */
+int __init iSeries_assign_IRQ(int irq, HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId) {
+
+ int rc;
+ u32 dsa = (busNumber << 16) | (subBusNumber << 8) | deviceId;
+ struct iSeries_irqEntry* newEntry;
+ unsigned long flags;
+
+ if (irq < 0 || irq >= NR_IRQS)
+ return -1;
+
+ newEntry = kmalloc(sizeof(*newEntry), GFP_KERNEL);
+ if (newEntry == NULL)
+ return -ENOMEM;
+ newEntry->dsa = dsa;
+ newEntry->next = NULL;
+
+ /* Probably not necessary to lock the irq since allocation is only
+ done during buswalk, but it should not hurt anything except a little
+ performance */
+ spin_lock_irqsave(&irq_desc[irq].lock, flags);
+
+ if (iSeries_irqMap[irq].valid) {
+ /* Push the new element onto the irq stack */
+ newEntry->next = iSeries_irqMap[irq].head;
+ iSeries_irqMap[irq].head = newEntry;
+ ++iSeries_irqMap[irq].entryCount;
+ rc = 0;
+ }
+ else
+ rc = -1;
+
+ spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+
+ if (rc != 0 && newEntry)
+ kfree(newEntry);
+
+ return rc;
+
+}
+
+
+/* This is called by iSeries_activate_IRQs */
+unsigned int iSeries_startup_IRQ(unsigned int irq) {
+ struct iSeries_irqEntry* entry;
+ u32 bus, subBus, deviceId, function, mask;
+
+ /* irq should be locked by the caller */
+
+ for(entry=iSeries_irqMap[irq].head; entry!=NULL; entry=entry->next) {
+ bus = (entry->dsa >> 16) & 0xFFFF;
+ subBus = (entry->dsa >> 8) & 0xFF;
+ deviceId = entry->dsa & 0xFF;
+ function = deviceId & 0x0F;
+ /* Link the IRQ number to the bridge */
+ HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
+ /* Unmask bridge interrupts in the FISR */
+ mask = 0x01010000 << function;
+ HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
+ }
+
+ return 0;
+}
+
+/* This is called out of iSeries_fixup to
+ activate interrupt generation for usable slots */
+void __init iSeries_activate_IRQs() {
+ int irq;
+ unsigned long flags;
+
+ for (irq=0; irq < NR_IRQS; irq++) {
+ spin_lock_irqsave(&irq_desc[irq].lock, flags);
+ irq_desc[irq].handler->startup(irq);
+ spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+ }
+
+}
+
+/* this is not called anywhere currently */
+void iSeries_shutdown_IRQ(unsigned int irq) {
+ struct iSeries_irqEntry* entry;
+ u32 bus, subBus, deviceId, function, mask;
+
+ /* irq should be locked by the caller */
+
+ for(entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
+ bus = (entry->dsa >> 16) & 0xFFFF;
+ subBus = (entry->dsa >> 8) & 0xFF;
+ deviceId = entry->dsa & 0xFF;
+ function = deviceId & 0x0F;
+ /* Invalidate the IRQ number in the bridge */
+ HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
+ /* Mask bridge interrupts in the FISR */
+ mask = 0x01010000 << function;
+ HvCallPci_maskFisr(bus, subBus, deviceId, mask);
+ }
+
+}
+
+
+/* This will be called by device drivers (via disable_IRQ to disable
+ INTA in the bridge interrupt status register */
+void iSeries_disable_IRQ(unsigned int irq) {
+ struct iSeries_irqEntry* entry;
+ u32 bus, subBus, deviceId, mask;
+
+ /* The IRQ has already been locked by the caller */
+
+ for(entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
+ bus = (entry->dsa >> 16) & 0xFFFF;
+ subBus = (entry->dsa >> 8) & 0xFF;
+ deviceId = entry->dsa & 0xFF;
+ /* Mask secondary INTA */
+ mask = 0x80000000;
+ HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
+ }
+}
+
+/* This will be called by device drivers (via enable_IRQ to enable
+ INTA in the bridge interrupt status register */
+void iSeries_enable_IRQ(unsigned int irq) {
+ struct iSeries_irqEntry* entry;
+ u32 bus, subBus, deviceId, mask;
+
+ /* The IRQ has already been locked by the caller */
+
+ for(entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
+ bus = (entry->dsa >> 16) & 0xFFFF;
+ subBus = (entry->dsa >> 8) & 0xFF;
+ deviceId = entry->dsa & 0xFF;
+ /* Unmask secondary INTA */
+ mask = 0x80000000;
+ HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
+ }
+}
+
+/* Need to define this so ppc_irq_dispatch_handler will NOT call
+ enable_IRQ at the end of interrupt handling. However, this
+ does nothing because there is not enough information provided
+ to do the EOI HvCall. This is done by XmPciLpEvent.c */
+void iSeries_end_IRQ(unsigned int irq) {
+}
+
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/iSeries_pci.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_pci.c
--- linux/arch/ppc64/kernel/iSeries_pci.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_pci.c Mon Sep 10 14:27:51 2001
@@ -27,58 +27,47 @@
#include
#include
#include
-#include
#include
#include
-#include
+//#include
#include
#include
-//#include
#include
-#include
+//#include
#include
#include
#include
-//#include
-#include
#include
-#include
-#include
#include
+#include
+#include
#include
+#include
#include
#include
+#include
+#include "iSeries_IoMmTable.h"
#include "pci.h"
extern struct pci_controller* hose_head;
extern struct pci_controller** hose_tail;
+extern int global_phb_number;
+extern int panic_timeout;
+
extern struct Naca *naca;
extern struct device_node *allnodes;
extern unsigned long phb_tce_table_init(struct pci_controller *phb);
+extern unsigned long iSeries_Base_Io_Memory;
extern struct pci_ops iSeries_pci_ops;
extern struct flightRecorder* PciFr;
int PciTraceFlag = 0;
-
-struct pci_dev;
-
-struct i_device_node {
- struct list_head iDevice_Chain;
- char* Name;
- char* Type;
- struct pci_dev* PciDev;
- int BusNumber;
- int SubBus;
- int ReturnCode;
- int DevFn;
-};
-
-LIST_HEAD(iDevice_List);
+extern void iSeries_MmIoTest(void);
/*******************************************************************
* Forward declares of prototypes.
@@ -91,57 +80,168 @@
void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb);
void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgents);
+void list_device_nodes(void);
+
+
+struct pci_dev;
+
+/* struct DsaAddr (64-bits total)
+ * u16 busNumber; 48
+ * u8 subBusNumber; 40
+ * u8 deviceId; 32
+ * u8 barNumber; 24
+ * u8 reserved[3];
+ */
+
+struct iSeries_Device_Node {
+ struct list_head Device_List; /* Must be first to allow cast to work. */
+ struct pci_dev* PciDev;
+ char* Name;
+ char* Type;
+ u64 DsaAddr;
+ int BusNumber;
+ int SubBus;
+ int AgentId;
+ int DevFn;
+ int Irq;
+ int ReturnCode;
+ int IoRetry;
+ int Flags;
+ u16 Vendor;
+ char* Location;
+ int DeviceNumber;
+};
+
+LIST_HEAD(Global_Device_List);
+
+int DeviceCount = 0;
/**********************************************************************************
+ * Dump the iSeries Temp Device Node
+ *<4>buswalk [swapper : - DeviceNode: 0xC000000000634300
+ *<4>00. Device Node = 0xC000000000634300
+ *<4> - PciDev = 0x0000000000000000
+ *<4> - tDevice = 0x 17:01.00 0x1022 00
+ *<4> 4. Device Node = 0xC000000000634480
+ *<4> - PciDev = 0x0000000000000000
+ *<4> - Device = 0x 18:38.16 Irq:0xA7 Vendor:0x1014 Flags:0x00
+ *<4> - Devfn = 0xB0: 22.18
+ **********************************************************************************/
+void dumpDevice_Node(struct iSeries_Device_Node* DeviceNode) {
+ udbg_printf("%3d. Device Node = 0x%016LX\n",DeviceNode->DeviceNumber, DeviceNode);
+ udbg_printf(" - PciDev = 0x%016LX\n",DeviceNode->PciDev);
+ udbg_printf(" - Device = 0x%4X:%02X.%02X (0x%02X)\n",
+ DeviceNode->BusNumber,
+ DeviceNode->SubBus,
+ DeviceNode->AgentId, DeviceNode->DevFn);
+ udbg_printf(" = Irq:0x%02X Vendor:0x%04X Flags:0x%02X\n",
+ DeviceNode->Irq,
+ DeviceNode->Vendor,
+ DeviceNode->Flags );
+}
+/**********************************************************************************
+ * Walk down the device node chain
+ **********************************************************************************/
+void list_device_nodes(void) {
+ struct list_head* Device_Node_Ptr = Global_Device_List.next;
+ while(Device_Node_Ptr != &Global_Device_List) {
+ dumpDevice_Node( (struct iSeries_Device_Node*)Device_Node_Ptr );
+ Device_Node_Ptr = Device_Node_Ptr->next;
+ }
+}
+
+
+/***********************************************************************
+ * build_device_node(u16 Bus, int SubBus, u8 DevFn)
*
- *
+ ***********************************************************************/
+struct iSeries_Device_Node* build_device_node(HvBusNumber Bus, HvSubBusNumber SubBus, int AgentId) {
+ struct iSeries_Device_Node* DeviceNode;
+
+ PPCDBG(PPCDBG_BUSWALK,"- "__FUNCTION__" 0x%02X.%02X.%02X\n",Bus,SubBus,AgentId);
+
+ DeviceNode = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL);
+ if(DeviceNode == NULL) return NULL;
+
+ memset(DeviceNode,0,sizeof(struct iSeries_Device_Node) );
+ list_add_tail(&DeviceNode->Device_List,&Global_Device_List);
+ DeviceNode->DsaAddr = ((u64)Bus<<48)+((u64)SubBus<<40)+((u64)0x10<<32);
+ DeviceNode->BusNumber = Bus;
+ DeviceNode->SubBus = SubBus;
+ DeviceNode->AgentId = AgentId;
+ DeviceNode->DevFn = AgentId<<3;
+ DeviceNode->DeviceNumber = DeviceCount;
+ DeviceNode->IoRetry = 0;
+ return DeviceNode;
+}
+
+
+/**********************************************************************************
+ * Look down the chain to find the matching Device Device
**********************************************************************************/
-#define ISERIES_PCI_READ_OP(size, call, type) \
-/***********************************************************************************/ \
-int iSeries_pci_read_config_##size(struct pci_dev* PciDev, int PciOffset, type ReadValue) { \
- struct i_device_node* DeviceNode = PciDev->sysdata; \
- if(DeviceNode->BusNumber == 0xFF) DeviceNode->ReturnCode = 0x301; return DeviceNode->ReturnCode; \
- DeviceNode->ReturnCode = HvCallPci_config##call(DeviceNode->BusNumber, DeviceNode->SubBus, \
- DeviceNode->DevFn, PciOffset, ReadValue); \
- if(DeviceNode->ReturnCode != 0 ) { \
- PCIFR("RC##size: %02X,%02X,%02X,%04X Rtn: %04X", \
- DeviceNode->BusNumber, DeviceNode->SubBus, DeviceNode->DevFn, PciOffset,DeviceNode->ReturnCode); \
- } \
- return DeviceNode->ReturnCode; \
-}
-/***********************************************************************************/ \
-#define ISERIES_PCI_WRITE_OP(size, call, type) \
-/***********************************************************************************/ \
-int iSeries_pci_write_config_##size(struct pci_dev* PciDev, int PciOffset, type WriteValue) { \
- struct i_device_node* DeviceNode = PciDev->sysdata; \
- DeviceNode->ReturnCode = HvCallPci_config##call(DeviceNode->BusNumber, DeviceNode->SubBus, \
- DeviceNode->DevFn, PciOffset, WriteValue); \
- if(DeviceNode->ReturnCode != 0 ) { \
- PCIFR("RC##size: %02X,%02X,%02X,%04X Rtn: %04X", \
- DeviceNode->BusNumber, DeviceNode->SubBus, DeviceNode->DevFn, PciOffset,DeviceNode->ReturnCode); \
- } \
- return DeviceNode->ReturnCode; \
-}
-
- ISERIES_PCI_READ_OP( byte, Load8, u8*)
- ISERIES_PCI_READ_OP( word, Load16, u16*)
- ISERIES_PCI_READ_OP( dword,Load32, u32*)
- ISERIES_PCI_WRITE_OP(byte, Store8, u8)
- ISERIES_PCI_WRITE_OP(word, Store16,u16)
- ISERIES_PCI_WRITE_OP(dword,Store32,u32)
+struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev) {
+ struct list_head* Device_Node_Ptr;
+ int Bus, DevFn;
+
+ Device_Node_Ptr = Global_Device_List.next;
+ Bus = PciDev->bus->number;
+ DevFn = PciDev->devfn;
+
+ while(Device_Node_Ptr != &Global_Device_List) {
+ struct iSeries_Device_Node* DeviceNode = (struct iSeries_Device_Node*)Device_Node_Ptr;
+ if(Bus == DeviceNode->BusNumber && DevFn == DeviceNode->DevFn) {
+ return DeviceNode;
+ }
+ Device_Node_Ptr = Device_Node_Ptr->next;
+ }
+ return NULL;
+}
+struct iSeries_Device_Node* find_Device_Nodex(int Bus, int DevFn) {
+ struct pci_dev TempPciDev;
+ struct pci_bus TempBus;
+
+ TempBus.number = Bus;
+ TempPciDev.bus = &TempBus;
+ TempPciDev.devfn = DevFn;
+ return find_Device_Node(&TempPciDev);
+}
-/************************************************************************/
-/* Branch Table */
-/************************************************************************/
-struct pci_ops iSeries_pci_ops = {
- iSeries_pci_read_config_byte,
- iSeries_pci_read_config_word,
- iSeries_pci_read_config_dword,
- iSeries_pci_write_config_byte,
- iSeries_pci_write_config_word,
- iSeries_pci_write_config_dword
-};
-
+/**********************************************************************************
+ * check to see if the it is a pci_dev or device_node passed.
+ **********************************************************************************/
+struct iSeries_Device_Node* check_Device_Node(struct pci_dev* PciDev) {
+ struct iSeries_Device_Node* DeviceNode= (struct iSeries_Device_Node*)PciDev->sysdata;
+ if(PciDev == DeviceNode->PciDev) return DeviceNode;
+ else return find_Device_Node(PciDev);
+}
+
+/****************************************************************************
+*
+* Allocate pci_controller(phb) initialized common variables.
+*
+*****************************************************************************/
+struct pci_controller* pci_alloc_pci_controllerX(char *model, enum phb_types controller_type)
+{
+ struct pci_controller *hose;
+ PPCDBG(PPCDBG_PHBINIT, "PCI: Allocate pci_controller for %s\n",model);
+
+ hose = (struct pci_controller*)kmalloc(sizeof(struct pci_controller), GFP_KERNEL);
+
+ if(hose == NULL) {
+ printk(KERN_ERR "PCI: Allocate pci_controller failed.\n");
+ return NULL;
+ }
+ memset(hose, 0, sizeof(struct pci_controller));
+ if(strlen(model) < 8) strcpy(hose->what,model);
+ else memcpy(hose->what,model,7);
+ hose->type = controller_type;
+ hose->global_number = global_phb_number;
+ global_phb_number++;
+
+ *hose_tail = hose;
+ hose_tail = &hose->next;
+ return hose;
+}
/****************************************************************************
*
@@ -154,9 +254,8 @@
* owned or fully owned by this guest partition.
****************************************************************************/
unsigned long __init find_and_init_phbs(void) {
- struct pci_controller* hose;
+ struct pci_controller* phb;
HvBusNumber BusNumber;
- int LxBusNumber = 0; /* Linux Bus number for grins */
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry\n");
@@ -173,37 +272,22 @@
PPCDBG(PPCDBG_BUSWALK, "Create iSeries PHB controller: %04X\n",BusNumber);
PCIFR("Create iSeries PHB controller: %04X",BusNumber);
- PPCDBG(PPCDBG_BUSWALK, "PCI: Allocate pci_controller for PBH HV\n");
- hose = (struct pci_controller *)kmalloc(sizeof(struct pci_controller),GFP_KERNEL);
- if(hose == NULL) {
+ phb = pci_alloc_pci_controllerX("PHB HV", phb_type_hypervisor);
+ if(phb == NULL) {
printk("PCI: Allocate pci_controller failed.\n");
PCIFR( "PCI: Allocate pci_controller failed.\n");
return -1;
}
- memset(hose, 0, sizeof(struct pci_controller));
- *hose_tail = hose;
- hose_tail = &hose->next;
- strcpy(hose->what,"PHB HV");
- hose->type = phb_type_hypervisor;
- hose->global_number = BusNumber;
- *hose_tail = hose;
- hose_tail = &hose->next;
-
- hose->local_number = BusNumber; /* Stuff HV bus number away. */
- hose->first_busno = LxBusNumber;/* This just for debug. pcibios will */
- hose->last_busno = 0xff; /* assign the bus numbers later. */
- hose->ops = &iSeries_pci_ops; /* Cnfg Reg Ops routines. */
- LxBusNumber += 1; /* Keep track for debug. */
-
- /*********************/
- /* TCE Table for Bus */
- /*********************/
- //create_pci_bus_tce_table(BusNumber);
+ phb->pci_mem_offset =
+ phb->local_number = BusNumber; /* Stuff HV bus number away. */
+ phb->first_busno = BusNumber;
+ phb->last_busno = BusNumber;
+ phb->ops = &iSeries_pci_ops; /* Cnfg Reg Ops routines. */
/*************************************************************************
* Find and connect the devices.
*************************************************************************/
- iSeries_Scan_PHBs_Slots(hose);
+ iSeries_Scan_PHBs_Slots(phb);
}
}
@@ -216,27 +300,70 @@
*
***********************************************************************/
void iSeries_pcibios_init(void) {
+ struct pci_controller *phb;
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry.\n");
- /* find_and_init_phbs(); comment out until debugged. */
+
+ iSeries_IoMmTable_Initialize();
+ return;
+
+ find_and_init_phbs();
+
+ PPCDBG(PPCDBG_BUSWALK,"\nList PHBs found.\n");
+ phb = hose_head;
+ while(phb != NULL) {
+ PPCDBG(PPCDBG_BUSWALK,"pci_controller(0x%016LX) for Bus 0x%02X\n",phb,phb->first_busno);
+ phb = phb->next;
+ }
+
+ PPCDBG(PPCDBG_BUSWALK,"\nList Device Tree.\n");
+ list_device_nodes();
+
+ pci_assign_all_busses = 0;
+
PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Exit.\n");
}
/***********************************************************************
* iSeries_pcibios_fixup(void)
- *
- *
- *
***********************************************************************/
void __init iSeries_pcibios_fixup(void) {
- struct pci_dev *dev;
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry.\n");
- return; /* Just return until debugged. */
+ struct pci_dev* PciDev;
+ struct iSeries_Device_Node* DeviceNode;
- pci_assign_all_busses = 0;
+ PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry.\n");
- pci_for_each_dev(dev) {
- PPCDBGCALL(PPCDBG_BUSWALK, dumpPci_Dev(dev) );
+ /******************************************************/
+ /* Fix up at the device node and pci_dev relationship */
+ /******************************************************/
+ pci_for_each_dev(PciDev) {
+ DeviceNode = find_Device_Node(PciDev);
+ if(DeviceNode != NULL) {
+ PciDev->sysdata = (void*)DeviceNode;
+ DeviceNode->PciDev = PciDev;
+ iSeries_allocateDeviceBars(PciDev);
+ } else {
+ printk("PCI: Device Tree not found for 0x%016lX\n",(unsigned long)PciDev);
+ }
}
+ iSeries_IoMmTable_Status();
+
+
+ // pci_for_each_dev(PciDev) {
+ // if (PciConfigTest(PciDev) != 0) panic("PCI: PciConfigTest Failed.\n");
+ //}
+ //iSeries_MmIoTest();
+
+ iSeries_activate_IRQs();
+}
+
+
+/***********************************************************************
+ * iSeries_pcibios_fixup_bus(int Bus)
+ *
+ ***********************************************************************/
+void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus) {
+ PPCDBG(PPCDBG_BUSWALK,__FUNCTION__"(0x%04X) Entry.\n",PciBus->number);
+
}
/***********************************************************************
* find_floppy(void)
@@ -248,7 +375,7 @@
***********************************************************************/
struct pci_dev*
find_floppy() {
- PPCDBG(PPCDBG_BUSWALK,"\tFind Floppy pci_dev.. None on iSeries.\n");
+ PPCDBG(PPCDBG_BUSWALK,"- Find Floppy pci_dev.. None on iSeries.\n");
return NULL;
}
@@ -260,53 +387,13 @@
*
*
***********************************************************************/
-void
-fixup_resources(struct pci_dev *dev) {
- struct pci_controller* phb = (struct pci_controller *)dev->sysdata;
-
- PPCDBG(PPCDBG_BUSWALK, "fixup_resources:\n");
- PPCDBG(PPCDBG_BUSWALK, "\tphb = 0x%016LX\n", phb);
- PPCDBG(PPCDBG_BUSWALK, "\tphb->local_number = 0x%004X \n", phb->local_number);
+void fixup_resources(struct pci_dev *PciDev) {
+ PPCDBG(PPCDBG_BUSWALK,__FILE__" "__FUNCTION__" PciDev 0x%016X\n",PciDev);
}
-/***********************************************************************
- * build_device_node(u16 Bus, int SubBus, u8 DevFn)
- *
- *
- * char* loc-code
- * int vendor-id
- * int device-id..
- * int BusNumber
- * int SubBus
- * int ReturnCode
- *
- * int regs
- * int interrupts
- * char* loc-code
- ***********************************************************************/
-void
-build_device_node(HvBusNumber BusNumber, HvSubBusNumber SubBus, u8 DevFn) {\
- struct i_device_node* iDevice = kmalloc(sizeof(struct i_device_node), GFP_KERNEL);
- list_add_tail(&iDevice->iDevice_Chain,&iDevice_List);
-
-
-
-}
-
-void list_device_nodes(void) {
- struct list_head* iDevice_Node_Ptr = iDevice_List.next;
- int index = 1;
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry\n");
- while(iDevice_Node_Ptr != &iDevice_List) {
- iDevice_Node_Ptr = iDevice_Node_Ptr->next;
- ++index;
- }
-}
-
-
/********************************************************************************
-* Loop through each node function to find usable bridges.
+* Loop through each node function to find usable EADs bridges.
*********************************************************************************/
void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb) {
struct HvCallPci_DeviceInfo* DevInfo;
@@ -316,8 +403,6 @@
int IdSel = 1;
int MaxAgents = 8;
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry\n");
-
DevInfo = (struct HvCallPci_DeviceInfo*)kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
if(DevInfo == NULL) return;
@@ -327,18 +412,15 @@
for (IdSel=1; IdSel < MaxAgents; ++IdSel) {
HvRc = HvCallPci_getDeviceInfo(Bus, SubBus, IdSel,REALADDR(DevInfo), sizeof(struct HvCallPci_DeviceInfo));
if (HvRc == 0) {
- PPCDBG(PPCDBG_BUSWALK,"\tFound Device 0x%02X\n",DevInfo->deviceType);
if(DevInfo->deviceType == HvCallPci_NodeDevice) {
- PPCDBG(PPCDBG_BUSWALK,"\tFound EADs Bridge(NodeDevice)\n");
iSeries_Scan_EADs_Bridge(Bus, SubBus, IdSel);
}
else {
- printk("PCI: Invalid System Configuration. \n");
+ printk("PCI: Invalid System Configuration(0x%02X.\n",DevInfo->deviceType);
}
}
}
kfree(DevInfo);
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Exit\n");
}
@@ -351,8 +433,6 @@
int Function;
int HvRc;
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry\n");
-
BridgeInfo = (struct HvCallPci_BridgeInfo*)kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL);
if(BridgeInfo == NULL) return;
@@ -363,41 +443,45 @@
AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, 0);
if (HvRc == 0) {
+ /* Connect EADs: 0x18.00.12 = 0x00 */
PPCDBG(PPCDBG_BUSWALK,"Connect EADs: 0x%02X.%02X.%02X = 0x%02X\n",Bus, SubBus, AgentId);
HvRc = HvCallPci_getBusUnitInfo(Bus, SubBus, AgentId,
REALADDR(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo));
if (HvRc == 0) {
- PPCDBG(PPCDBG_BUSWALK,"\tBridgeInfo..: 0x%02X.%02X.%02X = 0x%02X\n",Bus, SubBus, AgentId,
- BridgeInfo->busUnitInfo.deviceType);
-
if (BridgeInfo->busUnitInfo.deviceType == HvCallPci_BridgeDevice) {
- PPCDBG(PPCDBG_BUSWALK,"\tScan_Bridge_Slot...: 0x%02X.%02X.%02X\n",Bus, SubBus, AgentId);
+ /* Scan_Bridge_Slot...: 0x18.00.12 */
+ //PPCDBG(PPCDBG_BUSWALK,"\tScan_Bridge_Slot...: 0x%02X.%02X.%02X\n",Bus, SubBus, AgentId);
iSeries_Scan_Bridge_Slot(Bus, BridgeInfo->subBusNumber,BridgeInfo->maxAgents);
}
+ else {
+ printk("PCI: Invalid Bridge Configuration(0x%02X)\n",BridgeInfo->busUnitInfo.deviceType);
+ }
}
}
}
kfree(BridgeInfo);
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Exit\n");
}
/********************************************************************************
*
* This assumes that the node slot is always on the primary bus!
+*
*********************************************************************************/
int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgents) {
+ struct iSeries_Device_Node* DeviceNode;
u16 VendorId = 0;
int HvRc = 0;
int Irq = 0;
int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
- int ValidSlots = 0;
+ HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);
+ int FirstSlotId= 0;
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry\n");
-
+ /**********************************************************/
+ /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
+ /**********************************************************/
Irq = iSeries_allocate_IRQ(Bus, 0, AgentId);
- PPCDBG(PPCDBG_BUSWALK,"\tiSeries_allocate_IRQ.: 0x%02X.%02X.%02X(0x%02X)\n", Bus, SubBus, AgentId, Irq);
/****************************************************************************
* Connect all functions of any device found.
@@ -407,25 +491,358 @@
AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, Irq);
if (HvRc == 0) {
- PPCDBG(PPCDBG_BUSWALK,"\tConnect....: 0x%02X.%02X.%02X Irq: 0x%02X\n",Bus, SubBus, AgentId, Irq);
HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId, PCI_VENDOR_ID, &VendorId);
if (HvRc == 0) {
- PPCDBG(PPCDBG_BUSWALK,"\tVendorId...: 0x%02X.%02X.%02X = 0x%04X\n",Bus, SubBus, AgentId, VendorId);
- ++ValidSlots;
+ /**********************************************************/
+ /* FoundDevice: 0x18.28.10 = 0x12AE */
+ /**********************************************************/
+ HvCallPci_configStore8(Bus, SubBus, AgentId, PCI_INTERRUPT_LINE, Irq);
+ PPCDBG(PPCDBG_BUSWALK,"- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n",
+ Bus, SubBus, AgentId, VendorId);
+ ++DeviceCount;
+ PCIFR("Device(%4d): 0x%02X.%02X.%02X \n",DeviceCount,Bus, SubBus, AgentId);
+ DeviceNode = build_device_node(Bus, SubBus, EADsIdSel);
+ DeviceNode->Vendor = VendorId;
+ DeviceNode->Irq = Irq;
+
+ /***********************************************************
+ * On the first device/function, assign irq to slot
+ ***********************************************************/
+ if(Function == 0) {
+ FirstSlotId = AgentId;
+ iSeries_assign_IRQ(Irq, Bus, SubBus, AgentId);
+ PPCDBG(PPCDBG_BUSWALK,"- iSeries_assign_IRQ 0x%02X.%02X.%02X = 0x%02X\n",
+ Bus, SubBus, AgentId, Irq );
+ }
}
}
- if (HvRc != 0) {
- PPCDBG(PPCDBG_BUSWALK,"\tConnect/Read Vendor failed: 0x%02X.%02X.%02X = 0x%02X\n",Bus, SubBus, AgentId, HvRc);
- }
- }
- /****************************************************************************
- * If a device is found, assign irq to slot
- ****************************************************************************/
- if (ValidSlots > 0) {
- PPCDBG(PPCDBG_BUSWALK,"\tiSeries_assign_IRQ 0x%02X.%02X.%02X = 0x%02X\n",Bus, SubBus, AgentId, Irq );
- iSeries_assign_IRQ(Irq, Bus, SubBus, AgentId);
}
}
- PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Exit\n");
return HvRc;
+}
+/************************************************************************/
+/* I/0 Memory copy MUST use mmio commands on iSeries */
+/* To do; For performance, include the hv call directly */
+/************************************************************************/
+void* iSeries_memset(void* dest, char c, size_t Count) {
+ u8 ByteValue = c;
+ long NumberOfBytes = Count;
+ char* IoBuffer = dest;
+ while(NumberOfBytes > 0) {
+ iSeries_Write_Byte( ByteValue, (void*)IoBuffer );
+ ++IoBuffer;
+ -- NumberOfBytes;
+ }
+ return dest;
+}
+void* iSeries_memcpy_toio(void *dest, void *source, size_t count) {
+ char *dst = dest;
+ char *src = source;
+ long NumberOfBytes = count;
+ while(NumberOfBytes > 0) {
+ iSeries_Write_Byte(*src++, (void*)dst++);
+ -- NumberOfBytes;
+ }
+ return dest;
+}
+void* iSeries_memcpy_fromio(void *dest, void *source, size_t count) {
+ char *dst = dest;
+ char *src = source;
+ long NumberOfBytes = count;
+ while(NumberOfBytes > 0) {
+ *dst++ = iSeries_Read_Byte( (void*)src++);
+ -- NumberOfBytes;
+ }
+ return dest;
+}
+/**********************************************************************************
+ *
+ * Read PCI Config Space Code
+ *
+ **********************************************************************************/
+int iSeries_pci_read_config_byte(struct pci_dev* PciDev, int Offset, u8* ReadValue) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(PciDev);
+ u8 ReadData;
+ if(DeviceNode == NULL) { *ReadValue = -1; return 0x301; }
+ DeviceNode->ReturnCode = HvCallPci_configLoad8(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ Offset,&ReadData);
+ if(PciTraceFlag == 1) {
+ printk("RCB: 0x%02X.%02X 0x%04X = 0x%02X\n",DeviceNode->BusNumber,DeviceNode->DevFn,Offset,ReadData);
+ }
+ if(DeviceNode->ReturnCode != 0 ) {
+ printk("PCI: RCB (%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ PCIFR( "RCB (%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ }
+ *ReadValue = ReadData;
+ return DeviceNode->ReturnCode;
+}
+
+int iSeries_pci_read_config_word(struct pci_dev* PciDev, int Offset, u16* ReadValue) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(PciDev);
+ u16 ReadData;
+ if(DeviceNode == NULL) { *ReadValue = -1; return 0x301; }
+ DeviceNode->ReturnCode = HvCallPci_configLoad16(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ Offset,&ReadData);
+ if(PciTraceFlag == 1) {
+ printk("RCW: 0x%02X.%02X 0x%04X = 0x%04X\n",DeviceNode->BusNumber,DeviceNode->DevFn,Offset,ReadData);
+ }
+ if(DeviceNode->ReturnCode != 0 ) {
+ printk("PCI: RCW (%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ PCIFR( "RCW (%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ }
+ *ReadValue = ReadData;
+ return DeviceNode->ReturnCode;
+}
+int iSeries_pci_read_config_dword(struct pci_dev* PciDev, int Offset, u32* ReadValue) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(PciDev);
+ u32 ReadData;
+ if(DeviceNode == NULL) { *ReadValue = -1; return 0x301; }
+ DeviceNode->ReturnCode = HvCallPci_configLoad32(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ Offset,&ReadData);
+ if(PciTraceFlag == 1) {
+ printk("RCL: 0x%02X.%02X 0x%04X = 0x%08X\n",DeviceNode->BusNumber,DeviceNode->DevFn,Offset,ReadData);
+ }
+ if(DeviceNode->ReturnCode != 0 ) {
+ printk("PCI: RCL (%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ PCIFR( "RCL (%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ }
+ *ReadValue = ReadData;
+ return DeviceNode->ReturnCode;
+}
+/**********************************************************************************
+ *
+ * Write PCI Config Space Code
+ *
+ **********************************************************************************/
+int iSeries_pci_write_config_byte(struct pci_dev* PciDev, int Offset, u8 WriteData) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(PciDev);
+ if(DeviceNode == NULL) return 0x301;
+ DeviceNode->ReturnCode = HvCallPci_configStore8(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ Offset,WriteData);
+ if(PciTraceFlag == 1) {
+ printk("WCB: 0x%02X.%02X 0x%04X = 0x%02X\n",DeviceNode->BusNumber,DeviceNode->DevFn,Offset,WriteData);
+ }
+ if(DeviceNode->ReturnCode != 0 ) {
+ printk("PCI: WCB(%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ PCIFR( "WCB(%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ }
+ return DeviceNode->ReturnCode;
+}
+int iSeries_pci_write_config_word(struct pci_dev* PciDev, int Offset, u16 WriteData) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(PciDev);
+ if(DeviceNode == NULL) return 0x301;
+ DeviceNode->ReturnCode = HvCallPci_configStore16(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ Offset,WriteData);
+ if(PciTraceFlag == 1) {
+ printk("WCW: 0x%02X.%02X 0x%04X = 0x%04X\n",DeviceNode->BusNumber,DeviceNode->DevFn,Offset,WriteData);
+ }
+ if(DeviceNode->ReturnCode != 0 ) {
+ printk("PCI: WCW(%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ PCIFR( "WCW(%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ }
+ return DeviceNode->ReturnCode;
+}
+int iSeries_pci_write_config_dword(struct pci_dev* PciDev, int Offset, u32 WriteData) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(PciDev);
+ if(DeviceNode == NULL) return 0x301;
+ DeviceNode->ReturnCode = HvCallPci_configStore32(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ Offset,WriteData);
+ if(PciTraceFlag == 1) {
+ printk("WCL: 0x%02X.%02X 0x%04X = 0x%08X\n",DeviceNode->BusNumber,DeviceNode->DevFn,Offset,WriteData);
+ }
+ if(DeviceNode->ReturnCode != 0 ) {
+ printk("PCI: WCL(%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ PCIFR( "WCL(%016lX) = 0x%04X",DeviceNode->DsaAddr,DeviceNode->ReturnCode);
+ }
+ return DeviceNode->ReturnCode;
+}
+
+/************************************************************************/
+/* Branch Table */
+/************************************************************************/
+struct pci_ops iSeries_pci_ops = {
+ iSeries_pci_read_config_byte,
+ iSeries_pci_read_config_word,
+ iSeries_pci_read_config_dword,
+ iSeries_pci_write_config_byte,
+ iSeries_pci_write_config_word,
+ iSeries_pci_write_config_dword
+};
+
+int IoCounts = 0;
+int RetryMax = 7;
+/************************************************************************
+ * Check Return Code
+ * -> On Failure, print and log information.
+ * Increment Retry Count, if exceeds max, panic partition.
+ * -> If in retry, print and log success
+ ************************************************************************
+ * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
+ * PCI: Device 23.90 ReadL Retry( 1)
+ * PCI: Device 23.90 ReadL Retry Successful(1)
+ ************************************************************************/
+int CheckReturnCode(char* TextHdr, int OpCode, struct iSeries_Device_Node* DeviceNode) {
+ ++IoCounts;
+ if(DeviceNode->ReturnCode != 0) {
+ PCIFR("Device 0x%04X:%02X :%s%02d I/O Error(%2d): 0x%04X\n",
+ DeviceNode->BusNumber, DeviceNode->DevFn,TextHdr,OpCode,DeviceNode->IoRetry,DeviceNode->ReturnCode);
+ printk("Device 0x%04X:%02X :%s%02d I/O Error(%2d): 0x%04X\n",
+ DeviceNode->BusNumber, DeviceNode->DevFn,TextHdr,OpCode,DeviceNode->IoRetry,DeviceNode->ReturnCode);
+ /***************************************************************
+ * Bump the retry and check for retry count exceeded. *
+ * If, Exceeded, panic the system. *
+ ****************************************************************/
+ ++DeviceNode->IoRetry;
+ if(DeviceNode->IoRetry > RetryMax ) {
+ mf_displaySrc(0xB6000103);
+ panic_timeout = 0;
+ panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.\n");
+ }
+ }
+ /********************************************************************
+ * If retry was in progress, log success and rest retry count *
+ *********************************************************************/
+ else if(DeviceNode->IoRetry > 0) {
+ DeviceNode->IoRetry = 0;
+ PCIFR("Device 0x%04X:%02X %s Retry Successful(%2d).\n",DeviceNode->BusNumber, DeviceNode->DevFn,
+ TextHdr, DeviceNode->IoRetry);
+ DeviceNode->IoRetry = 0;
+ }
+ return DeviceNode->ReturnCode;
+}
+
+/************************************************************************/
+/* helper code until Todd and Al sync up. */
+/************************************************************************/
+struct iSeries_Device_Node* xlateIoMmAddress(void* IoAddress) {
+ struct pci_dev* PciDev = iSeries_xlateIoMmAddress(IoAddress);
+ return (struct iSeries_Device_Node*)PciDev->sysdata;
+}
+
+/************************************************************************/
+/* Read MM I/O Instructions for the iSeries */
+/* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal*/
+/* else, data is returned in big Endian format. */
+/************************************************************************/
+/* iSeries_Read_Byte = Read Byte ( 8 bit) */
+/* iSeries_Read_Word = Read Word (16 bit) */
+/* iSeries_Read_Long = Read Long (32 bit) */
+/************************************************************************/
+u8 iSeries_Read_Byte(void* IoAddress) {
+ u8 IoData, Data;
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(iSeries_xlateIoMmAddress(IoAddress) );
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ int BarOffset = iSeries_IoMmTable_BarOffset(IoAddress);
+
+ if(DeviceNode != 0) {
+ DeviceNode->ReturnCode = HvCallPci_barLoad8(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ BarNumber,BarOffset,&IoData);
+ Data = IoData;
+ if(PciTraceFlag == 1) {
+ printk("RDB: IoAddress 0x%016lX = 0x%02X\n",(unsigned long)IoAddress, Data);
+ }
+ if(DeviceNode->ReturnCode != 0) {
+ printk("RDB: %s Error: 0x%04X\n",DeviceNode->PciDev->slot_name,DeviceNode->ReturnCode);
+ }
+ }
+ return Data;
+}
+
+u16 iSeries_Read_Word(void* IoAddress) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(iSeries_xlateIoMmAddress(IoAddress) );
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ int BarOffset = iSeries_IoMmTable_BarOffset(IoAddress);
+ u16 IoData, Data;
+
+ if(DeviceNode != 0) {
+ DeviceNode->ReturnCode = HvCallPci_barLoad16(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ BarNumber,BarOffset,&IoData);
+ Data = swab16(IoData);
+
+ if(PciTraceFlag == 1) {
+ printk("RDW: IoAddress 0x%016lX = 0x%04X\n",(unsigned long)IoAddress, Data);
+ }
+ if(DeviceNode->ReturnCode != 0) {
+ printk("RDW: %s Error: 0x%04X\n",DeviceNode->PciDev->slot_name,DeviceNode->ReturnCode);
+ }
+ }
+ return Data;
+}
+u32 iSeries_Read_Long(void* IoAddress) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(iSeries_xlateIoMmAddress(IoAddress) );
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ int BarOffset = iSeries_IoMmTable_BarOffset(IoAddress);
+ u32 IoData, Data;
+
+ if(DeviceNode != 0) {
+ DeviceNode->ReturnCode = HvCallPci_barLoad32(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ BarNumber,BarOffset,&IoData);
+ Data = swab32(IoData);
+
+ if(PciTraceFlag == 1) {
+ printk("RDL: IoAddress 0x%016lX = 0x%08X\n",(unsigned long)IoAddress, Data);
+ }
+ if(DeviceNode->ReturnCode != 0) {
+ printk("RDL: %s Error: 0x%04X\n",DeviceNode->PciDev->slot_name,DeviceNode->ReturnCode);
+ }
+ }
+ return Data;
+}
+/************************************************************************/
+/* Write MM I/O Instructions for the iSeries */
+/************************************************************************/
+/* iSeries_Write_Byte = Write Byte (8 bit) */
+/* iSeries_Write_Word = Write Word(16 bit) */
+/* iSeries_Write_Long = Write Long(32 bit) */
+/************************************************************************/
+void iSeries_Write_Byte(u8 Data, void* IoAddress) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(iSeries_xlateIoMmAddress(IoAddress) );
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ int BarOffset = iSeries_IoMmTable_BarOffset(IoAddress);
+ u16 IoData = Data;
+
+ if(DeviceNode != 0 && BarNumber != -1) {
+ DeviceNode->ReturnCode = HvCallPci_barStore8 (DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ BarNumber,BarOffset,IoData);
+ if(PciTraceFlag == 1) {
+ printk("WWB: IoAddress 0x%016lX = 0x%02X\n",(unsigned long)IoAddress,Data);
+ }
+ if(DeviceNode->ReturnCode != 0) {
+ printk("WWB: %s Error: 0x%04X\n",DeviceNode->PciDev->slot_name,DeviceNode->ReturnCode);
+ }
+ }
+}
+void iSeries_Write_Word(u16 Data, void* IoAddress) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(iSeries_xlateIoMmAddress(IoAddress) );
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ int BarOffset = iSeries_IoMmTable_BarOffset(IoAddress);
+ u16 IoData = swab16(Data);
+
+ if(DeviceNode != 0 ) {
+ DeviceNode->ReturnCode = HvCallPci_barStore16(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ BarNumber,BarOffset,IoData);
+ if(PciTraceFlag == 1) {
+ printk("WWW: IoAddress 0x%016lX = 0x%04X\n",(unsigned long)IoAddress,Data);
+ }
+ if(DeviceNode->ReturnCode != 0) {
+ printk("WWW: %s Error: 0x%04X\n",DeviceNode->PciDev->slot_name,DeviceNode->ReturnCode);
+ }
+ }
+}
+void iSeries_Write_Long(u32 Data, void* IoAddress) {
+ struct iSeries_Device_Node* DeviceNode = check_Device_Node(iSeries_xlateIoMmAddress(IoAddress) );
+ int BarNumber = iSeries_IoMmTable_Bar(IoAddress);
+ int BarOffset = iSeries_IoMmTable_BarOffset(IoAddress);
+ u32 IoData = swab32(Data);
+
+ if(DeviceNode != 0 && BarNumber != -1) {
+ DeviceNode->ReturnCode = HvCallPci_barStore32(DeviceNode->BusNumber,DeviceNode->SubBus,0x10,
+ BarNumber,BarOffset,IoData);
+ if(PciTraceFlag == 1) {
+ printk("WWL: IoAddress 0x%016lX = 0x%08X\n",(unsigned long)IoAddress, Data);
+ }
+ if(DeviceNode->ReturnCode != 0) {
+ printk("WWL: %s Error: 0x%04X\n",DeviceNode->PciDev->slot_name,DeviceNode->ReturnCode);
+ }
+ }
}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/iSeries_setup.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_setup.c
--- linux/arch/ppc64/kernel/iSeries_setup.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_setup.c Mon Sep 10 14:27:51 2001
@@ -48,7 +48,6 @@
#include
#include
#include
-#include
/* Function Prototypes */
@@ -59,6 +58,9 @@
void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
pte_t * ptep, unsigned hpteflags, unsigned bolted );
extern void ppcdbg_initialize(void);
+extern void iSeries_pcibios_init(void);
+extern void iSeries_pcibios_fixup(void);
+extern void iSeries_pcibios_fixup_bus(int);
/* Global Variables */
@@ -77,6 +79,7 @@
extern struct Naca *naca;
extern int rd_size; /* Defined in drivers/block/rd.c */
extern unsigned long klimit;
+static int mf_initialized = 0;
/*
* void __init iSeries_init_early()
@@ -85,7 +88,7 @@
void __init
iSeries_init_early(void)
{
-
+#ifdef CONFIG_PPC_ISERIES
ppcdbg_initialize();
#if defined(CONFIG_BLK_DEV_INITRD)
@@ -107,19 +110,9 @@
#endif /* CONFIG_BLK_DEV_INITRD */
{
- ROOT_DEV = MKDEV( VIODASD_MAJOR, 1 );
+ /* ROOT_DEV = MKDEV( VIODASD_MAJOR, 1 ); */
}
- /* Initialize the table which translate Linux physical addresses to
- * AS/400 absolute addresses
- */
-
- build_iSeries_Memory_Map();
-
- setup_iSeries_cache_sizes();
-
- /* Initialize machine-dependency vectors */
-
ppc_md.setup_arch = iSeries_setup_arch;
ppc_md.setup_residual = iSeries_setup_residual;
ppc_md.get_cpuinfo = iSeries_get_cpuinfo;
@@ -128,6 +121,9 @@
ppc_md.get_irq = iSeries_get_irq;
ppc_md.init = NULL;
+ ppc_md.pcibios_fixup = iSeries_pcibios_fixup;
+ ppc_md.pcibios_fixup_bus = iSeries_pcibios_fixup_bus;
+
ppc_md.restart = iSeries_restart;
ppc_md.power_off = iSeries_power_off;
ppc_md.halt = iSeries_halt;
@@ -149,11 +145,29 @@
ppc_md.ppc_kbd_sysrq_xlate = NULL;
#endif
- if ( itLpNaca.xPirEnvironMode == 0 )
- piranha_simulator = 1;
+ htpe_init_iSeries();
+ tce_init_iSeries();
+ ppc_md.pcibios_fixup = iSeries_pcibios_fixup;
+ ppc_md.pcibios_fixup_bus = iSeries_pcibios_fixup_bus;
+
+ /* Initialize the table which translate Linux physical addresses to
+ * AS/400 absolute addresses
+ */
- return;
+ build_iSeries_Memory_Map();
+ setup_iSeries_cache_sizes();
+
+ /* Initialize machine-dependency vectors */
+
+
+#ifdef CONFIG_SMP
+ smp_init_iSeries();
+#endif
+
+ if ( itLpNaca.xPirEnvironMode == 0 )
+ piranha_simulator = 1;
+#endif
}
/*
@@ -188,15 +202,12 @@
iSeries_proc_early_init();
mf_init();
+ mf_initialized = 1;
+ mb();
iSeries_proc_callback( &pmc_proc_init );
-
- viopath_init();
-
- return;
}
-
/*
* The iSeries may have very large memories ( > 128 GB ) and a partition
* may get memory in "chunks" that may be anywhere in the 2**52 real
@@ -628,12 +639,12 @@
* Document me.
* and Implement me.
*/
-void __init
-iSeries_init_IRQ(void)
-{
- return;
-}
-
+//void __init
+//iSeries_init_IRQ(void)
+//{
+// return;
+//}
+//
/*
* Document me.
* and Implement me.
@@ -753,8 +764,10 @@
iSeries_progress( char * st, unsigned short code )
{
printk( "Progress: [%04x] - %s\n", (unsigned)code, st );
-#if 0
- if ( !piranha_simulator )
+ if ( !piranha_simulator && mf_initialized ) {
+ if (code != 0xffff)
mf_displayProgress( code );
-#endif
+ else
+ mf_clearSrc();
+ }
}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/misc.S linuxppc64_2_4/arch/ppc64/kernel/misc.S
--- linux/arch/ppc64/kernel/misc.S Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/misc.S Fri Sep 7 06:23:33 2001
@@ -308,11 +308,10 @@
* Flush a particular page from the data cache to RAM.
* Note: this is necessary because the instruction cache does *not*
* snoop from the data cache.
- * This is a no-op on the 601 which has a unified cache.
*
- * void __flush_page_to_ram(void *page)
+ * void __flush_dcache_icache(void *page)
*/
-_GLOBAL(__flush_page_to_ram)
+_GLOBAL(__flush_dcache_icache)
/*
* Flush the data cache to memory
*
@@ -346,33 +345,6 @@
/*
- * Flush a particular page from the instruction cache.
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- *
- * void __flush_icache_page(void *page)
- */
-_GLOBAL(__flush_icache_page)
-/*
- * Different systems have different cache line sizes
- */
-
-/* Invalidate the icache */
-
- LOADADDR(r6,naca)
- ld r6,0(r6)
- clrrdi r3,r3,12 /* Page align */
- lhz r4,ICACHEL1LINESPERPAGE(r6) /* Get # icache lines per page */
- lhz r5,ICACHEL1LINESIZE(r6) /* Get icache line size */
- mtctr r4
-1: icbi 0,r3
- add r3,r3,r5
- bdnz 1b
- sync
- isync
- blr
-
-/*
* Clear a page using the dcbz instruction, which doesn't cause any
* memory traffic (except to write out any cache lines which get
* displaced). This only works on cacheable memory.
@@ -641,6 +613,30 @@
_GLOBAL(_get_SP)
mr r3,r1 /* Close enough */
+ blr
+
+_GLOBAL(_get_THRM1)
+ mfspr r3,THRM1
+ blr
+
+_GLOBAL(_get_THRM2)
+ mfspr r3,THRM2
+ blr
+
+_GLOBAL(_get_THRM3)
+ mfspr r3,THRM3
+ blr
+
+_GLOBAL(_set_THRM1)
+ mtspr THRM1,r3
+ blr
+
+_GLOBAL(_set_THRM2)
+ mtspr THRM2,r3
+ blr
+
+_GLOBAL(_set_THRM3)
+ mtspr THRM3,r3
blr
_GLOBAL(_get_PVR)
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/mk_defs.c linuxppc64_2_4/arch/ppc64/kernel/mk_defs.c
--- linux/arch/ppc64/kernel/mk_defs.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/mk_defs.c Fri Sep 7 15:27:32 2001
@@ -69,13 +69,13 @@
DEFINE(PACASTABREAL, offsetof(struct Paca, xStab_data.real));
DEFINE(PACASTABVIRT, offsetof(struct Paca, xStab_data.virt));
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));
+ DEFINE(PACAEXCSP, offsetof(struct Paca, exception_sp));
+ DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca));
DEFINE(LPPACA, offsetof(struct Paca, xLpPaca));
+ DEFINE(PACAREGSAV, offsetof(struct Paca, xRegSav));
+ DEFINE(PACAEXC, offsetof(struct Paca, exception_stack));
DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/open_pic.c linuxppc64_2_4/arch/ppc64/kernel/open_pic.c
--- linux/arch/ppc64/kernel/open_pic.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/open_pic.c Fri Aug 31 15:48:52 2001
@@ -87,10 +87,10 @@
*/
#ifdef CONFIG_SMP
#define THIS_CPU Processor[cpu]
-#define DECL_THIS_CPU int cpu = cpu_hw_index[smp_processor_id()]
+#define DECL_THIS_CPU int cpu = hard_smp_processor_id()
#define CHECK_THIS_CPU check_arg_cpu(cpu)
#else
-#define THIS_CPU Processor[cpu_hw_index[0]]
+#define THIS_CPU Processor[hard_smp_processor_id()]
#define DECL_THIS_CPU
#define CHECK_THIS_CPU
#endif /* CONFIG_SMP */
@@ -358,7 +358,7 @@
/* SIOint (8259 cascade) is special */
if (offset) {
openpic_initirq(0, 8, offset, 1, 1);
- openpic_mapirq(0, 1<>= 1)
- mask |= (cpumask & 1) << cpu_hw_index[i];
+ mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
return mask;
}
@@ -595,7 +595,7 @@
{
#ifdef CONFIG_IRQ_ALL_CPUS
int i;
- u32 msk = 1 << cpu_hw_index[smp_processor_id()];
+ u32 msk = 1 << hard_smp_processor_id();
#endif
spin_lock(&openpic_setup_lock);
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/pSeries_pci.c linuxppc64_2_4/arch/ppc64/kernel/pSeries_pci.c
--- linux/arch/ppc64/kernel/pSeries_pci.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pSeries_pci.c Wed Sep 5 13:56:40 2001
@@ -46,16 +46,6 @@
#include "open_pic.h"
#include "pci.h"
-/* Supporting macros *********************************************/
-#define TESTBIT(value,bits) ((value&bits) == bits)
-#define TRUE 1
-#define FALSE 0
-
-extern struct pci_controller* hose_head;
-extern struct pci_controller** hose_tail;
-extern struct Naca *naca;
-extern struct pci_ops rtas_pci_ops;
-extern struct pci_ops ibm_phb_pci_ops;
extern struct device_node *allnodes;
extern unsigned long phb_tce_table_init(struct pci_controller *phb);
@@ -65,33 +55,69 @@
unsigned long find_and_init_phbs(void);
struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ;
void pSeries_pcibios_fixup(void);
-void pci_build_bar_resources(struct pci_dev* Pci_Dev, int BarCount);
-void pci_build_rom_resources(struct pci_dev* Pci_Dev);
-void pci_set_BARS(struct pci_dev* Pci_Dev);
/**********************************************************************************
*
* pSeries I/O Operations to access the PCI configuration space.
*
**********************************************************************************/
-#define RTAS_PCI_READ_OP(size, type, nbytes) \
-int __chrp \
-rtas_read_config_##size(struct pci_dev *dev, int offset, type val) { \
- unsigned long ReturnValue, ConfigAddr; \
- int ReturnCode; \
- ConfigAddr = ((dev->bus->number&0x0000FF) << 16) | (dev->devfn << 8) | (offset & 0xff); \
- ReturnCode = call_rtas("read-pci-config", 2, 2, &ReturnValue, ConfigAddr, nbytes);\
- *val = ReturnValue; \
- return ReturnCode; \
-}
-#define RTAS_PCI_WRITE_OP(size, type, nbytes) \
-int __chrp \
-rtas_write_config_##size(struct pci_dev *dev, int offset, type val) { \
- unsigned long ConfigAddr; \
- int ReturnCode; \
- ConfigAddr = ((dev->bus->number&0x0000FF) << 16) | (dev->devfn << 8) | (offset & 0xff); \
- ReturnCode = call_rtas("write-pci-config", 3, 1, NULL, ConfigAddr, nbytes, (ulong)val); \
- return ReturnCode; \
+#define RTAS_PCI_READ_OP(size, type, nbytes) \
+int __chrp \
+rtas_read_config_##size(struct device_node *dn, int offset, type val) { \
+ unsigned long returnval = ~0L; \
+ unsigned long buid; \
+ unsigned int addr; \
+ int ret; \
+ \
+ if (dn == NULL) { \
+ ret = -2; \
+ } else if (dn->status) { \
+ ret = -1; \
+ } else { \
+ addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
+ buid = dn->phb->buid; \
+ if (buid) { \
+ ret = call_rtas("ibm,read-pci-config", 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \
+ } else { \
+ ret = call_rtas("read-pci-config", 2, 2, &returnval, addr, nbytes); \
+ } \
+ } \
+ *val = returnval; \
+ return ret; \
+} \
+int __chrp \
+rtas_pci_read_config_##size(struct pci_dev *dev, int offset, type val) { \
+ struct device_node *dn = pci_device_to_OF_node(dev); \
+ int ret = rtas_read_config_##size(dn, offset, val); \
+ /* udbg_printf("read bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \
+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \
+}
+
+#define RTAS_PCI_WRITE_OP(size, type, nbytes) \
+int __chrp \
+rtas_write_config_##size(struct device_node *dn, int offset, type val) { \
+ unsigned long buid; \
+ unsigned int addr; \
+ int ret; \
+ \
+ if (dn == NULL) { \
+ ret = -2; \
+ } else if (dn->status) { \
+ ret = -1; \
+ } else { \
+ buid = dn->phb->buid; \
+ addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
+ if (buid) { \
+ ret = call_rtas("ibm,write-pci-config", 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, nbytes, (ulong) val); \
+ } else { \
+ ret = call_rtas("write-pci-config", 3, 1, NULL, addr, nbytes, (ulong)val); \
+ } \
+ } \
+ return ret; \
+} \
+int __chrp \
+rtas_pci_write_config_##size(struct pci_dev *dev, int offset, type val) { \
+ return rtas_write_config_##size(pci_device_to_OF_node(dev), offset, val); \
}
RTAS_PCI_READ_OP(byte, u8 *, 1)
@@ -102,75 +128,14 @@
RTAS_PCI_WRITE_OP(dword, u32, 4)
struct pci_ops rtas_pci_ops = {
- rtas_read_config_byte,
- rtas_read_config_word,
- rtas_read_config_dword,
- rtas_write_config_byte,
- rtas_write_config_word,
- rtas_write_config_dword,
- pci_read_bar_registers,
- pci_read_irq_line
-};
-
-/**********************************************************************************
- *
- * pSeries I/O Operations to access the PCI configuration space.
- * This is the support for Large Systems(>256 buses).
- *
- **********************************************************************************/
-#define RTAS64_PCI_READ_OP(size, type, nbytes) \
-int __chrp \
-rtas64_read_config_##size(struct pci_dev *dev, int offset, type val) \
-{ \
- struct pci_controller *hose = dev->sysdata; \
- unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
- | (((dev->bus->number) & 0xff) << 16); \
- unsigned long ret = ~0UL; \
- int rval; \
- int buidhi = hose->buid >> 32; \
- int buidlo = hose->buid & 0xffffffff; \
- \
- rval = call_rtas("ibm,read-pci-config", 4, 2, &ret, \
- addr, buidhi, buidlo, nbytes); \
- *val = ret; \
- /* udbg_printf("%08x %08x SYM Read Config %d\n",addr, ret,rval); */ \
- return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; \
-}
-
-#define RTAS64_PCI_WRITE_OP(size, type, nbytes) \
-int __chrp \
-rtas64_write_config_##size(struct pci_dev *dev, int offset, type val) \
-{ \
- struct pci_controller *hose = dev->sysdata; \
- unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
- | (((dev->bus->number) & 0xff) << 16); \
- int rval; \
- int buidhi = hose->buid >> 32; \
- int buidlo = hose->buid & 0xffffffff; \
- \
- rval = call_rtas("ibm,write-pci-config", 5, 1, NULL, \
- addr, buidhi, buidlo, nbytes, (ulong)val); \
- /* udbg_printf("%08x %08x SYM Write Config %d\n",addr, val,rval); */ \
- return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; \
-}
-
-RTAS64_PCI_READ_OP(byte, u8 *, 1)
-RTAS64_PCI_READ_OP(word, u16 *, 2)
-RTAS64_PCI_READ_OP(dword, u32 *, 4)
-RTAS64_PCI_WRITE_OP(byte, u8, 1)
-RTAS64_PCI_WRITE_OP(word, u16, 2)
-RTAS64_PCI_WRITE_OP(dword, u32, 4)
-
-struct pci_ops rtas64_pci_ops = {
- rtas64_read_config_byte,
- rtas64_read_config_word,
- rtas64_read_config_dword,
- rtas64_write_config_byte,
- rtas64_write_config_word,
- rtas64_write_config_dword
+ rtas_pci_read_config_byte,
+ rtas_pci_read_config_word,
+ rtas_pci_read_config_dword,
+ rtas_pci_write_config_byte,
+ rtas_pci_write_config_word,
+ rtas_pci_write_config_dword,
};
-
/******************************************************************
* pci_read_irq_line
*
@@ -204,216 +169,6 @@
PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n",Pci_Dev->slot_name,Pci_Dev->irq);
return 0;
}
-/******************************************************************
- * pci_set_BARS
- *
- * Sets the IOA BAR registers from the values from the register
- * values found in the OpenFirmware node for the device. Or in
- * the future, assigns space in phb and sets the values.
- ******************************************************************/
-void
-pci_set_BARS(struct pci_dev* Pci_Dev) {
- int AddrIndex;
- struct device_node *Device_Node = pci_device_to_OF_node(Pci_Dev);
-
- if(Device_Node == 0 || Device_Node->n_addrs == 0 || Device_Node->addrs == NULL) {
- PPCDBG(PPCDBG_BUSWALK, "\tDevice Node was not found or no defined bars\n");
- return;
- }
- PPCDBG(PPCDBG_BUSWALK, "\tSet Bar Regs(%d)\n",Device_Node->n_addrs);
- for(AddrIndex = 0; AddrIndex < Device_Node->n_addrs; ++AddrIndex) {
- int PciReg = (Device_Node->addrs[AddrIndex].space & 0x000000FF);
- u32 PciBar = Device_Node->addrs[AddrIndex].address;
- int BarSze = Device_Node->addrs[AddrIndex].size;
-
- PPCDBG(PPCDBG_BUSWALK, "\tPciBar 0x%02X, 0x%08X, 0x%08X\n",PciReg,PciBar,BarSze);
- pci_write_config_dword(Pci_Dev, PciReg,PciBar);
- }
-}
-/******************************************************************
- *
- * pci_build_bar_registers
- *
- * This function will build the resources based on the information
- * that is extracted from the BAR register. The original BAR value
- * is saved and restored.
- *
- * Note: This is pSeries brand specific code.
- * In the future, this code will be setting the initial BAR
- * value and handing out the memory space in the PHB.
- ******************************************************************/
-void
-pci_build_bar_resources(struct pci_dev* Pci_Dev, int Count) {
- int BarRegister = PCI_BASE_ADDRESS_0;
- int EndingBar = BarRegister + (Count*4);
- int ResourceIndex = 0;
- PPCDBG(PPCDBG_BUSWALK, "\npci_read_bar_registers %s\n",Pci_Dev->slot_name);
-
- /**************************************************************
- * Read Bars until the ending bar has been read.
- **************************************************************/
- for(BarRegister = PCI_BASE_ADDRESS_0;BarRegister <= EndingBar; BarRegister += 4) {
- struct resource* Resource = &Pci_Dev->resource[ResourceIndex];
- u32 BarSaveArea, BarSizeBits, BarSize;
- u64 BarStart;
- /**********************************************************
- * Save the original bar value and check for success.
- **********************************************************/
- if((pci_read_config_dword( Pci_Dev, BarRegister, &BarSaveArea) != 0) ||
- (BarSaveArea == 0xFFFFFFFF )) {
- BarRegister += 4;
- continue;
- }
- /**********************************************************
- * Write all ones to register to get the size of area.
- **********************************************************/
- pci_write_config_dword(Pci_Dev, BarRegister, 0xFFFFFFFF);
- pci_read_config_dword( Pci_Dev, BarRegister, &BarSizeBits);
- pci_write_config_dword(Pci_Dev, BarRegister, BarSaveArea);
-
- /**********************************************************
- * Error reading bar(all ones back) or unimplemented BAR(zero)
- **********************************************************/
- if(( BarSizeBits == 0xFFFFFFFF ) || BarSizeBits == 0 ) {
- BarRegister += 4;
- continue;
- }
- Resource->name = Pci_Dev->name;
- /**********************************************************
- * Test and read Io Space, It is always 32 bits.
- **********************************************************/
- if(TESTBIT(BarSizeBits,PCI_BASE_ADDRESS_SPACE_IO) == TRUE) {
- BarSize = (~(BarSizeBits&PCI_BASE_ADDRESS_IO_MASK)) +1;
- Resource->flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
- Resource->start = BarSaveArea & PCI_BASE_ADDRESS_IO_MASK;
- Resource->end = Resource->start + BarSize - 1;
- ++ResourceIndex;
- }
- /**********************************************************
- * Memory Space, could be 32 bits or 64 bits
- **********************************************************/
- else {
- Resource->flags = IORESOURCE_MEM;
- if( TESTBIT(BarSizeBits,PCI_BASE_ADDRESS_MEM_PREFETCH) == TRUE) {
- Resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
- }
- BarStart = BarSaveArea &PCI_BASE_ADDRESS_MEM_MASK;
- BarSize = ~((BarSizeBits)&PCI_BASE_ADDRESS_MEM_MASK)+1;
- /**********************************************************
- * 64 bit register, read next register to get the high 32
- * bits. PCI Spec says to write both and THEN read.
- **********************************************************/
- if( TESTBIT(BarSizeBits,PCI_BASE_ADDRESS_MEM_TYPE_64) == TRUE) {
- u64 High64Bits;
- u32 BarHigh64Save;
- Resource->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
- BarRegister += 4; /* Index to next Bar */
- pci_read_config_dword( Pci_Dev, BarRegister, &BarHigh64Save);
- High64Bits = BarHigh64Save;
- BarStart += (High64Bits<< 32);
- pci_write_config_dword(Pci_Dev, BarRegister-4,0xFFFFFFFF);
- pci_write_config_dword(Pci_Dev, BarRegister, 0xFFFFFFFF);
- pci_read_config_dword( Pci_Dev, BarRegister-4,&BarSizeBits);
- BarSize = ~((BarSizeBits)&PCI_BASE_ADDRESS_MEM_MASK)+1;
- pci_read_config_dword( Pci_Dev, BarRegister, &BarSizeBits);
- High64Bits = ~(BarSizeBits);
- BarSize += (High64Bits << 32);
- pci_write_config_dword(Pci_Dev, BarRegister-4,BarSaveArea);
- pci_write_config_dword(Pci_Dev, BarRegister, BarHigh64Save);
- ++ResourceIndex; /* Skip next resource */
- }
- /**********************************************************
- * Set resource fields with values.
- **********************************************************/
- Resource->start = BarStart;
- Resource->end = BarStart + BarSize - 1;
- ++ResourceIndex;
- }
- }
- PPCDBGCALL(PPCDBG_BUSWALK, dumpPci_Dev(Pci_Dev) );
-}
-/******************************************************************
- *
- * Read the rom register
- *
- ******************************************************************/
-void
-pci_build_rom_resources(struct pci_dev* Pci_Dev) {
- u32 RomSaveArea, RomSizeBits;
- u64 RomSize = 0;
- struct resource* Resource = &Pci_Dev->resource[PCI_ROM_RESOURCE];
- PPCDBG(PPCDBG_BUSWALK, "\tpci_read_bar_Rom \n");
-
- pci_read_config_dword( Pci_Dev, PCI_ROM_ADDRESS, &RomSaveArea);
- pci_write_config_dword(Pci_Dev, PCI_ROM_ADDRESS, 0XFFFFFFFF);
- pci_read_config_dword( Pci_Dev, PCI_ROM_ADDRESS, &RomSizeBits);
- pci_write_config_dword(Pci_Dev, PCI_ROM_ADDRESS, RomSaveArea);
-
- if( (RomSizeBits&PCI_ROM_ADDRESS_ENABLE) == PCI_ROM_ADDRESS_ENABLE) {
- RomSize = ~(RomSizeBits) & PCI_ROM_ADDRESS_MASK;
- if(RomSize > 0) {
- Resource->name = Pci_Dev->name;
- Resource->flags = IORESOURCE_MEM | IORESOURCE_READONLY | IORESOURCE_PREFETCH;
- Resource->start = RomSaveArea;
- Resource->end = Resource->start + RomSize - 1;
- }
- }
-}
-/******************************************************************
- *
- * pci_read_bar_registers
- *
- * This function is the hook from the independant code to the arch
- * dependant code to set and read the BAR registers.
- *
- * Note: This is pSeries brand specific code.
- * In the future, this code will be setting the initial BAR
- * value and handing out the PBH memory space.
- ******************************************************************/
-int
-pci_read_bar_registers(struct pci_dev* Pci_Dev, int Count, int RomFlag) {
- u16 Pci_Command_Register_Save = 0;
- u16 Pci_Mask_Reg;
- /**************************************************************
- * If Io or Memory is enabled, disable while the BARs are being
- * changed to avoid any side affects.
- **************************************************************/
- if(( pci_read_config_word( Pci_Dev, PCI_COMMAND, &Pci_Command_Register_Save) != 0 ) ||
- (Pci_Command_Register_Save == (u16)0xFFFF) ) {
- printk("PCI: Device %s Read Command Failed.\n",Pci_Dev->slot_name);
- PPCDBG(PPCDBG_BUSWALK,"\tDevice %s Read Command Failed.\n",Pci_Dev->slot_name);
- return -1;
- }
- Pci_Mask_Reg = Pci_Command_Register_Save &(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
- if( Pci_Mask_Reg != 0) {
- u16 ResetCmdReg = Pci_Command_Register_Save & (~Pci_Mask_Reg);
- pci_write_config_word( Pci_Dev, PCI_COMMAND, ResetCmdReg);
- }
- else {
- Pci_Command_Register_Save = 0;
- }
- /**************************************************************
- * Do the base BARS.
- **************************************************************/
- pci_build_bar_resources(Pci_Dev, Count);
-
- /**************************************************************
- * Rom Flag on, read ROM BARS.
- **************************************************************/
- if(RomFlag != 0) {
- pci_build_rom_resources(Pci_Dev);
- }
-
- /**************************************************************
- * If the Command Register was modifed, restore it.
- **************************************************************/
- if(Pci_Command_Register_Save != 0) {
- pci_write_config_word( Pci_Dev, PCI_COMMAND, Pci_Command_Register_Save);
- PPCDBG(PPCDBG_BUSWALK,"\tPCI_COMMAND Register Restored 0x%04X\n",
- Pci_Command_Register_Save);
- }
- return 0;
-}
/******************************************************************
* Find all PHBs in the system and initialize a set of data
@@ -432,7 +187,6 @@
struct resource *res;
unsigned int memno, rlen, i, index;
unsigned int *opprop;
-
PPCDBG(PPCDBG_PHBINIT, "find_and_init_phbs\n");
if(naca->interrupt_controller == IC_OPEN_PIC) {
@@ -449,6 +203,11 @@
return(-1);
}
+ if (find_type_devices("isa")) {
+ isa_io_limit = 0; /* allow all ISA ports down to zero. */
+ PPCDBG(PPCDBG_PHBINIT, "\tFound an ISA bus.\n");
+ }
+
index = 0;
/******************************************************************
@@ -476,10 +235,10 @@
range_stride = this_addr_count + root_addr_size_words + this_addr_size_words;
memno = 0;
- phb->io_base_phys = 0;
+ phb->io_base_phys = 0;
ranges = (unsigned int *) get_property(Pci_Node, "ranges", &rlen);
- PPCDBG(PPCDBG_PHBINIT, "\trange_stride = 0x%lx, rlen = 0x%x\n", range_stride, rlen);
+ PPCDBG(PPCDBG_PHBINIT, "\trange_stride = 0x%lx, rlen = 0x%x\n", range_stride, rlen);
for(i = 0; i < (rlen/sizeof(*ranges)); i+=range_stride) {
/* Put the PCI addr part of the current element into a
@@ -518,21 +277,26 @@
res = NULL;
switch ((range.child_addr.a_hi >> 24) & 0x3) {
case 1: /* I/O space */
+ PPCDBG(PPCDBG_PHBINIT, "\tIO Space\n");
phb->io_base_phys = range.parent_addr;
+ phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
+ if (!isa_io_base)
+ isa_io_base = (unsigned long)phb->io_base_virt;
res = &phb->io_resource;
+ res->name = Pci_Node->full_name;
res->flags = IORESOURCE_IO;
- if (isa_io_base == 0) {
- isa_io_base = (unsigned long)
- ioremap(phb->io_base_phys, range.size);
- PPCDBG(PPCDBG_PHBINIT, "\tisa_io_base = 0x%lx\n", isa_io_base);
- }
+ res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
+ res->start += (unsigned long)phb->io_base_virt - isa_io_base;
+ res->end = res->start + range.size - 1;
+ res->parent = NULL;
+ res->sibling = NULL;
+ res->child = NULL;
phb->pci_io_offset = range.parent_addr -
((((unsigned long)
range.child_addr.a_mid) << 32) |
(range.child_addr.a_lo));
PPCDBG(PPCDBG_PHBINIT, "\tpci_io_offset = 0x%lx\n",
phb->pci_io_offset);
-
break;
case 2: /* mem space */
PPCDBG(PPCDBG_PHBINIT, "\tMem Space\n");
@@ -542,37 +306,31 @@
(range.child_addr.a_lo));
PPCDBG(PPCDBG_PHBINIT, "\tpci_mem_offset = 0x%lx\n",
phb->pci_mem_offset);
- res = &(phb->mem_resources[memno]);
- res->flags = IORESOURCE_MEM;
- ++memno;
+ if (memno < sizeof(phb->mem_resources)/sizeof(phb->mem_resources[0])) {
+ res = &(phb->mem_resources[memno]);
+ ++memno;
+ res->name = Pci_Node->full_name;
+ res->flags = IORESOURCE_MEM;
+ res->start = range.parent_addr;
+ res->end = range.parent_addr + range.size - 1;
+ res->parent = NULL;
+ res->sibling = NULL;
+ res->child = NULL;
+ }
break;
}
- if (res) {
- res->name = Pci_Node->full_name;
- res->start = range.parent_addr;
- res->end = range.parent_addr + range.size - 1;
- res->parent = NULL;
- res->sibling = NULL;
- res->child = NULL;
- }
}
PPCDBG(PPCDBG_PHBINIT, "\tphb->io_base_phys = 0x%lx\n",
phb->io_base_phys);
PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%lx\n",
phb->pci_mem_offset);
- if(naca->interrupt_controller == IC_OPEN_PIC) {
- if(root_addr_size_words == 1) {
- openpic_setup_ISU(index, opprop[index+1]);
- } else {
- openpic_setup_ISU(index,
- ((unsigned long)opprop[(index+1)*2]) << 32 |
- opprop[(index+1)*2+1]);
- }
- }
-
+ if(naca->interrupt_controller == IC_OPEN_PIC) {
+ openpic_setup_ISU(index, opprop[index+1]);
+ }
index++;
}
+ pci_devs_phb_init();
return 0; /*Success */
}
@@ -587,7 +345,8 @@
struct pci_controller *phb;
unsigned int *ui_ptr = NULL, len;
struct reg_property64 reg_struct;
- int *bus_range;
+ int *bus_range;
+ int *buid_vals;
PPCDBG(PPCDBG_PHBINIT, "alloc_phb: %s\n", dev->full_name);
PPCDBG(PPCDBG_PHBINIT, "\tdev = 0x%lx\n", dev);
@@ -644,19 +403,25 @@
phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon);
if(phb == NULL) return NULL;
- phb->cfg_addr = (volatile unsigned long *)
- ioremap(reg_struct.address + 0x140, PAGE_SIZE);
- phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
- phb->phb_regs = (volatile unsigned long *)
- ioremap(reg_struct.address, PAGE_SIZE);
+ if (_machine == _MACH_pSeries) {
+ phb->cfg_addr = (volatile unsigned long *)
+ ioremap(reg_struct.address + 0x140, PAGE_SIZE);
+ phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
+ phb->phb_regs = (volatile unsigned long *)
+ ioremap(reg_struct.address, PAGE_SIZE);
+ /* Speedwagon's register file is 1 MB in size. */
+ phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL),
+ 0x100000);
+ PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n",
+ reg_struct.address & 0xfffff, phb->chip_regs);
+ } else {
+ phb->cfg_addr = NULL;
+ phb->cfg_data = NULL;
+ phb->phb_regs = NULL;
+ phb->chip_regs = NULL;
+ }
phb->local_number = ((reg_struct.address >> 12) & 0xf) - 0x8;
-
- /* Speedwagon's register file is 1 MB in size. */
- phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL),
- 0x100000);
- PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n",
- reg_struct.address & 0xfffff, phb->chip_regs);
/***************************************************************
* Trying to build a known just gets the code in trouble.
***************************************************************/
@@ -676,19 +441,26 @@
/***************************************************************
* Finished with the initialization
***************************************************************/
- phb->first_busno = bus_range[0];
- phb->last_busno = bus_range[1];
- //phb->first_busno = (phb->global_number <<8) + bus_range[0];
- //phb->last_busno = (phb->global_number <<8) + bus_range[1];
+ // phb->first_busno = bus_range[0];
+ // phb->last_busno = bus_range[1];
+ phb->first_busno = (phb->global_number <<8) + bus_range[0];
+ phb->last_busno = (phb->global_number <<8) + bus_range[1];
phb->arch_data = dev;
- if( Pci_Large_Bus_System == 0 ) phb->ops = &rtas_pci_ops;
- else phb->ops = &rtas64_pci_ops;
+ phb->ops = &rtas_pci_ops;
+
+ buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len);
+ if (buid_vals == NULL || len < 2 * sizeof(int)) {
+ phb->buid = 0;
+ } else {
+ phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
+ (((unsigned long)buid_vals[1]) & 0xffffffff);
+ }
/***************************************************************
* Build tce table for phb
***************************************************************/
- phb_tce_table_init(phb);
+ /* DRENG Obsolete phb_tce_table_init(phb); */
/* Dump PHB information for Debug */
PPCDBGCALL(PPCDBG_PHBINIT,dumpPci_Controller(phb) );
@@ -699,8 +471,7 @@
void
fixup_resources(struct pci_dev *dev) {
int i;
- unsigned long size;
- struct pci_controller* phb = (struct pci_controller *)dev->sysdata;
+ struct pci_controller* phb = PCI_GET_PHB_PTR(dev);
PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n");
PPCDBG(PPCDBG_PHBINIT, "\tphb = 0x%016LX\n", phb);
@@ -712,7 +483,7 @@
if(phb == NULL) return;
- for (i = 0; i < 6; ++i) {
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) {
PPCDBG(PPCDBG_PHBINIT, "\tdevice %x.%x[%d] (flags %x) [%lx..%lx]\n",
dev->bus->number, dev->devfn, i,
dev->resource[i].flags,
@@ -724,20 +495,20 @@
}
if (dev->resource[i].flags & IORESOURCE_IO) {
- dev->resource[i].start += phb->pci_io_offset;
- dev->resource[i].end += phb->pci_io_offset;
- size = dev->resource[i].end - dev->resource[i].start;
- dev->resource[i].start =
- ((unsigned long) ioremap(dev->resource[i].start,
- size)) - isa_io_base;
- dev->resource[i].end = dev->resource[i].start + size;
-
+ unsigned long offset = (unsigned long) phb->io_base_virt - isa_io_base;
+ dev->resource[i].start += offset;
+ dev->resource[i].end += offset;
PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx (%lx) .. %lx (%lx)]\n",
- dev->resource[i].start, ___pa(dev->resource[i].start + isa_io_base),
- dev->resource[i].end, ___pa(dev->resource[i].end + isa_io_base));
+ dev->resource[i].start, 0/*___pa(dev->resource[i].start + isa_io_base)*/,
+ dev->resource[i].end, 0/* ___pa(dev->resource[i].end + isa_io_base)*/);
} else if (dev->resource[i].flags & IORESOURCE_MEM) {
- dev->resource[i].start += phb->pci_mem_offset;
- dev->resource[i].end += phb->pci_mem_offset;
+ if (dev->resource[i].start == 0) {
+ /* Bogus. Probably an unused bridge. */
+ dev->resource[i].end = 0;
+ } else {
+ dev->resource[i].start += phb->pci_mem_offset;
+ dev->resource[i].end += phb->pci_mem_offset;
+ }
PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
dev->resource[i].start, dev->resource[i].end);
@@ -760,6 +531,7 @@
pci_assign_all_busses = 0;
pci_for_each_dev(dev) {
+ pci_read_irq_line(dev);
PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Dev(dev) );
}
@@ -787,89 +559,6 @@
return NULL;
}
-/***********************************************************************
- *
- * scan_OF_childs_for_device
- *
- * The function is a helper function for the pci_device_to_OF_node. It
- * walks down the passed node, looking for a node entry that matches the
- * requested bus and device function. NOTE: If a bridge is found in the
- * scan, it will recurse this the function to to scan that bridge looking
- * for a match. If none found, the return will continue down the orginal
- * tree.
- *
- * Return:
- * Node matching the bus and devfn passed or NULL.
- ***********************************************************************/
-static struct device_node*
-scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
-{
- struct device_node* CurrentNode; /* Current node being scanned. */
- struct device_node* DeviceNode; /* Node of Device */
- u32* Register; /* Pointer to Register Array */
- u32* Class_Code; /* Pointer to ClassCode property */
- CurrentNode = node;
- DeviceNode = NULL;
- while(CurrentNode != NULL && DeviceNode == NULL) {
- u32 IoaAddress;
- u8 IoaBus, IoaDevFn;
-
- Register = (unsigned int *) get_property(CurrentNode,"reg", 0);
- if(Register != NULL) {
- /* 1st register entry is the Ioa Address = 00BBSS00 */
- IoaAddress = Register[0];
- IoaBus = (IoaAddress & 0x00FF0000) >> 16;
- IoaDevFn = (IoaAddress & 0x0000FF00) >> 8;
- if( (IoaBus == bus) && (IoaDevFn == dev_fn ) ) {
- DeviceNode = CurrentNode;
- return DeviceNode;
- }
- }
- /***************************************************************
- * check for a bridge, if so scan the branch of the tree for a match.
- ***************************************************************/
- Class_Code = (unsigned int*) get_property(CurrentNode,"class-code", 0);
- if(Class_Code != NULL) {
- u32 PciClassCode = ((*Class_Code)&0x00FFFF00)>>8;
-
- if(( PciClassCode == PCI_CLASS_BRIDGE_PCI) ||
- ( PciClassCode == PCI_CLASS_BRIDGE_CARDBUS) ) {
-
- PPCDBG(PPCDBG_BUSWALK,"\tScan OF behind bridge\n");
- DeviceNode = scan_OF_childs_for_device(CurrentNode->child, bus, dev_fn);
- if(DeviceNode != NULL) {
- return DeviceNode;
- }
- }
- }
- /***************************************************************
- * Try the next node.
- ***************************************************************/
- CurrentNode = CurrentNode->sibling;
- }
- return NULL;
-}
-/***********************************************************************
- * pci_device_to_OF_node
- *
- * This function Finds the Open Firmware node for the passed in pci_dev.
- * It starts at the Phb's node for the device and calls the
- * scan_OF_childs_for_device to looking for the matching entry.
- *
- * Return:
- * Node matching the device or NULL if it was not found.
- ***********************************************************************/
-struct device_node*
-pci_device_to_OF_node(struct pci_dev* Pci_Dev)
-{
- struct pci_controller* Phb;
- struct device_node* PhbNode;
- struct device_node* DeviceNode;
- Phb = PCI_GET_PHB_PTR(Pci_Dev);
- PhbNode = (struct device_node *) Phb->arch_data;
- DeviceNode = scan_OF_childs_for_device(PhbNode->child, PCI_GET_BUS_NUMBER(Pci_Dev), Pci_Dev->devfn);
- return DeviceNode;
-}
/***********************************************************************
* find_floppy(void)
*
@@ -912,16 +601,6 @@
pSeries_pcibios_init(void) {
PPCDBG(PPCDBG_PHBINIT, "\tppc64_pcibios_init Entry.\n");
- if(get_property(find_path_device("/rtas"),"read-pc-config",NULL) != NULL) {
- PPCDBG(PPCDBG_PHBINIT, "\tFound: read-pc-config\n");
- }
- else PPCDBG(PPCDBG_PHBINIT, "\tNOT Found: read-pc-config\n");
-
-
- if(get_property(find_path_device("/rtas"),"ibm,read-pc-config",NULL) != NULL) {
- PPCDBG(PPCDBG_PHBINIT, "\tFound: ibm,read-pc-config\n");
- Pci_Set_IOA_Address = 1;
- }
if(get_property(find_path_device("/rtas"),"ibm,fw-phb-id",NULL) != NULL) {
PPCDBG(PPCDBG_PHBINIT, "\tFound: ibm,fw-phb-id\n");
Pci_Large_Bus_System = 1;
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/pacaData.c linuxppc64_2_4/arch/ppc64/kernel/pacaData.c
--- linux/arch/ppc64/kernel/pacaData.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pacaData.c Fri Sep 7 07:59:15 2001
@@ -31,49 +31,33 @@
* processor (not thread).
*/
#define PACAINITDATA(number,start,lpq,asrr,asrv) \
-{ (struct ItLpPaca *)(((char *)(&xPaca[number]))+offsetof(struct Paca, xLpPaca)), \
- (struct ItLpRegSave *)(((char *)(&xPaca[number]))+offsetof(struct Paca, xRegSav)), \
- 0, /* Current */ \
- 0, /* R21 Save */ \
- 0, /* R22 Save */ \
- 0, /* Kernel stack addr save */ \
- (number), /* Paca Index */ \
- 0, /* HW Proc Number */ \
- 0, /* CCR Save */ \
- 0, /* MSR Save */ \
- 0, /* LR Save */ \
- 0, /* Pointer to thread */ \
- {(asrr), /* Real pointer to segment table */ \
- (asrv), /* Virt pointer to segment table */ \
- REGION_COUNT-1}, /* Round robin index */ \
- {0,0,0,0,0,0,0,0},/* Segment cache */ \
- 0, /* Kernel TOC address */ \
- 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 */ \
- (start), /* Processor start */ \
- {0,0,0}, /* Resv */ \
- 0, /* Default Decrementer */ \
- 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 */ \
+{ \
+ xLpPacaPtr: &xPaca[number].xLpPaca, \
+ xLpRegSavePtr: &xPaca[number].xRegSav, \
+ xPacaIndex: (number), /* Paca Index */ \
+ xStab_data: { \
+ real: (asrr), /* Real pointer to segment table */ \
+ virt: (asrv), /* Virt pointer to segment table */ \
+ next_round_robin: 1 /* Round robin index */ \
+ }, \
+ lpQueuePtr: (lpq), /* &xItLpQueue, */ \
+ xRtas: { \
+ lock: SPIN_LOCK_UNLOCKED \
+ }, \
+ xProcStart: (start), /* Processor start */ \
+ xLpPaca: { \
+ xDesc: 0xd397d781, /* "LpPa" */ \
+ xSize: sizeof(struct ItLpPaca), \
+ xFPRegsInUse: 1, \
+ xDynProcStatus: 2, \
+ xEndOfQuantum: 0xffffffffffffffff \
+ }, \
+ xRegSav: { \
+ xDesc: 0xd397d9e2, /* "LpRS" */ \
+ xSize: sizeof(struct ItLpRegSave) \
+ }, \
+ exception_sp: \
+ &xPaca[number].exception_stack[N_EXC_STACK*EXC_FRAME_SIZE], \
}
struct Paca xPaca[maxPacas] __page_aligned = {
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/pci.c linuxppc64_2_4/arch/ppc64/kernel/pci.c
--- linux/arch/ppc64/kernel/pci.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pci.c Thu Sep 6 15:59:33 2001
@@ -34,6 +34,17 @@
#include "pci.h"
+/* isa_io_limit -- only I/O ports above this addr are recognized by inb/outb.
+ * We fake failure below this limit without trashing the system.
+ * This is zero when an ISA bus exists, else PAGE_SIZE.
+ */
+unsigned long isa_io_limit = PAGE_SIZE;
+/* isa_io_base -- the base address from which io bars are offsets.
+ * This is the lowest I/O base address (so bar values are always positive),
+ * and it *must* be the start of ISA space if an ISA bus exists because
+ * ISA drivers use hard coded offsets. If no ISA bus exists a dummy
+ * page is mapped and isa_io_limit prevents access to it.
+ */
unsigned long isa_io_base = 0;
unsigned long isa_mem_base = 0;
unsigned long pci_dram_offset = 0;
@@ -41,7 +52,8 @@
/******************************************************************
* Forward declare of prototypes
******************************************************************/
-void pcibios_fixup_resources(struct pci_dev* dev);
+static void pcibios_fixup_resources(struct pci_dev* dev);
+static void fixup_broken_pcnet32(struct pci_dev* dev);
void fixup_resources(struct pci_dev* dev); /* In brand pci code */
struct pci_dev *find_floppy(void);
@@ -67,10 +79,20 @@
struct pci_dev *ppc64_floppy_dev = NULL;
struct pci_fixup pcibios_fixups[] = {
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 },
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources },
{ 0 }
};
+static void fixup_broken_pcnet32(struct pci_dev* dev)
+{
+ if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
+ dev->vendor = PCI_VENDOR_ID_AMD;
+ pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
+ pci_name_device(dev);
+ }
+}
+
void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
struct pbus_set_ranges_data *pranges)
{
@@ -83,7 +105,7 @@
{
u32 new, check;
int reg;
- struct pci_controller* hose = dev->sysdata;
+ struct pci_controller* hose = PCI_GET_PHB_PTR(dev);
new = res->start;
if (hose && res->flags & IORESOURCE_MEM)
@@ -186,22 +208,29 @@
{
struct list_head *ln;
struct pci_bus *bus;
- struct pci_dev *dev;
- int idx;
- struct resource *r, *pr;
+ int i;
+ struct resource *res, *pr;
/* Depth-First Search on bus tree */
for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
bus = pci_bus_b(ln);
- if ((dev = bus->self)) {
- for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
- r = &dev->resource[idx];
- if (!r->start)
- continue;
- pr = pci_find_parent_resource(dev, r);
- if (!pr || request_resource(pr, r) < 0)
- printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
- }
+ for (i = 0; i < 4; ++i) {
+ if ((res = bus->resource[i]) == NULL || !res->flags)
+ continue;
+ if (bus->parent == NULL)
+ pr = (res->flags & IORESOURCE_IO)?
+ &ioport_resource: &iomem_resource;
+ else
+ pr = pci_find_parent_resource(bus->self, res);
+
+ if (pr == res)
+ continue; /* transparent bus or undefined */
+ if (pr && request_resource(pr, res) == 0)
+ continue;
+ printk(KERN_ERR "PCI: Cannot allocate resource region "
+ "%d of PCI bridge %x\n", i, bus->number);
+ printk(KERN_ERR "PCI: resource is %lx..%lx (%lx), parent %p\n",
+ res->start, res->end, res->flags, pr);
}
pcibios_allocate_bus_resources(&bus->children);
}
@@ -398,14 +427,13 @@
/* Scan all of the recorded PCI controllers. */
for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
hose->last_busno = 0xff;
- bus = pci_scan_bus(hose->first_busno, hose->ops, hose);
+ bus = pci_scan_bus(hose->first_busno, hose->ops, hose->arch_data);
hose->bus = bus;
hose->last_busno = bus->subordinate;
if (pci_assign_all_busses || next_busno <= hose->last_busno)
next_busno = hose->last_busno+1;
}
pci_bus_count = next_busno;
-
/* Call machine dependant fixup */
if (ppc_md.pcibios_fixup) {
@@ -417,21 +445,13 @@
/* Allocate and assign resources */
pcibios_allocate_bus_resources(&pci_root_buses);
- if(naca->io_subsystem == IOS_OPEN_PIC) {
- pcibios_allocate_resources(0); // DRENG Condor removed. This will have to be reviewed!!!
- }
- if(naca->io_subsystem == IOS_OPEN_PIC) {
- pcibios_allocate_resources(1); // DRENG Condor removed. This will have to be reviewed!!!
- }
+ pcibios_allocate_resources(0);
+ pcibios_allocate_resources(1);
pcibios_assign_resources();
- /*
- * Set up TCE tables for each PHB.
- */
- for (hose = hose_head; hose; hose = hose->next) {
- create_pci_bus_tce_table(hose->global_number,
- (unsigned long)hose);
- }
+ pci_fix_bus_sysdata();
+
+ create_tce_tables();
ppc64_floppy_dev = find_floppy();
@@ -454,7 +474,53 @@
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
- pci_read_bridge_bases(bus);
+ struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
+ struct resource *res;
+ unsigned long io_offset;
+ int i;
+
+ io_offset = (unsigned long)phb->io_base_virt - isa_io_base;
+
+ if (bus->parent == NULL) {
+ /* This is a host bridge - fill in its resources */
+ phb->bus = bus;
+ bus->resource[0] = res = &phb->io_resource;
+ if (!res->flags)
+ BUG(); /* No I/O resource for this PHB? */
+
+ for (i = 0; i < 3; ++i) {
+ res = &phb->mem_resources[i];
+ if (!res->flags) {
+ if (i == 0)
+ BUG(); /* No memory resource for this PHB? */
+ }
+ bus->resource[i+1] = res;
+ }
+ } else {
+ /* This is a subordinate bridge */
+ pci_read_bridge_bases(bus);
+
+ for (i = 0; i < 4; ++i) {
+ if ((res = bus->resource[i]) == NULL)
+ continue;
+ if (!res->flags)
+ continue;
+ if (res == pci_find_parent_resource(bus->self, res)) {
+ /* Transparent resource -- don't try to "fix" it. */
+ continue;
+ }
+ if (res->flags & IORESOURCE_IO) {
+ res->start += io_offset;
+ res->end += io_offset;
+ } else if (phb->pci_mem_offset
+ && (res->flags & IORESOURCE_MEM)) {
+ if (res->start < phb->pci_mem_offset) {
+ res->start += phb->pci_mem_offset;
+ res->end += phb->pci_mem_offset;
+ }
+ }
+ }
+ }
if ( ppc_md.pcibios_fixup_bus )
ppc_md.pcibios_fixup_bus(bus);
@@ -546,7 +612,7 @@
*/
int pci_controller_num(struct pci_dev *dev)
{
- struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
+ struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
return hose->global_number;
}
@@ -572,7 +638,7 @@
__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
- struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
+ struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long io_offset = 0;
int i, res_bit;
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/pci.h linuxppc64_2_4/arch/ppc64/kernel/pci.h
--- linux/arch/ppc64/kernel/pci.h Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pci.h Wed Sep 5 13:56:40 2001
@@ -9,8 +9,6 @@
#ifndef __PPC_KERNEL_PCI_H__
#define __PPC_KERNEL_PCI_H__
-/* Include these to prevent strange compile warnings if user forgets
- * to include them in their .c file. */
#include
#include
@@ -29,27 +27,55 @@
extern struct pci_controller* pci_alloc_pci_controller(char *model, enum phb_types controller_type);
extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node);
+extern struct pci_controller* hose_head;
+extern struct pci_controller** hose_tail;
+
/*******************************************************************
* Platform functions that are brand specific implementation.
*******************************************************************/
extern unsigned long find_and_init_phbs(void);
-extern int pci_read_irq_line(struct pci_dev* PciDev);
-extern int pci_read_bar_registers(struct pci_dev* PciDev, int Count, int RomFlag);
-
extern void fixup_resources(struct pci_dev *dev);
extern void ppc64_pcibios_init(void);
extern int pci_reset_device(struct pci_dev*);
extern int pci_get_location(struct pci_dev*, char*, int);
-extern struct pci_dev* find_floppy(void);
extern struct pci_dev *ppc64_floppy_dev;
+
+/*******************************************************************
+ * PCI device_node operations
+ *******************************************************************/
+struct device_node;
+typedef void *(*traverse_func)(struct device_node *me, void *data);
+void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data);
+void *traverse_all_pci_devices(traverse_func pre);
+
+void pci_devs_phb_init(void);
+void pci_fix_bus_sysdata(void);
+struct device_node *fetch_dev_dn(struct pci_dev *dev);
+
+/* Get a device_node from a pci_dev. This code must be fast except in the case
+ * where the sysdata is incorrect and needs to be fixed up (hopefully just once)
+ */
+static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
+{
+ struct device_node *dn = (struct device_node *)(dev->sysdata);
+ if (dn->devfn == dev->devfn && dn->busno == dev->bus->number)
+ return dn; /* fast path. sysdata is good */
+ else
+ return fetch_dev_dn(dev);
+}
+/* Use this macro after the PCI bus walk for max performance when it
+ * is known that sysdata is correct.
+ */
+#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
+
+
/*******************************************************************
* Platform configuration flags.. (Live in pci.c)
*******************************************************************/
extern int Pci_Large_Bus_System; /* System has > 256 buses */
-extern int Pci_Set_IOA_Address; /* Set IOA BARs from OF */
extern int Pci_Manage_Phb_Space; /* Manage Phb Space for IOAs*/
/*******************************************************************
@@ -58,9 +84,9 @@
* PCI_GET_PHB_NUMBER(struct pci_dev*) returns the Phb number.
* PCI_GET_BUS_NUMBER(struct pci_dev*) returns the bus number.
*******************************************************************/
-#define PCI_GET_PHB_PTR(PCIDEV) ((struct pci_controller*)##PCIDEV##->sysdata)
-#define PCI_GET_PHB_NUMBER(PCIDEV) ((##PCIDEV##->bus->number&0x00FFFF00)>>8)
-#define PCI_GET_BUS_NUMBER(PCIDEV) ( ##PCIDEV##->bus->number&0x0000FF)
+#define PCI_GET_PHB_PTR(dev) (((struct device_node *)(dev)->sysdata)->phb)
+#define PCI_GET_PHB_NUMBER(dev) (((dev)->bus->number&0x00FFFF00)>>8)
+#define PCI_GET_BUS_NUMBER(dev) ((dev)->bus->number&0x0000FF)
/*******************************************************************
* Pci Flight Recorder support.
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/pci_dma.c linuxppc64_2_4/arch/ppc64/kernel/pci_dma.c
--- linux/arch/ppc64/kernel/pci_dma.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pci_dma.c Thu Sep 6 13:24:15 2001
@@ -39,6 +39,10 @@
#include
#include
+#include
+
+#include "pci.h"
+
#define DEBUG_TCE 1
/* Initialize so this guy does not end up in the BSS section.
@@ -47,6 +51,9 @@
*/
extern struct _of_tce_table of_tce_table[];
+extern struct pci_controller* hose_head;
+extern struct pci_controller** hose_tail;
+
struct TceTable virtBusTceTable; /* Tce table for virtual bus */
struct TceTable * tceTables[256]; /* Tce tables for 256 busses
@@ -62,9 +69,9 @@
static long alloc_tce_range_nolock( struct TceTable *,
unsigned order );
/* frees a contiguous range of tces (power-of-2 size) */
-static void free_tce_range( struct TceTable *,
- long tcenum,
- unsigned order );
+void free_tce_range( struct TceTable *,
+ long tcenum,
+ unsigned order );
/* frees a contiguous rnage of tces (power-of-2 size)
* assumes lock already held
*/
@@ -78,10 +85,6 @@
unsigned numPages,
int tceType,
int direction );
-static void free_tces( struct TceTable *,
- dma_addr_t tce,
- unsigned order,
- unsigned numPages );
static long test_tce_range( struct TceTable *,
long tcenum,
unsigned order );
@@ -99,84 +102,109 @@
int tceType,
int direction );
-static void getTceTableParms( struct pci_controller *phb,
- struct TceTable *tce_table_parms );
+static void getTceTableParmsPSeries( struct pci_controller *phb,
+ struct TceTable *tce_table_parms );
-static unsigned long setTce( unsigned long base,
- unsigned long tce_num,
- unsigned long tce_data);
-
static long resv_tce_range_top_level( struct TceTable *tbl,
unsigned long dma_addr,
unsigned size );
+static void create_pci_bus_tce_table( unsigned long token );
+
u8 iSeries_Get_Bus( struct pci_dev * dv )
{
return 0;
}
-/*
- * Given a pci device, return which tce table is assigned to it.
- */
-unsigned long get_tce_table_index( struct pci_dev *dev) {
- unsigned long index =
- ((struct pci_controller *)dev->sysdata)->global_number;
- PPCDBG(PPCDBG_TCE, "get_tce_table_index:\n");
- PPCDBG(PPCDBG_TCE, "\tdev = 0x%lx, index = 0x%lx\n", dev, index);
- return(index);
+struct TceTable *get_tce_table(struct pci_dev *dev) {
+ unsigned long bus;
+
+ switch(_machine) {
+ case _MACH_iSeries:
+ /* If no dev, assume virtual bus */
+ if(dev) bus = ISERIES_GET_BUS(dev);
+ else bus = 255;
+ return(tceTables[bus]);
+ default:
+ return PCI_GET_DN(dev)->tce_table;
+ }
+ return(NULL);
}
-static unsigned __inline__ count_leading_zeros32( unsigned long x )
+static unsigned long __inline__ count_leading_zeros64( unsigned long x )
{
- unsigned lz;
- asm("cntlzw %0,%1" : "=r"(lz) : "r"(x));
+ unsigned long lz;
+ asm("cntlzd %0,%1" : "=r"(lz) : "r"(x));
return lz;
}
-static void __inline__ build_tce( struct TceTable * tbl, long tcenum,
- unsigned long uaddr, int tceType, int direction )
+static void tce_build_iSeries(struct TceTable *tbl, long tcenum,
+ unsigned long uaddr, int tceType, int direction )
{
u64 setTceRc;
union Tce tce;
PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr);
+ PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n",
+ tcenum, tbl, tbl->index);
+
tce.wholeTce = 0;
tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+
/* If for virtual bus */
if ( tceType == TCE_VB ) {
tce.tceBits.valid = 1;
tce.tceBits.allIo = 1;
if ( direction != PCI_DMA_TODEVICE )
tce.tceBits.readWrite = 1;
- }
- /* If for PCI bus */
- else {
+ } else {
+ /* If for PCI bus */
tce.tceBits.readWrite = 1; // Read allowed
if ( direction != PCI_DMA_TODEVICE )
tce.tceBits.pciWrite = 1;
}
-#ifdef CONFIG_PPC_ISERIES
- setTceRc = HvCallXm_setTce( (u64)tbl->index, (u64)tcenum, tce.wholeTce );
-#else
- setTceRc = setTce( (u64)tbl->base, (u64)tcenum, tce.wholeTce );
-#endif
+ setTceRc = HvCallXm_setTce((u64)tbl->index,
+ (u64)tcenum,
+ tce.wholeTce );
- if ( setTceRc ) {
- PPCDBG(PPCDBG_TCE, "build_tce: HvCallXm_setTce failed, rc=%ld, index=%ld, tcenum=%0lx, tce=%016lx\n",
- (u64)tbl->index, (u64)tcenum, tce.wholeTce );
+ if(setTceRc) {
+ PPCDBG(PPCDBG_TCE, "setTce failed. rc=%ld\n", setTceRc);
+ PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n", (u64)tbl->index);
+ PPCDBG(PPCDBG_TCE, "\ttce num = 0x%lx\n", (u64)tcenum);
+ PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n", tce.wholeTce );
}
-
}
+static void tce_build_pSeries(struct TceTable *tbl, long tcenum,
+ unsigned long uaddr, int tceType, int direction )
+{
+ union Tce tce;
+ union Tce *tce_addr;
+
+ PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr);
+ PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n",
+ tcenum, tbl, tbl->index);
+ tce.wholeTce = 0;
+ tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+
+ tce.tceBits.readWrite = 1; // Read allowed
+ if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1;
+
+ tce_addr = ((union Tce *)tbl->base) + tcenum;
+ *tce_addr = (union Tce)tce.wholeTce;
+
+ /* Make sure the update is visible to hardware. */
+ __asm__ __volatile__ ("sync" : : : "memory");
+}
/*
* Build a TceTable structure. This contains a multi-level bit map which
* is used to manage allocation of the tce space.
*/
-struct TceTable * build_tce_table( struct TceTable * tbl )
+static struct TceTable *build_tce_table( struct TceTable * tbl )
{
unsigned long bits, bytes, totalBytes;
unsigned long numBits[NUM_TCE_LEVELS], numBytes[NUM_TCE_LEVELS];
@@ -199,7 +227,7 @@
numBits[i] = bits;
numBytes[i] = bytes;
bits /= 2;
- totalBytes += bytes;
+ totalBytes += ((bytes + 7) / 8) * 8;
}
PPCDBG(PPCDBG_TCE, "build_tce_table: totalBytes=%ld\n", totalBytes );
@@ -259,9 +287,7 @@
}
}
-
return tbl;
-
}
static long alloc_tce_range( struct TceTable *tbl, unsigned order )
@@ -288,7 +314,7 @@
unsigned long numBits, numBytes;
unsigned long i, bit, block, mask;
long tcenum;
- unsigned char * map;
+ u64 * map;
/* If the order (power of 2 size) requested is larger than our
* biggest, indicate failure
@@ -301,23 +327,23 @@
numBits = tbl->mlbm.level[order].numBits;
numBytes = tbl->mlbm.level[order].numBytes;
- map = tbl->mlbm.level[order].map;
+ map = (u64 *)tbl->mlbm.level[order].map;
/* Initialize return value to -1 (failure) */
tcenum = -1;
/* Loop through the bytes of the bitmap */
- for (i=0; i> bit);
+ mask = 0xffffffffffffffffLL ^ (0x8000000000000000LL >> bit);
*map &= mask;
/* compute the index into our tce table for
* the first tce in the block
@@ -357,7 +383,7 @@
}
-static void free_tce_range( struct TceTable *tbl, long tcenum, unsigned order )
+void free_tce_range( struct TceTable *tbl, long tcenum, unsigned order )
{
unsigned long flags;
@@ -372,7 +398,7 @@
}
-static void free_tce_range_nolock( struct TceTable *tbl, long tcenum, unsigned order )
+static void free_tce_range_nolock( struct TceTable *tbl, long tcenum, unsigned order )
{
unsigned long block;
unsigned byte, bit, mask, b;
@@ -415,10 +441,12 @@
* If this is the highest level we can't buddy up
* If this level has an odd number of bits and
* we are freeing the last block we can't buddy up
+ * Don't buddy up if it's in the first 1/4 of the level
*/
if ( ( order < tbl->mlbm.maxLevel ) &&
( ( 0 == ( tbl->mlbm.level[order].numBits & 1 ) ) ||
- ( block < tbl->mlbm.level[order].numBits-1 ) ) ) {
+ ( block < tbl->mlbm.level[order].numBits-1 ) ) &&
+ ( block > (tbl->mlbm.level[order].numBits/4) ) ) {
/* See if we can buddy up the block we just freed */
bit &= 6; /* get to the first of the buddy bits */
@@ -485,7 +513,8 @@
retTce = tcenum << PAGE_SHIFT; /* Set the return dma address */
/* Setup a tce for each page */
for (i=0; istartOffset;
if ( tcenum > maxTcenum ) {
- PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum, tcenum = %ld, maxTcenum = %ld\n",
- tcenum, maxTcenum );
- PPCDBG(PPCDBG_TCE, "free_tces: TCE Table at %16lx\n", (unsigned long)tbl );
- PPCDBG(PPCDBG_TCE, "free_tces: bus# %lu\n", (unsigned long)tbl->busNumber );
- PPCDBG(PPCDBG_TCE, "free_tces: size %lu\n", (unsigned long)tbl->size );
- PPCDBG(PPCDBG_TCE, "free_tces: startOff %lu\n", (unsigned long)tbl->startOffset );
- PPCDBG(PPCDBG_TCE, "free_tces: index %lu\n", (unsigned long)tbl->index );
+ PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n");
+ PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx\n", tcenum);
+ PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum);
+ PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl);
+ PPCDBG(PPCDBG_TCE, "\tbus# = 0x%lx\n",
+ (u64)tbl->busNumber );
+ PPCDBG(PPCDBG_TCE, "\tsize = 0x%lx\n", (u64)tbl->size);
+ PPCDBG(PPCDBG_TCE, "\tstartOff = 0x%lx\n",
+ (u64)tbl->startOffset );
+ PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n", (u64)tbl->index);
return;
}
@@ -522,22 +555,68 @@
for (i=0; iindex, (u64)tcenum, tce.wholeTce );
-#else
- setTceRc = setTce( (u64)tbl->base, (u64)tcenum, tce.wholeTce );
-#endif
+ setTceRc = HvCallXm_setTce((u64)tbl->index,
+ (u64)tcenum,
+ tce.wholeTce );
if ( setTceRc ) {
- PPCDBG(PPCDBG_TCE, "free_tces: HvCallXm_setTce failed, rc=%ld, index=%ld, tcenum=%0lx, tce=%016lx\n",
- (u64)tbl->index, (u64)tcenum, tce.wholeTce );
+ PPCDBG(PPCDBG_TCE, "tce_free: setTce failed\n");
+ PPCDBG(PPCDBG_TCE, "\trc = 0x%lx\n", setTceRc);
+ PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n",
+ (u64)tbl->index);
+ PPCDBG(PPCDBG_TCE, "\ttce num = 0x%lx\n", (u64)tcenum);
+ PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n",
+ tce.wholeTce );
}
++tcenum;
}
free_tce_range( tbl, freeTce, order );
+}
+
+static void tce_free_pSeries(struct TceTable *tbl, dma_addr_t dma_addr,
+ unsigned order, unsigned numPages)
+{
+ long tcenum, freeTce, maxTcenum;
+ unsigned i;
+ union Tce tce;
+ union Tce *tce_addr;
+
+ maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1;
+
+ tcenum = dma_addr >> PAGE_SHIFT;
+ tcenum -= tbl->startOffset;
+
+ if ( tcenum > maxTcenum ) {
+ PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n");
+ PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx\n", tcenum);
+ PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum);
+ PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl);
+ PPCDBG(PPCDBG_TCE, "\tbus# = 0x%lx\n",
+ (u64)tbl->busNumber );
+ PPCDBG(PPCDBG_TCE, "\tsize = 0x%lx\n", (u64)tbl->size);
+ PPCDBG(PPCDBG_TCE, "\tstartOff = 0x%lx\n",
+ (u64)tbl->startOffset );
+ PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n", (u64)tbl->index);
+ return;
+ }
+
+ freeTce = tcenum;
+
+ for (i=0; ibase) + tcenum;
+ *tce_addr = (union Tce)tce.wholeTce;
+
+ ++tcenum;
+ }
+
+ /* Make sure the update is visible to hardware. */
+ __asm__ __volatile__ ("sync" : : : "memory");
+ free_tce_range( tbl, freeTce, order );
}
void __init create_virtual_bus_tce_table(void)
@@ -572,67 +651,93 @@
PPCDBG(PPCDBG_TCE, "Virtual Bus TCE table failed.\n");
}
-void create_pci_bus_tce_table( unsigned long busNumber,
- unsigned long token )
-{
- struct TceTable * t;
+void create_tce_tables(void) {
+ struct pci_controller *hose;
+ struct pci_dev *dev;
+ struct device_node *dn, *mydn;
+
+ if(_machine == _MACH_pSeries) {
+ for (hose = hose_head; hose; hose = hose->next) {
+ create_pci_bus_tce_table((unsigned long)hose);
+ }
+ }
+
+ /* Now copy the tce_table ptr from the bus devices down to every
+ * pci device_node. This means get_tce_table() won't need to search
+ * up the device tree to find it.
+ */
+ pci_for_each_dev(dev) {
+ mydn = dn = PCI_GET_DN(dev);
+ while (dn && dn->tce_table == NULL)
+ dn = dn->parent;
+ if (dn) {
+ mydn->tce_table = dn->tce_table;
+ } else {
+ printk("create_tce_tables could not locate a tce table for a device!\n");
+ BUG();
+ }
+ }
+}
+
+/*
+ * iSeries token = busNumber
+ * pSeries token = pci_controller*
+ */
+static void create_pci_bus_tce_table( unsigned long token ) {
+ struct TceTable * builtTceTable;
struct TceTable * newTceTable;
struct TceTableManagerCB pciBusTceTableParms;
-#ifdef CONFIG_PPC_ISERIES
u64 parmsPtr;
-#endif
- struct pci_controller *phb = (struct pci_controller *)token;
PPCDBG(PPCDBG_TCE, "Entering create_pci_bus_tce_table.\n");
- PPCDBG(PPCDBG_TCE, "\tbusNumber = 0x%lx, token = 0x%lx.\n",
- busNumber, token);
- if ( busNumber > 254 ) {
- PPCDBG(PPCDBG_TCE, "PCI Bus TCE table failed.\n");
- PPCDBG(PPCDBG_TCE, " Invalid bus number %u\n", busNumber );
- return;
- }
+ PPCDBG(PPCDBG_TCE, "\ttoken = 0x%lx\n", token);
newTceTable = kmalloc( sizeof(struct TceTable), GFP_KERNEL );
- PPCDBG(PPCDBG_TCE, "\tnewTceTable = 0x%lx\n", newTceTable);
- pciBusTceTableParms.busNumber = busNumber;
- pciBusTceTableParms.virtualBusFlag = 0;
-
-#ifdef CONFIG_PPC_ISERIES
- parmsPtr = virt_to_absolute( (u64)&pciBusTceTableParms );
+ if(_machine == _MACH_iSeries) {
+ if ( token > 254 ) {
+ PPCDBG(PPCDBG_TCE, "PCI Bus TCE table failed.\n");
+ PPCDBG(PPCDBG_TCE, " Invalid bus number %u\n", token );
+ return;
+ }
- /*
- * Call HV with the architected data structure to get TCE table info.
- * Put the returned data into the Linux representation of the TCE
- * table data.
- */
- HvCallXm_getTceTableParms( parmsPtr );
- newTceTable->size = pciBusTceTableParms.size;
- newTceTable->busNumber = pciBusTceTableParms.busNumber;
- newTceTable->startOffset = pciBusTceTableParms.startOffset;
- newTceTable->index = pciBusTceTableParms.index;
-#else
- getTceTableParms( phb, newTceTable );
-#endif
-
- t = build_tce_table( newTceTable );
- if ( t ) {
- tceTables[busNumber] = t;
- PPCDBG(PPCDBG_TCE, "PCI Bus TCE table built successfully.\n");
- PPCDBG(PPCDBG_TCE, " TCE table size = %ld entries\n",
- (unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) );
- PPCDBG(PPCDBG_TCE, " TCE table token = %d\n",
- (unsigned)t->index );
- PPCDBG(PPCDBG_TCE, " TCE table start entry = 0x%lx\n",
- (unsigned long)t->startOffset );
+ pciBusTceTableParms.busNumber = token;
+ pciBusTceTableParms.virtualBusFlag = 0;
+ parmsPtr = virt_to_absolute( (u64)&pciBusTceTableParms );
+
+ /*
+ * Call HV with the architected data structure to get TCE table
+ * info. Put the returned data into the Linux representation
+ * of the TCE table data.
+ */
+ HvCallXm_getTceTableParms( parmsPtr );
+
+ newTceTable->size = pciBusTceTableParms.size;
+ newTceTable->busNumber = pciBusTceTableParms.busNumber;
+ newTceTable->startOffset = pciBusTceTableParms.startOffset;
+ newTceTable->index = pciBusTceTableParms.index;
+
+ builtTceTable = build_tce_table( newTceTable );
+ tceTables[token] = builtTceTable;
+ return;
+ } else if(_machine == _MACH_pSeries) {
+ struct pci_controller *phb = (struct pci_controller *)token;
+ struct device_node *phbdn = (struct device_node *)phb->arch_data;
+
+ getTceTableParmsPSeries(phb, newTceTable);
+ builtTceTable = build_tce_table( newTceTable );
+ phbdn->tce_table = builtTceTable;
}
- else {
+
+ if(builtTceTable == NULL ) {
kfree( newTceTable );
PPCDBG(PPCDBG_TCE, "PCI Bus TCE table failed.\n");
return;
}
-#ifndef CONFIG_PPC_ISERIES
+ if (_machine != _MACH_pSeries)
+ return;
+
/* Do not allow DMA's to the 1st 16MB of PCI space in order
* to account for the I/O hole and aliases.
*
@@ -649,12 +754,7 @@
resv_tce_range_top_level(newTceTable, rtas.base,
(rtas.size) >> PAGE_SHIFT);
-#if 1
/* Initialize the table to have a one-to-one mapping over RTAS */
-
- /* DRENG strictly speaking, the RPA says this should be done.
- * I do not see how it can really be a valid thing to require however.
- */
{
unsigned long tce_entry, *tce_entryp, i;
@@ -669,16 +769,10 @@
tce_entry += (1UL << PAGE_SHIFT);
}
}
-#endif
-#endif
}
-static void getTceTableParms( struct pci_controller *phb,
- struct TceTable *newTceTable ) {
-#if 0
- struct pci_dev *dev;
- struct device_node *np;
-#endif
+static void getTceTableParmsPSeries(struct pci_controller *phb,
+ struct TceTable *newTceTable ) {
phandle node;
unsigned long i;
@@ -712,18 +806,9 @@
}
i++;
}
-
-#if 0
- pci_for_each_dev(dev) {
- np = pci_device_to_OF_node(dev);
- node = np->node;
- bus_number = dev->bus->number;
- create_pci_bus_tce_table( unsigned long bus_number );
- node = hose->arch_data->node;
- }
-#endif
}
+
/* Allocates a contiguous real buffer and creates TCEs over it.
* Returns the virtual address of the buffer and sets dma_handle
* to the dma address (tce) of the first page.
@@ -733,7 +818,7 @@
{
struct TceTable * tbl;
void *ret = NULL;
- unsigned order, nPages, bus;
+ unsigned order, nPages;
dma_addr_t tce;
int tceType;
@@ -748,24 +833,13 @@
/* If no pci_dev then use virtual bus */
if (hwdev == NULL ) {
- bus = 255;
tceType = TCE_VB;
- }
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = get_tce_table_index( hwdev );
- // bus = ISERIES_GET_BUS( hwdev );
+ } else {
tceType = TCE_PCI;
-#else
- BUG();
- return NULL;
-#endif /* CONFIG_PCI */
}
- tbl = tceTables[bus];
+ tbl = get_tce_table(hwdev);
+
if ( tbl ) {
/* Alloc enough pages (and possibly more) */
ret = (void *)__get_free_pages( GFP_ATOMIC, order );
@@ -798,7 +872,7 @@
void *vaddr, dma_addr_t dma_handle)
{
struct TceTable * tbl;
- unsigned order, nPages, bus;
+ unsigned order, nPages;
PPCDBG(PPCDBG_TCE, "pci_free_consistent:\n");
PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, dma_handle = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, dma_handle, vaddr);
@@ -811,31 +885,10 @@
PPCDBG(PPCDBG_TCE, "pci_free_consistent: order=%d, size=%d, nPages=%d, dma_handle=%016lx, vaddr=%016lx\n",
order, size, nPages, (unsigned long)dma_handle, (unsigned long)vaddr );
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL )
- bus = 255;
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = get_tce_table_index( hwdev );
- // bus = ISERIES_GET_BUS( hwdev );
-#else
- BUG();
- return;
-#endif /* CONFIG_PCI */
- }
-
- if ( bus > 255 ) {
- PPCDBG(PPCDBG_TCE, "pci_free_consistent: invalid bus # %d\n", bus );
- PPCDBG(PPCDBG_TCE, "pci_free_consistent: hwdev = %08lx\n", (unsigned long)hwdev );
- }
-
- tbl = tceTables[bus];
+ tbl = get_tce_table(hwdev);
if ( tbl ) {
- free_tces( tbl, dma_handle, order, nPages );
+ ppc_md.tce_free(tbl, dma_handle, order, nPages);
free_pages( (unsigned long)vaddr, order );
}
}
@@ -851,7 +904,7 @@
struct TceTable * tbl;
dma_addr_t dma_handle;
unsigned long uaddr;
- unsigned order, nPages, bus;
+ unsigned order, nPages;
int tceType;
PPCDBG(PPCDBG_TCE, "pci_map_single:\n");
@@ -868,25 +921,12 @@
/* If no pci_dev then use virtual bus */
if (hwdev == NULL ) {
- bus = 255;
tceType = TCE_VB;
- }
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = get_tce_table_index( hwdev );
- // bus = ISERIES_GET_BUS( hwdev );
+ } else {
tceType = TCE_PCI;
-#else
- BUG();
- return NO_TCE;
-#endif /* CONFIG_PCI */
-
}
- tbl = tceTables[bus];
+ tbl = get_tce_table(hwdev);
if ( tbl ) {
dma_handle = get_tces( tbl, order, vaddr, nPages, tceType,
@@ -900,7 +940,7 @@
void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction )
{
struct TceTable * tbl;
- unsigned order, nPages, bus;
+ unsigned order, nPages;
PPCDBG(PPCDBG_TCE, "pci_unmap_single:\n");
PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, direction = 0x%16.16lx, dma_handle = 0x%16.16lx\n", hwdev, size, direction, dma_handle);
@@ -915,31 +955,10 @@
PPCDBG(PPCDBG_TCE, "pci_unmap_single: order=%d, size=%d, nPages=%d, dma_handle=%016lx\n",
order, size, nPages, (unsigned long)dma_handle );
- /* If no pci_dev then use virtual bus */
- if (hwdev == NULL )
- bus = 255;
- else {
-#ifdef CONFIG_PCI
- /* Get the iSeries bus # to use as an index
- * into the TCE table array
- */
- bus = get_tce_table_index( hwdev );
- // bus = ISERIES_GET_BUS( hwdev );
-#else
- BUG();
- return;
-#endif /* CONFIG_PCI */
- }
-
- if ( bus > 255 ) {
- PPCDBG(PPCDBG_TCE, "pci_unmap_single: invalid bus # %d\n", bus );
- PPCDBG(PPCDBG_TCE, "pci_unmap_single: hwdev = %08lx\n", (unsigned long)hwdev );
- }
-
- tbl = tceTables[bus];
+ tbl = get_tce_table(hwdev);
if ( tbl )
- free_tces( tbl, dma_handle, order, nPages );
+ ppc_md.tce_free(tbl, dma_handle, order, nPages);
}
@@ -1113,8 +1132,8 @@
}
for (i=0; i 255 ) {
- PPCDBG(PPCDBG_TCE, "pci_unmap_sg: invalid bus # %d\n", bus );
- PPCDBG(PPCDBG_TCE, "pci_unmap_sg: hwdev = %08lx\n", (unsigned long)hwdev );
- }
-
-
- tbl = tceTables[bus];
+ tbl = get_tce_table(hwdev);
if ( tbl )
- free_tces( tbl, dma_start_page, order, numTces );
-
-}
-
-static unsigned long setTce( unsigned long base,
- unsigned long tce_num,
- unsigned long tce_data) {
- union Tce *tce_addr;
-
- PPCDBG(PPCDBG_TCE, "setTce:\n");
- PPCDBG(PPCDBG_TCE, "\tbase = 0x%lx\n", base);
- PPCDBG(PPCDBG_TCE, "\ttce_num = 0x%lx\n", tce_num);
- PPCDBG(PPCDBG_TCE, "\ttce_data = 0x%lx\n", tce_data);
-
- tce_addr = ((union Tce *)base) + tce_num;
-
- PPCDBG(PPCDBG_TCE, "\ttce_addr = 0x%lx\n", tce_addr);
-
- *tce_addr = (union Tce)tce_data;
+ ppc_md.tce_free( tbl, dma_start_page, order, numTces );
- /* Make sure the update is visible to hardware. */
- __asm__ __volatile__ ("sync" : : : "memory");
-
- return(0);
}
+/*
+ * phb_tce_table_init
+ *
+ * Function: Display TCE config registers. Could be easily changed
+ * to initialize the hardware to use TCEs.
+ */
unsigned long phb_tce_table_init(struct pci_controller *phb) {
unsigned int r, cfg_rw, i;
unsigned long r64;
@@ -1320,7 +1288,8 @@
}
PPCDBG(PPCDBG_TCEINIT, "phb_tce_table_init: done\n");
- // create_pci_bus_tce_table(phb->number, (unsigned long)phb);
+
+ return(0);
}
/*
@@ -1380,4 +1349,18 @@
}
return(0);
+}
+
+
+/* These are called very early. */
+void tce_init_pSeries(void)
+{
+ ppc_md.tce_build = tce_build_pSeries;
+ ppc_md.tce_free = tce_free_pSeries;
+}
+
+void tce_init_iSeries(void)
+{
+ ppc_md.tce_build = tce_build_iSeries;
+ ppc_md.tce_free = tce_free_iSeries;
}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/pci_dn.c linuxppc64_2_4/arch/ppc64/kernel/pci_dn.c
--- linux/arch/ppc64/kernel/pci_dn.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/arch/ppc64/kernel/pci_dn.c Mon Sep 10 14:27:51 2001
@@ -0,0 +1,334 @@
+/*
+ * pci_dn.c
+ *
+ * Copyright (C) 2001 Todd Inglett, IBM Corporation
+ *
+ * PCI manipulation via device_nodes.
+ *
+ * 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
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "pci.h"
+
+/* ToDo: need an interface for these. Probably ppc_md... */
+extern int rtas_read_config_dword(struct device_node *dn, int offset, u32 *val);
+extern int rtas_write_config_dword(struct device_node *dn, int offset, u32 val);
+
+/* Traverse_func that inits the PCI fields of the device node.
+ * NOTE: this *must* be done before read/write config to the device.
+ */
+static void * __init
+update_dn_pci_info(struct device_node *dn, void *data)
+{
+ struct pci_controller *phb = (struct pci_controller *)data;
+ u32 *regs;
+ char *name = get_property(dn, "name", 0);
+ char *device_type = get_property(dn, "device_type", 0);
+
+ dn->phb = phb;
+ if (device_type && strcmp(device_type, "pci") == 0 && get_property(dn, "class-code", 0) == 0) {
+ /* special case for PHB's. Sigh. */
+ regs = (u32 *)get_property(dn, "bus-range", 0);
+ dn->busno = regs[0];
+ dn->devfn = 0; /* assumption */
+ } else {
+ regs = (u32 *)get_property(dn, "reg", 0);
+ if (regs) {
+ /* First register entry is addr (00BBSS00) */
+ dn->busno = (regs[0] >> 16) & 0xff;
+ dn->devfn = (regs[0] >> 8) & 0xff;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Hit all the BARs of all the devices with values from OF.
+ * This is unnecessary on most systems, but also harmless.
+ */
+static void * __init
+write_OF_bars(struct device_node *dn, void *data)
+{
+ int i;
+ u32 oldbar, newbar, newbartest;
+ u8 config_offset;
+ char *name = get_property(dn, "name", 0);
+ char *device_type = get_property(dn, "device_type", 0);
+ char devname[128];
+ sprintf(devname, "%04x:%02x.%x %s (%s)", dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn), name ? name : "", device_type ? device_type : "");
+
+ if (device_type && strcmp(device_type, "pci") == 0 &&
+ get_property(dn, "class-code", 0) == 0)
+ return NULL; /* This is probably a phb. Skip it. */
+
+ if (dn->n_addrs == 0)
+ return NULL; /* This is normal for some adapters or bridges */
+
+ if (dn->addrs == NULL) {
+ /* This shouldn't happen. */
+ printk(KERN_WARNING "write_OF_bars %s: device has %d BARs, but no addrs recorded\n", devname, dn->n_addrs);
+ return NULL;
+ }
+
+/* Need to add iSeries support here... AHT */
+#ifndef CONFIG_PPC_ISERIES
+ for (i = 0; i < dn->n_addrs; i++) {
+ newbar = dn->addrs[i].address;
+ config_offset = dn->addrs[i].space & 0xff;
+ if (rtas_read_config_dword(dn, config_offset, &oldbar) != PCIBIOS_SUCCESSFUL) {
+ printk(KERN_WARNING "write_OF_bars %s: read BAR%d failed\n", devname, i);
+ continue;
+ }
+ /* Need to update this BAR. */
+ if (rtas_write_config_dword(dn, config_offset, newbar) != PCIBIOS_SUCCESSFUL) {
+ printk(KERN_WARNING "write_OF_bars %s: write BAR%d with 0x%08x failed (old was 0x%08x)\n", devname, i, newbar, oldbar);
+ continue;
+ }
+ /* sanity check */
+ if (rtas_read_config_dword(dn, config_offset, &newbartest) != PCIBIOS_SUCCESSFUL) {
+ printk(KERN_WARNING "write_OF_bars %s: sanity test read BAR%d failed?\n", devname, i);
+ continue;
+ }
+ if ((newbar & PCI_BASE_ADDRESS_MEM_MASK) != (newbartest & PCI_BASE_ADDRESS_MEM_MASK)) {
+ printk(KERN_WARNING "write_OF_bars %s: oops...BAR%d read back as 0x%08x%s!\n", devname, i, newbartest, (oldbar & PCI_BASE_ADDRESS_MEM_MASK) == (newbartest & PCI_BASE_ADDRESS_MEM_MASK) ? " (original value)" : "");
+ continue;
+ }
+ }
+#else
+ return NULL;
+#endif
+
+}
+
+#if 0
+/* Traverse_func that starts the BIST (self test) */
+static void * __init
+startBIST(struct device_node *dn, void *data)
+{
+ struct pci_controller *phb = (struct pci_controller *)data;
+ u8 bist;
+
+ char *name = get_property(dn, "name", 0);
+ udbg_printf("startBIST: %s phb=%p, device=%p\n", name ? name : "", phb, dn);
+
+ if (rtas_read_config_byte(dn, PCI_BIST, &bist) == PCIBIOS_SUCCESSFUL) {
+ if (bist & PCI_BIST_CAPABLE) {
+ udbg_printf(" -> is BIST capable!\n", phb, dn);
+ /* Start bist here */
+ }
+ }
+ return NULL;
+}
+#endif
+
+
+/******************************************************************
+ * Traverse a device tree stopping each PCI device in the tree.
+ * This is done depth first. As each node is processed, a "pre"
+ * function is called, the children are processed recursively, and
+ * then a "post" function is called.
+ *
+ * The "pre" and "post" funcs return a value. If non-zero
+ * is returned from the "pre" func, the traversal stops and this
+ * value is returned. The return value from "post" is not used.
+ * This return value is useful when using traverse as
+ * a method of finding a device.
+ *
+ * NOTE: we do not run the funcs for devices that do not appear to
+ * be PCI except for the start node which we assume (this is good
+ * because the start node is often a phb which may be missing PCI
+ * properties).
+ * We use the class-code as an indicator. If we run into
+ * one of these nodes we also assume its siblings are non-pci for
+ * performance.
+ *
+ ******************************************************************/
+void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data)
+{
+ struct device_node *dn, *nextdn;
+ void *ret;
+
+ if (pre && (ret = pre(start, data)) != NULL)
+ return ret;
+ for (dn = start->child; dn; dn = nextdn) {
+ nextdn = NULL;
+ if (get_property(dn, "class-code", 0)) {
+ if (pre && (ret = pre(dn, data)) != NULL)
+ return ret;
+ if (dn->child) {
+ /* Depth first...do children */
+ nextdn = dn->child;
+ } else if (dn->sibling) {
+ /* ok, try next sibling instead. */
+ nextdn = dn->sibling;
+ } else {
+ /* no more children or siblings...call "post" */
+ if (post)
+ post(dn, data);
+ }
+ }
+ if (!nextdn) {
+ /* Walk up to next valid sibling. */
+ do {
+ dn = dn->parent;
+ if (dn == start)
+ return NULL;
+ } while (dn->sibling == NULL);
+ nextdn = dn->sibling;
+ }
+ }
+ return NULL;
+}
+
+/* Same as traverse_pci_devices except this does it for all phbs.
+ */
+void *traverse_all_pci_devices(traverse_func pre)
+{
+ struct pci_controller* phb;
+ void *ret;
+ for (phb=hose_head;phb;phb=phb->next)
+ if ((ret = traverse_pci_devices((struct device_node *)phb->arch_data, pre, NULL, phb)) != NULL)
+ return ret;
+ return NULL;
+}
+
+
+/* Traversal func that looks for a value.
+ * If found, the device_node is returned (thus terminating the traversal).
+ */
+static void *
+is_devfn_node(struct device_node *dn, void *data)
+{
+ int busno = ((unsigned long)data >> 8) & 0xff;
+ int devfn = ((unsigned long)data) & 0xff;
+ return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL;
+}
+
+
+/* This is the "slow" path for looking up a device_node from a
+ * pci_dev. It will hunt for the device under it's parent's
+ * phb and then update sysdata for a future fastpath.
+ *
+ * It may also do fixups on the actual device since this happens
+ * on the first read/write.
+ *
+ * Note that it also must deal with devices that don't exist.
+ * In this case it may probe for real hardware ("just in case")
+ * and add a device_node to the device tree if necessary.
+ *
+ */
+struct device_node *fetch_dev_dn(struct pci_dev *dev)
+{
+ struct device_node *orig_dn = (struct device_node *)dev->sysdata;
+ struct pci_controller *phb = orig_dn->phb; /* assume same phb as orig_dn */
+ struct device_node *phb_dn;
+ struct device_node *dn;
+ unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
+
+ phb_dn = (struct device_node *)(phb->arch_data);
+ dn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_node, NULL, (void *)searchval);
+ if (dn) {
+ dev->sysdata = dn;
+ /* ToDo: call some device init hook here */
+ } else {
+ /* ToDo: device not found...probe for it anyway with a fake dn?
+ struct device_node fake_dn;
+ memset(&fake_dn, 0, sizeof(fake_dn));
+ fake_dn.phb = phb;
+ fake_dn.busno = dev->bus->number;
+ fake_dn.devfn = dev->devfn;
+ ... now do rtas_read_config(&fake_dn.....)
+ ... if ok, alloc a real device_node and dn = real_dn;
+ */
+ }
+ return dn;
+}
+
+
+/******************************************************************
+ * Actually initialize the phbs.
+ * The buswalk on this phb has not happened yet.
+ ******************************************************************/
+void __init
+pci_devs_phb_init(void)
+{
+ /* This must be done first so the device nodes have valid pci info! */
+ traverse_all_pci_devices(update_dn_pci_info);
+
+ /* Hack for regatta which does not init the bars correctly */
+ traverse_all_pci_devices(write_OF_bars);
+#if 0
+ traverse_all_pci_devices(startBIST);
+ mdelay(5000);
+ traverse_all_pci_devices(checkBIST);
+#endif
+}
+
+
+static void __init
+pci_fixup_bus_sysdata_list(struct list_head *bus_list)
+{
+ struct list_head *ln;
+ struct pci_bus *bus;
+ int newnum;
+
+ for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+ bus = pci_bus_b(ln);
+ if (bus->self) {
+ bus->sysdata = bus->self->sysdata;
+ /* Also fixup the bus number to include the PHB# in the next byte */
+ newnum = (PCI_GET_DN(bus)->phb->global_number << 8) | bus->number;
+ bus->number = newnum;
+ sprintf(bus->name, "PCI Bus #%x", bus->number);
+ }
+ pci_fixup_bus_sysdata_list(&bus->children);
+ }
+}
+
+
+/******************************************************************
+ * Fixup the bus->sysdata ptrs to point to the bus' device_node.
+ * This is done late in pcibios_init(). We do this mostly for
+ * sanity, but pci_dma.c uses these at DMA time so they must be
+ * correct.
+ * To do this we recurse down the bus hierarchy. Note that PHB's
+ * have bus->self == NULL, but fortunately bus->sysdata is already
+ * correct in this case.
+ ******************************************************************/
+void __init
+pci_fix_bus_sysdata(void)
+{
+ pci_fixup_bus_sysdata_list(&pci_root_buses);
+}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/pmac_nvram.c linuxppc64_2_4/arch/ppc64/kernel/pmac_nvram.c
--- linux/arch/ppc64/kernel/pmac_nvram.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/pmac_nvram.c Wed Sep 5 13:56:40 2001
@@ -260,7 +260,7 @@
#endif
for (i=0; iaddrs[0].address, dp->addrs[0].size);
nvram_mult = 1;
} else if (nvram_naddrs == 1) {
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/ppc_ksyms.c linuxppc64_2_4/arch/ppc64/kernel/ppc_ksyms.c
--- linux/arch/ppc64/kernel/ppc_ksyms.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/ppc_ksyms.c Fri Sep 7 08:47:24 2001
@@ -50,7 +50,6 @@
/* Tell string.h we don't want memcpy etc. as cpp defines */
#define EXPORT_SYMTAB_STROPS
-extern void transfer_to_handler(void);
extern void syscall_trace(void);
extern void do_IRQ(struct pt_regs *regs, int isfake);
extern void SystemResetException(struct pt_regs *regs);
@@ -67,10 +66,8 @@
int abs(int);
extern unsigned long ret_to_user_hook;
-EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(syscall_trace);
-EXPORT_SYMBOL(transfer_to_handler);
EXPORT_SYMBOL(do_IRQ);
EXPORT_SYMBOL(SystemResetException);
EXPORT_SYMBOL(MachineCheckException);
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/process.c linuxppc64_2_4/arch/ppc64/kernel/process.c
--- linux/arch/ppc64/kernel/process.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/process.c Fri Sep 7 07:57:15 2001
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
@@ -509,82 +510,29 @@
return error;
}
-
-unsigned long find_hpte(unsigned long);
-
-static __inline__ void set_pp_bit(unsigned long pp, HPTE *addr)
-{
- unsigned long old;
- unsigned long *p = (unsigned long *)(&(addr->dw1));
-
- __asm__ __volatile__(
-"1: ldarx %0,0,%3\n\
- rldimi %0,%2,0,62\n\
- stdcx. %0,0,%3\n\
- bne 1b"
- : "=&r" (old), "=m" (*p)
- : "r" (pp), "r" (p), "m" (*p)
- : "cc");
-}
-
-
-static void updateStackHptePP( unsigned long newpp, unsigned long ea )
-{
- unsigned long vsid,va,vpn;
- long slot;
-
-
- vsid = get_kernel_vsid( ea );
- va = ( vsid << 28 ) | ( ea & 0x0fffffff );
- vpn = va >> PAGE_SHIFT;
-
- slot = find_hpte( vpn );
-
-
- if ( _machine == _MACH_iSeries ) {
- HvCallHpt_setPp( slot, newpp );
- }
- else {
-
- HPTE * hptep = htab_data.htab + slot;
-
- set_pp_bit(newpp , hptep );
-
- /* Ensure it is out of the tlb too */
- _tlbie( va );
-
-
- /* Ensure it is visible before validating */
- __asm__ __volatile__ ("eieio" : : : "memory");
-
-
- __asm__ __volatile__ ("ptesync" : : : "memory");
-
-
- }
-}
-
-
struct task_struct * alloc_task_struct(void) {
- struct task_struct * new_task_ptr;
+ struct task_struct * new_task_ptr;
- new_task_ptr = ((struct task_struct *) __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)));
+ new_task_ptr = ((struct task_struct *)
+ __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)));
- /* Set the second page to be write protected - prevent kernel stack overflow */
- updateStackHptePP( PP_RXRX , (unsigned long)new_task_ptr + PAGE_SIZE );
+ /* Set the second page to be write protected - prevent kernel
+ * stack overflow
+ */
+ updateBoltedHptePP(PP_RXRX ,(unsigned long)new_task_ptr + PAGE_SIZE);
- return new_task_ptr;
+ return new_task_ptr;
}
void free_task_struct(struct task_struct * task_ptr) {
- if (atomic_read(&(virt_to_page(task_ptr)->count)) == 1) {
- updateStackHptePP( PP_RWXX , (unsigned long)task_ptr + PAGE_SIZE );
- }
- free_pages((unsigned long)(task_ptr), get_order(THREAD_SIZE));
+ if (atomic_read(&(virt_to_page(task_ptr)->count)) == 1) {
+ updateBoltedHptePP(PP_RWXX,
+ (unsigned long)task_ptr + PAGE_SIZE );
+ }
+ free_pages((unsigned long)(task_ptr), get_order(THREAD_SIZE));
}
-
void
print_backtrace(unsigned long *sp)
{
@@ -604,88 +552,6 @@
}
printk("\n");
}
-
-#if 0
-/*
- * Low level print for debugging - Cort
- */
-int __init ll_printk(const char *fmt, ...)
-{
- va_list args;
- char buf[256];
- int i;
-
- va_start(args, fmt);
- i=vsprintf(buf,fmt,args);
- ll_puts(buf);
- va_end(args);
- return i;
-}
-
-int lines = 24, cols = 80;
-int orig_x = 0, orig_y = 0;
-
-void puthex(unsigned long val)
-{
- unsigned char buf[10];
- int i;
- for (i = 7; i >= 0; i--)
- {
- buf[i] = "0123456789ABCDEF"[val & 0x0F];
- val >>= 4;
- }
- buf[8] = '\0';
- prom_print(buf);
-}
-
-void __init ll_puts(const char *s)
-{
- int x,y;
- char *vidmem = (char *)/*(_ISA_MEM_BASE + 0xB8000) */0xD00B8000;
- char c;
- extern int mem_init_done;
-
- if ( mem_init_done ) /* assume this means we can printk */
- {
- printk(s);
- return;
- }
-
- /*
- * can't ll_puts on chrp without openfirmware yet.
- * vidmem just needs to be setup for it.
- * -- Cort
- */
- if ( _machine != _MACH_prep )
- return;
- x = orig_x;
- y = orig_y;
-
- while ( ( c = *s++ ) != '\0' ) {
- if ( c == '\n' ) {
- x = 0;
- if ( ++y >= lines ) {
- /*scroll();*/
- /*y--;*/
- y = 0;
- }
- } else {
- vidmem [ ( x + cols * y ) * 2 ] = c;
- if ( ++x >= cols ) {
- x = 0;
- if ( ++y >= lines ) {
- /*scroll();*/
- /*y--;*/
- y = 0;
- }
- }
- }
- }
-
- orig_x = x;
- orig_y = y;
-}
-#endif
/*
* These bracket the sleeping functions..
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/prom.c linuxppc64_2_4/arch/ppc64/kernel/prom.c
--- linux/arch/ppc64/kernel/prom.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/prom.c Wed Sep 5 13:56:40 2001
@@ -158,7 +158,6 @@
#endif
};
-int cpu_hw_index[NR_CPUS] = {0};
char *prom_display_paths[FB_MAX] __initdata = { 0, };
unsigned int prom_num_displays = 0;
@@ -330,6 +329,8 @@
prom_print(RELOC("prom_initialize_naca: start...\n"));
#endif
+ _naca->pftSize = 0; /* ilog2 of htab size. computed below. */
+
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
@@ -429,6 +430,25 @@
_naca->physicalMemorySize = lmb_phys_mem_size();
+ if (RELOC(_machine) == _MACH_pSeries) {
+ unsigned long rnd_mem_size, pteg_count;
+
+ /* round mem_size up to next power of 2 */
+ rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize);
+ if (rnd_mem_size < _naca->physicalMemorySize)
+ rnd_mem_size <<= 1;
+
+ /* # pages / 2 */
+ pteg_count = (rnd_mem_size >> (12 + 1));
+
+ _naca->pftSize = __ilog2(pteg_count << 7);
+ }
+
+ if (_naca->pftSize == 0) {
+ prom_print(RELOC("prom: failed to compute pftSize!\n"));
+ PROM_BUG();
+ }
+
/*
* Hardcode to GP size. I am not sure where to get this info
* in general, as there does not appear to be a slb-size OF
@@ -445,6 +465,10 @@
prom_print_hex(_naca->physicalMemorySize);
prom_print_nl();
+ prom_print(RELOC("naca->pftSize = 0x"));
+ prom_print_hex(_naca->pftSize);
+ prom_print_nl();
+
prom_print(RELOC("naca->dCacheL1LineSize = 0x"));
prom_print_hex(_naca->dCacheL1LineSize);
prom_print_nl();
@@ -477,6 +501,10 @@
prom_print_hex(_naca->interrupt_controller);
prom_print_nl();
+ prom_print(RELOC("_machine = 0x\n"));
+ prom_print_hex(RELOC(_machine));
+ prom_print_nl();
+
prom_print(RELOC("prom_initialize_naca: end...\n"));
#endif
@@ -896,6 +924,7 @@
unsigned long *acknowledge = __v2a(&__secondary_hold_acknowledge);
unsigned long secondary_hold = __v2a(*PTRRELOC((unsigned long *)__secondary_hold));
struct Naca *_naca = RELOC(naca);
+ struct Paca *_xPaca = PTRRELOC(&xPaca);
struct prom_t *_prom = PTRRELOC(&prom);
/* Initially, we must have one active CPU. */
@@ -983,7 +1012,7 @@
prom_print_hex(reg);
prom_print_nl();
#endif
- RELOC(cpu_hw_index)[cpuid] = reg;
+ _xPaca[cpuid].xHwProcNum = reg;
prom_print(RELOC("starting cpu "));
prom_print(path);
@@ -1063,8 +1092,12 @@
unsigned long phys;
u32 getprop_rval;
struct Naca *_naca = RELOC(naca);
+ struct Paca *_xPaca = PTRRELOC(&xPaca);
struct prom_t *_prom = PTRRELOC(&prom);
+ /* Default machine type. */
+ RELOC(_machine) = _MACH_pSeries;
+
/* Get a handle to the prom entry point before anything else */
_prom->entry = pp;
@@ -1181,7 +1214,7 @@
cpu_pkg, RELOC("reg"),
&getprop_rval, sizeof(getprop_rval));
_prom->cpu = (int)(unsigned long)getprop_rval;
- cpu_hw_index[0] = _prom->cpu;
+ _xPaca[0].xHwProcNum = _prom->cpu;
#ifdef DEBUG_PROM
prom_print(RELOC("Booting CPU hw index = 0x"));
@@ -1229,7 +1262,8 @@
lmb_reserve(0, __pa(RELOC(klimit)));
- prom_initialize_tce_table();
+ if(RELOC(_machine) == _MACH_pSeries)
+ prom_initialize_tce_table();
if ((long) call_prom(RELOC("getprop"), 4, 1,
_prom->chosen,
@@ -1635,8 +1669,8 @@
/* XXX on chrp, offset interrupt numbers for the
8259 by 0, those for the openpic by 16 */
// DRENG Condor -- this info is not actually known yet ...
- cvt_irq = _machine == _MACH_chrp
- && get_property(node, "interrupt-parent", NULL) == 0;
+ cvt_irq = (_machine == _MACH_pSeries)
+ && (get_property(node, "interrupt-parent", NULL) == 0);
np->intrs = (struct interrupt_info *) mem_start;
np->n_intrs = ipsize / isize;
mem_start += np->n_intrs * sizeof(struct interrupt_info);
@@ -1662,7 +1696,7 @@
else
map = NULL;
if (map && l) {
- int i, found, temp_isize;
+ int i, found, temp_isize, temp_asize;
map_size = l>>2;
map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
asizep = (unsigned int *)get_property(node, "#address-cells", &l);
@@ -1691,22 +1725,29 @@
map+=1; map_size-=1;
parent_node = find_phandle(parent);
temp_isize = isize;
+ temp_asize = 0;
if (parent_node) {
isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
if (isizep)
temp_isize = *isizep;
+ asizep = (unsigned int *)get_property(parent_node, "#address-cells", &l);
+ if (asizep && l == sizeof(unsigned int))
+ temp_asize = *asizep;
}
if (!found) {
- map += temp_isize;
- map_size-=temp_isize;
+ map += temp_isize + temp_asize;
+ map_size -= temp_isize + temp_asize;
}
}
if (found) {
+ /* Mapped to a new parent. Use the reg and interrupts specified in
+ * the map as the new search parameters. Then search from the parent.
+ */
node = parent_node;
- reg = NULL;
- regpsize = 0;
- interrupts = (unsigned int *)map;
- ipsize = temp_isize*1;
+ reg = map;
+ regpsize = temp_asize;
+ interrupts = map + temp_asize;
+ ipsize = temp_isize;
continue;
}
}
@@ -1933,26 +1974,10 @@
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (ip != 0) {
np->intrs = (struct interrupt_info *) mem_start;
- if (_machine == _MACH_Pmac) {
- /* for the iMac */
- np->n_intrs = l / sizeof(int);
- /* Hack for BootX on Core99 */
- if (keylargo)
- np->n_intrs = np->n_intrs/2;
- for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = *ip++;
- if (keylargo)
- np->intrs[i].sense = *ip++;
- else
- np->intrs[i].sense = 1;
- }
- } else {
- /* CHRP machines */
- np->n_intrs = l / (2 * sizeof(int));
- for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = openpic_to_irq(*ip++);
- np->intrs[i].sense = *ip++;
- }
+ np->n_intrs = l / (2 * sizeof(int));
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = openpic_to_irq(*ip++);
+ np->intrs[i].sense = *ip++;
}
mem_start += np->n_intrs * sizeof(struct interrupt_info);
}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/rtas-proc.c linuxppc64_2_4/arch/ppc64/kernel/rtas-proc.c
--- linux/arch/ppc64/kernel/rtas-proc.c Mon Sep 10 14:37:42 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/rtas-proc.c Wed Sep 5 13:56:40 2001
@@ -200,7 +200,7 @@
struct proc_dir_entry *entry;
rtas_node = find_devices("rtas");
- if ((rtas_node == 0) || (_machine != _MACH_chrp)) {
+ if ((rtas_node == 0) || (_machine == _MACH_iSeries)) {
return;
}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/setup.c linuxppc64_2_4/arch/ppc64/kernel/setup.c
--- linux/arch/ppc64/kernel/setup.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/setup.c Wed Sep 5 13:56:40 2001
@@ -1,6 +1,6 @@
/*
*
- * Common prep/pmac/chrp boot and setup code.
+ * Common boot and setup code.
*
* Copyright (C) 2001 PPC64 Team, IBM Corp
*
@@ -49,6 +49,7 @@
extern void chrp_init_map_io_space( void );
extern void iSeries_init( void );
extern void iSeries_init_early( void );
+extern void pSeries_init_early( void );
extern void mm_init_ppc64( void );
unsigned long decr_overclock = 1;
@@ -70,13 +71,12 @@
__no_use_save_flags
};
struct ide_machdep_calls ppc_ide_md;
-int parse_bootinfo(void);
void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7);
unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
-int _machine = _MACH_chrp; /* DRENG prom.c needs this assumption, a better way needs to be found. */
+int _machine = _MACH_unknown;
#ifdef CONFIG_MAGIC_SYSRQ
unsigned long SYSRQ_KEY;
@@ -120,7 +120,7 @@
unsigned long offset = reloc_offset();
struct Naca *_naca = RELOC(naca);
- _naca->debug_switch = PPC_DEBUG_DEFAULT;
+ _naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
}
void naca_init(void) {
@@ -152,110 +152,97 @@
}
/*
- * Determine the type of system this we are running on.
- * For the PPC64 kernel, we assume chrp.
- */
-void identify_machine(void) {
- if ( itLpNaca.xLparInstalled == 1 )
- _machine = _MACH_iSeries;
- else
- _machine = _MACH_chrp;
-}
-
-/*
* Do some initial setup of the system. The paramters are those which
* were passed in from the bootloader.
*/
void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7) {
- identify_machine();
-
- switch (_machine) {
- case _MACH_chrp:
- parse_bootinfo();
- chrp_init_map_io_space();
- break;
- case _MACH_iSeries:
+ /* pSeries systems are identified in prom.c via OF. */
+ if ( itLpNaca.xLparInstalled == 1 )
+ _machine = _MACH_iSeries;
+ switch (_machine) {
+ case _MACH_iSeries:
iSeries_init_early();
- break;
- default:
- }
+ break;
+ case _MACH_pSeries:
+ pSeries_init_early();
+ break;
+ }
- udbg_init();
+ udbg_puts("\n-----------------------------------------------------\n");
+ udbg_puts("Naca Info...\n\n");
+ udbg_puts("naca = 0x");
+ udbg_puthex((unsigned long)naca);
+ udbg_putc('\n');
- udbg_puts("\n-----------------------------------------------------\n");
- udbg_puts("Naca Info...\n\n");
- udbg_puts("naca = 0x");
- udbg_puthex((unsigned long)naca);
- udbg_putc('\n');
+ udbg_puts("naca->processorCount = 0x");
+ udbg_puthex(naca->processorCount);
+ udbg_putc('\n');
- udbg_puts("naca->processorCount = 0x");
- udbg_puthex(naca->processorCount);
- udbg_putc('\n');
+ udbg_puts("naca->physicalMemorySize = 0x");
+ udbg_puthex(naca->physicalMemorySize);
+ udbg_putc('\n');
- udbg_puts("naca->physicalMemorySize = 0x");
- udbg_puthex(naca->physicalMemorySize);
- udbg_putc('\n');
+ udbg_puts("naca->dCacheL1LineSize = 0x");
+ udbg_puthex(naca->dCacheL1LineSize);
+ udbg_putc('\n');
- udbg_puts("naca->dCacheL1LineSize = 0x");
- udbg_puthex(naca->dCacheL1LineSize);
- udbg_putc('\n');
+ udbg_puts("naca->dCacheL1LogLineSize = 0x");
+ udbg_puthex(naca->dCacheL1LogLineSize);
+ udbg_putc('\n');
- udbg_puts("naca->dCacheL1LogLineSize = 0x");
- udbg_puthex(naca->dCacheL1LogLineSize);
- udbg_putc('\n');
+ udbg_puts("naca->dCacheL1LinesPerPage = 0x");
+ udbg_puthex(naca->dCacheL1LinesPerPage);
+ udbg_putc('\n');
- udbg_puts("naca->dCacheL1LinesPerPage = 0x");
- udbg_puthex(naca->dCacheL1LinesPerPage);
- udbg_putc('\n');
+ udbg_puts("naca->iCacheL1LineSize = 0x");
+ udbg_puthex(naca->iCacheL1LineSize);
+ udbg_putc('\n');
- udbg_puts("naca->iCacheL1LineSize = 0x");
- udbg_puthex(naca->iCacheL1LineSize);
- udbg_putc('\n');
+ udbg_puts("naca->iCacheL1LogLineSize = 0x");
+ udbg_puthex(naca->iCacheL1LogLineSize);
+ udbg_putc('\n');
- udbg_puts("naca->iCacheL1LogLineSize = 0x");
- udbg_puthex(naca->iCacheL1LogLineSize);
- udbg_putc('\n');
+ udbg_puts("naca->iCacheL1LinesPerPage = 0x");
+ udbg_puthex(naca->iCacheL1LinesPerPage);
+ udbg_putc('\n');
- udbg_puts("naca->iCacheL1LinesPerPage = 0x");
- udbg_puthex(naca->iCacheL1LinesPerPage);
- udbg_putc('\n');
+ udbg_puts("naca->pftSize = 0x");
+ udbg_puthex(naca->pftSize);
+ udbg_putc('\n');
- udbg_puts("naca->serialPortAddr = 0x");
- udbg_puthex(naca->serialPortAddr);
- udbg_putc('\n');
+ udbg_puts("naca->serialPortAddr = 0x");
+ udbg_puthex(naca->serialPortAddr);
+ udbg_putc('\n');
- udbg_puts("naca->interrupt_controller = 0x");
- udbg_puthex(naca->interrupt_controller);
- udbg_putc('\n');
+ udbg_puts("naca->interrupt_controller = 0x");
+ udbg_puthex(naca->interrupt_controller);
+ udbg_putc('\n');
- udbg_printf("\nHTAB Info ...\n\n");
- udbg_printf("htab_data.htab = 0x%lx\n", htab_data.htab);
- udbg_printf("htab_data.num_ptegs = 0x%lx\n", htab_data.htab_num_ptegs);
+ udbg_printf("\nHTAB Info ...\n\n");
+ udbg_printf("htab_data.htab = 0x%lx\n", htab_data.htab);
+ udbg_printf("htab_data.num_ptegs = 0x%lx\n", htab_data.htab_num_ptegs);
- udbg_puts("\n-----------------------------------------------------\n");
+ udbg_puts("\n-----------------------------------------------------\n");
- if ( _machine == _MACH_chrp ) {
- finish_device_tree();
- chrp_init(r3, r4, r5, r6, r7);
- }
+ if ( _machine & _MACH_pSeries ) {
+ finish_device_tree();
+ chrp_init(r3, r4, r5, r6, r7);
+ }
- mm_init_ppc64();
-
- switch (_machine) {
- case _MACH_chrp: // DRENG _MACH_chrp needs to be _MACH_pSeries now
- // The following relies on the device tree being fully configured.
- parse_cmd_line(r3, r4, r5, r6, r7);
-
- break;
- case _MACH_iSeries:
- iSeries_init();
- break;
- default:
- // Need a way to die here-prob have to display something to the panel DRENG
- }
+ mm_init_ppc64();
+
+ switch (_machine) {
+ case _MACH_iSeries:
+ iSeries_init();
+ break;
+ default:
+ /* The following relies on the device tree being */
+ /* fully configured. */
+ parse_cmd_line(r3, r4, r5, r6, r7);
+ }
}
/*
@@ -308,7 +295,7 @@
len += sprintf(len+buffer,"processor\t: %lu\n",i);
len += sprintf(len+buffer,"cpu\t\t: ");
- pvr = naca->paca[i].pvr;
+ pvr = xPaca[i].pvr;
switch (PVR_VER(pvr))
{
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/smp.c linuxppc64_2_4/arch/ppc64/kernel/smp.c
--- linux/arch/ppc64/kernel/smp.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/smp.c Wed Sep 5 13:56:40 2001
@@ -49,6 +49,7 @@
#include
#include
#include "open_pic.h"
+#include
int smp_threads_ready = 0;
volatile int smp_commenced = 0;
@@ -79,19 +80,6 @@
extern struct Naca *naca;
extern struct Paca xPaca[];
-/* Forward declarations */
-static void smp_iSeries_message_pass(int target, int msg, unsigned long data, int wait);
-static int smp_iSeries_probe(void);
-static void smp_iSeries_kick_cpu(int nr);
-static void smp_iSeries_setup_cpu(int nr);
-
-static void smp_openpic_message_pass(int target, int msg, unsigned long data, int wait);
-static int smp_chrp_probe(void);
-static void smp_chrp_kick_cpu(int nr);
-static void smp_chrp_setup_cpu(int cpu_nr);
-
-static void smp_xics_message_pass(int target, int msg, unsigned long data, int wait);
-static int smp_xics_probe(void);
void xics_setup_cpu(void);
void xics_cause_IPI(int cpu);
@@ -101,43 +89,10 @@
volatile unsigned long xics_ipi_message[NR_CPUS] = {0};
#define smp_message_pass(t,m,d,w) \
- do { if (smp_ops) \
- atomic_inc(&ipi_sent); \
- smp_ops->message_pass((t),(m),(d),(w)); \
+ do { atomic_inc(&ipi_sent); \
+ ppc_md.smp_message_pass((t),(m),(d),(w)); \
} while(0)
-static struct smp_ops_t {
- void (*message_pass)(int target, int msg, unsigned long data, int wait);
- int (*probe)(void);
- void (*kick_cpu)(int nr);
- void (*setup_cpu)(int nr);
-
-} *smp_ops;
-
-/* iSeries (iSeries) */
-static struct smp_ops_t iSeries_smp_ops = {
- smp_iSeries_message_pass,
- smp_iSeries_probe,
- smp_iSeries_kick_cpu,
- smp_iSeries_setup_cpu
-};
-
-/* CHRP with openpic */
-static struct smp_ops_t chrp_smp_ops = {
- smp_openpic_message_pass,
- smp_chrp_probe,
- smp_chrp_kick_cpu,
- smp_chrp_setup_cpu,
-};
-
-/* CHRP with new XICS interrupt controller */
-static struct smp_ops_t xics_smp_ops = {
- smp_xics_message_pass,
- smp_xics_probe,
- smp_chrp_kick_cpu,
- smp_chrp_setup_cpu,
-};
-
#ifdef CONFIG_KDB
void smp_kdb_stop(void)
{
@@ -220,6 +175,16 @@
{
}
+/* This is called very early. */
+void smp_init_iSeries(void)
+{
+ ppc_md.smp_message_pass = smp_iSeries_message_pass;
+ ppc_md.smp_probe = smp_iSeries_probe;
+ ppc_md.smp_kick_cpu = smp_iSeries_kick_cpu;
+ ppc_md.smp_setup_cpu = smp_iSeries_setup_cpu;
+}
+
+
static void
smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
{
@@ -254,7 +219,7 @@
}
static void
-smp_chrp_kick_cpu(int nr)
+smp_kick_cpu(int nr)
{
/* Verify we have a Paca for processor nr */
if ( ( nr <= 0 ) ||
@@ -335,14 +300,21 @@
return naca->processorCount;
}
-#if 0
-static void
-smp_xics_setup_cpu(int cpu_nr)
+/* This is called very early */
+void smp_init_pSeries(void)
{
- if (cpu_nr > 0)
- xics_setup_cpu();
+ if(naca->interrupt_controller == IC_OPEN_PIC) {
+ ppc_md.smp_message_pass = smp_openpic_message_pass;
+ ppc_md.smp_probe = smp_chrp_probe;
+ ppc_md.smp_kick_cpu = smp_kick_cpu;
+ ppc_md.smp_setup_cpu = smp_chrp_setup_cpu;
+ } else {
+ ppc_md.smp_message_pass = smp_xics_message_pass;
+ ppc_md.smp_probe = smp_xics_probe;
+ ppc_md.smp_kick_cpu = smp_kick_cpu;
+ ppc_md.smp_setup_cpu = smp_chrp_setup_cpu;
+ }
}
-#endif
void smp_local_timer_interrupt(struct pt_regs * regs)
@@ -576,7 +548,7 @@
init_idle();
for (i = 0; i < NR_CPUS; i++) {
- paca = &(naca->paca[i]);
+ paca = &xPaca[i];
paca->prof_counter=1;
paca->prof_multiplier = 1;
if(i != 0) {
@@ -590,7 +562,6 @@
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 = cpu_hw_index[i];
memset((void *)paca->xStab_data.virt, 0, PAGE_SIZE);
paca->default_decr = tb_ticks_per_jiffy / decr_overclock;
}
@@ -605,24 +576,8 @@
*/
cacheflush_time = 5 * 1024;
- switch ( _machine ) {
- case _MACH_chrp:
- if (OpenPIC_Addr) {
- smp_ops = &chrp_smp_ops;
- } else {
- smp_ops = &xics_smp_ops;
- }
- break;
- case _MACH_iSeries:
- smp_ops = &iSeries_smp_ops;
- break;
- default:
- printk("SMP not supported on this machine.\n");
- return;
- }
-
/* Probe arch for CPUs */
- cpu_nr = smp_ops->probe();
+ cpu_nr = ppc_md.smp_probe();
printk("Probe found %d CPUs\n", cpu_nr);
@@ -680,7 +635,7 @@
current_set[i].sp_real);
/* wake up cpus */
- smp_ops->kick_cpu(i);
+ ppc_md.smp_kick_cpu(i);
/*
* wait to see if the cpu made a callin (is actually up).
@@ -707,7 +662,7 @@
}
/* Setup CPU 0 last (important) */
- smp_ops->setup_cpu(0);
+ ppc_md.smp_setup_cpu(0);
if (smp_num_cpus < 2)
smp_tb_synchronized = 1;
@@ -731,7 +686,7 @@
set_dec(xPaca[cpu].default_decr);
cpu_callin_map[cpu] = 1;
- smp_ops->setup_cpu(cpu);
+ ppc_md.smp_setup_cpu(cpu);
init_idle();
@@ -785,7 +740,7 @@
*/
void __init smp_store_cpu_info(int id)
{
- naca->paca[id].pvr = _get_PVR();
+ xPaca[id].pvr = _get_PVR();
}
static int __init maxcpus(char *str)
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/stab.c linuxppc64_2_4/arch/ppc64/kernel/stab.c
--- linux/arch/ppc64/kernel/stab.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/stab.c Fri Sep 7 07:56:34 2001
@@ -317,8 +317,8 @@
ste = stab;
/* Never flush the first four entries. */
- ste += 4;
- for(entry = 4;
+ ste += 3;
+ for(entry = 3;
entry < (PAGE_SIZE / sizeof(STE));
entry++, ste++) {
ste->dw0.dw0.v = 0;
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/time.c linuxppc64_2_4/arch/ppc64/kernel/time.c
--- linux/arch/ppc64/kernel/time.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/time.c Wed Sep 5 13:56:40 2001
@@ -222,7 +222,8 @@
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
- unsigned long delta, lost_ticks, usec, sec;
+ unsigned long lost_ticks, sec;
+ long delta, usec;
read_lock_irqsave(&xtime_lock, flags);
sec = xtime.tv_sec;
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/traps.c linuxppc64_2_4/arch/ppc64/kernel/traps.c
--- linux/arch/ppc64/kernel/traps.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/traps.c Fri Sep 7 07:59:15 2001
@@ -191,7 +191,7 @@
}
void
-InstructionBreakpoint(struct pt_regs *regs)
+InstructionBreakpointException(struct pt_regs *regs)
{
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_iabr_match(regs))
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/udbg.c linuxppc64_2_4/arch/ppc64/kernel/udbg.c
--- linux/arch/ppc64/kernel/udbg.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/udbg.c Wed Sep 5 13:56:40 2001
@@ -21,6 +21,7 @@
#define WANT_PPCDBG_TAB /* Only defined here */
#include
#include
+#include
extern struct Naca *naca;
extern int _machine;
@@ -52,24 +53,24 @@
#define LSR_TEMT 0x40 /* Xmitter empty */
#define LSR_ERR 0x80 /* Error */
-void *comport1;
+volatile struct NS16550 *udbg_comport;
static inline void eieio(void) { asm volatile ("eieio" : :); }
void
-udbg_init(void)
+udbg_init_uart(void *comport)
{
- if ( _machine != _MACH_iSeries ) {
- volatile struct NS16550 *port = (struct NS16550 *)comport1;
- port->lcr = 0x00; eieio();
- port->ier = 0xFF; eieio();
- port->ier = 0x00; eieio();
- port->lcr = 0x80; eieio(); /* Access baud rate */
- port->dll = 12; eieio(); /* 1 = 115200, 2 = 57600, 3 = 38400, 12 = 9600 baud */
- port->dlm = 0; eieio(); /* dll >> 8 which should be zero for fast rates; */
- port->lcr = 0x03; eieio(); /* 8 data, 1 stop, no parity */
- port->mcr = 0x03; eieio(); /* RTS/DTR */
- port->fcr = 0x07; eieio(); /* Clear & enable FIFOs */
+ if (comport) {
+ udbg_comport = (struct NS16550 *)comport;
+ udbg_comport->lcr = 0x00; eieio();
+ udbg_comport->ier = 0xFF; eieio();
+ udbg_comport->ier = 0x00; eieio();
+ udbg_comport->lcr = 0x80; eieio(); /* Access baud rate */
+ udbg_comport->dll = 12; eieio(); /* 1 = 115200, 2 = 57600, 3 = 38400, 12 = 9600 baud */
+ udbg_comport->dlm = 0; eieio(); /* dll >> 8 which should be zero for fast rates; */
+ udbg_comport->lcr = 0x03; eieio(); /* 8 data, 1 stop, no parity */
+ udbg_comport->mcr = 0x03; eieio(); /* RTS/DTR */
+ udbg_comport->fcr = 0x07; eieio(); /* Clear & enable FIFOs */
}
}
@@ -77,32 +78,40 @@
void
udbg_putc(unsigned char c)
{
- if ( _machine != _MACH_iSeries ) {
- volatile struct NS16550 *port = (struct NS16550 *)comport1;
- while ((port->lsr & LSR_THRE) == 0)
- /* wait for idle */;
- port->thr = c; eieio();
- if (c == '\n') {
- /* Also put a CR. This is for convenience. */
- while ((port->lsr & LSR_THRE) == 0)
- /* wait for idle */;
- port->thr = '\r'; eieio();
- }
- }
- else {
- printk("%c", c);
- }
+ if ( udbg_comport ) {
+ while ((udbg_comport->lsr & LSR_THRE) == 0)
+ /* wait for idle */;
+ udbg_comport->thr = c; eieio();
+ if (c == '\n') {
+ /* Also put a CR. This is for convenience. */
+ while ((udbg_comport->lsr & LSR_THRE) == 0)
+ /* wait for idle */;
+ udbg_comport->thr = '\r'; eieio();
+ }
+ } else if ( _machine == _MACH_iSeries ) {
+ /* ToDo: switch this via ppc_md */
+ printk("%c", c);
+ }
+}
+int udbg_getc_poll(void)
+{
+ if ( udbg_comport ) {
+ if ((udbg_comport->lsr & LSR_DR) != 0)
+ return udbg_comport->rbr;
+ else
+ return -1;
+ }
+ return -1;
}
unsigned char
udbg_getc(void)
{
- if ( _machine != _MACH_iSeries ) {
- volatile struct NS16550 *port = (struct NS16550 *)comport1;
- while ((port->lsr & LSR_DR) == 0)
+ if ( udbg_comport ) {
+ while ((udbg_comport->lsr & LSR_DR) == 0)
/* wait for char */;
- return port->rbr;
+ return udbg_comport->rbr;
}
return 0;
}
@@ -110,18 +119,50 @@
void
udbg_puts(const char *s)
{
- if ( _machine != _MACH_iSeries ) {
+ if (ppc_md.udbg_putc) {
char c;
- if ( s && *s != '\0' )
+ if ( s && *s != '\0' ) {
while ( ( c = *s++ ) != '\0' )
- udbg_putc(c);
- else
+ ppc_md.udbg_putc(c);
+ } else
udbg_puts("NULL");
}
else
printk("%s", s);
}
+int
+udbg_write(const char *s, int n)
+{
+ int remain = n;
+ char c;
+ if (!ppc_md.udbg_putc)
+ for (;;); /* stop here for cpuctl */
+ if ( s && *s != '\0' ) {
+ while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
+ ppc_md.udbg_putc(c);
+ }
+ } else
+ udbg_puts("NULL");
+ return n - remain;
+}
+
+int
+udbg_read(char *buf, int buflen) {
+ char c, *p = buf;
+ int i;
+ if (!ppc_md.udbg_putc)
+ for (;;); /* stop here for cpuctl */
+ for (i = 0; i < buflen; ++i) {
+ do {
+ c = ppc_md.udbg_getc();
+ } while (c == 0x11 || c == 0x13);
+ *p++ = c;
+ }
+ return i;
+}
+
+
void
udbg_puthex(unsigned long val)
{
@@ -140,7 +181,7 @@
void
udbg_printSP(const char *s)
{
- if ( _machine != _MACH_iSeries ) {
+ if ( _machine == _MACH_pSeries ) {
unsigned long sp;
asm("mr %0,1" : "=r" (sp) :);
if (s)
@@ -167,34 +208,33 @@
void
udbg_ppcdbg(unsigned long flags, const char *fmt, ...)
{
- unsigned long active_debugs = flags & naca->debug_switch;
- if ( active_debugs ) {
- va_list ap;
- unsigned char buf[256];
- unsigned long i, len = 0;
-
- for(i=0; i < PPCDBG_NUM_FLAGS ;i++) {
- if (((1U << i) & active_debugs) &&
- trace_names[i]) {
- len += strlen(trace_names[i]);
- udbg_puts(trace_names[i]);
- break;
- }
+ unsigned long active_debugs = flags & naca->debug_switch;
+ if ( active_debugs ) {
+ va_list ap;
+ unsigned char buf[256];
+ unsigned long i, len = 0;
+ for(i=0; i < PPCDBG_NUM_FLAGS ;i++) {
+ if (((1U << i) & active_debugs) &&
+ trace_names[i]) {
+ len += strlen(trace_names[i]);
+ udbg_puts(trace_names[i]);
+ break;
}
- sprintf(buf, " [%s]: ", current->comm);
- len += strlen(buf);
- udbg_puts(buf);
-
- while(len < 18) {
- udbg_putc(' ');
- len++;
- }
-
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- udbg_puts(buf);
- va_end(ap);
}
+ sprintf(buf, " [%s]: ", current->comm);
+ len += strlen(buf);
+ udbg_puts(buf);
+
+ while(len < 18) {
+ udbg_puts(" ");
+ len++;
+ }
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ udbg_puts(buf);
+ va_end(ap);
+ }
}
unsigned long
@@ -210,7 +250,6 @@
void
udbg_dump(char *msg, void *addr, unsigned len)
{
- if ( _machine != _MACH_iSeries ) {
int i;
int j;
int numrows;
@@ -218,48 +257,49 @@
unsigned char tc;
char *buff = addr;
- if (msg) {
- udbg_puts(msg);
- udbg_puts("\n");
- }
-
- if (!buff) {
- udbg_puts(" Danger, Will Robinson, Null Pointer\n");
- return;
- }
- numrows = (len + 15) / 16;
-
- for (i = 0; i < numrows; i++) {
- udbg_printf("%016lx ", &buff[i*16]);
- for (j = 0; j < 16; j++) {
- if (j + i * 16 >= len) {
- udbg_puts(" ");
- } else {
- udbg_printf("%02x", (unsigned char)buff[j + i * 16]);
- } /* endif */
- if (j % 8 == 7) {
- udbg_puts(" ");
- } /* endif */
- } /* endfor */
-
- udbg_puts(" a|");
-
- for (j = 0; j < 16; j++) {
- if (j + i * 16 >= len) {
- udbg_putc(' ');
- } else {
- c = (unsigned char)buff[j + i * 16];
- tc = c;
- if (tc >= 32 && tc < 127 && tc != ' ') {
- udbg_putc(tc);
- } else {
- udbg_putc('.');
- } /* endif */
- } /* endif */
- } /* endfor */
- udbg_putc('|');
- udbg_putc('\n');
- } /* endfor */
+ if ( _machine == _MACH_pSeries ) {
+ if (msg) {
+ udbg_puts(msg);
+ udbg_puts("\n");
+ }
+
+ if (!buff) {
+ udbg_puts(" Danger, Will Robinson, Null Pointer\n");
+ return;
+ }
+ numrows = (len + 15) / 16;
+
+ for (i = 0; i < numrows; i++) {
+ udbg_printf("%016lx ", &buff[i*16]);
+ for (j = 0; j < 16; j++) {
+ if (j + i * 16 >= len) {
+ udbg_puts(" ");
+ } else {
+ udbg_printf("%02x", (unsigned char)buff[j + i * 16]);
+ } /* endif */
+ if (j % 8 == 7) {
+ udbg_puts(" ");
+ } /* endif */
+ } /* endfor */
+
+ udbg_puts(" a|");
+
+ for (j = 0; j < 16; j++) {
+ if (j + i * 16 >= len) {
+ ppc_md.udbg_putc(' ');
+ } else {
+ c = (unsigned char)buff[j + i * 16];
+ tc = c;
+ if (tc >= 32 && tc < 127 && tc != ' ') {
+ ppc_md.udbg_putc(tc);
+ } else {
+ ppc_md.udbg_putc('.');
+ } /* endif */
+ } /* endif */
+ } /* endfor */
+ ppc_md.udbg_putc('|');
+ ppc_md.udbg_putc('\n');
+ } /* endfor */
}
}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/viopath.c linuxppc64_2_4/arch/ppc64/kernel/viopath.c
--- linux/arch/ppc64/kernel/viopath.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/viopath.c Wed Dec 31 18:00:00 1969
@@ -1,711 +0,0 @@
-/*
- * arch/ppc64/viopath.c
- *
- * iSeries Virtual I/O Message Path code
- *
- * 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
- *
- */
-#ifndef _HVLPEVENT_H
-#include
-#endif
-#ifndef _HVLPConfig_H
-#include
-#endif
-#ifndef _HVCallCfg_H
-#include
-#endif
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#ifndef _VIO_H
-#include
-#endif
-#ifndef _MF_H
-#include
-#endif
-#ifndef _ISERIES_PROC_H
-#include
-#endif
-
-/* Status of the path to each other partition in the system.
- * This is overkill, since we will only ever establish connections
- * to our hosting partition and the primary partition on the system.
- * But this allows for other support in the future.
- */
-static struct viopathStatus {
- int isOpen:1; /* Did we open the path? */
- int isActive:1; /* Do we have a mon msg outstanding */
-#if defined(CONFIG_VIOCONS)
- int xCharUsers;
-#endif
-#if defined(CONFIG_VIODASD)
- int xBlockUsers;
-#endif
-#if defined(CONFIG_VIOCD)
- int xCDUsers;
-#endif
-#if defined(CONFIG_VIOTAPE)
- int xTapeUsers;
-#endif
- int xConfigUsers;
- HvLpInstanceId mSourceInst;
- HvLpInstanceId mTargetInst;
- int numberAllocated;
- spinlock_t statuslock;
- unsigned long statuslockFlags;
-} viopathStatus[HVMAXARCHITECTEDLPS];
-
-/* We use this structure to handle asynchronous responses. The caller
- * blocks on the semaphore and the handler posts the semaphore.
- */
-struct doneAllocParms_t {
- struct semaphore *sem;
- int number;
-};
-
-/* Put a sequence number in each mon msg. The value is not
- * important. Start at something other than 0 just for
- * readability. wrapping this is ok.
- */
-static u8 viomonseq = 22;
-
-/* Our hosting logical partition. We get this at startup
- * time, and different modules access this variable directly.
- */
-HvLpIndex viopath_hostLp;
-
-/* For each kind of incoming event we set a pointer to a
- * routine to call.
- */
-static vio_event_handler_t *vio_handleCharEvent;
-static vio_event_handler_t *vio_handleBlockEvent;
-static vio_event_handler_t *vio_handleCDEvent;
-static vio_event_handler_t *vio_handleTapeEvent;
-
-/*
- * For each kind of event we allocate a buffer that is
- * guaranteed not to cross a page boundary
- */
-void * vio_char_event_buffer;
-void * vio_block_event_buffer;
-void * vio_cd_event_buffer;
-void * vio_tape_event_buffer;
-
-/***************************************************************************
- * A page to build an lp event in
- ***************************************************************************/
-unsigned long VIOReqPage;
-
-/***************************************************************************
- * Handle reads from the proc file system
- ***************************************************************************/
-static int proc_read(char *buf, char **start, off_t offset,
- int blen, int *eof, void *data)
-{
- HvLpEvent_Rc hvrc;
- DECLARE_MUTEX_LOCKED(Semaphore);
- dma_addr_t dmaa = pci_map_single( NULL, buf, PAGE_SIZE, PCI_DMA_FROMDEVICE);
- int len = PAGE_SIZE;
-
- if (len > blen)
- len = blen;
-
- memset(buf,0x00,len);
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_config | vioconfigget,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)&Semaphore,
- VIOVERSION << 16,
- ((u64)dmaa) << 32,
- len,
- 0,
- 0);
- if (hvrc != HvLpEvent_Rc_Good)
- {
- printk("viopath hv error on op %d\n",(int)hvrc);
- }
-
- down(&Semaphore);
-
- pci_unmap_single( NULL, dmaa, PAGE_SIZE, PCI_DMA_FROMDEVICE);
-
- *eof = 1;
- return strlen(buf);
-}
-
-/***************************************************************************
- * Handle writes to our proc file system
- ***************************************************************************/
-static int proc_write(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- printk("viopath: in proc_write, got %ld bytes starting with %c\n",
- count, buffer[0]);
- return count;
-}
-
-/***************************************************************************
- * setup our proc file system entries
- ***************************************************************************/
-void vio_proc_init(struct proc_dir_entry *iSeries_proc)
-{
- struct proc_dir_entry *ent;
- ent = create_proc_entry("config", 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;
-}
-
-/* Boot time initialization of the vio path code. Needs
- * to be called before any VIO components start
- */
-void viopath_init(void)
-{
- int i;
- memset(viopathStatus,0x00,sizeof(viopathStatus));
- for (i=0; ixFlags.xFunction == HvLpEvent_Function_Int)
- {
- printk("viopath: got monitor INT event\n");
- remoteLp = event->xSourceLp;
- if (!viopathStatus[remoteLp].isActive)
- sendMonMsg(remoteLp);
- }
- else
- {
- remoteLp = event->xTargetLp;
- printk("viopath: got monitor ACK event %d, sinst %d, tinst %d\n",
- (int)event->xCorrelationToken,
- event->xSourceInstanceId,
- event->xTargetInstanceId);
- /* Other partition went away! */
- if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) ||
- (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst))
- {
- printk("viopath: ignoring ack....mismatched instances\n");
- }
- else
- {
- printk("viopath: closing path %d\n",remoteLp);
-
- viopathStatus[remoteLp].isActive = 0;
-
- if (vio_handleBlockEvent!= NULL)
- (*vio_handleBlockEvent)(NULL);
-
- if (vio_handleCharEvent != NULL)
- (*vio_handleCharEvent)(NULL);
-
- if (vio_handleCDEvent != NULL)
- (*vio_handleCDEvent)(NULL);
-
- if (vio_handleTapeEvent != NULL)
- (*vio_handleTapeEvent)(NULL);
- }
- }
-}
-
-void vio_setBlockHandler(vio_event_handler_t *beh)
-{
- vio_handleBlockEvent = *beh;
-}
-
-void vio_clearBlockHandler(void)
-{
- vio_handleBlockEvent = NULL;
-}
-
-void vio_setCharHandler(vio_event_handler_t *ceh)
-{
- vio_handleCharEvent = *ceh;
-}
-
-void vio_clearCharHandler(void)
-{
- vio_handleCharEvent = NULL;
-}
-
-void vio_setCDHandler(vio_event_handler_t *ceh)
-{
- vio_handleCDEvent = *ceh;
-}
-
-void vio_clearCDHandler(void)
-{
- vio_handleCDEvent = NULL;
-}
-
-void vio_setTapeHandler(vio_event_handler_t *ceh)
-{
- vio_handleTapeEvent = *ceh;
-}
-
-void vio_clearTapeHandler(void)
-{
- vio_handleTapeEvent = NULL;
-}
-
-static void vio_handleEvent(struct HvLpEvent *event, struct pt_regs *regs)
-{
- HvLpIndex remoteLp;
- if (event->xFlags.xFunction == HvLpEvent_Function_Int)
- {
- remoteLp = event->xSourceLp;
- if (event->xSourceInstanceId != viopathStatus[remoteLp].mTargetInst)
- {
- printk("viopath: int msg rcvd, source inst (%d) doesnt match (%d)\n",
- viopathStatus[remoteLp].mTargetInst,
- event->xSourceInstanceId);
- return;
- }
-
- if (event->xTargetInstanceId != viopathStatus[remoteLp].mSourceInst)
- {
- printk("viopath: int msg rcvd, target inst (%d) doesnt match (%d)\n",
- viopathStatus[remoteLp].mSourceInst,
- event->xTargetInstanceId);
- return;
- }
- }
- else
- {
- remoteLp = event->xTargetLp;
- if (event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst)
- {
- printk("viopath: ack msg rcvd, source inst (%d) doesnt match (%d)\n",
- viopathStatus[remoteLp].mSourceInst,
- event->xSourceInstanceId);
- return;
- }
-
- if (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)
- {
- printk("viopath: ack msg rcvd, target inst (%d) doesnt match (%d)\n",
- viopathStatus[remoteLp].mTargetInst,
- event->xTargetInstanceId);
- return;
- }
- }
-
-
- switch (event->xSubtype & VIOMAJOR_SUBTYPE_MASK) {
- case viomajorsubtype_config:
- up((struct semaphore *)event->xCorrelationToken);
- break;
-
- case viomajorsubtype_monitor:
- handleMonitorEvent(event);
- break;
- case viomajorsubtype_blockio:
- if (vio_handleBlockEvent)
- {
- (*vio_handleBlockEvent)(event);
- }
- else
- {
- printk("vio: unexpected virtual blockio event\n");
- if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
- {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
- break;
- case viomajorsubtype_chario:
- if (vio_handleCharEvent)
- {
- (*vio_handleCharEvent)(event);
- }
- else
- {
- printk("vio: unexpected virtual chario event\n");
- if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
- {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
- break;
- case viomajorsubtype_cdio:
- if (vio_handleCDEvent)
- {
- (*vio_handleCDEvent)(event);
- }
- else
- {
- printk("vio: unexpected virtual cd event\n");
- if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
- {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
- break;
- case viomajorsubtype_tape:
- if (vio_handleTapeEvent)
- {
- (*vio_handleTapeEvent)(event);
- }
- else
- {
- printk("vio: unexpected virtual tape event\n");
- if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
- {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
- break;
- default:
- printk("vio: unexpected virtual io event subtype %d\n",event->xSubtype);
- if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)
- {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
-}
-
-
-static void viopath_donealloc(void *parm, int number)
-{
- struct doneAllocParms_t *doneAllocParmsp = (struct doneAllocParms_t *)parm;
- doneAllocParmsp->number = number;
- up(doneAllocParmsp->sem);
-}
-
-int viopath_open(HvLpIndex remoteLp, int subtype)
-{
- HvLpEvent_Rc hvrc;
- struct doneAllocParms_t doneAllocParms;
- DECLARE_MUTEX_LOCKED(Semaphore);
-
- if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid))
- return -EINVAL;
-
- if (VIOReqPage == 0)
- {
- /* Get a page to build read/write LP events in */
- VIOReqPage = get_free_page(GFP_KERNEL);
- if (!VIOReqPage)
- {
- printk("viopath: error allocating I/O memory\n");
- return -ENOMEM;
- }
-
- vio_char_event_buffer = (void *)VIOReqPage;
- vio_block_event_buffer = (void *)(VIOReqPage+256);
- vio_cd_event_buffer = (void *)(VIOReqPage+512);
- vio_tape_event_buffer = (void *)(VIOReqPage+768);
- }
-
- if ( (0)
-#if defined(CONFIG_VIODASD)
- || (subtype == viomajorsubtype_blockio)
-#endif
-#if defined(CONFIG_VIOCONS)
- || (subtype == viomajorsubtype_chario)
-#endif
-#if defined(CONFIG_VIOCD)
- || (subtype == viomajorsubtype_cdio)
-#endif
-#if defined(CONFIG_VIOTAPE)
- || (subtype == viomajorsubtype_tape)
-#endif
- )
- {
- viopath_statuslock(remoteLp);
- switch (subtype) {
-#if defined(CONFIG_VIODASD)
- case viomajorsubtype_blockio:
- viopathStatus[remoteLp].xBlockUsers++;
- break;
-#endif
-#if defined(CONFIG_VIOCONS)
- case viomajorsubtype_chario:
- viopathStatus[remoteLp].xCharUsers++;
- break;
-#endif
-#if defined(CONFIG_VIOCD)
- case viomajorsubtype_cdio:
- viopathStatus[remoteLp].xCDUsers++;
- break;
-#endif
-#if defined(CONFIG_VIOTAPE)
- case viomajorsubtype_tape:
- viopathStatus[remoteLp].xTapeUsers++;
- break;
-#endif
- default:
- }
- if (!viopathStatus[remoteLp].isOpen)
- {
- HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo);
-
- viopathStatus[remoteLp].mSourceInst = HvCallEvent_getSourceLpInstanceId(remoteLp, HvLpEvent_Type_VirtualIo);
- viopathStatus[remoteLp].mTargetInst = HvCallEvent_getTargetLpInstanceId(remoteLp, HvLpEvent_Type_VirtualIo);
-
- printk("viopath: open, setting sinst %d, tinst %d\n",
- viopathStatus[remoteLp].mSourceInst,
- viopathStatus[remoteLp].mTargetInst);
-
- doneAllocParms.sem = &Semaphore;
-
- mf_allocateLpEvents(remoteLp,
- HvLpEvent_Type_VirtualIo,
- 250, /* TODO: Put a sizeof VIOLpEvent in here! */
- 25, /* TODO: Work out the real number */
- &viopath_donealloc,
- &doneAllocParms);
-
- down(&Semaphore);
-
- viopathStatus[remoteLp].numberAllocated = doneAllocParms.number;
-
- HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo, &vio_handleEvent);
-
- viopathStatus[remoteLp].isOpen = 1;
-
- hvrc = HvCallEvent_signalLpEventFast(remoteLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_monitor,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_DeferredAck,
- viopathStatus[remoteLp].mSourceInst,
- viopathStatus[remoteLp].mTargetInst,
- 0, 0, 0, 0, 0, 0);
-
- if (hvrc == HvLpEvent_Rc_Good)
- {
- viopathStatus[remoteLp].isActive = 1;
- }
- else
- {
- viopathStatus[remoteLp].isActive = 0;
- }
- }
- viopath_statusunlock(remoteLp);
-
- return 0;
- }
- else /* invalid subtype */
- {
- printk("viopath: invalid path subtype %d\n",subtype);
- return -EINVAL;
- }
-}
-
-int viopath_close(HvLpIndex remoteLp, int subtype)
-{
- printk("viopath: close(%d,%4.4x)\n",remoteLp,subtype);
-
- if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid))
- return -EINVAL;
-
- if ( (0)
-#if defined(CONFIG_VIODASD)
- || (subtype == viomajorsubtype_blockio)
-#endif
-#if defined(CONFIG_VIOCONS)
- || (subtype == viomajorsubtype_chario)
-#endif
-#if defined(CONFIG_VIOCD)
- || (subtype == viomajorsubtype_cdio)
-#endif
-#if defined(CONFIG_VIOTAPE)
- || (subtype == viomajorsubtype_tape)
-#endif
- )
- {
- viopath_statuslock(remoteLp);
- switch (subtype) {
-#if defined(CONFIG_VIODASD)
- case viomajorsubtype_blockio:
- viopathStatus[remoteLp].xBlockUsers--;
- break;
-#endif
-#if defined(CONFIG_VIOCONS)
- case viomajorsubtype_chario:
- viopathStatus[remoteLp].xCharUsers--;
- break;
-#endif
-#if defined(CONFIG_VIOCD)
- case viomajorsubtype_cdio:
- viopathStatus[remoteLp].xCDUsers--;
- break;
-#endif
-#if defined(CONFIG_VIOTAPE)
- case viomajorsubtype_tape:
- viopathStatus[remoteLp].xTapeUsers--;
- break;
-#endif
- default:
- }
-
- if ((viopathStatus[remoteLp].isOpen)
-#if defined(CONFIG_VIODASD)
- && (viopathStatus[remoteLp].xBlockUsers == 0)
-#endif
-#if defined(CONFIG_VIOCONS)
- && (viopathStatus[remoteLp].xCharUsers == 0)
-#endif
-#if defined(CONFIG_VIOCD)
- && (viopathStatus[remoteLp].xCDUsers == 0)
-#endif
-#if defined(CONFIG_VIOTAPE)
- && (viopathStatus[remoteLp].xTapeUsers == 0)
-#endif
- )
- {
- printk("viopath: closing event path\n");
- HvCallEvent_closeLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo);
- viopathStatus[remoteLp].isOpen = 0;
- viopathStatus[remoteLp].isActive = 0;
- }
- viopath_statusunlock(remoteLp);
-
- return 0;
- }
- else /* invalid subtype */
- {
- printk("viopath: invalid path subtype %d\n",subtype);
- return -EINVAL;
- }
-}
diff -uNr --exclude=CVS linux/arch/ppc64/kernel/xics.c linuxppc64_2_4/arch/ppc64/kernel/xics.c
--- linux/arch/ppc64/kernel/xics.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/kernel/xics.c Wed Sep 5 13:56:40 2001
@@ -1,4 +1,4 @@
-/*
+/*
* arch/ppc/kernel/xics.c
*
* Copyright 2000 IBM Corporation.
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include "i8259.h"
#include "xics.h"
#include
@@ -50,6 +51,7 @@
#define XICS_IPI 2
#define XICS_IRQ_OFFSET 0x10
+#define XICS_PCI_IRQ_START 0x10
#define XICS_IRQ_SPURIOUS 0
@@ -77,19 +79,54 @@
struct xics_info xics_info;
-#define xirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.word)
-#define cppr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.bytes[0])
-#define poll_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr_poll.word)
-#define qirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->qirr.bytes[0])
-
unsigned long long intr_base = 0;
unsigned int xics_irq_8259_cascade = 0;
+unsigned int default_server = 0;
struct xics_interrupt_node {
unsigned long long addr;
unsigned long long size;
} inodes[NR_CPUS*2];
+typedef struct {
+ int (*xirr_info_get)(int cpu);
+ void (*xirr_info_set)(int cpu, int val);
+ void (*cppr_info)(int cpu, u8 val);
+ void (*qirr_info)(int cpu, u8 val);
+} xics_ops;
+
+
+static int pSeries_xirr_info_get(int n_cpu)
+{
+ return (xics_info.per_cpu[n_cpu]->xirr.word);
+}
+
+static void pSeries_xirr_info_set(int n_cpu, int value)
+{
+ xics_info.per_cpu[n_cpu]->xirr.word = value;
+}
+
+static void pSeries_cppr_info(int n_cpu, u8 value)
+{
+ xics_info.per_cpu[n_cpu]->xirr.bytes[0] = value;
+}
+
+static void pSeries_qirr_info(int n_cpu , u8 value)
+{
+ xics_info.per_cpu[n_cpu]->qirr.bytes[0] = value;
+}
+
+static xics_ops pSeries_ops = {
+ pSeries_xirr_info_get,
+ pSeries_xirr_info_set,
+ pSeries_cppr_info,
+ pSeries_qirr_info
+};
+
+static xics_ops *ops = &pSeries_ops;
+
+
+
void
xics_enable_irq(
u_int irq
@@ -102,9 +139,9 @@
if (irq == XICS_IPI)
return;
call_status = call_rtas("ibm,set-xive", 3, 1, (unsigned long*)&status,
- irq, cpu_hw_index[0], DEFAULT_PRIORITY);
+ irq, default_server, DEFAULT_PRIORITY);
if( call_status != 0 ) {
- printk("xics_enable_irq: irq=%x: call_rtas failed; retn=%x, status=%x\n",
+ printk("xics_enable_irq: irq=%x: call_rtas failed; retn=%lx, status=%lx\n",
irq, call_status, status);
return;
}
@@ -122,9 +159,8 @@
call_status = call_rtas("ibm,int-off", 1, 1, (unsigned long*)&status,
irq);
if( call_status != 0 ) {
- printk("xics_disable_irq: irq=%x: call_rtas failed, retn=%x\n",
+ printk("xics_disable_irq: irq=%x: call_rtas failed, retn=%ld\n",
irq, call_status);
- return;
}
}
@@ -135,9 +171,9 @@
{
int cpu = smp_processor_id();
- cppr_info(cpu) = 0; /* actually the value overwritten by ack */
+ ops->cppr_info(cpu, 0); /* actually the value overwritten by ack */
iosync();
- xirr_info(cpu) = (0xff<<24) | (irq-XICS_IRQ_OFFSET);
+ ops->xirr_info_set(cpu, ((0xff<<24) | (irq-XICS_IRQ_OFFSET)));
iosync();
}
@@ -151,11 +187,11 @@
if( irq < XICS_IRQ_OFFSET ) {
i8259_pic.ack(irq);
iosync();
- xirr_info(cpu) = (0xff<<24) | xics_irq_8259_cascade;
+ ops->xirr_info_set(cpu, ((0xff<<24) | xics_irq_8259_cascade));
iosync();
}
else {
- cppr_info(cpu) = 0xff;
+ ops->cppr_info(cpu, 0xff);
iosync();
}
}
@@ -166,8 +202,8 @@
u_int cpu = smp_processor_id();
u_int vec;
int irq;
-
- vec = xirr_info(cpu);
+
+ vec = ops->xirr_info_get(cpu);
/* (vec >> 24) == old priority */
vec &= 0x00ffffff;
/* for sanity, this had better be < NR_IRQS - 16 */
@@ -176,10 +212,12 @@
if(irq == -1) {
/* Spurious cascaded interrupt. Still must ack xics */
xics_end_irq(XICS_IRQ_OFFSET + xics_irq_8259_cascade);
+ irq = -1;
}
- } else if( vec == XICS_IRQ_SPURIOUS )
+ } else if( vec == XICS_IRQ_SPURIOUS ) {
irq = -1;
- else
+ printk("spurious PPC interrupt!\n");
+ } else
irq = vec + XICS_IRQ_OFFSET;
return irq;
}
@@ -198,9 +236,8 @@
{
extern volatile unsigned long xics_ipi_message[];
int cpu = smp_processor_id();
-
- qirr_info(cpu) = 0xff;
+ ops->qirr_info(cpu, 0xff);
while (xics_ipi_message[cpu]) {
if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu])) {
mb();
@@ -211,19 +248,18 @@
smp_message_recv(PPC_MSG_RESCHEDULE, regs);
}
}
-
}
void xics_cause_IPI(int cpu)
{
- qirr_info(cpu) = 0;
+ ops->qirr_info(cpu,0) ;
}
void xics_setup_cpu(void)
{
int cpu = smp_processor_id();
- cppr_info(cpu) = 0xff;
+ ops->cppr_info(cpu, 0xff);
iosync();
}
#endif /* CONFIG_SMP */
@@ -274,6 +310,9 @@
np = np->next;
if ((indx < NR_CPUS) && np) goto nextnode;
+ /* For now all interrupts go through this cpu (not necessarily cpu #0)... */
+ default_server = hard_smp_processor_id();
+
/*
* XXX Assume for now that nodes are in order
* We could (and should) get the "interrupt-server-ranges" property
@@ -303,15 +342,17 @@
xics_irq_8259_cascade = *ireg;
+ if (_machine == _MACH_pSeries) {
#ifdef CONFIG_SMP
- for (i = 0; i < naca->processorCount; ++i) {
- xics_info.per_cpu[i] =
- ioremap((ulong)inodes[cpu_hw_index[i]].addr,
- (ulong)inodes[cpu_hw_index[i]].size);
- }
+ for (i = 0; i < naca->processorCount; ++i) {
+ xics_info.per_cpu[i] =
+ ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr,
+ (ulong)inodes[get_hard_smp_processor_id(i)].size);
+ }
#else
- xics_info.per_cpu[0] = ioremap((ulong)intr_base, intr_size);
+ xics_info.per_cpu[0] = ioremap((ulong)intr_base, intr_size);
#endif /* CONFIG_SMP */
+ }
xics_8259_pic.enable = i8259_pic.enable;
xics_8259_pic.disable = i8259_pic.disable;
@@ -320,7 +361,7 @@
for (; i < NR_IRQS; ++i)
irq_desc[i].handler = &xics_pic;
- cppr_info(0) = 0xff;
+ ops->cppr_info(0, 0xff);
iosync();
if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action,
0, "8259 cascade", 0))
diff -uNr --exclude=CVS linux/arch/ppc64/mm/init.c linuxppc64_2_4/arch/ppc64/mm/init.c
--- linux/arch/ppc64/mm/init.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/mm/init.c Fri Sep 7 11:07:04 2001
@@ -38,6 +38,7 @@
#include
#include
#include
+#include
#ifdef CONFIG_BLK_DEV_INITRD
#include /* for initrd_* */
#endif
@@ -220,7 +221,12 @@
void *
ioremap(unsigned long addr, unsigned long size)
{
+#ifdef CONFIG_PPC_ISERIES
+ /* iSeries I/O Remap is a noop */
+ return (void*)addr;
+#else
return __ioremap(addr, size, _PAGE_NO_CACHE);
+#endif
}
extern struct vm_struct * get_im_area( unsigned long size );
@@ -291,9 +297,15 @@
return (void *) (ea + (addr & ~PAGE_MASK));
}
-void iounmap(void *addr)
+void iounmap(void *addr)
{
+#ifdef CONFIG_PPC_ISERIES
+ /* iSeries I/O Remap is a noop */
+ return;
+#else
/* DRENG / PPPBBB todo */
+ return;
+#endif
}
unsigned long iopa(unsigned long addr)
@@ -682,3 +694,46 @@
}
+
+/*
+ * This is called when a page has been modified by the kernel.
+ * It just marks the page as not i-cache clean. We do the i-cache
+ * flush later when the page is given to a user process, if necessary.
+ */
+void flush_dcache_page(struct page *page)
+{
+ clear_bit(PG_arch_1, &page->flags);
+}
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ * On machines which use an MMU hash table we avoid changing the
+ * _PAGE_HASHPTE bit.
+ * If the new PTE has _PAGE_EXEC set, meaning that the user wants
+ * to be able to execute out of the page, we check if the page is
+ * i-cache dirty and flush it if so, and mark it clean.
+ */
+void set_pte(pte_t *ptep, pte_t pte)
+{
+ pte_update(ptep, ~_PAGE_HPTEFLAGS, pte_val(pte) & ~_PAGE_HPTEFLAGS);
+ if (mem_init_done && (pte_val(pte) & _PAGE_EXEC)
+ && pte_pagenr(pte) < max_mapnr) {
+ struct page *page = pte_page(pte);
+ if (!test_bit(PG_arch_1, &page->flags)) {
+ __flush_dcache_icache((unsigned long)page_address(page));
+ set_bit(PG_arch_1, &page->flags);
+ }
+ }
+}
+
+void clear_user_page(struct page *page, unsigned long vaddr)
+{
+ clear_mem_page(page);
+ clear_bit(PG_arch_1, &page->flags);
+}
+
+void copy_user_page(struct page *to, struct page *from, unsigned long vaddr)
+{
+ copy_mem_page(to, from);
+ clear_bit(PG_arch_1, &to->flags);
+}
diff -uNr --exclude=CVS linux/arch/ppc64/xmon/start.c linuxppc64_2_4/arch/ppc64/xmon/start.c
--- linux/arch/ppc64/xmon/start.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/xmon/start.c Wed Sep 5 13:56:41 2001
@@ -18,6 +18,12 @@
#include
#include
+/* Transition to udbg isn't quite done yet...but very close. */
+#define USE_UDBG 1
+#ifdef USE_UDBG
+#include
+#endif
+
static volatile unsigned char *sccc, *sccd;
unsigned long TXRDY, RXRDY;
extern void xmon_printf(const char *fmt, ...);
@@ -38,11 +44,12 @@
return ret;
}
+#ifndef USE_UDBG
void buf_access(void)
{
- if ( _machine == _MACH_chrp )
- sccd[3] &= ~0x80; /* reset DLAB */
+ sccd[3] &= ~0x80; /* reset DLAB */
}
+#endif
extern int adb_init(void);
@@ -60,13 +67,15 @@
void
xmon_map_scc(void)
{
+ /* This maybe isn't the best place to register sysrq 'x' */
+ __sysrq_put_key_op('x', &sysrq_xmon_op);
+#ifndef USE_UDBG
/* should already be mapped by the kernel boot */
sccd = (volatile unsigned char *) (((unsigned long)comport1));
sccc = (volatile unsigned char *) (((unsigned long)comport1)+5);
TXRDY = 0x20;
RXRDY = 1;
- /* This maybe isn't the best place to register sysrq 'x' */
- __sysrq_put_key_op('x', &sysrq_xmon_op);
+#endif
}
static int scc_initialized = 0;
@@ -77,6 +86,9 @@
int
xmon_write(void *handle, void *ptr, int nb)
{
+#ifdef USE_UDBG
+ return udbg_write(ptr, nb);
+#else
char *p = ptr;
int i, c, ct;
@@ -100,6 +112,7 @@
*sccd = c;
}
return i;
+#endif
}
int xmon_wants_key;
@@ -108,6 +121,9 @@
int
xmon_read(void *handle, void *ptr, int nb)
{
+#ifdef USE_UDBG
+ return udbg_read(ptr, nb);
+#else
char *p = ptr;
int i, c;
@@ -123,34 +139,34 @@
*p++ = c;
}
return i;
+#endif
}
int
xmon_read_poll(void)
{
+#ifdef USE_UDBG
+ return -1; /* ToDo: need a udbg_poll_getc() */
+#else
if ((*sccc & RXRDY) == 0) {
-#ifdef CONFIG_ADB_PMU
- if (sys_ctrler == SYS_CTRLER_PMU)
- pmu_poll();
-#endif /* CONFIG_ADB_PMU */
return -1;
}
buf_access();
return *sccd;
+#endif
}
void
xmon_init_scc()
{
- if ( _machine == _MACH_chrp )
- {
- sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
- sccd[0] = 12; eieio(); /* DLL = 9600 baud */
- sccd[1] = 0; eieio();
- sccd[2] = 0; eieio(); /* FCR = 0 */
- sccd[3] = 3; eieio(); /* LCR = 8N1 */
- sccd[1] = 0; eieio(); /* IER = 0 */
- }
+#ifndef USE_UDBG
+ sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
+ sccd[0] = 12; eieio(); /* DLL = 9600 baud */
+ sccd[1] = 0; eieio();
+ sccd[2] = 0; eieio(); /* FCR = 0 */
+ sccd[3] = 3; eieio(); /* LCR = 8N1 */
+ sccd[1] = 0; eieio(); /* IER = 0 */
+#endif
scc_initialized = 1;
if (via_modem) {
diff -uNr --exclude=CVS linux/arch/ppc64/xmon/xmon.c linuxppc64_2_4/arch/ppc64/xmon/xmon.c
--- linux/arch/ppc64/xmon/xmon.c Mon Sep 10 14:37:43 2001
+++ linuxppc64_2_4/arch/ppc64/xmon/xmon.c Fri Sep 7 14:41:07 2001
@@ -496,6 +496,8 @@
int i;
struct bpt *bp;
+ if (_machine != _MACH_pSeries)
+ return;
bp = bpts;
for (i = 0; i < NBPTS; ++i, ++bp) {
if (!bp->enabled)
@@ -525,6 +527,8 @@
struct bpt *bp;
unsigned instr;
+ if (_machine != _MACH_pSeries)
+ return;
if (!__is_processor(PV_POWER4)) {
set_dabr(0);
set_iabr(0);
@@ -1156,7 +1160,6 @@
// Dump out relevant Paca data areas.
printf("Paca: \n");
ptrPaca = (struct Paca*)get_sprg3();
- printf(" Saved Gpr21=%.16lx Saved Gpr22 =%.16lx \n", ptrPaca->xR21, ptrPaca->xR22);
printf(" Local Processor Control Area (LpPaca): \n");
ptrLpPaca = ptrPaca->xLpPacaPtr;
diff -uNr --exclude=CVS linux/drivers/block/Config.in linuxppc64_2_4/drivers/block/Config.in
--- linux/drivers/block/Config.in Mon Sep 10 14:37:48 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/drivers/block/Makefile linuxppc64_2_4/drivers/block/Makefile
--- linux/drivers/block/Makefile Mon Sep 10 14:37:48 2001
+++ linuxppc64_2_4/drivers/block/Makefile Mon Sep 10 11:06:39 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/drivers/block/genhd.c linuxppc64_2_4/drivers/block/genhd.c
--- linux/drivers/block/genhd.c Mon Sep 10 14:37:48 2001
+++ linuxppc64_2_4/drivers/block/genhd.c Mon Sep 10 14:28:01 2001
@@ -194,6 +194,9 @@
#ifdef CONFIG_VT
console_map_init();
#endif
+#ifdef CONFIG_VIODASD
+ viodasd_init();
+#endif
return 0;
}
diff -uNr --exclude=CVS linux/drivers/block/ll_rw_blk.c linuxppc64_2_4/drivers/block/ll_rw_blk.c
--- linux/drivers/block/ll_rw_blk.c Mon Sep 10 14:37:48 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/drivers/block/viodasd.c linuxppc64_2_4/drivers/block/viodasd.c
--- linux/drivers/block/viodasd.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/block/viodasd.c Fri Sep 7 13:45:16 2001
@@ -0,0 +1,1414 @@
+/* -*- linux-c -*-
+ * viodasd.c
+ * Authors: Dave Boutcher
+ * Ryan Arnold
+ * Colin Devilbiss
+ *
+ * (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) 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.
+ *
+ * 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
+
+#include
+#include
+#include
+#include "../char//vio.h"
+#include
+
+MODULE_DESCRIPTION("iSeries Virtual DASD");
+MODULE_AUTHOR("Dave Boutcher");
+
+#define VIOMAXREQ 16
+#define VIOMAXBLOCKDMA 12
+
+struct vioblocklpevent {
+ struct HvLpEvent event;
+ u32 mReserved1;
+ u16 mVersion;
+ u16 mSubTypeRc;
+ u16 mDisk;
+ u16 mFlags;
+ union {
+ struct { // Used during open
+ u64 mDiskLen;
+ u16 mMaxDisks;
+ u16 mCylinders;
+ u16 mTracks;
+ u16 mSectors;
+ u16 mBytesPerSector;
+ } openData;
+ struct { // Used during rw
+ u64 mOffset;
+ struct {
+ u32 mToken;
+ u32 reserved;
+ u64 mLen;
+ } dmaInfo[VIOMAXBLOCKDMA];
+ } rwData;
+
+ struct {
+ u64 changed;
+ } check;
+ } u;
+};
+
+#define vioblockflags_ro 0x0001
+
+enum vioblocksubtype {
+ vioblockopen = 0x0001,
+ vioblockclose = 0x0002,
+ vioblockread = 0x0003,
+ vioblockwrite = 0x0004,
+ vioblockflush = 0x0005,
+ vioblockcheck = 0x0007
+};
+
+/* 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;
+
+/* 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);
+
+/* 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; j < VIOMAXBLOCKDMA; j++)
+ len += sprintf(buf + len, " [%2.2d] %ld",
+ j,
+ viod_stats[i][0].ntce[j]);
+
+ len += sprintf(buf + len, "\nwr DMA: ");
+
+ for (j = 0; j < VIOMAXBLOCKDMA; j++)
+ len += sprintf(buf + len, " [%2.2d] %ld",
+ j,
+ viod_stats[i][1].ntce[j]);
+ len += sprintf(buf + len, "\n");
+ }
+ }
+
+ *eof = 1;
+ return len;
+}
+
+/* Handle writes to our proc file system
+ */
+static int proc_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ return count;
+}
+
+/* setup our proc file system entries
+ */
+void viodasd_proc_init(struct proc_dir_entry *iSeries_proc)
+{
+ struct proc_dir_entry *ent;
+ ent =
+ create_proc_entry("viodasd", 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 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 << PARTITION_SHIFT);
+ int minor;
+ kdev_t devp;
+ struct super_block *sb;
+
+ if (viodasd_devices[device_no].size == 0)
+ return 0;
+
+ for (i = npart - 1; i >= 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) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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 << PARTITION_SHIFT] !=
+ viodasd_devices[device_no].size >> 10) {
+ printk(KERN_WARNING_VIO
+ "disk size change (%dK to %dK) for device %d\n",
+ viodasd_sizes[device_no << PARTITION_SHIFT],
+ (int) viodasd_devices[device_no].size >> 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) {
+ printk(KERN_WARNING_VIO "bad rc sending event to OS/400 %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) {
+ printk(KERN_WARNING_VIO "no inode provided in open\n");
+ return -ENODEV;
+ }
+
+ if (MAJOR(ino->i_rdev) != MAJOR_NR) {
+ printk(KERN_WARNING_VIO "Wierd error...wrong major number on open\n");
+ return -ENODEV;
+ }
+
+ device_no = DEVICE_NR(ino->i_rdev);
+ if (device_no > numdsk) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "no inode provided in release\n");
+ return -ENODEV;
+ }
+
+ if (MAJOR(ino->i_rdev) != MAJOR_NR) {
+ printk(KERN_WARNING_VIO
+ "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) {
+ printk(KERN_WARNING_VIO "no inode provided in ioctl\n");
+ return -ENODEV;
+ }
+
+ if (MAJOR(ino->i_rdev) != MAJOR_NR) {
+ printk(KERN_WARNING_VIO "Wierd error...wrong major number on ioctl\n");
+ return -ENODEV;
+ }
+
+ device_no = DEVICE_NR(ino->i_rdev);
+ if (device_no > numdsk) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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: printk(KERN_WARNING_VIO "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 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)) {
+ printk(KERN_WARNING_VIO "Invalid request offset & length\n");
+ printk(KERN_WARNING_VIO "req->sector: %ld, req->nr_sectors: %ld\n",
+ req->sector, req->nr_sectors);
+ printk(KERN_WARNING_VIO "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)) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO
+ "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 {
+ bevent = (struct vioblocklpevent *) vio_get_event_buffer(viomajorsubtype_blockio);
+ if (bevent == NULL) {
+ printk(KERN_WARNING_VIO
+ "error allocating disk event buffer\n");
+ return -1;
+ }
+
+ /* 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);
+ vio_free_event_buffer(viomajorsubtype_blockio, bevent);
+ }
+
+ if (hvrc != HvLpEvent_Rc_Good) {
+ printk(KERN_WARNING_VIO "error sending disk event to OS/400 (rcp %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) {
+ printk(KERN_WARNING_VIO "Invalid device # %d\n", CURRENT_DEV);
+ viodasd_end_request(CURRENT, 0);
+ continue;
+ }
+
+ if (viodasd_gendsk.sizes == NULL) {
+ printk(KERN_WARNING_VIO
+ "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) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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 << PARTITION_SHIFT,
+ NULL, /* partition array - fill in later */
+ NULL, /* block sizes - fill in later */
+ 0, /* # units */
+ NULL, /* "real device" pointer */
+ NULL, /* next */
+ &viodasd_fops /* operations */
+};
+
+/* This routine handles incoming block LP events
+ */
+static void vioHandleBlockEvent(struct HvLpEvent *event)
+{
+ struct scatterlist sg[VIOMAXBLOCKDMA];
+ struct vioblocklpevent *bevent = (struct vioblocklpevent *) event;
+ int nsect;
+ struct request *req;
+ int i;
+ struct viodasd_waitevent *pwe;
+ int flags;
+ int maxsg;
+
+ 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) {
+ printk(KERN_WARNING_VIO
+ "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 ((i < maxsg) &&
+ (bevent->u.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) {
+ printk(KERN_WARNING_VIO
+ "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) {
+ printk(KERN_WARNING_VIO "read/wrute error %d:%d\n", event->xRc,
+ bevent->mSubTypeRc);
+ viodasd_end_request(req, 0);
+ } else {
+ if (nsect != req->current_nr_sectors) {
+ printk(KERN_WARNING_VIO
+ "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) {
+ printk(KERN_WARNING_VIO
+ "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:
+ printk(KERN_WARNING_VIO "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 < numdsk; i++)
+ fsync_dev(MKDEV(MAJOR_NR, i));
+
+ read_ahead[MAJOR_NR] = 0;
+
+ CLEANIT(viodasd_devices);
+ CLEANIT(blk_size[MAJOR_NR]);
+ CLEANIT(blksize_size[MAJOR_NR]);
+ CLEANIT(hardsect_size[MAJOR_NR]);
+ CLEANIT(max_sectors[MAJOR_NR]);
+ CLEANIT(viodasd_gendsk.part);
+ blk_size[MAJOR_NR] = NULL;
+ blksize_size[MAJOR_NR] = NULL;
+
+ devfs_unregister_blkdev(MAJOR_NR, VIOD_DEVICE_NAME);
+}
+
+/* Initialize the whole device driver. Handle module and non-module
+ * versions
+ */
+__init int viodasd_init(void)
+{
+ int i, j;
+ int rc;
+ int *viodasd_blksizes;
+ int numpart = numdsk << PARTITION_SHIFT;
+
+ /* Try to open to our host lp
+ */
+ if (viopath_hostLp == HvLpIndexInvalid) {
+ vio_set_hostlp();
+ }
+
+ if (viopath_hostLp == HvLpIndexInvalid) {
+ printk(KERN_WARNING_VIO "%s: invalid hosting partition\n",
+ VIOD_DEVICE_NAME);
+ return -1;
+ }
+
+ /*
+ * Do the devfs_register. This works even if devfs is not
+ * configured
+ */
+ if (devfs_register_blkdev
+ (MAJOR_NR, VIOD_DEVICE_NAME, &viodasd_fops)) {
+ printk(KERN_WARNING_VIO "%s: unable to get major number %d\n",
+ VIOD_DEVICE_NAME, MAJOR_NR);
+ return -1;
+ }
+
+ printk(KERN_INFO_VIO
+ "%s: Disk vers %s, major %d, max disks %d, hosting partition %d\n",
+ VIOD_DEVICE_NAME, VIODASD_VERS, MAJOR_NR, numdsk,
+ viopath_hostLp);
+
+ if (ROOT_DEV == NODEV) {
+ ROOT_DEV = MKDEV(MAJOR_NR,1);
+
+ printk(KERN_INFO_VIO
+ "Claiming root file system as first partition of first virtual disk");
+ }
+
+ /* Do the blk device initialization */
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+
+ read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
+
+ /* Start filling in gendsk structure */
+ viodasd_gendsk.major = MAJOR_NR;
+ viodasd_gendsk.major_name = VIOD_GENHD_NAME;
+ viodasd_gendsk.nr_real = numdsk;
+ viodasd_gendsk.next = gendisk_head;
+ gendisk_head = &viodasd_gendsk;
+
+ /* Actually open the path to the hosting partition */
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ+2);
+ if (rc) {
+ printk(KERN_WARNING_VIO "error opening path to host partition %d\n",
+ viopath_hostLp);
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ return -1;
+ } else {
+ printk("%s: opened path to hosting partition %d\n",
+ VIOD_DEVICE_NAME, viopath_hostLp);
+ }
+
+ /*
+ * Initialize our request handler
+ */
+ vio_setHandler(viomajorsubtype_blockio, vioHandleBlockEvent);
+
+ /*
+ * Now fill in all the device driver info
+ */
+ viodasd_devices =
+ kmalloc(numdsk * sizeof(struct viodasd_device), GFP_KERNEL);
+ if (!viodasd_devices) {
+ cleanup2();
+ return -ENOMEM;
+ }
+ memset(viodasd_devices, 0x00,
+ numdsk * sizeof(struct viodasd_device));
+
+ viodasd_sizes = kmalloc(numpart * sizeof(int), GFP_KERNEL);
+ if (!viodasd_sizes) {
+ cleanup2();
+ return -ENOMEM;
+ }
+ memset(viodasd_sizes, 0x00, numpart * sizeof(int));
+ blk_size[MAJOR_NR] = viodasd_gendsk.sizes = viodasd_sizes;
+
+ viodasd_partitions =
+ kmalloc(numpart * sizeof(struct hd_struct), GFP_KERNEL);
+ if (!viodasd_partitions) {
+ cleanup2();
+ return -ENOMEM;
+ }
+ memset(viodasd_partitions, 0x00,
+ numpart * sizeof(struct hd_struct));
+ viodasd_gendsk.part = viodasd_partitions;
+
+ viodasd_blksizes = kmalloc(numpart * sizeof(int), GFP_KERNEL);
+ if (!viodasd_blksizes) {
+ cleanup2();
+ return -ENOMEM;
+ }
+ for (i = 0; i < numpart; i++)
+ viodasd_blksizes[i] = blksize;
+ blksize_size[MAJOR_NR] = viodasd_blksizes;
+
+ viodasd_sectsizes = kmalloc(numpart * sizeof(int), GFP_KERNEL);
+ if (!viodasd_sectsizes) {
+ cleanup2();
+ return -ENOMEM;
+ }
+ for (i = 0; i < numpart; i++)
+ viodasd_sectsizes[i] = 0;
+ hardsect_size[MAJOR_NR] = viodasd_sectsizes;
+
+ viodasd_maxsectors = kmalloc(numpart * sizeof(int), GFP_KERNEL);
+ if (!viodasd_maxsectors) {
+ cleanup2();
+ return -ENOMEM;
+ }
+ for (i = 0; i < numpart; i++)
+ viodasd_maxsectors[i] = VIODASD_MAXSECTORS;
+ max_sectors[MAJOR_NR] = viodasd_maxsectors;
+
+ viodasd_max_disk = numdsk;
+ for (i = 0; i <= viodasd_max_disk; i++) {
+ // Note that internal_open has two side effects:
+ // a) it updates the size of the disk
+ // b) it updates viodasd_max_disk
+ if (internal_open(i) == 0) {
+ if (i == 0)
+ printk(KERN_INFO_VIO
+ "%s: Currently %d disks connected\n",
+ VIOD_DEVICE_NAME,
+ (int) viodasd_max_disk + 1);
+
+ register_disk(&viodasd_gendsk,
+ MKDEV(MAJOR_NR,
+ i << PARTITION_SHIFT),
+ 1 << PARTITION_SHIFT, &viodasd_fops,
+ viodasd_partitions[i <<
+ PARTITION_SHIFT].
+ nr_sects);
+
+ printk(KERN_INFO_VIO
+ "%s: Disk %2.2d size %dM, sectors %d, heads %d, cylinders %d, sectsize %d\n",
+ VIOD_DEVICE_NAME, i,
+ (int) (viodasd_devices[i].size /
+ (1024 * 1024)),
+ (int) viodasd_devices[i].sectors,
+ (int) viodasd_devices[i].tracks,
+ (int) viodasd_devices[i].cylinders,
+ (int) viodasd_sectsizes[i <<
+ PARTITION_SHIFT]);
+
+ for (j = (i << PARTITION_SHIFT) + 1;
+ j < ((i + 1) << PARTITION_SHIFT); j++) {
+ if (viodasd_gendsk.part[j].nr_sects)
+ printk(KERN_INFO_VIO
+ "%s: Disk %2.2d partition %2.2d start sector %ld, # sector %ld\n",
+ VIOD_DEVICE_NAME, i,
+ j - (i << PARTITION_SHIFT),
+ viodasd_gendsk.part[j].
+ start_sect,
+ viodasd_gendsk.part[j].
+ nr_sects);
+ }
+
+ internal_release(i);
+ }
+ }
+
+ /*
+ * Create the proc entry
+ */
+ iSeries_proc_callback(&viodasd_proc_init);
+
+ return 0;
+}
+
+#ifdef MODULE
+void viodasd_exit(void)
+{
+ int i;
+ for (i = 0; i < numdsk << PARTITION_SHIFT; i++)
+ fsync_dev(MKDEV(MAJOR_NR, i));
+
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+
+ iSeries_proc_callback(&viodasd_proc_delete);
+
+ cleanup2();
+}
+#endif
+
+#ifdef MODULE
+module_init(viodasd_init);
+module_exit(viodasd_exit);
+#endif
diff -uNr --exclude=CVS linux/drivers/cdrom/Config.in linuxppc64_2_4/drivers/cdrom/Config.in
--- linux/drivers/cdrom/Config.in Mon Jan 24 13:04:37 2000
+++ linuxppc64_2_4/drivers/cdrom/Config.in Mon Jun 18 18:18:47 2001
@@ -25,3 +25,10 @@
tristate ' ISP16/MAD16/Mozart soft configurable cdrom interface support' CONFIG_ISP16_CDI
tristate ' Sony CDU31A/CDU33A CDROM support' CONFIG_CDU31A
tristate ' Sony CDU535 CDROM support' CONFIG_CDU535
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+ dep_tristate 'iSeries Virtual I/O CD support' CONFIG_VIOCD $CONFIG_PPC_ISERIES
+ if [ "$CONFIG_VIOCD" = "y" -o "$CONFIG_VIOCD" = "m" ]; then
+ bool 'iSeries Virtual CD Aztech emulation' CONFIG_VIOCD_AZTECH
+ fi
+fi
+
diff -uNr --exclude=CVS linux/drivers/cdrom/Makefile linuxppc64_2_4/drivers/cdrom/Makefile
--- linux/drivers/cdrom/Makefile Fri Dec 29 16:07:21 2000
+++ linuxppc64_2_4/drivers/cdrom/Makefile Mon Jun 18 18:18:47 2001
@@ -42,6 +42,7 @@
obj-$(CONFIG_SBPCD4) += sbpcd4.o cdrom.o
obj-$(CONFIG_SJCD) += sjcd.o
obj-$(CONFIG_CDU535) += sonycd535.o
+obj-$(CONFIG_VIOCD) += viocd.o cdrom.o
# Hand off to Rules.make.
diff -uNr --exclude=CVS linux/drivers/cdrom/viocd.c linuxppc64_2_4/drivers/cdrom/viocd.c
--- linux/drivers/cdrom/viocd.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/cdrom/viocd.c Fri Sep 7 13:45:16 2001
@@ -0,0 +1,719 @@
+/* -*- linux-c -*-
+ * drivers/cdrom/viocd.c
+ *
+ ***************************************************************************
+ * iSeries Virtual CD Rom
+ *
+ * Authors: Dave Boutcher
+ * Ryan Arnold
+ * Colin Devilbiss
+ *
+ * (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.
+ *
+ * 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.
+ *
+ */
+
+#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
+
+#include
+#include
+#include "../char/vio.h"
+#include
+
+struct viocdlpevent {
+ struct HvLpEvent event;
+ u32 mReserved1;
+ u16 mVersion;
+ u16 mSubTypeRc;
+ u16 mDisk;
+ u16 mFlags;
+ u32 mToken;
+ u64 mOffset; // On open, the max number of disks
+ u64 mLen; // On open, the size of the disk
+ u32 mBlockSize; // Only set on open
+ u32 mMediaSize; // Only set on open
+};
+
+enum viocdsubtype {
+ viocdopen = 0x0001,
+ viocdclose = 0x0002,
+ viocdread = 0x0003,
+ viocdgetinfo = 0x0006,
+ viocdcheck = 0x0007
+};
+
+/* 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);
+
+/* 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) {
+ printk(KERN_WARNING_VIO "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) (unsigned long) &we,
+ VIOVERSION << 16, dmaaddr, 0,
+ sizeof(struct cdrom_info) *
+ VIOCD_MAX_CD, 0);
+ if (hvrc != HvLpEvent_Rc_Good) {
+ printk(KERN_WARNING_VIO "cdrom error sending event. rc %d\n", (int) hvrc);
+ return;
+ }
+
+ down(&Semaphore);
+
+ if (we.rc) {
+ printk(KERN_WARNING_VIO "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) (unsigned long) &we,
+ VIOVERSION << 16,
+ ((u64) device_no << 48), 0, 0,
+ 0);
+ if (hvrc != 0) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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) (unsigned long) req->
+ buffer, VIOVERSION << 16,
+ ((u64) device_no << 48) |
+ dmaaddr, start, len, 0);
+ if (hvrc != HvLpEvent_Rc_Good) {
+ printk(KERN_WARNING_VIO "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) {
+ 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 (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) {
+ printk(KERN_WARNING_VIO "%s\n", err_str);
+ viocd_end_request(req, 0);
+ } else {
+ spin_lock(&viocd_lock);
+ list_add_tail(&req->queue, &reqlist);
+ ++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) {
+ printk(KERN_WARNING_VIO "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) (unsigned long) &we,
+ VIOVERSION << 16,
+ ((u64) device_no << 48), 0, 0,
+ 0);
+
+ if (hvrc != 0) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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) {
+ printk(KERN_WARNING_VIO "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 *) (unsigned long) 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) (unsigned long) 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) {
+ printk(KERN_WARNING_VIO
+ "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)
+ printk(KERN_WARNING_VIO
+ "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) {
+ printk(KERN_WARNING_VIO
+ "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 *) (unsigned long) event->
+ xCorrelationToken;
+ pwe->rc = event->xRc;
+ pwe->changed = bevent->mFlags;
+ up(pwe->sem);
+ break;
+
+ default:
+ printk(KERN_WARNING_VIO "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; i < viocd_numdev; i++) {
+ len +=
+ sprintf(buf + len,
+ "viocd device %d is iSeries resource %10.10s type %4.4s, model %3.3s\n",
+ i, viocd_unitinfo[i].rsrcname,
+ viocd_unitinfo[i].type,
+ viocd_unitinfo[i].model);
+ }
+ *eof = 1;
+ return len;
+}
+
+
+/* setup our proc file system entries
+ */
+void viocd_proc_init(struct proc_dir_entry *iSeries_proc)
+{
+ struct proc_dir_entry *ent;
+ ent = create_proc_entry("viocd", S_IFREG | S_IRUSR, iSeries_proc);
+ if (!ent)
+ return;
+ ent->nlink = 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 (viopath_hostLp == HvLpIndexInvalid)
+ vio_set_hostlp();
+
+ /* If we don't have a host, bail out */
+ if (viopath_hostLp == HvLpIndexInvalid)
+ return -ENODEV;
+
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ+2);
+ if (rc) {
+ printk(KERN_WARNING_VIO "error opening path to host partition %d\n",
+ viopath_hostLp);
+ return rc;
+ }
+
+ /* Initialize our request handler
+ */
+ rwreq = 0;
+ vio_setHandler(viomajorsubtype_cdio, vioHandleCDEvent);
+
+ memset(viocd_diskinfo, 0x00, sizeof(viocd_diskinfo));
+
+ get_viocd_info();
+
+ if (viocd_numdev == 0) {
+ viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ+2);
+ 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; i < viocd_numdev; i++) {
+ viocd_info[i].dev = MKDEV(MAJOR_NR, i);
+ viocd_info[i].ops = &viocd_dops;
+ viocd_info[i].speed = 4;
+ viocd_info[i].capacity = 1;
+ sprintf(viocd_info[i].name, "viocd%d", i);
+ if (register_cdrom(&viocd_info[i]) != 0) {
+ printk("Cannot register viocd CD-ROM %s!\n",
+ viocd_info[i].name);
+ } else {
+ printk(KERN_INFO_VIO
+ "cd %s is iSeries resource %10.10s type %4.4s, model %3.3s\n",
+ viocd_info[i].name,
+ viocd_unitinfo[i].rsrcname,
+ viocd_unitinfo[i].type,
+ viocd_unitinfo[i].model);
+ }
+ }
+
+ /*
+ * Create the proc entry
+ */
+ iSeries_proc_callback(&viocd_proc_init);
+
+ return 0;
+}
+
+#ifdef MODULE
+void viocd_exit(void)
+{
+ int i;
+ for (i = 0; i < viocd_numdev; i++) {
+ if (unregister_cdrom(&viocd_info[i]) != 0) {
+ printk(KERN_WARNING_VIO "Cannot unregister viocd CD-ROM %s!\n",
+ viocd_info[i].name);
+ }
+ }
+ if ((devfs_unregister_blkdev(MAJOR_NR, "viocd") == -EINVAL)) {
+ printk("can't unregister viocd\n");
+ return;
+ }
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ if (viocd_unitinfo)
+ kfree(viocd_unitinfo);
+
+ iSeries_proc_callback(&viocd_proc_delete);
+
+ viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ+2);
+ vio_clearHandler(viomajorsubtype_cd);
+}
+#endif
+
+#ifdef MODULE
+module_init(viocd_init);
+module_exit(viocd_exit);
+#endif
diff -uNr --exclude=CVS linux/drivers/char/Config.in linuxppc64_2_4/drivers/char/Config.in
--- linux/drivers/char/Config.in Mon Sep 10 14:37:49 2001
+++ linuxppc64_2_4/drivers/char/Config.in Tue Sep 4 14:09:12 2001
@@ -101,6 +101,9 @@
fi
dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
fi
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+ dep_tristate 'iSeries Virtual Console Support' CONFIG_VIOCONS $CONFIG_PPC_ISERIES
+fi
source drivers/i2c/Config.in
@@ -138,6 +141,10 @@
fi
fi
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+ dep_tristate 'iSeries Virtual Tape Support' CONFIG_VIOTAPE $CONFIG_PPC_ISERIES
+fi
+
mainmenu_option next_comment
comment 'Watchdog Cards'
bool 'Watchdog Timer Support' CONFIG_WATCHDOG
@@ -180,6 +187,9 @@
dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
tristate '/dev/nvram support' CONFIG_NVRAM
+if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
+ tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
+fi
tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
if [ "$CONFIG_IA64" = "y" ]; then
bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
diff -uNr --exclude=CVS linux/drivers/char/Makefile linuxppc64_2_4/drivers/char/Makefile
--- linux/drivers/char/Makefile Mon Sep 10 14:37:49 2001
+++ linuxppc64_2_4/drivers/char/Makefile Mon Sep 10 14:28:02 2001
@@ -161,6 +161,7 @@
obj-$(CONFIG_SPECIALIX) += specialix.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
+obj-$(CONFIG_VIOCONS) += viocons.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o
@@ -170,6 +171,23 @@
obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
+ifdef CONFIG_VIOCONS
+ CONFIG_VIOPATH=y
+else
+ ifdef CONFIG_VIODASD
+ CONFIG_VIOPATH=y
+ else
+ ifdef CONFIG_VIOTAPE
+ CONFIG_VIOPATH=y
+ else
+ ifdef CONFIG_VIOCD
+ CONFIG_VIOPATH=y
+ endif
+ endif
+ endif
+endif
+obj-$(CONFIG_VIOPATH) += viopath.o
+
subdir-$(CONFIG_RIO) += rio
subdir-$(CONFIG_INPUT) += joystick
@@ -203,6 +221,7 @@
obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
obj-$(CONFIG_QIC02_TAPE) += tpqic02.o
+obj-$(CONFIG_VIOTAPE) += viotape.o
subdir-$(CONFIG_FTAPE) += ftape
subdir-$(CONFIG_DRM_NEW) += drm
diff -uNr --exclude=CVS linux/drivers/char/n_tty.c linuxppc64_2_4/drivers/char/n_tty.c
--- linux/drivers/char/n_tty.c Fri Apr 6 12:42:55 2001
+++ linuxppc64_2_4/drivers/char/n_tty.c Wed Jun 6 18:47:40 2001
@@ -538,7 +538,7 @@
* handle specially, do shortcut processing to speed things
* up.
*/
- if (!test_bit(c, &tty->process_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/drivers/char/tty_io.c linuxppc64_2_4/drivers/char/tty_io.c
--- linux/drivers/char/tty_io.c Mon Sep 10 14:37:53 2001
+++ linuxppc64_2_4/drivers/char/tty_io.c Tue Sep 4 14:09:13 2001
@@ -2239,6 +2239,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
@@ -2345,6 +2350,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/drivers/char/vio.h linuxppc64_2_4/drivers/char/vio.h
--- linux/drivers/char/vio.h Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/char/vio.h Fri Sep 7 13:45:16 2001
@@ -0,0 +1,115 @@
+/* -*- linux-c -*-
+ * drivers/char/vio.h
+ *
+ * iSeries Virtual I/O Message Path header
+ *
+ * Authors: Dave Boutcher
+ * Ryan Arnold
+ * Colin Devilbiss
+ *
+ * (C) Copyright 2000 IBM Corporation
+ *
+ * This header file is used by the iSeries virtual I/O device
+ * drivers. It defines the interfaces to the common functions
+ * (implemented in drivers/char/viopath.h) as well as defining
+ * common functions and structures. Currently (at the time I
+ * wrote this comment) the iSeries virtual I/O device drivers
+ * that use this are
+ * drivers/block/viodasd.c
+ * drivers/char/viocons.c
+ * drivers/char/viotape.c
+ * drivers/cdrom/viocd.c
+ *
+ * The iSeries virtual ethernet support (veth.c) uses a whole
+ * different set of functions.
+ *
+ * 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
+ *
+ */
+#ifndef _VIO_H
+#define _VIO_H
+
+#include
+#include
+
+/* iSeries virtual I/O events use the subtype field in
+ * HvLpEvent to figure out what kind of vio event is coming
+ * in. We use a table to route these, and this defines
+ * the maximum number of distinct subtypes
+ */
+#define VIO_MAX_SUBTYPES 7
+
+/* Each subtype can register a handler to process their events.
+ * The handler must have this interface.
+ */
+typedef void (vio_event_handler_t) (struct HvLpEvent * event);
+
+int viopath_open(HvLpIndex remoteLp, int subtype, int numReq);
+int viopath_close(HvLpIndex remoteLp, int subtype, int numReq);
+int vio_setHandler(int subtype, vio_event_handler_t * beh);
+int vio_clearHandler(int subtype);
+int viopath_isactive(HvLpIndex lp);
+HvLpInstanceId viopath_sourceinst(HvLpIndex lp);
+HvLpInstanceId viopath_targetinst(HvLpIndex lp);
+void vio_set_hostlp(void);
+void *vio_get_event_buffer(int subtype);
+void vio_free_event_buffer(int subtype, void *buffer);
+
+extern HvLpIndex viopath_hostLp;
+
+#define VIO_MESSAGE "iSeries virtual I/O: "
+#define KERN_DEBUG_VIO KERN_DEBUG VIO_MESSAGE
+#define KERN_INFO_VIO KERN_INFO VIO_MESSAGE
+#define KERN_WARNING_VIO KERN_WARNING VIO_MESSAGE
+
+#define VIOCHAR_MAX_DATA 200
+
+#define VIOMAJOR_SUBTYPE_MASK 0xff00
+#define VIOMINOR_SUBTYPE_MASK 0x00ff
+#define VIOMAJOR_SUBTYPE_SHIFT 8
+
+#define VIOVERSION 0x0101
+
+enum viosubtypes {
+ viomajorsubtype_monitor = 0x0100,
+ viomajorsubtype_blockio = 0x0200,
+ viomajorsubtype_chario = 0x0300,
+ viomajorsubtype_config = 0x0400,
+ viomajorsubtype_cdio = 0x0500,
+ viomajorsubtype_tape = 0x0600
+};
+
+
+enum vioconfigsubtype {
+ vioconfigget = 0x0001,
+};
+
+enum viorc {
+ viorc_good = 0x0000,
+ viorc_noConnection = 0x0001,
+ viorc_noReceiver = 0x0002,
+ viorc_noBufferAvailable = 0x0003,
+ viorc_invalidMessageType = 0x0004,
+ viorc_invalidRange = 0x0201,
+ viorc_invalidToken = 0x0202,
+ viorc_DMAError = 0x0203,
+ viorc_useError = 0x0204,
+ viorc_releaseError = 0x0205,
+ viorc_invalidDisk = 0x0206,
+ viorc_openRejected = 0x0301
+};
+
+
+#endif /* _VIO_H */
diff -uNr --exclude=CVS linux/drivers/char/viocons.c linuxppc64_2_4/drivers/char/viocons.c
--- linux/drivers/char/viocons.c Wed Dec 31 18:00:00 1969
+++ linuxppc64_2_4/drivers/char/viocons.c Fri Sep 7 13:45:16 2001
@@ -0,0 +1,1403 @@
+/* -*- linux-c -*-
+ * drivers/char/viocons.c
+ *
+ * iSeries Virtual Terminal
+ *
+ * Authors: Dave Boutcher
+ * Ryan Arnold
+ * Colin Devilbiss
+ *
+ * (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