diff -uNr --exclude=CVS linux-2.4.9-ac10/Documentation/Configure.help linuxppc64_2_4/Documentation/Configure.help --- linux-2.4.9-ac10/Documentation/Configure.help Thu Sep 6 14:11:16 2001 +++ linuxppc64_2_4/Documentation/Configure.help Fri Sep 14 10:42:50 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 @@ -14337,6 +14345,13 @@ hard drives and ADFS-formatted floppy disks. This is experimental codes, so if you're unsure, say N. +JFS filesystem support +CONFIG_JFS_FS + This is a port of IBM's Journaled Filesystem . More information is + available in the file Documentation/filesystems/jfs.txt. + + If you do not intend to use the JFS filesystem, say N. + /dev/pts file system for Unix98 PTYs CONFIG_DEVPTS_FS You should say Y here if you said Y to "Unix98 PTY support" above. @@ -19954,23 +19969,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. + + iSeries Linux information from IBM can be found at: + + + pSeries Linux information from IBM can be found at: + - Select APUS if configuring for a PowerUP Amiga. More information is - available 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 +20268,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 sparse + 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 +20302,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 +23024,11 @@ CONFIG_XMON Include in-kernel hooks for the xmon kernel monitor/debugger supported by the PPC port. + +Include realtime debugging +CONFIG_PPCDBG + Include in-kernel PowerPC 64 information hooks that may be turned on/off + in real time. Include kgdb kernel debugger CONFIG_KWDB diff -uNr --exclude=CVS linux-2.4.9-ac10/Documentation/cachetlb.txt linuxppc64_2_4/Documentation/cachetlb.txt --- linux-2.4.9-ac10/Documentation/cachetlb.txt Thu Sep 6 14:05:19 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-2.4.9-ac10/Documentation/filesystems/00-INDEX linuxppc64_2_4/Documentation/filesystems/00-INDEX --- linux-2.4.9-ac10/Documentation/filesystems/00-INDEX Thu Sep 6 14:05:13 2001 +++ linuxppc64_2_4/Documentation/filesystems/00-INDEX Thu Sep 13 14:29:38 2001 @@ -22,6 +22,8 @@ - info and mount options for the OS/2 HPFS. isofs.txt - info and mount options for the ISO 9660 (CDROM) filesystem. +jfs.txt + - info and mount options for the JFS filesystem. ncpfs.txt - info on Novell Netware(tm) filesystem using NCP protocol. ntfs.txt diff -uNr --exclude=CVS linux-2.4.9-ac10/Documentation/filesystems/changelog.jfs linuxppc64_2_4/Documentation/filesystems/changelog.jfs --- linux-2.4.9-ac10/Documentation/filesystems/changelog.jfs Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/Documentation/filesystems/changelog.jfs Thu Sep 13 14:31:38 2001 @@ -0,0 +1,594 @@ +IBM's Journaled File System (JFS) for Linux version 1.0.4 +Team members +Steve Best sbest@us.ibm.com +Dave Kleikamp shaggy@us.ibm.com +Barry Arndt barndt@us.ibm.com + + +Release August 31, 2001 (version 1.0.4) + +This is our forty-second release of IBM's Enterprise JFS technology port to Linux. +Beta 1 was release 0.1.0 on 12/8/2000, Beta 2 was release 0.2.0 on 3/7/2001, +Beta 3 was release 0.3.0 on 4/30/2001, and release 1.0.0 on 6/28/2001. + +The first drop on February 2, 2000 (jfs-0.0.1.tar.gz) had the following +functionality (enough to allow other developers to evaluate and potentially +contribute to this project): + + - MKFS functional and able to format an existing or newly created partition for JFS. + - mount/unmount functional + - able to view the self(.) and parent (..) directories entries. + +The second drop on February 28, 2000 (jfs-0.0.2.tar.gz) had fixes for MKFS and the +following utilities logredo, xchkdmp, xpeek are functional. The file system was able +to mkdir, create files and directories were working (and rm, rmdir). + +The third drop on March 24, 2000 (jfs-0.0.3.tar.gz) provided read and write capability +for the file system. Also, support for hard and soft links are functional. + +The fourth drop on March 29,2000 (jfs-0.0.4.tar.gz) provided rename capability for +the file system and fixes for write problems. + +The fifth drop on April 6, 2000 (jfs-0.0.5.tar.gz) provided mknod capability for the +file system. + +The sixth drop on April 21, 2000 (jfs-0.0.6.tar.gz) provided fixes for the file system +and utilities. + +The seventh drop on May 11, 2000 (jfs-0.0.7.tar.gz) provided changes to the file system +to be able to work on the development kernel 2.3.99-pre6. Drop 7 contains fixes for the +file system to be built within the kernel. + +The eighth drop on June 20, 2000 (jfs-0.0.8.tar.gz) provided fixes for the file system +and changes to the file system to be able to work on the development kernel 2.4.0-test1-ac21. +In the utility area: fsck and logdump are functional. + +The ninth drop on July 13, 2000 (jfs-0.0.9.tar.gz) has the meta-data of the file system +using the page cache. In the utility area: fixes for fsck.jfs and xpeek are included. + +The tenth drop on August 11, 2000 provided fixes for the file system +and changes to the file system to be able to work on the development kernel 2.4.0-test5. +In the utility area: fixes for fsck.jfs are included. The utility portion of extendfs has +been ported (still need to port the file system portion for extendfs). Man pages have +been written for the utilities. The compiler warnings have been removed from all of the +utilities. + +The eleventh drop on September 1, 2000 provided fixes for the file system +and changes to the file system to be able to work on the development kernel 2.4.0-test7. +The utility portion of defrag has been ported (still need to port the file system portion +for defrag). + +The twelfth drop on September 15, 2000 (jfs-0.0.12.tar.gz) provided the Transaction +Manager Log I/O routines. + +The thirteenth drop on September 29, 2000 (jfs-0.0.13.tar.gz) provided case-sensitive +support. In the utility area: fsck.jfs has the support for block/character special files. +Note: The JFS partition must be formatted/reformatted using mkfs.jfs created by drop 13 +for case-sensitive to work. + +The fourteenth drop on October 4, 2000 (jfs-0.0.14.tar.gz) included a fix to the file +system for not mounting a JFS partition if the size of the partition is > 4G on 2.2.x +series of the kernel. + +The fifteenth drop on October 9, 2000 (jfs-0.0.15.tar.gz) included the Transaction +Manager routines (Initialize, Begin, Locks, End). The file system has fixes and +changes to the file system to be able to work on the development kernel 2.4.0-test9. +The utility xchklog has been ported. + +The sixteenth drop on October 27, 2000 (jfs-0.0.16.tar.gz) included the Transaction +Manager routines (Commit, Buffer Management, Abort). The file system and utilities +have fixes included. + +The seventeenth drop on November 10, 2000 (jfs-0.0.17.tar.gz) has the transaction +sub operations back into the file system operations. The file system is now journaling +appropriate file system operations. The file system is temporary doing synchronous logging +(which slows down operations that are logged) to make sure that the transaction processing +is right. Asynchronous logging will be added shortly. The file system has fixes and changes +to the file system to be able to work on the development kernel 2.4.0-test10. + +The eighteenth drop on November 15, 2000 (jfs-0.0.18.tar.gz) included fixes to the file +system. + +The nineteenth drop on December 4, 2000 (jfs-0.0.19.tar.gz) is now doing asynchronous +logging. The file system has fixes and changes to the file system to be able to work +on the development kernel 2.4.0-test11. + +The twentieth drop on December 8, 2000 (jfs-0.1.0.tar.gz beta) included fixes to the file +system. + +The twenty-first drop on December 14, 2000 (jfs-0.1.1.tar.gz) included a fsck fix +to handle sparse files correctly. The file system has fixes and changes to the file +system to be able to work on the development kernel 2.4.0-test12 and 2.2.18 kernel. + +The twenty-second drop on January 5, 2001 (jfs-0.1.2.tar.gz) included fixes to the +file system. The file system has changes to able to work on the 2.4.0 kernel. + +The twenty-third drop on January 12, 2001 (jfs-0.1.3.tar.gz) included fixes to the +file system. Fsck now supports fifo correctly. + +The twenty-fourth drop on January 26, 2001 (jfs-0.1.4.tar.gz) included fixes to the +file system. The new feature in the file system is "Lazy Commit" which increases +performance while going asynchronous logging. The main makefile for the utilities +now has an install option. + +The twenty-fifth drop on February 7, 2001 (jfs-0.1.5.tar.gz) included fixes to the +file system. + +The twenty-sixth drop on February 26, 2001 (jfs-0.1.6.tar.gz) included fixes to the +file system. The log manager no longer uses the page cache for log pages, this +eliminates dead-locks that were occurring in the log manager. The file system has +general work done to remove SMP dead-lock problems. Fsck now supports default values +passed by fstab correctly. + +The twenty-seventh drop on March 7, 2001 (beta 2) (jfs-0.2.0.tar.gz) included fixes to the +file system. This drop contains jfsprogs.spec that can be used to create RPM for the +JFS utilities. The file system has general work done to remove SMP and UP hang related problems. +The file system performance has been increased by changes to extent inode cache. + +The twenty-eighth drop on March 21, 2001 (jfs-0.2.1.tar.gz) included fixes to the +file system. The file system has been changed to use standard types. + +The twenty-ninth drop on April 2, 2001 (jfs-0.2.2.tar.gz) included fixes to the +file system. The utilities have been changed to use standard types. + +The thirtieth drop on April 30, 2001 (jfs-0.3.0.tar.gz) included fixes to the +file system. The rest of the utilities have been changed to use standard types. +Both the file system and the utilities have been changed to use endian macros, +so that JFS will now store the meta-data as little endian when running on all +architectures, with this change you must re-format all of the JFS partitions +using the new mkfs.jfs included in this drop, if you are running on a big-endian system. + +The thirty-first drop on May 9, 2001 (jfs-0.3.1.tar.gz) included fixes to the file +system and the utilities. + +The thirty-second drop on May 18, 2001 (jfs-0.3.2-patch.tar.gz) included fixes to the file +system and the utilities. + +The thirty-third drop on May 25, 2001 (jfs-0.3.3-patch.tar.gz) included fixes to the file +system and the utilities. + +The thirty-fourth drop on June 8, 2001 (jfs-0.3.4-patch.tar.gz) included fixes to the +file system and the utilities. + +The thirty-fifth drop on June 15, 2001 (jfs-0.3.5-patch.tar.gz) includes fixes to the +file system and utilities. + +The thirty-sixth drop on June 22, 2001 (jfs-0.3.6-patch.tar.gz) includes fixes to the +file system and utilities. The change made to the file system to fix the rm -rf problem +is a disk layout change and with this change you must re-format all of the JFS partitions +using the new mkfs.jfs included in this drop to have the rm -rf problem fixed. + + +The thirty-seventh drop on June 25, 2001 (jfs-0.3.7-patch.tar.gz) includes fixes to the +file system and utilities. + +The thirty-eighth drop on June 28, 2001 (jfs-1.0.0-patch.tar.gz) includes fixes to the +file system and utilities. + +The thirty-ninth drop on July 10, 2001 (jfs-1.0.1-patch.tar.gz) includes fixes to the +file system and utilities. + +The fortieth drop on August 3, 2001 (jfs-1.0.2-patch.tar.gz) includes fixes to the +file system and utilities. + +The forty-first drop on August 20, 2001 (jfs-1.0.3-patch.tar.gz) includes fixes to the +file system and utilities. + + +The forty-second drop on August 31, 2001 (jfs-2.2-1.0.4-patch.tar.gz or +jfs-2.4-1.0.4-patch.tar.gz) includes fixes to the file system and utilities. + +Drop 42 has the temporary restriction that the block size must be 4K. MKFS.jfs defaults +the block size to 4K. + + +JFS today: + + +- Utilities: + Function in drop 1 + - MKFS.JFS builds on 2.2.12 + - MKFS successfully formats a new partition for JFS + + Function and Fixes in drop 2 + - MKFS supports all parameters now + - MKFS has fixes from release pre-alpha 0.0.1 + mkfs.jfs results in segmentation fault if no arguments are specified + mkfs.jfs hangs on invocation + + - XPEEK, utility to PEEK and POKE JFS on-disk data/structures + + Function and Fixes in drop 5 + - MKFS.jfs has a fix to support -l option correctly. + + Function and Fixes in drop 6 + - libfs has compiler warning fixes and a bug fix + + Function in drop 8 + - fsck.jfs successfully checks and repairs a jfs partition + - logdump, utility that dumps the contents of the journal log. + + Function and Fixes in drop 9 + - fixes for fsck.jfs and xpeek have been done. + + Function and Fixes in drop 10 + - fixes for fsck.jfs + - man pages for utilities + - extendfs utility part has been ported (still need to port FS portion) + - compiler warnings have been removed. + + Function and Fixes in drop 11 + - defrag utility part has been ported (still need to port FS portion) + + Function and Fixes in drop 13 + - fsck.jfs supports block special files and character special files (Jitterbug problem #28) + + Function and Fixes in drop 15 + - ported xchklog utility, extracts a log from fsck. + + Function and Fixes in drop 16 + - fixes for fsck.jfs to handle case-sensitive support correctly (Jitterbug problem #36) + - cleanup changes for the utilities + + Function and Fixes in drop 18 + - cleanup changes for the utilities + + Function and Fixes in drop 21 + - fix in fsck to handle sparse files correctly + + Function and Fixes in drop 23 + - fix in fsck to handle fifo correctly + + Function and Fixes in drop 24 + - man pages updates for the utilities + - install option for utilities + + Function and Fixes in drop 26 + - man page updates for fsck + - fsck now supports default options passed by fstab correctly + + Function and Fixes in drop 27 + - new jfsprogs.spec file + - fix in fsck for hard links + - fix for unicode conversion problem + + Function and Fixes in drop 29 + - cleanup changes for the utilities + - Code cleanup to use standard types + + Function and Fixes in drop 30 + - added endian macros support + - Code cleanup to use standard types (part 2) + - mkfs now clears out the 1st 4k bytes of the partition + + Function and Fixes in drop 31 + - completed endian macros support needed for xpeek + - added socket support for fsck + - minor bug fixes + + Function and Fixes in drop 32 + - Remove the warning message from fsck when partition is mounted read-only + + Function and Fixes in drop 33 + - Fix fsck to handle mount read-only correctly + - Fix top level utilities makefile to be able to easily overide version of gcc compiler + - Man pages are now available in html format + + Function and Fixes in drop 34 + - fsck fix to handle pre-existing lost+found sub dir + + Function and Fixes in drop 35 + - updated fsck error handling + - updated mkfs config options and the man page for fsck + + Function and Fixes in drop 36 + - Fixed jitterbug # 10 rm -rf fails on a big directory + + Function and Fixes in drop 38 + - Fixed small logredo problem + + Function and Fixes in drop 39 (1.0.1) + - Updated jfsprogs.spec file make it work on more distros + - Add force option to mkfs so the confirmation message isn't displayed + - Fixed fsck to handle index table on the root directory. + - Fixed error message displayed when partition was just created and haven't rebooted (jitterbug 130) + - Correctly place the built utilities in /sbin vs. /usr/sbin when using the make install + option. + + Note: If you have used the make install option to copy over the utilities from a + previous release then you should remove the following JFS utilities (fsck.jfs, logdump, + logredo, mkfs.jfs, xchkdmp, xchklog, and xpeek) that could be in /usr/sbin. This release + of make install places the utilities in the correct location which is /sbin. + + Function and Fixes in drop 40 (1.0.2) + - Fixed mkfs to display the correct error message if device name is not valid + or missing + - gzip the man pages and place /usr/share/man/man8 + - Fixed mkfs to properly setup buf_ai (caused Bus error with mkfs on SPARC Linux) + - Fixed fsck to display path correctly + + Function and Fixes in drop 41 (1.0.3) + - Fixed compiler warnings on 64 bit systems + - Created jfsutils package + + Function and Fixes in drop 42 (1.0.4) + - Fixed typecast problem causing intermittent fsck failures on 64 bit hardware (jitterbug 159) + - Fixed pointer calculation problem causing intermittent fsck failures on 64 bit hardware + - Fixed compiler warnings on s/390 and IA64 + - Fixed structure size mismatch between file system and utilities causing fsck problems when + large numbers of inodes are used + - Fixed seg fault in fsck when logging path lengths greater than 512 characters + - Fixed fsck printf format errors + + +- JFS: + Function in drop 1 + - builds on 2.2.12 + - successfully MOUNTs & UMOUNTs + - limited READ capability (i.e. LS is operational) + - other system commands (i.e. DF, CHOWN, CHMOD, etc. working limited) + + Function and Fixes in drop 2 + - Write capabilities are operational + - MKDIR + - CREATE file + - RMDIR + - RM + - Problems fixed from release pre-alpha 0.0.1 + using 2.2.14 jfs_imap.c:3004: `event' undeclared (first use in this function) + + Function and Fixes in drop 3 + - WRITE a file + - READ a file + - Support for hard and soft links + + Function and Fixes in drop 4 + - MV + - Executables can now be started from a jfs partition + - Problems while writing files have been fixed + + Function and Fixes in drop 5 + - added support for special files (mknod) + - alpha changes have been included + + Function and Fixes in drop 6 + - Jitterbug problem 9 du output is incorrect on jfs + - Jitterbug problem 11 unresolved symbol jfs_rwlock_lock on SMP build + + Function and Fixes in drop 7 + - moved JFS upto the 2.3.x development kernel (2.3.99-pre6) + - Jitterbug problem 14 can't build JFS within the kernel + + Function and Fixes in drop 8 + - moved JFS upto the 2.4.0 development kernel (2.4.0-test1-ac21) + - Jitterbug problem 17 undefined: jfs_rdwrlock_lock + - PowerPC build problem + + Function and Fixes in drop 9 + - moved JFS upto the 2.4.0 development kernel (2.4.0-test3) + - moved meta-data from buffer cache to page cache + - fixes for the file system are included + + Function and Fixes in drop 10 + - moved JFS upto the 2.4.0 development kernel (2.4.0-test5) + - fixes for the file system are included + + Function and Fixes in drop 11 + - moved JFS upto the 2.4.0 development kernel (2.4.0-test7) + - fixes for the file system are included + - start of journaling code has been included (jfs_txnmgr.h) + - WIP of log manager (jfs_logmgr.c) + + Function and Fixes in drop 12 + - Transaction Manager Log I/O -> Write log records is functional + + Function and Fixes in drop 13 + - case-sensitive support has been added + + Function and Fixes in drop 14 + - JFS mount error 22 is fixed (Jitterbug problem #30) + + Function and Fixes in drop 15 + - Following Transaction Manager routines are functional + Initialize -> Initialize transaction manager + Begin -> Start a transaction + Locks -> Acquire/release locks + End -> End a transaction + - moved JFS upto the 2.4.0 development kernel (2.4.0-test9) + - Fixed 2.2.x series block write problem. + + Function and Fixes in drop 16 + - Following Transaction Manager routines are functional + Commit -> Commit the transaction + Buffer Management -> Update inode, directory, extent + Abort -> Stop the commit from occurring + - File System build problem on 2.2.x series of the kernel (Jitterbug #35) + - Fixed case-sensitive bug in the filesystem (Jitterbug #36) + + + Function and Fixes in drop 17 + - Added transaction sub operations back into the file system operations. + - The file system is now journaling appropriate file system operations. + - moved JFS upto the 2.4.0 development kernel (2.4.0-test10) + + Function and Fixes in drop 18 + - symlink fix + - inode corruption problem + + Function and Fixes in drop 19 + - Added asynchronous logging support back into the file system. + - moved JFS upto the 2.4.0 development kernel (2.4.0-test11) + - Fixes to transaction related hang problems. + + Function and Fixes in drop 20 + - Fix to remove memory on module cleanup + + Function and Fixes in drop 21 + - Fix so fsck doesn't report the message + Secondary file/directory allocation structure(2) is not a correct redundant copy of primary structure. + - Fix for setup of finish_aync_io + - moved JFS upto the 2.4.0 development kernel (2.4.0-test12) + - moved JFS upto the 2.2.18 kernel + + Function and Fixes in drop 22 + + - moved JFS upto the 2.4.0 kernel + - Fix to do transaction processing for mknod correctly + - Fix for spinlock.h needed on 2.2.18 ppc + + Function and Fixes in drop 23 + - Fix for undefined BUG() in 2.2.x series + - Fix for 2.2 kernels, struct pipe_inode_info overlays the file system dependent portion of the inode structure. + + Function and Fixes in drop 24 + - rmmod jfs fix + - Implemented "Lazy Commit" - asynchronous logging enhancement to increase performance + - Removed ino_t from on-disk structures (fixes a mount problem) + + Function and Fixes in drop 25 + - Fix for deadlocks by putting IWRITE_LOCK/UNLOCK within jfs_delete_inode + - Fix to handle removing a link to an inode that isn't the last link. + - Fixes to general transaction processing SMP related hangs. + + Function and Fixes in drop 26 + - Fix for file writes on 2.2.x series of the kernel + - Change to log pages, so they no longer use the page cache. + - Fixes to general transaction processing SMP related dead-lock problems + + Function and Fixes in drop 27 + - Report error on read_metapage failure in jfs_readlink + - Report correct error in jfs_lookup if VFS fails to locate the inode + - Fix for a buffer overrun problem in jfs_readlink when compiled for linux-2.2 + - Fix to support fsync call correctly (jitterbug #57) + - Fixes to general SMP related dead-lock problems + - Fix to define BUG() if 2.2 and !i386 + - Fixes to general UP related hangs + - Changes to handling the inode extent cache increase the performance of the file system + + Function and Fixes in drop 28 + - Added ifdef IS_KIOBUFIO so JFS will be if kiobufs is in the kernel. Kiobufs has changed + the # of parameters for generic_make_request() + - Make jfsFYI a module parameter + insmod jfs.o jfsFYI=1 will turn on JFS FYI messages without having to recompile this + option is only supported on the 2.4.x kernel level. + - Defines cleanup_module() in terms of exit_jfs_fs() + - Fix to jfs_read_super, if get_empty_inode returns NULL cleanup correctly + - Code cleanup to use standard types + + + Function and Fixes in drop 29 + - Fix for assert(iagp->wmap[extno] & mask); (line #2875) in jfs_imap while running dbench + - Fixed hang on scsi + - added /proc/fs/jfs/jfsFYI (2.4.* kernels only) + echo 1 > /proc/fs/jfs/jfsFYI ; Turns on very verbose output to syslog + echo 0 > /proc/fs/jfs/jfsFYI ; Turns it back off + + Notes: + - IMPORTANT: If building jfs.o as a module on 2.2.* kernels, you will have to rebuild and + install the kernel to add wake_up_process to ksyms.c. Not needed on 2.4.* kernels. + + Function and Fixes in drop 30 + - Added endian macros support + - Fixed dbench hang + - jfs fails SPEC SFS validation on both NFSv2/NFSv3, fix to not add null-terminator to the symlink + value and accounting for it in the size. + - Fixed a bug where a casting of a 32 bit block # wasn't correct when a 64 bit value is needed. + xtLookup messages where display in the /var/log/messages (i.e of a message is below) + xtLookup: lstart (0x80000) >= size (0x80000) + + Notes: release 0.3.0 requires a re-format of the JFS partition, if the system architecture is + big-endian (i.e. s/390, PowerPC, etc.) + + Function and Fixes in drop 31 + - Removed max hard links check (showed up during cp -a /usr /jfs/usr) + - Fixed inode writing hang could have showed up running (dbench, iozone, etc), + the change was to prevent a deadlock during inode writing. + + Function and Fixes in drop 32 + - Fix for assert(mp->count) jfs_metapage.c 675! report as hardlink problem in drop 31 (dtDeleteUp + was discarding the wrong metapage_t. + - Fix seg fault problem while creating hard links. + - Fixed dbench hang do to transaction locks not being freed. + - Added support to correctly handle read-only and remounting the file system. + + Function and Fixes in drop 33 + + - Fixed statfs call to return the maximum number of inodes that JFS could allocate. (problem + reported as rpm exits with a (x) inodes needed message without installing the package). + - Fix to handle a case where a inode wasn't getting written to disk. + - Increase the performance of unlinking files. + - Fix to null terminate symlinks. + - General SMP fixes. + + Function and Fixes in drop 34 + + - Fixed to remove a hang waiting on inode (jitterbug #73) + - Fixed dbench hang on SMP 8-way + - Fixed a log sync problem, improved performance with this fix + + Function and Fixes in drop 35 + - Increase the performance of unlinking files, most unlinks are done asynchronously now + - Fixed "XT_GETPAGE: xtree page corrupt" during creating files on nfs mounted partition + + Function and Fixes in drop 36 + - Fixed jitterbug # 10 rm -rf fails on a big directory + + Notes: release 0.3.6 requires a re-format of the JFS partition, for the rm -rf problem + to be fixed. + + Function and Fixes in drop 37 + - Fixed find_entry called with index = 0 or 1 (jitterbug #126) + - Fixed the rm -rf case where if files weren't created sequential + then the rm -rf wasn't working correctly + + + Notes: If you used release 0.3.6 please re-format all JFS partitions, for the rm -rf problem + to be fixed. + + Function and Fixes in drop 38 + - Fixed some general log problems + + Function and Fixes in drop 39 (1.0.1) + - Fixed hang during copying files on 2.2.x series + - Fixed TxLock compile problem + - Fixed to correctly update the number of blocks for directories (this was causing the FS + to show fsck error after compiling mozilla). + - Fixed to prevent old data from being written to disk from the page cache. + + Function and Fixes in drop40 (1.0.2) + - Fixed multiple truncate hang + - Fixed hang on unlink a file and sync happening at the same time + - Improved handling of kmalloc error conditions + - Fixed hang in blk_get_queue and SMP deadlock: bh_end_io call generic_make_request + (jitterbug 145 and 146) + - stbl was not set correctly set in dtDelete + - changed trap to printk in dbAllocAG to avoid system hang + + Function and Fixes in drop41 (1.0.3) + - Patch to move from previous release to latest release needs to update the version number in super.c + - Jitterbug problems (134,140,152) removing files have been fixed + - Set rc=ENOSPC if ialloc fails in jfs_create and jfs_mkdir + - Fixed jfs_txnmgr.c 775! assert + - Fixed jfs_txnmgr.c 884! assert(mp->nohomeok==0) + - Fix hang - prevent tblocks from being exhausted + - Fix oops trying to mount reiserfs + - Fail more gracefully in jfs_imap.c + - Print more information when char2uni fails + - Fix timing problem between Block map and metapage cache - jitterbug 139 + - Code Cleanup (removed many ifdef's, obsolete code, ran code through indent) Mostly 2.4 tree + - Split source tree (Now have a separate source tree for 2.2, 2.4, and jfsutils) + + Function and Fixes in drop42 (1.0.4) + - Fixed compiler warnings in the FS when building on 64 bits systems + - Fixed deadlock where jfsCommit hung in hold_metapage + - Fixed problems with remount + - Reserve metapages for jfsCommit thread + - Get rid of buggy invalidate_metapage & use discard_metapage + - Don't hand metapages to jfsIOthread (too many context switches) (jitterbug 125, bugzilla 238) + - Fix error message in jfs_strtoUCS + + +Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com. + +The JFS mailing list can be subscribed to by using the link labeled "Mail list Subscribe" +at our web page http://oss.software.ibm.com/jfs/. diff -uNr --exclude=CVS linux-2.4.9-ac10/Documentation/filesystems/jfs.txt linuxppc64_2_4/Documentation/filesystems/jfs.txt --- linux-2.4.9-ac10/Documentation/filesystems/jfs.txt Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/Documentation/filesystems/jfs.txt Thu Sep 13 14:29:38 2001 @@ -0,0 +1,153 @@ +IBM's Journaled File System (JFS) for Linux version 1.0.4 +Team members +Steve Best sbest@us.ibm.com +Dave Kleikamp shaggy@us.ibm.com +Barry Arndt barndt@us.ibm.com + + +Release August 31, 2001 (version 1.0.4) + +This is our forty-second release of IBM's Enterprise JFS technology port to Linux. +Beta 1 was release 0.1.0 on 12/8/2000, Beta 2 was release 0.2.0 on 3/7/2001, +Beta 3 was release 0.3.0 on 4/30/2001, and release 1.0.0 on 6/28/2001. + +The changelog.jfs file contains detailed information of changes done in each source +code drop. + +JFS has a source tree that can be built on 2.2.14 - 2.2.19 and 2.4.0 - 2.4.9 +kernel.org source trees. + +There is a anonymous cvs access available for the JFS tree. The steps below are +what is needed to pull the JFS cvs tree from the oss.software.ibm.com server. + +id anoncvs +password anoncvs + +To checkout 2.2.x series of the JFS files do the following: +CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs +cvs checkout linux-2.2.12 + +To checkout 2.4.x series of the JFS files do the following: +CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs +cvs checkout linux24 + +To checkout the JFS utilities do the following: +CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs +cvs checkout jfsutils + +The jfs-2.4-1.0.4-patch.tar.gz file contains a readme and patch files for different +levels of the 2.4 kernel. Please see the README in the jfs-2.4-1.0.4-patch.tar.gz +file for help on applying the two patch files. + +Similarly jfs-2.2-1.0.4-patch.tar.gz contains a readme and patch files for +different levels of the 2.2 kernel. + +The following files in the kernel source tree have been changed so JFS can be built. +The jfs-2.4-1.0.4.tar.gz source tar ball now contains each of the files below with +the extension of the kernel level it is associated with. As an example, there are now +three Config.in files named Config.in-2.4.0, Config.in-2.4.5, and Config.in-2.4.7. + +Similarly, the jfs-2.2-1.0.4.tar.gz source tar ball contains the files +Config.in-2.2.14, Config.in-2.2.16, and Config.in-2.2.18. + +If you use the tar ball to build JFS you must rename each of the kernel files to the +file names listed below. The standard kernel from www.kernel.org is the source of the +kernel files that are included in the jfs tar files. + +In sub dir fs Config.in, Makefile, filesystem.c +In sub dir fs/nls Config.in +In sub dir arch/i386 defconfig +In sub dir Documentation Configure.help +In sub dir Documentation/filesystems 00-INDEX +In sub dir include/linux fs.h +In sub dir linux MAINTAINERS +In sub dir linux/kernel/ksyms.c + +Please backup the above files before the JFS patch file is added to the kernel source +tree. There are three new header files in the sub dir include/linux named jfs_fs.h, +jfs_fs_i.h,and jfs_fs_sb.h. All other JFS files are located in the include/linux/jfs +or fs/jfs sub dirs. + +Our development team has used the Linux kernel levels 2.2.14-2.2.19 and +2.4.0 - 2.4.9 kernels with gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) +for our port so far. A goal of the JFS team is to have JFS run on all architectures +that Linux supports, there is no architecture specific code in JFS. JFS has been run +on the following architectures (x86, PowerPC, Alpha, s/390, ARM) so far. + +To make JFS build, during the "make config" step of building the kernel answer y to +the Prompt for development and/or incomplete code/drivers in the Code maturity level +options section. In the Filesystems section use the m for the answer to +JFS filesystem support (experimental) (CONFIG_JFS_FS) [Y/m/n?] + +Note: If you are use JFS as module on the 2.2.x series of the kernel you must rebuild +the kernel and run that rebuilt kernel for JFS to run. The reason for this change is +that JFS needs to export symbols. + +Build in /usr/src/linux with the command: + + +make modules +make modules_install + +If you rebuild jfs.o after having mounted and unmounted a partition, "modprobe -r jfs" +will unload the old module. + +For the file system debugging messages are being written to /var/log/messages. + +There are two ways to the build the JFS utilities, the first using the jfsprogs.spec +file and the second way is to run make and then make install in the +/jfsutils sub dir. + +To use the jfsprogs.spec located in sub dir jfsutils/SPECS you need to update +the version of JFS in the spec file, also the corresponding jfs-x.x.x-patch.tar.gz file +must be in the SOURCES directory of your system. Now it's time to begin the build. First, +change into the directory holding jfsprogs.spec file: + +cd /jfsutils/SPECS + +Next, start the build with a rpm -b command: + +rpm -ba jfsprogs.spec + +The a following the -b option directs RPM to perform all phases of the build process. + + +The second way to build the utilities for JFS (mkfs, xpeek, logredo, xchkdmp, fsck, logdump, xchklog). + +Build in /jfsutils with the command: + +make +make install + +One of results of this build is a program called mkfs.jfs. +To format a JFS partition use the following command. + + mkfs -t jfs device-name + +will result in the specified device being formatted. + + + +JFS TODO list: + +Plans for our near term development items + + - Fix for 2.2.* SMP kernel hangs + - get defrag capabilities operational in the FS + - get extendfs capabilities operational in the FS + - test EXTENDFS utility, for growing JFS partitions + - test defrag utility, calls file system to defrag the file system. + - add support for block sizes (512,1024,2048) + - add support for logfile on dedicated partition + + +Longer term work items + + - get access control list functionality operational + - get extended attributes functionality operational + - add quota support + +Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com. + +The JFS mailing list can be subscribed to by using the link labeled "Mail list Subscribe" +at our web page http://oss.software.ibm.com/jfs/. diff -uNr --exclude=CVS linux-2.4.9-ac10/MAINTAINERS linuxppc64_2_4/MAINTAINERS --- linux-2.4.9-ac10/MAINTAINERS Mon Sep 10 11:58:10 2001 +++ linuxppc64_2_4/MAINTAINERS Thu Sep 13 14:29:38 2001 @@ -794,6 +794,13 @@ W: http://sources.redhat.com/jffs2/ S: Maintained +JFS FILESYSTEM +P: Dave Kleikamp +M: shaggy@austin.ibm.com +L: jfs-discussion@oss.software.ibm.com +W: http://oss.software.ibm.com/developerworks/opensource/jfs/ +S: Supported + JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@suse.cz diff -uNr --exclude=CVS linux-2.4.9-ac10/Makefile linuxppc64_2_4/Makefile --- linux-2.4.9-ac10/Makefile Mon Sep 10 11:58:10 2001 +++ linuxppc64_2_4/Makefile Mon Sep 10 10:53:31 2001 @@ -10,11 +10,13 @@ # SUBARCH tells the usermode build what the underlying arch is. That is set # first, and if a usermode build is happening, the "ARCH=um" on the command # line overrides the setting of ARCH below. If a native build is happening, -# then ARCH is assigned, getting whatever value it gets normally, and +# then ARCH is assigned, getting whatever value it gets normally, and # SUBARCH is subsequently ignored. SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) -ARCH := $(SUBARCH) +#ARCH := $(SUBARCH) + +ARCH := ppc64 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ @@ -27,7 +29,7 @@ HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -CROSS_COMPILE = +CROSS_COMPILE = /usr/local/ppc64-current3.0/bin/powerpc64-linux- # # Include the make variables (CC, etc...) @@ -97,7 +99,7 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH) CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ - -fomit-frame-pointer -fno-strict-aliasing -fno-common + -fomit-frame-pointer -fno-strict-aliasing -fno-common AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) # diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/i386/defconfig linuxppc64_2_4/arch/i386/defconfig --- linux-2.4.9-ac10/arch/i386/defconfig Thu Sep 6 14:04:16 2001 +++ linuxppc64_2_4/arch/i386/defconfig Thu Sep 13 14:29:38 2001 @@ -598,6 +598,7 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_JFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/Makefile linuxppc64_2_4/arch/ppc64/Makefile --- linux-2.4.9-ac10/arch/ppc64/Makefile Thu Sep 6 14:05:09 2001 +++ linuxppc64_2_4/arch/ppc64/Makefile Fri Sep 14 10:19:30 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) @@ -67,15 +73,9 @@ @$(MAKEBOOT) $@ endif -.PHONY: clean_config -clean_config: +%_config: arch/ppc64/configs/%_defconfig rm -f .config arch/ppc64/defconfig - -chrp_config: clean_config - cp -f arch/ppc64/configs/chrp_defconfig arch/ppc64/defconfig - -common_config: clean_config - cp -f arch/ppc64/configs/common_defconfig arch/ppc64/defconfig + cp -f arch/ppc64/configs/$(@:config=defconfig) arch/ppc64/defconfig archclean: rm -f arch/ppc64/kernel/{ppc_defs.h,checks,mk_defs.s,mk_defs_out.c,mk_defs_tpl} diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/boot/Makefile linuxppc64_2_4/arch/ppc64/boot/Makefile --- linux-2.4.9-ac10/arch/ppc64/boot/Makefile Thu Sep 6 14:05:09 2001 +++ linuxppc64_2_4/arch/ppc64/boot/Makefile Thu Sep 13 14:13:35 2001 @@ -29,7 +29,7 @@ $(BOOTCC) $(BOOTAFLAGS) -traditional -c -o $*.o $< CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS -LD_ARGS = -Ttext 0x00400000 +LD_ARGS = -Ttext 0x00400000 -e _start OBJS = crt0.o start.o main.o zlib.o image.o imagesize.o #LIBS = $(TOPDIR)/lib/lib.a @@ -84,7 +84,7 @@ imagesize.c: vmlinux.gz clean: - rm -f piggyback note addnote $(OBJS) zImage vmlinux.gz no_initrd.o + rm -f piggyback note addnote $(OBJS) zImage zImage.initrd vmlinux.gz no_initrd.o imagesize.c fastdep: $(TOPDIR)/scripts/mkdep *.[Sch] > .depend diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/boot/crt0.S linuxppc64_2_4/arch/ppc64/boot/crt0.S --- linux-2.4.9-ac10/arch/ppc64/boot/crt0.S Thu Sep 6 14:05:09 2001 +++ linuxppc64_2_4/arch/ppc64/boot/crt0.S Thu Sep 13 14:13:35 2001 @@ -22,28 +22,28 @@ sync isync - ## Clear out the BSS as per ANSI C requirements + ## Clear out the BSS as per ANSI C requirements - lis 7,_end@ha - addi 7,7,_end@l # r7 = &_end - lis 8,__bss_start@ha # - addi 8,8,__bss_start@l # r8 = &_bss_start + lis 7,_end@ha + addi 7,7,_end@l # r7 = &_end + lis 8,__bss_start@ha # + addi 8,8,__bss_start@l # r8 = &_bss_start - ## Determine how large an area, in number of words, to clear - - subf 7,8,7 # r7 = &_end - &_bss_start + 1 - addi 7,7,3 # r7 += 3 - srwi. 7,7,2 # r7 = size in words. - beq 3f # If the size is zero, do not bother - addi 8,8,-4 # r8 -= 4 - mtctr 7 # SPRN_CTR = number of words to clear - li 0,0 # r0 = 0 -2: stwu 0,4(8) # Clear out a word - bdnz 2b # If we are not done yet, keep clearing + ## Determine how large an area, in number of words, to clear + + subf 7,8,7 # r7 = &_end - &_bss_start + 1 + addi 7,7,3 # r7 += 3 + srwi. 7,7,2 # r7 = size in words. + beq 3f # If the size is zero, do not bother + addi 8,8,-4 # r8 -= 4 + mtctr 7 # SPRN_CTR = number of words to clear + li 0,0 # r0 = 0 +2: stwu 0,4(8) # Clear out a word + bdnz 2b # If we are not done yet, keep clearing 3: - b start + b start diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/boot/main.c linuxppc64_2_4/arch/ppc64/boot/main.c --- linux-2.4.9-ac10/arch/ppc64/boot/main.c Thu Sep 6 14:05:09 2001 +++ linuxppc64_2_4/arch/ppc64/boot/main.c Thu Sep 13 14:13:35 2001 @@ -10,12 +10,11 @@ */ #define __KERNEL__ #include "zlib.h" -#include #include #include +#include #include -#define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1))) extern void *finddevice(const char *); extern int getprop(void *, const char *, void *, int); @@ -25,16 +24,15 @@ void *claim(unsigned int, unsigned int, unsigned int); void flush_cache(void *, int); void pause(void); +static struct bi_record *make_bi_recs(unsigned long); #define RAM_START 0x00000000 #define RAM_END (64<<20) #define BOOT_START ((unsigned long)_start) -#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) - -#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) +#define BOOT_END ((unsigned long)_end) -// Value picked to match that used by yaboot +/* Value picked to match that used by yaboot */ #define PROG_START 0x01400000 char *avail_ram; @@ -42,6 +40,8 @@ char *avail_high; unsigned int heap_use; unsigned int heap_max; +unsigned long initrd_start = 0; +unsigned long initrd_size = 0; extern char _end[]; extern char image_data[]; @@ -54,32 +54,37 @@ static char scratch[128<<10]; /* 128kB of scratch space for gunzip */ +typedef void (*kernel_entry_t)( unsigned long, + unsigned long, + void *, + struct bi_record *); + void -chrpboot(int a1, int a2, void *prom) +chrpboot(unsigned long a1, unsigned long a2, void *prom) { - unsigned sa, len; - void *dst, *claim_addr; + unsigned len; + void *dst = (void *)-1; + unsigned long claim_addr; unsigned char *im; - unsigned initrd_start, initrd_size; extern char _start; + struct bi_record *bi_recs; + kernel_entry_t kernel_entry; printf("chrpboot starting: loaded at 0x%x\n\r", (unsigned)&_start); - printf(" initrd_len = 0x%x\n\r", (unsigned)initrd_len); if (initrd_len) { initrd_size = initrd_len; initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; + a1 = a2 = 0; claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", - initrd_start, (unsigned)initrd_data, initrd_size); + printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", + initrd_start, (unsigned long)initrd_data, initrd_size); memcpy((void *)initrd_start, (void *)initrd_data, initrd_size); } im = image_data; len = image_len; - uncompressed_size = _ALIGN(uncompressed_size, (1<<12)); /* page align it */ + uncompressed_size = PAGE_ALIGN(uncompressed_size); for(claim_addr = PROG_START; claim_addr <= PROG_START * 8; @@ -108,48 +113,72 @@ } flush_cache(dst, len); - make_bi_recs((unsigned long)dst + len); - sa = (unsigned long)dst; - printf("start address = 0x%x\n\r", (unsigned) sa); + bi_recs = make_bi_recs((unsigned long)dst + len); + + kernel_entry = (kernel_entry_t)dst; + printf( "kernel:\n\r" + " entry addr = 0x%lx\n\r" + " a1 = 0x%lx,\n\r" + " a2 = 0x%lx,\n\r" + " prom = 0x%lx,\n\r" + " bi_recs = 0x%lx,\n\r", + (unsigned long)kernel_entry, a1, a2, + (unsigned long)prom, (unsigned long)bi_recs); - (*(void (*)(int, int, void *))sa)(a1, a2, prom); + kernel_entry( a1, a2, prom, bi_recs ); printf("returned?\n\r"); pause(); } -void make_bi_recs(unsigned long addr) +static struct bi_record * +make_bi_recs(unsigned long addr) { + struct bi_record *bi_recs; struct bi_record *rec; - - rec = (struct bi_record *)_ALIGN(addr + (1<<20) -1, (1<<20)); + bi_recs = rec = bi_rec_init(addr); + + rec = bi_rec_alloc(rec, 1); rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - + /* rec->data[0] = ...; # Written below before return */ + + rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1); rec->tag = BI_BOOTLOADER_ID; sprintf( (char *)rec->data, "chrpboot"); - rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - + + rec = bi_rec_alloc(rec, 2); 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); + + if ( initrd_size > 0 ) { + rec = bi_rec_alloc(rec, 2); + rec->tag = BI_INITRD; + rec->data[0] = initrd_start; + rec->data[1] = initrd_size; + } + #if 0 - rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)sysmap_data; - rec->data[1] = sysmap_len; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); + if ( sysmap_len > 0 ) { + rec = bi_rec_alloc(rec, 2); + rec->tag = BI_SYSMAP; + rec->data[0] = (unsigned long)sysmap_data; + rec->data[1] = sysmap_len; + } #endif + + rec = bi_rec_alloc(rec, 0); rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); + + /* Save the _end_ address of the bi_rec's in the first bi_rec + * data field for easy access by the kernel. + */ + bi_recs->data[0] = (bi_rec_field)rec + rec->size; + + return bi_recs; } struct memchunk { @@ -212,47 +241,48 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) { - z_stream s; - int r, i, flags; + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); + } - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n\r"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n\r"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n\r", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n\r", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); } + diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/boot/start.c linuxppc64_2_4/arch/ppc64/boot/start.c --- linux-2.4.9-ac10/arch/ppc64/boot/start.c Thu Sep 6 14:05:09 2001 +++ linuxppc64_2_4/arch/ppc64/boot/start.c Thu Sep 13 14:13:35 2001 @@ -30,200 +30,200 @@ void start(int a1, int a2, void *promptr) { - prom = (int (*)(void *)) promptr; - chosen_handle = finddevice("/chosen"); - if (chosen_handle == (void *) -1) - exit(); - if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) - exit(); - stderr = stdout; - if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) + prom = (int (*)(void *)) promptr; + chosen_handle = finddevice("/chosen"); + if (chosen_handle == (void *) -1) + exit(); + if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) + exit(); + stderr = stdout; + if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) exit(); - chrpboot(a1, a2, promptr); - for (;;) - exit(); + chrpboot(a1, a2, promptr); + for (;;) + exit(); } int write(void *handle, void *ptr, int nb) { - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "write"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "write"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; } int read(void *handle, void *ptr, int nb) { - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "read"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "read"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; } void exit() { - struct prom_args { - char *service; - } args; + struct prom_args { + char *service; + } args; - for (;;) { - args.service = "exit"; - (*prom)(&args); - } + for (;;) { + args.service = "exit"; + (*prom)(&args); + } } void pause(void) { - struct prom_args { - char *service; - } args; + struct prom_args { + char *service; + } args; - args.service = "enter"; - (*prom)(&args); + args.service = "enter"; + (*prom)(&args); } void * finddevice(const char *name) { - struct prom_args { - char *service; - int nargs; - int nret; - const char *devspec; - void *phandle; - } args; - - args.service = "finddevice"; - args.nargs = 1; - args.nret = 1; - args.devspec = name; - args.phandle = (void *) -1; - (*prom)(&args); - return args.phandle; + struct prom_args { + char *service; + int nargs; + int nret; + const char *devspec; + void *phandle; + } args; + + args.service = "finddevice"; + args.nargs = 1; + args.nret = 1; + args.devspec = name; + args.phandle = (void *) -1; + (*prom)(&args); + return args.phandle; } void * -claim(unsigned int virt, unsigned int size, unsigned int align) +claim(unsigned long virt, unsigned long size, unsigned long align) { - struct prom_args { - char *service; - int nargs; - int nret; - unsigned int virt; - unsigned int size; - unsigned int align; - void *ret; - } args; - - args.service = "claim"; - args.nargs = 3; - args.nret = 1; - args.virt = virt; - args.size = size; - args.align = align; - (*prom)(&args); - return args.ret; + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; } int getprop(void *phandle, const char *name, void *buf, int buflen) { - struct prom_args { - char *service; - int nargs; - int nret; - void *phandle; - const char *name; - void *buf; - int buflen; - int size; - } args; - - args.service = "getprop"; - args.nargs = 4; - args.nret = 1; - args.phandle = phandle; - args.name = name; - args.buf = buf; - args.buflen = buflen; - args.size = -1; - (*prom)(&args); - return args.size; + struct prom_args { + char *service; + int nargs; + int nret; + void *phandle; + const char *name; + void *buf; + int buflen; + int size; + } args; + + args.service = "getprop"; + args.nargs = 4; + args.nret = 1; + args.phandle = phandle; + args.name = name; + args.buf = buf; + args.buflen = buflen; + args.size = -1; + (*prom)(&args); + return args.size; } int putc(int c, void *f) { - char ch = c; + char ch = c; - if (c == '\n') - putc('\r', f); - return write(f, &ch, 1) == 1? c: -1; + if (c == '\n') + putc('\r', f); + return write(f, &ch, 1) == 1? c: -1; } int putchar(int c) { - return putc(c, stdout); + return putc(c, stdout); } int fputs(char *str, void *f) { - int n = strlen(str); + int n = strlen(str); - return write(f, str, n) == n? 0: -1; + return write(f, str, n) == n? 0: -1; } int readchar(void) { - char ch; + char ch; - for (;;) { - switch (read(stdin, &ch, 1)) { - case 1: - return ch; - case -1: - printk("read(stdin) returned -1\r\n"); - return -1; + for (;;) { + switch (read(stdin, &ch, 1)) { + case 1: + return ch; + case -1: + printk("read(stdin) returned -1\r\n"); + return -1; + } } - } } static char line[256]; @@ -233,53 +233,53 @@ int getchar(void) { - int c; + int c; - if (lineleft == 0) { - lineptr = line; - for (;;) { - c = readchar(); - if (c == -1 || c == 4) - break; - if (c == '\r' || c == '\n') { - *lineptr++ = '\n'; - putchar('\n'); - break; - } - switch (c) { - case 0177: - case '\b': - if (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - case 'U' & 0x1F: - while (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - default: - if (lineptr >= &line[sizeof(line) - 1]) - putchar('\a'); - else { - putchar(c); - *lineptr++ = c; + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + putchar('\a'); + else { + putchar(c); + *lineptr++ = c; + } + } } - } + lineleft = lineptr - line; + lineptr = line; } - lineleft = lineptr - line; - lineptr = line; - } - if (lineleft == 0) - return -1; - --lineleft; - return *lineptr++; + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; } diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/boot/zImage.lds linuxppc64_2_4/arch/ppc64/boot/zImage.lds --- linux-2.4.9-ac10/arch/ppc64/boot/zImage.lds Thu Sep 6 14:05:09 2001 +++ linuxppc64_2_4/arch/ppc64/boot/zImage.lds Tue Sep 11 08:57:14 2001 @@ -33,6 +33,7 @@ *(.fixup) *(.got1) } + . = ALIGN(4096); _etext = .; PROVIDE (etext = .); .rodata : @@ -45,7 +46,7 @@ .ctors : { *(.ctors) } .dtors : { *(.dtors) } /* Read-write section, merged into data segment: */ - . = (. + 0x0FFF) & 0xFFFFF000; + . = ALIGN(4096); .data : { *(.data) @@ -56,11 +57,13 @@ *(.dynamic) CONSTRUCTORS } + . = ALIGN(4096); _edata = .; PROVIDE (edata = .); .fixup : { *(.fixup) } + . = ALIGN(4096); __bss_start = .; .bss : { @@ -69,6 +72,7 @@ *(.bss) *(COMMON) } + . = ALIGN(4096); _end = . ; PROVIDE (end = .); } diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig linuxppc64_2_4/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig --- linux-2.4.9-ac10/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-2.4.9-ac10/arch/ppc64/configs/pSeries_defconfig linuxppc64_2_4/arch/ppc64/configs/pSeries_defconfig --- linux-2.4.9-ac10/arch/ppc64/configs/pSeries_defconfig Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/configs/pSeries_defconfig Fri Sep 14 10:19:31 2001 @@ -26,6 +26,9 @@ # Loadable module support # CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + # # General setup diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/defconfig linuxppc64_2_4/arch/ppc64/defconfig --- linux-2.4.9-ac10/arch/ppc64/defconfig Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/ItLpQueue.c linuxppc64_2_4/arch/ppc64/kernel/ItLpQueue.c --- linux-2.4.9-ac10/arch/ppc64/kernel/ItLpQueue.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/ItLpQueue.c Fri Sep 14 10:03:28 2001 @@ -10,14 +10,42 @@ #include #include +#include #include #include #include #include #include +static __inline__ int set_inUse( struct ItLpQueue * lpQueue ) +{ + int t; + u32 * inUseP = &(lpQueue->xInUseWord); + + __asm__ __volatile__("\n\ +1: lwarx %0,0,%2 \n\ + cmpi 0,%0,0 \n\ + li %0,0 \n\ + bne- 2f \n\ + addi %0,%0,1 \n\ + stwcx. %0,0,%2 \n\ + bne- 1b \n\ +2: eieio" + : "=&r" (t), "=m" (lpQueue->xInUseWord) + : "r" (inUseP), "m" (lpQueue->xInUseWord) + : "cc"); + + return t; +} + +static __inline__ void clear_inUse( struct ItLpQueue * lpQueue ) +{ + lpQueue->xInUseWord = 0; +} + /* Array of LpEvent handler functions */ extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; +unsigned long ItLpQueueInProcess = 0; struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue ) { @@ -72,11 +100,24 @@ event->xFlags.xValid = 0; } +unsigned lpQueue_proc_count[32] = {}; + unsigned ItLpQueue_process( struct ItLpQueue * lpQueue, struct pt_regs *regs ) { unsigned numIntsProcessed = 0; struct HvLpEvent * nextLpEvent; + + /* If we have recursed, just return */ + if ( !set_inUse( lpQueue ) ) + return 0; + if (ItLpQueueInProcess == 0) + ItLpQueueInProcess = 1; + else + BUG(); + + ++lpQueue_proc_count[current->processor]; + for (;;) { nextLpEvent = ItLpQueue_getNextLpEvent( lpQueue ); if ( nextLpEvent ) { @@ -119,5 +160,10 @@ else /* If nothing left then we are done */ break; } + + ItLpQueueInProcess = 0; + mb(); + clear_inUse( lpQueue ); + return numIntsProcessed; } diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/Makefile linuxppc64_2_4/arch/ppc64/kernel/Makefile --- linux-2.4.9-ac10/arch/ppc64/kernel/Makefile Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/Makefile Mon Sep 10 13:54:26 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-2.4.9-ac10/arch/ppc64/kernel/XmPciLpEvent.c linuxppc64_2_4/arch/ppc64/kernel/XmPciLpEvent.c --- linux-2.4.9-ac10/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-2.4.9-ac10/arch/ppc64/kernel/align.c linuxppc64_2_4/arch/ppc64/kernel/align.c --- linux-2.4.9-ac10/arch/ppc64/kernel/align.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/align.c Fri Sep 14 07:41:02 2001 @@ -252,11 +252,6 @@ } flags = aligninfo[instr].flags; - - /* For the 4xx-family processors, the 'dar' field of the - * pt_regs structure is overloaded and is really from the DEAR. - */ - addr = (unsigned char *)regs->dar; /* Verify the address of the operand */ diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/chrp_setup.c linuxppc64_2_4/arch/ppc64/kernel/chrp_setup.c --- linux-2.4.9-ac10/arch/ppc64/kernel/chrp_setup.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/chrp_setup.c Thu Sep 13 14:13:35 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,10 +251,49 @@ ppc_md.progress(UTS_RELEASE, 0x7777); } + +/* Early initialization. Relocation is on but do not reference unbolted pages */ +void __init pSeries_init_early(void) +{ +#ifdef CONFIG_PPC_PSERIES /* This ifdef should go away */ + void *comport; + + htpe_init_pSeries(); + tce_init_pSeries(); + pSeries_pcibios_init_early(); + +#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; +#endif +} + void __init chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { +#if 0 /* PPPBBB remove this later... -Peter */ #ifdef CONFIG_BLK_DEV_INITRD /* take care of initrd if we have one */ if ( r6 ) @@ -266,8 +302,7 @@ initrd_end = __va(r6 + r7); } #endif /* CONFIG_BLK_DEV_INITRD */ - - /* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */ +#endif ppc_md.ppc_machine = _machine; @@ -303,20 +338,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 +353,7 @@ ppc_ide_md.io_base = _IO_BASE; #endif + ppc_md.progress("Linux ppc64\n", 0x0); } @@ -343,12 +365,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 +407,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-2.4.9-ac10/arch/ppc64/kernel/entry.S linuxppc64_2_4/arch/ppc64/kernel/entry.S --- linux-2.4.9-ac10/arch/ppc64/kernel/entry.S Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/entry.S Thu Sep 13 11:54:36 2001 @@ -32,6 +32,10 @@ #include #include +#ifdef CONFIG_PPC_ISERIES +#define DO_SOFT_DISABLE +#endif + #undef SHOW_SYSCALLS #undef SHOW_SYSCALLS_TASK @@ -324,19 +328,19 @@ _GLOBAL(ret_from_except) #ifdef CONFIG_PPC_ISERIES - ld r5,_MSR(r1) - andi. r5,r5,MSR_EE + ld r5,SOFTE(r1) + cmpdi 0,r5,0 beq 4f irq_recheck: - mfmsr r5 - andi. r5,r5,MSR_EE - bne 4f /* * Check for pending interrupts (iSeries) */ - CHECKANYINT(r4,r5) + CHECKANYINT(r3,r4) beq+ 4f /* skip do_IRQ if no interrupts */ + mfspr r5,SPRG3 + li r3,0 + stb r3,PACAPROCENABLED(r5) /* ensure we are disabled */ addi r3,r1,STACK_FRAME_OVERHEAD bl .do_IRQ b irq_recheck /* loop back and handle more */ @@ -386,23 +390,31 @@ rldicl r0,r0,16,0 /* clear MSR_EE */ mtmsrd r0 /* Update machine state */ #ifdef CONFIG_PPC_ISERIES - ld r0,_MSR(r1) - andi. r3,r0,MSR_EE + ld r0,SOFTE(r1) + cmpi 0,r0,0 beq+ 1f CHECKANYINT(r4,r3) - bne- irq_recheck + beq+ 1f + mfmsr r0 + ori r0,r0,MSR_EE + mtmsr r0 + b irq_recheck 1: #endif stdcx. r0,0,r1 /* to clear the reservation */ + mfspr r4,SPRG3 /* current task's PACA */ +#ifdef DO_SOFT_DISABLE + ld r0,SOFTE(r1) + stb r0,PACAPROCENABLED(r4) +#endif /* if returning to user mode, save kernel SP */ ld r0,_MSR(r1) andi. r0,r0,MSR_PR beq+ 1f addi r0,r1,INT_FRAME_SIZE /* size of frame */ - mfspr r4,SPRG3 /* current task's PACA */ ld r2,PACACURRENT(r4) /* Get 'current' */ std r0,THREAD+KSP(r2) /* save kernel stack pointer */ std r1,PACAKSAVE(r4) /* save exception stack pointer */ diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/head.S linuxppc64_2_4/arch/ppc64/kernel/head.S --- linux-2.4.9-ac10/arch/ppc64/kernel/head.S Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/head.S Thu Sep 13 11:54:36 2001 @@ -35,6 +35,10 @@ #include #include +#ifdef CONFIG_PPC_ISERIES +#define DO_SOFT_DISABLE +#endif + /* * We layout physical memory as follows: * 0x0000 - 0x00ff : Secondary processor spin code @@ -47,6 +51,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 +150,114 @@ * 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); \ + lbz r22,PACAPROCENABLED(r20); \ + std r22,SOFTE(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). */ /* @@ -218,16 +275,25 @@ EXCEPTION_PROLOG_ISERIES; \ b label##_common +#define MASKABLE_EXCEPTION_ISERIES( label ) \ + .globl label##_Iseries; \ +label##_Iseries: \ + EXCEPTION_PROLOG_ISERIES; \ + lbz r22,PACAPROCENABLED(r20); \ + cmpi 0,r22,0; \ + beq- label##_Iseries_masked; \ + b label##_common + #define STD_EXCEPTION_COMMON( trap, label, hdlr ) \ .globl label##_common; \ label##_common: \ EXCEPTION_PROLOG_COMMON; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ - SET_REG_TO_CONST(r20, MSR_KERNEL); \ + li r20,0; \ 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 +319,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 @@ -318,11 +385,11 @@ STD_EXCEPTION_ISERIES( DataAccessSLB ) STD_EXCEPTION_ISERIES( InstructionAccess ) STD_EXCEPTION_ISERIES( InstructionAccessSLB ) - STD_EXCEPTION_ISERIES( HardwareInterrupt ) + MASKABLE_EXCEPTION_ISERIES( HardwareInterrupt ) STD_EXCEPTION_ISERIES( Alignment ) STD_EXCEPTION_ISERIES( ProgramCheck ) STD_EXCEPTION_ISERIES( FPUnavailable ) - STD_EXCEPTION_ISERIES( Decrementer ) + MASKABLE_EXCEPTION_ISERIES( Decrementer ) STD_EXCEPTION_ISERIES( Trap_0a ) STD_EXCEPTION_ISERIES( Trap_0b ) STD_EXCEPTION_ISERIES( SystemCall ) @@ -362,9 +429,7 @@ /* Let the Hypervisor know we are alive */ /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ lis r3,0x8002 - rldicr r0,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ - rldicl r3,r3,0,48 /* r3 = r3 & 0x000000000000ffff */ - or r3,r3,r0 /* r3 = r3 | r0 */ + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ #else /* CONFIG_SMP */ /* Yield the processor. This is required for non-SMP kernels which are running on multi-threaded machines. */ @@ -380,6 +445,30 @@ b 1b /* If SMP not configured, secondaries * loop forever */ + .globl HardwareInterrupt_Iseries_masked +HardwareInterrupt_Iseries_masked: + b maskable_exception_exit + + .globl Decrementer_Iseries_masked +Decrementer_Iseries_masked: + li r22,1 + stb r22,PACALPPACA+LPPACADECRINT(r20) + lwz r22,PACADEFAULTDECR(r20) + mtspr DEC,r22 +maskable_exception_exit: + mtcrf 0xff,r23 /* Restore regs and free exception frame */ + ld r22,0(r21) + ld r23,8(r21) + mtspr SRR0,r22 + mtspr SRR1,r23 + ld r22,32(r21) + ld r23,40(r21) + addi r21,r21,EXC_FRAME_SIZE + std r21,PACAEXCSP(r20) + mfspr r21,SPRG1 + mfspr r20,SPRG2 + rfid + /*** Common interrupt handlers ***/ STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException ) @@ -390,32 +479,54 @@ 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) - andis. r0,r20,0xa450 /* weird error? */ + ld r3,_DSISR(r1) + andis. r0,r3,0xa450 /* weird error? */ bne 1f /* if not, try to put a PTE */ - mfspr r3,DAR /* into the hash table */ - std r3,_DAR(r21) - rlwinm r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ + andis. r0,r3,0x0020 /* Is it a page table fault? */ + rlwinm r4,r3,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ + ld r3,_DAR(r1) /* into the hash table */ - andis. r0,r20,0x0020 /* Is it a page table fault? */ beq 2f /* If so handle it */ li r4,0x300 /* Trap number */ bl .do_stab_SI @@ -423,60 +534,37 @@ 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 */ +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) /* Copy saved SOFTE bit */ +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif 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 */ +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif 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: @@ -497,12 +585,15 @@ mr r4,r22 mr r5,r23 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 */ +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif 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,89 +602,67 @@ li r4,0x480 /* Exception vector */ bl .ste_allocate or. r3,r3,r3 /* Check return code */ - bne 1f /* Branch on failure */ + beq fast_exception_return /* Return if we succeeded */ - /* 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) 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 */ +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif 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: EXCEPTION_PROLOG_COMMON HardwareInterrupt_entry: addi r3,r1,STACK_FRAME_OVERHEAD - SET_REG_TO_CONST(r20, MSR_KERNEL) + li r20,0 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 */ +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif 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: EXCEPTION_PROLOG_COMMON 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 */ +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif 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: EXCEPTION_PROLOG_COMMON bne .load_up_fpu /* if from user, just load it up */ - SET_REG_TO_CONST(r20, MSR_KERNEL) + li r20,0 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 +674,16 @@ beq+ HardwareInterrupt_entry 1: #endif - std r3,ORIG_GPR3(r21) - SET_REG_TO_CONST(r20, MSR_KERNEL) - rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + std r3,ORIG_GPR3(r1) +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif 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 +692,21 @@ ori r4,r4,1 /* add _PAGE_PRESENT */ mflr r21 /* Save LR in r21 */ - /* r21 restored later from r1 */ + +#ifdef DO_SOFT_DISABLE + /* + * We hard enable here (but first soft disable) so that the hash_page + * code can spin on the hash_table_lock with problem on a shared + * processor. + */ + li r0,0 + stb r0,PACAPROCENABLED(r20) /* Soft Disabled */ + + mfmsr r0 + ori r0,r0,MSR_EE + mtmsrd r0 /* Hard Enable */ +#endif + /* * r3 contains the faulting address * r4 contains the required access permissions @@ -629,58 +715,61 @@ */ 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 */ +#ifdef DO_SOFT_DISABLE /* - * The HPTE has been created/updated. Restore and retry the faulting inst + * Now go back to hard disabled. */ + mfmsr r0 + li r4,0 + ori r4,r4,MSR_EE + andc r0,r0,r4 + mtmsrd r0 /* Hard Disable */ + + ld r0,SOFTE(r1) + cmpdi 0,r0,0 /* See if we will soft enable in */ + /* save_remaining_regs */ + beq 5f + CHECKANYINT(r4,r5) + bne- HardwareInterrupt_entry /* Convert this DSI into an External */ + /* to process interrupts which occurred */ + /* during hash_page */ +5: + stb r0,PACAPROCENABLED(r20) /* Restore soft enable/disable status */ +#endif + or. r3,r3,r3 /* Check return code */ + beq fast_exception_return /* Return from exception on success */ - 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 + mtlr r21 /* restore LR */ + blr /* Return to DSI or ISI on failure */ -/* 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 */ + mfspr r21,DSISR + andis. r21,r21,0x0020 + bne+ 2f + li r3,0 +#ifdef CONFIG_XMON + bl .xmon +#endif +1: b 1b +2: /* (((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 +788,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 +821,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 +850,27 @@ 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 +_TRACEBACK(do_stab_bolted) _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 +879,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 */ - - /* - * 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 + beq fast_exception_return /* Return from exception on success */ + mtlr r21 /* restore LR */ + blr /* Return to DSI or ISI on failure */ /* - * 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 - */ - 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 */ - -/* - * Get the handler address and its return address and - * rfid to the handler - */ -/* MIKEC: Do we really need to rfid here? Since we are already running - with relocate on, could we just branch to the handler? - We also will be turning on MSR.EE for some interrupts here -*/ - mflr r23 - ld r24,0(r23) /* virtual address of handler */ - ld r23,8(r23) /* where to go when done */ - mtspr SRR0,r24 - mtspr SRR1,r20 - mtlr r23 - rfid /* jump to handler */ + SET_REG_TO_CONST(r22, MSR_KERNEL) + +#ifdef DO_SOFT_DISABLE + stb r20,PACAPROCENABLED(r23) /* possibly soft enable */ + ori r22,r22,MSR_EE /* always hard enable */ +#else + rldimi r22,r20,15,48 /* Insert desired EE value */ +#endif + + mtmsrd r22 + blr -#ifdef CONFIG_SMP /* * On pSeries, secondary processors spin in the following code. * At entry, r3 = this processor's number (in Linux terms, not hardware). @@ -918,11 +974,12 @@ ldx r1,r3,r28 cmpi 0,r23,0 +#ifdef CONFIG_SMP #ifdef SECONDARY_PROCESSORS bne .__secondary_start #endif +#endif b 1b /* Loop until told to go */ -#endif /* CONFIG_SMP */ _GLOBAL(__start_initialization_iSeries) @@ -1106,20 +1163,6 @@ copy_to_here: /* - * On kernel stack overflow, load up an initial stack pointer - * and call StackOverflow(regs), which should not return. - */ -_STATIC(stack_ovf) - addi r3,r1,STACK_FRAME_OVERHEAD - LOADADDR(r1,init_task_union) - addi r1,r1,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD - LOADADDR(r24,StackOverflow) - SET_REG_TO_CONST(r20, MSR_KERNEL); - mtspr SRR0,r24 - mtspr SRR1,r20 - rfid - -/* * Disable FP for the task which had the FPU previously, * and save its floating-point registers in its thread_struct. * Enables the FPU for use in the kernel on return. @@ -1130,7 +1173,7 @@ mfmsr r5 /* grab the current MSR */ ori r5,r5,MSR_FP mtmsrd r5 /* enable use of fpu now */ - SYNC + isync /* * For SMP, we don't do lazy FPU switching because it just gets too * horrendously complex, especially when a task switches from one CPU @@ -1166,19 +1209,7 @@ std r4,last_task_used_math@l(r3) #endif /* CONFIG_SMP */ /* restore registers and return */ - ld r3,_CCR(r21) - ld r4,_LINK(r21) - mtcrf 0xff,r3 - mtlr r4 - REST_2GPRS(1, r21) - REST_4GPRS(3, r21) - /* we haven't used ctr or xer */ - mtspr SRR1,r23 - mtspr SRR0,r22 - REST_GPR(20, r21) - REST_2GPRS(22, r21) - ld r21,GPR21(r21) - rfid + b fast_exception_return /* * FP unavailable trap from kernel - print a message, but let @@ -1206,7 +1237,7 @@ mfmsr r5 ori r5,r5,MSR_FP mtmsrd r5 /* enable use of fpu now */ - SYNC + isync cmpi 0,r3,0 beqlr- /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ @@ -1255,6 +1286,7 @@ std r2,PACATOC(r25) li r6,0 std r6,PACAKSAVE(r25) + stb r6,PACAPROCENABLED(r25) #ifndef CONFIG_PPC_ISERIES /* Initialize the page table pointer register. */ @@ -1295,6 +1327,9 @@ /* enable MMU and jump to start_secondary */ LOADADDR(r3,.start_secondary) SET_REG_TO_CONST(r4, MSR_KERNEL) +#ifdef DO_SOFT_DISABLE + ori r4,r4,MSR_EE +#endif mtspr SRR0,r3 mtspr SRR1,r4 rfid @@ -1312,7 +1347,7 @@ rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) or r11,r11,r12 mtmsrd r11 - SYNC + isync blr /* @@ -1327,7 +1362,7 @@ rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) andc r11,r11,r12 mtmsrd r11 - SYNC + isync blr @@ -1466,14 +1501,6 @@ std r2,PACATOC(r4) li r5,0 std r0,PACAKSAVE(r4) -/* - * Register old definition new definition - * - * SPRG0 temp - used to save gpr reserved for hypervisor - * SPRG1 temp - used to save gpr unused - * SPRG2 0 or kernel stack frame temp - used to save gpr - * SPRG3 Linux thread virt addr of Paca - */ /* * Restore the parms passed in from the bootloader. @@ -1488,6 +1515,15 @@ /* Load up the kernel context */ 5: +#ifdef DO_SOFT_DISABLE + mfspr r4,SPRG3 + li r5,0 + stb r5,PACAPROCENABLED(r4) /* Soft Disabled */ + mfmsr r5 + ori r5,r5,MSR_EE /* Hard Enabled */ + mtmsrd r5 +#endif + bl .start_kernel /* diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/htab.c linuxppc64_2_4/arch/ppc64/kernel/htab.c --- linux-2.4.9-ac10/arch/ppc64/kernel/htab.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/htab.c Fri Sep 7 07:57:15 2001 @@ -38,6 +38,7 @@ #include #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-2.4.9-ac10/arch/ppc64/kernel/iSeries_IoMmTable.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.c --- linux-2.4.9-ac10/arch/ppc64/kernel/iSeries_IoMmTable.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/iSeries_IoMmTable.h linuxppc64_2_4/arch/ppc64/kernel/iSeries_IoMmTable.h --- linux-2.4.9-ac10/arch/ppc64/kernel/iSeries_IoMmTable.h Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/iSeries_VpdInfo.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_VpdInfo.c --- linux-2.4.9-ac10/arch/ppc64/kernel/iSeries_VpdInfo.c Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_VpdInfo.c Fri Aug 24 06:41:08 2001 @@ -0,0 +1,360 @@ +/************************************************************************/ +/* File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. */ +/************************************************************************/ +/* This code gets the card location of the hardware */ +/* Copyright (C) 20yy */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the: */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, */ +/* Boston, MA 02111-1307 USA */ +/************************************************************************/ +/* Change Activity: */ +/* Created, Feb 2, 2001 */ +/* Ported to ppc64, August 20, 2001 */ +/* End Change Activity */ +/************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "pci.h" + +/************************************************/ +/* Size of Bus VPD data */ +/************************************************/ +#define BUS_VPDSIZE 1024 +/************************************************/ +/* Bus Vpd Tags */ +/************************************************/ +#define VpdEndOfDataTag 0x78 +#define VpdEndOfAreaTag 0x79 +#define VpdIdStringTag 0x82 +#define VpdVendorAreaTag 0x84 +/************************************************/ +/* Mfg Area Tags */ +/************************************************/ +#define VpdAsmPartNumber 0x504E // "PN" +#define VpdFruFlag 0x4647 // "FG" +#define VpdFruLocation 0x464C // "FL" +#define VpdFruFrameId 0x4649 // "FI" +#define VpdFruPartNumber 0x464E // "FN" +#define VpdFruPowerData 0x5052 // "PR" +#define VpdFruSerial 0x534E // "SN" +#define VpdFruType 0x4343 // "CC" +#define VpdFruCcinExt 0x4345 // "CE" +#define VpdFruRevision 0x5256 // "RV" +#define VpdSlotMapFormat 0x4D46 // "MF" +#define VpdSlotMap 0x534D // "SM" + +/************************************************/ +/* Structures of the areas */ +/************************************************/ +struct BusVpdAreaStruct { + u8 Tag; + u8 LowLength; + u8 HighLength; +}; +typedef struct BusVpdAreaStruct BusVpdArea; +#define BUS_ENTRY_SIZE 3 + +struct MfgVpdAreaStruct { + u16 Tag; + u8 TagLength; +}; +typedef struct MfgVpdAreaStruct MfgVpdArea; +#define MFG_ENTRY_SIZE 3 + +struct SlotMapFormatStruct { + u16 Tag; + u8 TagLength; + u16 Format; +}; + +struct FrameIdMapStruct{ + u16 Tag; + u8 TagLength; + u8 FrameId; +}; +typedef struct FrameIdMapStruct FrameIdMap; + +struct SlotMapStruct { + u8 AgentId; + u8 SecondaryAgentId; + u8 PhbId; + char CardLocation[3]; + char Parms[8]; + char Reserved[2]; +}; +typedef struct SlotMapStruct SlotMap; +#define SLOT_ENTRY_SIZE 16 + +/****************************************************************/ +/* Prototypes */ +/****************************************************************/ +static void iSeries_Parse_Vpd(BusVpdArea*, int, LocationData*); +static void iSeries_Parse_MfgArea(MfgVpdArea*,int, LocationData*); +static void iSeries_Parse_SlotArea(SlotMap*, int, LocationData*); +static void iSeries_Parse_PhbId(BusVpdArea*, int, LocationData*); + +/**************************************************************** + * iSeries_loc-code(struct pci_dev* PciDev) * + * * + * Gets the frame and card location of the pci_dev device. The * + * return is a kmalloc string. The user must free this string * + * when they are done. This is specifically for the device tree* + * * + * Returns: * + * "Frame 1, Card C10" * + ****************************************************************/ +char* iSeries_Location_Code(struct pci_dev* PciDev) { + char TempBuffer[128]; + LocationData* LocationPtr = iSeries_GetLocationData(PciDev); + int LineLen = sprintf(TempBuffer," Frame%3d, Card %4s ", + LocationPtr->FrameId,LocationPtr->CardLocation); + char* RtnString = kmalloc(LineLen+7,GFP_KERNEL); + strcpy(RtnString,TempBuffer); + kfree(LocationPtr); + return RtnString; +} +/****************************************************************/ +/* */ +/* */ +/* */ +/****************************************************************/ +LocationData* iSeries_GetLocationData(struct pci_dev* PciDev) { + LocationData* LocationPtr = 0; + BusVpdArea* BusVpdPtr = 0; + int BusVpdLen = 0; + BusVpdPtr = (BusVpdArea*)kmalloc(BUS_VPDSIZE, GFP_KERNEL); + BusVpdLen = HvCallPci_getBusVpd(PciDev->bus->number,REALADDR(BusVpdPtr),BUS_VPDSIZE); + /* printk("PCI: VpdBuffer 0x%08X \n",(int)BusVpdPtr); */ + /***************************************************************/ + /* Need to set Agent Id, Bus in location info before the call */ + /***************************************************************/ + LocationPtr = (LocationData*)kmalloc(LOCATION_DATA_SIZE, GFP_KERNEL); + LocationPtr->Bus = PciDev->bus->number; + LocationPtr->Board = 0; + LocationPtr->FrameId = 0; + iSeries_Parse_PhbId(BusVpdPtr,BusVpdLen,LocationPtr); + LocationPtr->Card = PCI_SLOT(PciDev->devfn); + strcpy(LocationPtr->CardLocation,"Cxx"); + LocationPtr->AgentId = ISERIES_DECODE_DEVICE(PciDev->devfn); + LocationPtr->SecondaryAgentId = 0x10; + /* And for Reference only. */ + LocationPtr->LinuxBus = PciDev->bus->number; + LocationPtr->LinuxDevFn = PciDev->devfn; + /***************************************************************/ + /* Any data to process? */ + /***************************************************************/ + if(BusVpdLen > 0) { + iSeries_Parse_Vpd(BusVpdPtr, BUS_VPDSIZE, LocationPtr); + } + else { + PCIFR("No VPD Data...."); + } + kfree(BusVpdPtr); + + return LocationPtr; +} +/****************************************************************/ +/* */ +/****************************************************************/ +void iSeries_Parse_Vpd(BusVpdArea* VpdData,int VpdLen, LocationData* LocationPtr) { + MfgVpdArea* MfgVpdPtr = 0; + int BusTagLen = 0; + BusVpdArea* BusVpdPtr = VpdData; + int BusVpdLen = VpdLen; + /*************************************************************/ + /* Make sure this is what I think it is */ + /*************************************************************/ + if(BusVpdPtr->Tag != VpdIdStringTag) { /*0x82 */ + PCIFR("Not 0x82 start of VPD."); + return; + } + BusTagLen = (BusVpdPtr->HighLength*256)+BusVpdPtr->LowLength; + BusTagLen += BUS_ENTRY_SIZE; + BusVpdPtr = (BusVpdArea*)((u32)BusVpdPtr+BusTagLen); + BusVpdLen -= BusTagLen; + /*************************************************************/ + /* Parse the Data */ + /*************************************************************/ + while(BusVpdLen > 0 ) { + BusTagLen = (BusVpdPtr->HighLength*256)+BusVpdPtr->LowLength; + /*********************************************************/ + /* End of data Found */ + /*********************************************************/ + if(BusVpdPtr->Tag == VpdEndOfAreaTag) { + BusVpdLen = 0; /* Done, Make sure */ + } + /*********************************************************/ + /* Was Mfg Data Found */ + /*********************************************************/ + else if(BusVpdPtr->Tag == VpdVendorAreaTag) { + MfgVpdPtr = (MfgVpdArea*)((u32)BusVpdPtr+BUS_ENTRY_SIZE); + iSeries_Parse_MfgArea(MfgVpdPtr,BusTagLen,LocationPtr); + } + /********************************************************/ + /* On to the next tag. */ + /********************************************************/ + if(BusVpdLen > 0) { + BusTagLen += BUS_ENTRY_SIZE; + BusVpdPtr = (BusVpdArea*)((u32)BusVpdPtr+BusTagLen); + BusVpdLen -= BusTagLen; + } + } +} + +/*****************************************************************/ +/* Parse the Mfg Area */ +/*****************************************************************/ +void iSeries_Parse_MfgArea(MfgVpdArea* VpdDataPtr,int VpdLen, LocationData* LocationPtr) { + SlotMap* SlotMapPtr = 0; + u16 SlotMapFmt = 0; + int MfgTagLen = 0; + MfgVpdArea* MfgVpdPtr = VpdDataPtr; + int MfgVpdLen = VpdLen; + + /*************************************************************/ + /* Parse Mfg Data */ + /*************************************************************/ + while(MfgVpdLen > 0) { + MfgTagLen = MfgVpdPtr->TagLength; + if (MfgVpdPtr->Tag == VpdFruFlag) {} /* FG */ + else if(MfgVpdPtr->Tag == VpdFruSerial) {} /* SN */ + else if(MfgVpdPtr->Tag == VpdAsmPartNumber){} /* PN */ + /*********************************************************/ + /* Frame ID */ + /*********************************************************/ + if(MfgVpdPtr->Tag == VpdFruFrameId) { /* FI */ + LocationPtr->FrameId = ((FrameIdMap*)MfgVpdPtr)->FrameId; + } + /*********************************************************/ + /* Slot Map Format */ + /*********************************************************/ + else if(MfgVpdPtr->Tag == VpdSlotMapFormat){ /* MF */ + SlotMapFmt = ((struct SlotMapFormatStruct*)MfgVpdPtr)->Format; + } + /*********************************************************/ + /* Slot Labels */ + /*********************************************************/ + else if(MfgVpdPtr->Tag == VpdSlotMap){ /* SM */ + if(SlotMapFmt == 0x1004) SlotMapPtr = (SlotMap*)((u32)MfgVpdPtr+MFG_ENTRY_SIZE+1); + else SlotMapPtr = (SlotMap*)((u32)MfgVpdPtr+MFG_ENTRY_SIZE); + iSeries_Parse_SlotArea(SlotMapPtr,MfgTagLen, LocationPtr); + } + /*********************************************************/ + /* Point to the next Mfg Area */ + /* Use defined size, sizeof give wrong answer */ + /*********************************************************/ + MfgTagLen += MFG_ENTRY_SIZE; + MfgVpdPtr = (MfgVpdArea*)( (u32)MfgVpdPtr + MfgTagLen); + MfgVpdLen -= MfgTagLen; + } +} +/*****************************************************************/ +/* Look for "BUS" Tag to set the PhbId. */ +/*****************************************************************/ +void iSeries_Parse_PhbId(BusVpdArea* VpdData,int VpdLen,LocationData* LocationPtr) { + int PhbId = 0xff; /* Not found flag */ + char* PhbPtr = (char*)VpdData+3; /* Skip over 82 tag */ + int DataLen = VpdLen; + while(DataLen > 0) { + if(*PhbPtr == 'B' && *(PhbPtr+1) == 'U' && *(PhbPtr+2) == 'S') { + if(*(PhbPtr+3) == ' ') PhbPtr += 4;/* Skip white spac*/ + else PhbPtr += 3; + if (*PhbPtr == '0') PhbId = 0; /* Don't convert, */ + else if(*PhbPtr == '1') PhbId = 1; /* Sanity check */ + else if(*PhbPtr == '2') PhbId = 2; /* values */ + DataLen = 0; /* Exit loop. */ + } + ++PhbPtr; + --DataLen; + } + LocationPtr->PhbId = PhbId; +} +/*****************************************************************/ +/* Parse the Slot Area */ +/*****************************************************************/ +void iSeries_Parse_SlotArea(SlotMap* MapPtr,int MapLen, LocationData* LocationPtr) { + int SlotMapLen = MapLen; + SlotMap* SlotMapPtr = MapPtr; + /*************************************************************/ + /* Parse Slot label until we find the one requrested */ + /*************************************************************/ + while(SlotMapLen > 0) { + if(SlotMapPtr->AgentId == LocationPtr->AgentId && + SlotMapPtr->SecondaryAgentId == LocationPtr->SecondaryAgentId) { + /*****************************************************/ + /* If Phb wasn't found, grab the first one found. */ + /*****************************************************/ + if(LocationPtr->PhbId == 0xff) LocationPtr->PhbId = SlotMapPtr->PhbId; + if( SlotMapPtr->PhbId == LocationPtr->PhbId ) { + /*****************************************************/ + /* Found what we were looking for, extract the data. */ + /*****************************************************/ + memcpy(&LocationPtr->CardLocation,&SlotMapPtr->CardLocation,3); + LocationPtr->CardLocation[3] = 0; /* Null terminate*/ + SlotMapLen = 0; /* We are done */ + } + } + /*********************************************************/ + /* Point to the next Slot */ + /* Use defined size, sizeof may give wrong answer */ + /*********************************************************/ + SlotMapLen -= SLOT_ENTRY_SIZE; + SlotMapPtr = (SlotMap*)((u32)SlotMapPtr+SLOT_ENTRY_SIZE); + } +} +/************************************************************************/ +/* Formats the device information. */ +/* - Pass in pci_dev* pointer to the device. */ +/* - Pass in buffer to place the data. Danger here is the buffer must */ +/* be as big as the client says it is. Should be at least 128 bytes.*/ +/* Return will the length of the string data put in the buffer. */ +/* Format: */ +/* PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet */ +/* controller */ +/************************************************************************/ +int iSeries_Device_Information(struct pci_dev* PciDev,char* Buffer, int BufferSize) { + LocationData* LocationPtr; /* VPD Information */ + char* BufPtr = Buffer; + int LineLen = 0; + if(BufferSize >= 128) { + LineLen = sprintf(BufPtr+LineLen,"PCI: Bus%3d, Device%3d, Vendor %04X ", + PciDev->bus->number, PCI_SLOT(PciDev->devfn),PciDev->vendor); + + LocationPtr = iSeries_GetLocationData(PciDev); + LineLen += sprintf(BufPtr+LineLen," Frame%3d, Card %4s ", + LocationPtr->FrameId,LocationPtr->CardLocation); + kfree(LocationPtr); + + if(pci_class_name(PciDev->class >> 8) == 0) { + LineLen += sprintf(BufPtr+LineLen,"0x%04X ",(int)(PciDev->class >> 8)); + } + else { + LineLen += sprintf(BufPtr+LineLen,"%s",pci_class_name(PciDev->class >> 8) ); + } + } + return LineLen; +} diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/iSeries_dma.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_dma.c --- linux-2.4.9-ac10/arch/ppc64/kernel/iSeries_dma.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/iSeries_irq.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_irq.c --- linux-2.4.9-ac10/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-2.4.9-ac10/arch/ppc64/kernel/iSeries_pci.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_pci.c --- linux-2.4.9-ac10/arch/ppc64/kernel/iSeries_pci.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_pci.c Mon Sep 10 11:24:50 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-2.4.9-ac10/arch/ppc64/kernel/iSeries_setup.c linuxppc64_2_4/arch/ppc64/kernel/iSeries_setup.c --- linux-2.4.9-ac10/arch/ppc64/kernel/iSeries_setup.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/iSeries_setup.c Thu Sep 13 11:54:36 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,27 @@ ppc_md.ppc_kbd_sysrq_xlate = NULL; #endif - if ( itLpNaca.xPirEnvironMode == 0 ) - piranha_simulator = 1; + htpe_init_iSeries(); + tce_init_iSeries(); + + /* 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 */ - return; +#ifdef CONFIG_SMP + smp_init_iSeries(); +#endif + + if ( itLpNaca.xPirEnvironMode == 0 ) + piranha_simulator = 1; +#endif } /* @@ -188,15 +200,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 @@ -514,7 +523,7 @@ return (len); } -#ifdef CONFIG_SMP +#if 0 void iSeries_spin_lock(spinlock_t *lock) { int i; @@ -528,7 +537,7 @@ } } HMT_medium(); - HvCallCfg_getLps(); + ALLOW_HYPERVISOR_PREEMPTION; } } @@ -545,7 +554,7 @@ } } HMT_medium(); - HvCallCfg_getLps(); + ALLOW_HYPERVISOR_PREEMPTION; } } @@ -562,7 +571,7 @@ } } HMT_medium(); - HvCallCfg_getLps(); + ALLOW_HYPERVISOR_PREEMPTION; } } @@ -579,7 +588,7 @@ } HMT_medium(); - HvCallCfg_getLps(); + ALLOW_HYPERVISOR_PREEMPTION; } } @@ -628,12 +637,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 +762,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-2.4.9-ac10/arch/ppc64/kernel/irq.c linuxppc64_2_4/arch/ppc64/kernel/irq.c --- linux-2.4.9-ac10/arch/ppc64/kernel/irq.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/irq.c Fri Sep 14 10:05:47 2001 @@ -565,7 +565,7 @@ } #endif /* CONFIG_SMP */ lpq = paca->lpQueuePtr; - if ( lpq ) + if ( lpq && ItLpQueue_isLpIntPending( lpq ) ) lpEvent_count += ItLpQueue_process( lpq, regs ); } diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/misc.S linuxppc64_2_4/arch/ppc64/kernel/misc.S --- linux-2.4.9-ac10/arch/ppc64/kernel/misc.S Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/misc.S Thu Sep 13 18:57:20 2001 @@ -27,6 +27,10 @@ #include #include "ppc_asm.h" +#ifdef CONFIG_PPC_ISERIES +#define DO_SOFT_DISABLE +#endif + .text /* @@ -63,13 +67,14 @@ mr r3,r1 blr -_GLOBAL(get_paca) - mfspr r3,SPRG3; - blr - /* void __no_use_save_flags(unsigned long *flags) */ _GLOBAL(__no_use_save_flags) +#ifdef DO_SOFT_DISABLE + mfspr r4,SPRG3 + lbz r4,PACAPROCENABLED(r4) +#else mfmsr r4 +#endif std r4,0(r3) blr @@ -81,6 +86,10 @@ * sense anyway. * -- Cort */ +#ifdef DO_SOFT_DISABLE + mfspr r6,SPRG3 + lbz r5,PACAPROCENABLED(r6) +#else mfmsr r5 mr r4,r3 mr r3,r5 @@ -88,59 +97,56 @@ /* Copy all except the MSR_EE bit from r4 (current MSR value) to r3. This is the sort of thing the rlwimi instruction is designed for. -- paulus. */ +#endif /* Check if things are setup the way we want _already_. */ cmpw 0,r3,r5 beqlr /* are we enabling interrupts? */ +#ifdef DO_SOFT_DISABLE + cmpi 0,r3,0 + stb r3,PACAPROCENABLED(r6) +#else rlwinm. r0,r3,0,16,16 + mtmsrd r3 +#endif beq 1f - /* Check pending interrupts - * A decrementer, IPI or PMC interrupt may have occurred - * while we were in the hypervisor (which enables) - */ + /* Check pending interrupts */ CHECKANYINT(r4,r5) beq+ 1f /* * Handle pending interrupts in interrupt context */ - mtmsrd r3 li r0,0x5555 - sc - blr + sc 1: - sync - mtmsrd r3 - isync - blr -/* void __no_lpq_restore_flags(unsigned long flags) */ -_GLOBAL(__no_lpq_restore_flags) - mfmsr r5 - mr r4,r3 - mr r3,r5 - rlwimi r3,r4,0,16,16 - /* Copy all except the MSR_EE bit from r4 (current MSR value) - to r3. This is the sort of thing the rlwimi instruction is - designed for. -- paulus. */ - /* Check if things are setup the way we want _already_. */ - cmpw 0,r3,r5 - beqlr - sync - mtmsrd r3 - isync blr _GLOBAL(__no_use_cli) +#ifdef DO_SOFT_DISABLE + mfspr r5,SPRG3 + lbz r3,PACAPROCENABLED(r5) + li r4,0 + stb r4,PACAPROCENABLED(r5) +#else mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ rldicl r0,r0,48,1 rldicl r0,r0,16,0 /* clear MSR_EE in r0 */ mtmsrd r0 /* Update machine state */ +#endif blr /* Done */ _GLOBAL(__no_use_sti) +#ifdef DO_SOFT_DISABLE + mfspr r6,SPRG3 + li r3,1 + stb r3,PACAPROCENABLED(r6) +#else mfmsr r3 /* Get current state */ ori r3,r3,MSR_EE /* Turn on 'EE' bit */ + mtmsrd r3 +#endif /* Check for pending interrupts * A decrementer, IPI or PMC interrupt may have occurred @@ -152,40 +158,12 @@ /* * Handle pending interrupts in interrupt context */ - mtmsrd r3 li r0,0x5555 sc - blr 1: - sync /* Some chip revs have problems here... */ - mtmsrd r3 /* Update machine state */ blr /* - * We were about to enable interrupts but we have to simulate - * some interrupts that were lost by enable_irq first. - */ -#if 0 -_GLOBAL(do_fake_interrupt) - mflr r0 - std r0,16(r1) - std r3,-8(r1) - stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1) -1: bl .fake_interrupt - /* Check for pending interrupt - * A decrementer, IPI or PMC interrupt may have occurred - * while we were in the hypervisor (which enables) - */ - CHECKANYINT(r4,r5) - bne- 1b - addi r1,r1,STACK_FRAME_OVERHEAD+16 - ld r3,-8(r1) - ld r0,16(r1) - mtlr r0 - mtmsrd r3 - blr -#endif -/* * complement mask on the msr then "or" some values on. * _nmask_and_or_msr(nmask, value_to_or) */ @@ -308,11 +286,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 * @@ -344,126 +321,25 @@ isync blr - /* - * 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 + * Copy a whole page. Assumes a 4096B page size. */ - -/* 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. - */ -_GLOBAL(clear_page) - LOADADDR(r6,naca) - ld r6,0(r6) - clrrdi r3,r3,12 /* Page align */ - lhz r4,DCACHEL1LINESPERPAGE(r6) /* Get # dcache lines per page */ - lhz r5,DCACHEL1LINESIZE(r6) /* Get dcache line size */ - mtctr r4 -0: dcbz 0,r3 - add r3,r3,r5 - bdnz 0b - blr - -/* - * Copy a whole page. We use the dcbz instruction on the destination - * to reduce memory traffic (it eliminates the unnecessary reads of - * the destination into cache). This requires that the destination - * is cacheable. - */ -#define COPY_32_BYTES \ - ld r6,8(r4); \ - ld r7,16(r4); \ - ld r8,24(r4); \ - ldu r9,32(r4); \ - std r6,8(r3); \ - std r7,16(r3); \ - std r8,24(r3); \ - stdu r9,32(r3) - _GLOBAL(copy_page) - LOADADDR(r9,naca) ld r9,0(r9) clrrdi r3,r3,12 /* Page align */ clrrdi r4,r4,12 /* Page align */ - lhz r5,DCACHEL1LINESPERPAGE(r9) /* Get # dcache lines per page */ - lhz r0,DCACHEL1LINESIZE(r9) /* Get dcache line size */ + li r5,256 mtctr r5 addi r3,r3,-8 addi r4,r4,-8 - li r10,8 - cmpi 0,r0,32 - beq do_32_byte_line - cmpi 0,r0,64 - beq do_64_byte_line - cmpi 0,r0,128 - beq do_128_byte_line - - /* We don't have code specifically for this cache line size */ - /* Assume that the cache line size is at least 32 (and of */ - /* course a multiple of 32) */ - /* This code will work for all power-of-2 cache line sizes */ - /* from 32 to 4096 */ - -1: mr r5,r0 - dcbz r10,r3 -0: COPY_32_BYTES - addi r5,r5,-32 - or. r5,r5,r5 - bne 0b - bdnz 1b - blr - - .globl do_32_byte_line -do_32_byte_line: - dcbz r10,r3 - COPY_32_BYTES - bdnz do_32_byte_line - blr - - .globl do_64_byte_line -do_64_byte_line: - dcbz r10,r3 - COPY_32_BYTES - COPY_32_BYTES - bdnz do_64_byte_line - blr - - .globl do_128_byte_line -do_128_byte_line: - dcbz r10,r3 - COPY_32_BYTES - COPY_32_BYTES - COPY_32_BYTES - COPY_32_BYTES - bdnz do_128_byte_line - blr +1: ld r6,8(r4) + ldu r7,16(r4) + std r6,8(r3) + stdu r7,16(r3) + bdnz+ 1b + blr /* * I/O string operations @@ -641,6 +517,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-2.4.9-ac10/arch/ppc64/kernel/mk_defs.c linuxppc64_2_4/arch/ppc64/kernel/mk_defs.c --- linux-2.4.9-ac10/arch/ppc64/kernel/mk_defs.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/mk_defs.c Thu Sep 13 10:16:37 2001 @@ -69,13 +69,15 @@ 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(PACAPROCENABLED, offsetof(struct Paca, xProcEnabled)); + DEFINE(PACADEFAULTDECR, offsetof(struct Paca, default_decr)); + 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)); @@ -132,6 +134,7 @@ DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); + DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); DEFINE(CLONE_VM, CLONE_VM); return 0; diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/open_pic.c linuxppc64_2_4/arch/ppc64/kernel/open_pic.c --- linux-2.4.9-ac10/arch/ppc64/kernel/open_pic.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/pSeries_pci.c linuxppc64_2_4/arch/ppc64/kernel/pSeries_pci.c --- linux-2.4.9-ac10/arch/ppc64/kernel/pSeries_pci.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/pSeries_pci.c Tue Sep 11 07:12:11 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,18 +601,21 @@ 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; } +} + +/* + * This is called very early before the page table is setup. + */ +void +pSeries_pcibios_init_early(void) { + ppc_md.pcibios_read_config_byte = rtas_read_config_byte; + ppc_md.pcibios_read_config_word = rtas_read_config_word; + ppc_md.pcibios_read_config_dword = rtas_read_config_dword; + ppc_md.pcibios_write_config_byte = rtas_write_config_byte; + ppc_md.pcibios_write_config_word = rtas_write_config_word; + ppc_md.pcibios_write_config_dword = rtas_write_config_dword; } diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/pacaData.c linuxppc64_2_4/arch/ppc64/kernel/pacaData.c --- linux-2.4.9-ac10/arch/ppc64/kernel/pacaData.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/pacaData.c Thu Sep 13 11:54:36 2001 @@ -31,49 +31,35 @@ * 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 */ \ + default_decr: 0x00ff0000, /* Initial Decr */ \ + 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, \ + xDecrVal: 0x00ff0000, \ + 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-2.4.9-ac10/arch/ppc64/kernel/pci.c linuxppc64_2_4/arch/ppc64/kernel/pci.c --- linux-2.4.9-ac10/arch/ppc64/kernel/pci.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/pci.h linuxppc64_2_4/arch/ppc64/kernel/pci.h --- linux-2.4.9-ac10/arch/ppc64/kernel/pci.h Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/pci.h Tue Sep 11 07:12:11 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,58 @@ 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); + +void iSeries_pcibios_init_early(void); +void pSeries_pcibios_init_early(void); + +/* 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 +87,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-2.4.9-ac10/arch/ppc64/kernel/pci_dma.c linuxppc64_2_4/arch/ppc64/kernel/pci_dma.c --- linux-2.4.9-ac10/arch/ppc64/kernel/pci_dma.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/pci_dma.c Thu Sep 13 08:06:56 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 ); +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 = dev->bus->number; + 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* + */ +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 ); @@ -785,9 +859,9 @@ *dma_handle = tce; } } - else - PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: __get_free_pages failed for order = %d\n", order); + else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: __get_free_pages failed for order = %d\n", order); } + else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tce_table failed for 0x%016lx\n", hwdev); PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: dma_handle = 0x%16.16lx\n", *dma_handle); PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: return = 0x%16.16lx\n", ret); @@ -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 ); + ppc_md.tce_free( 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; - - /* 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-2.4.9-ac10/arch/ppc64/kernel/pci_dn.c linuxppc64_2_4/arch/ppc64/kernel/pci_dn.c --- linux-2.4.9-ac10/arch/ppc64/kernel/pci_dn.c Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/arch/ppc64/kernel/pci_dn.c Tue Sep 11 07:12:11 2001 @@ -0,0 +1,326 @@ +/* + * 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" + +/* 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 *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; + } + +#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 (ppc_md.pcibios_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 (ppc_md.pcibios_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 (ppc_md.pcibios_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; + } + } +#endif + return NULL; +} + +#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 (ppc_md.pcibios_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 ppc_md.pcibios_read_config_dword(&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-2.4.9-ac10/arch/ppc64/kernel/pmac_nvram.c linuxppc64_2_4/arch/ppc64/kernel/pmac_nvram.c --- linux-2.4.9-ac10/arch/ppc64/kernel/pmac_nvram.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/ppc_asm.h linuxppc64_2_4/arch/ppc64/kernel/ppc_asm.h --- linux-2.4.9-ac10/arch/ppc64/kernel/ppc_asm.h Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/ppc_asm.h Fri Sep 14 10:05:47 2001 @@ -48,30 +48,6 @@ sync; \ isync -/* iSeries LPAR uses an event queue to signal I/O events - This code checks the queue */ - -#define CHECKLPQUEUE(ra,rb,rc) \ - mfspr ra,SPRG3; /* Get PACA address */\ - ld ra,PACALPQUEUE(ra); /* Get LpQueue address */\ - cmpi 0,ra,0; /* Does LpQueue exist? */\ - beq 99f; /* No? - then skip rest */\ - ld rb,LPQCUREVENTPTR(ra); /* Get current LpEvent */\ - lbz rb,LPEVENTFLAGS(rb); /* Get valid bit */\ - lbz rc,LPQOVERFLOW(ra); /* Get LpQueue overflow */\ - andi. ra,rb,0x0080; /* Isolate valid bit */\ - or. ra,ra,rc; /* 0 == no pending events */\ -99: - -#define CHECKDECR(ra,rb) \ - mfspr rb,SPRG3; /* Get Paca address */\ - lbz ra,PACALPPACA+LPPACADECRINT(rb); /* Get DECR int flag */\ - cmpi 0,ra,0; /* DECR occurred in hypervisor ? */\ - beq 99f; /* If not, skip rest */\ - xor ra,ra,ra; \ - stb ra,PACALPPACA+LPPACADECRINT(rb); /* Clear DECR int flag */\ -99: - #define CHECKANYINT(ra,rb) \ mfspr rb,SPRG3; /* Get Paca address */\ ld ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\ diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/ppc_ksyms.c linuxppc64_2_4/arch/ppc64/kernel/ppc_ksyms.c --- linux-2.4.9-ac10/arch/ppc64/kernel/ppc_ksyms.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/ppc_ksyms.c Mon Sep 10 15:17:54 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); @@ -87,6 +84,7 @@ #endif /* CONFIG_SMP */ EXPORT_SYMBOL(isa_io_base); +EXPORT_SYMBOL(isa_io_limit); EXPORT_SYMBOL(isa_mem_base); EXPORT_SYMBOL(pci_dram_offset); @@ -179,6 +177,7 @@ EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); #endif +EXPORT_SYMBOL(int_control); #ifndef CONFIG_MACH_SPECIFIC EXPORT_SYMBOL(_machine); diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/process.c linuxppc64_2_4/arch/ppc64/kernel/process.c --- linux-2.4.9-ac10/arch/ppc64/kernel/process.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/prom.c linuxppc64_2_4/arch/ppc64/kernel/prom.c --- linux-2.4.9-ac10/arch/ppc64/kernel/prom.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/prom.c Fri Sep 14 13:50:13 2001 @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef DEBUG_YABOOT #define call_yaboot(FUNC,...) \ @@ -66,6 +67,7 @@ #include #include #include "open_pic.h" +#include #include #ifdef CONFIG_FB @@ -152,13 +154,13 @@ 0, /* disp_node */ {0,0,0,{0},NULL}, /* args */ 0, /* version */ - 32 /* encode_phys_size */ + 32, /* encode_phys_size */ + 0 /* bi_rec pointer */ #ifdef DEBUG_YABOOT ,NULL /* yaboot */ #endif }; -int cpu_hw_index[NR_CPUS] = {0}; char *prom_display_paths[FB_MAX] __initdata = { 0, }; unsigned int prom_num_displays = 0; @@ -194,6 +196,7 @@ static unsigned long finish_node_interrupts(struct device_node *, unsigned long); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); +static void prom_bi_rec_init(unsigned long); #ifdef CONFIG_MSCHUNKS static unsigned long prom_initialize_mschunks(unsigned long); @@ -330,6 +333,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 +434,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 +469,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 +505,10 @@ prom_print_hex(_naca->interrupt_controller); prom_print_nl(); + prom_print(RELOC("_machine = 0x")); + prom_print_hex(RELOC(_machine)); + prom_print_nl(); + prom_print(RELOC("prom_initialize_naca: end...\n")); #endif @@ -628,22 +660,22 @@ } #ifdef DEBUG_PROM - prom_print(RELOC("rtas->base = 0x")); + prom_print(RELOC("rtas->base = 0x")); prom_print_hex(_rtas->base); prom_print_nl(); - prom_print(RELOC("rtas->entry = 0x")); + prom_print(RELOC("rtas->entry = 0x")); prom_print_hex(_rtas->entry); prom_print_nl(); - prom_print(RELOC("rtas->size = 0x")); + prom_print(RELOC("rtas->size = 0x")); prom_print_hex(_rtas->size); prom_print_nl(); - prom_print(RELOC("rtas->event_scan.rate = 0x")); + prom_print(RELOC("rtas->event_scan.rate = 0x")); prom_print_hex(_rtas->event_scan.rate); prom_print_nl(); - prom_print(RELOC("rtas->event_scan.log = 0x")); + prom_print(RELOC("rtas->event_scan.log = 0x")); prom_print_hex((unsigned long)_rtas->event_scan.log); prom_print_nl(); - prom_print(RELOC("rtas->event_scan.log_size = 0x")); + prom_print(RELOC("rtas->event_scan.log_size = 0x")); prom_print_hex(_rtas->event_scan.log_size); prom_print_nl(); #endif @@ -896,6 +928,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 +1016,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,10 +1096,15 @@ 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; + _prom->bi_recs = (struct bi_record *)r6; #ifdef DEBUG_YABOOT call_yaboot(yaboot->dummy,offset>>32,offset&0xffffffff); @@ -1181,7 +1219,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")); @@ -1206,6 +1244,8 @@ mem = prom_initialize_lmb(mem); + prom_bi_rec_init(mem); + mem = prom_instantiate_rtas(mem); /* Initialize some system info into the Naca early... */ @@ -1229,7 +1269,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 +1676,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 +1703,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 +1732,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 +1981,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); } @@ -2345,6 +2377,35 @@ #endif for (;;) prom_exit(); +} + + +static void +prom_bi_rec_init(unsigned long mem) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + struct bi_record *rec; + + if ( _prom->bi_recs == NULL) + return; + + for (rec=_prom->bi_recs; rec->tag != BI_LAST ;rec=bi_rec_next(rec) ) + { + switch (rec->tag) + { +#ifdef CONFIG_BLK_DEV_INITRD + case BI_INITRD: + lmb_reserve(rec->data[0], rec->data[1]); + break; +#endif /* CONFIG_BLK_DEV_INITRD */ + } + } + /* The next use of this field will be after relocation + * is enabled, so convert this physical address into a + * virtual address. + */ + _prom->bi_recs = __va(_prom->bi_recs); } diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/ptrace.c linuxppc64_2_4/arch/ppc64/kernel/ptrace.c --- linux-2.4.9-ac10/arch/ppc64/kernel/ptrace.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/ptrace.c Thu Sep 13 11:54:36 2001 @@ -57,7 +57,7 @@ static inline int put_reg(struct task_struct *task, int regno, unsigned long data) { - if (regno <= PT_MQ) { + if (regno < PT_SOFTE) { if (regno == PT_MSR) data = (data & MSR_DEBUGCHANGE) | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/ptrace32.c linuxppc64_2_4/arch/ppc64/kernel/ptrace32.c --- linux-2.4.9-ac10/arch/ppc64/kernel/ptrace32.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/ptrace32.c Thu Sep 13 11:54:36 2001 @@ -57,7 +57,7 @@ */ static inline int put_reg(struct task_struct *task, int regno, unsigned long data) { - if (regno <= PT_MQ) + if (regno < PT_SOFTE) { if (regno == PT_MSR) data = (data & MSR_DEBUGCHANGE) | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); @@ -319,7 +319,7 @@ if ((addr & 3) || numReg > PT_FPSCR) break; /* Insure it is a register we let them change */ - if ((numReg == PT_ORIG_R3) || ((numReg > PT_MQ) && (numReg < PT_FPR0))) + if ((numReg == PT_ORIG_R3) || ((numReg > PT_CCR) && (numReg < PT_FPR0))) break; if (numReg >= PT_FPR0) diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/kernel/rtas-proc.c linuxppc64_2_4/arch/ppc64/kernel/rtas-proc.c --- linux-2.4.9-ac10/arch/ppc64/kernel/rtas-proc.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/setup.c linuxppc64_2_4/arch/ppc64/kernel/setup.c --- linux-2.4.9-ac10/arch/ppc64/kernel/setup.c Thu Sep 6 14:05:10 2001 +++ linuxppc64_2_4/arch/ppc64/kernel/setup.c Fri Sep 14 13:29:33 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,103 @@ } /* - * 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: - } - - 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("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->dCacheL1LineSize = 0x"); - udbg_puthex(naca->dCacheL1LineSize); - 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->iCacheL1LineSize = 0x"); - udbg_puthex(naca->iCacheL1LineSize); - 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->serialPortAddr = 0x"); - udbg_puthex(naca->serialPortAddr); - 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_puts("\n-----------------------------------------------------\n"); + break; + case _MACH_pSeries: + pSeries_init_early(); + initrd_start = initrd_end = 0; + parse_bootinfo(); + break; + } + 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->physicalMemorySize = 0x"); + udbg_puthex(naca->physicalMemorySize); + 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->dCacheL1LinesPerPage = 0x"); + udbg_puthex(naca->dCacheL1LinesPerPage); + 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->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->interrupt_controller = 0x"); + udbg_puthex(naca->interrupt_controller); + udbg_putc('\n'); + + udbg_printf("\nHTAB Info ...\n\n"); + udbg_puts("htab_data.htab = 0x"); + udbg_puthex(htab_data.htab); + udbg_putc('\n'); + udbg_puts("htab_data.num_ptegs = 0x"); + udbg_puthex(htab_data.htab_num_ptegs); + udbg_putc('\n'); + + udbg_puts("\n-----------------------------------------------------\n"); + + + if ( _machine & _MACH_pSeries ) { + finish_device_tree(); + chrp_init(r3, r4, r5, r6, r7); + } - if ( _machine == _MACH_chrp ) { - finish_device_tree(); - chrp_init(r3, r4, r5, r6, r7); - } + mm_init_ppc64(); - 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 - } + 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 +301,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)) { @@ -394,100 +387,106 @@ * Fetch the cmd_line from open firmware. */ void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - struct device_node *chosen; - char *p; + struct device_node *chosen; + char *p; #ifdef CONFIG_BLK_DEV_INITRD - if (r3 && r4 && r4 != 0xdeadbeef) - { - if (r3 < KERNELBASE) - r3 += KERNELBASE; - initrd_start = r3; - initrd_end = r3 + r4; - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); - initrd_below_start_ok = 1; + if ((initrd_start == 0) && r3 && r4 && r4 != 0xdeadbeef) { + initrd_start = (r3 >= KERNELBASE) ? r3 : __va(r3); + initrd_end = initrd_start + r4; + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_below_start_ok = 1; } #endif - cmd_line[0] = 0; - chosen = find_devices("chosen"); - if (chosen != NULL) { - p = get_property(chosen, "bootargs", NULL); - if (p != NULL) - strncpy(cmd_line, p, sizeof(cmd_line)); - } - cmd_line[sizeof(cmd_line) - 1] = 0; - - /* Look for mem= option on command line */ - if (strstr(cmd_line, "mem=")) { - char *p, *q; - unsigned long maxmem = 0; - extern unsigned long __max_memory; - - for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { - q = p + 4; - if (p > cmd_line && p[-1] != ' ') - continue; - maxmem = simple_strtoul(q, &q, 0); - if (*q == 'k' || *q == 'K') { - maxmem <<= 10; - ++q; - } else if (*q == 'm' || *q == 'M') { - maxmem <<= 20; - ++q; - } - } - __max_memory = maxmem; - } - ppc_md.progress("id mach: done", 0x200); + cmd_line[0] = 0; + chosen = find_devices("chosen"); + if (chosen != NULL) { + p = get_property(chosen, "bootargs", NULL); + if (p != NULL) + strncpy(cmd_line, p, sizeof(cmd_line)); + } + cmd_line[sizeof(cmd_line) - 1] = 0; + + /* Look for mem= option on command line */ + if (strstr(cmd_line, "mem=")) { + char *p, *q; + unsigned long maxmem = 0; + extern unsigned long __max_memory; + + for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { + q = p + 4; + if (p > cmd_line && p[-1] != ' ') + continue; + maxmem = simple_strtoul(q, &q, 0); + if (*q == 'k' || *q == 'K') { + maxmem <<= 10; + ++q; + } else if (*q == 'm' || *q == 'M') { + maxmem <<= 20; + ++q; + } + } + __max_memory = maxmem; + } + ppc_md.progress("id mach: done", 0x200); +} + + +char *bi_tag2str(unsigned long tag) +{ + switch (tag) { + case BI_FIRST: + return "BI_FIRST"; + case BI_LAST: + return "BI_LAST"; + case BI_CMD_LINE: + return "BI_CMD_LINE"; + case BI_BOOTLOADER_ID: + return "BI_BOOTLOADER_ID"; + case BI_INITRD: + return "BI_INITRD"; + case BI_SYSMAP: + return "BI_SYSMAP"; + case BI_MACHTYPE: + return "BI_MACHTYPE"; + default: + return "BI_UNKNOWN"; + } } int parse_bootinfo(void) { -#if 0 - /* DRENG this stuff is needs to be completly redone in the context of - * yaboot. Remove for now - I think we can wait on this for some time. - */ struct bi_record *rec; - extern char __bss_start[]; extern char *sysmap; extern unsigned long sysmap_size; - rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20)); - if ( rec->tag != BI_FIRST ) - { - /* - * This 0x10000 offset is a terrible hack but it will go away when - * we have the bootloader handle all the relocation and - * prom calls -- Cort - */ - rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20)); - if ( rec->tag != BI_FIRST ) - return -1; - } - for ( ; rec->tag != BI_LAST ; - rec = (struct bi_record *)((ulong)rec + rec->size) ) - { - ulong *data = rec->data; - switch (rec->tag) - { + rec = prom.bi_recs; + + if ( rec == NULL || rec->tag != BI_FIRST ) + return -1; + + for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) { + switch (rec->tag) { case BI_CMD_LINE: - memcpy(cmd_line, (void *)data, rec->size); + memcpy(cmd_line, (void *)rec->data, rec->size); break; case BI_SYSMAP: - sysmap = (char *)((data[0] >= (KERNELBASE)) ? data[0] : - (data[0]+KERNELBASE)); - sysmap_size = data[1]; + sysmap = (char *)((rec->data[0] >= (KERNELBASE)) + ? rec->data[0] : __va(rec->data[0])); + sysmap_size = rec->data[1]; break; #ifdef CONFIG_BLK_DEV_INITRD case BI_INITRD: - initrd_start = data[0]; - initrd_end = data[0] + rec->size; + initrd_start = __va(rec->data[0]); + initrd_end = initrd_start + rec->data[1]; + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_below_start_ok = 1; break; #endif /* CONFIG_BLK_DEV_INITRD */ } } -#endif + return 0; } @@ -655,6 +654,20 @@ udbg_puts(" "); udbg_puthex(srr1); udbg_puts("\n"); } +int set_spread_lpevents( char * str ) +{ + /* The parameter is the number of processors to share in processing lp events */ + unsigned long i; + unsigned long val = simple_strtoul( str, NULL, 0 ); + if ( ( val > 0 ) && ( val <= maxPacas ) ) { + for ( i=1; i int smp_threads_ready = 0; volatile int smp_commenced = 0; @@ -79,19 +81,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 +90,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 +176,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 +220,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 +301,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) @@ -481,13 +454,13 @@ #ifdef CONFIG_XMON xmon(0); #endif +#ifdef CONFIG_PPC_ISERIES + HvCall_terminateMachineSrc(); +#endif goto out; } barrier(); udelay(1); -#ifdef CONFIG_PPC_ISERIES - HvCallCfg_getLps(); -#endif } if (wait) { @@ -497,13 +470,13 @@ if (--timeout == 0) { printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); +#ifdef CONFIG_PPC_ISERIES + HvCall_terminateMachineSrc(); +#endif goto out; } barrier(); udelay(1); -#ifdef CONFIG_PPC_ISERIES - HvCallCfg_getLps(); -#endif } } ret = 0; @@ -576,7 +549,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 +563,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 +577,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 +636,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). @@ -688,9 +644,6 @@ * -- Cort */ for ( c = 5000; c && !cpu_callin_map[i] ; c-- ) { -#ifdef CONFIG_PPC_ISERIES - HvCallCfg_getLps(); -#endif udelay(100); } @@ -707,7 +660,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 +684,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(); @@ -745,9 +698,6 @@ cpu_callin_map[cpu] = 1; while(!smp_commenced) { -#ifdef CONFIG_PPC_ISERIES - HvCallCfg_getLps(); -#endif barrier(); } __sti(); @@ -785,7 +735,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-2.4.9-ac10/arch/ppc64/kernel/stab.c linuxppc64_2_4/arch/ppc64/kernel/stab.c --- linux-2.4.9-ac10/arch/ppc64/kernel/stab.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/time.c linuxppc64_2_4/arch/ppc64/kernel/time.c --- linux-2.4.9-ac10/arch/ppc64/kernel/time.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/traps.c linuxppc64_2_4/arch/ppc64/kernel/traps.c --- linux-2.4.9-ac10/arch/ppc64/kernel/traps.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/udbg.c linuxppc64_2_4/arch/ppc64/kernel/udbg.c --- linux-2.4.9-ac10/arch/ppc64/kernel/udbg.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/viopath.c linuxppc64_2_4/arch/ppc64/kernel/viopath.c --- linux-2.4.9-ac10/arch/ppc64/kernel/viopath.c Thu Sep 6 14:05:10 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-2.4.9-ac10/arch/ppc64/kernel/xics.c linuxppc64_2_4/arch/ppc64/kernel/xics.c --- linux-2.4.9-ac10/arch/ppc64/kernel/xics.c Thu Sep 6 14:05:11 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-2.4.9-ac10/arch/ppc64/mm/init.c linuxppc64_2_4/arch/ppc64/mm/init.c --- linux-2.4.9-ac10/arch/ppc64/mm/init.c Thu Sep 6 14:05:11 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-2.4.9-ac10/arch/ppc64/vmlinux.lds linuxppc64_2_4/arch/ppc64/vmlinux.lds --- linux-2.4.9-ac10/arch/ppc64/vmlinux.lds Thu Sep 6 14:05:11 2001 +++ linuxppc64_2_4/arch/ppc64/vmlinux.lds Tue Sep 11 08:55:40 2001 @@ -104,7 +104,6 @@ . = ALIGN(4096); __init_end = .; - . = ALIGN(4096); __chrp_begin = .; .text.chrp : { *(.text.chrp) } .data.chrp : { *(.data.chrp) } @@ -118,8 +117,6 @@ . = ALIGN(4096); __openfirmware_end = .; - - . = ALIGN(4096); __toc_start = .; .toc : { @@ -128,7 +125,6 @@ . = ALIGN(4096); __toc_end = .; - . = ALIGN(4096); __bss_start = .; .bss : { diff -uNr --exclude=CVS linux-2.4.9-ac10/arch/ppc64/xmon/start.c linuxppc64_2_4/arch/ppc64/xmon/start.c --- linux-2.4.9-ac10/arch/ppc64/xmon/start.c Thu Sep 6 14:05:11 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-2.4.9-ac10/arch/ppc64/xmon/xmon.c linuxppc64_2_4/arch/ppc64/xmon/xmon.c --- linux-2.4.9-ac10/arch/ppc64/xmon/xmon.c Thu Sep 6 14:05:11 2001 +++ linuxppc64_2_4/arch/ppc64/xmon/xmon.c Thu Sep 13 12:37:21 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; @@ -2931,8 +2934,8 @@ ((p->thread.regs)->ctr), ((p->thread.regs)->link)); printf(" xer : 0x%16.16lx ccr : 0x%16.16lx\n", ((p->thread.regs)->xer), ((p->thread.regs)->ccr)); - printf(" mq : 0x%16.16lx trap : 0x%16.16lx\n", - ((p->thread.regs)->mq), ((p->thread.regs)->trap)); + printf(" trap : 0x%16.16lx\n", + ((p->thread.regs)->trap)); printf(" dar : 0x%16.16lx dsis : 0x%16.16lx\n", ((p->thread.regs)->dar), ((p->thread.regs)->dsisr)); printf(" rslt : 0x%16.16lx org3 : 0x%16.16lx\n", diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/block/Config.in linuxppc64_2_4/drivers/block/Config.in --- linux-2.4.9-ac10/drivers/block/Config.in Thu Sep 6 14:03:35 2001 +++ linuxppc64_2_4/drivers/block/Config.in Fri Aug 17 13:03:16 2001 @@ -28,6 +28,12 @@ tristate ' Atari SLM laser printer support' CONFIG_ATARI_SLM fi fi +if [ "$CONFIG_PPC_ISERIES" = "y" ]; then + dep_tristate 'iSeries Virtual I/O disk support' CONFIG_VIODASD $CONFIG_PPC_ISERIES + if [ "$CONFIG_VIODASD" = "y" -o "$CONFIG_VIODASD" = "m" ]; then + bool 'iSeries Virtual disk IDE emulation' CONFIG_VIODASD_IDE + fi +fi dep_tristate 'XT hard disk support' CONFIG_BLK_DEV_XD $CONFIG_ISA dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/block/Makefile linuxppc64_2_4/drivers/block/Makefile --- linux-2.4.9-ac10/drivers/block/Makefile Thu Sep 6 14:11:11 2001 +++ linuxppc64_2_4/drivers/block/Makefile Mon Sep 10 10:54:08 2001 @@ -20,6 +20,7 @@ obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o +obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SWIM_IOP) += swim_iop.o obj-$(CONFIG_ATARI_ACSI) += acsi.o obj-$(CONFIG_ATARI_SLM) += acsi_slm.o diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/block/genhd.c linuxppc64_2_4/drivers/block/genhd.c --- linux-2.4.9-ac10/drivers/block/genhd.c Thu Sep 6 14:11:16 2001 +++ linuxppc64_2_4/drivers/block/genhd.c Mon Sep 10 14:04:09 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-2.4.9-ac10/drivers/block/ll_rw_blk.c linuxppc64_2_4/drivers/block/ll_rw_blk.c --- linux-2.4.9-ac10/drivers/block/ll_rw_blk.c Thu Sep 6 14:03:35 2001 +++ linuxppc64_2_4/drivers/block/ll_rw_blk.c Fri Aug 10 13:08:53 2001 @@ -1229,6 +1229,9 @@ #ifdef CONFIG_BLK_DEV_XD xd_init(); #endif +#ifdef CONFIG_VIOCD + viocd_init(); +#endif #ifdef CONFIG_BLK_DEV_MFM mfm_init(); #endif diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/block/viodasd.c linuxppc64_2_4/drivers/block/viodasd.c --- linux-2.4.9-ac10/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-2.4.9-ac10/drivers/cdrom/Config.in linuxppc64_2_4/drivers/cdrom/Config.in --- linux-2.4.9-ac10/drivers/cdrom/Config.in Thu Sep 6 14:03:53 2001 +++ 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-2.4.9-ac10/drivers/cdrom/Makefile linuxppc64_2_4/drivers/cdrom/Makefile --- linux-2.4.9-ac10/drivers/cdrom/Makefile Thu Sep 6 14:03:53 2001 +++ 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-2.4.9-ac10/drivers/cdrom/viocd.c linuxppc64_2_4/drivers/cdrom/viocd.c --- linux-2.4.9-ac10/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-2.4.9-ac10/drivers/char/Config.in linuxppc64_2_4/drivers/char/Config.in --- linux-2.4.9-ac10/drivers/char/Config.in Thu Sep 6 14:03:36 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-2.4.9-ac10/drivers/char/Makefile linuxppc64_2_4/drivers/char/Makefile --- linux-2.4.9-ac10/drivers/char/Makefile Thu Sep 6 14:03:36 2001 +++ linuxppc64_2_4/drivers/char/Makefile Mon Sep 10 13:56:58 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-2.4.9-ac10/drivers/char/n_tty.c linuxppc64_2_4/drivers/char/n_tty.c --- linux-2.4.9-ac10/drivers/char/n_tty.c Thu Sep 6 14:03:36 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-2.4.9-ac10/drivers/char/tty_io.c linuxppc64_2_4/drivers/char/tty_io.c --- linux-2.4.9-ac10/drivers/char/tty_io.c Thu Sep 6 14:03:36 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-2.4.9-ac10/drivers/char/vio.h linuxppc64_2_4/drivers/char/vio.h --- linux-2.4.9-ac10/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-2.4.9-ac10/drivers/char/viocons.c linuxppc64_2_4/drivers/char/viocons.c --- linux-2.4.9-ac10/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 +#include +#include +#include +#include +#include +#include +#include + +#include "vio.h" + +#include +#include "asm/iSeries/HvCallEvent.h" +#include "asm/iSeries/HvLpConfig.h" +#include "asm/iSeries/HvCall.h" +#include + +/* Check that the tty_driver_data actually points to our stuff + */ +#define VIOTTY_PARANOIA_CHECK 1 +#define VIOTTY_MAGIC (0x0DCB) + +static int debug; + +static DECLARE_WAIT_QUEUE_HEAD(viocons_wait_queue); + +static int viotty_major = 229; + +#define VTTY_PORTS 10 +#define VIOTTY_SERIAL_START 65 + +static u64 sndMsgSeq[VTTY_PORTS]; +static u64 sndMsgAck[VTTY_PORTS]; + +static spinlock_t consolelock = SPIN_LOCK_UNLOCKED; + +/* THe structure of the events that flow between us and OS/400. You can't + * mess with this unless the OS/400 side changes too + */ +struct viocharlpevent { + struct HvLpEvent event; + u32 mReserved1; + u16 mVersion; + u16 mSubTypeRc; + u8 virtualDevice; + u8 immediateDataLen; + u8 immediateData[VIOCHAR_MAX_DATA]; +}; + +#define viochar_window (10) +#define viochar_highwatermark (3) + +enum viocharsubtype { + viocharopen = 0x0001, + viocharclose = 0x0002, + viochardata = 0x0003, + viocharack = 0x0004, + viocharconfig = 0x0005 +}; + +enum viochar_rc { + viochar_rc_ebusy = 1 +}; + +/* When we get writes faster than we can send it to the partition, + * buffer the data here. There is one set of buffers for each virtual + * port. + * Note that bufferUsed is a bit map of used buffers. + * It had better have enough bits to hold NUM_BUF + * the bitops assume it is a multiple of unsigned long + */ +#define NUM_BUF (8) +#define OVERFLOW_SIZE VIOCHAR_MAX_DATA + +static struct overflowBuffers { + unsigned long bufferUsed; + u8 *buffer[NUM_BUF]; + int bufferBytes[NUM_BUF]; + int curbuf; + int bufferOverflow; + int overflowMessage; +} overflow[VTTY_PORTS]; + +static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp); + +static struct tty_driver viotty_driver; +static struct tty_driver viottyS_driver; +static int viotty_refcount; + +static struct tty_struct *viotty_table[VTTY_PORTS]; +static struct tty_struct *viottyS_table[VTTY_PORTS]; +static struct termios *viotty_termios[VTTY_PORTS]; +static struct termios *viottyS_termios[VTTY_PORTS]; +static struct termios *viotty_termios_locked[VTTY_PORTS]; +static struct termios *viottyS_termios_locked[VTTY_PORTS]; + +void hvlog(char *fmt, ...) +{ + int i; + static char buf[256]; + va_list args; + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + HvCall_writeLogBuffer(buf, i); + HvCall_writeLogBuffer("\r", 1); + +} + +/* Our port information. We store a pointer to one entry in the + * tty_driver_data + */ +static struct port_info_tag { + int magic; + struct tty_struct *tty; + HvLpIndex lp; + u8 vcons; + u8 port; +} port_info[VTTY_PORTS]; + +/* Make sure we're pointing to a valid port_info structure. Shamelessly + * plagerized from serial.c + */ +static inline int viotty_paranoia_check(struct port_info_tag *pi, + kdev_t device, const char *routine) +{ +#ifdef VIOTTY_PARANOIA_CHECK + static const char *badmagic = + "%s Warning: bad magic number for port_info struct (%s) in %s\n"; + static const char *badinfo = + "%s Warning: null port_info for (%s) in %s\n"; + + if (!pi) { + printk(badinfo, KERN_WARNING_VIO, kdevname(device), + routine); + return 1; + } + if (pi->magic != VIOTTY_MAGIC) { + printk(badmagic, KERN_WARNING_VIO, kdevname(device), + routine); + return 1; + } +#endif + return 0; +} + +/* + * Handle reads from the proc file system. Right now we just dump the + * state of the first TTY + */ +static int proc_read(char *buf, char **start, off_t offset, + int blen, int *eof, void *data) +{ + int len = 0; + struct tty_struct *tty = viotty_table[0]; + struct termios *termios; + if (tty == NULL) { + len += sprintf(buf + len, "no tty\n"); + *eof = 1; + return len; + } + + len += + sprintf(buf + len, + "tty info: COOK_OUT %ld COOK_IN %ld, NO_WRITE_SPLIT %ld\n", + tty->flags & TTY_HW_COOK_OUT, + tty->flags & TTY_HW_COOK_IN, + tty->flags & TTY_NO_WRITE_SPLIT); + + termios = tty->termios; + if (termios == NULL) { + len += sprintf(buf + len, "no termios\n"); + *eof = 1; + return len; + } + len += sprintf(buf + len, "INTR_CHAR %2.2x\n", INTR_CHAR(tty)); + len += sprintf(buf + len, "QUIT_CHAR %2.2x\n", QUIT_CHAR(tty)); + len += + sprintf(buf + len, "ERASE_CHAR %2.2x\n", ERASE_CHAR(tty)); + len += sprintf(buf + len, "KILL_CHAR %2.2x\n", KILL_CHAR(tty)); + len += sprintf(buf + len, "EOF_CHAR %2.2x\n", EOF_CHAR(tty)); + len += sprintf(buf + len, "TIME_CHAR %2.2x\n", TIME_CHAR(tty)); + len += sprintf(buf + len, "MIN_CHAR %2.2x\n", MIN_CHAR(tty)); + len += sprintf(buf + len, "SWTC_CHAR %2.2x\n", SWTC_CHAR(tty)); + len += + sprintf(buf + len, "START_CHAR %2.2x\n", START_CHAR(tty)); + len += sprintf(buf + len, "STOP_CHAR %2.2x\n", STOP_CHAR(tty)); + len += sprintf(buf + len, "SUSP_CHAR %2.2x\n", SUSP_CHAR(tty)); + len += sprintf(buf + len, "EOL_CHAR %2.2x\n", EOL_CHAR(tty)); + len += + sprintf(buf + len, "REPRINT_CHAR %2.2x\n", REPRINT_CHAR(tty)); + len += + sprintf(buf + len, "DISCARD_CHAR %2.2x\n", DISCARD_CHAR(tty)); + len += + sprintf(buf + len, "WERASE_CHAR %2.2x\n", WERASE_CHAR(tty)); + len += + sprintf(buf + len, "LNEXT_CHAR %2.2x\n", LNEXT_CHAR(tty)); + len += sprintf(buf + len, "EOL2_CHAR %2.2x\n", EOL2_CHAR(tty)); + + len += sprintf(buf + len, "I_IGNBRK %4.4x\n", I_IGNBRK(tty)); + len += sprintf(buf + len, "I_BRKINT %4.4x\n", I_BRKINT(tty)); + len += sprintf(buf + len, "I_IGNPAR %4.4x\n", I_IGNPAR(tty)); + len += sprintf(buf + len, "I_PARMRK %4.4x\n", I_PARMRK(tty)); + len += sprintf(buf + len, "I_INPCK %4.4x\n", I_INPCK(tty)); + len += sprintf(buf + len, "I_ISTRIP %4.4x\n", I_ISTRIP(tty)); + len += sprintf(buf + len, "I_INLCR %4.4x\n", I_INLCR(tty)); + len += sprintf(buf + len, "I_IGNCR %4.4x\n", I_IGNCR(tty)); + len += sprintf(buf + len, "I_ICRNL %4.4x\n", I_ICRNL(tty)); + len += sprintf(buf + len, "I_IUCLC %4.4x\n", I_IUCLC(tty)); + len += sprintf(buf + len, "I_IXON %4.4x\n", I_IXON(tty)); + len += sprintf(buf + len, "I_IXANY %4.4x\n", I_IXANY(tty)); + len += sprintf(buf + len, "I_IXOFF %4.4x\n", I_IXOFF(tty)); + len += sprintf(buf + len, "I_IMAXBEL %4.4x\n", I_IMAXBEL(tty)); + + len += sprintf(buf + len, "O_OPOST %4.4x\n", O_OPOST(tty)); + len += sprintf(buf + len, "O_OLCUC %4.4x\n", O_OLCUC(tty)); + len += sprintf(buf + len, "O_ONLCR %4.4x\n", O_ONLCR(tty)); + len += sprintf(buf + len, "O_OCRNL %4.4x\n", O_OCRNL(tty)); + len += sprintf(buf + len, "O_ONOCR %4.4x\n", O_ONOCR(tty)); + len += sprintf(buf + len, "O_ONLRET %4.4x\n", O_ONLRET(tty)); + len += sprintf(buf + len, "O_OFILL %4.4x\n", O_OFILL(tty)); + len += sprintf(buf + len, "O_OFDEL %4.4x\n", O_OFDEL(tty)); + len += sprintf(buf + len, "O_NLDLY %4.4x\n", O_NLDLY(tty)); + len += sprintf(buf + len, "O_CRDLY %4.4x\n", O_CRDLY(tty)); + len += sprintf(buf + len, "O_TABDLY %4.4x\n", O_TABDLY(tty)); + len += sprintf(buf + len, "O_BSDLY %4.4x\n", O_BSDLY(tty)); + len += sprintf(buf + len, "O_VTDLY %4.4x\n", O_VTDLY(tty)); + len += sprintf(buf + len, "O_FFDLY %4.4x\n", O_FFDLY(tty)); + + len += sprintf(buf + len, "C_BAUD %4.4x\n", C_BAUD(tty)); + len += sprintf(buf + len, "C_CSIZE %4.4x\n", C_CSIZE(tty)); + len += sprintf(buf + len, "C_CSTOPB %4.4x\n", C_CSTOPB(tty)); + len += sprintf(buf + len, "C_CREAD %4.4x\n", C_CREAD(tty)); + len += sprintf(buf + len, "C_PARENB %4.4x\n", C_PARENB(tty)); + len += sprintf(buf + len, "C_PARODD %4.4x\n", C_PARODD(tty)); + len += sprintf(buf + len, "C_HUPCL %4.4x\n", C_HUPCL(tty)); + len += sprintf(buf + len, "C_CLOCAL %4.4x\n", C_CLOCAL(tty)); + len += sprintf(buf + len, "C_CRTSCTS %4.4x\n", C_CRTSCTS(tty)); + + len += sprintf(buf + len, "L_ISIG %4.4x\n", L_ISIG(tty)); + len += sprintf(buf + len, "L_ICANON %4.4x\n", L_ICANON(tty)); + len += sprintf(buf + len, "L_XCASE %4.4x\n", L_XCASE(tty)); + len += sprintf(buf + len, "L_ECHO %4.4x\n", L_ECHO(tty)); + len += sprintf(buf + len, "L_ECHOE %4.4x\n", L_ECHOE(tty)); + len += sprintf(buf + len, "L_ECHOK %4.4x\n", L_ECHOK(tty)); + len += sprintf(buf + len, "L_ECHONL %4.4x\n", L_ECHONL(tty)); + len += sprintf(buf + len, "L_NOFLSH %4.4x\n", L_NOFLSH(tty)); + len += sprintf(buf + len, "L_TOSTOP %4.4x\n", L_TOSTOP(tty)); + len += sprintf(buf + len, "L_ECHOCTL %4.4x\n", L_ECHOCTL(tty)); + len += sprintf(buf + len, "L_ECHOPRT %4.4x\n", L_ECHOPRT(tty)); + len += sprintf(buf + len, "L_ECHOKE %4.4x\n", L_ECHOKE(tty)); + len += sprintf(buf + len, "L_FLUSHO %4.4x\n", L_FLUSHO(tty)); + len += sprintf(buf + len, "L_PENDIN %4.4x\n", L_PENDIN(tty)); + len += sprintf(buf + len, "L_IEXTEN %4.4x\n", L_IEXTEN(tty)); + + *eof = 1; + return len; +} + +/* + * Handle writes to our proc file system. Right now just turns on and off + * our debug flag + */ +static int proc_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + if (count) { + if (buffer[0] == '1') { + printk("viocons: debugging on\n"); + debug = 1; + } else { + printk("viocons: debugging off\n"); + debug = 0; + } + } + return count; +} + +/* + * setup our proc file system entries + */ +void viocons_proc_init(struct proc_dir_entry *iSeries_proc) +{ + struct proc_dir_entry *ent; + ent = + create_proc_entry("viocons", S_IFREG | S_IRUSR, iSeries_proc); + if (!ent) + return; + ent->nlink = 1; + ent->data = NULL; + ent->read_proc = proc_read; + ent->write_proc = proc_write; +} + +/* + * clean up our proc file system entries + */ +void viocons_proc_delete(struct proc_dir_entry *iSeries_proc) +{ + remove_proc_entry("viocons", iSeries_proc); +} + +/* + * Add data to our pending-send buffers. + * + * NOTE: Don't use printk in here because it gets nastily recursive. hvlog can be + * used to log to the hypervisor buffer + */ +static int bufferAdd(u8 port, const char *buf, size_t len, int userFlag) +{ + size_t bleft = len; + size_t curlen; + char *cbuf = (char *) buf; + int nextbuf; + struct overflowBuffers *pov = &overflow[port]; + while (bleft > 0) { + /* If there is no space left in the current buffer, we have + * filled everything up, so return. If we filled the previous + * buffer we would already have moved to the next one. + */ + if (pov->bufferBytes[pov->curbuf] == OVERFLOW_SIZE) { + hvlog("buffer %d full. no more space\n", + pov->curbuf); + pov->bufferOverflow++; + pov->overflowMessage = 1; + return len - bleft; + } + + /* Turn on the "used" bit for this buffer. If it's already on, that's + * fine. + */ + set_bit(pov->curbuf, &pov->bufferUsed); + + /* + * See if this buffer has been allocated. If not, allocate it + */ + if (pov->buffer[pov->curbuf] == NULL) + pov->buffer[pov->curbuf] = + kmalloc(OVERFLOW_SIZE, GFP_ATOMIC); + + /* + * Figure out how much we can copy into this buffer + */ + if (bleft < + (OVERFLOW_SIZE - pov->bufferBytes[pov->curbuf])) + curlen = bleft; + else + curlen = + OVERFLOW_SIZE - pov->bufferBytes[pov->curbuf]; + + /* + * Copy the data into the buffer + */ + if (userFlag) + copy_from_user(pov->buffer[pov->curbuf] + + pov->bufferBytes[pov->curbuf], cbuf, + curlen); + else + memcpy(pov->buffer[pov->curbuf] + + pov->bufferBytes[pov->curbuf], cbuf, + curlen); + + pov->bufferBytes[pov->curbuf] += curlen; + cbuf += curlen; + bleft -= curlen; + + /* + * Now see if we've filled this buffer + */ + if (pov->bufferBytes[pov->curbuf] == OVERFLOW_SIZE) { + nextbuf = (pov->curbuf + 1) % NUM_BUF; + + /* + * Move to the next buffer if it hasn't been used yet + */ + if (test_bit(nextbuf, &pov->bufferUsed) == 0) { + pov->curbuf = nextbuf; + } + } + } + return len; +} + +/* Send pending data + * + * NOTE: Don't use printk in here because it gets nastily recursive. hvlog can be + * used to log to the hypervisor buffer + */ +void sendBuffers(u8 port, HvLpIndex lp) +{ + HvLpEvent_Rc hvrc; + int nextbuf; + struct viocharlpevent *viochar; + int flags; + struct overflowBuffers *pov = &overflow[port]; + + spin_lock_irqsave(&consolelock, flags); + + viochar = (struct viocharlpevent *) + vio_get_event_buffer(viomajorsubtype_chario); + + /* Make sure we got a buffer + */ + if (viochar == NULL) { + hvlog("Yikes...can't get viochar buffer"); + spin_unlock_irqrestore(&consolelock, flags); + return; + } + + if (pov->bufferUsed == 0) { + hvlog("in sendbuffers, but no buffers used\n"); + vio_free_event_buffer(viomajorsubtype_chario, viochar); + spin_unlock_irqrestore(&consolelock, flags); + return; + } + + /* + * curbuf points to the buffer we're filling. We want to start sending AFTER + * this one. + */ + nextbuf = (pov->curbuf + 1) % NUM_BUF; + + /* + * Loop until we find a buffer with the bufferUsed bit on + */ + while (test_bit(nextbuf, &pov->bufferUsed) == 0) + nextbuf = (nextbuf + 1) % NUM_BUF; + + initDataEvent(viochar, lp); + + /* + * While we have buffers with data, and our send window is open, send them + */ + while ((test_bit(nextbuf, &pov->bufferUsed)) && + ((sndMsgSeq[port] - sndMsgAck[port]) < viochar_window)) { + viochar->immediateDataLen = pov->bufferBytes[nextbuf]; + viochar->event.xCorrelationToken = sndMsgSeq[port]++; + viochar->event.xSizeMinus1 = + offsetof(struct viocharlpevent, + immediateData) + viochar->immediateDataLen; + + memcpy(viochar->immediateData, pov->buffer[nextbuf], + viochar->immediateDataLen); + + hvrc = HvCallEvent_signalLpEvent(&viochar->event); + if (hvrc) { + /* + * MUST unlock the spinlock before doing a printk + */ + vio_free_event_buffer(viomajorsubtype_chario, + viochar); + spin_unlock_irqrestore(&consolelock, flags); + + printk(KERN_WARNING_VIO + "console error sending event! return code %d\n", + (int) hvrc); + return; + } + + /* + * clear the bufferUsed bit, zero the number of bytes in this buffer, + * and move to the next buffer + */ + clear_bit(nextbuf, &pov->bufferUsed); + pov->bufferBytes[nextbuf] = 0; + nextbuf = (nextbuf + 1) % NUM_BUF; + } + + + /* + * If we have emptied all the buffers, start at 0 again. + * this will re-use any allocated buffers + */ + if (pov->bufferUsed == 0) { + pov->curbuf = 0; + + if (pov->overflowMessage) + pov->overflowMessage = 0; + + if (port_info[port].tty) { + if ((port_info[port].tty-> + flags & (1 << TTY_DO_WRITE_WAKEUP)) + && (port_info[port].tty->ldisc.write_wakeup)) + (port_info[port].tty->ldisc. + write_wakeup) (port_info[port].tty); + wake_up_interruptible(&port_info[port].tty-> + write_wait); + } + } + + vio_free_event_buffer(viomajorsubtype_chario, viochar); + spin_unlock_irqrestore(&consolelock, flags); + +} + +/* Our internal writer. Gets called both from the console device and + * the tty device. the tty pointer will be NULL if called from the console. + * + * NOTE: Don't use printk in here because it gets nastily recursive. hvlog can be + * used to log to the hypervisor buffer + */ +static int internal_write(struct tty_struct *tty, const char *buf, + size_t len, int userFlag) +{ + HvLpEvent_Rc hvrc; + size_t bleft = len; + size_t curlen; + const char *curbuf = buf; + struct viocharlpevent *viochar; + unsigned long flags; + struct port_info_tag *pi = NULL; + HvLpIndex lp; + u8 port; + + if (tty) { + pi = (struct port_info_tag *) tty->driver_data; + + if (!pi + || viotty_paranoia_check(pi, tty->device, + "viotty_internal_write")) + return -ENODEV; + + lp = pi->lp; + port = pi->port; + } else { + /* If this is the console device, use the lp from the first port entry + */ + port = 0; + lp = port_info[0].lp; + } + + /* Always put console output in the hypervisor console log + */ + if (port == 0) + HvCall_writeLogBuffer(buf, len); + + /* If the path to this LP is closed, don't bother doing anything more. + * just dump the data on the floor + */ + if (!viopath_isactive(lp)) + return len; + + /* + * If there is already data queued for this port, send it + */ + if (overflow[port].bufferUsed) + sendBuffers(port, lp); + + spin_lock_irqsave(&consolelock, flags); + + viochar = (struct viocharlpevent *) + vio_get_event_buffer(viomajorsubtype_chario); + /* Make sure we got a buffer + */ + if (viochar == NULL) { + hvlog("Yikes...can't get viochar buffer"); + spin_unlock_irqrestore(&consolelock, flags); + return -1; + } + + initDataEvent(viochar, lp); + + /* Got the lock, don't cause console output */ + while ((bleft > 0) && + (overflow[port].bufferUsed == 0) && + ((sndMsgSeq[port] - sndMsgAck[port]) < viochar_window)) { + if (bleft > VIOCHAR_MAX_DATA) + curlen = VIOCHAR_MAX_DATA; + else + curlen = bleft; + + viochar->immediateDataLen = curlen; + viochar->event.xCorrelationToken = sndMsgSeq[port]++; + + if (userFlag) + copy_from_user(viochar->immediateData, curbuf, + curlen); + else + memcpy(viochar->immediateData, curbuf, curlen); + + viochar->event.xSizeMinus1 = + offsetof(struct viocharlpevent, + immediateData) + curlen; + + hvrc = HvCallEvent_signalLpEvent(&viochar->event); + if (hvrc) { + /* + * MUST unlock the spinlock before doing a printk + */ + vio_free_event_buffer(viomajorsubtype_chario, + viochar); + spin_unlock_irqrestore(&consolelock, flags); + + hvlog("viocons: error sending event! %d\n", + (int) hvrc); + return len - bleft; + } + + curbuf += curlen; + bleft -= curlen; + } + + /* + * If we didn't send it all, buffer it + */ + if (bleft > 0) { + bleft -= bufferAdd(port, curbuf, bleft, userFlag); + } + vio_free_event_buffer(viomajorsubtype_chario, viochar); + spin_unlock_irqrestore(&consolelock, flags); + + return len - bleft; +} + +/* Initialize the common fields in a charLpEvent + */ +static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp) +{ + memset(viochar, 0x00, sizeof(struct viocharlpevent)); + + viochar->event.xFlags.xValid = 1; + viochar->event.xFlags.xFunction = HvLpEvent_Function_Int; + viochar->event.xFlags.xAckInd = HvLpEvent_AckInd_NoAck; + viochar->event.xFlags.xAckType = HvLpEvent_AckType_DeferredAck; + viochar->event.xType = HvLpEvent_Type_VirtualIo; + viochar->event.xSubtype = viomajorsubtype_chario | viochardata; + viochar->event.xSourceLp = HvLpConfig_getLpIndex(); + viochar->event.xTargetLp = lp; + viochar->event.xSizeMinus1 = sizeof(struct viocharlpevent); + viochar->event.xSourceInstanceId = viopath_sourceinst(lp); + viochar->event.xTargetInstanceId = viopath_targetinst(lp); +} + + +/* console device write + */ +static void viocons_write(struct console *co, const char *s, + unsigned count) +{ + /* This parser will ensure that all single instances of either \n or \r are + * matched into carriage return/line feed combinations. It also allows for + * instances where there already exist \n\r combinations as well as the + * reverse, \r\n combinations. + */ + + int index; + char charptr[1]; + int foundcr; + int slicebegin; + int sliceend; + + foundcr = 0; + slicebegin = 0; + sliceend = 0; + + for (index = 0; index < count; index++) { + if (!foundcr && s[index] == 0x0a) { + if ((slicebegin - sliceend > 0) + && sliceend < count) { + internal_write(NULL, &s[slicebegin], + sliceend - slicebegin, 0); + slicebegin = sliceend; + } + charptr[0] = '\r'; + internal_write(NULL, charptr, 1, 0); + } + if (foundcr && s[index] != 0x0a) { + if ((index - 2) >= 0) { + if (s[index - 2] != 0x0a) { + internal_write(NULL, + &s[slicebegin], + sliceend - + slicebegin, 0); + slicebegin = sliceend; + charptr[0] = '\n'; + internal_write(NULL, charptr, 1, + 0); + } + } + } + sliceend++; + + if (s[index] == 0x0d) + foundcr = 1; + else + foundcr = 0; + } + + internal_write(NULL, &s[slicebegin], sliceend - slicebegin, 0); + + if (count > 1) { + if (foundcr == 1 && s[count - 1] != 0x0a) { + charptr[0] = '\n'; + internal_write(NULL, charptr, 1, 0); + } else if (s[count - 1] == 0x0a && s[count - 2] != 0x0d) { + + charptr[0] = '\r'; + internal_write(NULL, charptr, 1, 0); + } + } +} + +/* Work out a the device associate with this console + */ +static kdev_t viocons_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, c->index + viotty_driver.minor_start); +} + +/* console device read method + */ +static int viocons_read(struct console *co, const char *s, unsigned count) +{ + printk(KERN_DEBUG_VIO "viocons_read\n"); + // Implement me + interruptible_sleep_on(&viocons_wait_queue); + return 0; +} + +/* console device wait until a key is pressed + */ +static int viocons_wait_key(struct console *co) +{ + printk(KERN_DEBUG_VIO "In viocons_wait_key\n"); + // Implement me + interruptible_sleep_on(&viocons_wait_queue); + return 0; +} + +/* Do console device setup + */ +static int __init viocons_setup(struct console *co, char *options) +{ + return 0; +} + +/* console device I/O methods + */ +static struct console viocons = { + name:"ttyS", + write:viocons_write, + read:viocons_read, + device:viocons_device, + wait_key:viocons_wait_key, + setup:viocons_setup, + flags:CON_PRINTBUFFER, +}; + + +/* TTY Open method + */ +static int viotty_open(struct tty_struct *tty, struct file *filp) +{ + int port; + unsigned long flags; + MOD_INC_USE_COUNT; + port = MINOR(tty->device) - tty->driver.minor_start; + + if (port >= VIOTTY_SERIAL_START) + port -= VIOTTY_SERIAL_START; + + if ((port < 0) || (port >= VTTY_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + spin_lock_irqsave(&consolelock, flags); + + /* + * If some other TTY is already connected here, reject the open + */ + if ((port_info[port].tty) && (port_info[port].tty != tty)) { + spin_unlock_irqrestore(&consolelock, flags); + MOD_DEC_USE_COUNT; + printk(KERN_WARNING_VIO + "console attempt to open device twice from different ttys\n"); + return -EBUSY; + } + tty->driver_data = &port_info[port]; + port_info[port].tty = tty; + spin_unlock_irqrestore(&consolelock, flags); + + return 0; +} + +/* TTY Close method + */ +static void viotty_close(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + struct port_info_tag *pi = + (struct port_info_tag *) tty->driver_data; + + if (!pi || viotty_paranoia_check(pi, tty->device, "viotty_close")) + return; + + spin_lock_irqsave(&consolelock, flags); + if (tty->count == 1) { + pi->tty = NULL; + } + + spin_unlock_irqrestore(&consolelock, flags); + + MOD_DEC_USE_COUNT; +} + +/* TTY Write method + */ +static int viotty_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + return internal_write(tty, buf, count, from_user); +} + +/* TTY put_char method + */ +static void viotty_put_char(struct tty_struct *tty, unsigned char ch) +{ + internal_write(tty, &ch, 1, 0); +} + +/* TTY flush_chars method + */ +static void viotty_flush_chars(struct tty_struct *tty) +{ +} + +/* TTY write_room method + */ +static int viotty_write_room(struct tty_struct *tty) +{ + int i; + int room = 0; + struct port_info_tag *pi = + (struct port_info_tag *) tty->driver_data; + + if (!pi + || viotty_paranoia_check(pi, tty->device, + "viotty_sendbuffers")) + return 0; + + // If no buffers are used, return the max size + if (overflow[pi->port].bufferUsed == 0) + return VIOCHAR_MAX_DATA * NUM_BUF; + + for (i = 0; ((i < NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++) { + room += + (OVERFLOW_SIZE - overflow[pi->port].bufferBytes[i]); + } + + if (room > VIOCHAR_MAX_DATA) + return VIOCHAR_MAX_DATA; + else + return room; +} + +/* TTY chars_in_buffer_room method + */ +static int viotty_chars_in_buffer(struct tty_struct *tty) +{ + return 0; +} + +static void viotty_flush_buffer(struct tty_struct *tty) +{ +} + +static int viotty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + /* the ioctls below read/set the flags usually shown in the leds */ + /* don't use them - they will go away without warning */ + case KDGETLED: + case KDGKBLED: + return put_user(0, (char *) arg); + + case KDSKBLED: + return 0; + } + + return n_tty_ioctl(tty, file, cmd, arg); +} + +static void viotty_throttle(struct tty_struct *tty) +{ +} + +static void viotty_unthrottle(struct tty_struct *tty) +{ +} + +static void viotty_set_termios(struct tty_struct *tty, + struct termios *old_termios) +{ +} + +static void viotty_stop(struct tty_struct *tty) +{ +} + +static void viotty_start(struct tty_struct *tty) +{ +} + +static void viotty_hangup(struct tty_struct *tty) +{ +} + +static void viotty_break(struct tty_struct *tty, int break_state) +{ +} + +static void viotty_send_xchar(struct tty_struct *tty, char ch) +{ +} + +static void viotty_wait_until_sent(struct tty_struct *tty, int timeout) +{ +} + +/* Handle an open charLpEvent. Could be either interrupt or ack + */ +static void vioHandleOpenEvent(struct HvLpEvent *event) +{ + unsigned long flags; + u8 eventRc; + u16 eventSubtypeRc; + struct viocharlpevent *cevent = (struct viocharlpevent *) event; + u8 port = cevent->virtualDevice; + + if (event->xFlags.xFunction == HvLpEvent_Function_Ack) { + if (port >= VTTY_PORTS) + return; + + spin_lock_irqsave(&consolelock, flags); + /* Got the lock, don't cause console output */ + + if (event->xRc == HvLpEvent_Rc_Good) { + sndMsgSeq[port] = sndMsgAck[port] = 0; + } + + port_info[port].lp = event->xTargetLp; + + spin_unlock_irqrestore(&consolelock, flags); + + if (event->xCorrelationToken != 0) { + unsigned long semptr = event->xCorrelationToken; + up((struct semaphore *) semptr); + } else + printk(KERN_WARNING_VIO + "console: wierd...got open ack without semaphore\n"); + } else { + /* This had better require an ack, otherwise complain + */ + if (event->xFlags.xAckInd != HvLpEvent_AckInd_DoAck) { + printk(KERN_WARNING_VIO + "console: viocharopen without ack bit!\n"); + return; + } + + spin_lock_irqsave(&consolelock, flags); + /* Got the lock, don't cause console output */ + + /* Make sure this is a good virtual tty */ + if (port >= VTTY_PORTS) { + eventRc = HvLpEvent_Rc_SubtypeError; + eventSubtypeRc = viorc_openRejected; + } + + /* If this is tty is already connected to a different + partition, fail */ + else if ((port_info[port].lp != HvLpIndexInvalid) && + (port_info[port].lp != event->xSourceLp)) { + eventRc = HvLpEvent_Rc_SubtypeError; + eventSubtypeRc = viorc_openRejected; + } else { + port_info[port].lp = event->xSourceLp; + eventRc = HvLpEvent_Rc_Good; + eventSubtypeRc = viorc_good; + sndMsgSeq[port] = sndMsgAck[port] = 0; + } + + spin_unlock_irqrestore(&consolelock, flags); + + /* Return the acknowledgement */ + HvCallEvent_ackLpEvent(event); + } +} + +/* Handle a close open charLpEvent. Could be either interrupt or ack + */ +static void vioHandleCloseEvent(struct HvLpEvent *event) +{ + unsigned long flags; + struct viocharlpevent *cevent = (struct viocharlpevent *) event; + u8 port = cevent->virtualDevice; + + if (event->xFlags.xFunction == HvLpEvent_Function_Int) { + if (port >= VTTY_PORTS) + return; + + /* For closes, just mark the console partition invalid */ + spin_lock_irqsave(&consolelock, flags); + /* Got the lock, don't cause console output */ + + if (port_info[port].lp == event->xSourceLp) + port_info[port].lp = HvLpIndexInvalid; + + spin_unlock_irqrestore(&consolelock, flags); + printk(KERN_INFO_VIO + "console close from %d\n", event->xSourceLp); + } else { + printk(KERN_WARNING_VIO + "console got unexpected close acknowlegement\n"); + } +} + +/* Handle a config charLpEvent. Could be either interrupt or ack + */ +static void vioHandleConfig(struct HvLpEvent *event) +{ + struct viocharlpevent *cevent = (struct viocharlpevent *) event; + int len; + + len = cevent->immediateDataLen; + HvCall_writeLogBuffer(cevent->immediateData, + cevent->immediateDataLen); + + if (cevent->immediateData[0] == 0x01) { + printk(KERN_INFO_VIO + "console window resized to %d: %d: %d: %d\n", + cevent->immediateData[1], + cevent->immediateData[2], + cevent->immediateData[3], cevent->immediateData[4]); + } else { + printk(KERN_WARNING_VIO "console unknown config event\n"); + } + return; +} + +/* Handle a data charLpEvent. + */ +static void vioHandleData(struct HvLpEvent *event) +{ + struct tty_struct *tty; + struct viocharlpevent *cevent = (struct viocharlpevent *) event; + struct port_info_tag *pi; + int len; + u8 port = cevent->virtualDevice; + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING_VIO + "console data on invalid virtual device %d\n", + port); + return; + } + + tty = port_info[port].tty; + + if (tty == NULL) { + printk(KERN_WARNING_VIO + "no tty for virtual device %d\n", port); + return; + } + + if (tty->magic != TTY_MAGIC) { + printk(KERN_WARNING_VIO "tty bad magic\n"); + return; + } + + /* + * Just to be paranoid, make sure the tty points back to this port + */ + pi = (struct port_info_tag *) tty->driver_data; + + if (!pi || viotty_paranoia_check(pi, tty->device, "vioHandleData")) + return; + + len = cevent->immediateDataLen; + + if (len == 0) + return; + + /* + * Log port 0 data to the hypervisor log + */ + if (port == 0) + HvCall_writeLogBuffer(cevent->immediateData, + cevent->immediateDataLen); + + /* Don't copy more bytes than there is room for in the buffer */ + if (tty->flip.count + len > TTY_FLIPBUF_SIZE) { + len = TTY_FLIPBUF_SIZE - tty->flip.count; + printk(KERN_WARNING_VIO + "console input buffer overflow!\n"); + } + + memcpy(tty->flip.char_buf_ptr, cevent->immediateData, len); + memset(tty->flip.flag_buf_ptr, TTY_NORMAL, len); + + /* Update the kernel buffer end */ + tty->flip.count += len; + tty->flip.char_buf_ptr += len; + + tty->flip.flag_buf_ptr += len; + + tty_flip_buffer_push(tty); +} + +/* Handle an ack charLpEvent. + */ +static void vioHandleAck(struct HvLpEvent *event) +{ + struct viocharlpevent *cevent = (struct viocharlpevent *) event; + unsigned long flags; + u8 port = cevent->virtualDevice; + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING_VIO + "viocons: data on invalid virtual device\n"); + return; + } + + spin_lock_irqsave(&consolelock, flags); + sndMsgAck[port] = event->xCorrelationToken; + spin_unlock_irqrestore(&consolelock, flags); + + if (overflow[port].bufferUsed) + sendBuffers(port, port_info[port].lp); +} + +/* Handle charLpEvents and route to the appropriate routine + */ +static void vioHandleCharEvent(struct HvLpEvent *event) +{ + int charminor; + + if (event == NULL) { + return; + } + charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; + switch (charminor) { + case viocharopen: + vioHandleOpenEvent(event); + break; + case viocharclose: + vioHandleCloseEvent(event); + break; + case viochardata: + vioHandleData(event); + break; + case viocharack: + vioHandleAck(event); + break; + case viocharconfig: + vioHandleConfig(event); + break; + default: + if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && + (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +/* Send an open event + */ +static int viocons_sendOpen(HvLpIndex remoteLp, u8 port, void *sem) +{ + return HvCallEvent_signalLpEventFast(remoteLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_chario + | viocharopen, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (remoteLp), + viopath_targetinst + (remoteLp), + (u64) (unsigned long) + sem, VIOVERSION << 16, + ((u64) port << 48), 0, 0, 0); + +} + +int __init viocons_init2(void) +{ + DECLARE_MUTEX_LOCKED(Semaphore); + int rc; + + /* + * Now open to the primary LP + */ + printk(KERN_INFO_VIO "console open path to primary\n"); + rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), viomajorsubtype_chario, viochar_window + 2); /* +2 for fudge */ + if (rc) { + printk(KERN_WARNING_VIO + "console error opening to primary %d\n", rc); + } + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + } + + /* + * And if the primary is not the same as the hosting LP, open to the + * hosting lp + */ + if ((viopath_hostLp != HvLpIndexInvalid) && + (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { + printk(KERN_INFO_VIO + "console open path to hosting (%d)\n", + viopath_hostLp); + rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, viochar_window + 2); /* +2 for fudge */ + if (rc) { + printk(KERN_WARNING_VIO + "console error opening to partition %d: %d\n", + viopath_hostLp, rc); + } + } + + if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0) { + printk(KERN_WARNING_VIO + "Error seting handler for console events!\n"); + } + + printk(KERN_INFO_VIO "console major number is %d\n", TTY_MAJOR); + + /* First, try to open the console to the hosting lp. + * Wait on a semaphore for the response. + */ + if ((viopath_isactive(viopath_hostLp)) && + (viocons_sendOpen(viopath_hostLp, 0, &Semaphore) == 0)) { + printk(KERN_INFO_VIO + "opening console to hosting partition %d\n", + viopath_hostLp); + down(&Semaphore); + } + + /* + * If we don't have an active console, try the primary + */ + if ((!viopath_isactive(port_info[0].lp)) && + (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && + (viocons_sendOpen + (HvLpConfig_getPrimaryLpIndex(), 0, &Semaphore) == 0)) { + printk(KERN_INFO_VIO + "opening console to primary partition\n"); + down(&Semaphore); + } + + /* Initialize the tty_driver structure */ + memset(&viotty_driver, 0, sizeof(struct tty_driver)); + viotty_driver.magic = TTY_DRIVER_MAGIC; + viotty_driver.driver_name = "vioconsole"; +#if defined(CONFIG_DEVFS_FS) + viotty_driver.name = "tty%d"; +#else + viotty_driver.name = "tty"; +#endif + viotty_driver.major = TTY_MAJOR; + viotty_driver.minor_start = 1; + viotty_driver.name_base = 1; + viotty_driver.num = VTTY_PORTS; + viotty_driver.type = TTY_DRIVER_TYPE_CONSOLE; + viotty_driver.subtype = 1; + viotty_driver.init_termios = tty_std_termios; + viotty_driver.flags = + TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + viotty_driver.refcount = &viotty_refcount; + viotty_driver.table = viotty_table; + viotty_driver.termios = viotty_termios; + viotty_driver.termios_locked = viotty_termios_locked; + + viotty_driver.open = viotty_open; + viotty_driver.close = viotty_close; + viotty_driver.write = viotty_write; + viotty_driver.put_char = viotty_put_char; + viotty_driver.flush_chars = viotty_flush_chars; + viotty_driver.write_room = viotty_write_room; + viotty_driver.chars_in_buffer = viotty_chars_in_buffer; + viotty_driver.flush_buffer = viotty_flush_buffer; + viotty_driver.ioctl = viotty_ioctl; + viotty_driver.throttle = viotty_throttle; + viotty_driver.unthrottle = viotty_unthrottle; + viotty_driver.set_termios = viotty_set_termios; + viotty_driver.stop = viotty_stop; + viotty_driver.start = viotty_start; + viotty_driver.hangup = viotty_hangup; + viotty_driver.break_ctl = viotty_break; + viotty_driver.send_xchar = viotty_send_xchar; + viotty_driver.wait_until_sent = viotty_wait_until_sent; + + viottyS_driver = viotty_driver; +#if defined(CONFIG_DEVFS_FS) + viottyS_driver.name = "ttyS%d"; +#else + viottyS_driver.name = "ttyS"; +#endif + viottyS_driver.major = TTY_MAJOR; + viottyS_driver.minor_start = VIOTTY_SERIAL_START; + viottyS_driver.type = TTY_DRIVER_TYPE_SERIAL; + viottyS_driver.table = viottyS_table; + viottyS_driver.termios = viottyS_termios; + viottyS_driver.termios_locked = viottyS_termios_locked; + + if (tty_register_driver(&viotty_driver)) { + printk(KERN_WARNING_VIO + "Couldn't register console driver\n"); + } + + if (tty_register_driver(&viottyS_driver)) { + printk(KERN_WARNING_VIO + "Couldn't register console S driver\n"); + } + /* Now create the vcs and vcsa devfs entries so mingetty works */ +#if defined(CONFIG_DEVFS_FS) + { + struct tty_driver temp_driver = viotty_driver; + int i; + + temp_driver.name = "vcs%d"; + for (i = 0; i < VTTY_PORTS; i++) + tty_register_devfs(&temp_driver, + 0, i + temp_driver.minor_start); + + temp_driver.name = "vcsa%d"; + for (i = 0; i < VTTY_PORTS; i++) + tty_register_devfs(&temp_driver, + 0, i + temp_driver.minor_start); + + // For compatibility with some earlier code only! + // This will go away!!! + temp_driver.name = "viocons/%d"; + temp_driver.name_base = 0; + for (i = 0; i < VTTY_PORTS; i++) + tty_register_devfs(&temp_driver, + 0, i + temp_driver.minor_start); + } +#endif + + /* + * Create the proc entry + */ + iSeries_proc_callback(&viocons_proc_init); + + return 0; +} + +void __init viocons_init(void) +{ + int i; + printk(KERN_INFO_VIO "registering console\n"); + + memset(&port_info, 0x00, sizeof(port_info)); + for (i = 0; i < VTTY_PORTS; i++) { + sndMsgSeq[i] = sndMsgAck[i] = 0; + port_info[i].port = i; + port_info[i].lp = HvLpIndexInvalid; + port_info[i].magic = VIOTTY_MAGIC; + } + + register_console(&viocons); + memset(overflow, 0x00, sizeof(overflow)); + debug = 0; + + HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); +} diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/char/viopath.c linuxppc64_2_4/drivers/char/viopath.c --- linux-2.4.9-ac10/drivers/char/viopath.c Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/drivers/char/viopath.c Fri Sep 7 13:45:16 2001 @@ -0,0 +1,606 @@ +/* -*- linux-c -*- + * arch/ppc64/viopath.c + * + * iSeries Virtual I/O Message Path code + * + * Authors: Dave Boutcher + * Ryan Arnold + * Colin Devilbiss + * + * (C) Copyright 2000 IBM Corporation + * + * This code is used by the iSeries virtual disk, cd, + * tape, and console to communicate with OS/400 in another + * partition. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) anyu later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "vio.h" + +/* 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 */ + int users[VIO_MAX_SUBTYPES]; + HvLpInstanceId mSourceInst; + HvLpInstanceId mTargetInst; + int numberAllocated; + unsigned long statuslockFlags; +} viopathStatus[HVMAXARCHITECTEDLPS]; + +static spinlock_t statuslock = SPIN_LOCK_UNLOCKED; +static int statuslockflags; + +/* + * For each kind of event we allocate a buffer that is + * guaranteed not to cross a page boundary + */ +static void *event_buffer[VIO_MAX_SUBTYPES]; +static atomic_t event_buffer_available[VIO_MAX_SUBTYPES]; + +static void handleMonitorEvent(struct HvLpEvent *event); + +/* 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 = 0xff; /* HvLpIndexInvalid */ + +/* For each kind of incoming event we set a pointer to a + * routine to call. + */ +static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES]; + +/* A page to build an lp event in + */ +static 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) +{ + /* Doesn't do anything today!!! + */ + return count; +} + +/* setup our proc file system entries + */ +static 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; +} + +/* See if a given LP is active. Allow for invalid lps to be passed in + * and just return invalid + */ +int viopath_isactive(HvLpIndex lp) +{ + if (lp == HvLpIndexInvalid) + return 0; + if (lp < HVMAXARCHITECTEDLPS) + return viopathStatus[lp].isActive; + else + return 0; +} + +/* We cache the source and target instance ids for each + * partition. + */ +HvLpInstanceId viopath_sourceinst(HvLpIndex lp) +{ + return viopathStatus[lp].mSourceInst; +} + +HvLpInstanceId viopath_targetinst(HvLpIndex lp) +{ + return viopathStatus[lp].mTargetInst; +} + +/* Send a monitor message. This is a message with the acknowledge + * bit on that the other side will NOT explicitly acknowledge. WHen + * the other side goes down, the hypervisor will acknowledge any + * outstanding messages....so we will know when the other side dies. + */ +static void sendMonMsg(HvLpIndex remoteLp) +{ + HvLpEvent_Rc hvrc; + + viopathStatus[remoteLp].mSourceInst = + HvCallEvent_getSourceLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + viopathStatus[remoteLp].mTargetInst = + HvCallEvent_getTargetLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + + /* Deliberately ignore the return code here. if we call this + * more than once, we don't care. + */ + vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent); + + hvrc = HvCallEvent_signalLpEventFast(remoteLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_monitor, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_DeferredAck, + viopathStatus[remoteLp]. + mSourceInst, + viopathStatus[remoteLp]. + mTargetInst, viomonseq++, + 0, 0, 0, 0, 0); + + if (hvrc == HvLpEvent_Rc_Good) { + viopathStatus[remoteLp].isActive = 1; + } else { + printk(KERN_WARNING_VIO + "could not connect ot partition %d\n", remoteLp); + viopathStatus[remoteLp].isActive = 0; + } +} + +static void handleMonitorEvent(struct HvLpEvent *event) +{ + HvLpIndex remoteLp; + int i; + + /* First see if this is just a normal monitor message from the + * other partition + */ + if (event->xFlags.xFunction == HvLpEvent_Function_Int) { + remoteLp = event->xSourceLp; + if (!viopathStatus[remoteLp].isActive) + sendMonMsg(remoteLp); + return; + } + + /* This path is for an acknowledgement; the other partition + * died + */ + remoteLp = event->xTargetLp; + if ((event->xSourceInstanceId != + viopathStatus[remoteLp].mSourceInst) + || (event->xTargetInstanceId != + viopathStatus[remoteLp].mTargetInst)) { + printk(KERN_WARNING_VIO + "ignoring ack....mismatched instances\n"); + return; + } + + printk(KERN_WARNING_VIO "partition %d ended\n", remoteLp); + + viopathStatus[remoteLp].isActive = 0; + + /* For each active handler, pass them a NULL + * message to indicate that the other partition + * died + */ + for (i = 0; i < VIO_MAX_SUBTYPES; i++) { + if (vio_handler[i] != NULL) + (*vio_handler[i]) (NULL); + } +} + +int vio_setHandler(int subtype, vio_event_handler_t * beh) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + + if (vio_handler[subtype] != NULL) + return -EBUSY; + + vio_handler[subtype] = beh; + return 0; +} + +int vio_clearHandler(int subtype) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + + if (vio_handler[subtype] == NULL) + return -EAGAIN; + + vio_handler[subtype] = NULL; + return 0; +} + +static void handleConfig(struct HvLpEvent *event) +{ + if (event->xFlags.xFunction == HvLpEvent_Function_Int) { + printk(KERN_WARNING_VIO + "unexpected config request from partition %d", + event->xSourceLp); + + if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && + (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + up((struct semaphore *) event->xCorrelationToken); +} + +/* Initialization of the hosting partition + */ +void vio_set_hostlp(void) +{ + /* If this has already been set then we DON'T want to either change + * it or re-register the proc file system + */ + if (viopath_hostLp != HvLpIndexInvalid) + return; + + /* Figure out our hosting partition. This isn't allowed to change + * while we're active + */ + viopath_hostLp = + HvCallCfg_getHostingLpIndex(HvLpConfig_getLpIndex()); + + /* If we have a valid hosting LP, create a proc file system entry + * for config information + */ + if (viopath_hostLp != HvLpIndexInvalid) { + iSeries_proc_callback(&vio_proc_init); + vio_setHandler(viomajorsubtype_monitor, handleConfig); + } +} + +static void vio_handleEvent(struct HvLpEvent *event, struct pt_regs *regs) +{ + HvLpIndex remoteLp; + int subtype = + (event-> + xSubtype & VIOMAJOR_SUBTYPE_MASK) >> VIOMAJOR_SUBTYPE_SHIFT; + + if (event->xFlags.xFunction == HvLpEvent_Function_Int) { + remoteLp = event->xSourceLp; + if (event->xSourceInstanceId != + viopathStatus[remoteLp].mTargetInst) { + printk(KERN_WARNING_VIO + "message from invalid partition. " + "int msg rcvd, source inst (%d) doesnt match (%d)\n", + viopathStatus[remoteLp].mTargetInst, + event->xSourceInstanceId); + return; + } + + if (event->xTargetInstanceId != + viopathStatus[remoteLp].mSourceInst) { + printk(KERN_WARNING_VIO + "message from invalid partition. " + "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(KERN_WARNING_VIO + "message from invalid partition. " + "ack msg rcvd, source inst (%d) doesnt match (%d)\n", + viopathStatus[remoteLp].mSourceInst, + event->xSourceInstanceId); + return; + } + + if (event->xTargetInstanceId != + viopathStatus[remoteLp].mTargetInst) { + printk(KERN_WARNING_VIO + "message from invalid partition. " + "viopath: ack msg rcvd, target inst (%d) doesnt match (%d)\n", + viopathStatus[remoteLp].mTargetInst, + event->xTargetInstanceId); + return; + } + } + + if (vio_handler[subtype] == NULL) { + printk(KERN_WARNING_VIO + "unexpected virtual io event subtype %d from partition %d\n", + event->xSubtype, remoteLp); + /* No handler. Ack if necessary + */ + if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && + (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + /* This inocuous little line is where all the real work happens + */ + (*vio_handler[subtype]) (event); +} + +static void viopath_donealloc(void *parm, int number) +{ + struct doneAllocParms_t *doneAllocParmsp = + (struct doneAllocParms_t *) parm; + doneAllocParmsp->number = number; + up(doneAllocParmsp->sem); +} + +static int allocateEvents(HvLpIndex remoteLp, int numEvents) +{ + struct doneAllocParms_t doneAllocParms; + DECLARE_MUTEX_LOCKED(Semaphore); + doneAllocParms.sem = &Semaphore; + + mf_allocateLpEvents(remoteLp, HvLpEvent_Type_VirtualIo, 250, /* It would be nice to put a real number here! */ + numEvents, + &viopath_donealloc, &doneAllocParms); + + down(&Semaphore); + + return doneAllocParms.number; +} + +int viopath_open(HvLpIndex remoteLp, int subtype, int numReq) +{ + int i; + + if ((remoteLp >= HvMaxArchitectedLps) + || (remoteLp == HvLpIndexInvalid)) + return -EINVAL; + + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + + spin_lock_irqsave(&statuslock, statuslockflags); + + /* OK...we can fit 4 maximum-sized events (256 bytes) in + * each page (4096). Get a new page every 4 + */ + if (event_buffer[0] == NULL) { + for (i = 0; i < VIO_MAX_SUBTYPES; i++) { + if ((i % 4) == 0) { + event_buffer[i] = + (void *) get_free_page(GFP_KERNEL); + if (event_buffer[i] == NULL) { + return -ENOMEM; + } + } else { + event_buffer[i] = + event_buffer[i - 1] + 256; + } + atomic_set(&event_buffer_available[i], 1); + } + } + + viopathStatus[remoteLp].users[subtype]++; + + if (!viopathStatus[remoteLp].isOpen) { + HvCallEvent_openLpEventPath(remoteLp, + HvLpEvent_Type_VirtualIo); + + viopathStatus[remoteLp].numberAllocated += + allocateEvents(remoteLp, 1); + + if (viopathStatus[remoteLp].numberAllocated == 0) { + HvCallEvent_closeLpEventPath(remoteLp, + HvLpEvent_Type_VirtualIo); + return -ENOMEM; + } + + viopathStatus[remoteLp].mSourceInst = + HvCallEvent_getSourceLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + viopathStatus[remoteLp].mTargetInst = + HvCallEvent_getTargetLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + + HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo, + &vio_handleEvent); + + viopathStatus[remoteLp].isOpen = 1; + + sendMonMsg(remoteLp); + + printk(KERN_INFO_VIO + "Opening connection to partition %d, setting sinst %d, tinst %d\n", + remoteLp, + viopathStatus[remoteLp].mSourceInst, + viopathStatus[remoteLp].mTargetInst); + } + + viopathStatus[remoteLp].numberAllocated += + allocateEvents(remoteLp, numReq); + spin_unlock_irqrestore(&statuslock, statuslockflags); + + return 0; +} + +int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) +{ + int i; + int numOpen; + struct doneAllocParms_t doneAllocParms; + DECLARE_MUTEX_LOCKED(Semaphore); + doneAllocParms.sem = &Semaphore; + + if ((remoteLp >= HvMaxArchitectedLps) + || (remoteLp == HvLpIndexInvalid)) + return -EINVAL; + + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + + spin_lock_irqsave(&statuslock, statuslockflags); + + mf_deallocateLpEvents( remoteLp,HvLpEvent_Type_VirtualIo, + numReq, + &viopath_donealloc, + &doneAllocParms ); + + for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++) { + numOpen += viopathStatus[remoteLp].users[i]; + } + + if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { + printk(KERN_INFO_VIO + "Closing connection to partition %d", remoteLp); + + HvCallEvent_closeLpEventPath(remoteLp, + HvLpEvent_Type_VirtualIo); + viopathStatus[remoteLp].isOpen = 0; + viopathStatus[remoteLp].isActive = 0; + + for (i = 0; i < VIO_MAX_SUBTYPES; i++) { + atomic_set(&event_buffer_available[i], 0); + + for (i = 0; i < VIO_MAX_SUBTYPES; i += 4) { + free_page((unsigned long) event_buffer[i]); + } + } + + } + + spin_unlock_irqrestore(&statuslock, statuslockflags); + + return 0; +} + +void *vio_get_event_buffer(int subtype) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return NULL; + + if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0) + return event_buffer[subtype]; + else + return NULL; +} + +void vio_free_event_buffer(int subtype, void *buffer) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) { + printk(KERN_WARNING_VIO + "unexpected subtype %d freeing event buffer\n", + subtype); + return; + } + + if (atomic_read(&event_buffer_available[subtype]) != 0) { + printk(KERN_WARNING_VIO + "freeing unallocated event buffer, subtype %d\n", + subtype); + return; + } + + if (buffer != event_buffer[subtype]) { + printk(KERN_WARNING_VIO + "freeing invalid event buffer, subtype %d\n", + subtype); + } + + atomic_set(&event_buffer_available[subtype], 1); +} diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/char/viotape.c linuxppc64_2_4/drivers/char/viotape.c --- linux-2.4.9-ac10/drivers/char/viotape.c Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/drivers/char/viotape.c Fri Sep 7 13:45:16 2001 @@ -0,0 +1,1293 @@ +/* -*- linux-c -*- + * drivers/char/viotape.c + * + * iSeries Virtual Tape + *************************************************************************** + * + * 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 tape drives owned and managed by an OS/400 + * partition running on the same box as this Linux partition. + * + * All tape operations are performed by sending messages back and forth to + * the OS/400 partition. The format of the messages is defined in + * iSeries/vio.h + * + */ + + +#undef VIOT_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vio.h" +#include +#include "asm/iSeries/HvCallEvent.h" +#include "asm/iSeries/HvLpConfig.h" +#include + +static int viotape_major = 230; +static int viotape_numdev = 0; + +#define VIOTAPE_MAXREQ 1 + +/* version number for viotape driver */ +static unsigned int version_major = 1; +static unsigned int version_minor = 0; + +static u64 sndMsgSeq; +static u64 sndMsgAck; +static u64 rcvMsgSeq; +static u64 rcvMsgAck; + +/*************************************************************************** + * The minor number follows the conventions of the SCSI tape drives. The + * rewind and mode are encoded in the minor #. We use this struct to break + * them out + ***************************************************************************/ +struct viot_devinfo_struct { + int major; + int minor; + int devno; + int mode; + int rewind; +}; + +#define VIOTAPOP_RESET 0 +#define VIOTAPOP_FSF 1 +#define VIOTAPOP_BSF 2 +#define VIOTAPOP_FSR 3 +#define VIOTAPOP_BSR 4 +#define VIOTAPOP_WEOF 5 +#define VIOTAPOP_REW 6 +#define VIOTAPOP_NOP 7 +#define VIOTAPOP_EOM 8 +#define VIOTAPOP_ERASE 9 +#define VIOTAPOP_SETBLK 10 +#define VIOTAPOP_SETDENSITY 11 +#define VIOTAPOP_SETPOS 12 +#define VIOTAPOP_GETPOS 13 +#define VIOTAPOP_SETPART 14 + +struct viotapelpevent { + struct HvLpEvent event; + u32 mReserved1; + u16 mVersion; + u16 mSubTypeRc; + u16 mTape; + u16 mFlags; + u32 mToken; + u64 mLen; + union { + struct { + u32 mTapeOp; + u32 mCount; + } tapeOp; + struct { + u32 mType; + u32 mResid; + u32 mDsreg; + u32 mGstat; + u32 mErreg; + u32 mFileNo; + u32 mBlkNo; + } getStatus; + struct { + u32 mBlkNo; + } getPos; + } u; +}; +enum viotapesubtype { + viotapeopen = 0x0001, + viotapeclose = 0x0002, + viotaperead = 0x0003, + viotapewrite = 0x0004, + viotapegetinfo = 0x0005, + viotapeop = 0x0006, + viotapegetpos = 0x0007, + viotapesetpos = 0x0008, + viotapegetstatus = 0x0009 +}; + +enum viotapeRc { + viotape_InvalidRange = 0x0601, + viotape_InvalidToken = 0x0602, + viotape_DMAError = 0x0603, + viotape_UseError = 0x0604, + viotape_ReleaseError = 0x0605, + viotape_InvalidTape = 0x0606, + viotape_InvalidOp = 0x0607, + viotape_TapeErr = 0x0608, + + viotape_AllocTimedOut = 0x0640, + viotape_BOTEnc = 0x0641, + viotape_BlankTape = 0x0642, + viotape_BufferEmpty = 0x0643, + viotape_CleanCartFound = 0x0644, + viotape_CmdNotAllowed = 0x0645, + viotape_CmdNotSupported = 0x0646, + viotape_DataCheck = 0x0647, + viotape_DecompressErr = 0x0648, + viotape_DeviceTimeout = 0x0649, + viotape_DeviceUnavail = 0x064a, + viotape_DeviceBusy = 0x064b, + viotape_EndOfMedia = 0x064c, + viotape_EndOfTape = 0x064d, + viotape_EquipCheck = 0x064e, + viotape_InsufficientRs = 0x064f, + viotape_InvalidLogBlk = 0x0650, + viotape_LengthError = 0x0651, + viotape_LibDoorOpen = 0x0652, + viotape_LoadFailure = 0x0653, + viotape_NotCapable = 0x0654, + viotape_NotOperational = 0x0655, + viotape_NotReady = 0x0656, + viotape_OpCancelled = 0x0657, + viotape_PhyLinkErr = 0x0658, + viotape_RdyNotBOT = 0x0659, + viotape_TapeMark = 0x065a, + viotape_WriteProt = 0x065b +}; + +/* Maximum # tapes we support + */ +#define VIOTAPE_MAX_TAPE 8 +#define MAX_PARTITIONS 4 + +/* defines for current tape state */ +#define VIOT_IDLE 0 +#define VIOT_READING 1 +#define VIOT_WRITING 2 + +/* Our info on the tapes + */ +struct tape_descr { + char rsrcname[10]; + char type[4]; + char model[3]; +}; + +static struct tape_descr *viotape_unitinfo = NULL; + +static char *lasterr[VIOTAPE_MAX_TAPE]; + +static struct mtget viomtget[VIOTAPE_MAX_TAPE]; + +/* maintain the current state of each tape (and partition) + so that we know when to write EOF marks. +*/ +static struct { + unsigned char cur_part; + devfs_handle_t dev_handle; + struct { + unsigned char rwi; + } part_stat[MAX_PARTITIONS]; +} state[VIOTAPE_MAX_TAPE]; + +/* We single-thread + */ +static struct semaphore reqSem; + +/* When we send a request, we use this struct to get the response back + * from the interrupt handler + */ +struct opStruct { + void *buffer; + dma_addr_t dmaaddr; + size_t count; + int rc; + struct semaphore *sem; + struct opStruct *free; +}; + +static spinlock_t opStructListLock; +static struct opStruct *opStructList; + +/* forward declaration to resolve interdependence */ +static int chg_state(int index, unsigned char new_state, + struct file *file); + +/* Decode the kdev_t into its parts + */ +void getDevInfo(kdev_t dev, struct viot_devinfo_struct *devi) +{ + devi->major = MAJOR(dev); + devi->minor = MINOR(dev); + devi->devno = devi->minor & 0x1F; + devi->mode = (devi->minor & 0x60) >> 5; + /* if bit is set in the minor, do _not_ rewind automatically */ + devi->rewind = !(devi->minor & 0x80); +} + + +/* Allocate an op structure from our pool + */ +static struct opStruct *getOpStruct(void) +{ + struct opStruct *newOpStruct; + spin_lock(&opStructListLock); + + if (opStructList == NULL) { + newOpStruct = kmalloc(sizeof(struct opStruct), GFP_KERNEL); + } else { + newOpStruct = opStructList; + opStructList = opStructList->free; + } + + if (newOpStruct) + memset(newOpStruct, 0x00, sizeof(struct opStruct)); + + spin_unlock(&opStructListLock); + + return newOpStruct; +} + +/* Return an op structure to our pool + */ +static void freeOpStruct(struct opStruct *opStruct) +{ + spin_lock(&opStructListLock); + opStruct->free = opStructList; + opStructList = opStruct; + spin_unlock(&opStructListLock); +} + +/* Map our tape return codes to errno values + */ +int tapeRcToErrno(int tapeRc, char *operation, int tapeno) +{ + int terrno; + char *tmsg; + + switch (tapeRc) { + case 0: + return 0; + case viotape_InvalidRange: + terrno = EIO; + tmsg = "Internal error"; + break; + case viotape_InvalidToken: + terrno = EIO; + tmsg = "Internal error"; + break; + case viotape_DMAError: + terrno = EIO; + tmsg = "DMA error"; + break; + case viotape_UseError: + terrno = EIO; + tmsg = "Internal error"; + break; + case viotape_ReleaseError: + terrno = EIO; + tmsg = "Internal error"; + break; + case viotape_InvalidTape: + terrno = EIO; + tmsg = "Invalid tape device"; + break; + case viotape_InvalidOp: + terrno = EIO; + tmsg = "Invalid operation"; + break; + case viotape_TapeErr: + terrno = EIO; + tmsg = "Tape error"; + break; + + case viotape_AllocTimedOut: + terrno = EBUSY; + tmsg = "Allocate timed out"; + break; + case viotape_BOTEnc: + terrno = EIO; + tmsg = "Beginning of tape encountered"; + break; + case viotape_BlankTape: + terrno = EIO; + tmsg = "Blank tape"; + break; + case viotape_BufferEmpty: + terrno = EIO; + tmsg = "Buffer empty"; + break; + case viotape_CleanCartFound: + terrno = ENOMEDIUM; + tmsg = "Cleaning cartridge found"; + break; + case viotape_CmdNotAllowed: + terrno = EIO; + tmsg = "Command not allowed"; + break; + case viotape_CmdNotSupported: + terrno = EIO; + tmsg = "Command not supported"; + break; + case viotape_DataCheck: + terrno = EIO; + tmsg = "Data check"; + break; + case viotape_DecompressErr: + terrno = EIO; + tmsg = "Decompression error"; + break; + case viotape_DeviceTimeout: + terrno = EBUSY; + tmsg = "Device timeout"; + break; + case viotape_DeviceUnavail: + terrno = EIO; + tmsg = "Device unavailable"; + break; + case viotape_DeviceBusy: + terrno = EBUSY; + tmsg = "Device busy"; + break; + case viotape_EndOfMedia: + terrno = ENOSPC; + tmsg = "End of media"; + break; + case viotape_EndOfTape: + terrno = ENOSPC; + tmsg = "End of tape"; + break; + case viotape_EquipCheck: + terrno = EIO; + tmsg = "Equipment check"; + break; + case viotape_InsufficientRs: + terrno = EOVERFLOW; + tmsg = "Insufficient tape resources"; + break; + case viotape_InvalidLogBlk: + terrno = EIO; + tmsg = "Invalid logical block location"; + break; + case viotape_LengthError: + terrno = EOVERFLOW; + tmsg = "Length error"; + break; + case viotape_LibDoorOpen: + terrno = EBUSY; + tmsg = "Door open"; + break; + case viotape_LoadFailure: + terrno = ENOMEDIUM; + tmsg = "Load failure"; + break; + case viotape_NotCapable: + terrno = EIO; + tmsg = "Not capable"; + break; + case viotape_NotOperational: + terrno = EIO; + tmsg = "Not operational"; + break; + case viotape_NotReady: + terrno = EIO; + tmsg = "Not ready"; + break; + case viotape_OpCancelled: + terrno = EIO; + tmsg = "Operation cancelled"; + break; + case viotape_PhyLinkErr: + terrno = EIO; + tmsg = "Physical link error"; + break; + case viotape_RdyNotBOT: + terrno = EIO; + tmsg = "Ready but not beginning of tape"; + break; + case viotape_TapeMark: + terrno = EIO; + tmsg = "Tape mark"; + break; + case viotape_WriteProt: + terrno = EROFS; + tmsg = "Write protection error"; + break; + default: + terrno = EIO; + tmsg = "I/O error"; + } + + printk(KERN_WARNING_VIO "tape error on Device %d (%10.10s): %s\n", + tapeno, viotape_unitinfo[tapeno].rsrcname, tmsg); + + lasterr[tapeno] = tmsg; + + return -terrno; +} + +/* Handle reads from the proc file system. + */ +static int proc_read(char *buf, char **start, off_t offset, + int blen, int *eof, void *data) +{ + int len = 0; + int i; + + len += sprintf(buf + len, "viotape driver version %d.%d\n", + version_major, version_minor); + + for (i = 0; i < viotape_numdev; i++) { + + len += + sprintf(buf + len, + "viotape device %d is iSeries resource %10.10s type %4.4s, model %3.3s\n", + i, viotape_unitinfo[i].rsrcname, + viotape_unitinfo[i].type, + viotape_unitinfo[i].model); + if (lasterr[i]) + len += + sprintf(buf + len, " last error: %s\n", + lasterr[i]); + } + + *eof = 1; + return len; +} + +/* setup our proc file system entries + */ +void viotape_proc_init(struct proc_dir_entry *iSeries_proc) +{ + struct proc_dir_entry *ent; + ent = + create_proc_entry("viotape", 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 viotape_proc_delete(struct proc_dir_entry *iSeries_proc) +{ + remove_proc_entry("viotape", iSeries_proc); +} + + +/* Get info on all tapes from OS/400 + */ +static void get_viotape_info(void) +{ + dma_addr_t dmaaddr; + HvLpEvent_Rc hvrc; + int i; + struct opStruct *op = getOpStruct(); + DECLARE_MUTEX_LOCKED(Semaphore); + if (op == NULL) + return; + + if (viotape_unitinfo == NULL) { + viotape_unitinfo = + kmalloc(sizeof(struct tape_descr) * VIOTAPE_MAX_TAPE, + GFP_KERNEL); + } + memset(viotape_unitinfo, 0x00, + sizeof(struct tape_descr) * VIOTAPE_MAX_TAPE); + memset(lasterr, 0x00, sizeof(lasterr)); + + op->sem = &Semaphore; + + dmaaddr = pci_map_single(NULL, viotape_unitinfo, + sizeof(struct tape_descr) * + VIOTAPE_MAX_TAPE, PCI_DMA_FROMDEVICE); + if (dmaaddr == 0xFFFFFFFF) { + printk(KERN_WARNING_VIO "viotape error allocating tce\n"); + return; + } + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | + viotapegetinfo, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned long) op, + VIOVERSION << 16, dmaaddr, + sizeof(struct tape_descr) * + VIOTAPE_MAX_TAPE, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk("viotape hv error on op %d\n", (int) hvrc); + } + + down(&Semaphore); + + freeOpStruct(op); + + + for (i = 0; + ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0])); + i++) { + printk("found a tape %10.10s\n", + viotape_unitinfo[i].rsrcname); + viotape_numdev++; + } +} + + +/* Write + */ +static ssize_t viotap_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + HvLpEvent_Rc hvrc; + kdev_t dev = file->f_dentry->d_inode->i_rdev; + unsigned short flags = file->f_flags; + struct opStruct *op = getOpStruct(); + int noblock = ((flags & O_NONBLOCK) != 0); + int err; + struct viot_devinfo_struct devi; + DECLARE_MUTEX_LOCKED(Semaphore); + + if (op == NULL) + return -ENOMEM; + + getDevInfo(dev, &devi); + + /* We need to make sure we can send a request. We use + * a semaphore to keep track of # requests in use. If + * we are non-blocking, make sure we don't block on the + * semaphore + */ + if (noblock) { + if (down_trylock(&reqSem)) { + freeOpStruct(op); + return -EWOULDBLOCK; + } + } else { + down(&reqSem); + } + + /* Allocate a DMA buffer */ + op->buffer = pci_alloc_consistent(NULL, count, &op->dmaaddr); + + if ((op->dmaaddr == 0xFFFFFFFF) || (op->buffer == NULL)) { + printk(KERN_WARNING_VIO + "tape error allocating dma buffer for len %ld\n", + count); + freeOpStruct(op); + up(&reqSem); + return -EFAULT; + } + + op->count = count; + + /* Copy the data into the buffer */ + err = copy_from_user(op->buffer, (const void *) buf, count); + if (err) { + printk(KERN_WARNING_VIO + "tape: error on copy from user\n"); + pci_free_consistent(NULL, count, op->buffer, op->dmaaddr); + freeOpStruct(op); + up(&reqSem); + return -EFAULT; + } + + if (noblock) { + op->sem = NULL; + } else { + op->sem = &Semaphore; + } + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | + viotapewrite, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned long) op, + VIOVERSION << 16, + ((u64) devi. + devno << 48) | op->dmaaddr, + count, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk("viotape hv error on op %d\n", (int) hvrc); + pci_free_consistent(NULL, count, op->buffer, op->dmaaddr); + freeOpStruct(op); + up(&reqSem); + return -EIO; + } + + if (noblock) + return count; + + down(&Semaphore); + + err = op->rc; + + /* Free the buffer */ + pci_free_consistent(NULL, count, op->buffer, op->dmaaddr); + + count = op->count; + + freeOpStruct(op); + up(&reqSem); + if (err) + return tapeRcToErrno(err, "write", devi.devno); + else { + chg_state(devi.devno, VIOT_WRITING, file); + return count; + } +} + +/* read + */ +static ssize_t viotap_read(struct file *file, char *buf, size_t count, + loff_t * ptr) +{ + HvLpEvent_Rc hvrc; + kdev_t dev = file->f_dentry->d_inode->i_rdev; + unsigned short flags = file->f_flags; + struct opStruct *op = getOpStruct(); + int noblock = ((flags & O_NONBLOCK) != 0); + int err; + struct viot_devinfo_struct devi; + DECLARE_MUTEX_LOCKED(Semaphore); + + if (op == NULL) + return -ENOMEM; + + getDevInfo(dev, &devi); + + /* We need to make sure we can send a request. We use + * a semaphore to keep track of # requests in use. If + * we are non-blocking, make sure we don't block on the + * semaphore + */ + if (noblock) { + if (down_trylock(&reqSem)) { + freeOpStruct(op); + return -EWOULDBLOCK; + } + } else { + down(&reqSem); + } + + chg_state(devi.devno, VIOT_READING, file); + + /* Allocate a DMA buffer */ + op->buffer = pci_alloc_consistent(NULL, count, &op->dmaaddr); + + if ((op->dmaaddr == 0xFFFFFFFF) || (op->buffer == NULL)) { + freeOpStruct(op); + up(&reqSem); + return -EFAULT; + } + + op->count = count; + + op->sem = &Semaphore; + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | + viotaperead, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned long) op, + VIOVERSION << 16, + ((u64) devi. + devno << 48) | op->dmaaddr, + count, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING_VIO + "tape hv error on op %d\n", (int) hvrc); + pci_free_consistent(NULL, count, op->buffer, op->dmaaddr); + freeOpStruct(op); + up(&reqSem); + return -EIO; + } + + down(&Semaphore); + + if (op->rc == 0) { + /* If we got data back */ + if (op->count) { + /* Copy the data into the buffer */ + err = copy_to_user(buf, op->buffer, count); + if (err) { + printk("error on copy_to_user\n"); + pci_free_consistent(NULL, count, + op->buffer, + op->dmaaddr); + freeOpStruct(op); + up(&reqSem); + return -EFAULT; + } + } + } + + err = op->rc; + + /* Free the buffer */ + pci_free_consistent(NULL, count, op->buffer, op->dmaaddr); + count = op->count; + + freeOpStruct(op); + up(&reqSem); + if (err) + return tapeRcToErrno(err, "read", devi.devno); + else + return count; +} + +/* read + */ +static int viotap_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + HvLpEvent_Rc hvrc; + int err; + DECLARE_MUTEX_LOCKED(Semaphore); + kdev_t dev = file->f_dentry->d_inode->i_rdev; + struct opStruct *op = getOpStruct(); + struct viot_devinfo_struct devi; + if (op == NULL) + return -ENOMEM; + + getDevInfo(dev, &devi); + + down(&reqSem); + + switch (cmd) { + case MTIOCTOP:{ + struct mtop mtc; + u32 myOp; + + /* inode is null if and only if we (the kernel) made the request */ + if (inode == NULL) + memcpy(&mtc, (void *) arg, + sizeof(struct mtop)); + else if (copy_from_user + ((char *) &mtc, (char *) arg, + sizeof(struct mtop))) { + freeOpStruct(op); + up(&reqSem); + return -EFAULT; + } + + switch (mtc.mt_op) { + case MTRESET: + myOp = VIOTAPOP_RESET; + break; + case MTFSF: + myOp = VIOTAPOP_FSF; + break; + case MTBSF: + myOp = VIOTAPOP_BSF; + break; + case MTFSR: + myOp = VIOTAPOP_FSR; + break; + case MTBSR: + myOp = VIOTAPOP_BSR; + break; + case MTWEOF: + myOp = VIOTAPOP_WEOF; + break; + case MTREW: + myOp = VIOTAPOP_REW; + break; + case MTNOP: + myOp = VIOTAPOP_NOP; + break; + case MTEOM: + myOp = VIOTAPOP_EOM; + break; + case MTERASE: + myOp = VIOTAPOP_ERASE; + break; + case MTSETBLK: + myOp = VIOTAPOP_SETBLK; + break; + case MTSETDENSITY: + myOp = VIOTAPOP_SETDENSITY; + break; + case MTTELL: + myOp = VIOTAPOP_GETPOS; + break; + case MTSEEK: + myOp = VIOTAPOP_SETPOS; + break; + case MTSETPART: + myOp = VIOTAPOP_SETPART; + break; + default: + return -EIO; + } + +/* if we moved the head, we are no longer reading or writing */ + switch (mtc.mt_op) { + case MTFSF: + case MTBSF: + case MTFSR: + case MTBSR: + case MTTELL: + case MTSEEK: + case MTREW: + chg_state(devi.devno, VIOT_IDLE, file); + } + + op->sem = &Semaphore; + hvrc = + HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape + | viotapeop, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned + long) op, + VIOVERSION << 16, + ((u64) devi. + devno << 48), 0, + (((u64) myOp) << + 32) | mtc. + mt_count, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk("viotape hv error on op %d\n", + (int) hvrc); + freeOpStruct(op); + up(&reqSem); + return -EIO; + } + down(&Semaphore); + if (op->rc) { + freeOpStruct(op); + up(&reqSem); + return tapeRcToErrno(op->rc, + "tape operation", + devi.devno); + } else { + freeOpStruct(op); + up(&reqSem); + return 0; + } + break; + } + + case MTIOCGET: + op->sem = &Semaphore; + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | + viotapegetstatus, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned long) + op, VIOVERSION << 16, + ((u64) devi. + devno << 48), 0, 0, + 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk("viotape hv error on op %d\n", (int) hvrc); + freeOpStruct(op); + up(&reqSem); + return -EIO; + } + down(&Semaphore); + up(&reqSem); + if (op->rc) { + freeOpStruct(op); + return tapeRcToErrno(op->rc, "get status", + devi.devno); + } else { + freeOpStruct(op); + err = + copy_to_user((void *) arg, &viomtget[dev], + sizeof(viomtget[0])); + if (err) { + freeOpStruct(op); + return -EFAULT; + } + return 0; + } + break; + case MTIOCPOS: + printk("Got an MTIOCPOS\n"); + default: + return -ENOSYS; + } + return 0; +} + +/* Open + */ +static int viotap_open(struct inode *inode, struct file *file) +{ + DECLARE_MUTEX_LOCKED(Semaphore); + kdev_t dev = file->f_dentry->d_inode->i_rdev; + HvLpEvent_Rc hvrc; + struct opStruct *op = getOpStruct(); + struct viot_devinfo_struct devi; + if (op == NULL) + return -ENOMEM; + + getDevInfo(dev, &devi); + +// Note: We currently only support one mode! + if ((devi.devno >= viotape_numdev) || (devi.mode)) { + freeOpStruct(op); + return -ENODEV; + } + + op->sem = &Semaphore; + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | + viotapeopen, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned long) op, + VIOVERSION << 16, + ((u64) devi.devno << 48), 0, + 0, 0); + + + if (hvrc != 0) { + printk("viotape bad rc on signalLpEvent %d\n", (int) hvrc); + freeOpStruct(op); + return -EIO; + } + + down(&Semaphore); + + if (op->rc) { + freeOpStruct(op); + return tapeRcToErrno(op->rc, "open", devi.devno); + } else { + freeOpStruct(op); + MOD_INC_USE_COUNT; + return 0; + } +} + + +/* Release + */ +static int viotap_release(struct inode *inode, struct file *file) +{ + DECLARE_MUTEX_LOCKED(Semaphore); + kdev_t dev = file->f_dentry->d_inode->i_rdev; + HvLpEvent_Rc hvrc; + struct viot_devinfo_struct devi; + struct opStruct *op = getOpStruct(); + + if (op == NULL) + return -ENOMEM; + op->sem = &Semaphore; + + getDevInfo(dev, &devi); + + if (devi.devno >= viotape_numdev) { + freeOpStruct(op); + return -ENODEV; + } + + chg_state(devi.devno, VIOT_IDLE, file); + + if (devi.rewind) { + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | + viotapeop, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned long) + op, VIOVERSION << 16, + ((u64) devi. + devno << 48), 0, + ((u64) VIOTAPOP_REW) + << 32, 0); + down(&Semaphore); + + if (op->rc) { + tapeRcToErrno(op->rc, "rewind", devi.devno); + } + } + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | + viotapeclose, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst + (viopath_hostLp), + viopath_targetinst + (viopath_hostLp), + (u64) (unsigned long) op, + VIOVERSION << 16, + ((u64) devi.devno << 48), 0, + 0, 0); + + + if (hvrc != 0) { + printk("viotape: bad rc on signalLpEvent %d\n", + (int) hvrc); + return -EIO; + } + + down(&Semaphore); + + if (op->rc) { + printk("viotape: close failed\n"); + } + MOD_DEC_USE_COUNT; + return 0; +} + +struct file_operations viotap_fops = { + owner:THIS_MODULE, + read:viotap_read, + write:viotap_write, + ioctl:viotap_ioctl, + open:viotap_open, + release:viotap_release, +}; + +/* Handle interrupt events for tape + */ +static void vioHandleTapeEvent(struct HvLpEvent *event) +{ + int tapeminor; + struct opStruct *op; + struct viotapelpevent *tevent = (struct viotapelpevent *) event; + + if (event == NULL) { + /* Notification that a partition went away! */ + if (!viopath_isactive(viopath_hostLp)) { + /* TODO! Clean up */ + } + return; + } + + tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; + switch (tapeminor) { + case viotapegetinfo: + case viotapeopen: + case viotapeclose: + op = (struct opStruct *) (unsigned long) event-> + xCorrelationToken; + op->rc = tevent->mSubTypeRc; + up(op->sem); + break; + case viotaperead: + case viotapewrite: + op = (struct opStruct *) (unsigned long) event-> + xCorrelationToken; + op->rc = tevent->mSubTypeRc;; + op->count = tevent->mLen; + + if (op->sem) { + up(op->sem); + } else { + freeOpStruct(op); + up(&reqSem); + } + break; + case viotapeop: + case viotapegetpos: + case viotapesetpos: + case viotapegetstatus: + op = (struct opStruct *) (unsigned long) event-> + xCorrelationToken; + if (op) { + op->count = tevent->u.tapeOp.mCount; + op->rc = tevent->mSubTypeRc;; + + if (op->sem) { + up(op->sem); + } + } + break; + default: + printk("viotape: wierd ack\n"); + } +} + + +/* Do initialization + */ +int __init viotap_init(void) +{ + DECLARE_MUTEX_LOCKED(Semaphore); + int rc; + char tapename[32]; + int i; + + printk("viotape driver version %d.%d\n", version_major, + version_minor); + + sndMsgSeq = sndMsgAck = 0; + rcvMsgSeq = rcvMsgAck = 0; + opStructList = NULL; + spin_lock_init(&opStructListLock); + + sema_init(&reqSem, VIOTAPE_MAXREQ); + + if (viopath_hostLp == HvLpIndexInvalid) + vio_set_hostlp(); + + /* + * Open to our hosting lp + */ + if (viopath_hostLp == HvLpIndexInvalid) + return -1; + + printk("viotape: init - open path to hosting (%d)\n", + viopath_hostLp); + + rc = viopath_open(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); + if (rc) { + printk("viotape: error on viopath_open to hostlp %d\n", + rc); + } + + vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent); + + printk("viotape major is %d\n", viotape_major); + + get_viotape_info(); + + if (devfs_register_chrdev(viotape_major, "viotape", &viotap_fops)) { + printk("Error registering viotape device\n"); + return -1; + } + + for (i = 0; i < viotape_numdev; i++) { + int j; + state[i].cur_part = 0; + for (j = 0; j < MAX_PARTITIONS; ++j) + state[i].part_stat[j].rwi = VIOT_IDLE; + sprintf(tapename, "viotape%d", i); + state[i].dev_handle = + devfs_register(NULL, tapename, DEVFS_FL_DEFAULT, + viotape_major, i, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP, &viotap_fops, NULL); + printk + ("viotape device %s is iSeries resource %10.10s type %4.4s, model %3.3s\n", + tapename, viotape_unitinfo[i].rsrcname, + viotape_unitinfo[i].type, viotape_unitinfo[i].model); + } + + /* + * Create the proc entry + */ + iSeries_proc_callback(&viotape_proc_init); + + return 0; +} + +/* Give a new state to the tape object + */ +static int chg_state(int index, unsigned char new_state, struct file *file) +{ + unsigned char *cur_state = + &state[index].part_stat[state[index].cur_part].rwi; + int rc = 0; + + /* if the same state, don't bother */ + if (*cur_state == new_state) + return 0; + + /* write an EOF if changing from writing to some other state */ + if (*cur_state == VIOT_WRITING) { + struct mtop write_eof = { MTWEOF, 1 }; + rc = viotap_ioctl(NULL, file, MTIOCTOP, + (unsigned long) &write_eof); + } + *cur_state = new_state; + return rc; +} + +/* Cleanup + */ +static void __exit viotap_exit(void) +{ + int i, ret; + for (i = 0; i < viotape_numdev; ++i) + devfs_unregister(state[i].dev_handle); + ret = devfs_unregister_chrdev(viotape_major, "viotape"); + if (ret < 0) + printk("Error unregistering device: %d\n", ret); + iSeries_proc_callback(&viotape_proc_delete); + if (viotape_unitinfo != NULL) { + kfree(viotape_unitinfo); + viotape_unitinfo = NULL; + } + viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); + vio_clearHandler(viomajorsubtype_tape); +} + +module_init(viotap_init); +module_exit(viotap_exit); diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/net/Space.c linuxppc64_2_4/drivers/net/Space.c --- linux-2.4.9-ac10/drivers/net/Space.c Thu Sep 6 14:03:27 2001 +++ linuxppc64_2_4/drivers/net/Space.c Tue Sep 4 14:09:18 2001 @@ -537,9 +537,10 @@ -#ifdef CONFIG_TR +#if 0 /* ifdef CONFIG_TR */ /* Token-ring device probe */ extern int ibmtr_probe(struct net_device *); +extern int olympic_probe(struct net_device *); extern int smctr_probe(struct net_device *); static int @@ -548,6 +549,9 @@ if (1 #ifdef CONFIG_IBMTR && ibmtr_probe(dev) +#endif +#ifdef CONFIG_IBMOL + && olympic_probe(dev) #endif #ifdef CONFIG_SMCTR && smctr_probe(dev) diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/net/acenic.c linuxppc64_2_4/drivers/net/acenic.c --- linux-2.4.9-ac10/drivers/net/acenic.c Thu Sep 6 14:03:28 2001 +++ linuxppc64_2_4/drivers/net/acenic.c Wed Aug 22 08:27:45 2001 @@ -120,30 +120,6 @@ #define PCI_DEVICE_ID_SGI_ACENIC 0x0009 #endif -#if LINUX_VERSION_CODE >= 0x20400 -static struct pci_device_id acenic_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, - { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C985, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, - { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, - { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, - /* - * Farallon used the DEC vendor ID on their cards incorrectly. - */ - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, - { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, - { } -}; -MODULE_DEVICE_TABLE(pci, acenic_pci_tbl); -#endif - #ifndef wmb #define wmb() mb() @@ -521,230 +497,188 @@ "acenic.c: v0.81 04/20/2001 Jes Sorensen, linux-acenic@SunSITE.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; -static struct net_device *root_dev; - -static int probed __initdata = 0; - - -int __devinit acenic_probe (ACE_PROBE_ARG) +static int __devinit acenic_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { -#ifdef NEW_NETINIT struct net_device *dev; -#endif - struct ace_private *ap; - struct pci_dev *pdev = NULL; int boards_found = 0; int version_disp; - if (probed) - return -ENODEV; - probed++; - if (!pci_present()) /* is PCI support present? */ return -ENODEV; version_disp = 0; - while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) { + dev = init_etherdev(NULL, sizeof(struct ace_private)); - if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) && - ((pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE) || - (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_COPPER)))&& - !((pdev->vendor == PCI_VENDOR_ID_3COM) && - (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && - !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && - ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) || - (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) && - /* - * Farallon used the DEC vendor ID on their cards by - * mistake for a while - */ - !((pdev->vendor == PCI_VENDOR_ID_DEC) && - (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) && - !((pdev->vendor == PCI_VENDOR_ID_SGI) && - (pdev->device == PCI_DEVICE_ID_SGI_ACENIC))) - continue; - - dev = init_etherdev(NULL, sizeof(struct ace_private)); - - if (dev == NULL) { - printk(KERN_ERR "acenic: Unable to allocate " - "net_device structure!\n"); - break; - } + if (dev == NULL) { + printk(KERN_ERR "acenic: Unable to allocate " + "net_device structure!\n"); + return -ENODEV; + } - SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(dev); - if (!dev->priv) - dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL); - if (!dev->priv) { - printk(KERN_ERR "acenic: Unable to allocate memory\n"); - return -ENOMEM; - } - - ap = dev->priv; - ap->pdev = pdev; - - dev->irq = pdev->irq; - dev->open = &ace_open; - dev->hard_start_xmit = &ace_start_xmit; - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; - if (1) { - static void ace_watchdog(struct net_device *dev); - dev->tx_timeout = &ace_watchdog; - dev->watchdog_timeo = 5*HZ; - } - dev->stop = &ace_close; - dev->get_stats = &ace_get_stats; - dev->set_multicast_list = &ace_set_multicast_list; - dev->do_ioctl = &ace_ioctl; - dev->set_mac_address = &ace_set_mac_addr; - dev->change_mtu = &ace_change_mtu; + if (!dev->priv) + dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL); + if (!dev->priv) { + printk(KERN_ERR "acenic: Unable to allocate memory\n"); + return -ENOMEM; + } - /* display version info if adapter is found */ - if (!version_disp) - { - /* set display flag to TRUE so that */ - /* we only display this string ONCE */ - version_disp = 1; - printk(version); - } + ap = dev->priv; + ap->pdev = pdev; - /* - * Enable master mode before we start playing with the - * pci_command word since pci_set_master() will modify - * it. - */ - pci_set_master(pdev); + dev->irq = pdev->irq; + dev->open = &ace_open; + dev->hard_start_xmit = &ace_start_xmit; + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + if (1) { + static void ace_watchdog(struct net_device *dev); + dev->tx_timeout = &ace_watchdog; + dev->watchdog_timeo = 5*HZ; + } + dev->stop = &ace_close; + dev->get_stats = &ace_get_stats; + dev->set_multicast_list = &ace_set_multicast_list; + dev->do_ioctl = &ace_ioctl; + dev->set_mac_address = &ace_set_mac_addr; + dev->change_mtu = &ace_change_mtu; - pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); + /* display version info if adapter is found */ + if (!version_disp) + { + /* set display flag to TRUE so that */ + /* we only display this string ONCE */ + version_disp = 1; + printk(version); + } - /* OpenFirmware on Mac's does not set this - DOH.. */ - if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { - printk(KERN_INFO "%s: Enabling PCI Memory Mapped " - "access - was not enabled by BIOS/Firmware\n", - dev->name); - ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY; - pci_write_config_word(ap->pdev, PCI_COMMAND, - ap->pci_command); - wmb(); - } + /* + * Enable master mode before we start playing with the + * pci_command word since pci_set_master() will modify + * it. + */ + pci_set_master(pdev); - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, - &ap->pci_latency); - if (ap->pci_latency <= 0x40) { - ap->pci_latency = 0x40; - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, - ap->pci_latency); - } + pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); - /* - * Remap the regs into kernel space - this is abuse of - * dev->base_addr since it was means for I/O port - * addresses but who gives a damn. - */ - dev->base_addr = pci_resource_start(pdev, 0); - ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); - if (!ap->regs) { - printk(KERN_ERR "%s: Unable to map I/O register, " - "AceNIC %i will be disabled.\n", - dev->name, boards_found); - break; - } + /* OpenFirmware on Mac's does not set this - DOH.. */ + if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { + printk(KERN_INFO "%s: Enabling PCI Memory Mapped " + "access - was not enabled by BIOS/Firmware\n", + dev->name); + ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY; + pci_write_config_word(ap->pdev, PCI_COMMAND, + ap->pci_command); + wmb(); + } - switch(pdev->vendor) { - case PCI_VENDOR_ID_ALTEON: - strncpy(ap->name, "AceNIC Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: Alteon AceNIC ", dev->name); - break; - case PCI_VENDOR_ID_3COM: - strncpy(ap->name, "3Com 3C985 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); - break; - case PCI_VENDOR_ID_NETGEAR: - strncpy(ap->name, "NetGear GA620 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: NetGear GA620 ", dev->name); - break; - case PCI_VENDOR_ID_DEC: - if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { - strncpy(ap->name, "Farallon PN9000-SX " - "Gigabit Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: Farallon PN9000-SX ", - dev->name); - break; - } - case PCI_VENDOR_ID_SGI: - strncpy(ap->name, "SGI AceNIC Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: SGI AceNIC ", dev->name); - break; - default: - strncpy(ap->name, "Unknown AceNIC based Gigabit " - "Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, + &ap->pci_latency); + if (ap->pci_latency <= 0x40) { + ap->pci_latency = 0x40; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + ap->pci_latency); + } + + /* + * Remap the regs into kernel space - this is abuse of + * dev->base_addr since it was means for I/O port + * addresses but who gives a damn. + */ + dev->base_addr = pci_resource_start(pdev, 0); + ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); + if (!ap->regs) { + printk(KERN_ERR "%s: Unable to map I/O register, " + "AceNIC %i will be disabled.\n", + dev->name, boards_found); + return -ENODEV; + } + + switch(pdev->vendor) { + case PCI_VENDOR_ID_ALTEON: + strncpy(ap->name, "AceNIC Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: Alteon AceNIC ", dev->name); + break; + case PCI_VENDOR_ID_3COM: + strncpy(ap->name, "3Com 3C985 Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); + break; + case PCI_VENDOR_ID_NETGEAR: + strncpy(ap->name, "NetGear GA620 Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: NetGear GA620 ", dev->name); + break; + case PCI_VENDOR_ID_DEC: + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { + strncpy(ap->name, "Farallon PN9000-SX " + "Gigabit Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Farallon PN9000-SX ", + dev->name); break; } - ap->name [sizeof (ap->name) - 1] = '\0'; - printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); + case PCI_VENDOR_ID_SGI: + strncpy(ap->name, "SGI AceNIC Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: SGI AceNIC ", dev->name); + break; + default: + strncpy(ap->name, "Unknown AceNIC based Gigabit " + "Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); + break; + } + ap->name [sizeof (ap->name) - 1] = '\0'; + printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); #ifdef __sparc__ - printk("irq %s\n", __irq_itoa(dev->irq)); + printk("irq %s\n", __irq_itoa(dev->irq)); #else - printk("irq %i\n", dev->irq); + printk("irq %i\n", dev->irq); #endif #ifdef CONFIG_ACENIC_OMIT_TIGON_I - if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { - printk(KERN_ERR "%s: Driver compiled without Tigon I" - " support - NIC disabled\n", dev->name); - ace_init_cleanup(dev); - kfree(dev); - continue; - } + if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { + printk(KERN_ERR "%s: Driver compiled without Tigon I" + " support - NIC disabled\n", dev->name); + ace_init_cleanup(dev); + kfree(dev); + return -ENODEV; + } #endif - if (ace_allocate_descriptors(dev)) { - /* - * ace_allocate_descriptors() calls - * ace_init_cleanup() on error. - */ - kfree(dev); - continue; - } + if (ace_allocate_descriptors(dev)) { + /* + * ace_allocate_descriptors() calls + * ace_init_cleanup() on error. + */ + kfree(dev); + return -ENODEV; + } #ifdef MODULE - if (boards_found >= ACE_MAX_MOD_PARMS) - ap->board_idx = BOARD_IDX_OVERFLOW; - else - ap->board_idx = boards_found; + if (boards_found >= ACE_MAX_MOD_PARMS) + ap->board_idx = BOARD_IDX_OVERFLOW; + else + ap->board_idx = boards_found; #else - ap->board_idx = BOARD_IDX_STATIC; + ap->board_idx = BOARD_IDX_STATIC; #endif - if (ace_init(dev)) { - /* - * ace_init() calls ace_init_cleanup() on error. - */ - kfree(dev); - continue; - } + pdev->driver_data = dev; - boards_found++; + if (ace_init(dev)) { + /* + * ace_init() calls ace_init_cleanup() on error. + */ + kfree(dev); + return -ENODEV; } - /* - * If we're at this point we're going through ace_probe() for - * the first time. Return success (0) if we've initialized 1 - * or more boards. Otherwise, return failure (-ENODEV). - */ - - if (boards_found > 0) - return 0; - else - return -ENODEV; + return 0; } @@ -759,136 +693,95 @@ MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); #endif - -static void __exit ace_module_cleanup(void) +static void __devexit acenic_remove_one(struct pci_dev *pdev) { + struct net_device *dev = pdev->driver_data; struct ace_private *ap; struct ace_regs *regs; - struct net_device *next; short i; - while (root_dev) { - ap = root_dev->priv; - next = ap->next; - - regs = ap->regs; + ap = dev->priv; + regs = ap->regs; - writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); - if (ap->version >= 2) - writel(readl(®s->CpuBCtrl) | CPU_HALT, - ®s->CpuBCtrl); - /* - * This clears any pending interrupts - */ - writel(1, ®s->Mb0Lo); + writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); + if (ap->version >= 2) + writel(readl(®s->CpuBCtrl) | CPU_HALT, + ®s->CpuBCtrl); + /* + * This clears any pending interrupts + */ + writel(1, ®s->Mb0Lo); - /* - * Make sure no other CPUs are processing interrupts - * on the card before the buffers are being released. - * Otherwise one might experience some `interesting' - * effects. - * - * Then release the RX buffers - jumbo buffers were - * already released in ace_close(). - */ - synchronize_irq(); + /* + * Make sure no other CPUs are processing interrupts + * on the card before the buffers are being released. + * Otherwise one might experience some `interesting' + * effects. + * + * Then release the RX buffers - jumbo buffers were + * already released in ace_close(). + */ + synchronize_irq(); - for (i = 0; i < RX_STD_RING_ENTRIES; i++) { - struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; + for (i = 0; i < RX_STD_RING_ENTRIES; i++) { + struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; - if (skb) { + if (skb) { #ifndef DUMMY_PCI_UNMAP - dma_addr_t mapping; + dma_addr_t mapping; - mapping = ap->skb->rx_std_skbuff[i].mapping; - pci_unmap_single(ap->pdev, mapping, - ACE_STD_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); + mapping = ap->skb->rx_std_skbuff[i].mapping; + pci_unmap_single(ap->pdev, mapping, + ACE_STD_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); #endif - ap->rx_std_ring[i].size = 0; - ap->skb->rx_std_skbuff[i].skb = NULL; - dev_kfree_skb(skb); - } + ap->rx_std_ring[i].size = 0; + ap->skb->rx_std_skbuff[i].skb = NULL; + dev_kfree_skb(skb); } - if (ap->version >= 2) { - for (i = 0; i < RX_MINI_RING_ENTRIES; i++) { - struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; - - if (skb) { -#ifndef DUMMY_PCI_UNMAP - dma_addr_t mapping; + } + if (ap->version >= 2) { + for (i = 0; i < RX_MINI_RING_ENTRIES; i++) { + struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; - mapping = ap->skb->rx_mini_skbuff[i].mapping; - pci_unmap_single(ap->pdev, mapping, - ACE_MINI_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); -#endif - ap->rx_mini_ring[i].size = 0; - ap->skb->rx_mini_skbuff[i].skb = NULL; - dev_kfree_skb(skb); - } - } - } - for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { - struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; if (skb) { #ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; - mapping = ap->skb->rx_jumbo_skbuff[i].mapping; + mapping = ap->skb->rx_mini_skbuff[i].mapping; pci_unmap_single(ap->pdev, mapping, - ACE_JUMBO_BUFSIZE - (2 + 16), + ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); #endif - - ap->rx_jumbo_ring[i].size = 0; - ap->skb->rx_jumbo_skbuff[i].skb = NULL; + ap->rx_mini_ring[i].size = 0; + ap->skb->rx_mini_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } - - ace_init_cleanup(root_dev); - kfree(root_dev); - root_dev = next; } -} - - -int __init ace_module_init(void) -{ - int status; - - root_dev = NULL; + for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { + struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; + if (skb) { +#ifndef DUMMY_PCI_UNMAP + dma_addr_t mapping; -#ifdef NEW_NETINIT - status = acenic_probe(); -#else - status = acenic_probe(NULL); + mapping = ap->skb->rx_jumbo_skbuff[i].mapping; + pci_unmap_single(ap->pdev, mapping, + ACE_JUMBO_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); #endif - return status; -} + ap->rx_jumbo_ring[i].size = 0; + ap->skb->rx_jumbo_skbuff[i].skb = NULL; + dev_kfree_skb(skb); + } + } -#if (LINUX_VERSION_CODE < 0x02032a) -#ifdef MODULE -int init_module(void) -{ - return ace_module_init(); + ace_init_cleanup(dev); + kfree(dev); } - -void cleanup_module(void) -{ - ace_module_cleanup(); -} -#endif -#else -module_init(ace_module_init); -module_exit(ace_module_cleanup); -#endif - - static void ace_free_descriptors(struct net_device *dev) { struct ace_private *ap = dev->priv; @@ -1324,13 +1217,6 @@ goto init_error; } - /* - * Register the device here to be able to catch allocated - * interrupt handlers in case the firmware doesn't come up. - */ - ap->next = root_dev; - root_dev = dev; - #ifdef INDEX_DEBUG spin_lock_init(&ap->debug_lock); ap->last_tx = TX_RING_ENTRIES - 1; @@ -2525,7 +2411,7 @@ #if defined(CONFIG_X86) #define DMAADDR_OFFSET 0 typedef unsigned long long dmaaddr_high_t; -#elif defined(CONFIG_PPC) +#elif defined(CONFIG_PPC32) #define DMAADDR_OFFSET PCI_DRAM_OFFSET typedef unsigned long dmaaddr_high_t; #endif @@ -3338,3 +3224,45 @@ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" * End: */ + +static struct pci_device_id acenic_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C985, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + /* + * Farallon used the DEC vendor ID on their cards incorrectly. + */ + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { } +}; +MODULE_DEVICE_TABLE(pci, acenic_pci_tbl); + +static struct pci_driver acenic_driver = { + name: "acenic", + id_table: acenic_pci_tbl, + probe: acenic_init_one, + remove: acenic_remove_one, +}; + +static int __init acenic_init_module(void) +{ + return pci_module_init(&acenic_driver); +} + +static void __exit acenic_cleanup_module(void) +{ + pci_unregister_driver(&acenic_driver); +} + +module_init(acenic_init_module); +module_exit(acenic_cleanup_module); diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/net/acenic.h linuxppc64_2_4/drivers/net/acenic.h --- linux-2.4.9-ac10/drivers/net/acenic.h Thu Sep 6 14:03:29 2001 +++ linuxppc64_2_4/drivers/net/acenic.h Wed Aug 22 08:27:45 2001 @@ -582,7 +582,7 @@ aceaddr stats2_ptr; }; -#if defined(CONFIG_X86) || defined(CONFIG_PPC) +#if defined(CONFIG_X86) || defined(CONFIG_PPC32) /* Intel has null pci_unmap_single, no reasons to remember mapping. */ #define DUMMY_PCI_UNMAP #endif diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/net/pcnet32.c linuxppc64_2_4/drivers/net/pcnet32.c --- linux-2.4.9-ac10/drivers/net/pcnet32.c Thu Sep 6 14:03:29 2001 +++ linuxppc64_2_4/drivers/net/pcnet32.c Thu Sep 6 12:11:14 2001 @@ -201,7 +201,7 @@ #define RX_RING_MOD_MASK (RX_RING_SIZE - 1) #define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) -#define PKT_BUF_SZ 1544 +#define PKT_BUF_SZ 2048 /* Offsets from base I/O address. */ #define PCNET32_WIO_RDP 0x10 @@ -294,7 +294,7 @@ static int pcnet32_probe_vlbus(int cards_found); static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); -static int pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *); +static int pcnet32_probe1(unsigned long, unsigned int, int, int, struct pci_dev *); static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); @@ -317,7 +317,7 @@ const char *name; u16 vendor_id, device_id, svid, sdid, flags; int io_size; - int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *); + int (*probe1) (unsigned long, unsigned int, int, int, struct pci_dev *); }; @@ -440,7 +440,9 @@ static int __init pcnet32_probe_vlbus(int cards_found) { unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0; +#ifndef __powerpc__ unsigned int irq_line = 0; // FIXME dev ? dev->irq : 0; +#endif int *port; printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found); @@ -508,7 +510,7 @@ * pdev will be NULL when called from pcnet32_probe_vlbus. */ static int __devinit -pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev) +pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, int card_idx, struct pci_dev *pdev) { struct pcnet32_private *lp; struct resource *res; @@ -525,14 +527,16 @@ /* reset the chip */ pcnet32_dwio_reset(ioaddr); + udelay (100); pcnet32_wio_reset(ioaddr); - /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ - if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { - a = &pcnet32_wio; + /* Important to do the check for dwio mode first. */ + if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { + a = &pcnet32_dwio; } else { - if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { - a = &pcnet32_dwio; + if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && + pcnet32_wio_check(ioaddr)) { + a = &pcnet32_wio; } else return -ENODEV; } @@ -607,11 +611,18 @@ * one for latency - although on PCI this isnt a big loss. Older chips * have FIFO's smaller than a packet, so you can't do this. */ - + /* + * UPDATE + * Got to make sure that BCR18:MEMCMD, BCR18:BREADE, BCR18:BWRITE are + * set on a PCI + */ if(fset) { - a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800)); - a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); + a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0xA60)); + a->write_csr(ioaddr, 3, 0x2eb7); + a->write_csr(ioaddr, 4, 0x32ea); + a->write_csr(ioaddr, 80, 0x3f00); + #ifdef DO_DXSUFLO dxsuflo = 1; #endif @@ -643,19 +654,31 @@ for (i = 0; i < 6; i++) { promaddr[i] = inb(ioaddr + i); } + printk("csraddr: "); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] ); + printk("\npromaddr: "); + for (i = 0; i < 6; i++) + printk(" %2.2x", promaddr[i] ); + printk("\n"); if( memcmp( promaddr, dev->dev_addr, 6) ) - { - printk(" warning PROM address does not match CSR address\n"); -#if defined(__i386__) - printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name); - memcpy(dev->dev_addr, promaddr, 6); -#endif - } + printk(" warning: PROM address does not match CSR address\n"); + if( !is_valid_ether_addr(dev->dev_addr) ) { + printk("bad csr addr\n"); + if (!is_valid_ether_addr(promaddr)) { + printk("bad promaddr\n"); + /* if neither ethernet address is not valid, force to 00:00:00:00:00:00 */ + for (i = 0; i < 6; i++) + dev->dev_addr[i]=0; + } + else + { + printk(" warning: Using PROM address\n"); + for (i = 0; i < 6; i++) + dev->dev_addr[i]=promaddr[i]; + } + } } - /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ - if( !is_valid_ether_addr(dev->dev_addr) ) - for (i = 0; i < 6; i++) - dev->dev_addr[i]=0; for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] ); @@ -885,7 +908,7 @@ lp->init_block.filter[1] = 0x00000000; if (pcnet32_init_ring(dev)) return -ENOMEM; - + /* Re-initialize the PCNET32, and start it when done. */ lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) &0xffff); lp->a.write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16); @@ -967,7 +990,7 @@ } skb_reserve (rx_skbuff, 2); } - lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE); + lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); lp->rx_ring[i].status = le16_to_cpu(0x8000); @@ -1301,7 +1324,8 @@ skb_put (skb, pkt_len); lp->rx_skbuff[entry] = newskb; newskb->dev = dev; - lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE); + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); + lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]); rx_in_place = 1; } else @@ -1387,7 +1411,7 @@ for (i = 0; i < RX_RING_SIZE; i++) { lp->rx_ring[i].status = 0; if (lp->rx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE); + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_skbuff[i]); } lp->rx_skbuff[i] = NULL; diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/net/veth-proc.c linuxppc64_2_4/drivers/net/veth-proc.c --- linux-2.4.9-ac10/drivers/net/veth-proc.c Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/drivers/net/veth-proc.c Fri May 4 17:12:47 2001 @@ -0,0 +1,73 @@ +/* File veth-proc.c created by Kyle A. Lucke on Wed Oct 18 2000. */ + +/* Change Activity: */ +/* End Change Activity */ + +#ifndef _VETH_PROC_H +#include +#endif +#ifndef _HVTYPES_H +#include +#endif +#ifndef _HVLPCONFIG_H +#include +#endif +#ifndef _VETH_H +#include "veth.h" +#endif + + +static struct proc_dir_entry * veth_proc_root = NULL; + +void veth_proc_init(struct proc_dir_entry *iSeries_proc) +{ + long i=0; + HvLpIndex thisLp = HvLpConfig_getLpIndex(); + u16 vlanMap = HvLpConfig_getVirtualLanIndexMap(); + long vlanIndex = 0; + + + veth_proc_root = proc_mkdir("veth", iSeries_proc); + if (!veth_proc_root) return; + + for (i=0; i < HvMaxArchitectedLps; ++i) + { + if (i != thisLp) + { + if (HvLpConfig_doLpsCommunicateOnVirtualLan(thisLp, i)) + { + struct proc_dir_entry *ent; + char name[10] = ""; + sprintf(name, "lp%ld", i); + ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)i; + ent->read_proc = proc_veth_dump_connection; + ent->write_proc = NULL; + } + } + } + + while (vlanMap != 0) + { + int bitOn = vlanMap & 0x8000; + + if (bitOn) + { + struct proc_dir_entry *ent; + char name[10] = ""; + sprintf(name, "veth%ld", vlanIndex); + ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)vlanIndex; + ent->read_proc = proc_veth_dump_port; + ent->write_proc = NULL; + } + + ++vlanIndex; + vlanMap = vlanMap << 1; + } +} + diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/net/veth.c linuxppc64_2_4/drivers/net/veth.c --- linux-2.4.9-ac10/drivers/net/veth.c Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/drivers/net/veth.c Thu Sep 6 06:45:29 2001 @@ -0,0 +1,1755 @@ +/* File veth.c created by Kyle A. Lucke on Mon Aug 7 2000. */ + +/**************************************************************************/ +/* */ +/* IBM eServer iSeries Virtual Ethernet Device Driver */ +/* Copyright (C) 2001 Kyle A. Lucke (klucke@raleigh.ibm.com), IBM Corp. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 */ +/* USA */ +/* */ +/* This module contains the implementation of a virtual ethernet device */ +/* for use with iSeries LPAR Linux. It utilizes low-level message passing*/ +/* provided by the hypervisor to enable an ethernet-like network device */ +/* that can be used to enable inter-partition communications on the same */ +/* physical iSeries. */ +/* */ +/* The iSeries LPAR hypervisor has currently defined the ability for a */ +/* partition to communicate on up to 16 different virtual ethernets, all */ +/* dynamically configurable, at least for an OS/400 partition. The */ +/* dynamic nature is not supported for Linux yet. */ +/* */ +/* Each virtual ethernet a given Linux partition participates in will */ +/* cause a network device with the form vethXX to be created, where XX is */ +/* a decimal number from 0 to 15, corresponding to the virtual ethernet */ +/* the given netdevice talks on. This is slightly different from the */ +/* standard eth0, eth1, etc. way of naming network devices, but without */ +/* this little naming convention, it would not be as easy to configure */ +/* the tcpip interfaces to a given veth device, and if the partition */ +/* was configured to use a new virtual ethernet at some point, the devices*/ +/* would most likely get renumbered. */ +/* */ +/* This driver (and others like it on other partitions) is responsible */ +/* routing packets to and from other partitions. The MAC addresses used */ +/* by the virtual ethernets contain meaning, and should not be modified. */ +/* Doing so could disable the ability of your Linux partition to */ +/* communicate with the other OS/400 partitions on your physical iSeries. */ +/* Similarly, setting the MAC address to something other than the */ +/* "virtual burned-in" address is not allowed, for the same reason. */ +/* */ +/* Notes: */ +/* */ +/* 1. Although there is the capability to talk on multiple shared */ +/* ethernets to communicate to the same partition, each shared */ +/* ethernet to a given partition X will use a finite, shared amount */ +/* of hypervisor messages to do the communication. So having 2 shared */ +/* ethernets to the same remote partition DOES NOT double the */ +/* available bandwidth. Each of the 2 shared ethernets will share the */ +/* same bandwidth available to another. */ +/* */ +/* 2. It is allowed to have a virtual ethernet that does not communicate */ +/* with any other partition. It won't do anything, but it's allowed. */ +/* */ +/* 3. There is no "loopback" mode for a virtual ethernet device. If you */ +/* send a packet to your own mac address, it will just be dropped, you */ +/* won't get it on the receive side. Such a thing could be done, */ +/* but my default driver DOES NOT do so. */ +/* */ +/* 4. Multicast addressing is implemented via broadcasting the multicast */ +/* frames to other partitions. It is the responsibility of the */ +/* receiving partition to filter the addresses desired. */ +/* */ +/* 5. This module utilizes several different bottom half handlers for */ +/* non-high-use path function (setup, error handling, etc.). Multiple */ +/* bottom halves were used because only one would not keep up to the */ +/* much faster iSeries device drivers this Linux driver is talking to. */ +/* All hi-priority work (receiving frames, handling frame acks) is done*/ +/* in the interrupt handler for maximum performance. */ +/* */ +/* Tunable parameters: */ +/* */ +/* VethBuffersToAllocate: This compile time option defaults to 120. It can*/ +/* be safely changed to something greater or less than the default. It */ +/* controls how much memory Linux will allocate per remote partition it is*/ +/* communicating with. The user can play with this to see how it affects */ +/* performance, packets dropped, etc. Without trying to understand the */ +/* complete driver, it can be thought of as the maximum number of packets */ +/* outstanding to a remote partition at a time. */ +/* */ +/**************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _VETH_H +#include "veth.h" +#endif +#ifndef _HVLPCONFIG_H +#include +#endif +#ifndef _VETH_PROC_H +#include +#endif +#ifndef _HVTYPES_H +#include +#endif +#ifndef _ISERIES_PROC_H +#include +#endif +#include +#include + + +#define veth_printk(fmt, args...) \ +printk(KERN_INFO "%s: " fmt, __FILE__, ## args) + +#define veth_error_printk(fmt, args...) \ +printk(KERN_ERR "(%s:%3.3d) ERROR: " fmt, __FILE__, __LINE__ , ## args) + +static const char __initdata *version = +"v0.9 02/15/2001 Kyle Lucke, klucke@raleigh.ibm.com, klucke@us.ibm.com\n"; + +static int probed __initdata = 0; +#define VethBuffersToAllocate 120 + +static struct VethFabricMgr *mFabricMgr = NULL; +static struct proc_dir_entry * veth_proc_root = NULL; + +DECLARE_MUTEX_LOCKED(VethProcSemaphore); + +static int veth_open(struct net_device *dev); +static int veth_close(struct net_device *dev); +static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static void veth_handleEvent(struct HvLpEvent *, struct pt_regs *); +static void veth_handleAck(struct HvLpEvent *); +static void veth_handleInt(struct HvLpEvent *); +static void veth_openConnections(void); +static void veth_openConnection(u8, int lockMe); +static void veth_closeConnection(u8, int lockMe); +static void veth_intFinishOpeningConnections(void *, int number); +static void veth_finishOpeningConnections(void *); +static void veth_finishOpeningConnectionsLocked(struct VethLpConnection *); +static int veth_multicast_wanted(struct VethPort *port, u64 dest); +static void veth_set_multicast_list(struct net_device *dev); + +static void veth_sendCap(struct VethLpConnection *); +static void veth_sendMonitor(struct VethLpConnection *); +static void veth_takeCap(struct VethLpConnection *, struct VethLpEvent *); +static void veth_takeCapAck(struct VethLpConnection *, struct VethLpEvent *); +static void veth_takeMonitorAck(struct VethLpConnection *, struct VethLpEvent *); +static void veth_msgsInit(struct VethLpConnection *connection); +static void veth_recycleMsg(struct VethLpConnection *, u16); +static void veth_capBh(struct VethLpConnection *); +static void veth_capAckBh(struct VethLpConnection *); +static void veth_monitorAckBh(struct VethLpConnection *); +static void veth_takeFrames(struct VethLpConnection *, struct VethLpEvent *); +static void veth_pTransmit(struct sk_buff *skb, HvLpIndex remoteLp, struct net_device *dev); +static struct net_device_stats *veth_get_stats(struct net_device *dev); +static void veth_intFinishMsgsInit(void *, int); +static void veth_finishMsgsInit(struct VethLpConnection *connection); +static void veth_intFinishCapBh(void *, int); +static void veth_finishCapBh(struct VethLpConnection *connection); +static void veth_finishCapBhLocked(struct VethLpConnection *connection); +static void veth_finishSendCap(struct VethLpConnection *connection); +static void veth_timedAck(unsigned long connectionPtr); +#ifdef MODULE +static void veth_waitForEnd(void); +#endif +static void veth_failMe(struct VethLpConnection *connection); + +int __init veth_probe(void) +{ + struct net_device *dev= NULL; + struct VethPort *port = NULL; + int vlansFound = 0; + int displayVersion = 0; + + u16 vlanMap = HvLpConfig_getVirtualLanIndexMap(); + int vlanIndex = 0; + + if (probed) + return -ENODEV; + probed = 1; + + while (vlanMap != 0) + { + int bitOn = vlanMap & 0x8000; + + if (bitOn) + { + vlansFound++; + + dev = init_vethdev(NULL, sizeof(struct VethPort), vlanIndex); + + if (dev == NULL) { + veth_error_printk("Unable to allocate net_device structure!\n"); + break; + } + + if (!dev->priv) + dev->priv = kmalloc(sizeof(struct VethPort), GFP_KERNEL); + if (!dev->priv) { + veth_error_printk("Unable to allocate memory\n"); + return -ENOMEM; + } + + veth_printk("Found an ethernet device %s (veth=%d) (addr=%p)\n", dev->name, vlanIndex, dev); + port = mFabricMgr->mPorts[vlanIndex] = (struct VethPort *)dev->priv; + memset(port, 0, sizeof(struct VethPort)); + rwlock_init(&(port->mMcastGate)); + mFabricMgr->mPorts[vlanIndex]->mDev = dev; + + dev->dev_addr[0] = 0x02; + dev->dev_addr[1] = 0x01; + dev->dev_addr[2] = 0xFF; + dev->dev_addr[3] = vlanIndex; + dev->dev_addr[4] = 0xFF; + dev->dev_addr[5] = HvLpConfig_getLpIndex_outline(); + dev->mtu = 9000; + + memcpy(&(port->mMyAddress), dev->dev_addr, 6); + + dev->open = &veth_open; + dev->hard_start_xmit = &veth_start_xmit; + dev->stop = &veth_close; + dev->get_stats = veth_get_stats; + dev->set_multicast_list = &veth_set_multicast_list; + dev->do_ioctl = &veth_ioctl; + + /* display version info if adapter is found */ + if (!displayVersion) + { + /* set display flag to TRUE so that */ + /* we only display this string ONCE */ + displayVersion = 1; + veth_printk("%s", version); + } + + } + + ++vlanIndex; + vlanMap = vlanMap << 1; + } + + if (vlansFound > 0) + return 0; + else + return -ENODEV; +} + +#ifdef MODULE +MODULE_AUTHOR("Kyle Lucke , "); +MODULE_DESCRIPTION("iSeries Virtual ethernet driver"); + +DECLARE_MUTEX_LOCKED(VethModuleBhDone); +int VethModuleReopen = 1; + +void veth_proc_delete(struct proc_dir_entry *iSeries_proc) +{ + int i=0; + HvLpIndex thisLp = HvLpConfig_getLpIndex_outline(); + u16 vlanMap = HvLpConfig_getVirtualLanIndexMap(); + int vlanIndex = 0; + + for (i=0; i < HvMaxArchitectedLps; ++i) + { + if (i != thisLp) + { + if (HvLpConfig_doLpsCommunicateOnVirtualLan(thisLp, i)) + { + char name[10] = ""; + sprintf(name, "lp%d", i); + remove_proc_entry(name, veth_proc_root); + } + } + } + + while (vlanMap != 0) + { + int bitOn = vlanMap & 0x8000; + + if (bitOn) + { + char name[10] = ""; + sprintf(name, "veth%d", vlanIndex); + remove_proc_entry(name, veth_proc_root); + } + + ++vlanIndex; + vlanMap = vlanMap << 1; + } + + remove_proc_entry("veth", iSeries_proc); + + up(&VethProcSemaphore); +} + +void veth_waitForEnd(void) +{ + up(&VethModuleBhDone); +} + +void __exit veth_module_cleanup(void) +{ + int i; + struct VethFabricMgr *myFm = mFabricMgr; + struct tq_struct myBottomHalf; + struct net_device *thisOne = NULL; + + VethModuleReopen = 0; + + for (i = 0; i < HvMaxArchitectedLps; ++i) + { + veth_closeConnection(i, 1); + } + + myBottomHalf.routine = (void *)(void *)veth_waitForEnd; + + queue_task(&myBottomHalf, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + down(&VethModuleBhDone); + + HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan); + + mb(); + mFabricMgr = NULL; + mb(); + + down(&VethProcSemaphore); + + iSeries_proc_callback(&veth_proc_delete); + + down(&VethProcSemaphore); + + for (i = 0; i < HvMaxArchitectedLps; ++i) + { + if (myFm->mConnection[i].mNumberAllocated + myFm->mConnection[i].mNumberRcvMsgs > 0) + { + mf_deallocateLpEvents(myFm->mConnection[i].mRemoteLp, + HvLpEvent_Type_VirtualLan, + myFm->mConnection[i].mNumberAllocated + myFm->mConnection[i].mNumberRcvMsgs, + NULL, + NULL); + } + + if (myFm->mConnection[i].mMsgs != NULL) + { + kfree(myFm->mConnection[i].mMsgs); + } + } + + for (i = 0; i < HvMaxArchitectedVirtualLans; ++i) + { + if (myFm->mPorts[i] != NULL) + { + thisOne = myFm->mPorts[i]->mDev; + myFm->mPorts[i] = NULL; + + mb(); + + if (thisOne != NULL) + { + veth_printk("Unregistering %s (veth=%d)\n", thisOne->name, i); + unregister_netdev(thisOne); + } + } + } + + kfree(myFm); +} + +module_exit(veth_module_cleanup); +#endif + + +void veth_proc_init(struct proc_dir_entry *iSeries_proc) +{ + int i=0; + HvLpIndex thisLp = HvLpConfig_getLpIndex_outline(); + u16 vlanMap = HvLpConfig_getVirtualLanIndexMap(); + int vlanIndex = 0; + + + veth_proc_root = proc_mkdir("veth", iSeries_proc); + if (!veth_proc_root) return; + + for (i=0; i < HvMaxArchitectedLps; ++i) + { + if (i != thisLp) + { + if (HvLpConfig_doLpsCommunicateOnVirtualLan(thisLp, i)) + { + struct proc_dir_entry *ent; + char name[10] = ""; + sprintf(name, "lpar%d", i); + ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)i; + ent->read_proc = proc_veth_dump_connection; + ent->write_proc = NULL; + } + } + } + + while (vlanMap != 0) + { + int bitOn = vlanMap & 0x8000; + + if (bitOn) + { + struct proc_dir_entry *ent; + char name[10] = ""; + sprintf(name, "veth%d", vlanIndex); + ent = create_proc_entry(name, S_IFREG|S_IRUSR, veth_proc_root); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)vlanIndex; + ent->read_proc = proc_veth_dump_port; + ent->write_proc = NULL; + } + + ++vlanIndex; + vlanMap = vlanMap << 1; + } + + up(&VethProcSemaphore); +} + +int __init veth_module_init(void) +{ + int status; + int i; + + mFabricMgr = kmalloc(sizeof(struct VethFabricMgr), GFP_KERNEL); + memset(mFabricMgr, 0, sizeof(struct VethFabricMgr)); + veth_printk("Initializing veth module, fabric mgr (address=%p)\n", mFabricMgr); + + mFabricMgr->mEyecatcher = 0x56455448464D4752ULL; + mFabricMgr->mThisLp = HvLpConfig_getLpIndex_outline(); + + for (i=0; i < HvMaxArchitectedLps; ++i) + { + mFabricMgr->mConnection[i].mEyecatcher = 0x564554484C50434EULL; + veth_failMe(mFabricMgr->mConnection+i); + spin_lock_init(&mFabricMgr->mConnection[i].mAckGate); + spin_lock_init(&mFabricMgr->mConnection[i].mStatusGate); + } + + status = veth_probe(); + + if (status == 0) + { + veth_openConnections(); + } + + iSeries_proc_callback(&veth_proc_init); + + return status; +} + +module_init(veth_module_init); + +static void veth_failMe(struct VethLpConnection *connection) +{ + connection->mConnectionStatus.mSentCap = 0; + connection->mConnectionStatus.mCapAcked = 0; + connection->mConnectionStatus.mGotCap = 0; + connection->mConnectionStatus.mGotCapAcked = 0; + connection->mConnectionStatus.mSentMonitor = 0; + connection->mConnectionStatus.mFailed = 1; +} + +static int veth_open(struct net_device *dev) +{ + struct VethPort *port = (struct VethPort *)dev->priv; + + memset(&port->mStats, 0, sizeof(port->mStats)); + MOD_INC_USE_COUNT; + + netif_start_queue(dev); + + return 0; +} + +static int veth_close(struct net_device *dev) +{ + netif_stop_queue(dev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct net_device_stats *veth_get_stats(struct net_device *dev) +{ + struct VethPort *port = (struct VethPort *)dev->priv; + + return(&port->mStats); +} + + +static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + unsigned char *frame = skb->data; + HvLpIndex remoteLp = frame[5]; + int i = 0; + int clone = 0; + + if (mFabricMgr == NULL) + { + veth_error_printk("NULL fabric manager with active ports!\n"); + netif_stop_queue(dev); + return 1; + } + + mb(); + + if ((*frame & 0x01) != 0x01) /* broadcast or multicast */ + { + if ((remoteLp != mFabricMgr->mThisLp) && + (HvLpConfig_doLpsCommunicateOnVirtualLan(mFabricMgr->mThisLp, remoteLp))) + veth_pTransmit(skb, remoteLp, dev); + } + else + { + for (i=0; i < HvMaxArchitectedLps; ++i) + { + if (i != mFabricMgr->mThisLp) + { + if (clone) + skb = skb_clone(skb, GFP_ATOMIC); + else + clone = 1; + + if (HvLpConfig_doLpsCommunicateOnVirtualLan(mFabricMgr->mThisLp, i)) + { + /* the ack handles deleting the skb */ + veth_pTransmit(skb, i, dev); + } + } + } + } + + return 0; +} + +static void veth_pTransmit(struct sk_buff *skb, HvLpIndex remoteLp, struct net_device *dev) +{ + struct VethLpConnection *connection = mFabricMgr->mConnection + remoteLp; + HvLpEvent_Rc returnCode; + + if (connection->mConnectionStatus.mFailed != 1) + { + struct VethMsg *msg = NULL; + VETHSTACKPOP(&(connection->mMsgStack), msg); + + if (msg != NULL) + { + if ((skb->len > 14) && + (skb->len <= 9018)) + { + dma_addr_t dma_addr = pci_map_single(NULL, + skb->data, + skb->len, + PCI_DMA_TODEVICE); + + + + if (dma_addr != -1) + { + msg->mSkb = skb; + msg->mEvent.mSendData.mAddress[0] = dma_addr; + msg->mEvent.mSendData.mLength[0] = skb->len; + msg->mEvent.mSendData.mEofMask = 0xFFFFFFFFUL; + + test_and_set_bit(0, &(msg->mInUse)); + + returnCode = HvCallEvent_signalLpEventFast(remoteLp, + HvLpEvent_Type_VirtualLan, + VethEventTypeFrames, + HvLpEvent_AckInd_NoAck, + HvLpEvent_AckType_ImmediateAck, + connection->mSourceInst, + connection->mTargetInst, + msg->mIndex, + msg->mEvent.mFpData.mData1, + msg->mEvent.mFpData.mData2, + msg->mEvent.mFpData.mData3, + msg->mEvent.mFpData.mData4, + msg->mEvent.mFpData.mData5); + } + else + { + returnCode = -1; /* Bad return code */ + } + + if (returnCode != HvLpEvent_Rc_Good) + { + struct VethPort *port = (struct VethPort *)dev->priv; + + if (msg->mEvent.mSendData.mAddress[0]) + { + pci_unmap_single(NULL, dma_addr, skb->len, PCI_DMA_TODEVICE); + } + + dev_kfree_skb_irq(skb); + + msg->mSkb = NULL; + memset(&(msg->mEvent.mSendData), 0, sizeof(struct VethFramesData)); + VETHSTACKPUSH(&(connection->mMsgStack), msg); + port->mStats.tx_dropped++; + } + else + { + struct VethPort *port = (struct VethPort *)dev->priv; + port->mStats.tx_packets++; + port->mStats.tx_bytes += skb->len; + } + } + } + else + { + struct VethPort *port = (struct VethPort *)dev->priv; + port->mStats.tx_dropped++; + } + } + else + { + struct VethPort *port = (struct VethPort *)dev->priv; + port->mStats.tx_dropped++; + } +} + +static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + + return -EOPNOTSUPP; +} + +static void veth_set_multicast_list(struct net_device *dev) +{ + char *addrs; + struct VethPort *port = (struct VethPort *)dev->priv; + u64 newAddress = 0; + unsigned long flags; + + write_lock_irqsave(&port->mMcastGate, flags); + + if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ + port->mPromiscuous = 1; + } else { + struct dev_mc_list *dmi = dev->mc_list; + + if (dev->flags & IFF_ALLMULTI) { + port->mAllMcast = 1; + } else { + int i; + /* Update table */ + port->mNumAddrs = 0; + + for (i = 0; ((i < dev->mc_count) && (i < 12)); i++) { /* for each address in the list */ + addrs = dmi->dmi_addr; + dmi = dmi->next; + if ((*addrs & 0x01) == 1) { /* multicast address? */ + memcpy(&newAddress, addrs, 6); + newAddress &= 0xFFFFFFFFFFFF0000; + + port->mMcasts[port->mNumAddrs] = newAddress; + mb(); + port->mNumAddrs = port->mNumAddrs + 1; + } + } + } + } + + write_unlock_irqrestore(&port->mMcastGate, flags); +} + + +static void veth_handleEvent(struct HvLpEvent *event, struct pt_regs *regs) +{ + if (event->xFlags.xFunction == HvLpEvent_Function_Ack) + { + veth_handleAck(event); + } + else if (event->xFlags.xFunction == HvLpEvent_Function_Int) + { + veth_handleInt(event); + } +} + +static void veth_handleAck(struct HvLpEvent *event) +{ + struct VethLpConnection *connection = &(mFabricMgr->mConnection[event->xTargetLp]); + struct VethLpEvent *vethEvent = (struct VethLpEvent *)event; + + switch(event->xSubtype) + { + case VethEventTypeCap: + { + veth_takeCapAck(connection, vethEvent); + break; + } + case VethEventTypeMonitor: + { + veth_takeMonitorAck(connection, vethEvent); + break; + } + default: + { + veth_error_printk("Unknown ack type %d from lpar %d\n", event->xSubtype, connection->mRemoteLp); + } + }; +} + +static void veth_handleInt(struct HvLpEvent *event) +{ + int i=0; + struct VethLpConnection *connection = &(mFabricMgr->mConnection[event->xSourceLp]); + struct VethLpEvent *vethEvent = (struct VethLpEvent *)event; + + switch(event->xSubtype) + { + case VethEventTypeCap: + { + veth_takeCap(connection, vethEvent); + break; + } + case VethEventTypeMonitor: + { + /* do nothing... this'll hang out here til we're dead, and the hypervisor will return it for us. */ + break; + } + case VethEventTypeFramesAck: + { + for (i=0; i < VethMaxFramesMsgsAcked; ++i) + { + u16 msg = vethEvent->mDerivedData.mFramesAckData.mToken[i]; + veth_recycleMsg(connection, msg); + } + break; + } + case VethEventTypeFrames: + { + veth_takeFrames(connection, vethEvent); + break; + } + default: + { + veth_error_printk("Unknown interrupt type %d from lpar %d\n", event->xSubtype, connection->mRemoteLp); + } + }; +} + +static void veth_openConnections() +{ + int i=0; + + HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan, &veth_handleEvent); + + /* Now I need to run through the active lps and open connections to the ones I'm supposed to + open to. */ + + for (i=HvMaxArchitectedLps-1; i >=0; --i) + { + if (i != mFabricMgr->mThisLp) + { + if (HvLpConfig_doLpsCommunicateOnVirtualLan(mFabricMgr->mThisLp, i)) + { + veth_openConnection(i, 1); + } + else + { + veth_closeConnection(i, 1); + } + } + } +} + +static void veth_intFinishOpeningConnections(void *parm, int number) +{ + struct VethLpConnection *connection = (struct VethLpConnection *)parm; + connection->mAllocBhTq.data = parm; + connection->mNumberAllocated = number; + queue_task(&connection->mAllocBhTq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void veth_finishOpeningConnections(void *parm) +{ + unsigned long flags; + struct VethLpConnection *connection = (struct VethLpConnection *)parm; + spin_lock_irqsave(&connection->mStatusGate, flags); + veth_finishOpeningConnectionsLocked(connection); + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +static void veth_finishOpeningConnectionsLocked(struct VethLpConnection *connection) +{ + if (connection->mNumberAllocated >= 2) + { + connection->mConnectionStatus.mCapMonAlloced = 1; + veth_sendCap(connection); + } + else + { + veth_error_printk("Couldn't allocate base msgs for lpar %d, only got %d\n", connection->mRemoteLp, connection->mNumberAllocated); + veth_failMe(connection); + } +} + +static void veth_openConnection(u8 remoteLp, int lockMe) +{ + unsigned long flags; + unsigned long flags2; + HvLpInstanceId source; + HvLpInstanceId target; + u64 i = 0; + struct VethLpConnection *connection = &(mFabricMgr->mConnection[remoteLp]); + + memset(&connection->mCapBhTq, 0, sizeof(connection->mCapBhTq)); + connection->mCapBhTq.routine = (void *)(void *)veth_capBh; + + memset(&connection->mCapAckBhTq, 0, sizeof(connection->mCapAckBhTq)); + connection->mCapAckBhTq.routine = (void *)(void *)veth_capAckBh; + + memset(&connection->mMonitorAckBhTq, 0, sizeof(connection->mMonitorAckBhTq)); + connection->mMonitorAckBhTq.routine = (void *)(void *)veth_monitorAckBh; + + memset(&connection->mAllocBhTq, 0, sizeof(connection->mAllocBhTq)); + connection->mAllocBhTq.routine = (void *)(void *)veth_finishOpeningConnections; + + if (lockMe) + spin_lock_irqsave(&connection->mStatusGate, flags); + + connection->mRemoteLp = remoteLp; + + spin_lock_irqsave(&connection->mAckGate, flags2); + + memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData)); + connection->mNumAcks = 0; + + HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualLan); + + /* clean up non-acked msgs */ + for (i=0; i < connection->mNumMsgs; ++i) + { + veth_recycleMsg(connection, i); + } + + connection->mConnectionStatus.mOpen = 1; + + source = connection->mSourceInst = HvCallEvent_getSourceLpInstanceId(remoteLp, HvLpEvent_Type_VirtualLan); + target = connection->mTargetInst = HvCallEvent_getTargetLpInstanceId(remoteLp, HvLpEvent_Type_VirtualLan); + + if (connection->mConnectionStatus.mCapMonAlloced != 1) + { + connection->mAllocBhTq.routine = (void *)(void *)veth_finishOpeningConnections; + mf_allocateLpEvents(remoteLp, + HvLpEvent_Type_VirtualLan, + sizeof(struct VethLpEvent), + 2, + &veth_intFinishOpeningConnections, + connection); + } + else + { + veth_finishOpeningConnectionsLocked(connection); + } + + spin_unlock_irqrestore(&connection->mAckGate, flags2); + + if (lockMe) + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +static void veth_closeConnection(u8 remoteLp, int lockMe) +{ + struct VethLpConnection *connection = &(mFabricMgr->mConnection[remoteLp]); + unsigned long flags; + unsigned long flags2; + if (lockMe) + spin_lock_irqsave(&connection->mStatusGate, flags); + + del_timer(&connection->mAckTimer); + + if (connection->mConnectionStatus.mOpen == 1) + { + HvCallEvent_closeLpEventPath(remoteLp, HvLpEvent_Type_VirtualLan); + connection->mConnectionStatus.mOpen = 0; + veth_failMe(connection); + + /* reset ack data */ + spin_lock_irqsave(&connection->mAckGate, flags2); + + memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData)); + connection->mNumAcks = 0; + + spin_unlock_irqrestore(&connection->mAckGate, flags2); + } + + if (lockMe) + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +static void veth_msgsInit(struct VethLpConnection *connection) +{ + connection->mAllocBhTq.routine = (void *)(void *)veth_finishMsgsInit; + mf_allocateLpEvents(connection->mRemoteLp, + HvLpEvent_Type_VirtualLan, + sizeof(struct VethLpEvent), + connection->mMyCap.mUnionData.mFields.mNumberBuffers, + &veth_intFinishMsgsInit, + connection); +} + +static void veth_intFinishMsgsInit(void *parm, int number) +{ + struct VethLpConnection *connection = (struct VethLpConnection *)parm; + connection->mAllocBhTq.data = parm; + connection->mNumberRcvMsgs = number; + queue_task(&connection->mAllocBhTq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void veth_intFinishCapBh(void *parm, int number) +{ + struct VethLpConnection *connection = (struct VethLpConnection *)parm; + connection->mAllocBhTq.data = parm; + if (number > 0) + connection->mNumberLpAcksAlloced += number; + + queue_task(&connection->mAllocBhTq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void veth_finishMsgsInit(struct VethLpConnection *connection) +{ + int i=0; + unsigned int numberGotten = 0; + u64 amountOfHeapToGet = connection->mMyCap.mUnionData.mFields.mNumberBuffers * sizeof(struct VethMsg); + char *msgs = NULL; + unsigned long flags; + spin_lock_irqsave(&connection->mStatusGate, flags); + + if (connection->mNumberRcvMsgs >= connection->mMyCap.mUnionData.mFields.mNumberBuffers) + { + msgs = kmalloc(amountOfHeapToGet, GFP_ATOMIC); + + connection->mMsgs = (struct VethMsg *)msgs; + + if (msgs != NULL) + { + memset(msgs, 0, amountOfHeapToGet); + + for (i=0; i < connection->mMyCap.mUnionData.mFields.mNumberBuffers; ++i) + { + connection->mMsgs[i].mIndex = i; + ++numberGotten; + VETHSTACKPUSH(&(connection->mMsgStack), (connection->mMsgs+i)); + } + if (numberGotten > 0) + { + connection->mNumMsgs = numberGotten; + } + } + else + { + kfree(msgs); + connection->mMsgs = NULL; + } + } + + connection->mMyCap.mUnionData.mFields.mNumberBuffers = connection->mNumMsgs; + + if (connection->mNumMsgs < 10) + connection->mMyCap.mUnionData.mFields.mThreshold = 1; + else if (connection->mNumMsgs < 20) + connection->mMyCap.mUnionData.mFields.mThreshold = 4; + else if (connection->mNumMsgs < 40) + connection->mMyCap.mUnionData.mFields.mThreshold = 10; + else + connection->mMyCap.mUnionData.mFields.mThreshold = 20; + + connection->mMyCap.mUnionData.mFields.mTimer = VethAckTimeoutUsec; + + veth_finishSendCap(connection); + + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +static void veth_sendCap(struct VethLpConnection *connection) +{ + if (connection->mMsgs == NULL) + { + connection->mMyCap.mUnionData.mFields.mNumberBuffers = VethBuffersToAllocate; + veth_msgsInit(connection); + } + else + { + veth_finishSendCap(connection); + } +} + +static void veth_finishSendCap(struct VethLpConnection *connection) +{ + HvLpEvent_Rc returnCode = HvCallEvent_signalLpEventFast(connection->mRemoteLp, + HvLpEvent_Type_VirtualLan, + VethEventTypeCap, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + connection->mSourceInst, + connection->mTargetInst, + 0, + connection->mMyCap.mUnionData.mNoFields.mReserved1, + connection->mMyCap.mUnionData.mNoFields.mReserved2, + connection->mMyCap.mUnionData.mNoFields.mReserved3, + connection->mMyCap.mUnionData.mNoFields.mReserved4, + connection->mMyCap.mUnionData.mNoFields.mReserved5); + + if ((returnCode == HvLpEvent_Rc_PartitionDead) || + (returnCode == HvLpEvent_Rc_PathClosed)) + { + connection->mConnectionStatus.mSentCap = 0; + } + else if (returnCode != HvLpEvent_Rc_Good) + { + veth_error_printk("Couldn't send cap to lpar %d, rc %Lx\n", connection->mRemoteLp, returnCode); + veth_failMe(connection); + } + else + { + connection->mConnectionStatus.mSentCap = 1; + } +} + +static void veth_takeCap(struct VethLpConnection *connection, struct VethLpEvent *event) +{ + if (!test_and_set_bit(0,&(connection->mCapBhPending))) + { + connection->mCapBhTq.data = connection; + memcpy(&connection->mCapEvent, event, sizeof(connection->mCapEvent)); + queue_task(&connection->mCapBhTq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + else + { + veth_error_printk("Received a capabilities from lpar %d while already processing one\n", connection->mRemoteLp); + event->mBaseEvent.xRc = HvLpEvent_Rc_BufferNotAvailable; + HvCallEvent_ackLpEvent((struct HvLpEvent *)event); + } +} + +static void veth_takeCapAck(struct VethLpConnection *connection, struct VethLpEvent *event) +{ + if (!test_and_set_bit(0,&(connection->mCapAckBhPending))) + { + connection->mCapAckBhTq.data = connection; + memcpy(&connection->mCapAckEvent, event, sizeof(connection->mCapAckEvent)); + queue_task(&connection->mCapAckBhTq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + else + { + veth_error_printk("Received a capabilities ack from lpar %d while already processing one\n", connection->mRemoteLp); + } +} + +static void veth_takeMonitorAck(struct VethLpConnection *connection, struct VethLpEvent *event) +{ + if (!test_and_set_bit(0,&(connection->mMonitorAckBhPending))) + { + connection->mMonitorAckBhTq.data = connection; + memcpy(&connection->mMonitorAckEvent, event, sizeof(connection->mMonitorAckEvent)); + queue_task(&connection->mMonitorAckBhTq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + else + { + veth_error_printk("Received a monitor ack from lpar %d while already processing one\n", connection->mRemoteLp); + } +} + +static void veth_recycleMsg(struct VethLpConnection *connection, u16 msg) +{ + if (msg < connection->mNumMsgs) + { + struct VethMsg *myMsg = connection->mMsgs + msg; + if (test_and_clear_bit(0, &(myMsg->mInUse))) + { + pci_unmap_single(NULL, + myMsg->mEvent.mSendData.mAddress[0], + myMsg->mEvent.mSendData.mLength[0], + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(myMsg->mSkb); + + myMsg->mSkb = NULL; + memset(&(myMsg->mEvent.mSendData), 0, sizeof(struct VethFramesData)); + VETHSTACKPUSH(&connection->mMsgStack, myMsg); + } + else + { + if (connection->mConnectionStatus.mOpen) + { + veth_error_printk("Received a frames ack for msg %d from lpar %d while not outstanding\n", msg, connection->mRemoteLp); + } + } + } +} + +static void veth_capBh(struct VethLpConnection *connection) +{ + struct VethLpEvent *event = &connection->mCapEvent; + unsigned long flags; + struct VethCapData *remoteCap = &(connection->mRemoteCap); + u64 numAcks = 0; + spin_lock_irqsave(&connection->mStatusGate, flags); + connection->mConnectionStatus.mGotCap = 1; + + memcpy(remoteCap, &(event->mDerivedData.mCapabilitiesData), sizeof(connection->mRemoteCap)); + + if ((remoteCap->mUnionData.mFields.mNumberBuffers <= VethMaxFramesMsgs) && + (remoteCap->mUnionData.mFields.mNumberBuffers != 0) && + (remoteCap->mUnionData.mFields.mThreshold <= VethMaxFramesMsgsAcked) && + (remoteCap->mUnionData.mFields.mThreshold != 0)) + { + numAcks = (remoteCap->mUnionData.mFields.mNumberBuffers / remoteCap->mUnionData.mFields.mThreshold) + 1; + + if (connection->mNumberLpAcksAlloced < numAcks) + { + numAcks = numAcks - connection->mNumberLpAcksAlloced; + connection->mAllocBhTq.routine = (void *)(void *)veth_finishCapBh; + mf_allocateLpEvents(connection->mRemoteLp, + HvLpEvent_Type_VirtualLan, + sizeof(struct VethLpEvent), + numAcks, + &veth_intFinishCapBh, + connection); + } + else + veth_finishCapBhLocked(connection); + } + else + { + veth_error_printk("Received incompatible capabilities from lpar %d\n", connection->mRemoteLp); + event->mBaseEvent.xRc = HvLpEvent_Rc_InvalidSubtypeData; + HvCallEvent_ackLpEvent((struct HvLpEvent *)event); + } + + clear_bit(0,&(connection->mCapBhPending)); + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +static void veth_capAckBh(struct VethLpConnection *connection) +{ + struct VethLpEvent *event = &connection->mCapAckEvent; + unsigned long flags; + + spin_lock_irqsave(&connection->mStatusGate, flags); + + if (event->mBaseEvent.xRc == HvLpEvent_Rc_Good) + { + connection->mConnectionStatus.mCapAcked = 1; + + if ((connection->mConnectionStatus.mGotCap == 1) && + (connection->mConnectionStatus.mGotCapAcked == 1)) + { + if (connection->mConnectionStatus.mSentMonitor != 1) + veth_sendMonitor(connection); + } + } + else + { + veth_error_printk("Bad rc(%d) from lpar %d on capabilities\n", event->mBaseEvent.xRc, connection->mRemoteLp); + veth_failMe(connection); + } + + clear_bit(0,&(connection->mCapAckBhPending)); + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +static void veth_monitorAckBh(struct VethLpConnection *connection) +{ + unsigned long flags; + + spin_lock_irqsave(&connection->mStatusGate, flags); + + veth_failMe(connection); + + veth_printk("Monitor ack returned for lpar %d\n", connection->mRemoteLp); + + if (connection->mConnectionStatus.mOpen) + { + veth_closeConnection(connection->mRemoteLp, 0); + + udelay(100); + + queue_task(&connection->mMonitorAckBhTq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + else + { +#ifdef MODULE + if (VethModuleReopen) +#endif + veth_openConnection(connection->mRemoteLp, 0); +#ifdef MODULE + else + { + int i=0; + + for (i=0; i < connection->mNumMsgs; ++i) + { + veth_recycleMsg(connection, i); + } + } +#endif + clear_bit(0,&(connection->mMonitorAckBhPending)); + } + + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +#define number_of_pages(v, l) ((((unsigned long)(v) & ((1 << 12) - 1)) + (l) + 4096 - 1) / 4096) +#define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) + +static void veth_takeFrames(struct VethLpConnection *connection, struct VethLpEvent *event) +{ + int i; + struct VethPort *port = NULL; + struct BufList + { + union + { + struct + { + u32 token2; + u32 garbage; + } token1; + u64 address; + } addr; + u64 size; + }; + + struct BufList myBufList[4]; + struct BufList remoteList; + + for (i=0; i < VethMaxFramesPerMsg; ++i) + { + u16 length = event->mDerivedData.mSendData.mLength[i]; + u32 address = event->mDerivedData.mSendData.mAddress[i]; + if ((address != 0) && + (length <= 9018) && + (length > 14)) + { + struct sk_buff *skb = alloc_skb(event->mDerivedData.mSendData.mLength[i], GFP_ATOMIC); + remoteList.addr.token1.token2 = address; + remoteList.size = length; + if (skb != NULL) + { + HvLpDma_Rc returnCode = HvLpDma_Rc_Good; + int numPages = number_of_pages((skb->data), length); + int i; + + + myBufList[0].addr.address = (0x8000000000000000LL | (virt_to_absolute((unsigned long)skb->data))); + myBufList[0].size = (numPages > 1) ? (4096 - page_offset(skb->data)) : length; + + if (numPages > 1) + { + myBufList[1].addr.address = (0x8000000000000000LL | (virt_to_absolute((unsigned long) skb->data + myBufList[0].size))); + myBufList[1].size = (numPages > 2) ? (4096 - page_offset(skb->data)) : length - myBufList[0].size; + + if (numPages > 2) + { + myBufList[2].addr.address = (0x8000000000000000LL | (virt_to_absolute((unsigned long) skb->data + myBufList[0].size + myBufList[1].size))); + myBufList[2].size = (numPages > 3) ? (4096 - page_offset(skb->data)) : length - myBufList[1].size - myBufList[0].size; + + if (numPages > 3) + { + myBufList[3].addr.address = 0x8000000000000000LL | (virt_to_absolute((unsigned long) skb->data + myBufList[0].size + myBufList[1].size + myBufList[2].size)); + myBufList[3].size = (numPages > 4) ? (4096 - page_offset(skb->data)) : length - myBufList[2].size - myBufList[1].size - myBufList[0].size; + } + } + } + + returnCode = HvCallEvent_dmaBufList(HvLpEvent_Type_VirtualLan, + event->mBaseEvent.xSourceLp, + HvLpDma_Direction_RemoteToLocal, + connection->mSourceInst, + connection->mTargetInst, + HvLpDma_AddressType_RealAddress, + HvLpDma_AddressType_TceIndex, + 0x8000000000000000LL | (virt_to_absolute((unsigned long)&myBufList)), + 0x8000000000000000LL | (virt_to_absolute((unsigned long)&remoteList)), + length); + + if (returnCode == HvLpDma_Rc_Good) + { + HvLpVirtualLanIndex vlan = skb->data[9]; + u64 dest = *((u64 *)skb->data) & 0xFFFFFFFFFFFF0000; + port = mFabricMgr->mPorts[vlan]; + + if (((vlan < HvMaxArchitectedVirtualLans) && + (port != NULL)) && + ((dest == port->mMyAddress) || /* it's for me */ + (veth_multicast_wanted(port, dest))) || /* it's one of my multicasts */ + (dest == 0xFFFFFFFFFFFF0000) || /* it's a broadcast */ + (port->mPromiscuous == 1)) /* I'm promiscuous */ + { + skb_put(skb, length); + skb->dev = mFabricMgr->mPorts[vlan]->mDev; + skb->protocol = eth_type_trans(skb, mFabricMgr->mPorts[vlan]->mDev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); /* send it up */ + port->mStats.rx_packets++; + port->mStats.rx_bytes += length; + + } + else + { + dev_kfree_skb_irq(skb); + } + } + else + { + printk("bad lp event rc %x length %d remote address %x raw address %x\n", (int)returnCode, length, remoteList.addr.token1.token2, address); + dev_kfree_skb_irq(skb); + } + } + } + else + break; + } + /* Ack it */ + + { + unsigned long flags; + spin_lock_irqsave(&connection->mAckGate, flags); + + if (connection->mNumAcks < VethMaxFramesMsgsAcked) + { + connection->mEventData.mAckData.mToken[connection->mNumAcks] = event->mBaseEvent.xCorrelationToken; + ++connection->mNumAcks; + + if (connection->mNumAcks == connection->mRemoteCap.mUnionData.mFields.mThreshold) + { + HvLpEvent_Rc rc = HvCallEvent_signalLpEventFast(connection->mRemoteLp, + HvLpEvent_Type_VirtualLan, + VethEventTypeFramesAck, + HvLpEvent_AckInd_NoAck, + HvLpEvent_AckType_ImmediateAck, + connection->mSourceInst, + connection->mTargetInst, + 0, + connection->mEventData.mFpData.mData1, + connection->mEventData.mFpData.mData2, + connection->mEventData.mFpData.mData3, + connection->mEventData.mFpData.mData4, + connection->mEventData.mFpData.mData5); + + if (rc != HvLpEvent_Rc_Good) + { + veth_error_printk("Bad lp event return code(%Lx) acking frames from lpar %d\n", rc, connection->mRemoteLp); + } + + connection->mNumAcks = 0; + + memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData)); + } + + } + + spin_unlock_irqrestore(&connection->mAckGate, flags); + } +} +#undef number_of_pages +#undef page_offset + +static void veth_timedAck(unsigned long connectionPtr) +{ + unsigned long flags; + HvLpEvent_Rc rc; + struct VethLpConnection *connection = (struct VethLpConnection *) connectionPtr; + /* Ack all the events */ + spin_lock_irqsave(&connection->mAckGate, flags); + + if (connection->mNumAcks > 0) + { + rc = HvCallEvent_signalLpEventFast(connection->mRemoteLp, + HvLpEvent_Type_VirtualLan, + VethEventTypeFramesAck, + HvLpEvent_AckInd_NoAck, + HvLpEvent_AckType_ImmediateAck, + connection->mSourceInst, + connection->mTargetInst, + 0, + connection->mEventData.mFpData.mData1, + connection->mEventData.mFpData.mData2, + connection->mEventData.mFpData.mData3, + connection->mEventData.mFpData.mData4, + connection->mEventData.mFpData.mData5); + + if (rc != HvLpEvent_Rc_Good) + { + veth_error_printk("Bad lp event return code(%Lx) acking frames from lpar %d!\n", rc, connection->mRemoteLp); + } + + connection->mNumAcks = 0; + + memset(&connection->mEventData, 0xFF, sizeof(connection->mEventData)); + } + + spin_unlock_irqrestore(&connection->mAckGate, flags); + + /* Reschedule the timer */ + connection->mAckTimer.expires = jiffies + connection->mTimeout; + add_timer(&connection->mAckTimer); +} + +static int veth_multicast_wanted(struct VethPort *port, u64 thatAddr) +{ + int returnParm = 0; + int i; + unsigned long flags; + + if ((*((char *)&thatAddr) & 0x01) != 1) + return 0; + + read_lock_irqsave(&port->mMcastGate, flags); + if (port->mAllMcast) + return 1; + + for (i=0; i < port->mNumAddrs; ++i) + { + u64 thisAddr = port->mMcasts[i]; + + if (thisAddr == thatAddr) + { + returnParm = 1; + break; + } + } + read_unlock_irqrestore(&port->mMcastGate, flags); + + return returnParm; +} + +static void veth_sendMonitor(struct VethLpConnection *connection) +{ + HvLpEvent_Rc returnCode = HvCallEvent_signalLpEventFast(connection->mRemoteLp, + HvLpEvent_Type_VirtualLan, + VethEventTypeMonitor, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_DeferredAck, + connection->mSourceInst, + connection->mTargetInst, + 0, 0, 0, 0, 0, 0); + + if (returnCode == HvLpEvent_Rc_Good) + { + connection->mConnectionStatus.mSentMonitor = 1; + connection->mConnectionStatus.mFailed = 0; + + /* Start the ACK timer */ + init_timer(&connection->mAckTimer); + connection->mAckTimer.function = veth_timedAck; + connection->mAckTimer.data = (unsigned long) connection; + connection->mAckTimer.expires = jiffies + connection->mTimeout; + add_timer(&connection->mAckTimer); + + } + else + { + veth_error_printk("Monitor send to lpar %d failed with rc %Lx\n", connection->mRemoteLp, returnCode); + veth_failMe(connection); + } +} + +static void veth_finishCapBh(struct VethLpConnection *connection) +{ + unsigned long flags; + spin_lock_irqsave(&connection->mStatusGate, flags); + veth_finishCapBhLocked(connection); + spin_unlock_irqrestore(&connection->mStatusGate, flags); +} + +static void veth_finishCapBhLocked(struct VethLpConnection *connection) +{ + struct VethLpEvent *event = &connection->mCapEvent; + struct VethCapData *remoteCap = &(connection->mRemoteCap); + int numAcks = (remoteCap->mUnionData.mFields.mNumberBuffers / remoteCap->mUnionData.mFields.mThreshold) + 1; + + /* Convert timer to jiffies */ + if (connection->mMyCap.mUnionData.mFields.mTimer) + connection->mTimeout = remoteCap->mUnionData.mFields.mTimer * HZ / 1000000; + else + connection->mTimeout = VethAckTimeoutUsec * HZ / 1000000; + + if (connection->mNumberLpAcksAlloced >= numAcks) + { + HvLpEvent_Rc returnCode = HvCallEvent_ackLpEvent((struct HvLpEvent *)event); + + if (returnCode == HvLpEvent_Rc_Good) + { + connection->mConnectionStatus.mGotCapAcked = 1; + + if (connection->mConnectionStatus.mSentCap != 1) + { + connection->mTargetInst = HvCallEvent_getTargetLpInstanceId(connection->mRemoteLp, HvLpEvent_Type_VirtualLan); + + veth_sendCap(connection); + } + else if (connection->mConnectionStatus.mCapAcked == 1) + { + if (connection->mConnectionStatus.mSentMonitor != 1) + veth_sendMonitor(connection); + } + } + else + { + veth_error_printk("Failed to ack remote cap for lpar %d with rc %Lx\n", connection->mRemoteLp, returnCode); + veth_failMe(connection); + } + } + else + { + veth_error_printk("Couldn't allocate all the frames ack events for lpar %d\n", connection->mRemoteLp); + event->mBaseEvent.xRc = HvLpEvent_Rc_BufferNotAvailable; + HvCallEvent_ackLpEvent((struct HvLpEvent *)event); + } +} + +int proc_veth_dump_connection +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *out = page; + int whichConnection = (int) data; + int len = 0; + struct VethLpConnection *connection = NULL; + + if ((whichConnection < 0) || (whichConnection > HvMaxArchitectedLps) || (mFabricMgr == NULL)) + { + veth_error_printk("Got bad data from /proc file system\n"); + len = sprintf(page, "ERROR\n"); + } + else + { + int thereWasStuffBefore = 0; + connection = &(mFabricMgr->mConnection[whichConnection]); + + out += sprintf(out, "Remote Lp:\t%d\n", connection->mRemoteLp); + out += sprintf(out, "Source Inst:\t%04X\n", connection->mSourceInst); + out += sprintf(out, "Target Inst:\t%04X\n", connection->mTargetInst); + out += sprintf(out, "Num Msgs:\t%d\n", connection->mNumMsgs); + out += sprintf(out, "Num Lp Acks:\t%d\n", connection->mNumberLpAcksAlloced); + out += sprintf(out, "Num Acks:\t%d\n", connection->mNumAcks); + + if (connection->mConnectionStatus.mOpen) + { + out += sprintf(out, "mConnectionStatus.mCapMonAlloced) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "CapMonAlloced"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mBaseMsgsAlloced) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "BaseMsgsAlloced"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mSentCap) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "SentCap"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mCapAcked) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "CapAcked"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mGotCap) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "GotCap"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mGotCapAcked) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "GotCapAcked"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mSentMonitor) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "SentMonitor"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mPopulatedRings) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "PopulatedRings"); + thereWasStuffBefore = 1; + } + + if (connection->mConnectionStatus.mFailed) + { + if (thereWasStuffBefore) + out += sprintf(out,"/"); + else + out += sprintf(out,"<"); + out += sprintf(out, "Failed"); + thereWasStuffBefore = 1; + } + + if (thereWasStuffBefore) + out += sprintf(out, ">"); + + out += sprintf(out, "\n"); + + out += sprintf(out, "Capabilities (System:):\n"); + out += sprintf(out, "\tLocal:<"); + out += sprintf(out, "%d/%d/%d/%d>\n", + connection->mMyCap.mUnionData.mFields.mVersion, + connection->mMyCap.mUnionData.mFields.mNumberBuffers, + connection->mMyCap.mUnionData.mFields.mThreshold, + connection->mMyCap.mUnionData.mFields.mTimer); + out += sprintf(out, "\tRemote:<"); + out += sprintf(out, "%d/%d/%d/%d>\n", + connection->mRemoteCap.mUnionData.mFields.mVersion, + connection->mRemoteCap.mUnionData.mFields.mNumberBuffers, + connection->mRemoteCap.mUnionData.mFields.mThreshold, + connection->mRemoteCap.mUnionData.mFields.mTimer); + len = out - page; + } + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + return len; +} + +int proc_veth_dump_port +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *out = page; + int whichPort = (int) data; + int len = 0; + struct VethPort *port = NULL; + + if ((whichPort < 0) || (whichPort > HvMaxArchitectedVirtualLans) || (mFabricMgr == NULL)) + len = sprintf(page, "Virtual ethernet is not configured.\n"); + else + { + int i=0; + u32 *myAddr; + u16 *myEndAddr; + port = mFabricMgr->mPorts[whichPort]; + + if (port != NULL) + { + myAddr = (u32 *)&(port->mMyAddress); + myEndAddr = (u16 *)(myAddr + 1); + out += sprintf(out, "Net device:\t%p\n", port->mDev); + out += sprintf(out, "Address:\t%08X%04X\n", myAddr[0], myEndAddr[0]); + out += sprintf(out, "Promiscuous:\t%d\n", port->mPromiscuous); + out += sprintf(out, "All multicast:\t%d\n", port->mAllMcast); + out += sprintf(out, "Number multicast:\t%d\n", port->mNumAddrs); + + for (i=0; i < port->mNumAddrs; ++i) + { + u32 *multi = (u32 *)&(port->mMcasts[i]); + u16 *multiEnd = (u16 *)(multi + 1); + out += sprintf(out, " %08X%04X\n", multi[0], multiEnd[0]); + } + } + else + { + out += sprintf(page, "veth%d is not configured.\n", whichPort); + } + + len = out - page; + } + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + return len; +} + + diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/net/veth.h linuxppc64_2_4/drivers/net/veth.h --- linux-2.4.9-ac10/drivers/net/veth.h Wed Dec 31 18:00:00 1969 +++ linuxppc64_2_4/drivers/net/veth.h Fri May 4 17:12:47 2001 @@ -0,0 +1,255 @@ +/* File veth.h created by Kyle A. Lucke on Mon Aug 7 2000. */ + +/* Change Activity: */ +/* End Change Activity */ + +#ifndef _VETH_H +#define _VETH_H + +#ifndef _HVTYPES_H +#include +#endif +#ifndef _HVLPEVENT_H +#include +#endif +#include + +#define VethEventNumTypes (4) +#define VethEventTypeCap (0) +#define VethEventTypeFrames (1) +#define VethEventTypeMonitor (2) +#define VethEventTypeFramesAck (3) + +#define VethMaxFramesMsgsAcked (20) +#define VethMaxFramesMsgs (0xFFFF) +#define VethMaxFramesPerMsg (6) +#define VethAckTimeoutUsec (1000000) + +#define VETHSTACKTYPE(T) struct VethStack##T +#define VETHSTACK(T) \ +VETHSTACKTYPE(T) \ +{ \ +struct T *head; \ +spinlock_t lock; \ +} +#define VETHSTACKCTOR(s) do { (s)->head = NULL; spin_lock_init(&(s)->lock); } while(0) +#define VETHSTACKPUSH(s, p) \ +do { \ +unsigned long flags; \ +spin_lock_irqsave(&(s)->lock,flags); \ +(p)->next = (s)->head; \ +(s)->head = (p); \ +spin_unlock_irqrestore(&(s)->lock, flags); \ +} while(0) + +#define VETHSTACKPOP(s,p) \ +do { \ +unsigned long flags; \ +spin_lock_irqsave(&(s)->lock,flags); \ +(p) = (s)->head; \ +if ((s)->head != NULL) \ +{ \ +(s)->head = (s)->head->next; \ +} \ +spin_unlock_irqrestore(&(s)->lock, flags); \ +} while(0) + +#define VETHQUEUE(T) \ +struct VethQueue##T \ +{ \ +T *head; \ +T *tail; \ +spinlock_t lock; \ +} +#define VETHQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; spin_lock_init(&(q)->lock); } while(0) +#define VETHQUEUEENQ(q, p) \ +do { \ +unsigned long flags; \ +spin_lock_irqsave(&(q)->lock,flags); \ +(p)->next = NULL; \ +if ((q)->head != NULL) \ +{ \ +(q)->head->next = (p); \ +(q)->head = (p); \ +} \ +else \ +{ \ +(q)->tail = (q)->head = (p); \ +} \ +spin_unlock_irqrestore(&(q)->lock, flags); \ +} while(0) + +#define VETHQUEUEDEQ(q,p) \ +do { \ +unsigned long flags; \ +spin_lock_irqsave(&(q)->lock,flags); \ +(p) = (q)->tail; \ +if ((p) != NULL) \ +{ \ +(q)->tail = (p)->next; \ +(p)->next = NULL; \ +} \ +if ((q)->tail == NULL) \ +(q)->head = NULL; \ +spin_unlock_irqrestore(&(q)->lock, flags); \ +} while(0) + +struct VethFramesData +{ + u32 mAddress[6]; + u16 mLength[6]; + u32 mEofMask; +}; + +struct VethFramesAckData +{ + u16 mToken[VethMaxFramesMsgsAcked]; +}; + +struct VethCapData +{ + union + { + struct Fields + { + u8 mVersion; + u8 mReserved1; + u16 mNumberBuffers; + u16 mThreshold; + u16 mReserved2; + u32 mTimer; + u32 mReserved3; + u64 mReserved4; + u64 mReserved5; + u64 mReserved6; + } mFields; + struct NoFields + { + u64 mReserved1; + u64 mReserved2; + u64 mReserved3; + u64 mReserved4; + u64 mReserved5; + } mNoFields; + } mUnionData; +}; + +struct VethFastPathData +{ + u64 mData1; + u64 mData2; + u64 mData3; + u64 mData4; + u64 mData5; +}; + +struct VethLpEvent +{ + struct HvLpEvent mBaseEvent; + union { + struct VethFramesData mSendData; + struct VethCapData mCapabilitiesData; + struct VethFramesAckData mFramesAckData; + struct VethFastPathData mFastPathData; + } mDerivedData; + +}; + +struct VethMsg +{ + struct VethMsg *next; + union { + struct VethFramesData mSendData; + struct VethFastPathData mFpData; + } mEvent; + int mIndex; + unsigned long mInUse; + struct sk_buff *mSkb; +}; + + +struct VethControlBlock +{ + struct net_device *mDev; + struct VethControlBlock *mNext; + HvLpVirtualLanIndex mVlanId; +}; + +struct VethLpConnection +{ + u64 mEyecatcher; + HvLpIndex mRemoteLp; + HvLpInstanceId mSourceInst; + HvLpInstanceId mTargetInst; + u32 mNumMsgs; + struct VethMsg *mMsgs; + int mNumberRcvMsgs; + int mNumberLpAcksAlloced; + union + { + struct VethFramesAckData mAckData; + struct VethFastPathData mFpData; + } mEventData; + spinlock_t mAckGate; + u32 mNumAcks; + spinlock_t mStatusGate; + struct + { + u64 mOpen : 1; + u64 mCapMonAlloced : 1; + u64 mBaseMsgsAlloced : 1; + u64 mSentCap : 1; + u64 mCapAcked : 1; + u64 mGotCap : 1; + u64 mGotCapAcked : 1; + u64 mSentMonitor : 1; + u64 mPopulatedRings : 1; + u64 mReserved : 54; + u64 mFailed : 1; + } mConnectionStatus; + struct VethCapData mMyCap; + struct VethCapData mRemoteCap; + unsigned long mCapAckBhPending; + struct tq_struct mCapAckBhTq; + struct VethLpEvent mCapAckEvent; + unsigned long mCapBhPending; + struct tq_struct mCapBhTq; + struct VethLpEvent mCapEvent; + unsigned long mMonitorAckBhPending; + struct tq_struct mMonitorAckBhTq; + struct VethLpEvent mMonitorAckEvent; + unsigned long mAllocBhPending; + struct tq_struct mAllocBhTq; + int mNumberAllocated; + struct timer_list mAckTimer; + u32 mTimeout; + VETHSTACK(VethMsg) mMsgStack; +}; +#define HVMAXARCHITECTEDVIRTUALLANS 16 +struct VethPort +{ + struct net_device *mDev; + struct net_device_stats mStats; + int mLock; + u64 mMyAddress; + int mPromiscuous; + int mAllMcast; + rwlock_t mMcastGate; + int mNumAddrs; + u64 mMcasts[12]; +}; + +struct VethFabricMgr +{ + u64 mEyecatcher; + HvLpIndex mThisLp; + struct VethLpConnection mConnection[HVMAXARCHITECTEDLPS]; + spinlock_t mPortListGate; + u64 mNumPorts; + struct VethPort *mPorts[HVMAXARCHITECTEDVIRTUALLANS]; +}; + +int proc_veth_dump_connection(char *page, char **start, off_t off, int count, int *eof, void *data); +int proc_veth_dump_port(char *page, char **start, off_t off, int count, int *eof, void *data); + +#endif /* _VETH_H */ diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/pci/pci.c linuxppc64_2_4/drivers/pci/pci.c --- linux-2.4.9-ac10/drivers/pci/pci.c Mon Sep 10 11:58:11 2001 +++ linuxppc64_2_4/drivers/pci/pci.c Thu Sep 6 15:58:26 2001 @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $ + * * * PCI Bus Services, see include/linux/pci.h for further explanation. * @@ -876,6 +876,14 @@ u32 l, sz; struct resource *res; + /************************************************************ + * Check for architecture dependant call to read the BARs. + ************************************************************/ + if( dev->bus->ops->pci_read_bases != NULL) { + dev->bus->ops->pci_read_bases(dev, howmany, rom); + return; + } + for(pos=0; posresource[pos]; @@ -1167,6 +1175,14 @@ static void pci_read_irq(struct pci_dev *dev) { unsigned char irq; + + /************************************************************ + * Check for architecture dependant call to read and set irg + ************************************************************/ + if(dev->bus->ops->pci_read_irq != NULL) { + dev->bus->ops->pci_read_irq(dev); + return; + } pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq); if (irq) @@ -1188,7 +1204,17 @@ { u32 class; - sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + /* sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); */ + + + /******************************************************************** + * Prefix the bus number with the phb number for large(>256 bus) systems. + ********************************************************************/ + sprintf(dev->slot_name, "%4x%02x:%02x.%1x", + ( (dev->bus->number>>8) &0xFF0000), + ( dev->bus->number&0x0000FF), + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); @@ -1235,6 +1261,14 @@ printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n", dev->slot_name, class, dev->hdr_type); dev->class = PCI_CLASS_NOT_DEFINED; + } + + + /********************************************************************* + * Give the architure code a chance to fix up/tweak the devices. + *********************************************************************/ + if(dev->bus->ops->pci_fixup_registers != NULL) { + dev->bus->ops->pci_fixup_registers(dev); } /* We found a fine healthy device, go go go... */ diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/scsi/scsi_scan.c linuxppc64_2_4/drivers/scsi/scsi_scan.c --- linux-2.4.9-ac10/drivers/scsi/scsi_scan.c Thu Sep 6 14:03:46 2001 +++ linuxppc64_2_4/drivers/scsi/scsi_scan.c Mon Sep 10 15:30:00 2001 @@ -305,8 +305,13 @@ scsi_initialize_queue(SDpnt, shpnt); SDpnt->request_queue.queuedata = (void *) SDpnt; /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ((!shpnt->unchecked_isa_dma) - ? &scsi_result0[0] : kmalloc(512, GFP_DMA)); + ? &scsi_result0[0] : kmalloc(512, GFP_DMA)); + + /* scsi_result = kmalloc(512, (shpnt->unchecked_isa_dma)?GFP_KERNEL:GFP_DMA); */ + + } if (scsi_result == NULL) { diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/scsi/sr_ioctl.c linuxppc64_2_4/drivers/scsi/sr_ioctl.c --- linux-2.4.9-ac10/drivers/scsi/sr_ioctl.c Thu Sep 6 14:03:42 2001 +++ linuxppc64_2_4/drivers/scsi/sr_ioctl.c Mon Sep 10 14:15:34 2001 @@ -334,7 +334,12 @@ { u_char sr_cmd[10]; int result, target = MINOR(cdi->dev); - unsigned char buffer[32]; + unsigned char *buffer = scsi_malloc(512); + + if (buffer == NULL) { + printk("SCSI DMA pool exhausted."); + return -ENOMEM; + } memset(sr_cmd, 0, sizeof(sr_cmd)); @@ -407,6 +412,7 @@ return -EINVAL; } + scsi_free(buffer, 512); #if 0 if (result) printk("DEBUG: sr_audio: result for ioctl %x: %x\n", cmd, result); diff -uNr --exclude=CVS linux-2.4.9-ac10/drivers/video/offb.c linuxppc64_2_4/drivers/video/offb.c --- linux-2.4.9-ac10/drivers/video/offb.c Thu Sep 6 14:03:58 2001 +++ linuxppc64_2_4/drivers/video/offb.c Tue Sep 4 14:09:20 2001 @@ -32,7 +32,9 @@ #endif #include #include +#ifndef CONFIG_PPC64 #include +#endif #include