diff -u --recursive --new-file v2.1.78/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.78/linux/Documentation/Configure.help Fri Jan 2 14:37:01 1998 +++ linux/Documentation/Configure.help Mon Jan 12 14:46:16 1998 @@ -1,4 +1,4 @@ -# Maintained by Axel Boldt (boldt@math.ucsb.edu) +# Maintained by Axel Boldt (boldt@math.ucsb.edu) # # This version of the Linux kernel configuration help texts # corresponds to the kernel versions 2.1.x. Be aware that these are @@ -333,17 +333,6 @@ enable DMA for drives which were not enabled automatically. You can get the latest version of the hdparm utility via anonymous FTP from sunsite.unc.edu/pub/Linux/system/hardware/ - It is safe to say Y to this question. - - If your PCI system uses IDE drive(s) (as opposed to SCSI, say) - and is capable of bus-master DMA operation (most Pentium PCI - systems), you will want to enable this option to allow use of - bus-mastering DMA data transfers. Read the comments at the - beginning of drivers/block/idedma.c and Documentation/ide.txt. - You can get the latest version of the hdparm utility via - ftp (user: anonymous) from - sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is - used to tune your harddisk. It is safe to say Y to this question. Other IDE chipset support @@ -3526,28 +3515,6 @@ sdla.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -WAN Router -CONFIG_WAN_ROUTER - Wide Area Networks (WANs), such as X.25, frame relay and leased - lines, are used to interconnect Local Area Networks (LANs) over vast - distances with data transfer rates significantly higher than those - achievable with commonly used asynchronous modem connections. - Usually, a quite expensive external device called `WAN router' is - needed to connect to a WAN. - As an alternative, WAN routing can be built into the Linux - kernel. With relatively inexpensive WAN interface cards available - on the market, a perfectly usable router can be built for less than - half the price of an external router. If you have one of those - cards (with appropriate WAN Link Driver) and wish to use your Linux - box as a WAN router, you may say 'Y' to this option. You will also - need a wan-tools package available via FTP (user: anonymous) from - ftp.sangoma.com. Read Documentation/networking/wan-router.txt for - more information. - WAN routing is always built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called wanrouter.o. For general information about - modules read Documentation/modules.txt. - CPU is too slow to handle full bandwidth CONFIG_CPU_IS_SLOW ### @@ -3651,68 +3618,79 @@ ### schedulers? ### +WAN Router +CONFIG_WAN_ROUTER + Wide Area Networks (WANs), such as X.25, frame relay and leased + lines, are used to interconnect Local Area Networks (LANs) over vast + distances with data transfer rates significantly higher than those + achievable with commonly used asynchronous modem connections. + Usually, a quite expensive external device called `WAN router' is + needed to connect to WAN. + As an alternative, WAN router can be build into Linux kernel. + With relatively inexpensive WAN interface cards available on the + market, a perfectly usable router can be built for less than half a + price of an external router. If you have one of those cards (with + appropriate WAN Link Driver) and wish to use your Linux box as a WAN + router, you may say 'Y' to this option. You will also need a + wan-tools package available via FTP (user: anonymous) from + ftp.sangoma.com. Read Documentation/networking/wan-router.txt for + more information. + WAN router is always built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + For general information about modules read Documentation/modules.txt. + WAN Drivers CONFIG_WAN_DRIVERS - Say Y to this option if you are planning to use your Linux box as a - WAN ( = Wide Area Network) router ( = device used to interconnect - local area networks over wide area communication links, such as - leased lines and public data networks, e.g. X.25 and frame relay) - and you will be offered a list of WAN drivers currently available. - For more information, read - Documentation/networking/wan-router.txt. Note that the answer to - this question won't directly affect the kernel: saying N will just - cause this configure script to skip all the questions about WAN - drivers. If unsure, say N. + Say 'Y' to this option if you are planning to use your Linux box + as a WAN router ( = device used to interconnect local area networks + over wide area communication links, such as leased lines and public + data networks, e.g. X.25 and frame relay) and you will be offered a + list of WAN drivers currently available. For more information, read + Documentation/networking/wan-router.txt. Sangoma WANPIPE(tm) multiprotocol cards CONFIG_VENDOR_SANGOMA - WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com; to - browse the WWW, you need to have access to a machine on the Internet - that has a program like lynx or netscape) is a family of intelligent - multiprotocol WAN adapters with data transfer rates up to T1 (1.544 - Mbps). They are also known as Synchronous Data Link Adapters (SDLA) - and designated S502E(A), S503 or S508. These cards support the X.25, - Frame Relay, and PPP protocols. If you have one or more of these - cards, say Y to this option and read - Documentation/networking/wanpipe.txt. The next questions will ask - you about the protocols you want the driver to support. The driver - will be compiled as a module ( = code which can be inserted in and - removed from the running kernel whenever you want). The module will - be called wanpipe.o. For general information about modules read - Documentation/modules.txt. + WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com) + is a family of intelligent multiprotocol WAN adapter with data + transfer rates up to T1 (1.544 Mbps). They are also known as + Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503 + or S508. If you have one of these cards, say 'Y' to this option. + WANPIPE driver is always built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + For general information about modules read Documentation/modules.txt. Maximum number of cards CONFIG_WANPIPE_CARDS - Enter number of WANPIPE adapters installed in your machine. The - driver can support up to 8 cards. You may enter more than you + Enter number of WANPIPE adapters installed in your machine. The + driver can support up to 8 cards. You may enter more that you actually have if you plan to add more cards in the future without re-compiling the driver, but remember that in this case you'll waste some kernel memory (about 1K per card). WANPIPE X.25 support CONFIG_WANPIPE_X25 - Say Y to this option, if you are planning to connect a WANPIPE card - to an X.25 network. You should then also have said Y to "CCITT X.25 - Packet Layer" and "LAPB Data Link Driver", above. If you say N, the - X.25 support will not be included in the driver (saves about 16K of - kernel memory). + Say 'Y' to this option, if you are planning to connect WANPIPE + card to an X.25 network. If you say 'N', the X.25 support will not + be included in the driver (saves about 16K of kernel memory). WANPIPE Frame Relay support CONFIG_WANPIPE_FR - Say Y to this option, if you are planning to connect a WANPIPE card - to a frame relay network. You should then also have said Y to "Frame - Relay (DLCI) support", above. If you say N, the frame relay + Say 'Y' to this option, if you are planning to connect WANPIPE + card to a frame relay network. If you say 'N', the frame relay support will not be included in the driver (saves about 16K of kernel memory). WANPIPE PPP support CONFIG_WANPIPE_PPP - Say Y to this option, if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). You should - then also have said Y to "PPP (point-to-point) support", above. If - you say N, the PPP support will not be included in the driver (saves + Say 'Y' to this option, if you are planning to connect WANPIPE + card to a leased line using Point-to-Point protocol (PPP). If you + say 'N', the PPP support will not be included in the driver (saves about 16K of kernel memory). + + Sun LANCE Ethernet support + CONFIG_SUN_LANCE + This is support for lance ethernet cards on Sun workstations such as Sun LANCE Ethernet support CONFIG_SUN_LANCE This is support for lance ethernet cards on Sun workstations such as @@ -7576,6 +7554,13 @@ removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. + +Colour QuickCam Video For Linux +CONFIG_VIDEO_CQCAM + This is the video4linux driver for the colour version of the Connectix + Quickcam. If you have one of these cameras, say Y here, otherwise say N. + This driver does not work with the original monochrome Quickcam, + Quickcam VC or QuickClip. It is also available as a module (c-qcam.o). Mediavision Pro Movie Studio Video For Linux CONFIG_VIDEO_PMS diff -u --recursive --new-file v2.1.78/linux/Documentation/filesystems/fat_cvf.txt linux/Documentation/filesystems/fat_cvf.txt --- v2.1.78/linux/Documentation/filesystems/fat_cvf.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/filesystems/fat_cvf.txt Thu Jan 8 14:02:41 1998 @@ -0,0 +1,190 @@ +This is the main documentation for the CVF-FAT filesystem extension. 31DEC1997 + + +Table of Contents: + +1. The idea of CVF-FAT +2. Restrictions +3. Mount options +4. Description of the CVF-FAT interface +5. CVF Modules + +------------------------------------------------------------------------------ + + +1. The idea of CVF-FAT +------------------------------------------------------------------------------ + +CVF-FAT is a FAT filesystem extension that provides a generic interface for +Compressed Volume Files in FAT partitions. Popular CVF software, for +example, are Microsoft's Doublespace/Drivespace and Stac's Stacker. +Using the CVF-FAT interface, it is possible to load a module that handles +all the low-level disk access that has to do with on-the-fly compression +and decompression. All other part of FAT filesystem access is still handled +by the FAT, MSDOS or VFAT or even UMSDOS driver. + +CVF access works by redirecting certain low-level routines from the FAT +driver to a loadable, CVF-format specific module. This module must fake +a normal FAT filesystem to the FAT driver while doing all the extra stuff +like compression and decompression silently. + + +2. Restrictions +------------------------------------------------------------------------------ + +- BMAP problems + + CVF filesystems cannot do bmap. It's impossible by principle. Thus + all actions that require bmap do not work (swapping, writable mmapping). + Read-only mmapping works because the FAT driver has a hack for this + situation :) Well, with some tricks writable mmapping could work, + (proof: they did under old dmsdos), but..... (hint: readpage/writepage + interface functions) ...... but the FAT driver has to support them + first without bmap :-) + + We'll see. If someone points me to an application that needs this, I + might be persuaded to implement it :). CVF-FAT is already prepared + for using readpage. + +- DOSEMU users attention + + You may have to unmount all CVF partitions before running DOSEMU depending + on your configuration. If DOSEMU is configured to use wholedisk or + partition access (this is often the case to let DOSEMU access + compressed partitions) there's a risk of destroying your compressed + partitions or crashing your system because of confused drivers. + + Note that it is always safe to redirect the compressed partitions with + lredir or emufs.sys. Refer to the DOSEMU documentation for details. + + +3. Mount options +------------------------------------------------------------------------------ + +The CVF-FAT extension currently adds the following options to the FAT +driver's standard options: + + cvf_format=xxx + Forces the driver to use the CVF module "xxx" instead of auto-detection. + This is only necessary if the CVF format is not recognized corrrectly + because of bugs or incompatibilities in the CVF modules. (It skips + the detect_cvf call.) "xxx" may be the text "none" (without the quotes) + to inhibit using any of the loaded CVF modules, just in case a CVF + module insists on mounting plain FAT filesystems by misunderstanding :) + + cvf_options=yyy + Option string passed to the CVF module. I.e. only the "yyy" is passed + (without the quotes). The documentation for each CVF module should + explain it since it is interpreted only by the CVF module. Note that + the string must not contain a comma (",") - this would lead to + misinterpretation by the FAT driver, which would recognize the text + after a comma as a FAT driver option and might get confused or print + strange error messages. The documentation for the CVF module should + offer a different seperation symbol, for example the dot ".", which + is only valid inside the string "yyy". + + +4. Description of the CVF-FAT interface +------------------------------------------------------------------------------ + +Assuming you want to write your own CVF module, you need to write a lot of +interface funtions. Most of them are covered in the kernel documentation +you can find on the net, and thus won't be described here. They have been +marked with "[...]" :-) Take a look at include/linux/fat_cvf.h. + +struct cvf_format +{ int cvf_version; + char* cvf_version_text; + unsigned long int flags; + int (*detect_cvf) (struct super_block*sb); + int (*mount_cvf) (struct super_block*sb,char*options); + int (*unmount_cvf) (struct super_block*sb); + [...] + void (*cvf_zero_cluster) (struct inode*inode,int clusternr); +} + +This structure defines the capabilities of a CVF module. It must be filled +out completely by a CVF module. Consider it as a kind of form that is used +to introduce the module to the FAT/CVF-FAT driver. + +It contains... + - cvf_version: + A version id which must be uniqe. Choose one. + - cvf_version_text: + A human readable version string that should be one short word + describing the CVF format the module implements. This text is used + for the cvf_format option. This name must also be uniqe. + - flags: + Bit coded flags, currently only used for a readpage/mmap hack that + provides both mmap and readpage functionality. If CVF_USE_READPAGE + is set, mmap is set to generic_file_mmap and readpage is caught + and redirected to the cvf_readpage function. If it is not set, + readpage is set to generic_readpage and mmap is caught and redirected + to cvf_mmap. + - detect_cvf: + A function that is called to decide whether the filesystem is a CVF of + the type the module supports. The detect_cvf function must return 0 + for "NO, I DON'T KNOW THIS GARBAGE" or anything !=0 for "YES, THIS IS + THE KIND OF CVF I SUPPORT". The function must maintain the module + usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning + and MOD_DEC_USE_COUNT at the end. The function *must not* assume that + successful recongition would lead to a call of the mount_cvf function + later. + - mount_cvf: + A function that sets up some values or initializes something additional + to what has to be done when a CVF is mounted. This is called at the + end of fat_read_super and must return 0 on success. Definitely, this + function must increment the module usage counter by MOD_INC_USE_COUNT. + This mount_cvf function is also responsible for interpreting a CVF + module specific option string (the "yyy" from the FAT mount option + "cvf_options=yyy") which cannot contain a comma (use for example the + dot "." as option separator symbol). + - unmount_cvf: + A function that is called when the filesystem is unmounted. Most likely + it only frees up some memory and calls MOD_DEC_USE_COUNT. The return + value might be ignored (it currently is ignored). + - [...]: + All other interface functions are "caught" FAT driver functions, i.e. + are executed by the FAT driver *instead* of the original FAT driver + functions. NULL means use the original FAT driver functions instead. + If you really want "no action", write a function that does nothing and + hang it in instead. + - cvf_zero_cluster: + The cvf_zero_cluster function is called when the fat driver wants to + zero out a (new) cluster. This is important for directories (mkdir). + If it is NULL, the FAT driver defaults to overwriting the whole + cluster with zeros. Note that clusternr is absolute, not relative + to the provided inode. + +Notes: + 1. The cvf_bmap function should be ignored. It really should never + get called from somewhere. I recommend redirecting it to a panic + or fatal error message so bugs show up immediately. + 2. The cvf_writepage function is ignored. This is because the fat + driver doesn't support it. This might change in future. I recommend + setting it to NULL (i.e use default). + +int register_cvf_format(struct cvf_format*cvf_format); + If you have just set up a variable containing the above structure, + call this function to introduce your CVF format to the FAT/CVF-FAT + driver. This is usually done in init_module. Be sure to check the + return value. Zero means success, everything else causes a kernel + message printed in the syslog describing the error that occured. + Typical errors are: + - a module with the same version id is already registered or + - too many CVF formats. Hack fs/fat/cvf.c if you need more. + +int unregister_cvf_format(struct cvf_format*cvf_format); + This is usually called in cleanup_module. Return value =0 means + success. An error only occurs if you try to unregister a CVF format + that has not been previously registered. The code uses the version id + to distinguish the modules, so be sure to keep it uniqe. + +5. CVS Modules +------------------------------------------------------------------------------ + +Refer to the dmsdos module (the successor of the dmsdos filesystem) for a +sample implementation. It can currently be found at + + ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos + diff -u --recursive --new-file v2.1.78/linux/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt --- v2.1.78/linux/Documentation/networking/wan-router.txt Thu Jul 17 10:06:03 1997 +++ linux/Documentation/networking/wan-router.txt Mon Jan 12 14:46:16 1998 @@ -1,6 +1,8 @@ ------------------------------------------------------------------------------ WAN Router for Linux Operating System ------------------------------------------------------------------------------ +Version 2.0.1 - Nov 28, 1997 +Version 2.0.0 - Nov 06, 1997 Version 1.0.3 - June 3, 1997 Version 1.0.1 - January 30, 1997 Author: Jaspreet Singh @@ -8,6 +10,11 @@ Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ + +WARNING: This Version of WANPIPE supports only the S508 and S508/FT1 cards. +IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR +AN UPGRADE. + INTRODUCTION Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) @@ -73,10 +80,14 @@ To ba able to use Linux WAN Router you will also need a WAN Tools package available from - ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz + ftp.sangoma.com/pub/linux/vX.Y.Z/wantools-X.Y.Z.tgz + or + ftp.sangoma.com/pub/linux/vX.Y.Z/wanpipe-X.Y.Z.tgz + +where vX.Y.Z represent the linux kernel version number. For technical questions and/or comments regarding this product please e-mail -to genek@compuserve.com or dm@sangoma.com. +to jaspreet@sangoma.com or dm@sangoma.com. @@ -117,19 +128,55 @@ REVISION HISTORY + +2.0.1 Nov 28, 1997 - Protection of "enable_irq()" while + "disable_irq()" has been enabled from any other + routine (for Frame Relay, PPP and X25). + - Added additional Stats for Fpipemon and Ppipemon - Improved Load Sharing for multiple boards. + + +2.0.0 Nov 07, 1997 - Implemented protection of RACE conditions by + critical flags for FRAME RELAY and PPP. + - DLCI List interrupt mode implemented. + - IPX support in FRAME RELAY and PPP. + - IPX Server Support (MARS) + - More driver specific stats included in FPIPEMON + and PIPEMON. + +1.0.5 July 28, 1997 - Configurable T391,T392,N391,N392,N393 for Frame + Relay in router.conf. + - Configurable Memory Address through router.conf + for Frame Relay, PPP and X.25. (commenting this + out enables auto-detection). + - Fixed freeing up received buffers using kfree() + for Frame Relay and X.25. + - Protect sdla_peek() by calling save_flags(), + cli() and restore_flags(). + - Changed number of Trace elements from 32 to 20 + - Added DLCI specific data monitoring in FPIPEMON. + +1.0.4 July 10, 1997 - S508/FT1 monitoring capability in fpipemon and + ppipemon utilities. + - Configurable TTL for UDP packets. + - Multicast and Broadcast IP source addresses are + silently discarded. + 1.0.3 June 3, 1997 - o UDP port for multiple boards (Frame relay, PPP) - o Continuous Transmission of Configure Request Packet for PPP (this - support is only added for 508 cards) - o Connection Timeout for PPP changed from 900 to 0 - o Flow Control for multiple boards and multiple channels (Frame Relay) + - UDP port for multiple boards (Frame relay, PPP) + Continuous Transmission of Configure Request + - Packet for PPP (this support is only added for + 508 cards) + - Connection Timeout for PPP changed from 900 to 0 + - Flow Control for multiple boards and multiple + channels (Frame Relay) 1.0.1 January 30, 1997 - o Implemented user-readable status and statistics via /proc filesystem + - Implemented user-readable status and statistics + via /proc filesystem 1.0.0 December 31, 1996 - o Initial version + - Initial version >>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff -u --recursive --new-file v2.1.78/linux/Documentation/networking/wanpipe.txt linux/Documentation/networking/wanpipe.txt --- v2.1.78/linux/Documentation/networking/wanpipe.txt Sat Nov 29 11:25:08 1997 +++ linux/Documentation/networking/wanpipe.txt Mon Jan 12 14:46:16 1998 @@ -1,9 +1,9 @@ ------------------------------------------------------------------------------ WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router ------------------------------------------------------------------------------ -Release 3.1.0 -January 30, 1997 -Author: Gene Kozin +Release 4.1 +November 17, 1997 +Author: Jaspreet Singh Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ @@ -23,8 +23,13 @@ is available via the Internet from Sangoma Technologies' anonymous FTP server: ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz + or + ftp.sangoma.com/pub/linux/wanpipe-X.Y.Z.tgz -For technical questions and/or comments please e-mail to genek@compuserve.com. +The name of the package differ only due to naming convention. The functionalityof wantools and wanpipe packages are the same. The latest version of WAN +Drivers is wanpipe-2.0.0. + +For technical questions and/or comments please e-mail to jaspreet@sangoma.com. For general inquiries please contact Sangoma Technologies Inc. by Hotline: 1-800-388-2475 (USA and Canada, toll free) @@ -53,10 +58,13 @@ NEW IN THIS RELEASE - o Implemented as WAN Link Driver compliant with Linux WAN Router interface - o Added support for X.25 protocol - o Miscellaneous bug fixes and performance improvements - + o This Version of WANPIPE supports only the S508 and S508/FT1 cards. IF YOU + OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR AN + UPGRADE. + o Protection of "enable_irq()" while "disable_irq()" has been enabled from + any other routine (for Frame Relay, PPP and X25). + o Added additional Stats for Fpipemon and Ppipemon. + o Improved Load Sharing for multiple boards FILE LIST @@ -64,22 +72,38 @@ drivers/net: README.wanpipe This file sdladrv.c SDLA support module source code - wpmain.c WANPIPE driver module main source code - wpx.c WANPIPE driver module X.25 source code - wpf.c WANPIPE driver module frame relay source code - wpp.c WANPIPE driver module PPP source code + sdla_fr.c SDLA Frame Relay source code + sdla_ppp.c SDLA PPP source code + sdla_x25.c SDLA X25 source code + sdlamain.c SDLA support source code + +include/linux: sdla_x25.h SDLA X.25 firmware API definitions sdla_fr.h SDLA frame relay firmware API definitions sdla_ppp.h SDLA PPP firmware API definitions - -include/linux: wanpipe.h WANPIPE API definitions sdladrv.h SDLA support module API definitions sdlasfm.h SDLA firmware module definitions - + router.h REVISION HISTORY + +4.1 November 28, 1997 + o Protection of "enable_irq()" while "disable_irq()" has been enabled + from any other routine (for Frame Relay, PPP and X25). + o Added additional Stats for Fpipemon and Ppipemon + o Improved Load Sharing for multiple boards + + +4.0 November 06, 1997 + o Implemented better protection of RACE conditions by critical flags for + FRAME RELAY, PPP and X25. + o DLCI List interrupt mode implemented for DLCI specific CIR. + o IPX support for FRAME RELAY, PPP and X25. + o IPX Server Support (MARS) for FRAME RELAY, PPP and X25. + o More driver specific stats included. + o MULTICAST for FRAME RELAY and PPP. 3.1.0 January 30, 1997 diff -u --recursive --new-file v2.1.78/linux/Documentation/powerpc/00-INDEX linux/Documentation/powerpc/00-INDEX --- v2.1.78/linux/Documentation/powerpc/00-INDEX Sat Nov 29 11:25:09 1997 +++ linux/Documentation/powerpc/00-INDEX Mon Jan 12 15:18:12 1998 @@ -7,5 +7,8 @@ - this file ppc_htab.txt - info about the Linux/PPC /proc/ppc_htab entry +smp.txt + - use and state info about Linux/PPC on MP machines sound.txt - info on sound support under Linux/PPC + diff -u --recursive --new-file v2.1.78/linux/Documentation/powerpc/smp.txt linux/Documentation/powerpc/smp.txt --- v2.1.78/linux/Documentation/powerpc/smp.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/powerpc/smp.txt Mon Jan 12 15:18:12 1998 @@ -0,0 +1,20 @@ + Information about Linux/PPC SMP mode +===================================================================== + +This document and the related code was written by me (Cort Dougan), please +email me (cort@cs.nmt.edu) if you have questions, comments or corrections. + +SMP support for Linux/PPC is still in its early stages and likely to +be buggy for a while. If you want to help by writing code or testing +different hardware please email me! + +1. State of Supported Hardware + + UMAX s900 + The second processor on this machine boots up just fine and + enters its idle loop. Hopefully a completely working SMP kernel + on this machine will be done shortly. + + BeBox + BeBox support hasn't been added to the 2.1.X kernels from 2.0.X + but work is being done and SMP support for BeBox is in the works. diff -u --recursive --new-file v2.1.78/linux/Documentation/spinlocks.txt linux/Documentation/spinlocks.txt --- v2.1.78/linux/Documentation/spinlocks.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/spinlocks.txt Mon Jan 12 14:46:16 1998 @@ -0,0 +1,186 @@ +On Fri, 2 Jan 1998, Doug Ledford wrote: +> +> I'm working on making the aic7xxx driver more SMP friendly (as well as +> importing the latest FreeBSD sequencer code to have 7895 support) and wanted +> to get some info from you. The goal here is to make the various routines +> SMP safe as well as UP safe during interrupts and other manipulating +> routines. So far, I've added a spin_lock variable to things like my queue +> structs. Now, from what I recall, there are some spin lock functions I can +> use to lock these spin locks frmo other use as oppossed to a (nasty) +> save_flags(); cli(); stuff; restore_flags(); construct. Where do I find +> these routines and go about making use of them? Do they only lock on a +> per-processor basis or can they also lock say an interrupt routine from +> mucking with a queue if the queue routine was manipulating it when the +> interrupt occured, or should I still use a cli(); based construct on that +> one? + +See . The basic version is: + + spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED; + + + unsigned long flags; + + spin_lock_irqsave(&xxx_lock, flags); + ... critical section here .. + spin_unlock_irqrestore(&xxx_lock, flags); + +and the above is always safe. It will disable interrupt _locally_, but the +spinlock itself will guarantee the global lock, so it will guarantee that +there is only one thread-of-control within the region(s) protected by that +lock. + +Note that it works well even under UP - the above sequence under UP +essentially is just the same as doing a + + unsigned long flags; + + save_flags(flags); cli(); + ... critical section ... + restore_flags(flags); + +so the code does _not_ need to worry about UP vs SMP issues: the spinlocks +work correctly under both (and spinlocks are actually more efficient on +architectures that allow doing the "save_flags + cli" in one go because I +don't export that interface normally). + +NOTE NOTE NOTE! The reason the spinlock is so much faster than a global +interrupt lock under SMP is exactly because it disables interrupts only on +the local CPU. The spin-lock is safe only when you _also_ use the lock +itself to do locking across CPU's, which implies that EVERYTHING that +touches a shared variable has to agree about the spinlock they want to +use. + +The above is usually pretty simple (you usually need and want only one +spinlock for most things - using more than one spinlock can make things a +lot more complex and even slower and is usually worth it only for +sequences that you _know_ need to be split up: avoid it at all cost if you +aren't sure). HOWEVER, it _does_ mean that if you have some code that does + + cli(); + .. critical section .. + sti(); + +and another sequence that does + + spin_lock_irqsave(flags); + .. critical section .. + spin_unlock_irqrestore(flags); + +then they are NOT mutually exclusive, and the critical regions can happen +at the same time on two different CPU's. That's fine per se, but the +critical regions had better be critical for different things (ie they +can't stomp on each other). + +The above is a problem mainly if you end up mixing code - for example the +routines in ll_rw_block() tend to use cli/sti to protect the atomicity of +their actions, and if a driver uses spinlocks instead then you should +think about issues like the above.. + +This is really the only really hard part about spinlocks: once you start +using spinlocks they tend to expand to areas you might not have noticed +before, because you have to make sure the spinlocks correctly protect the +shared data structures _everywhere_ they are used. The spinlocks are most +easily added to places that are completely independent of other code (ie +internal driver data structures that nobody else ever touches, for +example). + +---- + +Lesson 2: reader-writer spinlocks. + +If your data accesses have a very natural pattern where you usually tend +to mostly read from the shared variables, the reader-writer locks +(rw_lock) versions of the spinlocks are often nicer. They allow multiple +readers to be in the same critical region at once, but if somebody wants +to change the variables it has to get an exclusive write lock. The +routines look the same as above: + + rwlock_t xxx_lock = RW_LOCK_UNLOCKED; + + + unsigned long flags; + + read_lock_irqsave(&xxx_lock, flags); + .. critical section that only reads the info ... + read_unlock_irqrestore(&xxx_lock, flags); + + write_lock_irqsave(&xxx_lock, flags); + .. read and write exclusive access to the info ... + write_unlock_irqrestore(&xxx_lock, flags); + +The above kind of lock is useful for complex data structures like linked +lists etc, especially when you know that most of the work is to just +traverse the list searching for entries without changing the list itself, +for example. Then you can use the read lock for that kind of list +traversal, which allows many concurrent readers. Anything that _changes_ +the list will have to get the write lock. + +Note: you cannot "upgrade" a read-lock to a write-lock, so if you at _any_ +time need to do any changes (even if you don't do it every time), you have +to get the write-lock at the very beginning. I could fairly easily add a +primitive to create a "upgradeable" read-lock, but it hasn't been an issue +yet. Tell me if you'd want one. + +---- + +Lesson 3: spinlocks revisited. + +The single spin-lock primitives above are by no means the only ones. They +are the most safe ones, and the ones that work under all circumstances, +but partly _because_ they are safe they are also fairly slow. They are +much faster than a generic global cli/sti pair, but slower than they'd +need to be, because they do have to disable interrupts (which is just a +single instruction on a x86, but it's an expensive one - and on other +architectures it can be worse). + +If you have a case where you have to protect a data structure across +several CPU's and you want to use spinlocks you can potentially use +cheaper versions of the spinlocks. IFF you know that the spinlocks are +never used in interrupt handlers, you can use the non-irq versions: + + spin_lock(&lock); + ... + spin_unlock(&lock); + +(and the equivalent read-write versions too, of course). The spinlock will +guarantee the same kind of exclusive access, and it will be much faster. +This is useful if you know that the data in question is only ever +manipulated from a "process context", ie no interrupts involved. + +The reasons you mustn't use these versions if you have interrupts that +play with the spinlock is that you can get deadlocks: + + spin_lock(&lock); + ... + <- interrupt comes in: + spin_lock(&lock); + +where an interrupt tries to lock an already locked variable. This is ok if +the other interrupt happens on another CPU, but it is _not_ ok if the +interrupt happens on the same CPU that already holds the lock, because the +lock will obviously never be released (because the interrupt is waiting +for the lock, and the lock-holder is interrupted by the interrupt and will +not continue until the interrupt has been processed). + +(This is also the reason why the irq-versions of the spinlocks only need +to disable the _local_ interrupts - it's ok to use spinlocks in interrupts +on other CPU's, because an interrupt on another CPU doesn't interrupt the +CPU that holds the lock, so the lock-holder can continue and eventually +releases the lock). + +Note that you can be clever with read-write locks and interrupts. For +example, if you know that the interrupt only ever gets a read-lock, then +you can use a non-irq version of read locks everywhere - because they +don't block on each other (and thus there is no dead-lock wrt interrupts. +But when you do the write-lock, you have to use the irq-safe version. + +For an example of being clever with rw-locks, see the "waitqueue_lock" +handling in kernel/sched.c - nothing ever _changes_ a wait-queue from +within an interrupt, they only read the queue in order to know whom to +wake up. So read-locks are safe (which is good: they are very common +indeed), while write-locks need to protect themselves against interrupts. + + Linus + + diff -u --recursive --new-file v2.1.78/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.78/linux/MAINTAINERS Tue Jan 6 09:37:32 1998 +++ linux/MAINTAINERS Mon Jan 12 15:21:04 1998 @@ -442,6 +442,12 @@ M: jmaurer@cck.uni-kl.de S: Maintained +PCI SUBSYSTEM +P: Martin Mares +M: mj@atrey.karlin.mff.cuni.cz +L: linux-kernel@vger.rutgers.edu +S: Maintained + PCNET32 NETWORK DRIVER P: Thomas Bogendoerfer M: tsbogend@alpha.franken.de @@ -537,7 +543,7 @@ SVGA HANDLING: P: Martin Mares -M: mj@k332.feld.cvut.cz +M: mj@atrey.karlin.mff.cuni.cz L: linux-video@atrey.karlin.mff.cuni.cz S: Maintained diff -u --recursive --new-file v2.1.78/linux/Makefile linux/Makefile --- v2.1.78/linux/Makefile Tue Jan 6 09:37:32 1998 +++ linux/Makefile Mon Jan 12 14:47:55 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 78 +SUBLEVEL = 79 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.78/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v2.1.78/linux/arch/alpha/Makefile Thu May 29 21:53:03 1997 +++ linux/arch/alpha/Makefile Mon Jan 12 14:51:14 1998 @@ -44,3 +44,6 @@ archdep: @$(MAKEBOOT) dep + +bootpfile: + @$(MAKEBOOT) bootpfile diff -u --recursive --new-file v2.1.78/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile --- v2.1.78/linux/arch/alpha/boot/Makefile Sun Aug 4 03:37:59 1996 +++ linux/arch/alpha/boot/Makefile Mon Jan 12 14:51:14 1998 @@ -26,6 +26,7 @@ $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< OBJECTS = head.o main.o +BPOBJECTS = head.o bootp.o TARGETS = vmlinux.gz tools/objstrip # also needed by aboot & milo VMLINUX = $(TOPDIR)/vmlinux OBJSTRIP = tools/objstrip @@ -44,6 +45,9 @@ ( cat tools/lxboot tools/bootlx vmlinux.nh ) > bootimage tools/mkbb bootimage tools/lxboot +bootpfile: tools/bootph vmlinux.nh + ( cat tools/bootph vmlinux.nh ) > bootpfile + srmboot: bootdevice bootimage dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1 tools/mkbb $(BOOTDEV) tools/lxboot @@ -59,6 +63,8 @@ # main.o: ksize.h +bootp.o: ksize.h + ksize.h: $(OBJSTRIP) vmlinux.nh echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@ @@ -82,6 +88,9 @@ tools/bootlx: bootloader $(OBJSTRIP) $(OBJSTRIP) -vb bootloader tools/bootlx +tools/bootph: bootpheader $(OBJSTRIP) + $(OBJSTRIP) -vb bootpheader tools/bootph + $(OBJSTRIP): $(OBJSTRIP).c $(HOSTCC) $(OBJSTRIP).c -o $(OBJSTRIP) @@ -95,8 +104,15 @@ -o bootloader && strip bootloader || \ (rm -f bootloader && exit 1) +bootpheader: $(BPOBJECTS) + $(LD) $(LINKFLAGS) \ + $(BPOBJECTS) \ + $(LIBS) \ + -o bootpheader && strip bootpheader || \ + (rm -f bootpheader && exit 1) + clean: rm -f $(TARGETS) bootloader bootimage vmlinux.nh \ - tools/mkbb tools/bootlx tools/lxboot + tools/mkbb tools/bootlx tools/lxboot ksize.h dep: diff -u --recursive --new-file v2.1.78/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c --- v2.1.78/linux/arch/alpha/boot/bootp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/boot/bootp.c Mon Jan 12 14:51:14 1998 @@ -0,0 +1,222 @@ +/* + * arch/alpha/boot/bootp.c + * + * Copyright (C) 1997 Jay Estabrook + * + * This file is used for creating a bootp file for the Linux/AXP kernel + * + * based significantly on the arch/alpha/boot/main.c of Linus Torvalds + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "ksize.h" + +extern int vsprintf(char *, const char *, va_list); +extern unsigned long switch_to_osf_pal(unsigned long nr, + struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, + unsigned long vptb, unsigned long *kstk); + +int printk(const char * fmt, ...) +{ + va_list args; + int i, j, written, remaining, num_nl; + static char buf[1024]; + char * str; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + + /* expand \n into \r\n: */ + + num_nl = 0; + for (j = 0; j < i; ++j) { + if (buf[j] == '\n') + ++num_nl; + } + remaining = i + num_nl; + for (j = i - 1; j >= 0; --j) { + buf[j + num_nl] = buf[j]; + if (buf[j] == '\n') { + --num_nl; + buf[j + num_nl] = '\r'; + } + } + + str = buf; + do { + written = puts(str, remaining); + remaining -= written; + str += written; + } while (remaining > 0); + return i; +} + +#define hwrpb (*INIT_HWRPB) + +/* + * Find a physical address of a virtual object.. + * + * This is easy using the virtual page table address. + */ +struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb) +{ + unsigned long address = (unsigned long) pcb; + unsigned long result; + + result = vptb[address >> 13]; + result >>= 32; + result <<= 13; + result |= address & 0x1fff; + return (struct pcb_struct *) result; +} + +/* + * This function moves into OSF/1 pal-code, and has a temporary + * PCB for that. The kernel proper should replace this PCB with + * the real one as soon as possible. + * + * The page table muckery in here depends on the fact that the boot + * code has the L1 page table identity-map itself in the second PTE + * in the L1 page table. Thus the L1-page is virtually addressable + * itself (through three levels) at virtual address 0x200802000. + * + * As we don't want it there anyway, we also move the L1 self-map + * up as high as we can, so that the last entry in the L1 page table + * maps the page tables. + * + * As a result, the OSF/1 pal-code will instead use a virtual page table + * map located at 0xffffffe00000000. + */ +#define pcb_va ((struct pcb_struct *) 0x20000000) +#define old_vptb (0x0000000200000000UL) +#define new_vptb (0xfffffffe00000000UL) +void pal_init(void) +{ + unsigned long i, rev, sum; + unsigned long *L1, *l; + struct percpu_struct * percpu; + struct pcb_struct * pcb_pa; + + /* Find the level 1 page table and duplicate it in high memory */ + L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */ + L1[1023] = L1[1]; + + percpu = (struct percpu_struct *) + (hwrpb.processor_offset + (unsigned long) &hwrpb), + + pcb_va->ksp = 0; + pcb_va->usp = 0; + pcb_va->ptbr = L1[1] >> 32; + pcb_va->asn = 0; + pcb_va->pcc = 0; + pcb_va->unique = 0; + pcb_va->flags = 1; + pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va); + printk("Switching to OSF PAL-code .. "); + /* + * a0 = 2 (OSF) + * a1 = return address, but we give the asm the vaddr of the PCB + * a2 = physical addr of PCB + * a3 = new virtual page table pointer + * a4 = KSP (but we give it 0, asm sets it) + */ + i = switch_to_osf_pal( + 2, + pcb_va, + pcb_pa, + new_vptb, + 0); + if (i) { + printk("failed, code %ld\n", i); + halt(); + } + rev = percpu->pal_revision = percpu->palcode_avail[2]; + + hwrpb.vptb = new_vptb; + + /* update checksum: */ + sum = 0; + for (l = (unsigned long *) &hwrpb; + l < (unsigned long *) &hwrpb.chksum; + ++l) + sum += *l; + hwrpb.chksum = sum; + + printk("Ok (rev %lx)\n", rev); + /* remove the old virtual page-table mapping */ + L1[1] = 0; + flush_tlb_all(); +} + +static inline long load(unsigned long dst, + unsigned long src, + unsigned long count) +{ + extern void * memcpy(void *, const void *, size_t); + + memcpy((void *)dst, (void *)src, count); + return count; +} + +/* + * Start the kernel. + */ +static void runkernel(void) +{ + __asm__ __volatile__( + "bis %1,%1,$30\n\t" + "bis %0,%0,$27\n\t" + "jmp ($27)" + : /* no outputs: it doesn't even return */ + : "r" (START_ADDR), + "r" (PAGE_SIZE + INIT_STACK)); +} + +extern char _end; +#define KERNEL_ORIGIN \ + ((((unsigned long)&_end) + 511) & ~511) + +void start_kernel(void) +{ + long i; + int nbytes; + char envval[256]; + + printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n"); + if (hwrpb.pagesize != 8192) { + printk("Expected 8kB pages, got %ldkB\n", hwrpb.pagesize >> 10); + return; + } + pal_init(); + + nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, + envval, sizeof(envval)); + if (nbytes < 0) { + nbytes = 0; + } + envval[nbytes] = '\0'; + strcpy((char*)ZERO_PAGE, envval); + + printk("Loading the kernel ...\n"); + + /* NOTE: *no* callbacks or printouts from here on out!!! */ + + i = load(START_ADDR, KERNEL_ORIGIN, KERNEL_SIZE); + + runkernel(); + + for (i = 0 ; i < 0x100000000 ; i++) + /* nothing */; + halt(); +} diff -u --recursive --new-file v2.1.78/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.78/linux/arch/alpha/config.in Sun Dec 21 22:36:12 1997 +++ linux/arch/alpha/config.in Mon Jan 12 14:51:14 1998 @@ -6,7 +6,10 @@ # clear all implied options (don't want default values for those): unset CONFIG_CROSSCOMPILE CONFIG_NATIVE -unset CONFIG_PCI CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 +unset CONFIG_PCI CONFIG_ALPHA_EISA +unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA +unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION mainmenu_option next_comment @@ -46,19 +49,29 @@ Jensen CONFIG_ALPHA_JENSEN \ Noname CONFIG_ALPHA_NONAME \ Mikasa CONFIG_ALPHA_MIKASA \ + Noritake CONFIG_ALPHA_NORITAKE \ Alcor CONFIG_ALPHA_ALCOR \ + Miata CONFIG_ALPHA_MIATA \ + Sable CONFIG_ALPHA_SABLE \ + AlphaBook1 CONFIG_ALPHA_BOOK1 \ Platform2000 CONFIG_ALPHA_P2K" Cabriolet + +if [ "$CONFIG_ALPHA_BOOK1" = "y" ] +then + define_bool CONFIG_ALPHA_NONAME y +fi if [ "$CONFIG_ALPHA_NONAME" = "y" -o "$CONFIG_ALPHA_EB66" = "y" \ -o "$CONFIG_ALPHA_EB66P" = "y" -o "$CONFIG_ALPHA_P2K" = "y" ] then define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_LCA y fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ - -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ - -o "$CONFIG_ALPHA_XL" = "y" ] + -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_XL" = "y" ] then define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_APECS y fi if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ @@ -67,16 +80,56 @@ define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y -else +fi +if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ] +then + choice 'CPU daughtercard' \ + "Pinnacle CONFIG_ALPHA_PINNACLE \ + Primo CONFIG_ALPHA_PRIMO" Primo + if [ "$CONFIG_ALPHA_PRIMO" = "y" ] + then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y + else + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_APECS y + fi + define_bool CONFIG_PCI y +fi +if [ "$CONFIG_ALPHA_SABLE" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_T2 y +fi +if [ "$CONFIG_ALPHA_MIATA" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_PYXIS y +fi +if [ "$CONFIG_ALPHA_JENSEN" = "y" ] +then + define_bool CONFIG_ALPHA_EV4 y +fi +if [ "$CONFIG_ALPHA_EV4" = "y" ] +then # EV45 and older do not support all rounding modes in hw: define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ - -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" ] + -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ + -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ] then bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM +fi +if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ] +then + define_bool CONFIG_ALPHA_EISA y fi if [ "$CONFIG_ALPHA_XL" = "y" ] then diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.1.78/linux/arch/alpha/kernel/Makefile Fri Jan 3 01:33:25 1997 +++ linux/arch/alpha/kernel/Makefile Mon Jan 12 14:51:14 1998 @@ -16,8 +16,25 @@ O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - bios32.o ptrace.o time.o apecs.o lca.o cia.o + bios32.o ptrace.o time.o OX_OBJS := alpha_ksyms.o + + +ifdef CONFIG_ALPHA_APECS +O_OBJS += apecs.o +endif +ifdef CONFIG_ALPHA_CIA +O_OBJS += cia.o +endif +ifdef CONFIG_ALPHA_LCA +O_OBJS += lca.o +endif +ifdef CONFIG_ALPHA_PYXIS +O_OBJS += pyxis.o +endif +ifdef CONFIG_ALPHA_T2 +O_OBJS += t2.o +endif all: kernel.o head.o diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/apecs.c linux/arch/alpha/kernel/apecs.c --- v2.1.78/linux/arch/alpha/kernel/apecs.c Mon Oct 7 02:40:22 1996 +++ linux/arch/alpha/kernel/apecs.c Mon Jan 12 14:51:14 1998 @@ -21,12 +21,11 @@ extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); extern int alpha_sys_type; + /* * BIOS32-style PCI interface: */ -#ifdef CONFIG_ALPHA_APECS - #ifdef DEBUG # define DBG(args) printk args #else @@ -88,7 +87,8 @@ { unsigned long addr; - DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n", + DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," + " pci_addr=0x%p, type1=0x%p)\n", bus, device_fn, where, pci_addr, type1)); if (bus == 0) { @@ -97,7 +97,8 @@ /* type 0 configuration cycle: */ if (device > 20) { - DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", device)); + DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", + device)); return -1; } @@ -142,15 +143,15 @@ DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); /* reset status register to avoid losing errors: */ - stat0 = *((volatile unsigned int *)APECS_IOC_DCSR); - *((volatile unsigned int *)APECS_IOC_DCSR) = stat0; + stat0 = *(vuip)APECS_IOC_DCSR; + *(vuip)APECS_IOC_DCSR = stat0; mb(); DBG(("conf_read: APECS DCSR was 0x%x\n", stat0)); /* if Type1 access, must set HAE #2 */ if (type1) { - haxr2 = *((unsigned int *)APECS_IOC_HAXR2); + haxr2 = *(vuip)APECS_IOC_HAXR2; mb(); - *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1; + *(vuip)APECS_IOC_HAXR2 = haxr2 | 1; DBG(("conf_read: TYPE1 access\n")); } @@ -159,8 +160,7 @@ apecs_mcheck_taken = 0; mb(); /* access configuration space: */ - value = *((volatile unsigned int *)addr); - mb(); + value = *(vuip)addr; mb(); if (apecs_mcheck_taken) { apecs_mcheck_taken = 0; @@ -169,17 +169,18 @@ } apecs_mcheck_expected = 0; mb(); + +#if 1 /* * david.rusling@reo.mts.dec.com. This code is needed for the * EB64+ as it does not generate a machine check (why I don't * know). When we build kernels for one particular platform * then we can make this conditional on the type. */ -#if 1 draina(); /* now look for any errors */ - stat0 = *((unsigned int *)APECS_IOC_DCSR); + stat0 = *(vuip)APECS_IOC_DCSR; DBG(("conf_read: APECS DCSR after read 0x%x\n", stat0)); if (stat0 & 0xffe0U) { /* is any error bit set? */ /* if not NDEV, print status */ @@ -188,7 +189,7 @@ } /* reset error status: */ - *((volatile unsigned long *)APECS_IOC_DCSR) = stat0; + *(vulp)APECS_IOC_DCSR = stat0; mb(); wrmces(0x7); /* reset machine check */ value = 0xffffffff; @@ -197,7 +198,7 @@ /* if Type1 access, must reset HAE #2 so normal IO space ops work */ if (type1) { - *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1; + *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; mb(); } restore_flags(flags); @@ -224,37 +225,37 @@ cli(); /* reset status register to avoid losing errors: */ - stat0 = *((volatile unsigned int *)APECS_IOC_DCSR); - *((volatile unsigned int *)APECS_IOC_DCSR) = stat0; + stat0 = *(vuip)APECS_IOC_DCSR; + *(vuip)APECS_IOC_DCSR = stat0; mb(); /* if Type1 access, must set HAE #2 */ if (type1) { - haxr2 = *((unsigned int *)APECS_IOC_HAXR2); + haxr2 = *(vuip)APECS_IOC_HAXR2; mb(); - *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1; + *(vuip)APECS_IOC_HAXR2 = haxr2 | 1; } draina(); apecs_mcheck_expected = 1; mb(); /* access configuration space: */ - *((volatile unsigned int *)addr) = value; - mb(); + *(vuip)addr = value; mb(); apecs_mcheck_expected = 0; mb(); + +#if 1 /* * david.rusling@reo.mts.dec.com. This code is needed for the * EB64+ as it does not generate a machine check (why I don't * know). When we build kernels for one particular platform * then we can make this conditional on the type. */ -#if 1 draina(); /* now look for any errors */ - stat0 = *((unsigned int *)APECS_IOC_DCSR); + stat0 = *(vuip)APECS_IOC_DCSR; if (stat0 & 0xffe0U) { /* is any error bit set? */ /* if not NDEV, print status */ if (!(stat0 & 0x0800)) { @@ -262,7 +263,7 @@ } /* reset error status: */ - *((volatile unsigned long *)APECS_IOC_DCSR) = stat0; + *(vulp)APECS_IOC_DCSR = stat0; mb(); wrmces(0x7); /* reset machine check */ } @@ -270,7 +271,7 @@ /* if Type1 access, must reset HAE #2 so normal IO space ops work */ if (type1) { - *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1; + *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; mb(); } restore_flags(flags); @@ -433,7 +434,7 @@ #ifdef CONFIG_ALPHA_CABRIOLET /* * JAE: HACK!!! for now, hardwire if configured... - * davidm: Older miniloader versions don't set the clockfrequency + * davidm: Older miniloader versions don't set the clock frequency * right, so hardcode it for now. */ if (hwrpb->sys_type == ST_DEC_EB64P) { @@ -448,7 +449,9 @@ unsigned long *l, sum; sum = 0; - for (l = (unsigned long *) hwrpb; l < (unsigned long *) &hwrpb->chksum; ++l) + for (l = (unsigned long *) hwrpb; + l < (unsigned long *) &hwrpb->chksum; + ++l) sum += *l; hwrpb->chksum = sum; } @@ -462,10 +465,10 @@ */ { #if 0 - unsigned int haxr2 = *((unsigned int *)APECS_IOC_HAXR2); mb(); + unsigned int haxr2 = *(vuip)APECS_IOC_HAXR2; mb(); if (haxr2) printk("apecs_init: HAXR2 was 0x%x\n", haxr2); #endif - *((unsigned int *)APECS_IOC_HAXR2) = 0; mb(); + *(vuip)APECS_IOC_HAXR2 = 0; mb(); } @@ -474,15 +477,15 @@ int apecs_pci_clr_err(void) { - apecs_jd = *((unsigned long *)APECS_IOC_DCSR); + apecs_jd = *(vulp)APECS_IOC_DCSR; if (apecs_jd & 0xffe0L) { - apecs_jd1 = *((unsigned long *)APECS_IOC_SEAR); - *((unsigned long *)APECS_IOC_DCSR) = apecs_jd | 0xffe1L; - apecs_jd = *((unsigned long *)APECS_IOC_DCSR); + apecs_jd1 = *(vulp)APECS_IOC_SEAR; + *(vulp)APECS_IOC_DCSR = apecs_jd | 0xffe1L; + apecs_jd = *(vulp)APECS_IOC_DCSR; mb(); } - *((unsigned long *)APECS_IOC_TBIA) = APECS_IOC_TBIA; - apecs_jd2 = *((unsigned long *)APECS_IOC_TBIA); + *(vulp)APECS_IOC_TBIA = APECS_IOC_TBIA; + apecs_jd2 = *(vulp)APECS_IOC_TBIA; mb(); return 0; } @@ -547,7 +550,8 @@ wrmces(0x1f); /* disable correctable from now on */ mb(); draina(); - printk("apecs_machine_check: HW correctable (0x%lx)\n", vector); + printk("apecs_machine_check: HW correctable (0x%lx)\n", + vector); } else { printk(KERN_CRIT "APECS machine check:\n"); @@ -572,4 +576,3 @@ #endif } } -#endif /* CONFIG_ALPHA_APECS */ diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.78/linux/arch/alpha/kernel/bios32.c Tue Sep 23 16:48:46 1997 +++ linux/arch/alpha/kernel/bios32.c Mon Jan 12 14:51:14 1998 @@ -40,13 +40,15 @@ { return 0; } + asmlinkage int sys_pciconfig_read() { - return 0; + return -ENOSYS; } + asmlinkage int sys_pciconfig_write() { - return 0; + return -ENOSYS; } #else /* CONFIG_PCI */ @@ -95,31 +97,73 @@ extern struct hwrpb_struct *hwrpb; +/* Forward declarations for some extra fixup routines for specific hardware. */ +#ifdef CONFIG_ALPHA_PC164 +static int SMCInit(void); +#endif +#ifdef CONFIG_ALPHA_MIATA +static int es1888_init(void); +#endif #if PCI_MODIFY -/* NOTE: we can't just blindly use 64K for machines with EISA busses; they - may also have PCI-PCI bridges present, and then we'd configure the bridge - incorrectly */ -#if 0 -static unsigned int io_base = 64*KB; /* <64KB are (E)ISA ports */ +/* + * NOTE: we can't just blindly use 64K for machines with EISA busses; they + * may also have PCI-PCI bridges present, and then we'd configure the bridge + * incorrectly + * + * Also, we start at 0x8000 or 0x9000, in hopes to get all devices' + * IO space areas allocated *before* 0xC000; this is because certain + * BIOSes (Millennium for one) use PCI Config space "mechanism #2" + * accesses to probe the bus. If a device's registers appear at 0xC000, + * it may see an INx/OUTx at that address during BIOS emulation of the + * VGA BIOS, and some cards, notably Adaptec 2940UW, take mortal offense. + */ +#if defined(CONFIG_ALPHA_EISA) +static unsigned int io_base = 0x9000; /* start above 8th slot */ #else -static unsigned int io_base = 0xb000; +static unsigned int io_base = 0x8000; #endif #if defined(CONFIG_ALPHA_XL) /* - an AVANTI *might* be an XL, and an XL has only 27 bits of ISA address - that get passed through the PCI<->ISA bridge chip. Because this causes - us to set the PCI->Mem window bases lower than normal, we've gotta allocate - PCI bus devices' memory addresses *above* the PCI<->memory mapping windows, - so that CPU memory DMA addresses issued by a bus device don't conflict - with bus memory addresses, like frame buffer memory for graphics cards. -*/ -static unsigned int mem_base = 1024*MB; -#else /* CONFIG_ALPHA_XL */ -static unsigned int mem_base = 16*MB; /* <16MB is ISA memory */ -#endif /* CONFIG_ALPHA_XL */ + * An XL is AVANTI (APECS) family, *but* it has only 27 bits of ISA address + * that get passed through the PCI<->ISA bridge chip. Although this causes + * us to set the PCI->Mem window bases lower than normal, we still allocate + * PCI bus devices' memory addresses *below* the low DMA mapping window, + * and hope they fit below 64Mb (to avoid conflicts), and so that they can + * be accessed via SPARSE space. + * + * We accept the risk that a broken Myrinet card will be put into a true XL + * and thus can more easily run into the problem described below. + */ +static unsigned int mem_base = 16*MB + 2*MB; /* 16M to 64M-1 is avail */ + +#elif defined(CONFIG_ALPHA_LCA) || defined(CONFIG_ALPHA_APECS) +/* + * We try to make this address *always* have more than 1 bit set. + * this is so that devices like the broken Myrinet card will always have + * a PCI memory address that will never match a IDSEL address in + * PCI Config space, which can cause problems with early rev cards. + * + * However, APECS and LCA have only 34 bits for physical addresses, thus + * limiting PCI bus memory addresses for SPARSE access to be less than 128Mb. + */ +static unsigned int mem_base = 64*MB + 2*MB; + +#else +/* + * We try to make this address *always* have more than 1 bit set. + * this is so that devices like the broken Myrinet card will always have + * a PCI memory address that will never match a IDSEL address in + * PCI Config space, which can cause problems with early rev cards. + * + * Because CIA and PYXIS and T2 have more bits for physical addresses, + * they support an expanded range of SPARSE memory addresses. + */ +static unsigned int mem_base = 128*MB + 16*MB; + +#endif /* * Disable PCI device DEV so that it does not respond to I/O or memory @@ -130,14 +174,14 @@ struct pci_bus *bus; unsigned short cmd; -#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR) +#if defined(CONFIG_ALPHA_EISA) /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( */ if (dev->vendor == 0x8086 && dev->device == 0x0482) { - DBG_DEVS(("disable_dev: ignoring PCEB...\n")); - return; + DBG_DEVS(("disable_dev: ignoring PCEB...\n")); + return; } #endif @@ -153,7 +197,7 @@ /* * Layout memory and I/O for a device: */ -#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2) +#define MAX(val1, val2) ((val1) > (val2) ? val1 : val2) static void layout_dev(struct pci_dev *dev) { @@ -162,16 +206,15 @@ unsigned int base, mask, size, reg; unsigned int alignto; -#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR) /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( */ - if (dev->vendor == 0x8086 && dev->device == 0x0482) { - DBG_DEVS(("layout_dev: ignoring PCEB...\n")); - return; + if (dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82375) { + DBG_DEVS(("layout_dev: ignoring PCEB...\n")); + return; } -#endif bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -203,12 +246,23 @@ base &= PCI_BASE_ADDRESS_IO_MASK; mask = (~base << 1) | 0x1; size = (mask & base) & 0xffffffff; - /* align to multiple of size of minimum base */ - alignto = MAX(0x400, size) ; - base = ALIGN(io_base, alignto ); + /* + * Aligning to 0x800 rather than the minimum base of + * 0x400 is an attempt to avoid having devices in + * any 0x?C?? range, which is where the de4x5 driver + * probes for EISA cards. + * + * Adaptecs, especially, resent such intrusions. + */ + alignto = MAX(0x800, size); + base = ALIGN(io_base, alignto); io_base = base + size; pcibios_write_config_dword(bus->number, dev->devfn, reg, base | 0x1); + dev->base_address[(reg - PCI_BASE_ADDRESS_0)>>2] + = base | 0x1; + DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%x (0x%x)\n", + dev->device, base, size)); } else { unsigned int type; /* @@ -220,10 +274,10 @@ mask = (~base << 1) | 0x1; size = (mask & base) & 0xffffffff; switch (type) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: + case PCI_BASE_ADDRESS_MEM_TYPE_32: break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: + case PCI_BASE_ADDRESS_MEM_TYPE_64: printk("bios32 WARNING: " "ignoring 64-bit device in " "slot %d, function %d: \n", @@ -232,7 +286,7 @@ reg += 4; /* skip extra 4 bytes */ continue; - case PCI_BASE_ADDRESS_MEM_TYPE_1M: + case PCI_BASE_ADDRESS_MEM_TYPE_1M: /* * Allocating memory below 1MB is *very* * tricky, as there may be all kinds of @@ -242,9 +296,9 @@ * Alpha (or that the console has set it * up properly). */ - printk("bios32 WARNING: slot %d, function %d " - "requests memory below 1MB---don't " - "know how to do that.\n", + printk("bios32 WARNING: slot %d, function %d" + " requests memory below 1MB---don't" + " know how to do that.\n", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); continue; @@ -265,13 +319,13 @@ * dense memory space only! */ /* align to multiple of size of minimum base */ - alignto = MAX(0x1000, size) ; + alignto = MAX(0x1000, size); base = ALIGN(mem_base, alignto); if (size > 7 * 16*MB) { - printk("bios32 WARNING: slot %d, function %d " - "requests %dB of contiguous address " - " space---don't use sparse memory " - " accesses on this device!!\n", + printk("bios32 WARNING: slot %d, function %d" + " requests 0x%x bytes of contiguous" + " address space---don't use sparse" + " memory accesses on this device!!\n", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), size); } else { @@ -280,7 +334,7 @@ base += 16*MB; base = ALIGN(base, alignto); } - if (base / (128*MB) != (base + size) / (128*MB)) { + if (base/(128*MB) != (base + size)/(128*MB)) { base &= ~(128*MB - 1); base += (128 + 16)*MB; base = ALIGN(base, alignto); @@ -289,13 +343,17 @@ mem_base = base + size; pcibios_write_config_dword(bus->number, dev->devfn, reg, base); + dev->base_address[(reg-PCI_BASE_ADDRESS_0)>>2] = base; + DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%x (0x%x)\n", + dev->device, base, size)); } } - /* enable device: */ + + /* Enable device: */ if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED || dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || - dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || - dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + dev->class >> 8 == PCI_CLASS_STORAGE_IDE || + dev->class >> 16 == PCI_BASE_CLASS_DISPLAY) { /* * All of these (may) have I/O scattered all around @@ -308,8 +366,11 @@ pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); - DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n", - bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); + + DBG_DEVS(("layout_dev: bus %d slot %d VID 0x%x DID 0x%x" + " class 0x%x cmd 0 x%x\n", + bus->number, PCI_SLOT(dev->devfn), dev->vendor, + dev->device, dev->class, cmd|PCI_COMMAND_MASTER)); } @@ -322,7 +383,7 @@ DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); if (!bus->devices && !bus->children) - return; + return; /* * Align the current bases on appropriate boundaries (4K for @@ -341,8 +402,9 @@ * decoders are programmed consistently. */ for (dev = bus->devices; dev; dev = dev->sibling) { - if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { - disable_dev(dev) ; + if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || + (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) { + disable_dev(dev); } } @@ -352,7 +414,8 @@ DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number)); for (dev = bus->devices; dev; dev = dev->sibling) { - if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { + if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || + (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) { layout_dev(dev); } } @@ -378,7 +441,8 @@ */ pcibios_read_config_dword(bridge->bus->number, bridge->devfn, 0x1c, &l); - l = (l & 0xffff0000) | ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000); + l &= 0xffff0000; + l |= ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, 0x1c, l); /* @@ -504,9 +568,10 @@ } /* - * A small note about bridges and interrupts. The DECchip 21050 (and later chips) - * adheres to the PCI-PCI bridge specification. This says that the interrupts on - * the other side of a bridge are swizzled in the following manner: + * A small note about bridges and interrupts. The DECchip 21050 (and later) + * adheres to the PCI-PCI bridge specification. This says that the + * interrupts on the other side of a bridge are swizzled in the following + * manner: * * Dev Interrupt Interrupt * Pin on Pin on @@ -538,64 +603,89 @@ * The following code is somewhat simplistic as it assumes only one bridge. * I will fix it later (david.rusling@reo.mts.dec.com). */ -static inline unsigned char bridge_swizzle(unsigned char pin, unsigned int slot) +static inline unsigned char +bridge_swizzle(unsigned char pin, unsigned int slot) { /* swizzle */ - return (((pin-1) + slot) % 4) + 1 ; + return (((pin-1) + slot) % 4) + 1; } /* - * Most evaluation boards share most of the fixup code, which is isolated here. - * This function is declared "inline" as only one platform will ever be selected - * in any given kernel. If that platform doesn't need this code, we don't want - * it around as dead code. + * Most evaluation boards share most of the fixup code, which is isolated + * here. This function is declared "inline" as only one platform will ever + * be selected in any given kernel. If that platform doesn't need this code, + * we don't want it around as dead code. */ -static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_slot, - char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot], - long ide_base) +static inline void +common_fixup(long min_idsel, long max_idsel, long irqs_per_slot, + char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot], + long ide_base) { struct pci_dev *dev; unsigned char pin; - unsigned char slot ; + unsigned char slot; /* * Go through all devices, fixing up irqs as we see fit: */ for (dev = pci_devices; dev; dev = dev->next) { - if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE -#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR) - /* PCEB (PCI to EISA bridge) does not identify - itself as a bridge... :-( */ - && !((dev->vendor==0x8086) && (dev->device==0x482)) -#endif - ) { - dev->irq = 0; + if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE + /* PCEB (PCI to EISA bridge) does not identify + itself as a bridge... :-P */ + && !(dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82375)) + || dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) { /* - * This device is not on the primary bus, we need to figure out which - * interrupt pin it will come in on. We know which slot it will come - * in on 'cos that slot is where the bridge is. Each time the interrupt - * line passes through a PCI-PCI bridge we must apply the swizzle function - * (see the inline static routine above). + * This device is not on the primary bus, we need + * to figure out which interrupt pin it will come + * in on. We know which slot it will come in on + * 'cos that slot is where the bridge is. Each + * time the interrupt line passes through a PCI-PCI + * bridge we must apply the swizzle function (see + * the inline static routine above). */ + dev->irq = 0; if (dev->bus->number != 0) { - struct pci_dev *curr = dev ; - /* read the pin and do the PCI-PCI bridge interrupt pin swizzle */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_PIN, &pin); + struct pci_dev *curr = dev; + /* read the pin and do the PCI-PCI bridge + interrupt pin swizzle */ + pcibios_read_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_PIN, + &pin); /* cope with 0 */ - if (pin == 0) pin = 1 ; - /* follow the chain of bridges, swizzling as we go */ + if (pin == 0) + pin = 1; + /* follow the chain of bridges, swizzling + as we go */ +#if defined(CONFIG_ALPHA_MIATA) + slot = PCI_SLOT(dev->devfn) + 5; + DBG_DEVS(("MIATA: bus 1 slot %d pin %d" + " irq %d min_idsel %d\n", + PCI_SLOT(dev->devfn), pin, + irq_tab[slot - min_idsel][pin], + min_idsel)); +#elif defined(CONFIG_ALPHA_NORITAKE) + /* WAG Alert! */ + slot = PCI_SLOT(dev->devfn) + 14; + DBG_DEVS(("NORITAKE: bus 1 slot %d pin %d" + " irq %d min_idsel %d\n", + PCI_SLOT(dev->devfn), pin, + irq_tab[slot - min_idsel][pin], + min_idsel)); +#else do { /* swizzle */ - pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)) ; + pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)); /* move up the chain of bridges */ - curr = curr->bus->self ; - } while (curr->bus->self) ; + curr = curr->bus->self; + } while (curr->bus->self); /* The slot is the slot of the last bridge. */ - slot = PCI_SLOT(curr->devfn) ; + slot = PCI_SLOT(curr->devfn); +#endif /* MIATA */ } else { /* work out the slot */ - slot = PCI_SLOT(dev->devfn) ; + slot = PCI_SLOT(dev->devfn); /* read the pin */ pcibios_read_config_byte(dev->bus->number, dev->devfn, @@ -606,20 +696,39 @@ dev->irq = irq_tab[slot - min_idsel][pin]; #if PCI_MODIFY /* tell the device: */ - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_LINE, + dev->irq); #endif + + DBG_DEVS(("common_fixup: bus %d slot 0x%x" + " VID 0x%x DID 0x%x\n" + " int_slot 0x%x pin 0x%x" + " pirq 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + dev->vendor, dev->device, + slot, pin, dev->irq)); + /* * if it's a VGA, enable its BIOS ROM at C0000 */ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - pcibios_write_config_dword(dev->bus->number, - dev->devfn, - PCI_ROM_ADDRESS, - 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); + pcibios_write_config_dword(dev->bus->number, + dev->devfn, + PCI_ROM_ADDRESS, + 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); + } + /* + * if it's a SCSI, disable its BIOS ROM + */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) { + pcibios_write_config_dword(dev->bus->number, + dev->devfn, + PCI_ROM_ADDRESS, + 0x0000000); } } - } if (ide_base) { enable_ide(ide_base); @@ -641,12 +750,12 @@ */ static inline void eb66p_fixup(void) { - char irq_tab[5][5] = { - {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ - {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */ - {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */ + static char irq_tab[5][5] = { + {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ + {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */ + {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */ }; common_fixup(6, 10, 5, irq_tab, 0x398); } @@ -694,27 +803,24 @@ * */ +#ifdef CONFIG_ALPHA_PC164 static inline void alphapc164_fixup(void) { - extern int SMCInit(void); - char irq_tab[7][5] = { - /* - * int intA intB intC intD - * ---- ---- ---- ---- ---- - */ - { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ - { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ - { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */ - { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */ - { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */ + static char irq_tab[7][5] = { + /*INT INTA INTB INTC INTD */ + { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ + { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ + { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */ + { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */ + { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */ }; common_fixup(5, 11, 5, irq_tab, 0); - SMCInit(); } +#endif /* * The AlphaPC64 is very similar to the EB66+ except that its slots @@ -731,12 +837,12 @@ */ static inline void cabriolet_fixup(void) { - char irq_tab[5][5] = { - { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ - { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ - { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */ + static char irq_tab[5][5] = { + { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ + { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ + { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */ }; common_fixup(5, 9, 5, irq_tab, 0x398); @@ -787,12 +893,12 @@ */ static inline void eb66_and_eb64p_fixup(void) { - char irq_tab[5][5] = { - {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */ - {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */ - {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - {16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 9, TULIP */ + static char irq_tab[5][5] = { + {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */ + {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */ + {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + {16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 9, TULIP */ }; common_fixup(5, 9, 5, irq_tab, 0); } @@ -836,21 +942,97 @@ */ static inline void mikasa_fixup(void) { - char irq_tab[8][5] = { - /*INT INTA INTB INTC INTD */ - {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ - { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ - { -1, -1, -1, -1, -1}, /* IdSel 19, ???? */ - { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ - { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ - { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 0 */ - { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ - { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 24, slot 2 */ + static char irq_tab[8][5] = { + /*INT INTA INTB INTC INTD */ + {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ + { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ + { -1, -1, -1, -1, -1}, /* IdSel 19, ???? */ + { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ + { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ + { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 0 */ + { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ + { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 24, slot 2 */ }; common_fixup(6, 13, 5, irq_tab, 0); } /* + * Fixup configuration for NORITAKE (MIKASA is different) + * + * Summary @ 0x542, summary register #1: + * Bit Meaning + * 0 All valid ints from summary regs 2 & 3 + * 1 QLOGIC ISP1020A SCSI + * 2 Interrupt Line A from slot 0 + * 3 Interrupt Line B from slot 0 + * 4 Interrupt Line A from slot 1 + * 5 Interrupt line B from slot 1 + * 6 Interrupt Line A from slot 2 + * 7 Interrupt Line B from slot 2 + * 8 Interrupt Line A from slot 3 + * 9 Interrupt Line B from slot 3 + *10 Interrupt Line A from slot 4 + *11 Interrupt Line B from slot 4 + *12 Interrupt Line A from slot 5 + *13 Interrupt Line B from slot 5 + *14 Interrupt Line A from slot 6 + *15 Interrupt Line B from slot 6 + * + * Summary @ 0x544, summary register #2: + * Bit Meaning + * 0 OR of all unmasked ints in SR #2 + * 1 OR of secondary bus ints + * 2 Interrupt Line C from slot 0 + * 3 Interrupt Line D from slot 0 + * 4 Interrupt Line C from slot 1 + * 5 Interrupt line D from slot 1 + * 6 Interrupt Line C from slot 2 + * 7 Interrupt Line D from slot 2 + * 8 Interrupt Line C from slot 3 + * 9 Interrupt Line D from slot 3 + *10 Interrupt Line C from slot 4 + *11 Interrupt Line D from slot 4 + *12 Interrupt Line C from slot 5 + *13 Interrupt Line D from slot 5 + *14 Interrupt Line C from slot 6 + *15 Interrupt Line D from slot 6 + * + * The device to slot mapping looks like: + * + * Slot Device + * 7 Intel PCI-EISA bridge chip + * 8 DEC PCI-PCI bridge chip + * 11 PCI on board slot 0 + * 12 PCI on board slot 1 + * 13 PCI on board slot 2 + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ +static inline void noritake_fixup(void) +{ + static char irq_tab[13][5] = { + /*INT INTA INTB INTC INTD */ + { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ + { -1, -1, -1, -1, -1}, /* IdSel 19, PPB */ + { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ + { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ + { 16+2, 16+2, 16+3, 32+2, 32+3}, /* IdSel 22, slot 0 */ + { 16+4, 16+4, 16+5, 32+4, 32+5}, /* IdSel 23, slot 1 */ + { 16+6, 16+6, 16+7, 32+6, 32+7}, /* IdSel 24, slot 2 */ + /* The following are actually on bus 1, across the bridge */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* IdSel 16, QLOGIC */ + { 16+8, 16+8, 16+9, 32+8, 32+9}, /* IdSel 17, slot 3 */ + {16+10, 16+10, 16+11, 32+10, 32+11}, /* IdSel 18, slot 4 */ + {16+12, 16+12, 16+13, 32+12, 32+13}, /* IdSel 19, slot 5 */ + {16+14, 16+14, 16+15, 32+14, 32+15}, /* IdSel 20, slot 6 */ + }; + common_fixup(7, 18, 5, irq_tab, 0); +} + +/* * Fixup configuration for ALCOR * * Summary @ GRU_INT_REQ: @@ -895,14 +1077,14 @@ */ static inline void alcor_fixup(void) { - char irq_tab[6][5] = { - /*INT INTA INTB INTC INTD */ - { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ - {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */ - {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 20, slot 4 */ - { -1, -1, -1, -1, -1}, /* IdSel 21, PCEB */ - { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */ - { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ + static char irq_tab[6][5] = { + /*INT INTA INTB INTC INTD */ + { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ + {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */ + {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 20, slot 4 */ + { -1, -1, -1, -1, -1}, /* IdSel 21, PCEB */ + { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */ + { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ }; common_fixup(7, 12, 5, irq_tab, 0); } @@ -950,19 +1132,183 @@ */ static inline void xlt_fixup(void) { - char irq_tab[7][5] = { - /*INT INTA INTB INTC INTD */ - {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ - { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ - { -1, -1, -1, -1, -1}, /* IdSel 19, none */ - {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 20, SCSI */ - { -1, -1, -1, -1, -1}, /* IdSel 21, SIO */ - { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */ - { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ + static char irq_tab[7][5] = { + /*INT INTA INTB INTC INTD */ + {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ + { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ + { -1, -1, -1, -1, -1}, /* IdSel 19, none */ + {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 20, SCSI */ + { -1, -1, -1, -1, -1}, /* IdSel 21, SIO */ + { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */ + { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ }; common_fixup(6, 12, 5, irq_tab, 0); } +/* + * Fixup configuration for ALPHA SABLE (2100) - 2100A is different ?? + * + * Summary Registers (536/53a/53c): + * Bit Meaning + *----------------- + * 0 PCI slot 0 + * 1 NCR810 (builtin) + * 2 TULIP (builtin) + * 3 mouse + * 4 PCI slot 1 + * 5 PCI slot 2 + * 6 keyboard + * 7 floppy + * 8 COM2 + * 9 parallel port + *10 EISA irq 3 + *11 EISA irq 4 + *12 EISA irq 5 + *13 EISA irq 6 + *14 EISA irq 7 + *15 COM1 + *16 EISA irq 9 + *17 EISA irq 10 + *18 EISA irq 11 + *19 EISA irq 12 + *20 EISA irq 13 + *21 EISA irq 14 + *22 NC + *23 IIC + * + * The device to slot mapping looks like: + * + * Slot Device + * 0 TULIP + * 1 SCSI + * 2 PCI-EISA bridge + * 3 none + * 4 none + * 5 none + * 6 PCI on board slot 0 + * 7 PCI on board slot 1 + * 8 PCI on board slot 2 + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ +/* NOTE: the IRQ assignments below are arbitrary, but need to be consistent + with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables + in irq.c + */ +static inline void sable_fixup(void) +{ + static char irq_tab[9][5] = { + /*INT INTA INTB INTC INTD */ + { 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */ + { 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */ + { -1, -1, -1, -1, -1}, /* IdSel 2, SIO */ + { -1, -1, -1, -1, -1}, /* IdSel 3, none */ + { -1, -1, -1, -1, -1}, /* IdSel 4, none */ + { -1, -1, -1, -1, -1}, /* IdSel 5, none */ + { 32+2, 32+2, 32+2, 32+2, 32+2}, /* IdSel 6, slot 0 */ + { 32+3, 32+3, 32+3, 32+3, 32+3}, /* IdSel 7, slot 1 */ + { 32+4, 32+4, 32+4, 32+4, 32+4}, /* IdSel 8, slot 2 */ + }; + common_fixup(0, 8, 5, irq_tab, 0); +} + +/* + * Fixup configuration for MIATA (EV56+PYXIS) + * + * Summary @ PYXIS_INT_REQ: + * Bit Meaning + * 0 Fan Fault + * 1 NMI + * 2 Halt/Reset switch + * 3 none + * 4 CID0 (Riser ID) + * 5 CID1 (Riser ID) + * 6 Interval timer + * 7 PCI-ISA Bridge + * 8 Ethernet + * 9 EIDE (deprecated, ISA 14/15 used) + *10 none + *11 USB + *12 Interrupt Line A from slot 4 + *13 Interrupt Line B from slot 4 + *14 Interrupt Line C from slot 4 + *15 Interrupt Line D from slot 4 + *16 Interrupt Line A from slot 5 + *17 Interrupt line B from slot 5 + *18 Interrupt Line C from slot 5 + *19 Interrupt Line D from slot 5 + *20 Interrupt Line A from slot 1 + *21 Interrupt Line B from slot 1 + *22 Interrupt Line C from slot 1 + *23 Interrupt Line D from slot 1 + *24 Interrupt Line A from slot 2 + *25 Interrupt Line B from slot 2 + *26 Interrupt Line C from slot 2 + *27 Interrupt Line D from slot 2 + *27 Interrupt Line A from slot 3 + *29 Interrupt Line B from slot 3 + *30 Interrupt Line C from slot 3 + *31 Interrupt Line D from slot 3 + * + * The device to slot mapping looks like: + * + * Slot Device + * 3 DC21142 Ethernet + * 4 EIDE CMD646 + * 5 none + * 6 USB + * 7 PCI-ISA bridge + * 8 PCI-PCI Bridge (SBU Riser) + * 9 none + * 10 none + * 11 PCI on board slot 4 (SBU Riser) + * 12 PCI on board slot 5 (SBU Riser) + * + * These are behind the bridge, so I'm not sure what to do... + * + * 13 PCI on board slot 1 (SBU Riser) + * 14 PCI on board slot 2 (SBU Riser) + * 15 PCI on board slot 3 (SBU Riser) + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ + +#ifdef CONFIG_ALPHA_MIATA +static inline void miata_fixup(void) +{ + static char irq_tab[18][5] = { + /*INT INTA INTB INTC INTD */ + {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142 */ + { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */ + { -1, -1, -1, -1, -1}, /* IdSel 16, none */ + { -1, -1, -1, -1, -1}, /* IdSel 17, none */ +/* {16+11, 16+11, 16+11, 16+11, 16+11},*//* IdSel 17, USB ?? */ + { -1, -1, -1, -1, -1}, /* IdSel 18, PCI-ISA */ + { -1, -1, -1, -1, -1}, /* IdSel 19, PCI-PCI */ + { -1, -1, -1, -1, -1}, /* IdSel 20, none */ + { -1, -1, -1, -1, -1}, /* IdSel 21, none */ + {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 22, slot 4 */ + {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 23, slot 5 */ + /* The following are actually on bus 1, across the bridge */ + {16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 24, slot 1 */ + {16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 25, slot 2 */ + {16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 26, slot 3 */ + { -1, -1, -1, -1, -1}, /* IdSel 27, none */ + { -1, -1, -1, -1, -1}, /* IdSel 28, none */ + { -1, -1, -1, -1, -1}, /* IdSel 29, none */ + { -1, -1, -1, -1, -1}, /* IdSel 30, none */ + { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI */ + }; + common_fixup(3, 20, 5, irq_tab, 0); + es1888_init(); +} +#endif /* * Fixup configuration for all boards that route the PCI interrupts @@ -1011,6 +1357,8 @@ { 0, 0, 0, 0, 0}, /* idsel 14 AS255 TULIP */ #endif }; + const size_t pirq_tab_len = sizeof(pirq_tab)/sizeof(pirq_tab[0]); + /* * route_tab selects irq routing in PCI/ISA bridge so that: * PIRQ0 -> irq 15 @@ -1021,7 +1369,12 @@ * This probably ought to be configurable via MILO. For * example, sound boards seem to like using IRQ 9. */ -#ifdef CONFIG_ALPHA_NONAME + +#if defined(CONFIG_ALPHA_BOOK1) + /* for the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15 */ + const unsigned int route_tab = 0x0e0f0a0a; + +#elif defined(CONFIG_ALPHA_NONAME) /* * For UDB, the only available PCI slot must not map to IRQ 9, * since that's the builtin MSS sound chip. That PCI slot @@ -1033,9 +1386,10 @@ * selected... :-( */ const unsigned int route_tab = 0x0b0a0f09; -#else /* CONFIG_ALPHA_NONAME */ +#else const unsigned int route_tab = 0x0b0a090f; -#endif /* CONFIG_ALPHA_NONAME */ +#endif + unsigned int level_bits; unsigned char pin, slot; int pirq; @@ -1047,11 +1401,13 @@ */ level_bits = 0; for (dev = pci_devices; dev; dev = dev->next) { - if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) + if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && + (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) continue; + dev->irq = 0; if (dev->bus->number != 0) { - struct pci_dev *curr = dev ; + struct pci_dev *curr = dev; /* * read the pin and do the PCI-PCI bridge * interrupt pin swizzle @@ -1059,41 +1415,44 @@ pcibios_read_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, &pin); /* cope with 0 */ - if (pin == 0) pin = 1 ; + if (pin == 0) + pin = 1; /* follow the chain of bridges, swizzling as we go */ do { /* swizzle */ - pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)) ; + pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)); /* move up the chain of bridges */ - curr = curr->bus->self ; - } while (curr->bus->self) ; + curr = curr->bus->self; + } while (curr->bus->self); /* The slot is the slot of the last bridge. */ - slot = PCI_SLOT(curr->devfn) ; + slot = PCI_SLOT(curr->devfn); } else { /* work out the slot */ - slot = PCI_SLOT(dev->devfn) ; + slot = PCI_SLOT(dev->devfn); /* read the pin */ pcibios_read_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, &pin); } - if (slot < 6 || slot >= 6 + sizeof(pirq_tab)/sizeof(pirq_tab[0])) { + if (slot < 6 || slot >= 6 + pirq_tab_len) { printk("bios32.sio_fixup: " - "weird, found device %04x:%04x in non-existent slot %d!!\n", + "weird, found device %04x:%04x in" + " non-existent slot %d!!\n", dev->vendor, dev->device, slot); continue; } pirq = pirq_tab[slot - 6][pin]; DBG_DEVS(("sio_fixup: bus %d slot 0x%x VID 0x%x DID 0x%x\n" - " int_slot 0x%x int_pin 0x%x, pirq 0x%x\n", - dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, - slot, pin, pirq)); + " int_slot 0x%x pin 0x%x pirq 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, + dev->device, slot, pin, pirq)); /* * if it's a VGA, enable its BIOS ROM at C0000 */ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - pcibios_write_config_dword(dev->bus->number, dev->devfn, + pcibios_write_config_dword(dev->bus->number, + dev->devfn, PCI_ROM_ADDRESS, 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); } @@ -1103,22 +1462,60 @@ if (pirq < 0) { printk("bios32.sio_fixup: " - "weird, device %04x:%04x coming in on slot %d has no irq line!!\n", + "weird, device %04x:%04x coming in on" + " slot %d has no irq line!!\n", dev->vendor, dev->device, slot); continue; } dev->irq = (route_tab >> (8 * pirq)) & 0xff; - /* must set the PCI IRQs to level triggered */ - level_bits |= (1 << dev->irq); +#ifndef CONFIG_ALPHA_BOOK1 + /* do not set *ANY* level triggers for AlphaBook1 */ + /* must set the PCI IRQs to level triggered */ + level_bits |= (1 << dev->irq); +#endif /* !CONFIG_ALPHA_BOOK1 */ #if PCI_MODIFY /* tell the device: */ pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq); #endif - } + +#ifdef CONFIG_ALPHA_BOOK1 + /* + * On the AlphaBook1, the PCMCIA chip (Cirrus 6729) + * is sensitive to PCI bus bursts, so we must DISABLE + * burst mode for the NCR 8xx SCSI... :-( + * + * Note that the NCR810 SCSI driver must preserve the + * setting of the bit in order for this to work. At the + * moment (2.0.29), ncr53c8xx.c does NOT do this, but + * 53c7,8xx.c DOES. + */ + if (dev->vendor == PCI_VENDOR_ID_NCR && + (dev->device == PCI_DEVICE_ID_NCR_53C810 || + dev->device == PCI_DEVICE_ID_NCR_53C815 || + dev->device == PCI_DEVICE_ID_NCR_53C820 || + dev->device == PCI_DEVICE_ID_NCR_53C825)) { + unsigned int io_port; + unsigned char ctest4; + + pcibios_read_config_dword(dev->bus->number, + dev->devfn, + PCI_BASE_ADDRESS_0, + &io_port); + io_port &= PCI_BASE_ADDRESS_IO_MASK; + ctest4 = inb(io_port+0x21); + if (!(ctest4 & 0x80)) { + printk("AlphaBook1 NCR init: setting" + " burst disable\n"); + outb(ctest4 | 0x80, io_port+0x21); + } + } +#endif /* CONFIG_ALPHA_BOOK1 */ + } /* end for-devs */ + /* * Now, make all PCI interrupts level sensitive. Notice: * these registers must be accessed byte-wise. inw()/outw() @@ -1128,11 +1525,34 @@ * so that the only bits getting set are for devices actually found. * Note that we do preserve the remainder of the bits, which we hope * will be set correctly by ARC/SRM. + * + * Note: we at least preserve any level-set bits on AlphaBook1 */ level_bits |= ((inb(0x4d0) | (inb(0x4d1) << 8)) & 0x71ff); outb((level_bits >> 0) & 0xff, 0x4d0); outb((level_bits >> 8) & 0xff, 0x4d1); - enable_ide(0x26e); + +#ifdef CONFIG_ALPHA_BOOK1 + { + unsigned char orig, config; + /* On the AlphaBook1, make sure that register PR1 + indicates 1Mb mem */ + outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5 */ + outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */ + outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */ + if ((config & 0xc0) != 0xc0) { + printk("AlphaBook1 VGA init: setting 1Mb memory\n"); + config |= 0xc0; + outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */ + } + outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */ + } +#endif /* CONFIG_ALPHA_BOOK1 */ + +#ifndef CONFIG_ALPHA_BOOK1 + /* Do not do IDE init for AlphaBook1 */ + enable_ide(0x26e); +#endif } @@ -1152,7 +1572,8 @@ /* * Now is the time to do all those dirty little deeds... */ -#if defined(CONFIG_ALPHA_NONAME) || defined(CONFIG_ALPHA_AVANTI) || defined(CONFIG_ALPHA_P2K) +#if defined(CONFIG_ALPHA_NONAME) || defined(CONFIG_ALPHA_AVANTI) || \ + defined(CONFIG_ALPHA_P2K) sio_fixup(); #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164) cabriolet_fixup(); @@ -1170,72 +1591,82 @@ alcor_fixup(); #elif defined(CONFIG_ALPHA_XLT) xlt_fixup(); +#elif defined(CONFIG_ALPHA_SABLE) + sable_fixup(); +#elif defined(CONFIG_ALPHA_MIATA) + miata_fixup(); +#elif defined(CONFIG_ALPHA_NORITAKE) + noritake_fixup(); #else -# error You must tell me what kind of platform you want. +# error "You must tell me what kind of platform you want." #endif +#ifndef CONFIG_ABSTRACT_CONSOLE #ifdef CONFIG_TGA_CONSOLE tga_console_init(); -#endif /* CONFIG_TGA_CONSOLE */ +#endif +#endif return mem_start; } -asmlinkage int sys_pciconfig_read( - unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf) +asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) { unsigned char ubyte; unsigned short ushort; unsigned int uint; long err = 0; + if (!suser()) + return -EPERM; + lock_kernel(); switch (len) { - case 1: + case 1: err = pcibios_read_config_byte(bus, dfn, off, &ubyte); if (err != PCIBIOS_SUCCESSFUL) - ubyte = 0xff; + ubyte = 0xff; put_user(ubyte, buf); break; - case 2: + case 2: err = pcibios_read_config_word(bus, dfn, off, &ushort); if (err != PCIBIOS_SUCCESSFUL) - ushort = 0xffff; + ushort = 0xffff; put_user(ushort, (unsigned short *)buf); break; - case 4: + case 4: err = pcibios_read_config_dword(bus, dfn, off, &uint); if (err != PCIBIOS_SUCCESSFUL) - uint = 0xffffffff; + uint = 0xffffffff; put_user(uint, (unsigned int *)buf); break; - default: + default: err = -EINVAL; break; } unlock_kernel(); return err; } -asmlinkage int sys_pciconfig_write( - unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf) + + +asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) { unsigned char ubyte; unsigned short ushort; unsigned int uint; long err = 0; + if (!suser()) + return -EPERM; + lock_kernel(); switch (len) { - case 1: + case 1: err = get_user(ubyte, buf); if (err) break; @@ -1244,7 +1675,7 @@ err = -EFAULT; } break; - case 2: + case 2: err = get_user(ushort, (unsigned short *)buf); if (err) break; @@ -1253,7 +1684,7 @@ err = -EFAULT; } break; - case 4: + case 4: err = get_user(uint, (unsigned int *)buf); if (err) break; @@ -1262,7 +1693,7 @@ err = -EFAULT; } break; - default: + default: err = -EINVAL; break; } @@ -1270,8 +1701,8 @@ return err; } -#ifdef CONFIG_ALPHA_PC164 +#ifdef CONFIG_ALPHA_PC164 /* device "activate" register contents */ #define DEVICE_ON 1 #define DEVICE_OFF 0 @@ -1326,206 +1757,233 @@ #define SMC_DEBUG 0 -unsigned long SMCConfigState( unsigned long baseAddr ) +static unsigned long SMCConfigState(unsigned long baseAddr) { - unsigned char devId; - unsigned char devRev; - - unsigned long configPort; - unsigned long indexPort; - unsigned long dataPort; + unsigned char devId; + unsigned char devRev; - configPort = indexPort = baseAddr; - dataPort = ( unsigned long )( ( char * )configPort + 1 ); - - outb(CONFIG_ON_KEY, configPort); - outb(CONFIG_ON_KEY, configPort); - outb(DEVICE_ID, indexPort); - devId = inb(dataPort); - if ( devId == VALID_DEVICE_ID ) { - outb(DEVICE_REV, indexPort); - devRev = inb(dataPort); - } - else { - baseAddr = 0; - } - return( baseAddr ); + unsigned long configPort; + unsigned long indexPort; + unsigned long dataPort; + + configPort = indexPort = baseAddr; + dataPort = configPort + 1; + + outb(CONFIG_ON_KEY, configPort); + outb(CONFIG_ON_KEY, configPort); + outb(DEVICE_ID, indexPort); + devId = inb(dataPort); + if ( devId == VALID_DEVICE_ID ) { + outb(DEVICE_REV, indexPort); + devRev = inb(dataPort); + } + else { + baseAddr = 0; + } + return baseAddr; } -void SMCRunState( unsigned long baseAddr ) +static void SMCRunState(unsigned long baseAddr) { - outb(CONFIG_OFF_KEY, baseAddr); + outb(CONFIG_OFF_KEY, baseAddr); } -unsigned long SMCDetectUltraIO(void) +static unsigned long SMCDetectUltraIO(void) { - unsigned long baseAddr; + unsigned long baseAddr; - baseAddr = 0x3F0; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { - return( baseAddr ); - } - baseAddr = 0x370; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { - return( baseAddr ); - } - return( ( unsigned long )0 ); + baseAddr = 0x3F0; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { + return( baseAddr ); + } + baseAddr = 0x370; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { + return( baseAddr ); + } + return( ( unsigned long )0 ); } -void SMCEnableDevice( unsigned long baseAddr, - unsigned long device, - unsigned long portaddr, - unsigned long interrupt) +static void SMCEnableDevice(unsigned long baseAddr, + unsigned long device, + unsigned long portaddr, + unsigned long interrupt) { - unsigned long indexPort; - unsigned long dataPort; + unsigned long indexPort; + unsigned long dataPort; - indexPort = baseAddr; - dataPort = ( unsigned long )( ( char * )baseAddr + 1 ); + indexPort = baseAddr; + dataPort = baseAddr + 1; - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(device, dataPort); + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(device, dataPort); - outb(ADDR_LO, indexPort); - outb(( portaddr & 0xFF ), dataPort); + outb(ADDR_LO, indexPort); + outb(( portaddr & 0xFF ), dataPort); - outb(ADDR_HI, indexPort); - outb(( ( portaddr >> 8 ) & 0xFF ), dataPort); + outb(ADDR_HI, indexPort); + outb((portaddr >> 8) & 0xFF, dataPort); - outb(INTERRUPT_SEL, indexPort); - outb(interrupt, dataPort); + outb(INTERRUPT_SEL, indexPort); + outb(interrupt, dataPort); - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); } -void SMCEnableKYBD( unsigned long baseAddr ) +static void SMCEnableKYBD(unsigned long baseAddr) { - unsigned long indexPort; - unsigned long dataPort; + unsigned long indexPort; + unsigned long dataPort; - indexPort = baseAddr; - dataPort = ( unsigned long )( ( char * )baseAddr + 1 ); + indexPort = baseAddr; + dataPort = baseAddr + 1; - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(KYBD, dataPort); + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(KYBD, dataPort); - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(KYBD_INTERRUPT, dataPort); + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(KYBD_INTERRUPT, dataPort); - outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */ - outb(MOUS_INTERRUPT, dataPort); + outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */ + outb(MOUS_INTERRUPT, dataPort); - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); } -void SMCEnableFDC( unsigned long baseAddr ) +static void SMCEnableFDC(unsigned long baseAddr) { - unsigned long indexPort; - unsigned long dataPort; + unsigned long indexPort; + unsigned long dataPort; - unsigned char oldValue; + unsigned char oldValue; - indexPort = baseAddr; - dataPort = ( unsigned long )( ( char * )baseAddr + 1 ); + indexPort = baseAddr; + dataPort = baseAddr + 1; - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(FDC, dataPort); + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(FDC, dataPort); - outb(FDD_MODE_REGISTER, indexPort); - oldValue = inb(dataPort); + outb(FDD_MODE_REGISTER, indexPort); + oldValue = inb(dataPort); - oldValue |= 0x0E; /* Enable burst mode */ - outb(oldValue, dataPort); + oldValue |= 0x0E; /* Enable burst mode */ + outb(oldValue, dataPort); - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(0x06, dataPort ); + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(0x06, dataPort ); - outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ - outb(0x02, dataPort); + outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ + outb(0x02, dataPort); - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); } #if SMC_DEBUG -void SMCReportDeviceStatus( unsigned long baseAddr ) +static void SMCReportDeviceStatus(unsigned long baseAddr) { - unsigned long indexPort; - unsigned long dataPort; - unsigned char currentControl; - - indexPort = baseAddr; - dataPort = ( unsigned long )( ( char * )baseAddr + 1 ); - - outb(POWER_CONTROL, indexPort); - currentControl = inb(dataPort); - - if ( currentControl & ( 1 << FDC ) ) - printk( "\t+FDC Enabled\n" ); - else - printk( "\t-FDC Disabled\n" ); - - if ( currentControl & ( 1 << IDE1 ) ) - printk( "\t+IDE1 Enabled\n" ); - else - printk( "\t-IDE1 Disabled\n" ); - - if ( currentControl & ( 1 << IDE2 ) ) - printk( "\t+IDE2 Enabled\n" ); - else - printk( "\t-IDE2 Disabled\n" ); - - if ( currentControl & ( 1 << PARP ) ) - printk( "\t+PARP Enabled\n" ); - else - printk( "\t-PARP Disabled\n" ); - - if ( currentControl & ( 1 << SER1 ) ) - printk( "\t+SER1 Enabled\n" ); - else - printk( "\t-SER1 Disabled\n" ); + unsigned long indexPort; + unsigned long dataPort; + unsigned char currentControl; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(POWER_CONTROL, indexPort); + currentControl = inb(dataPort); + + printk(currentControl & (1 << FDC) + ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n"); + printk(currentControl & (1 << IDE1) + ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n"); + printk(currentControl & (1 << IDE2) + ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n"); + printk(currentControl & (1 << PARP) + ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n"); + printk(currentControl & (1 << SER1) + ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n"); + printk(currentControl & (1 << SER2) + ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n"); - if ( currentControl & ( 1 << SER2 ) ) - printk( "\t+SER2 Enabled\n" ); - else - printk( "\t-SER2 Disabled\n" ); - - printk( "\n" ); + printk( "\n" ); } #endif -int SMCInit(void) +static int SMCInit(void) { - unsigned long SMCUltraBase; + unsigned long SMCUltraBase; - if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) { - printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", - SMCUltraBase ); + if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { + printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", + SMCUltraBase); #if SMC_DEBUG - SMCReportDeviceStatus( SMCUltraBase ); + SMCReportDeviceStatus(SMCUltraBase); #endif - SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT ); - SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT ); - SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT ); - /* on PC164, IDE on the SMC is not enabled; CMD646 (PCI) on MB */ - SMCEnableKYBD( SMCUltraBase ); - SMCEnableFDC( SMCUltraBase ); + SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT); + SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT); + SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT); + /* On PC164, IDE on the SMC is not enabled; + CMD646 (PCI) on MB */ + SMCEnableKYBD(SMCUltraBase); + SMCEnableFDC(SMCUltraBase); #if SMC_DEBUG - SMCReportDeviceStatus( SMCUltraBase ); + SMCReportDeviceStatus(SMCUltraBase); #endif - SMCRunState( SMCUltraBase ); - return( 1 ); - } - else { + SMCRunState(SMCUltraBase); + return 1; + } + else { #if SMC_DEBUG - printk( "No SMC FDC37C93X Ultra I/O Controller found\n" ); + printk("No SMC FDC37C93X Ultra I/O Controller found\n"); #endif - return( 0 ); - } + return 0; + } } - #endif /* CONFIG_ALPHA_PC164 */ + +#ifdef CONFIG_ALPHA_MIATA +/* + * Init the built-in ES1888 sound chip (SB16 compatible) + */ +static int es1888_init(void) +{ + /* Sequence of IO reads to init the audio controller */ + inb(0x0229); + inb(0x0229); + inb(0x0229); + inb(0x022b); + inb(0x0229); + inb(0x022b); + inb(0x0229); + inb(0x0229); + inb(0x022b); + inb(0x0229); + inb(0x0220); /* This sets the base address to 0x220 */ + + /* Sequence to set DMA channels */ + outb(0x01, 0x0226); /* reset */ + inb(0x0226); /* pause */ + outb(0x00, 0x0226); /* release reset */ + while (!(inb(0x022e) & 0x80)) /* wait for bit 7 to assert*/ + continue; + inb(0x022a); /* pause */ + outb(0xc6, 0x022c); /* enable extended mode */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0xb1, 0x022c); /* setup for write to Interrupt CR */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0x14, 0x022c); /* set IRQ 5 */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0xb2, 0x022c); /* setup for write to DMA CR */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0x18, 0x022c); /* set DMA channel 1 */ + + return 0; +} +#endif /* CONFIG_ALPHA_MIATA */ #endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/cia.c linux/arch/alpha/kernel/cia.c --- v2.1.78/linux/arch/alpha/kernel/cia.c Mon Oct 7 02:40:22 1996 +++ linux/arch/alpha/kernel/cia.c Mon Jan 12 14:51:14 1998 @@ -6,7 +6,6 @@ * */ #include -#include #include #include #include @@ -38,12 +37,19 @@ * BIOS32-style PCI interface: */ -#ifdef CONFIG_ALPHA_CIA +/* #define DEBUG_MCHECK */ +/* #define DEBUG_CONFIG */ +/* #define DEBUG_DUMP_REGS */ -#ifdef DEBUG -# define DBG(args) printk args +#ifdef DEBUG_MCHECK +# define DBGM(args) printk args #else -# define DBG(args) +# define DBGM(args) +#endif +#ifdef DEBUG_CONFIG +# define DBGC(args) printk args +#else +# define DBGC(args) #endif #define vulp volatile unsigned long * @@ -51,7 +57,7 @@ static volatile unsigned int CIA_mcheck_expected = 0; static volatile unsigned int CIA_mcheck_taken = 0; -static unsigned long CIA_jd; +static unsigned int CIA_jd; /* @@ -101,8 +107,9 @@ { unsigned long addr; - DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n", - bus, device_fn, where, pci_addr, type1)); + DBGC(("mk_conf_addr(bus=%d, device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); if (bus == 0) { int device = device_fn >> 3; @@ -110,7 +117,8 @@ /* type 0 configuration cycle: */ if (device > 20) { - DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", device)); + DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n", + device)); return -1; } @@ -122,7 +130,7 @@ addr = (bus << 16) | (device_fn << 8) | (where); } *pci_addr = addr; - DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); return 0; } @@ -133,22 +141,25 @@ unsigned int stat0, value; unsigned int cia_cfg = 0; /* to keep gcc quiet */ + value = 0xffffffffU; + mb(); + save_flags(flags); /* avoid getting hit by machine check */ cli(); - DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); + DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); /* reset status register to avoid losing errors: */ - stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR); - *((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0; + stat0 = *(vuip)CIA_IOC_CIA_ERR; + *(vuip)CIA_IOC_CIA_ERR = stat0; mb(); - DBG(("conf_read: CIA ERR was 0x%x\n", stat0)); + DBGC(("conf_read: CIA ERR was 0x%x\n", stat0)); /* if Type1 access, must set CIA CFG */ if (type1) { - cia_cfg = *((unsigned int *)CIA_IOC_CFG); + cia_cfg = *(vuip)CIA_IOC_CFG; + *(vuip)CIA_IOC_CFG = cia_cfg | 1; mb(); - *((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1; - DBG(("conf_read: TYPE1 access\n")); + DBGC(("conf_read: TYPE1 access\n")); } mb(); @@ -157,8 +168,7 @@ CIA_mcheck_taken = 0; mb(); /* access configuration space: */ - value = *((volatile unsigned int *)addr); - mb(); + value = *(vuip)addr; mb(); if (CIA_mcheck_taken) { CIA_mcheck_taken = 0; @@ -167,26 +177,25 @@ } CIA_mcheck_expected = 0; mb(); - /* - * david.rusling@reo.mts.dec.com. This code is needed for the - * EB64+ as it does not generate a machine check (why I don't - * know). When we build kernels for one particular platform - * then we can make this conditional on the type. - */ + #if 0 + /* + this code might be necessary if machine checks aren't taken, + but I can't get it to work on CIA-2, so its disabled. + */ draina(); /* now look for any errors */ - stat0 = *((unsigned int *)CIA_IOC_CIA_ERR); - DBG(("conf_read: CIA ERR after read 0x%x\n", stat0)); - if (stat0 & 0x8280U) { /* is any error bit set? */ - /* if not NDEV, print status */ + stat0 = *(vuip)CIA_IOC_CIA_ERR; + DBGC(("conf_read: CIA ERR after read 0x%x\n", stat0)); + if (stat0 & 0x8FEF0FFFU) { /* is any error bit set? */ + /* if not MAS_ABT, print status */ if (!(stat0 & 0x0080)) { printk("CIA.c:conf_read: got stat0=%x\n", stat0); } /* reset error status: */ - *((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0; + *(vuip)CIA_IOC_CIA_ERR = stat0; mb(); wrmces(0x7); /* reset machine check */ value = 0xffffffff; @@ -195,18 +204,19 @@ /* if Type1 access, must reset IOC CFG so normal IO space ops work */ if (type1) { - *((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1; + *(vuip)CIA_IOC_CFG = cia_cfg & ~1; mb(); } - DBG(("conf_read(): finished\n")); + DBGC(("conf_read(): finished\n")); restore_flags(flags); return value; } -static void conf_write(unsigned long addr, unsigned int value, unsigned char type1) +static void conf_write(unsigned long addr, unsigned int value, + unsigned char type1) { unsigned long flags; unsigned int stat0; @@ -216,47 +226,46 @@ cli(); /* reset status register to avoid losing errors: */ - stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR); - *((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0; + stat0 = *(vuip)CIA_IOC_CIA_ERR; + *(vuip)CIA_IOC_CIA_ERR = stat0; mb(); - DBG(("conf_write: CIA ERR was 0x%x\n", stat0)); + DBGC(("conf_write: CIA ERR was 0x%x\n", stat0)); /* if Type1 access, must set CIA CFG */ if (type1) { - cia_cfg = *((unsigned int *)CIA_IOC_CFG); + cia_cfg = *(vuip)CIA_IOC_CFG; + *(vuip)CIA_IOC_CFG = cia_cfg | 1; mb(); - *((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1; - DBG(("conf_read: TYPE1 access\n")); + DBGC(("conf_write: TYPE1 access\n")); } draina(); CIA_mcheck_expected = 1; mb(); /* access configuration space: */ - *((volatile unsigned int *)addr) = value; - mb(); + *(vuip)addr = value; mb(); + CIA_mcheck_expected = 0; mb(); + +#if 0 /* - * david.rusling@reo.mts.dec.com. This code is needed for the - * EB64+ as it does not generate a machine check (why I don't - * know). When we build kernels for one particular platform - * then we can make this conditional on the type. + * This code might be necessary if machine checks aren't taken, + * but I can't get it to work on CIA-2, so its disabled. */ -#if 0 draina(); - /* now look for any errors */ - stat0 = *((unsigned int *)CIA_IOC_CIA_ERR); - DBG(("conf_write: CIA ERR after write 0x%x\n", stat0)); - if (stat0 & 0x8280U) { /* is any error bit set? */ - /* if not NDEV, print status */ + /* Now look for any errors */ + stat0 = *(vuip)CIA_IOC_CIA_ERR; + DBGC(("conf_write: CIA ERR after write 0x%x\n", stat0)); + if (stat0 & 0x8FEF0FFFU) { /* is any error bit set? */ + /* If not MAS_ABT, print status */ if (!(stat0 & 0x0080)) { printk("CIA.c:conf_read: got stat0=%x\n", stat0); } /* reset error status: */ - *((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0; + *(vulp)CIA_IOC_CIA_ERR = stat0; mb(); wrmces(0x7); /* reset machine check */ value = 0xffffffff; @@ -265,11 +274,11 @@ /* if Type1 access, must reset IOC CFG so normal IO space ops work */ if (type1) { - *((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1; + *(vuip)CIA_IOC_CFG = cia_cfg & ~1; mb(); } - DBG(("conf_write(): finished\n")); + DBGC(("conf_write(): finished\n")); restore_flags(flags); } @@ -390,15 +399,58 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end) { - unsigned int cia_err ; + unsigned int cia_tmp; + +#ifdef DEBUG_DUMP_REGS + { + unsigned int temp; + temp = *(vuip)CIA_IOC_CIA_REV; mb(); + printk("CIA_init: CIA_REV was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_PCI_LAT; mb(); + printk("CIA_init: CIA_PCI_LAT was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_CIA_CTRL; mb(); + printk("CIA_init: CIA_CTRL was 0x%x\n", temp); + temp = *(vuip)0xfffffc8740000140UL; mb(); + printk("CIA_init: CIA_CTRL1 was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_HAE_MEM; mb(); + printk("CIA_init: CIA_HAE_MEM was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_HAE_IO; mb(); + printk("CIA_init: CIA_HAE_IO was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_CFG; mb(); + printk("CIA_init: CIA_CFG was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_CACK_EN; mb(); + printk("CIA_init: CIA_CACK_EN was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_CFG; mb(); + printk("CIA_init: CIA_CFG was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_CIA_DIAG; mb(); + printk("CIA_init: CIA_DIAG was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_DIAG_CHECK; mb(); + printk("CIA_init: CIA_DIAG_CHECK was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_PERF_MONITOR; mb(); + printk("CIA_init: CIA_PERF_MONITOR was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_PERF_CONTROL; mb(); + printk("CIA_init: CIA_PERF_CONTROL was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_CIA_ERR; mb(); + printk("CIA_init: CIA_ERR was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_CIA_STAT; mb(); + printk("CIA_init: CIA_STAT was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_MCR; mb(); + printk("CIA_init: CIA_MCR was 0x%x\n", temp); + } +#endif /* DEBUG_DUMP_REGS */ /* * Set up error reporting. */ - cia_err = *(vuip)CIA_IOC_CIA_ERR ; - cia_err |= (0x1 << 7) ; /* master abort */ - *(vuip)CIA_IOC_CIA_ERR = cia_err ; - mb() ; + cia_tmp = *(vuip)CIA_IOC_CIA_ERR; + cia_tmp |= 0x180; /* master, target abort */ + *(vuip)CIA_IOC_CIA_ERR = cia_tmp; + mb(); + + cia_tmp = *(vuip)CIA_IOC_CIA_CTRL; + cia_tmp |= 0x400; /* turn on FILL_ERR to get mchecks */ + *(vuip)CIA_IOC_CIA_CTRL = cia_tmp; + mb(); /* * Set up the PCI->physical memory translation windows. @@ -411,16 +463,16 @@ *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN_SIZE - 1) & 0xfff00000U; *(vuip)CIA_IOC_PCI_T0_BASE = 0; - *(vuip)CIA_IOC_PCI_W1_BASE = 0x0 ; - *(vuip)CIA_IOC_PCI_W2_BASE = 0x0 ; - *(vuip)CIA_IOC_PCI_W3_BASE = 0x0 ; + *(vuip)CIA_IOC_PCI_W1_BASE = 0x0; + *(vuip)CIA_IOC_PCI_W2_BASE = 0x0; + *(vuip)CIA_IOC_PCI_W3_BASE = 0x0; /* * check ASN in HWRPB for validity, report if bad */ if (hwrpb->max_asn != MAX_ASN) { printk("CIA_init: max ASN from HWRPB is bad (0x%lx)\n", - hwrpb->max_asn); + hwrpb->max_asn); hwrpb->max_asn = MAX_ASN; } @@ -432,20 +484,29 @@ */ { #if 0 - unsigned int cia_cfg = *((unsigned int *)CIA_IOC_CFG); mb(); - if (cia_cfg) printk("CIA_init: CFG was 0x%x\n", cia_cfg); + unsigned int cia_cfg = *(vuip)CIA_IOC_CFG; mb(); + if (cia_cfg) printk("CIA_init: CFG was 0x%x\n", cia_cfg); #endif - *((unsigned int *)CIA_IOC_CFG) = 0; mb(); + *(vuip)CIA_IOC_CFG = 0; mb(); } +#if 0 + { + unsigned int temp; + temp = *(vuip)CIA_IOC_CIA_CTRL; mb(); + printk("CIA_init: CIA_CTRL was 0x%x\n", temp); + temp = *(vuip)CIA_IOC_ERR_MASK; mb(); + printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp); + } +#endif return mem_start; } int cia_pci_clr_err(void) { - CIA_jd = *((unsigned int *)CIA_IOC_CIA_ERR); - DBG(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd)); - *((unsigned long *)CIA_IOC_CIA_ERR) = 0x0080; + CIA_jd = *(vuip)CIA_IOC_CIA_ERR; + DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd)); + *(vulp)CIA_IOC_CIA_ERR = 0x0180; mb(); return 0; } @@ -462,17 +523,21 @@ long i; mchk_header = (struct el_common *)la_ptr; - mchk_procdata = - (struct el_procdata *)(la_ptr + mchk_header->proc_offset); - mchk_sysdata = - (struct el_CIA_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset); - - DBG(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr)); - DBG((" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset)); - DBG(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", - CIA_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear)); -#ifdef DEBUG + mchk_procdata = (struct el_procdata *) + (la_ptr + mchk_header->proc_offset); + mchk_sysdata = (struct el_CIA_sysdata_mcheck *) + (la_ptr + mchk_header->sys_offset); + + DBGM(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + DBGM((" pc=0x%lx size=0x%x procoffset=0x%x " + "sysoffset 0x%x\n", regs->pc, mchk_header->size, + mchk_header->proc_offset, mchk_header->sys_offset)); + DBGM(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", + CIA_mcheck_expected, mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear)); + +#ifdef DEBUG_MCHECK { unsigned long *ptr; int i; @@ -483,15 +548,15 @@ ptr[i], ptr[i+1]); } } -#endif /* DEBUG */ +#endif + /* * Check if machine check is due to a badaddr() and if so, * ignore the machine check. */ mb(); - mb(); - if (CIA_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) { - DBG(("CIA machine check expected\n")); + if (CIA_mcheck_expected) { + DBGM(("CIA machine check expected\n")); CIA_mcheck_expected = 0; CIA_mcheck_taken = 1; mb(); @@ -504,34 +569,34 @@ } switch ((unsigned int) mchk_header->code) { - case MCHK_K_TPERR: reason = "tag parity error"; break; - case MCHK_K_TCPERR: reason = "tag control parity error"; break; - case MCHK_K_HERR: reason = "generic hard error"; break; - case MCHK_K_ECC_C: reason = "correctable ECC error"; break; - case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break; - case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break; - case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break; - case 0x96: reason = "i-cache read retryable error"; break; - case 0x98: reason = "processor detected hard error"; break; + case MCHK_K_TPERR: reason = "tag parity error"; break; + case MCHK_K_TCPERR: reason = "tag control parity error"; break; + case MCHK_K_HERR: reason = "generic hard error"; break; + case MCHK_K_ECC_C: reason = "correctable ECC error"; break; + case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break; + case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break; + case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break; + case 0x96: reason = "i-cache read retryable error"; break; + case 0x98: reason = "processor detected hard error"; break; /* system specific (these are for Alcor, at least): */ - case 0x203: reason = "system detected uncorrectable ECC error"; break; - case 0x205: reason = "parity error detected by CIA"; break; - case 0x207: reason = "non-existent memory error"; break; - case 0x209: reason = "PCI SERR detected"; break; - case 0x20b: reason = "PCI data parity error detected"; break; - case 0x20d: reason = "PCI address parity error detected"; break; - case 0x20f: reason = "PCI master abort error"; break; - case 0x211: reason = "PCI target abort error"; break; - case 0x213: reason = "scatter/gather PTE invalid error"; break; - case 0x215: reason = "flash ROM write error"; break; - case 0x217: reason = "IOA timeout detected"; break; - case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; - case 0x21b: reason = "EISA fail-safe timer timeout"; break; - case 0x21d: reason = "EISA bus time-out"; break; - case 0x21f: reason = "EISA software generated NMI"; break; - case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; - default: + case 0x203: reason = "system detected uncorrectable ECC error"; break; + case 0x205: reason = "parity error detected by CIA"; break; + case 0x207: reason = "non-existent memory error"; break; + case 0x209: reason = "PCI SERR detected"; break; + case 0x20b: reason = "PCI data parity error detected"; break; + case 0x20d: reason = "PCI address parity error detected"; break; + case 0x20f: reason = "PCI master abort error"; break; + case 0x211: reason = "PCI target abort error"; break; + case 0x213: reason = "scatter/gather PTE invalid error"; break; + case 0x215: reason = "flash ROM write error"; break; + case 0x217: reason = "IOA timeout detected"; break; + case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; + case 0x21b: reason = "EISA fail-safe timer timeout"; break; + case 0x21d: reason = "EISA bus time-out"; break; + case 0x21f: reason = "EISA software generated NMI"; break; + case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; + default: sprintf(buf, "reason for machine-check unknown (0x%x)", (unsigned int) mchk_header->code); reason = buf; @@ -542,14 +607,14 @@ printk(KERN_CRIT " CIA machine check: %s%s\n", reason, mchk_header->retry ? " (retryable)" : ""); + printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx pc=0x%lx\n", + vector, la_ptr, regs->pc); /* dump the the logout area to give all info: */ ptr = (unsigned long *)la_ptr; for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(KERN_CRIT " +%8lx %016lx %016lx\n", - i*sizeof(long), ptr[i], ptr[i+1]); + printk(KERN_CRIT " +%8lx %016lx %016lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); } } - -#endif /* CONFIG_ALPHA_CIA */ diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.78/linux/arch/alpha/kernel/entry.S Tue Dec 23 16:30:59 1997 +++ linux/arch/alpha/kernel/entry.S Sat Jan 10 11:58:12 1998 @@ -29,11 +29,10 @@ /* * task structure offsets */ -#define TASK_STATE 0 -#define TASK_COUNTER 8 -#define TASK_PRIORITY 16 -#define TASK_FLAGS 24 -#define TASK_SIGPENDING 32 +#define TASK_STATE 0 +#define TASK_FLAGS 8 +#define TASK_SIGPENDING 16 +#define TASK_SIZE 24 /* * task flags (must match include/linux/sched.h): diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.1.78/linux/arch/alpha/kernel/head.S Tue May 13 22:41:00 1997 +++ linux/arch/alpha/kernel/head.S Mon Jan 12 14:51:14 1998 @@ -80,6 +80,48 @@ ret ($26) .end wrmces + .align 3 + .globl whami + .ent whami +whami: + call_pal PAL_whami + ret ($26) + .end whami + + .align 3 + .globl wripir + .ent wripir +wripir: + call_pal PAL_wripir + ret ($26) + .end wripir + + # + # The following two functions are needed for supporting SRM PALcode + # on the PC164 (at least), since that PALcode manages the interrupt + # masking, and we cannot duplicate the effort without causing problems + # + + .align 3 + .globl cserve_ena + .ent cserve_ena +cserve_ena: + bis $16,$16,$17 + lda $16,52($31) + call_pal PAL_cserve + ret ($26) + .end cserve_ena + + .align 3 + .globl cserve_dis + .ent cserve_dis +cserve_dis: + bis $16,$16,$17 + lda $16,53($31) + call_pal PAL_cserve + ret ($26) + .end cserve_dis + # # The following two functions don't need trapb/excb instructions # around the mf_fpcr/mt_fpcr instructions because (a) the kernel diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.1.78/linux/arch/alpha/kernel/irq.c Mon Oct 20 10:36:52 1997 +++ linux/arch/alpha/kernel/irq.c Mon Jan 12 14:51:14 1998 @@ -26,6 +26,9 @@ #include #include +#define vulp volatile unsigned long * +#define vuip volatile unsigned int * + #define RTC_IRQ 8 #ifdef CONFIG_RTC #define TIMER_IRQ 0 /* timer is the pit */ @@ -58,8 +61,9 @@ * The bits are used as follows: * 0.. 7 first (E)ISA PIC (irq level 0..7) * 8..15 second (E)ISA PIC (irq level 8..15) - * Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT): - * 16..47 PCI interrupts 0..31 (int at GRU_INT_MASK) + * Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT) + * or PYXIS (e.g. Miata, PC164-LX): + * 16..47 PCI interrupts 0..31 (int at xxx_INT_MASK) * Mikasa: * 16..31 PCI interrupts 0..15 (short at I/O port 536) * Other systems (not Mikasa) with 16 PCI interrupt lines: @@ -67,53 +71,259 @@ * 24..31 PCI interrupts 8..15 (char at I/O port 27) * Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164): * 16..32 PCI interrupts 0..31 (int at I/O port 804) + * For SABLE, which is really baroque, we manage 40 IRQ's, but the + * hardware really only supports 24, not via normal ISA PIC, + * but cascaded custom 8259's, etc. + * 0-7 (char at 536) + * 8-15 (char at 53a) + * 16-23 (char at 53c) */ static unsigned long irq_mask = ~0UL; +#ifdef CONFIG_ALPHA_SABLE +/* + * Note that the vector reported by the SRM PALcode corresponds to the + * interrupt mask bits, but we have to manage via more normal IRQs. + * + * We have to be able to go back and forth between MASK bits and IRQ: + * these tables help us do so. + */ +static char sable_irq_to_mask[NR_IRQS] = { + -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */ + -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */ + 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */ +}; +#define IRQ_TO_MASK(irq) (sable_irq_to_mask[(irq)]) +static char sable_mask_to_irq[NR_IRQS] = { + 34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */ + 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */ + 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */ +}; +#else /* CONFIG_ALPHA_SABLE */ +#define IRQ_TO_MASK(irq) (irq) +#endif /* CONFIG_ALPHA_SABLE */ + /* * Update the hardware with the irq mask passed in MASK. The function * exploits the fact that it is known that only bit IRQ has changed. */ -static void update_hw(unsigned long irq, unsigned long mask) + +static inline void +sable_update_hw(unsigned long irq, unsigned long mask) { + /* The "irq" argument is really the mask bit number */ switch (irq) { -#if NR_IRQS == 48 - default: - /* note inverted sense of mask bits: */ - *(unsigned int *)GRU_INT_MASK = ~(mask >> 16); mb(); + default: /* 16 ... 23 */ + outb(mask >> 16, 0x53d); + break; + case 8 ... 15: + outb(mask >> 8, 0x53b); + break; + case 0 ... 7: + outb(mask, 0x537); break; + } +} -#elif NR_IRQS == 33 - default: - outl(mask >> 16, 0x804); +static inline void +noritake_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + default: /* 32 ... 47 */ + outw(~(mask >> 32), 0x54c); + break; + case 16 ... 31: + outw(~(mask >> 16), 0x54a); + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); break; + } +} -#elif defined(CONFIG_ALPHA_MIKASA) - default: +#ifdef CONFIG_ALPHA_MIATA +static inline void +miata_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + default: /* 16 ... 47 */ + /* Make CERTAIN none of the bogus ints get enabled... */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x4000000000000e3bUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + +#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) +static inline void +alcor_and_xlt_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + default: /* 16 ... 47 */ + /* On Alcor, at least, lines 20..30 are not connected and can + generate spurrious interrupts if we turn them on while IRQ + probing. So explicitly mask them out. */ + mask |= 0x7ff000000000UL; + + /* Note inverted sense of mask bits: */ + *(vuip)GRU_INT_MASK = ~(mask >> 16); + mb(); + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + +static inline void +mikasa_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + default: /* 16 ... 31 */ outw(~(mask >> 16), 0x536); /* note invert */ break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} -#elif NR_IRQS == 32 - case 16 ... 23: - outb(mask >> 16, 0x26); +/* Unlabeled mechanisms based on the number of irqs. Someone should + probably document and name these. */ + +static inline void +update_hw_33(unsigned long irq, unsigned long mask) +{ + switch (irq) { + default: /* 16 ... 32 */ + outl(mask >> 16, 0x804); break; - default: - outb(mask >> 24, 0x27); + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); break; -#endif - /* handle ISA irqs last---fast devices belong on PCI... */ + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} - case 0 ... 7: /* ISA PIC1 */ +static inline void +update_hw_32(unsigned long irq, unsigned long mask) +{ + switch (irq) { + default: /* 24 ... 31 */ + outb(mask >> 24, 0x27); + break; + case 16 ... 23: + outb(mask >> 16, 0x26); + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ outb(mask, 0x21); break; + } +} - case 8 ...15: /* ISA PIC2 */ +static inline void +update_hw_16(unsigned long irq, unsigned long mask) +{ + switch (irq) { + default: /* 8 ... 15, ISA PIC2 */ outb(mask >> 8, 0xA1); break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; } } +#if defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) +/* + * On the pc164, we cannot take over the IRQs from the SRM, + * so we call down to do our dirty work. Too bad the SRM + * isn't consistent across platforms otherwise we could do + * this always. + */ + +extern void cserve_ena(unsigned long); +extern void cserve_dis(unsigned long); + +static inline void mask_irq(unsigned long irq) +{ + irq_mask |= (1UL << irq); + cserve_dis(irq - 16); +} + +static inline void unmask_irq(unsigned long irq) +{ + irq_mask &= ~(1UL << irq); + cserve_ena(irq - 16); +} + +/* Since we are calling down to PALcode, no need to diddle IPL. */ +void disable_irq(unsigned int irq_nr) +{ + mask_irq(IRQ_TO_MASK(irq_nr)); +} + +void enable_irq(unsigned int irq_nr) +{ + unmask_irq(IRQ_TO_MASK(irq_nr)); +} + +#else +/* + * We manipulate the hardware ourselves. + */ + +static void update_hw(unsigned long irq, unsigned long mask) +{ +#if defined(CONFIG_ALPHA_SABLE) + sable_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_MIATA) + miata_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_NORITAKE) + noritake_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + alcor_and_xlt_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_MIKASA) + mikasa_update_hw(irq, mask); +#elif NR_IRQS == 33 + update_hw_33(irq, mask); +#elif NR_IRQS == 32 + update_hw_32(irq, mask); +#elif NR_IRQS == 16 + update_hw_16(irq, mask); +#else +#error "How do I update the IRQ hardware?" +#endif +} + static inline void mask_irq(unsigned long irq) { irq_mask |= (1UL << irq); @@ -132,7 +342,7 @@ save_flags(flags); cli(); - mask_irq(irq_nr); + mask_irq(IRQ_TO_MASK(irq_nr)); restore_flags(flags); } @@ -142,9 +352,10 @@ save_flags(flags); cli(); - unmask_irq(irq_nr); + unmask_irq(IRQ_TO_MASK(irq_nr)); restore_flags(flags); } +#endif /* PC164 && SRM */ /* * Initial irq handlers. @@ -157,18 +368,18 @@ int i, len = 0; struct irqaction * action; - for (i = 0 ; i < NR_IRQS ; i++) { + for (i = 0; i < NR_IRQS; i++) { action = irq_action[i]; if (!action) continue; len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.interrupts[i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); + i, kstat.interrupts[i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); for (action=action->next; action; action = action->next) { len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); } len += sprintf(buf+len, "\n"); } @@ -177,6 +388,23 @@ static inline void ack_irq(int irq) { +#ifdef CONFIG_ALPHA_SABLE + /* Note that the "irq" here is really the mask bit number */ + switch (irq) { + case 0 ... 7: + outb(0xE0 | (irq - 0), 0x536); + outb(0xE0 | 1, 0x534); /* slave 0 */ + break; + case 8 ... 15: + outb(0xE0 | (irq - 8), 0x53a); + outb(0xE0 | 3, 0x534); /* slave 1 */ + break; + case 16 ... 24: + outb(0xE0 | (irq - 16), 0x53c); + outb(0xE0 | 4, 0x534); /* slave 2 */ + break; + } +#else /* CONFIG_ALPHA_SABLE */ if (irq < 16) { /* ACK the interrupt making it the lowest priority */ /* First the slave .. */ @@ -188,10 +416,11 @@ outb(0xE0 | irq, 0x20); #if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) /* on ALCOR/XLT, need to dismiss interrupt via GRU */ - *(int *)GRU_INT_CLEAR = 0x80000000; mb(); - *(int *)GRU_INT_CLEAR = 0x00000000; mb(); + *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); + *(vuip)GRU_INT_CLEAR = 0x00000000; mb(); #endif /* ALCOR || XLT */ } +#endif /* CONFIG_ALPHA_SABLE */ } int request_irq(unsigned int irq, @@ -221,7 +450,7 @@ if ((action->flags ^ irqflags) & SA_INTERRUPT) return -EBUSY; - /* add new interrupt at end of irq queue */ + /* Add new interrupt at end of irq queue */ do { p = &action->next; action = *p; @@ -229,11 +458,11 @@ shared = 1; } - if (irq == TIMER_IRQ) - action = &timer_irq; - else + if (irq == TIMER_IRQ) + action = &timer_irq; + else action = (struct irqaction *)kmalloc(sizeof(struct irqaction), - GFP_KERNEL); + GFP_KERNEL); if (!action) return -ENOMEM; @@ -252,7 +481,7 @@ *p = action; if (!shared) - unmask_irq(irq); + unmask_irq(IRQ_TO_MASK(irq)); restore_flags(flags); return 0; @@ -280,7 +509,7 @@ cli(); *p = action->next; if (!irq[irq_action]) - mask_irq(irq); + mask_irq(IRQ_TO_MASK(irq)); restore_flags(flags); kfree(action); return; @@ -298,7 +527,7 @@ atomic_t __alpha_bh_counter; #ifdef __SMP__ -#error Me no hablo Alpha SMP +#error "Me no hablo Alpha SMP" #else #define irq_enter(cpu, irq) (++local_irq_count[cpu]) #define irq_exit(cpu, irq) (--local_irq_count[cpu]) @@ -319,9 +548,12 @@ action = action->next; } printk("\n"); + #if defined(CONFIG_ALPHA_JENSEN) + /* ??? Is all this just debugging, or are the inb's and outb's + necessary to make things work? */ printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n", - inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa)); + inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa)); outb(0x0c, 0x3fc); outb(0x0c, 0x2fc); outb(0,0x61); @@ -353,7 +585,7 @@ int cpu = smp_processor_id(); if ((unsigned) irq > NR_IRQS) { - printk("device_interrupt: unexpected interrupt %d\n", irq); + printk("device_interrupt: illegal interrupt %d\n", irq); return; } @@ -365,7 +597,7 @@ * This way another (more timing-critical) interrupt can * come through while we're doing this one. * - * Note! A irq without a handler gets masked and acked, but + * Note! An irq without a handler gets masked and acked, but * never unmasked. The autoirq stuff depends on this (it looks * at the masks before and after doing the probing). */ @@ -397,6 +629,8 @@ # define IACK_SC LCA_IACK_SC #elif defined(CONFIG_ALPHA_CIA) # define IACK_SC CIA_IACK_SC +#elif defined(CONFIG_ALPHA_PYXIS) +# define IACK_SC PYXIS_IACK_SC #else /* * This is bogus but necessary to get it to compile @@ -413,14 +647,13 @@ * Generate a PCI interrupt acknowledge cycle. The PIC will * respond with the interrupt vector of the highest priority * interrupt that is pending. The PALcode sets up the - * interrupts vectors such that irq level L generates vector - * L. + * interrupts vectors such that irq level L generates vector L. */ j = *(volatile int *) IACK_SC; j &= 0xff; if (j == 7) { if (!(inb(0x20) & 0x80)) { - /* it's only a passive release... */ + /* It's only a passive release... */ return; } } @@ -454,43 +687,44 @@ } #if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) -/* we have to conditionally compile this because of GRU_xxx symbols */ -static inline void alcor_and_xlt_device_interrupt(unsigned long vector, - struct pt_regs * regs) -{ - unsigned long pld; - unsigned int i; - unsigned long flags; +/* We have to conditionally compile this because of GRU_xxx symbols */ +static inline void +alcor_and_xlt_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); + cli(); - /* read the interrupt summary register of the GRU */ - pld = (*(unsigned int *)GRU_INT_REQ) & GRU_INT_REQ_BITS; + /* read the interrupt summary register of the GRU */ + pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS; #if 0 - printk("[0x%08lx/0x%04x]", pld, inb(0x20) | (inb(0xA0) << 8)); + printk("[0x%08lx/0x%04x]", pld, inb(0x20) | (inb(0xA0) << 8)); #endif - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 31) { - isa_device_interrupt(vector, regs); - } else { - device_interrupt(16 + i, 16 + i, regs); - } - } - restore_flags(flags); + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 31) { + isa_device_interrupt(vector, regs); + } else { + device_interrupt(16 + i, 16 + i, regs); + } + } + restore_flags(flags); } #endif /* ALCOR || XLT */ -static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector, - struct pt_regs * regs) +static inline void +cabriolet_and_eb66p_device_interrupt(unsigned long vector, + struct pt_regs *regs) { unsigned long pld; unsigned int i; @@ -522,8 +756,8 @@ restore_flags(flags); } -static inline void mikasa_device_interrupt(unsigned long vector, - struct pt_regs * regs) +static inline void +mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs) { unsigned long pld; unsigned int i; @@ -532,20 +766,20 @@ save_flags(flags); cli(); - /* read the interrupt summary registers */ - pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) | - (((unsigned long) inb(0xa0)) << 8) | - ((unsigned long) inb(0x20)); + /* read the interrupt summary registers */ + pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) | + (((unsigned long) inb(0xa0)) << 8) | + ((unsigned long) inb(0x20)); #if 0 - printk("[0x%08lx]", pld); + printk("[0x%08lx]", pld); #endif - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i < 16) { @@ -553,12 +787,12 @@ } else { device_interrupt(i, i, regs); } - } + } restore_flags(flags); } -static inline void eb66_and_eb64p_device_interrupt(unsigned long vector, - struct pt_regs * regs) +static inline void +eb66_and_eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs) { unsigned long pld; unsigned int i; @@ -586,6 +820,93 @@ restore_flags(flags); } +#if defined(CONFIG_ALPHA_MIATA) +/* We have to conditionally compile this because of PYXIS_xxx symbols */ +static inline void +miata_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld, tmp; + unsigned int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* read the interrupt summary register of PYXIS */ + pld = (*(vulp)PYXIS_INT_REQ); + +#if 0 + printk("[0x%08lx/0x%08lx/0x%04x]", pld, + *(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8)); +#endif + +#if 1 + /* + * For now, AND off any bits we are not interested in: + * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8) + * then all the PCI slots/INTXs (12-31). + */ + /* Maybe HALT should only be used for SRM console boots? */ + pld &= 0x00000000fffff1c4UL; +#endif + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 7) { + isa_device_interrupt(vector, regs); + } else if (i == 6) + continue; + else { /* if not timer int */ + device_interrupt(16 + i, 16 + i, regs); + } + *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); + tmp = *(vulp)PYXIS_INT_REQ; + } + restore_flags(flags); +} +#endif /* MIATA */ + +static inline void +noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* read the interrupt summary registers of NORITAKE */ + pld = ((unsigned long) inw(0x54c) << 32) | + ((unsigned long) inw(0x54a) << 16) | + ((unsigned long) inb(0xa0) << 8) | + ((unsigned long) inb(0x20)); + +#if 0 + printk("[0x%08lx]", pld); +#endif + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i < 16) { + isa_device_interrupt(vector, regs); + } else { + device_interrupt(i, i, regs); + } + } + restore_flags(flags); +} + #endif /* CONFIG_PCI */ /* @@ -611,7 +932,8 @@ * "ack" to a different interrupt than we report to the rest of the * world. */ -static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +static inline void +srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq, ack; unsigned long flags; @@ -624,25 +946,69 @@ #ifdef CONFIG_ALPHA_JENSEN switch (vector) { - case 0x660: handle_nmi(regs); return; + case 0x660: handle_nmi(regs); return; /* local device interrupts: */ - case 0x900: handle_irq(4, regs); return; /* com1 -> irq 4 */ - case 0x920: handle_irq(3, regs); return; /* com2 -> irq 3 */ - case 0x980: handle_irq(1, regs); return; /* kbd -> irq 1 */ - case 0x990: handle_irq(9, regs); return; /* mouse -> irq 9 */ - default: + case 0x900: handle_irq(4, regs); return; /* com1 -> irq 4 */ + case 0x920: handle_irq(3, regs); return; /* com2 -> irq 3 */ + case 0x980: handle_irq(1, regs); return; /* kbd -> irq 1 */ + case 0x990: handle_irq(9, regs); return; /* mouse -> irq 9 */ + default: if (vector > 0x900) { printk("Unknown local interrupt %lx\n", vector); } } - /* irq1 is supposed to be the keyboard, silly Jensen (is this really needed??) */ + /* irq1 is supposed to be the keyboard, silly Jensen + (is this really needed??) */ if (irq == 1) irq = 7; #endif /* CONFIG_ALPHA_JENSEN */ +#ifdef CONFIG_ALPHA_MIATA + /* + * I really hate to do this, but the MIATA SRM console ignores the + * low 8 bits in the interrupt summary register, and reports the + * vector 0x80 *lower* than I expected from the bit numbering in + * the documentation. + * This was done because the low 8 summary bits really aren't used + * for reporting any interrupts (the PCI-ISA bridge, bit 7, isn't + * used for this purpose, as PIC interrupts are delivered as the + * vectors 0x800-0x8f0). + * But I really don't want to change the fixup code for allocation + * of IRQs, nor the irq_mask maintenance stuff, both of which look + * nice and clean now. + * So, here's this grotty hack... :-( + */ + if (irq >= 16) + ack = irq = irq + 8; +#endif /* CONFIG_ALPHA_MIATA */ + +#ifdef CONFIG_ALPHA_NORITAKE + /* + * I really hate to do this, but the NORITAKE SRM console reports + * PCI vectors *lower* than I expected from the bit numbering in + * the documentation. + * But I really don't want to change the fixup code for allocation + * of IRQs, nor the irq_mask maintenance stuff, both of which look + * nice and clean now. + * So, here's this additional grotty hack... :-( + */ + if (irq >= 16) + ack = irq = irq + 1; +#endif /* CONFIG_ALPHA_NORITAKE */ + +#ifdef CONFIG_ALPHA_SABLE + irq = sable_mask_to_irq[(ack)]; +#if 0 + if (irq == 5 || irq == 9 || irq == 10 || irq == 11 || + irq == 14 || irq == 15) + printk("srm_device_interrupt: vector=0x%lx ack=0x%x" + " irq=0x%x\n", vector, ack, irq); +#endif +#endif /* CONFIG_ALPHA_SABLE */ + device_interrupt(irq, ack, regs); - restore_flags(flags) ; + restore_flags(flags); } /* @@ -665,6 +1031,7 @@ irqs |= (1UL << i); } } + /* * Wait about 100ms for spurious interrupts to mask themselves * out again... @@ -695,66 +1062,154 @@ return i; } -static void machine_check(unsigned long vector, unsigned long la, struct pt_regs * regs) +extern void lca_machine_check (unsigned long vector, unsigned long la, + struct pt_regs *regs); +extern void apecs_machine_check(unsigned long vector, unsigned long la, + struct pt_regs * regs); +extern void cia_machine_check(unsigned long vector, unsigned long la, + struct pt_regs * regs); +extern void pyxis_machine_check(unsigned long vector, unsigned long la, + struct pt_regs * regs); +extern void t2_machine_check(unsigned long vector, unsigned long la, + struct pt_regs * regs); + +static void +machine_check(unsigned long vector, unsigned long la, struct pt_regs *regs) { #if defined(CONFIG_ALPHA_LCA) - extern void lca_machine_check (unsigned long vector, unsigned long la, - struct pt_regs *regs); lca_machine_check(vector, la, regs); #elif defined(CONFIG_ALPHA_APECS) - extern void apecs_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); apecs_machine_check(vector, la, regs); #elif defined(CONFIG_ALPHA_CIA) - extern void cia_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); cia_machine_check(vector, la, regs); +#elif defined(CONFIG_ALPHA_PYXIS) + pyxis_machine_check(vector, la, regs); +#elif defined(CONFIG_ALPHA_T2) + t2_machine_check(vector, la, regs); #else printk("Machine check\n"); #endif } -asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) +asmlinkage void +do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs regs) { switch (type) { - case 0: - printk("Interprocessor interrupt? You must be kidding\n"); - break; - case 1: - handle_irq(RTC_IRQ, ®s); - return; - case 2: - machine_check(vector, la_ptr, ®s); - return; - case 3: + case 0: + printk("Interprocessor interrupt? You must be kidding\n"); + break; + case 1: + handle_irq(RTC_IRQ, ®s); + return; + case 2: + machine_check(vector, la_ptr, ®s); + return; + case 3: #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \ defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM) - srm_device_interrupt(vector, ®s); -#elif NR_IRQS == 48 - alcor_and_xlt_device_interrupt(vector, ®s); + srm_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_MIATA) + miata_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_NORITAKE) + noritake_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + alcor_and_xlt_device_interrupt(vector, ®s); #elif NR_IRQS == 33 - cabriolet_and_eb66p_device_interrupt(vector, ®s); + cabriolet_and_eb66p_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_MIKASA) - mikasa_device_interrupt(vector, ®s); + mikasa_device_interrupt(vector, ®s); #elif NR_IRQS == 32 - eb66_and_eb64p_device_interrupt(vector, ®s); + eb66_and_eb64p_device_interrupt(vector, ®s); #elif NR_IRQS == 16 - isa_device_interrupt(vector, ®s); + isa_device_interrupt(vector, ®s); #endif - return; - case 4: - printk("Performance counter interrupt\n"); - break;; - default: - printk("Hardware intr %ld %lx? Huh?\n", type, vector); + return; + case 4: + printk("Performance counter interrupt\n"); + break; + default: + printk("Hardware intr %ld %lx? Huh?\n", type, vector); } printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps); } extern asmlinkage void entInt(void); +static inline void sable_init_IRQ(void) +{ + outb(irq_mask , 0x537); /* slave 0 */ + outb(irq_mask >> 8, 0x53b); /* slave 1 */ + outb(irq_mask >> 16, 0x53d); /* slave 2 */ + outb(0x44, 0x535); /* enable cascades in master */ +} + +#ifdef CONFIG_ALPHA_MIATA +static inline void miata_init_IRQ(void) +{ + /* note invert on MASK bits */ + *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); /* invert */ + *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */ + *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */ + *(vulp)PYXIS_INT_REQ = 0x4000000000000000UL; mb(); /* clear upper timer */ +#if 0 + *(vulp)PYXIS_INT_ROUTE = 0UL; mb(); /* all are level */ + *(vulp)PYXIS_INT_CNFG = 0UL; mb(); /* all clear */ +#endif + enable_irq(16 + 2); /* enable HALT switch - SRM only? */ + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} +#endif + +static inline void noritake_init_IRQ(void) +{ + outw(~(irq_mask >> 16), 0x54a); /* note invert */ + outw(~(irq_mask >> 32), 0x54c); /* note invert */ + enable_irq(2); /* enable cascade */ +} + +#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) +static inline void alcor_and_xlt_init_IRQ(void) +{ + *(vuip)GRU_INT_MASK = ~(irq_mask >> 16); mb(); /* note invert */ + *(vuip)GRU_INT_EDGE = 0U; mb(); /* all are level */ + *(vuip)GRU_INT_HILO = 0x80000000U; mb(); /* ISA only HI */ + *(vuip)GRU_INT_CLEAR = 0UL; mb(); /* all clear */ + + enable_irq(16 + 31); /* enable (E)ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} +#endif + +static inline void mikasa_init_IRQ(void) +{ + outw(~(irq_mask >> 16), 0x536); /* note invert */ + enable_irq(2); /* enable cascade */ +} + +static inline void init_IRQ_33(void) +{ + outl(irq_mask >> 16, 0x804); + enable_irq(16 + 4); /* enable SIO cascade */ + enable_irq(2); /* enable cascade */ +} + +static inline void init_IRQ_32(void) +{ + outb(irq_mask >> 16, 0x26); + outb(irq_mask >> 24, 0x27); + enable_irq(16 + 5); /* enable SIO cascade */ + enable_irq(2); /* enable cascade */ +} + +static inline void init_IRQ_16(void) +{ + enable_irq(2); /* enable cascade */ +} + void init_IRQ(void) { wrent(entInt, 0); @@ -762,21 +1217,27 @@ dma_outb(0, DMA2_RESET_REG); dma_outb(0, DMA1_CLR_MASK_REG); dma_outb(0, DMA2_CLR_MASK_REG); -#if NR_IRQS == 48 - *(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16); mb();/* invert */ - *(unsigned int *)GRU_INT_EDGE = 0UL; mb();/* all are level */ - *(unsigned int *)GRU_INT_HILO = 0x80000000UL; mb();/* ISA only HI */ - *(unsigned int *)GRU_INT_CLEAR = 0UL; mb();/* all clear */ - enable_irq(16 + 31); /* enable (E)ISA PIC cascade */ -#elif NR_IRQS == 33 - outl(irq_mask >> 16, 0x804); - enable_irq(16 + 4); /* enable SIO cascade */ + +#if defined(CONFIG_ALPHA_SABLE) + sable_init_IRQ(); +#elif defined(CONFIG_ALPHA_MIATA) + miata_init_IRQ(); +#elif defined(CONFIG_ALPHA_NORITAKE) + noritake_init_IRQ(); +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + alcor_and_xlt_init_IRQ(); +#elif defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) + /* Disable all the PCI interrupts? Otherwise, everthing was + done by SRM already. */ #elif defined(CONFIG_ALPHA_MIKASA) - outw(~(irq_mask >> 16), 0x536); /* note invert */ + mikasa_init_IRQ(); +#elif NR_IRQS == 33 + init_IRQ_33(); #elif NR_IRQS == 32 - outb(irq_mask >> 16, 0x26); - outb(irq_mask >> 24, 0x27); - enable_irq(16 + 5); /* enable SIO cascade */ + init_IRQ_32(); +#elif NR_IRQS == 16 + init_IRQ_16(); +#else +#error "How do I initialize the interrupt hardware?" #endif - enable_irq(2); /* enable cascade */ } diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/lca.c linux/arch/alpha/kernel/lca.c --- v2.1.78/linux/arch/alpha/kernel/lca.c Wed Oct 9 22:54:43 1996 +++ linux/arch/alpha/kernel/lca.c Mon Jan 12 14:51:14 1998 @@ -6,7 +6,6 @@ * bios code. */ #include -#include #include #include #include @@ -19,9 +18,8 @@ * BIOS32-style PCI interface: */ -#ifdef CONFIG_ALPHA_LCA - #define vulp volatile unsigned long * +#define vuip volatile unsigned int * /* * Machine check reasons. Defined according to PALcode sources @@ -102,11 +100,11 @@ return -1; } - *((volatile unsigned long*) LCA_IOC_CONF) = 0; + *((vulp) LCA_IOC_CONF) = 0; addr = (1 << (11 + device)) | (func << 8) | where; } else { /* type 1 configuration cycle: */ - *((volatile unsigned long*) LCA_IOC_CONF) = 1; + *((vulp) LCA_IOC_CONF) = 1; addr = (bus << 16) | (device_fn << 8) | where; } *pci_addr = addr; @@ -123,13 +121,13 @@ cli(); /* reset status register to avoid loosing errors: */ - stat0 = *((volatile unsigned long*)LCA_IOC_STAT0); - *((volatile unsigned long*)LCA_IOC_STAT0) = stat0; + stat0 = *(vulp)LCA_IOC_STAT0; + *(vulp)LCA_IOC_STAT0 = stat0; mb(); /* access configuration space: */ - value = *((volatile unsigned int*)addr); + value = *(vuip)addr; draina(); stat0 = *((unsigned long*)LCA_IOC_STAT0); @@ -141,7 +139,7 @@ } /* reset error status: */ - *((volatile unsigned long*)LCA_IOC_STAT0) = stat0; + *(vulp)LCA_IOC_STAT0 = stat0; mb(); wrmces(0x7); /* reset machine check */ @@ -160,13 +158,13 @@ cli(); /* reset status register to avoid loosing errors: */ - stat0 = *((volatile unsigned long*)LCA_IOC_STAT0); - *((volatile unsigned long*)LCA_IOC_STAT0) = stat0; + stat0 = *(vulp)LCA_IOC_STAT0; + *(vulp)LCA_IOC_STAT0 = stat0; mb(); /* access configuration space: */ - *((volatile unsigned int*)addr) = value; + *(vuip)addr = value; draina(); stat0 = *((unsigned long*)LCA_IOC_STAT0); @@ -178,7 +176,7 @@ } /* reset error status: */ - *((volatile unsigned long*)LCA_IOC_STAT0) = stat0; + *(vulp)LCA_IOC_STAT0 = stat0; mb(); wrmces(0x7); /* reset machine check */ } @@ -310,13 +308,12 @@ } - - /* * Constants used during machine-check handling. I suppose these * could be moved into lca.h but I don't see much reason why anybody * else would want to use them. */ + #define ESR_EAV (1UL<< 0) /* error address valid */ #define ESR_CEE (1UL<< 1) /* correctable error */ #define ESR_UEE (1UL<< 2) /* uncorrectable error */ @@ -338,53 +335,60 @@ void mem_error (unsigned long esr, unsigned long ear) { - printk(" %s %s error to %s occurred at address %x\n", - (esr & ESR_CEE) ? "Correctable" : ((esr & ESR_UEE) ? "Uncorrectable" : "A"), - (esr & ESR_WRE) ? "write" : "read", - (esr & ESR_SOR) ? "memory" : "b-cache", - (unsigned) (ear & 0x1ffffff8)); - if (esr & ESR_CTE) { - printk(" A b-cache tag parity error was detected.\n"); - } - if (esr & ESR_MSE) { - printk(" Several other correctable errors occurred.\n"); - } - if (esr & ESR_MHE) { - printk(" Several other uncorrectable errors occurred.\n"); - } - if (esr & ESR_NXM) { - printk(" Attempted to access non-existent memory.\n"); - } + printk(" %s %s error to %s occurred at address %x\n", + *((esr & ESR_CEE) ? "Correctable" : + (esr & ESR_UEE) ? "Uncorrectable" : "A"), + (esr & ESR_WRE) ? "write" : "read", + (esr & ESR_SOR) ? "memory" : "b-cache", + (unsigned) (ear & 0x1ffffff8)); + if (esr & ESR_CTE) { + printk(" A b-cache tag parity error was detected.\n"); + } + if (esr & ESR_MSE) { + printk(" Several other correctable errors occurred.\n"); + } + if (esr & ESR_MHE) { + printk(" Several other uncorrectable errors occurred.\n"); + } + if (esr & ESR_NXM) { + printk(" Attempted to access non-existent memory.\n"); + } } void ioc_error (__u32 stat0, __u32 stat1) { - const char *pci_cmd[] = { - "Interrupt Acknowledge", "Special", "I/O Read", "I/O Write", - "Rsvd 1", "Rsvd 2", "Memory Read", "Memory Write", "Rsvd3", "Rsvd4", - "Configuration Read", "Configuration Write", "Memory Read Multiple", - "Dual Address", "Memory Read Line", "Memory Write and Invalidate" - }; - const char *err_name[] = { - "exceeded retry limit", "no device", "bad data parity", "target abort", - "bad address parity", "page table read error", "invalid page", "data error" - }; - unsigned code = (stat0 & IOC_CODE) >> IOC_CODE_SHIFT; - unsigned cmd = (stat0 & IOC_CMD) >> IOC_CMD_SHIFT; - - printk(" %s initiated PCI %s cycle to address %x failed due to %s.\n", - code > 3 ? "PCI" : "CPU", pci_cmd[cmd], stat1, err_name[code]); - if (code == 5 || code == 6) { - printk(" (Error occurred at PCI memory address %x.)\n", (stat0 & ~IOC_P_NBR)); - } - if (stat0 & IOC_LOST) { - printk(" Other PCI errors occurred simultaneously.\n"); - } + static const char * const pci_cmd[] = { + "Interrupt Acknowledge", "Special", "I/O Read", "I/O Write", + "Rsvd 1", "Rsvd 2", "Memory Read", "Memory Write", "Rsvd3", + "Rsvd4", "Configuration Read", "Configuration Write", + "Memory Read Multiple", "Dual Address", "Memory Read Line", + "Memory Write and Invalidate" + }; + static const char * const err_name[] = { + "exceeded retry limit", "no device", "bad data parity", + "target abort", "bad address parity", "page table read error", + "invalid page", "data error" + }; + unsigned code = (stat0 & IOC_CODE) >> IOC_CODE_SHIFT; + unsigned cmd = (stat0 & IOC_CMD) >> IOC_CMD_SHIFT; + + printk(" %s initiated PCI %s cycle to address %x" + " failed due to %s.\n", + code > 3 ? "PCI" : "CPU", pci_cmd[cmd], stat1, err_name[code]); + + if (code == 5 || code == 6) { + printk(" (Error occurred at PCI memory address %x.)\n", + (stat0 & ~IOC_P_NBR)); + } + if (stat0 & IOC_LOST) { + printk(" Other PCI errors occurred simultaneously.\n"); + } } -void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs) +void lca_machine_check (unsigned long vector, unsigned long la, + struct pt_regs *regs) { unsigned long * ptr; const char * reason; @@ -403,21 +407,21 @@ * revision level, which we ignore for now. */ switch (el.c->code & 0xffffffff) { - case MCHK_K_TPERR: reason = "tag parity error"; break; - case MCHK_K_TCPERR: reason = "tag control parity error"; break; - case MCHK_K_HERR: reason = "access to non-existent memory"; break; - case MCHK_K_ECC_C: reason = "correctable ECC error"; break; - case MCHK_K_ECC_NC: reason = "non-correctable ECC error"; break; - case MCHK_K_CACKSOFT: reason = "MCHK_K_CACKSOFT"; break; /* what's this? */ - case MCHK_K_BUGCHECK: reason = "illegal exception in PAL mode"; break; - case MCHK_K_OS_BUGCHECK: reason = "callsys in kernel mode"; break; - case MCHK_K_DCPERR: reason = "d-cache parity error"; break; - case MCHK_K_ICPERR: reason = "i-cache parity error"; break; - case MCHK_K_SIO_SERR: reason = "SIO SERR occurred on on PCI bus"; break; - case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break; - case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break; - case MCHK_K_UNKNOWN: - default: + case MCHK_K_TPERR: reason = "tag parity error"; break; + case MCHK_K_TCPERR: reason = "tag control parity error"; break; + case MCHK_K_HERR: reason = "access to non-existent memory"; break; + case MCHK_K_ECC_C: reason = "correctable ECC error"; break; + case MCHK_K_ECC_NC: reason = "non-correctable ECC error"; break; + case MCHK_K_CACKSOFT: reason = "MCHK_K_CACKSOFT"; break; /* what's this? */ + case MCHK_K_BUGCHECK: reason = "illegal exception in PAL mode"; break; + case MCHK_K_OS_BUGCHECK: reason = "callsys in kernel mode"; break; + case MCHK_K_DCPERR: reason = "d-cache parity error"; break; + case MCHK_K_ICPERR: reason = "i-cache parity error"; break; + case MCHK_K_SIO_SERR: reason = "SIO SERR occurred on on PCI bus"; break; + case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break; + case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break; + case MCHK_K_UNKNOWN: + default: sprintf(buf, "reason for machine-check unknown (0x%lx)", el.c->code & 0xffffffff); reason = buf; @@ -427,19 +431,20 @@ wrmces(rdmces()); /* reset machine check pending flag */ switch (el.c->size) { - case sizeof(struct el_lca_mcheck_short): + case sizeof(struct el_lca_mcheck_short): printk(KERN_CRIT " Reason: %s (short frame%s, dc_stat=%lx):\n", - reason, el.c->retry ? ", retryable" : "", el.s->dc_stat); + reason, el.c->retry ? ", retryable" : "", + el.s->dc_stat); if (el.s->esr & ESR_EAV) { - mem_error(el.s->esr, el.s->ear); + mem_error(el.s->esr, el.s->ear); } if (el.s->ioc_stat0 & IOC_ERR) { - ioc_error(el.s->ioc_stat0, el.s->ioc_stat1); + ioc_error(el.s->ioc_stat0, el.s->ioc_stat1); } break; - case sizeof(struct el_lca_mcheck_long): + case sizeof(struct el_lca_mcheck_long): printk(KERN_CRIT " Reason: %s (long frame%s):\n", reason, el.c->retry ? ", retryable" : ""); printk(KERN_CRIT @@ -447,14 +452,14 @@ el.l->pt[0], el.l->exc_addr, el.l->dc_stat); printk(KERN_CRIT " car: %lx\n", el.l->car); if (el.l->esr & ESR_EAV) { - mem_error(el.l->esr, el.l->ear); + mem_error(el.l->esr, el.l->ear); } if (el.l->ioc_stat0 & IOC_ERR) { - ioc_error(el.l->ioc_stat0, el.l->ioc_stat1); + ioc_error(el.l->ioc_stat0, el.l->ioc_stat1); } break; - default: + default: printk(KERN_CRIT " Unknown errorlog size %d\n", el.c->size); } @@ -462,9 +467,51 @@ ptr = (unsigned long *) la; for (i = 0; i < el.c->size / sizeof(long); i += 2) { - printk(KERN_CRIT " +%8lx %016lx %016lx\n", - i*sizeof(long), ptr[i], ptr[i+1]); + printk(KERN_CRIT " +%8lx %016lx %016lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); } } -#endif /* CONFIG_ALPHA_LCA */ +/* + * The following routines are needed to support the SPEED changing + * necessary to successfully manage the thermal problem on the AlphaBook1. + */ + +void +lca_clock_print(void) +{ + long pmr_reg; + + pmr_reg = READ_PMR; + + printk("Status of clock control:\n"); + printk("\tPrimary clock divisor\t0x%x\n", GET_PRIMARY(pmr_reg)); + printk("\tOverride clock divisor\t0x%x\n", GET_OVERRIDE(pmr_reg)); + printk("\tInterrupt override is %s\n", + (pmr_reg & LCA_PMR_INTO) ? "on" : "off"); + printk("\tDMA override is %s\n", + (pmr_reg & LCA_PMR_DMAO) ? "on" : "off"); + +} + +int +lca_get_clock(void) +{ + long pmr_reg; + + pmr_reg = READ_PMR; + return(GET_PRIMARY(pmr_reg)); + +} + +void +lca_clock_fiddle(int divisor) +{ + long pmr_reg; + + pmr_reg = READ_PMR; + SET_PRIMARY_CLOCK(pmr_reg, divisor); + /* lca_norm_clock = divisor; */ + WRITE_PMR(pmr_reg); + mb(); +} diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.1.78/linux/arch/alpha/kernel/osf_sys.c Fri Jan 2 14:37:01 1998 +++ linux/arch/alpha/kernel/osf_sys.c Mon Jan 12 14:49:36 1998 @@ -846,10 +846,6 @@ return -EOPNOTSUPP; } -/* Dummy functions for now */ -#define wrfpcr(x) do { } while (0) -#define rdfpcr() 0 - asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes, int *start, void *arg) diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.1.78/linux/arch/alpha/kernel/process.c Thu Jul 17 10:06:03 1997 +++ linux/arch/alpha/kernel/process.c Mon Jan 12 14:51:14 1998 @@ -38,6 +38,7 @@ #include #include #include +#include /* * Initial task structure. Make this a per-architecture thing, @@ -86,7 +87,7 @@ return ret; } -void machine_restart(char * __unused) +static void finish_shutdown(void) { #ifdef CONFIG_RTC /* reset rtc to defaults */ unsigned char control; @@ -105,7 +106,6 @@ CMOS_READ(RTC_INTR_FLAGS); restore_flags(flags); #endif - #if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR) /* who said DEC engineer's have no sense of humor? ;-)) */ *(int *) GRU_RESET = 0x0000dead; @@ -114,12 +114,50 @@ halt(); } +void machine_restart(char * __unused) +{ +#if defined(CONFIG_ALPHA_SRM) + extern struct hwrpb_struct *hwrpb; + struct percpu_struct *cpup; + unsigned long flags; + + cpup = (struct percpu_struct *) + ((unsigned long)hwrpb + hwrpb->processor_offset); + flags = cpup->flags; + flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */ + flags |= 0x0000000000020000UL; /* this is "cold bootstrap" */ +/* flags |= 0x0000000000030000UL; *//* this is "warm bootstrap" */ + cpup->flags = flags; + mb(); +#endif /* SRM */ + + finish_shutdown(); +} + void machine_halt(void) { +#if defined(CONFIG_ALPHA_SRM) + extern struct hwrpb_struct *hwrpb; + struct percpu_struct *cpup; + unsigned long flags; + + cpup = (struct percpu_struct *) + ((unsigned long)hwrpb + hwrpb->processor_offset); + flags = cpup->flags; + flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */ + flags |= 0x0000000000040000UL; /* this is "remain halted" */ + cpup->flags = flags; + mb(); + + finish_shutdown(); +#endif /* SRM */ } void machine_power_off(void) { + /* None of the machines we support, at least, has switchable + power supplies. */ + machine_halt(); } void show_regs(struct pt_regs * regs) diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/pyxis.c linux/arch/alpha/kernel/pyxis.c --- v2.1.78/linux/arch/alpha/kernel/pyxis.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/pyxis.c Mon Jan 12 14:51:14 1998 @@ -0,0 +1,503 @@ +/* + * Code common to all PYXIS chips. + * + * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern struct hwrpb_struct *hwrpb; +extern asmlinkage void wrmces(unsigned long mces); +extern int alpha_sys_type; + +/* + * BIOS32-style PCI interface: + */ + +#ifdef DEBUG +# define DBG(args) printk args +#else +# define DBG(args) +#endif + +#define DEBUG_MCHECK +#ifdef DEBUG_MCHECK +# define DBG_MCK(args) printk args +#else +# define DBG_MCK(args) +#endif + +#define vulp volatile unsigned long * +#define vuip volatile unsigned int * + +static volatile unsigned int PYXIS_mcheck_expected = 0; +static volatile unsigned int PYXIS_mcheck_taken = 0; +static unsigned int PYXIS_jd; + + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address and setup the PYXIS_HAXR2 register + * accordingly. It is therefore not safe to have concurrent + * invocations to configuration space access routines, but there + * really shouldn't be any need for this. + * + * Type 0: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:11 Device select bit. + * 10:8 Function number + * 7:2 Register number + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., scsi and ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ +static int mk_conf_addr(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned long *pci_addr, + unsigned char *type1) +{ + unsigned long addr; + + DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," + " pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + if (bus == 0) { + int device; + + device = device_fn >> 3; + /* type 0 configuration cycle: */ +#if NOT_NOW + if (device > 20) { + DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", + device)); + return -1; + } +#endif + *type1 = 0; + addr = (device_fn << 8) | (where); + } else { + /* type 1 configuration cycle: */ + *type1 = 1; + addr = (bus << 16) | (device_fn << 8) | (where); + } + *pci_addr = addr; + DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + + +static unsigned int conf_read(unsigned long addr, unsigned char type1) +{ + unsigned long flags; + unsigned int stat0, value; + unsigned int pyxis_cfg = 0; /* to keep gcc quiet */ + + save_flags(flags); /* avoid getting hit by machine check */ + cli(); + + DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); + + /* reset status register to avoid losing errors: */ + stat0 = *(vuip)PYXIS_ERR; + *(vuip)PYXIS_ERR = stat0; + mb(); + DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0)); + /* if Type1 access, must set PYXIS CFG */ + if (type1) { + pyxis_cfg = *(vuip)PYXIS_CFG; + *(vuip)PYXIS_CFG = pyxis_cfg | 1; + mb(); + DBG(("conf_read: TYPE1 access\n")); + } + + mb(); + draina(); + PYXIS_mcheck_expected = 1; + PYXIS_mcheck_taken = 0; + mb(); + /* access configuration space: */ + value = *(vuip)addr; + mb(); + if (PYXIS_mcheck_taken) { + PYXIS_mcheck_taken = 0; + value = 0xffffffffU; + mb(); + } + PYXIS_mcheck_expected = 0; + mb(); + /* + * david.rusling@reo.mts.dec.com. This code is needed for the + * EB64+ as it does not generate a machine check (why I don't + * know). When we build kernels for one particular platform + * then we can make this conditional on the type. + */ +#if 0 + draina(); + + /* now look for any errors */ + stat0 = *(vuip)PYXIS_IOC_PYXIS_ERR; + DBG(("conf_read: PYXIS ERR after read 0x%x\n", stat0)); + if (stat0 & 0x8280U) { /* is any error bit set? */ + /* if not NDEV, print status */ + if (!(stat0 & 0x0080)) { + printk("PYXIS.c:conf_read: got stat0=%x\n", stat0); + } + + /* reset error status: */ + *(vulp)PYXIS_IOC_PYXIS_ERR = stat0; + mb(); + wrmces(0x7); /* reset machine check */ + value = 0xffffffff; + } +#endif + + /* if Type1 access, must reset IOC CFG so normal IO space ops work */ + if (type1) { + *(vuip)PYXIS_CFG = pyxis_cfg & ~1; + mb(); + } + + DBG(("conf_read(): finished\n")); + + restore_flags(flags); + return value; +} + + +static void conf_write(unsigned long addr, unsigned int value, + unsigned char type1) +{ + unsigned long flags; + unsigned int stat0; + unsigned int pyxis_cfg = 0; /* to keep gcc quiet */ + + save_flags(flags); /* avoid getting hit by machine check */ + cli(); + + /* reset status register to avoid losing errors: */ + stat0 = *(vuip)PYXIS_ERR; + *(vuip)PYXIS_ERR = stat0; + mb(); + DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0)); + /* if Type1 access, must set PYXIS CFG */ + if (type1) { + pyxis_cfg = *(vuip)PYXIS_CFG; + *(vuip)PYXIS_CFG = pyxis_cfg | 1; + mb(); + DBG(("conf_read: TYPE1 access\n")); + } + + draina(); + PYXIS_mcheck_expected = 1; + mb(); + /* access configuration space: */ + *(vuip)addr = value; + mb(); + PYXIS_mcheck_expected = 0; + mb(); + + /* if Type1 access, must reset IOC CFG so normal IO space ops work */ + if (type1) { + *(vuip)PYXIS_CFG = pyxis_cfg & ~1; + mb(); + } + + DBG(("conf_write(): finished\n")); + restore_flags(flags); +} + + +int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xff; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + + addr |= (pci_addr << 5) + 0x00; + + *value = conf_read(addr, type1) >> ((where & 3) * 8); + + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xffff; + + if (where & 0x1) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { + return PCIBIOS_SUCCESSFUL; + } + + addr |= (pci_addr << 5) + 0x08; + + *value = conf_read(addr, type1) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xffffffff; + if (where & 0x3) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + *value = conf_read(addr, type1); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x00; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x08; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + + +unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end) +{ + unsigned int pyxis_err ; + + /* + * Set up error reporting. + */ + pyxis_err = *(vuip)PYXIS_ERR ; + pyxis_err |= 0x180; /* master/target abort */ + *(vuip)PYXIS_ERR = pyxis_err ; + mb() ; + pyxis_err = *(vuip)PYXIS_ERR ; + + /* + * Set up the PCI->physical memory translation windows. + * For now, windows 1,2 and 3 are disabled. In the future, we may + * want to use them to do scatter/gather DMA. Window 0 + * goes at 1 GB and is 1 GB large. + */ + + *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE & 0xfff00000U); + *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE - 1) & 0xfff00000U; + *(vuip)PYXIS_T0_BASE = 0; + + *(vuip)PYXIS_W1_BASE = 0x0 ; + *(vuip)PYXIS_W2_BASE = 0x0 ; + *(vuip)PYXIS_W3_BASE = 0x0 ; + mb(); + + /* + * check ASN in HWRPB for validity, report if bad + */ + if (hwrpb->max_asn != MAX_ASN) { + printk("PYXIS_init: max ASN from HWRPB is bad (0x%lx)\n", + hwrpb->max_asn); + hwrpb->max_asn = MAX_ASN; + } + + /* + * Finally, clear the PYXIS_CFG register, which gets used + * for PCI Config Space accesses. That is the way + * we want to use it, and we do not want to depend on + * what ARC or SRM might have left behind... + */ + { + unsigned int pyxis_cfg; + pyxis_cfg = *(vuip)PYXIS_CFG; mb(); +#if 0 + printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg); +#endif + *(vuip)PYXIS_CFG = 0; mb(); + } + + { + unsigned int pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM; + unsigned int pyxis_hae_io = *(vuip)PYXIS_HAE_IO; +#if 0 + printk("PYXIS_init: HAE_MEM was 0x%x\n", pyxis_hae_mem); + printk("PYXIS_init: HAE_IO was 0x%x\n", pyxis_hae_io); +#endif + *(vuip)PYXIS_HAE_MEM = 0; mb(); + pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM; + *(vuip)PYXIS_HAE_IO = 0; mb(); + pyxis_hae_io = *(vuip)PYXIS_HAE_IO; + } + + return mem_start; +} + +int pyxis_pci_clr_err(void) +{ + PYXIS_jd = *(vuip)PYXIS_ERR; + DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd)); + *(vuip)PYXIS_ERR = 0x0180; + mb(); + PYXIS_jd = *(vuip)PYXIS_ERR; + return 0; +} + +void pyxis_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + struct el_common *mchk_header; + struct el_PYXIS_sysdata_mcheck *mchk_sysdata; + + mchk_header = (struct el_common *)la_ptr; + + mchk_sysdata = (struct el_PYXIS_sysdata_mcheck *) + (la_ptr + mchk_header->sys_offset); + +#if 0 + DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset)); + DBG_MCK(("pyxis_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", + PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear)); +#endif +#ifdef DEBUG_MCHECK_DUMP + { + unsigned long *ptr; + int i; + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); + } + } +#endif /* DEBUG_MCHECK_DUMP */ + + /* + * Check if machine check is due to a badaddr() and if so, + * ignore the machine check. + */ + mb(); + if (PYXIS_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) { + DBG(("PYXIS machine check expected\n")); + PYXIS_mcheck_expected = 0; + PYXIS_mcheck_taken = 1; + mb(); + draina(); + pyxis_pci_clr_err(); + wrmces(0x7); + mb(); + } +#if 1 + else { + printk("PYXIS machine check NOT expected\n") ; + DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset)); + PYXIS_mcheck_expected = 0; + PYXIS_mcheck_taken = 1; + mb(); + draina(); + pyxis_pci_clr_err(); + wrmces(0x7); + mb(); + } +#endif +} diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.1.78/linux/arch/alpha/kernel/setup.c Tue May 13 22:41:00 1997 +++ linux/arch/alpha/kernel/setup.c Mon Jan 12 14:51:14 1998 @@ -62,6 +62,18 @@ * code think we're on a VGA color display. */ struct screen_info screen_info = { +#if defined(CONFIG_ALPHA_BOOK1) + /* the AlphaBook1 has LCD video fixed at 800x600, 37 rows and 100 cols */ + 0, 37, /* orig-x, orig-y */ + { 0, 0 }, /* unused */ + 0, /* orig-video-page */ + 0, /* orig-video-mode */ + 100, /* orig-video-cols */ + 0,0,0, /* ega_ax, ega_bx, ega_cx */ + 37, /* orig-video-lines */ + 1, /* orig-video-isVGA */ + 16 /* orig-video-points */ +#else 0, 25, /* orig-x, orig-y */ { 0, 0 }, /* unused */ 0, /* orig-video-page */ @@ -71,6 +83,7 @@ 25, /* orig-video-lines */ 1, /* orig-video-isVGA */ 16 /* orig-video-points */ +#endif }; /* @@ -166,6 +179,10 @@ *memory_start_p = apecs_init(*memory_start_p, *memory_end_p); #elif defined(CONFIG_ALPHA_CIA) *memory_start_p = cia_init(*memory_start_p, *memory_end_p); +#elif defined(CONFIG_ALPHA_PYXIS) + *memory_start_p = pyxis_init(*memory_start_p, *memory_end_p); +#elif defined(CONFIG_ALPHA_T2) + *memory_start_p = t2_init(*memory_start_p, *memory_end_p); #endif } @@ -175,7 +192,8 @@ int get_cpuinfo(char *buffer) { const char *cpu_name[] = { - "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45" + "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45", "EV56", + "EV6", "PCA56" }; # define SYSTYPE_NAME_BIAS 20 const char *systype_name[] = { @@ -185,8 +203,9 @@ "ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen", "Pelican", "8", "Sable", "AXPvme", "Noname", "Turbolaser", "Avanti", "Mustang", "Alcor", "16", - "Mikasa", "18", "EB66", "EB64+", "21", "22", "23", - "24", "25", "EB164" + "Mikasa", "18", "EB66", "EB64+", "AlphaBook1", + "Rawhide", "Lego", "Lynx", "25", "EB164", "Noritake", + "Cortex", "29", "Miata", "31", "Takara", "Yukon" }; struct percpu_struct *cpu; unsigned int cpu_index; diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/t2.c linux/arch/alpha/kernel/t2.c --- v2.1.78/linux/arch/alpha/kernel/t2.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/t2.c Mon Jan 12 14:51:14 1998 @@ -0,0 +1,591 @@ +/* + * Code common to all T2 chips. + * + * Written by Jay A Estabrook (jestabro@amt.tay1.dec.com). + * December 1996. + * + * based on CIA code by David A Rusling (david.rusling@reo.mts.dec.com) + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern struct hwrpb_struct *hwrpb; +extern asmlinkage void wrmces(unsigned long mces); +extern asmlinkage unsigned long whami(void); +extern int alpha_sys_type; + +#define CPUID whami() + + +/* + * Machine check reasons. Defined according to PALcode sources + * (osf.h and platform.h). + */ +#define MCHK_K_TPERR 0x0080 +#define MCHK_K_TCPERR 0x0082 +#define MCHK_K_HERR 0x0084 +#define MCHK_K_ECC_C 0x0086 +#define MCHK_K_ECC_NC 0x0088 +#define MCHK_K_OS_BUGCHECK 0x008A +#define MCHK_K_PAL_BUGCHECK 0x0090 + +/* + * BIOS32-style PCI interface: + */ + +#ifdef DEBUG_CONF +# define DBG(args) printk args +#else +# define DBG(args) +#endif + +#ifdef DEBUG_MCHECK +# define DBGMC(args) printk args +#else +# define DBGMC(args) +#endif + +#define vulp volatile unsigned long * +#define vuip volatile unsigned int * + +static volatile unsigned int T2_mcheck_expected = 0; +static volatile unsigned int T2_mcheck_taken = 0; +static unsigned long T2_jd; + + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address and setup the T2_HAXR2 register + * accordingly. It is therefore not safe to have concurrent + * invocations to configuration space access routines, but there + * really shouldn't be any need for this. + * + * Type 0: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:11 Device select bit. + * 10:8 Function number + * 7:2 Register number + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., scsi and ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ +static int mk_conf_addr(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned long *pci_addr, + unsigned char *type1) +{ + unsigned long addr; + + DBG(("mk_conf_addr(bus=%d, dfn=0x%x, where=0x%x," + " addr=0x%lx, type1=0x%x)\n", + bus, device_fn, where, pci_addr, type1)); + + if (bus == 0) { + int device = device_fn >> 3; + + /* type 0 configuration cycle: */ + + if (device > 8) { + DBG(("mk_conf_addr: device (%d)>20, returning -1\n", + device)); + return -1; + } + + *type1 = 0; + addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where); + } else { + /* type 1 configuration cycle: */ + *type1 = 1; + addr = (bus << 16) | (device_fn << 8) | (where); + } + *pci_addr = addr; + DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + + +static unsigned int conf_read(unsigned long addr, unsigned char type1) +{ + unsigned long flags; + unsigned int stat0, value; + unsigned int t2_cfg = 0; /* to keep gcc quiet */ + + save_flags(flags); /* avoid getting hit by machine check */ + cli(); + + DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); + +#if 0 + /* reset status register to avoid losing errors: */ + stat0 = *(vuip)T2_IOCSR; + *(vuip)T2_IOCSR = stat0; + mb(); + DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0)); + /* if Type1 access, must set T2 CFG */ + if (type1) { + t2_cfg = *(vuip)T2_IOC_CFG; + mb(); + *(vuip)T2_IOC_CFG = t2_cfg | 1; + DBG(("conf_read: TYPE1 access\n")); + } + mb(); + draina(); +#endif + + T2_mcheck_expected = 1; + T2_mcheck_taken = 0; + mb(); + /* access configuration space: */ + value = *(vuip)addr; + mb(); + if (T2_mcheck_taken) { + T2_mcheck_taken = 0; + value = 0xffffffffU; + mb(); + } + T2_mcheck_expected = 0; + mb(); + +#if 0 + /* if Type1 access, must reset IOC CFG so normal IO space ops work */ + if (type1) { + *(vuip)T2_IOC_CFG = t2_cfg & ~1; + mb(); + } +#endif + DBG(("conf_read(): finished\n")); + + restore_flags(flags); + return value; +} + + +static void conf_write(unsigned long addr, unsigned int value, + unsigned char type1) +{ + unsigned long flags; + unsigned int stat0; + unsigned int t2_cfg = 0; /* to keep gcc quiet */ + + save_flags(flags); /* avoid getting hit by machine check */ + cli(); + +#if 0 + /* reset status register to avoid losing errors: */ + stat0 = *(vuip)T2_IOCSR; + *(vuip)T2_IOCSR = stat0; + mb(); + DBG(("conf_write: T2 ERR was 0x%x\n", stat0)); + /* if Type1 access, must set T2 CFG */ + if (type1) { + t2_cfg = *(vuip)T2_IOC_CFG; + mb(); + *(vuip)T2_IOC_CFG = t2_cfg | 1; + DBG(("conf_write: TYPE1 access\n")); + } + draina(); +#endif + + T2_mcheck_expected = 1; + mb(); + /* access configuration space: */ + *(vuip)addr = value; + mb(); + T2_mcheck_expected = 0; + mb(); + +#if 0 + /* if Type1 access, must reset IOC CFG so normal IO space ops work */ + if (type1) { + *(vuip)T2_IOC_CFG = t2_cfg & ~1; + mb(); + } +#endif + DBG(("conf_write(): finished\n")); + restore_flags(flags); +} + + +int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned long addr = T2_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xff; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + + addr |= (pci_addr << 5) + 0x00; + + *value = conf_read(addr, type1) >> ((where & 3) * 8); + + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned long addr = T2_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xffff; + + if (where & 0x1) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { + return PCIBIOS_SUCCESSFUL; + } + + addr |= (pci_addr << 5) + 0x08; + + *value = conf_read(addr, type1) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned long addr = T2_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xffffffff; + if (where & 0x3) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + *value = conf_read(addr, type1); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) +{ + unsigned long addr = T2_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x00; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) +{ + unsigned long addr = T2_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x08; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) +{ + unsigned long addr = T2_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + + +unsigned long t2_init(unsigned long mem_start, unsigned long mem_end) +{ + unsigned int t2_err; + struct percpu_struct *cpu; + int i; + +#if 0 + /* + * Set up error reporting. + */ + t2_err = *(vuip)T2_IOCSR ; + t2_err |= (0x1 << 7) ; /* master abort */ + *(vuip)T2_IOC_T2_ERR = t2_err ; + mb() ; +#endif + + printk("t2_init: HBASE was 0x%lx\n", *(vulp)T2_HBASE); +#if 0 + printk("t2_init: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", + *(vulp)T2_WBASE1, + *(vulp)T2_WMASK1, + *(vulp)T2_TBASE1); + printk("t2_init: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", + *(vulp)T2_WBASE2, + *(vulp)T2_WMASK2, + *(vulp)T2_TBASE2); +#endif + + /* + * Set up the PCI->physical memory translation windows. + * For now, window 2 is disabled. In the future, we may + * want to use it to do scatter/gather DMA. Window 1 + * goes at 1 GB and is 1 GB large. + */ + + /* WARNING!! must correspond to the DMA_WIN params!!! */ + *(vuip)T2_WBASE1 = 0x400807ffU; + *(vuip)T2_WMASK1 = 0x3ff00000U; + *(vuip)T2_TBASE1 = 0; + + *(vuip)T2_WBASE2 = 0x0; + + *(vuip)T2_HBASE = 0x0; + + /* + * check ASN in HWRPB for validity, report if bad + */ + if (hwrpb->max_asn != MAX_ASN) { + printk("T2_init: max ASN from HWRPB is bad (0x%lx)\n", + hwrpb->max_asn); + hwrpb->max_asn = MAX_ASN; + } + + /* + * Finally, clear the T2_HAE_3 register, which gets used + * for PCI Config Space accesses. That is the way + * we want to use it, and we do not want to depend on + * what ARC or SRM might have left behind... + */ + { +#if 0 + printk("T2_init: HAE1 was 0x%lx\n", *(vulp)T2_HAE_1); + printk("T2_init: HAE2 was 0x%lx\n", *(vulp)T2_HAE_2); + printk("T2_init: HAE3 was 0x%lx\n", *(vulp)T2_HAE_3); + printk("T2_init: HAE4 was 0x%lx\n", *(vulp)T2_HAE_4); +#endif +#if 0 + *(vuip)T2_HAE_1 = 0; mb(); + *(vuip)T2_HAE_2 = 0; mb(); + *(vuip)T2_HAE_3 = 0; mb(); + *(vuip)T2_HAE_4 = 0; mb(); +#endif + } + +#if 1 + if (hwrpb->nr_processors > 1) { + printk("T2_init: nr_processors 0x%lx\n", + hwrpb->nr_processors); + printk("T2_init: processor_size 0x%lx\n", + hwrpb->processor_size); + printk("T2_init: processor_offset 0x%lx\n", + hwrpb->processor_offset); + + cpu = (struct percpu_struct *) + ((char*)hwrpb + hwrpb->processor_offset); + + for (i = 0; i < hwrpb->nr_processors; i++ ) { + printk("T2_init: CPU 0x%x: flags 0x%lx type 0x%lx\n", + i, cpu->flags, cpu->type); + cpu = (struct percpu_struct *) + ((char *)cpu + hwrpb->processor_size); + } + } +#endif + + return mem_start; +} + +#define SIC_SEIC (1UL << 33) /* System Event Clear */ + +static struct sable_cpu_csr *sable_cpu_regs[4] = { + (struct sable_cpu_csr *)CPU0_BASE, + (struct sable_cpu_csr *)CPU1_BASE, + (struct sable_cpu_csr *)CPU2_BASE, + (struct sable_cpu_csr *)CPU3_BASE, +}; + +int t2_clear_errors(void) +{ + DBGMC(("???????? t2_clear_errors\n")); + + sable_cpu_regs[CPUID]->sic &= ~SIC_SEIC; + + /* + * clear cpu errors + */ + sable_cpu_regs[CPUID]->bcce |= sable_cpu_regs[CPUID]->bcce; + sable_cpu_regs[CPUID]->cbe |= sable_cpu_regs[CPUID]->cbe; + sable_cpu_regs[CPUID]->bcue |= sable_cpu_regs[CPUID]->bcue; + sable_cpu_regs[CPUID]->dter |= sable_cpu_regs[CPUID]->dter; + + *(vulp)T2_CERR1 |= *(vulp)T2_CERR1; + *(vulp)T2_PERR1 |= *(vulp)T2_PERR1; + + mb(); + return 0; +} + +void t2_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + struct el_t2_logout_header *mchk_header; + struct el_t2_procdata_mcheck *mchk_procdata; + struct el_t2_sysdata_mcheck *mchk_sysdata; + unsigned long * ptr; + const char * reason; + char buf[128]; + long i; + + DBGMC(("t2_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + + mchk_header = (struct el_t2_logout_header *)la_ptr; + + DBGMC(("t2_machine_check: susoffset=0x%lx procoffset=0x%lx\n", + mchk_header->elfl_sysoffset, mchk_header->elfl_procoffset)); + + mchk_sysdata = (struct el_t2_sysdata_mcheck *) + (la_ptr + mchk_header->elfl_sysoffset); + mchk_procdata = (struct el_t2_procdata_mcheck *) + (la_ptr + mchk_header->elfl_procoffset - sizeof(unsigned long)*32); + + DBGMC((" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->elfl_size, mchk_header->elfl_procoffset, + mchk_header->elfl_sysoffset)); + DBGMC(("t2_machine_check: expected %d\n", T2_mcheck_expected)); + +#ifdef DEBUG_DUMP + { + unsigned long *ptr; + int i; + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->elfl_size/sizeof(long); i += 2) { + printk(" +%lx %lx %lx\n", i*sizeof(long), + ptr[i], ptr[i+1]); + } + } +#endif /* DEBUG_DUMP */ + + /* + * Check if machine check is due to a badaddr() and if so, + * ignore the machine check. + */ + mb(); + if (T2_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) { + DBGMC(("T2 machine check expected\n")); + T2_mcheck_taken = 1; + t2_clear_errors(); + T2_mcheck_expected = 0; + mb(); + wrmces(rdmces()|1);/* ??? */ + draina(); + return; + } + + switch ((unsigned int) mchk_header->elfl_error_type) { + case MCHK_K_TPERR: reason = "tag parity error"; break; + case MCHK_K_TCPERR: reason = "tag control parity error"; break; + case MCHK_K_HERR: reason = "generic hard error"; break; + case MCHK_K_ECC_C: reason = "correctable ECC error"; break; + case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break; + case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break; + case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break; + case 0x96: reason = "i-cache read retryable error"; break; + case 0x98: reason = "processor detected hard error"; break; + + /* System specific (these are for Alcor, at least): */ + case 0x203: reason = "system detected uncorrectable ECC error"; break; + case 0x205: reason = "parity error detected by T2"; break; + case 0x207: reason = "non-existent memory error"; break; + case 0x209: reason = "PCI SERR detected"; break; + case 0x20b: reason = "PCI data parity error detected"; break; + case 0x20d: reason = "PCI address parity error detected"; break; + case 0x20f: reason = "PCI master abort error"; break; + case 0x211: reason = "PCI target abort error"; break; + case 0x213: reason = "scatter/gather PTE invalid error"; break; + case 0x215: reason = "flash ROM write error"; break; + case 0x217: reason = "IOA timeout detected"; break; + case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; + case 0x21b: reason = "EISA fail-safe timer timeout"; break; + case 0x21d: reason = "EISA bus time-out"; break; + case 0x21f: reason = "EISA software generated NMI"; break; + case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; + default: + sprintf(buf, "reason for machine-check unknown (0x%x)", + (unsigned int) mchk_header->elfl_error_type); + reason = buf; + break; + } + wrmces(rdmces()|1); /* reset machine check pending flag */ + mb(); + + printk(KERN_CRIT " T2 machine check: %s%s\n", + reason, mchk_header->elfl_retry ? " (retryable)" : ""); + + /* dump the the logout area to give all info: */ + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) { + printk(KERN_CRIT " +%8lx %016lx %016lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); + } +} diff -u --recursive --new-file v2.1.78/linux/arch/alpha/lib/csum_ipv6_magic.S linux/arch/alpha/lib/csum_ipv6_magic.S --- v2.1.78/linux/arch/alpha/lib/csum_ipv6_magic.S Thu Feb 6 02:44:41 1997 +++ linux/arch/alpha/lib/csum_ipv6_magic.S Mon Jan 12 14:49:36 1998 @@ -58,10 +58,14 @@ addq $3,$1,$3 # .. e1 : addq $0,$3,$0 # e0 : unop # : - extwl $0,2,$1 # e0 : + extwl $0,2,$1 # e0 : fold 18-bit value zapnot $0,3,$0 # .. e1 : addq $0,$1,$0 # e0 : - not $0,$0 # e1 : + unop # : + extwl $0,2,$1 # e0 : fold 17-bit value + zapnot $0,3,$0 # .. e1 : + addq $0,$1,$0 # e0 : + not $0,$0 # e1 : and compliment. zapnot $0,3,$0 # e0 : ret # .. e1 : diff -u --recursive --new-file v2.1.78/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.78/linux/arch/i386/defconfig Tue Jan 6 09:37:32 1998 +++ linux/arch/i386/defconfig Mon Jan 12 15:29:37 1998 @@ -84,7 +84,6 @@ # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set -# CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -267,7 +266,6 @@ # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set # CONFIG_VIDEO_BT848 is not set -# CONFIG_VIDEO_BWQCAM is not set # CONFIG_VIDEO_PMS is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set diff -u --recursive --new-file v2.1.78/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.78/linux/arch/i386/kernel/entry.S Tue Dec 2 16:45:17 1997 +++ linux/arch/i386/kernel/entry.S Sat Jan 10 11:57:29 1998 @@ -71,13 +71,10 @@ * these are offsets into the task-struct. */ state = 0 -counter = 4 -priority = 8 -flags = 12 -sigpending = 16 -dbgreg6 = 44 -dbgreg7 = 48 -exec_domain = 52 +flags = 4 +sigpending = 8 +addr_limit = 12 +exec_domain = 16 ENOSYS = 38 diff -u --recursive --new-file v2.1.78/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.1.78/linux/arch/i386/kernel/i386_ksyms.c Sun Dec 21 22:36:12 1997 +++ linux/arch/i386/kernel/i386_ksyms.c Sat Jan 10 18:04:59 1998 @@ -47,6 +47,20 @@ EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL_NOVERS(__get_user_1); +EXPORT_SYMBOL_NOVERS(__get_user_2); +EXPORT_SYMBOL_NOVERS(__get_user_4); +EXPORT_SYMBOL_NOVERS(__put_user_1); +EXPORT_SYMBOL_NOVERS(__put_user_2); +EXPORT_SYMBOL_NOVERS(__put_user_4); + +EXPORT_SYMBOL(strncpy_from_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(clear_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(__generic_copy_from_user); +EXPORT_SYMBOL(__generic_copy_to_user); +EXPORT_SYMBOL(strlen_user); #ifdef __SMP__ EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */ @@ -79,3 +93,4 @@ EXPORT_SYMBOL(mca_isenabled); EXPORT_SYMBOL(mca_isadapter); #endif + diff -u --recursive --new-file v2.1.78/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.78/linux/arch/i386/kernel/smp.c Fri Jan 2 14:37:01 1998 +++ linux/arch/i386/kernel/smp.c Mon Jan 12 14:47:46 1998 @@ -55,7 +55,7 @@ extern unsigned long start_kernel, _etext; extern void update_one_process( struct task_struct *p, unsigned long ticks, unsigned long user, - unsigned long system); + unsigned long system, int cpu); /* * Some notes on processor bugs: * @@ -1346,8 +1346,7 @@ irq_enter(cpu, 0); if (p->pid) { - - update_one_process(p, 1, user, system); + update_one_process(p, 1, user, system, cpu); p->counter -= 1; if (p->counter < 0) { @@ -1360,6 +1359,7 @@ kstat.cpu_user += user; kstat.cpu_system += system; + kstat.per_cpu_system[cpu] += system; } else { #ifdef __SMP_PROF__ @@ -1382,7 +1382,7 @@ * we might want to decouple profiling from the 'long path', * and do the profiling totally in assembly. * - * Currently this isnt too much of an issue (performancewise), + * Currently this isnt too much of an issue (performance wise), * we can take more than 100K local irqs per second on a 100 MHz P5. */ } diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.1.78/linux/arch/i386/lib/Makefile Sat Nov 29 11:25:09 1997 +++ linux/arch/i386/lib/Makefile Sat Jan 10 14:51:20 1998 @@ -11,6 +11,6 @@ endif L_TARGET = lib.a -L_OBJS = checksum.o semaphore.o locks.o delay.o +L_OBJS = checksum.o semaphore.o locks.o delay.o usercopy.o getuser.o putuser.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/getuser.S linux/arch/i386/lib/getuser.S --- v2.1.78/linux/arch/i386/lib/getuser.S Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/getuser.S Mon Jan 12 13:42:52 1998 @@ -0,0 +1,73 @@ +/* + * __get_user functions. + * + * (C) Copyright 1998 Linus Torvalds + * + * These functions have a non-standard call interface + * to make them more efficient, especially as they + * return an error value in addition to the "real" + * return value. + */ + +/* + * __get_user_X + * + * Inputs: %eax contains the address + * + * Outputs: %eax is error code (0 or -EFAULT) + * %edx contains zero-extended value + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +addr_limit = 12 + +.text +.align 4 +.globl __get_user_1 +__get_user_1: + movl %esp,%edx + andl $0xffffe000,%edx + cmpl addr_limit(%edx),%eax + jae bad_get_user +1: movzbl (%eax),%edx + xorl %eax,%eax + ret + +.align 4 +.globl __get_user_2 +__get_user_2: + addl $1,%eax + movl %esp,%edx + jc bad_get_user + andl $0xffffe000,%edx + cmpl addr_limit(%edx),%eax + jae bad_get_user +2: movzwl -1(%eax),%edx + xorl %eax,%eax + ret + +.align 4 +.globl __get_user_4 +__get_user_4: + addl $3,%eax + movl %esp,%edx + jc bad_get_user + andl $0xffffe000,%edx + cmpl addr_limit(%edx),%eax + jae bad_get_user +3: movl -3(%eax),%edx + xorl %eax,%eax + ret + +bad_get_user: + xorl %edx,%edx + movl $-14,%eax + ret + +.section __ex_table,"a" + .long 1b,bad_get_user + .long 2b,bad_get_user + .long 3b,bad_get_user +.previous diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/putuser.S linux/arch/i386/lib/putuser.S --- v2.1.78/linux/arch/i386/lib/putuser.S Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/putuser.S Mon Jan 12 13:37:26 1998 @@ -0,0 +1,71 @@ +/* + * __put_user functions. + * + * (C) Copyright 1998 Linus Torvalds + * + * These functions have a non-standard call interface + * to make them more efficient. + */ + +/* + * __put_user_X + * + * Inputs: %eax contains the address + * %edx contains the value + * + * Outputs: %eax is error code (0 or -EFAULT) + * %ecx is corrupted (will contain "current_task"). + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +addr_limit = 12 + +.text +.align 4 +.globl __put_user_1 +__put_user_1: + movl %esp,%ecx + andl $0xffffe000,%ecx + cmpl addr_limit(%ecx),%eax + jae bad_put_user +1: movb %dl,(%eax) + xorl %eax,%eax + ret + +.align 4 +.globl __put_user_2 +__put_user_2: + addl $1,%eax + movl %esp,%ecx + jc bad_put_user + andl $0xffffe000,%ecx + cmpl addr_limit(%ecx),%eax + jae bad_put_user +2: movw %dx,-1(%eax) + xorl %eax,%eax + ret + +.align 4 +.globl __put_user_4 +__put_user_4: + addl $3,%eax + movl %esp,%ecx + jc bad_put_user + andl $0xffffe000,%ecx + cmpl addr_limit(%ecx),%eax + jae bad_put_user +3: movl %edx,-3(%eax) + xorl %eax,%eax + ret + +bad_put_user: + movl $-14,%eax + ret + +.section __ex_table,"a" + .long 1b,bad_put_user + .long 2b,bad_put_user + .long 3b,bad_put_user +.previous diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c --- v2.1.78/linux/arch/i386/lib/usercopy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/usercopy.c Sat Jan 10 21:28:41 1998 @@ -0,0 +1,136 @@ +/* + * User address space access functions. + * The non inlined parts of asm-i386/uaccess.h are here. + * + * Copyright 1997 Andi Kleen + * Copyright 1997 Linus Torvalds + */ +#include + +inline unsigned long +__generic_copy_to_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __copy_user(to,from,n); + return n; +} + +inline unsigned long +__generic_copy_from_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_READ, from, n)) + __copy_user(to,from,n); + return n; +} + + +/* + * Copy a null terminated string from userspace. + */ + +#define __do_strncpy_from_user(dst,src,count,res) \ + __asm__ __volatile__( \ + " testl %1,%1\n" \ + " jz 2f\n" \ + "0: lodsb\n" \ + " stosb\n" \ + " testb %%al,%%al\n" \ + " jz 1f\n" \ + " decl %1\n" \ + " jnz 0b\n" \ + "1: subl %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %2,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=d"(res), "=c"(count) \ + : "i"(-EFAULT), "0"(count), "1"(count), "S"(src), "D"(dst) \ + : "si", "di", "ax", "memory") + +long +__strncpy_from_user(char *dst, const char *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +long +strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + + +/* + * Zero Userspace + */ + +#define __do_clear_user(addr,size) \ + __asm__ __volatile__( \ + "0: rep; stosl\n" \ + " movl %1,%0\n" \ + "1: rep; stosb\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: lea 0(%1,%0,4),%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,3b\n" \ + " .long 1b,2b\n" \ + ".previous" \ + : "=c"(size) \ + : "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0) \ + : "di") + +unsigned long +clear_user(void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __do_clear_user(to, n); + return n; +} + +unsigned long +__clear_user(void *to, unsigned long n) +{ + __do_clear_user(to, n); + return n; +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 for error + */ + +long strlen_user(const char *s) +{ + unsigned long res; + + __asm__ __volatile__( + "0: repne; scasb\n" + " notl %0\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: xorl %0,%0\n" + " jmp 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,2b\n" + ".previous" + :"=c" (res), "=D" (s) + :"1" (s), "a" (0), "0" (-__addr_ok(s))); + return res & -__addr_ok(s); +} diff -u --recursive --new-file v2.1.78/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.78/linux/arch/i386/mm/fault.c Sun Dec 21 22:36:12 1997 +++ linux/arch/i386/mm/fault.c Wed Jan 7 12:04:52 1998 @@ -192,11 +192,6 @@ /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { - printk(KERN_DEBUG "%s: Exception at [<%lx>] cr2=%lx (fixup: %lx)\n", - tsk->comm, - regs->eip, - address, - fixup); regs->eip = fixup; goto out; } diff -u --recursive --new-file v2.1.78/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.1.78/linux/arch/i386/mm/init.c Fri Jan 2 14:37:01 1998 +++ linux/arch/i386/mm/init.c Mon Jan 12 14:33:20 1998 @@ -72,7 +72,7 @@ void show_mem(void) { int i,free = 0,total = 0,reserved = 0; - int shared = 0; + int shared = 0, cached = 0; printk("Mem-info:\n"); show_free_areas(); @@ -82,6 +82,8 @@ total++; if (PageReserved(mem_map+i)) reserved++; + if (PageSwapCache(mem_map+i)) + cached++; else if (!atomic_read(&mem_map[i].count)) free++; else @@ -91,6 +93,7 @@ printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); show_buffers(); #ifdef CONFIG_NET show_net_buffers(); diff -u --recursive --new-file v2.1.78/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.1.78/linux/arch/mips/kernel/irixelf.c Fri Dec 19 15:52:51 1997 +++ linux/arch/mips/kernel/irixelf.c Mon Jan 12 14:52:46 1998 @@ -691,7 +691,6 @@ /* OK, This is the point of no return */ current->mm->end_data = 0; current->mm->end_code = 0; - current->mm->start_mmap = ELF_START_MMAP; current->mm->mmap = NULL; elf_entry = (unsigned int) elf_ex.e_entry; diff -u --recursive --new-file v2.1.78/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.1.78/linux/arch/ppc/Makefile Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/Makefile Mon Jan 12 15:18:12 1998 @@ -12,10 +12,13 @@ # Rewritten by Cort Dougan and Paul Mackerras # -ifeq ($(CONFIG_PMAC),y) -KERNELBASE =0xc0000000 -else +ifdef CONFIG_CHRP +# XXX for now KERNELBASE =0x90000000 +KERNELLOAD =0x90010000 +else +KERNELBASE =0xc0000000 +KERNELLOAD =0xc0000000 endif # PowerPC (cross) tools @@ -26,10 +29,11 @@ endif ASFLAGS = -LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELBASE) -Bstatic +LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__ CFLAGS := $(CFLAGS) -D__powerpc__ -fsigned-char -msoft-float -pipe \ - -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring + -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring \ + -DKERNELBASE=$(KERNELBASE) CPP = $(CC) -E $(CFLAGS) ifdef CONFIG_601 @@ -56,30 +60,39 @@ CORE_FILES += arch/ppc/xmon/x.o endif -ifdef CONFIG_PMAC -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/coffboot -else -# PReP and CHRP systems MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -endif +MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot +MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot checks: @$(MAKE) -C arch/$(ARCH)/kernel checks BOOT_TARGETS = netboot znetboot zImage floppy install \ - vmlinux.coff znetboot.initrd zImage.initrd + vmlinux.coff znetboot.initrd zImage.initrd vmlinux.coff.initrd $(BOOT_TARGETS): $(CHECKS) vmlinux + @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ + @$(MAKECHRPBOOT) $@ + +pmac_config: + rm -f .config arch/ppc/defconfig + ln -s pmac_defconfig arch/ppc/defconfig + +prep_config: + rm -f .config arch/ppc/defconfig + ln -s prep_defconfig arch/ppc/defconfig tags: etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h} archclean: - rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h - rm -f arch/ppc/kernel/checks + rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks} + @$(MAKECOFFBOOT) clean @$(MAKEBOOT) clean + @$(MAKECHRPBOOT) clean archdep: $(MAKEBOOT) fastdep + $(MAKECHRPBOOT) fastdep diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile --- v2.1.78/linux/arch/ppc/boot/Makefile Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/boot/Makefile Mon Jan 12 15:18:12 1998 @@ -9,94 +9,118 @@ # Adapted for PowerPC by Gary Thomas # modified by Cort (cort@cs.nmt.edu) # - .c.s: $(CC) $(CFLAGS) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: - $(CC) $(CFLAGS) -c -o $*.o $< + $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< .S.s: $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< .S.o: $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000 +ZOFF = 0 +ZSZ = 0 +IOFF = 0 +ISZ = 0 +#ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000 +ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00600000 GZIP_FLAGS = -v9 -SYSTEM = $(TOPDIR)/vmlinux -OBJECTS := head.o inflate.o unzip.o misc.o vreset.o kbd.o -CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include +OBJECTS := head.o misc.o vreset.o kbd.o ../coffboot/zlib.o # inflate.o unzip.o +#OBJECTS := crt0.o start.o vreset.o +CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O elf32-powerpc +all: zImage -all: $(TOPDIR)/zImage +ifeq ($(CONFIG_PREP),y) mkprep : mkprep.c - $(HOSTCC) $(CFLAGSINC) -o mkprep mkprep.c - -piggyback : piggyback.c - $(HOSTCC) $(CFLAGSINC) -o piggyback piggyback.c - -find_name : find_name.c - $(HOSTCC) $(CFLAGSINC) -o find_name find_name.c - -floppy: $(TOPDIR)/vmlinux zImage - dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b + $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c -floppy.initrd: $(TOPDIR)/vmlinux zImage - dd if=$(TOPDIR)/zImage.initrd of=/dev/fd0H1440 bs=64b +floppy: $(TOPDIR)/vmlinux zImage + dd if=zImage of=/dev/fd0H1440 bs=64b -znetboot : zImage mkprep - cp $(TOPDIR)/zImage /usr/local/tftpboot/vmlinux +znetboot : zImage + cp zImage /tftpboot/zImage.prep -znetboot.initrd : zImage.initrd mkprep - cp $(TOPDIR)/zImage.initrd /usr/local/tftpboot/vmlinux +znetboot.initrd : zImage.initrd + cp zImage.initrd /tftpboot/zImage.prep +zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz # -# This really needs to go away. Perhaps a -# zImage.prep and zImage.chrp might be better. -# Once we're able to get a lilo-ish program -# on prep systems this won't be a problem. -# -- Cort +# build the boot loader image and then compute the offset into it +# for the kernel image # -ifdef CONFIG_CHRP -zImage: zvmlinux - cp zvmlinux $(TOPDIR)/zImage - -zImage.initrd: zvmlinux.initrd - cp zvmlinux.initrd $(TOPDIR)/zImage.initrd - -zvmlinux: $(OBJECTS) $(SYSTEM) find_name vmlinux.gz piggyback - ./piggyback < vmlinux.gz | $(AS) -o piggy.o - $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) piggy.o - rm -f piggy.o -else + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`./offset zvmlinux image` \ + -DZIMAGE_SIZE=`./size zvmlinux image` -DKERNELBASE=$(KERNELBASE) \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.tmp $@ + rm zvmlinux.tmp + +zvmlinux.initrd: zvmlinux + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=ramdisk.image.gz \ + --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.initrd.tmp zvmlinux.initrd + $(CC) $(CFLAGS) -DINITRD_OFFSET=`./offset zvmlinux.initrd initrd` \ + -DINITRD_SIZE=`./size zvmlinux.initrd initrd` \ + -DZIMAGE_OFFSET=`./offset zvmlinux.initrd image` \ + -DZIMAGE_SIZE=`./size zvmlinux.initrd image` \ + -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=ramdisk.image.gz \ + --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.initrd.tmp $@ + rm zvmlinux.initrd.tmp + zImage: zvmlinux mkprep - mkprep -pbp zvmlinux $(TOPDIR)/zImage + ./mkprep -pbp zvmlinux zImage zImage.initrd: zvmlinux.initrd mkprep - mkprep -pbp zvmlinux.initrd $(TOPDIR)/zImage.initrd + ./mkprep -pbp zvmlinux.initrd zImage.initrd +else +mkprep: -zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name vmlinux.gz - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \ - zvmlinux.tmp $@ - rm zvmlinux.tmp +floppy: + +znetboot: + +znetboot.initrd: + +zvmlinux: + +zvmlinux.initrd: + +zImage: + +zImage.initrd: endif -vmlinux.gz: $(TOPDIR)/vmlinux - dd bs=64k skip=1 if=$(TOPDIR)/vmlinux | gzip -vf9 - > vmlinux.gz -zvmlinux.initrd: zvmlinux - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \ - zvmlinux $@ + +# just here to match coffboot/Makefile +vmlinux.coff: + +vmlinux.coff.initrd: clean: - rm -f vmlinux* znetboot* zImage* zvmlinux* mkprep find_name - rm -f $(TOPDIR)/{zImage*,znetboot*,zvmlinux*,vmlinux*} + rm -f vmlinux* zvmlinux* mkprep zImage* fastdep: $(TOPDIR)/scripts/mkdep *.[Sch] > .depend diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/crypt.h linux/arch/ppc/boot/crypt.h --- v2.1.78/linux/arch/ppc/boot/crypt.h Wed Dec 18 00:49:52 1996 +++ linux/arch/ppc/boot/crypt.h Wed Dec 31 16:00:00 1969 @@ -1,12 +0,0 @@ -/* crypt.h (dummy version) -- do not perform encryption - * Hardly worth copyrighting :-) - */ - -#ifdef CRYPT -# undef CRYPT /* dummy version */ -#endif - -#define RAND_HEAD_LEN 12 /* length of encryption random header */ - -#define zencode -#define zdecode diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/find_name.c linux/arch/ppc/boot/find_name.c --- v2.1.78/linux/arch/ppc/boot/find_name.c Mon Aug 4 16:25:36 1997 +++ linux/arch/ppc/boot/find_name.c Wed Dec 31 16:00:00 1969 @@ -1,47 +0,0 @@ -#include -#include -#include -/* - * Finds a given address in the System.map and prints it out - * with its neighbors. -- Cort - */ - -void main(int argc, char **argv) -{ - unsigned long addr, cmp, i; - FILE *f; - char *ptr; - char s[256], last[256]; - - if ( argc < 2 ) - { - fprintf(stderr, "Usage: %s
\n", argv[0]); - exit(-1); - } - - for ( i = 1 ; argv[i] ; i++ ) - { - sscanf( argv[i], "%0x", &addr ); - /* adjust if addr is relative to kernelbase */ - if ( addr < PAGE_OFFSET ) - addr += PAGE_OFFSET; - - if ( (f = fopen( "System.map", "r" )) == NULL ) - { - perror("fopen()\n"); - exit(-1); - } - - while ( !feof(f) ) - { - fgets(s, 255 , f); - sscanf( s, "%0x", &cmp ); - if ( addr < cmp ) - break; - strcpy( last, s); - } - - printf( "%s", last); - } - fclose(f); -} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/gzip.h linux/arch/ppc/boot/gzip.h --- v2.1.78/linux/arch/ppc/boot/gzip.h Mon Aug 4 16:25:36 1997 +++ linux/arch/ppc/boot/gzip.h Wed Dec 31 16:00:00 1969 @@ -1,284 +0,0 @@ -/* gzip.h -- common declarations for all gzip modules - * Copyright (C) 1992-1993 Jean-loup Gailly. - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -#if defined(__STDC__) || defined(PROTO) -# define OF(args) args -#else -# define OF(args) () -#endif - -#ifdef __STDC__ - typedef void *voidp; -#else - typedef char *voidp; -#endif - -/* I don't like nested includes, but the string functions are used too often */ -#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) -# include -# define memzero(s, n) memset ((s), 0, (n)) -#else -# include -# define strchr index -# define strrchr rindex -# define memcpy(d, s, n) bcopy((s), (d), (n)) -# define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) -# define memzero(s, n) bzero((s), (n)) -#endif - -#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) -# include -#endif - -#ifndef RETSIGTYPE -# define RETSIGTYPE void -#endif - -#define local static - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -/* Return codes from gzip */ -#define OK 0 -#define ERROR 1 -#define WARNING 2 - -/* Compression methods (see algorithm.doc) */ -#define STORED 0 -#define COMPRESSED 1 -#define PACKED 2 -/* methods 3 to 7 reserved */ -#define DEFLATED 8 -extern int method; /* compression method */ - -/* To save memory for 16 bit systems, some arrays are overlayed between - * the various modules: - * deflate: prev+head window d_buf l_buf outbuf - * unlzw: tab_prefix tab_suffix stack inbuf outbuf - * inflate: window inbuf - * unpack: window inbuf - * For compression, input is done in window[]. For decompression, output - * is done in window except for unlzw. - */ - -#ifndef INBUFSIZ -# define INBUFSIZ 0x8000 /* input buffer size */ -#endif -#define INBUF_EXTRA 64 /* required by unlzw() */ - -#ifndef OUTBUFSIZ -# define OUTBUFSIZ 16384 /* output buffer size */ -#endif -#define OUTBUF_EXTRA 2048 /* required by unlzw() */ - -#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ - -#ifdef DYN_ALLOC -# define EXTERN(type, array) extern type * near array -# define DECLARE(type, array, size) type * near array -# define ALLOC(type, array, size) { \ - array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \ - if (array == NULL) error("insufficient memory"); \ - } -# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;} -#else -# define EXTERN(type, array) extern type array[] -# define DECLARE(type, array, size) type array[size] -# define ALLOC(type, array, size) -# define FREE(array) -#endif - -EXTERN(uch, inbuf); /* input buffer */ -EXTERN(uch, outbuf); /* output buffer */ -EXTERN(ush, d_buf); /* buffer for distances, see trees.c */ -EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */ -#define tab_suffix window -#ifndef MAXSEG_64K -# define tab_prefix prev /* hash link (see deflate.c) */ -# define head (prev+WSIZE) /* hash head (see deflate.c) */ - EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */ -#else -# define tab_prefix0 prev -# define head tab_prefix1 - EXTERN(ush, tab_prefix0); /* prefix for even codes */ - EXTERN(ush, tab_prefix1); /* prefix for odd codes */ -#endif - -extern unsigned insize; /* valid bytes in inbuf */ -extern unsigned inptr; /* index of next byte to be processed in inbuf */ -extern unsigned outcnt; /* bytes in output buffer */ - -extern long bytes_in; /* number of input bytes */ -extern long bytes_out; /* number of output bytes */ -extern long overhead; /* number of bytes in gzip header */ - -#define isize bytes_in -/* for compatibility with old zip sources (to be cleaned) */ - -extern int ifd; /* input file descriptor */ -extern int ofd; /* output file descriptor */ -extern char ifname[]; /* input filename or "stdin" */ -extern char ofname[]; /* output filename or "stdout" */ - -extern ulg time_stamp; /* original time stamp (modification time) */ -extern long ifile_size; /* input file size, -1 for devices (debug only) */ - -extern int exit_code; /* program exit code */ - -typedef int file_t; /* Do not use stdio */ -#define NO_FILE (-1) /* in memory compression */ - - -#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ -#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ -#define PKZIP_MAGIC "PK\003\004" /* Magic header for pkzip files */ -#define PACK_MAGIC "\037\036" /* Magic header for packed files */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ -#define RESERVED 0xC0 /* bit 6,7: reserved */ - -/* internal file attribute */ -#define UNKNOWN (-1) -#define BINARY 0 -#define ASCII 1 - -#ifndef WSIZE -# define WSIZE 0x8000 /* window size--must be a power of two, and */ -#endif /* at least 32K for zip's deflate method */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - -extern int decrypt; /* flag to turn on decryption */ -extern int save_orig_name; /* set if original name must be saved */ -extern int verbose; /* be verbose (-v) */ -extern int level; /* compression level */ -extern int test; /* check .z file integrity */ -extern int to_stdout; /* output to stdout (-c) */ - -#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) - -/* put_byte is used for the compressed output, put_char for the - * uncompressed output. However unlzw() uses window for its - * suffix table instead of its output buffer, so it does not use put_char. - * (to be cleaned up). - */ -#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ - flush_outbuf();} -#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\ - flush_window();} - -/* Output a 16 bit value, lsb first */ -#define put_short(w) \ -{ if (outcnt < OUTBUFSIZ-2) { \ - outbuf[outcnt++] = (uch) ((w) & 0xff); \ - outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \ - } else { \ - put_byte((uch)((w) & 0xff)); \ - put_byte((uch)((ush)(w) >> 8)); \ - } \ -} - -/* Output a 32 bit value to the bit stream, lsb first */ -#define put_long(n) { \ - put_short((n) & 0xffff); \ - put_short(((ulg)(n)) >> 16); \ -} - -#define seekable() 0 /* force sequential output */ -#define translate_eol 0 /* no option -a yet */ - -#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */ - -/* Macros for getting two-byte and four-byte header values */ -#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) -#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) - -/* Diagnostic functions */ -#ifdef DEBUG -# define Assert(cond,msg) {if(!(cond)) error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - /* in zip.c: */ -extern void zip OF((int in, int out)); -extern int file_read OF((char *buf, unsigned size)); - - /* in unzip.c */ -extern void unzip OF((int in, int out)); -extern int check_zipfile OF((int in)); - - /* in unpack.c */ -extern void unpack OF((int in, int out)); - - /* in gzip.c */ -RETSIGTYPE abort_gzip OF((void)); - - /* in deflate.c */ -void lm_init OF((int pack_level, ush *flags)); -ulg deflate OF((void)); - - /* in trees.c */ -void ct_init OF((ush *attr, int *method)); -int ct_tally OF((int dist, int lc)); -ulg flush_block OF((char *buf, ulg stored_len, int eof)); - - /* in bits.c */ -void bi_init OF((file_t zipfile)); -void send_bits OF((int value, int length)); -unsigned bi_reverse OF((unsigned value, int length)); -void bi_windup OF((void)); -void copy_block OF((char *buf, unsigned len, int header)); -extern int (*read_buf) OF((char *buf, unsigned size)); - - /* in util.c: */ -extern ulg updcrc OF((uch *s, unsigned n)); -extern void clear_bufs OF((void)); -extern int fill_inbuf OF((void)); -extern void flush_outbuf OF((void)); -extern void flush_window OF((void)); -extern char *strlwr OF((char *s)); -/*extern char *basename OF((char *fname));*/ -extern char *add_envopt OF((int *argcp, char ***argvp, char *env)); -extern void error OF((char *m)); -extern void warn OF((char *a, char *b)); -extern void read_error OF((void)); -extern void write_error OF((void)); -extern void display_ratio OF((long num, long den)); -extern voidp xmalloc OF((unsigned int size)); - - /* in inflate.c */ -extern int inflate OF((void)); diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S --- v2.1.78/linux/arch/ppc/boot/head.S Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/boot/head.S Mon Jan 12 15:18:12 1998 @@ -46,8 +46,13 @@ mr r8,r3 lis r4,start@h ori r4,r4,start@l +#if 0 lis r5,edata@h ori r5,r5,edata@l +#else + lis r5,end@h + ori r5,r5,end@l +#endif addi r5,r5,3 /* Round up - just in case */ sub r5,r5,r4 /* Compute # longwords to move */ srwi r5,r5,2 diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/inflate.c linux/arch/ppc/boot/inflate.c --- v2.1.78/linux/arch/ppc/boot/inflate.c Mon Aug 4 16:25:36 1997 +++ linux/arch/ppc/boot/inflate.c Wed Dec 31 16:00:00 1969 @@ -1,810 +0,0 @@ -#define DEBG(x) -#define DEBG1(x) -/* inflate.c -- Not copyrighted 1992 by Mark Adler - version c10p1, 10 January 1993 */ - -/* - * Adapted for booting Linux by Hannu Savolainen 1993 - * based on gzip-1.0.3 - */ - -#ifndef lint -static char rcsid[] = "$Id: inflate.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $"; -#endif - -#include "gzip.h" -#define slide window - -#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) -# include -# include -#endif - -struct huft { - uch e; /* number of extra bits or operation */ - uch b; /* number of bits in this code or subcode */ - union { - ush n; /* literal, length base, or distance base */ - struct huft *t; /* pointer to next level of table */ - } v; -}; - - -/* Function prototypes */ -int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *, - struct huft **, int *)); -int huft_free OF((struct huft *)); -int inflate_codes OF((struct huft *, struct huft *, int, int)); -int inflate_stored OF((void)); -int inflate_fixed OF((void)); -int inflate_dynamic OF((void)); -int inflate_block OF((int *)); -int inflate OF((void)); - - -#define wp outcnt -#define flush_output(w) (wp=(w),flush_window()) - -/* Tables for deflate from PKZIP's appnote.txt. */ -static unsigned border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; -static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* note: see note #13 above about the 258 in this list. */ -static ush cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ -static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -static ush cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - - -ulg bb; /* bit buffer */ -unsigned bk; /* bits in bit buffer */ - -ush mask_bits[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -#ifdef CRYPT - uch cc; -# define NEXTBYTE() \ - (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte()) -#else -# define NEXTBYTE() (uch)get_byte() -#endif -#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} - -int lbits = 9; /* bits in base literal/length lookup table */ -int dbits = 6; /* bits in base distance lookup table */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ -#define BMAX 16 /* maximum bit length of any code (16 for explode) */ -#define N_MAX 288 /* maximum number of codes in any set */ - - -unsigned hufts; /* track memory usage */ - - -int huft_build(b, n, s, d, e, t, m) -unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ -unsigned n; /* number of codes (assumed <= N_MAX) */ -unsigned s; /* number of simple-valued codes (0..s-1) */ -ush *d; /* list of base values for non-simple codes */ -ush *e; /* list of extra bits for non-simple codes */ -struct huft **t; /* result: starting table */ -int *m; /* maximum lookup bits, returns actual */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return zero on success, one if - the given code set is incomplete (the tables are still built in this - case), two if the input is invalid (all zero length codes or an - oversubscribed set of lengths), and three if not enough memory. */ -{ - unsigned a; /* counter for codes of length k */ - unsigned c[BMAX+1]; /* bit length count table */ - unsigned f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register unsigned i; /* counter, current code */ - register unsigned j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register unsigned *p; /* pointer into c[], b[], or v[] */ - register struct huft *q; /* points to current table */ - struct huft r; /* table entry for structure assignment */ - struct huft *u[BMAX]; /* table stack */ - unsigned v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - unsigned x[BMAX+1]; /* bit offsets, then code stack */ - unsigned *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - unsigned z; /* number of entries in current table */ - -DEBG("huft1 "); - - /* Generate counts for each bit length */ - memzero(c, sizeof(c)); - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (struct huft *)NULL; - *m = 0; - return 0; - } - -DEBG("huft2 "); - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((unsigned)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((unsigned)l > i) - l = i; - *m = l; - -DEBG("huft3 "); - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return 2; /* bad input: more codes than bits */ - if ((y -= c[i]) < 0) - return 2; - c[i] += y; - -DEBG("huft4 "); - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - -DEBG("huft5 "); - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - -DEBG("h6 "); - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (struct huft *)NULL; /* just to keep compilers happy */ - q = (struct huft *)NULL; /* ditto */ - z = 0; /* ditto */ -DEBG("h6a "); - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { -DEBG("h6b "); - a = c[k]; - while (a--) - { -DEBG("h6b1 "); - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { -DEBG1("1 "); - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ -DEBG1("2 "); - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } -DEBG1("3 "); - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - q = (struct huft *)malloc((z + 1)*sizeof(struct huft)); -DEBG1("4 "); - hufts += z + 1; /* track memory usage */ - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->v.t)) = (struct huft *)NULL; - u[h] = ++q; /* table starts after link */ - -DEBG1("5 "); - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.b = (uch)l; /* bits to dump before this table */ - r.e = (uch)(16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h-1][j] = r; /* connect to last table */ - } -DEBG1("6 "); - } -DEBG("h6c "); - - /* set up table entry in r */ - r.b = (uch)(k - w); - if (p >= v + n) - r.e = 99; /* out of values--invalid code */ - else if (*p < s) - { - r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ - r.v.n = *p++; /* simple code is just the value */ - } - else - { - r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } -DEBG("h6d "); - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - } -DEBG("h6e "); - } -DEBG("h6f "); - } - -DEBG("huft7 "); - - /* Return true (1) if we were given an incomplete table */ - return y != 0 && g != 1; -} - - - -int huft_free(t) -struct huft *t; /* table to free */ -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register struct huft *p, *q; - - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != (struct huft *)NULL) - { - q = (--p)->v.t; - free(p); - p = q; - } - return 0; -} - - -int inflate_codes(tl, td, bl, bd) -struct huft *tl, *td; /* literal/length and distance decoder tables */ -int bl, bd; /* number of bits decoded by tl[] and td[] */ -/* inflate (decompress) the codes in a deflated (compressed) block. - Return an error code or zero if it all goes ok. */ -{ - register unsigned e; /* table entry flag/number of extra bits */ - unsigned n, d; /* length and index for copy */ - unsigned w; /* current window position */ - struct huft *t; /* pointer to table entry */ - unsigned ml, md; /* masks for bl and bd bits */ - register ulg b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - - - /* make local copies of globals */ - b = bb; /* initialize bit buffer */ - k = bk; - w = wp; /* initialize window position */ - - /* inflate the coded data */ - ml = mask_bits[bl]; /* precompute masks for speed */ - md = mask_bits[bd]; - for (;;) /* do until end of block */ - { - NEEDBITS((unsigned)bl) - if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) - do { - if (e == 99) - return 1; - DUMPBITS(t->b) - e -= 16; - NEEDBITS(e) - } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); - DUMPBITS(t->b) - if (e == 16) /* then it's a literal */ - { - slide[w++] = (uch)t->v.n; - if (w == WSIZE) - { - flush_output(w); - w = 0; - } - } - else /* it's an EOB or a length */ - { - /* exit if end of block */ - if (e == 15) - break; - - /* get length of block to copy */ - NEEDBITS(e) - n = t->v.n + ((unsigned)b & mask_bits[e]); - DUMPBITS(e); - - /* decode distance of block to copy */ - NEEDBITS((unsigned)bd) - if ((e = (t = td + ((unsigned)b & md))->e) > 16) - do { - if (e == 99) - return 1; - DUMPBITS(t->b) - e -= 16; - NEEDBITS(e) - } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); - DUMPBITS(t->b) - NEEDBITS(e) - d = w - t->v.n - ((unsigned)b & mask_bits[e]); - DUMPBITS(e) - - /* do the copy */ - do { - n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); -#if !defined(NOMEMCPY) && !defined(DEBUG) - if (w - d >= e) /* (this test assumes unsigned comparison) */ - { - memcpy(slide + w, slide + d, e); - w += e; - d += e; - } - else /* do it slow to avoid memcpy() overlap */ -#endif /* !NOMEMCPY */ - do { - slide[w++] = slide[d++]; - } while (--e); - if (w == WSIZE) - { - flush_output(w); - w = 0; - } - } while (n); - } - } - - - /* restore the globals from the locals */ - wp = w; /* restore global window pointer */ - bb = b; /* restore global bit buffer */ - bk = k; - - /* done */ - return 0; -} - - - -int inflate_stored() -/* "decompress" an inflated type 0 (stored) block. */ -{ - unsigned n; /* number of bytes in block */ - unsigned w; /* current window position */ - register ulg b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - -DEBG(""); - return 0; -} - - - -int inflate_fixed() -/* decompress an inflated type 1 (fixed Huffman codes) block. We should - either replace this with a custom decoder, or at least precompute the - Huffman tables. */ -{ - int i; /* temporary variable */ - struct huft *tl; /* literal/length code table */ - struct huft *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned l[288]; /* length list for huft_build */ - -DEBG(" 1) - { - huft_free(tl); - - DEBG(">"); - return i; - } - - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; -} - - - -int inflate_dynamic() -/* decompress an inflated type 2 (dynamic Huffman codes) block. */ -{ - int i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ - struct huft *tl; /* literal/length code table */ - struct huft *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ -#ifdef PKZIP_BUG_WORKAROUND - unsigned ll[288+32]; /* literal/length and distance code lengths */ -#else - unsigned ll[286+30]; /* literal/length and distance code lengths */ -#endif - register ulg b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - -DEBG(" 288 || nd > 32) -#else - if (nl > 286 || nd > 30) -#endif - return 1; /* bad lengths */ - -DEBG("dyn1 "); - - /* read in bit-length-code lengths */ - for (j = 0; j < nb; j++) - { - NEEDBITS(3) - ll[border[j]] = (unsigned)b & 7; - DUMPBITS(3) - } - for (; j < 19; j++) - ll[border[j]] = 0; - -DEBG("dyn2 "); - - /* build decoding table for trees--single level, 7 bit lookup */ - bl = 7; - if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) - { - if (i == 1) - huft_free(tl); - return i; /* incomplete code set */ - } - -DEBG("dyn3 "); - - /* read in literal and distance code lengths */ - n = nl + nd; - m = mask_bits[bl]; - i = l = 0; - while ((unsigned)i < n) - { - NEEDBITS((unsigned)bl) - j = (td = tl + ((unsigned)b & m))->b; - DUMPBITS(j) - j = td->v.n; - if (j < 16) /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - else if (j == 16) /* repeat last length 3 to 6 times */ - { - NEEDBITS(2) - j = 3 + ((unsigned)b & 3); - DUMPBITS(2) - if ((unsigned)i + j > n) - return 1; - while (j--) - ll[i++] = l; - } - else if (j == 17) /* 3 to 10 zero length codes */ - { - NEEDBITS(3) - j = 3 + ((unsigned)b & 7); - DUMPBITS(3) - if ((unsigned)i + j > n) - return 1; - while (j--) - ll[i++] = 0; - l = 0; - } - else /* j == 18: 11 to 138 zero length codes */ - { - NEEDBITS(7) - j = 11 + ((unsigned)b & 0x7f); - DUMPBITS(7) - if ((unsigned)i + j > n) - return 1; - while (j--) - ll[i++] = 0; - l = 0; - } - } - -DEBG("dyn4 "); - - /* free decoding table for trees */ - huft_free(tl); - -DEBG("dyn5 "); - - /* restore the global bit buffer */ - bb = b; - bk = k; - -DEBG("dyn5a "); - - /* build the decoding tables for literal/length and distance codes */ - bl = lbits; - if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) - { -DEBG("dyn5b "); - if (i == 1) { - error(" incomplete literal tree\n"); - huft_free(tl); - } - return i; /* incomplete code set */ - } -DEBG("dyn5c "); - bd = dbits; - if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) - { -DEBG("dyn5d "); - if (i == 1) { - error(" incomplete distance tree\n"); -#ifdef PKZIP_BUG_WORKAROUND - i = 0; - } -#else - huft_free(td); - } - huft_free(tl); - return i; /* incomplete code set */ -#endif - } - -DEBG("dyn6 "); - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - -DEBG("dyn7 "); - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - - DEBG(">"); - return 0; -} - - - -int inflate_block(e) -int *e; /* last block flag */ -/* decompress an inflated block */ -{ - unsigned t; /* block type */ - register ulg b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - - DEBG(""); - - /* bad block type */ - return 2; -} - - - -int inflate() -/* decompress an inflated entry */ -{ - int e; /* last block flag */ - int r; /* result code */ - unsigned h; /* maximum struct huft's malloc'ed */ - - - /* initialize window, bit buffer */ - wp = 0; - bk = 0; - bb = 0; - - - /* decompress until the last block */ - h = 0; - do { - hufts = 0; - if ((r = inflate_block(&e)) != 0) - return r; - if (hufts > h) - h = hufts; - } while (!e); - - /* Undo too much lookahead. The next read will be byte aligned so we - * can discard unused bits in the last meaningful byte. - */ - while (bk >= 8) { - bk -= 8; - inptr--; - } - - /* flush out slide */ - flush_output(wp); - - - /* return success */ -#ifdef DEBUG - fprintf(stderr, "<%u> ", h); -#endif /* DEBUG */ - return 0; -} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/kbd.c linux/arch/ppc/boot/kbd.c --- v2.1.78/linux/arch/ppc/boot/kbd.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/boot/kbd.c Mon Jan 12 15:18:13 1998 @@ -1,19 +1,10 @@ -/* Keyboard handler */ -#include <../drivers/char/defkeymap.c> /* yeah I know it's bad */ +#include -#define L 0x0001 /* locking function */ -#define SHF 0x0002 /* keyboard shift */ -#define ALT 0x0004 /* alternate shift -- alternate chars */ -#define NUM 0x0008 /* numeric shift cursors vs. numeric */ -#define CTL 0x0010 /* control shift -- allows ctl function */ -#define CPS 0x0020 /* caps shift -- swaps case of letter */ -#define ASCII 0x0040 /* ascii code for this key */ -#define STP 0x0080 /* stop output */ -#define FUNC 0x0100 /* function key */ -#define SCROLL 0x0200 /* scroll lock key */ +#include <../drivers/char/defkeymap.c> /* yeah I know it's bad */ -unsigned char shfts, ctls, alts, caps, num, stp; + +unsigned char shfts, ctls, alts, caps; #define KBDATAP 0x60 /* kbd data port */ #define KBSTATUSPORT 0x61 /* kbd status */ @@ -21,37 +12,15 @@ #define KBINRDY 0x01 #define KBOUTRDY 0x02 -#define _x__ 0x00 /* Unknown / unmapped */ -const unsigned short action[] = { - 0, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 0- 7 */ - ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 8-15 */ - ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 16-23 */ - ASCII, ASCII, ASCII, ASCII, ASCII, CTL, ASCII, ASCII, /* scan 24-31 */ - ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 32-39 */ - ASCII, ASCII, SHF, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 40-47 */ - ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, SHF, ASCII, /* scan 48-55 */ - ALT, ASCII, CPS, FUNC, FUNC, FUNC, FUNC, FUNC, /* scan 56-63 */ - FUNC, FUNC, FUNC, FUNC, FUNC, NUM,SCROLL, ASCII, /* scan 64-71 */ - ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 72-79 */ - ASCII, ASCII, ASCII, ASCII, 0, 0, 0, 0, /* scan 80-87 */ - 0,0,0,0,0,0,0,0, /* scan 88-95 */ - 0,0,0,0,0,0,0,0, /* scan 96-103 */ - 0,0,0,0,0,0,0,0, /* scan 104-111 */ - 0,0,0,0,0,0,0,0, /* scan 112-119 */ - 0,0,0,0,0,0,0,0, /* scan 120-127 */ -}; - -static int -kbd(noblock) - int noblock; +static int kbd(int noblock) { - unsigned char dt, brk, act; - int first = 1; + unsigned char dt, brk, val; + unsigned code; loop: if (noblock) { - if ((inb(KBSTATP) & KBINRDY) == 0) - return (-1); + if ((inb(KBSTATP) & KBINRDY) == 0) + return (-1); } else while((inb(KBSTATP) & KBINRDY) == 0) ; dt = inb(KBDATAP); @@ -59,72 +28,102 @@ brk = dt & 0x80; /* brk == 1 on key release */ dt = dt & 0x7f; /* keycode */ - act = action[dt]; - if (/*act&SHF*/ dt == 54) - shfts = brk ? 0 : 1; - if (/*act&ALT*/ dt == 48) - alts = brk ? 0 : 1; - if (/*act&NUM*/ dt == 69) - if (act&L) { - /* NUM lock */ - if(!brk) - num = !num; - } else - num = brk ? 0 : 1; - if (/*act&CTL*/ dt == 29) - ctls = brk ? 0 : 1; - if (/*act&CPS*/ dt == 58) - if (act&L) { - /* CAPS lock */ - if(!brk) - caps = !caps; - } else - caps = brk ? 0 : 1; - if (0/*act&STP*/) - if (act&L) { - if(!brk) - stp = !stp; - } else - stp = brk ? 0 : 1; - - if ((act&ASCII) && !brk) { - unsigned char chr; - if (shfts) - chr = shift_map[dt]; - else if (ctls) - chr = ctrl_map[dt]; - else - chr = plain_map[dt]; + if (shfts) + code = shift_map[dt]; + else if (ctls) + code = ctrl_map[dt]; + else + code = plain_map[dt]; + + val = KVAL(code); + switch (KTYP(code) & 0x0f) { + case KT_LATIN: + if (brk) + break; if (alts) - chr |= 0x80; + val |= 0x80; + if (val == 0x7f) /* map delete to backspace */ + val = '\b'; + return val; + + case KT_LETTER: + if (brk) + break; + if (caps) + val -= 'a'-'A'; + return val; + + case KT_SPEC: + if (brk) + break; + if (val == KVAL(K_CAPS)) + caps = !caps; + else if (val == KVAL(K_ENTER)) { +enter: /* Wait for key up */ + while (1) { + while((inb(KBSTATP) & KBINRDY) == 0) ; + dt = inb(KBDATAP); + if (dt & 0x80) /* key up */ break; + } + return 10; + } + break; + + case KT_PAD: + if (brk) + break; + if (val < 10) + return val; + if (val == KVAL(K_PENTER)) + goto enter; + break; + + case KT_SHIFT: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + shfts = brk ? 0 : 1; + break; + case KG_ALT: + case KG_ALTGR: + alts = brk ? 0 : 1; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + ctls = brk ? 0 : 1; + break; + } + break; - if (caps && (chr >= 'a' && chr <= 'z')) - chr -= 'a' - 'A' ; - if ( chr == 0x01 ) chr = '\n'; /* hack */ -#define CTRL(s) (s & 0x1F) - if ((chr == '\r') || (chr == '\n') || (chr == CTRL('A')) || (chr == CTRL('S'))) - { - /* Wait for key up */ - while (1) - { - while((inb(KBSTATP) & KBINRDY) == 0) ; - dt = inb(KBDATAP); - if (dt & 0x80) /* key up */ break; - } + case KT_LOCK: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + if (brk) + shfts = !shfts; + break; + case KG_ALT: + case KG_ALTGR: + if (brk) + alts = !alts; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + if (brk) + ctls = !ctls; + break; } - return (chr); + break; } - if (first && brk) return (0); /* Ignore initial 'key up' codes */ + if (brk) return (0); /* Ignore initial 'key up' codes */ goto loop; } -static -scankbd(void) { - return (kbd(1) != -1); -} - -static -kbdreset(void) +static void kbdreset(void) { unsigned char c; int i; @@ -151,7 +150,7 @@ static int kbd_reset = 0; -CRT_getc(void) +int CRT_getc(void) { int c; if (!kbd_reset) {kbdreset(); kbd_reset++; } @@ -159,7 +158,7 @@ return(c); } -CRT_tstc(void) +int CRT_tstc(void) { if (!kbd_reset) {kbdreset(); kbd_reset++; } return ((inb(KBSTATP) & KBINRDY) != 0); diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/lzw.h linux/arch/ppc/boot/lzw.h --- v2.1.78/linux/arch/ppc/boot/lzw.h Wed Dec 18 00:49:52 1996 +++ linux/arch/ppc/boot/lzw.h Wed Dec 31 16:00:00 1969 @@ -1,42 +0,0 @@ -/* lzw.h -- define the lzw functions. - * Copyright (C) 1992-1993 Jean-loup Gailly. - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -#if !defined(OF) && defined(lint) -# include "gzip.h" -#endif - -#ifndef BITS -# define BITS 16 -#endif -#define INIT_BITS 9 /* Initial number of bits per code */ - -#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */ - -#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */ -/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free. - * It's a pity that old uncompress does not check bit 0x20. That makes - * extension of the format actually undesirable because old compress - * would just crash on the new format instead of giving a meaningful - * error message. It does check the number of bits, but it's more - * helpful to say "unsupported format, get a new version" than - * "can only handle 16 bits". - */ - -#define BLOCK_MODE 0x80 -/* Block compression: if table is full and compression rate is dropping, - * clear the dictionary. - */ - -#define LZW_RESERVED 0x60 /* reserved bits */ - -#define CLEAR 256 /* flush the dictionary */ -#define FIRST (CLEAR+1) /* first free entry */ - -extern int maxbits; /* max bits per code for LZW */ -extern int block_mode; /* block compress mode -C compatible with 2.0 */ - -extern void lzw OF((int in, int out)); -extern void unlzw OF((int in, int out)); diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c --- v2.1.78/linux/arch/ppc/boot/misc.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/boot/misc.c Mon Jan 12 15:18:13 1998 @@ -1,65 +1,29 @@ /* * misc.c * - * This is a collection of several routines from gzip-1.0.3 - * adapted for Linux. - * - * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 - * puts by Nick Holloway 1993 - * * Adapted for PowerPC by Gary Thomas - * Updated and modified by Cort Dougan (cort@cs.nmt.edu) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) + * Soon to be replaced by a single bootloader for chrp/prep/pmac. -- Cort */ -#include "gzip.h" -#include "lzw.h" +#include "../coffboot/zlib.h" #include "asm/residual.h" #include +/* this is where the INITRD gets moved to for safe keeping */ +#define INITRD_DESTINATION /*0x00f00000*/ 0x01f00000 +/* this will do for now - Cort */ +char *avail_ram = (char *) 0x00800000; /* start with 8M */ +/* assume 15M max since this is where we copy the initrd to -- Cort */ +char *end_avail = (char *) INITRD_DESTINATION; + RESIDUAL hold_residual; unsigned long initrd_start = 0, initrd_end = 0; char *zimage_start; int zimage_size; -extern char input_data[]; -extern int input_len; -void cksum_text(void); -void verify_data(unsigned long load_addr); - -void dump_buf(unsigned char *p, int s); -#define EOF -1 - -DECLARE(uch, inbuf, INBUFSIZ); -DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); -DECLARE(uch, window, WSIZE); - -unsigned outcnt; -unsigned insize; -unsigned inptr; - char cmd_line[256]; -int input_ptr; - -int method, exit_code, part_nb, last_member; -int test = 0; -int force = 0; -int verbose = 1; -long bytes_in, bytes_out; - -char *output_data; -unsigned long output_ptr; - -extern int end; -long free_mem_ptr = (long)&end; - -int to_stdout = 0; -int hard_math = 0; - -void (*work)(int inf, int outf); -void makecrc(void); - -local int get_method(int); - char *vidmem = (char *)0xC00B8000; int lines, cols; int orig_x, orig_y; @@ -68,43 +32,19 @@ void putc(const char c); void puthex(unsigned long val); void _bcopy(char *src, char *dst, int len); +void * memcpy(void * __dest, __const void * __src, + int __n); +void gunzip(void *, int, unsigned char *, int *); -void *malloc(int size) +void pause() { - void *p; - - if (size <0) error("Malloc error\n"); - if (free_mem_ptr <= 0) error("Memory error\n"); - - while(1) { - free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ - - p = (void *)free_mem_ptr; - free_mem_ptr += size; - - /* - * The part of the compressed kernel which has already been expanded - * is no longer needed. Therefore we can reuse it for malloc. - * With bigger kernels, this is necessary. - */ - - if (free_mem_ptr < (long)&end) { - if (free_mem_ptr > (long)&zimage_start[input_ptr]) - error("\nOut of memory\n"); - - return p; - } -#if 0 - if (free_mem_ptr < 0x90000) -#endif - return p; - puts("large kernel, low 1M tight..."); - free_mem_ptr = (long)zimage_start; - } + puts("pause\n"); } -void free(void *where) -{ /* Don't care */ +void exit() +{ + puts("exit\n"); + while(1); } static void clear_screen() @@ -205,16 +145,8 @@ orig_y = y; } -__ptr_t memset(__ptr_t s, int c, size_t n) -{ - int i; - char *ss = (char*)s; - - for (i=0;i> 8); - } - } - crc = c; - return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ -} + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); -/* =========================================================================== - * Clear input and output buffers - */ -void clear_bufs() -{ - outcnt = 0; - insize = inptr = 0; - bytes_in = bytes_out = 0L; + while(1); /* Halt */ } -/* =========================================================================== - * Fill the input buffer. This is called only when the buffer is empty - * and at least one byte is really needed. - */ -int fill_inbuf() -{ - int len, i; - - /* Read as much as possible */ -puts("*"); - insize = 0; - do { - len = INBUFSIZ-insize; - if (len > (zimage_size-input_ptr+1)) len=zimage_size-input_ptr+1; - if (len == 0 || len == EOF) break; - - for (i=0;i end_avail) { + puts("oops... out of memory\n"); + pause(); + } + return p; } -/* - * Code to compute the CRC-32 table. Borrowed from - * gzip-1.0.3/makecrc.c. - */ - -ulg crc_32_tab[256]; - -void -makecrc(void) +void zfree(void *x, void *addr, unsigned nb) { -/* Not copyrighted 1990 Mark Adler */ - - unsigned long c; /* crc shift register */ - unsigned long e; /* polynomial exclusive-or pattern */ - int i; /* counter for all possible eight bit values */ - int k; /* byte being shifted into crc apparatus */ - - /* terms of polynomial defining this crc (except x^32): */ - static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* Make exclusive-or pattern from polynomial */ - e = 0; - for (i = 0; i < sizeof(p)/sizeof(int); i++) - e |= 1L << (31 - p[i]); - - crc_32_tab[0] = 0; - - for (i = 1; i < 256; i++) - { - c = 0; - for (k = i | 256; k != 1; k >>= 1) - { - c = c & 1 ? (c >> 1) ^ e : c >> 1; - if (k & 1) - c ^= e; - } - crc_32_tab[i] = c; - } } -void error(char *x) -{ - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); - - while(1); /* Halt */ +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + puts("bad gzipped data\n"); + 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) { + puts("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + puts("inflateInit2 returned %d\n"); + 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) { + puts("inflate returned %d\n"); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); } unsigned long decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual) { - int timer; - char *cp, ch; - Elf32_Ehdr *eh; - Elf32_Shdr *sh, *strtab_shdr; - char *strtab; - unsigned long i; - extern unsigned long start(void); - + int timer; + extern unsigned long start; + char *cp, ch; + unsigned long i; + + + lines = 25; + cols = 80; + orig_x = 0; + orig_y = 24; + + + /* Turn off MMU. Since we are mapped 1-1, this is OK. */ + flush_instruction_cache(); + _put_HID0(_get_HID0() & ~0x0000C000); + _put_MSR(_get_MSR() & ~0x0030); + + vga_init(0xC0000000); + /*clear_screen();*/ + + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); puthex((unsigned long)((unsigned long)&start + (4*num_words))); puts("\n"); + + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + else + initrd_start = 0; + initrd_end = INITRD_SIZE + initrd_start; - output_data = (char *)0x0; /* Points to 0 */ - lines = 25; - cols = 80; - orig_x = 0; - orig_y = 24; - - - /* Turn off MMU. Since we are mapped 1-1, this is OK. */ - flush_instruction_cache(); - _put_HID0(_get_HID0() & ~0x0000C000); - _put_MSR(_get_MSR() & ~0x0030); - - vga_init(0xC0000000); - /*clear_screen();*/ - - output_ptr = 0; - - exit_code = 0; - test = 0; - input_ptr = 0; - part_nb = 0; - - clear_bufs(); - makecrc(); - - puts("Cksum: "); puthex(cksum); puts("\n"); - puts("Loaded at: "); puthex(load_addr); puts(" "); puthex(num_words+load_addr); - puts("\n"); - puts("Boot code relocated to: "); puthex((unsigned long)start); puts(" "); - puthex((unsigned long)(num_words+start)); - puts("\n"); - if (residual) { - _bcopy((char *)residual, (char *)&hold_residual, sizeof(hold_residual)); - puts("Residual data at: "); puthex((unsigned long)residual); puts(" "); - puthex((unsigned long)((unsigned long)(residual->ResidualLength) + residual)); puts("\n"); - puts("Residual data relocated to: "); puthex((unsigned long)&hold_residual); puts("\n"); - } - - /* - * Take care of initrd if we have one - */ - /* - * the _actual_ load addr is 64k (elf hdr size) lower but the - * firmware gives us the starting exec point not the load ptr - * -- Cort - */ - eh = (Elf32_Ehdr *)(load_addr - 65536); - sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff ); - /*puts("Entry point: "); puthex(eh->e_entry); puts("\n");*/ - - /* find string table */ - for ( i = 0 ; i <= eh->e_shnum ; i++,sh++) - { - /*puts("Section: "); puthex(i); - puts(" type: "); puthex(sh->sh_type); - puts(" offset: "); puthex(sh->sh_offset); - puts("\n");*/ - - if ( sh->sh_type == SHT_STRTAB ) - { - strtab_shdr = sh; - strtab = (char *)(sh->sh_offset + (unsigned long)eh); - /*puts("Found strtab at: "); puthex((unsigned long)strtab); - puts("\n");*/ - break; - } - } + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + + memcpy ((void *)INITRD_DESTINATION,(void *)initrd_start, + INITRD_SIZE ); + initrd_end = INITRD_DESTINATION + INITRD_SIZE; + initrd_start = INITRD_DESTINATION; + puts("Moved initrd to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + + CRT_tstc(); /* Forces keyboard to be initialized */ + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\n"); - /* find the initrd and image sections */ - if ( strtab_shdr ) - { - sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff ); - for ( i = 0 ; i <= eh->e_shnum ; i++,sh++) - { - if ( !memcmp("initrd", (char *)(strtab+sh->sh_name), 6 ) ) - { - initrd_start = (unsigned long)eh + sh->sh_offset; - initrd_end = initrd_start + sh->sh_size; - puts("Found initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); - puts("\n"); - } - if ( !memcmp("image", (char *)(strtab+sh->sh_name), 5 ) ) - { - zimage_start = (char *)((unsigned long)eh + sh->sh_offset); - zimage_size = sh->sh_size; - puts("Found zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); - puts("\n"); - } - } - } - else - { - puts("Couldn't find string table for boot image!\n"); - } - - /* relocate initrd */ - if ( initrd_start ) - { - memcpy ((void *)0x00D00000,(void *)initrd_start, - initrd_end - initrd_start ); - initrd_end = 0x00D00000 + initrd_end - initrd_start; - initrd_start = 0x00D00000; - puts("Moved initrd to: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - } - - - CRT_tstc(); /* Forces keyboard to be initialized */ - puts("\nLinux/PPC load: "); - timer = 0; - cp = cmd_line; - while (timer++ < 5*1000) { - if (tstc()) { - while ((ch = getc()) != '\n' && ch != '\r') { - if (ch == '\b') { - if (cp != cmd_line) { - cp--; - puts("\b \b"); - } - } else { - *cp++ = ch; - putc(ch); - } - } - break; /* Exit 'timer' loop */ - } - udelay(1000); /* 1 msec */ - } - *cp = 0; - puts("\n"); - - /* mappings on early boot can only handle 16M */ - if ( (int)(&cmd_line[0]) > (16<<20)) - puts("cmd_line > 16M\n"); - if ( (int)&hold_residual > (16<<20)) - puts("hold_residual > 16M\n"); - if ( initrd_start > (16<<20)) - puts("initrd_start > 16M\n"); + /* mappings on early boot can only handle 16M */ + if ( (int)(&cmd_line[0]) > (16<<20)) + puts("cmd_line located > 16M\n"); + if ( (int)&hold_residual > (16<<20)) + puts("hold_residual located > 16M\n"); + if ( initrd_start > (16<<20)) + puts("initrd_start located > 16M\n"); - puts("Uncompressing Linux..."); - method = get_method(0); - work(0, 0); - puts("done.\n"); - - puts("Now booting the kernel\n"); - return (unsigned long)&hold_residual; -} - -show_residual_data(RESIDUAL *res) -{ - puts("Residual data: "); puthex(res->ResidualLength); puts(" bytes\n"); -#if 0 - puts("Residual structure = "); puthex(sizeof(*res)); puts(" bytes\n"); - dump_buf(&hold_residual, 32); - dump_buf(res, 32); -#endif -} - -do_cksum(unsigned long loc) -{ - unsigned int ptr, cksum; - puts("cksum["); puthex(loc); puts("] = "); - cksum = 0; - for (ptr = loc; ptr < (loc+0x40000); ptr += 4) - { - cksum ^= *(unsigned long *)ptr; - } - puthex(cksum); puts(" "); - cksum = 0; loc += 0x40000; - for (ptr = loc; ptr < (loc+0x40000); ptr += 4) - { - cksum ^= *(unsigned long *)ptr; - } - puthex(cksum); puts(" "); - cksum = 0; loc += 0x40000; - for (ptr = loc; ptr < (loc+0x40000); ptr += 4) - { - cksum ^= *(unsigned long *)ptr; - } - puthex(cksum); puts(" "); - cksum = 0; loc += 0x40000; - for (ptr = loc; ptr < (loc+0x40000); ptr += 4) - { - cksum ^= *(unsigned long *)ptr; - } - puthex(cksum); puts("\n"); -} - -cksum_data() -{ - unsigned int *ptr, len, cksum, cnt; - cksum = cnt = 0; - ptr = (unsigned int *)zimage_start; - puts("Checksums: "); - for (len = 0; len < zimage_size; len += 4) { - cksum ^= *ptr++; - if (len && ((len & 0x0FFF) == 0)) { - if (cnt == 0) { - puts("\n ["); - puthex((unsigned long)ptr-1); - puts("] "); - } - puthex(cksum); - if (++cnt == 6) { - cnt = 0; - } else { - puts(" "); - } - } - } - puts("\n"); - puts("Data cksum = "); puthex(cksum); puts("\n"); -} - -void cksum_text(void) -{ - extern int start, etext; - unsigned int *ptr, len, text_len, cksum, cnt; - cksum = cnt = 0; - ptr = &start; - text_len = (unsigned int)&etext - (unsigned int)&start; - puts("Checksums: "); - for (len = 0; len < text_len; len += 4) { - cksum ^= *ptr++; - if (len && ((len & 0x0FFF) == 0)) { - if (cnt == 0) { - puts("\n ["); - puthex((unsigned long)ptr-1); - puts("] "); - } - puthex(cksum); - if (++cnt == 6) { - cnt = 0; - } else { - puts(" "); - } - } - } - puts("\n"); - puts("TEXT cksum = "); puthex(cksum); puts("\n"); -} - -void verify_data(unsigned long load_addr) -{ - extern int start, etext; - unsigned int *orig_ptr, *copy_ptr, len, errors; - errors = 0; - copy_ptr = (unsigned int *)zimage_start; - orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start)); - for (len = 0; len < zimage_size; len += 4) { - if (*copy_ptr++ != *orig_ptr++) { - errors++; - } - } - copy_ptr = (unsigned int *)zimage_start; - orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start)); - for (len = 0; len < zimage_size; len += 4) { - if (*copy_ptr++ != *orig_ptr++) { - dump_buf((unsigned char *) (copy_ptr-1), 128); - dump_buf((unsigned char *) (orig_ptr-1), 128); - puts("Total errors = "); puthex(errors*4); puts("\n"); - while (1) ; - } - } -} - -test_data(unsigned long load_addr) -{ - extern int start, etext; - unsigned int *orig_ptr, *copy_ptr, len, errors; - errors = 0; - copy_ptr = (unsigned int *)zimage_start; - orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start)); - for (len = 0; len < zimage_size; len += 4) { - if (*copy_ptr++ != *orig_ptr++) { - errors++; - } - } - return (errors == 0); + puts("Uncompressing Linux..."); + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + puts("Now booting the kernel\n"); + return (unsigned long)&hold_residual; } 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'; - puts(buf); -} - -#if 1 -void puthex2(unsigned long val) -{ - unsigned char buf[4]; - int i; - for (i = 1; i >= 0; i--) - { - buf[i] = "0123456789ABCDEF"[val & 0x0F]; - val >>= 4; - } - buf[2] = '\0'; - puts(buf); -} - -void dump_buf(unsigned char *p, int s) -{ - int i, c; - if ((unsigned int)s > (unsigned int)p) - { - s = (unsigned int)s - (unsigned int)p; - } - while (s > 0) - { - puthex((unsigned long)p); puts(": "); - for (i = 0; i < 16; i++) - { - if (i < s) - { - puthex2(p[i] & 0xFF); - } else - { - puts(" "); - } - if ((i % 2) == 1) puts(" "); - if ((i % 8) == 7) puts(" "); - } - puts(" |"); - for (i = 0; i < 16; i++) - { - char buf[2]; - if (i < s) - { - c = p[i] & 0xFF; - if ((c < 0x20) || (c >= 0x7F)) c = '.'; - } else - { - c = ' '; - } - buf[0] = c; buf[1] = '\0'; - puts(buf); - } - puts("|\n"); - s -= 16; - p += 16; - } + unsigned char buf[10]; + int i; + for (i = 7; i >= 0; i--) + { + buf[i] = "0123456789ABCDEF"[val & 0x0F]; + val >>= 4; + } + buf[8] = '\0'; + puts(buf); } -#endif /* * PCI/ISA I/O support @@ -765,79 +389,8 @@ return ((addr & 0x7FFFFFFF) | 0x80000000); } -/* ======================================================================== - * Check the magic number of the input file and update ofname if an - * original name was given and to_stdout is not set. - * Return the compression method, -1 for error, -2 for warning. - * Set inptr to the offset of the next byte to be processed. - * This function may be called repeatedly for an input file consisting - * of several contiguous gzip'ed members. - * IN assertions: there is at least one remaining compressed member. - * If the member is a zip file, it must be the only one. - */ -local int get_method(in) - int in; /* input file descriptor */ -{ - uch flags; - char magic[2]; /* magic header */ - - magic[0] = (char)get_byte(); - magic[1] = (char)get_byte(); - - method = -1; /* unknown yet */ - part_nb++; /* number of parts in gzip file */ - last_member = 0; - /* assume multiple members in gzip file except for record oriented I/O */ - - if (memcmp(magic, GZIP_MAGIC, 2) == 0 - || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { - - work = unzip; - method = (int)get_byte(); - flags = (uch)get_byte(); - if ((flags & ENCRYPTED) != 0) - error("Input is encrypted\n"); - if ((flags & CONTINUATION) != 0) - error("Multi part input\n"); - if ((flags & RESERVED) != 0) { - error("Input has invalid flags\n"); - exit_code = ERROR; - if (force <= 1) return -1; - } - (ulg)get_byte(); /* Get timestamp */ - ((ulg)get_byte()) << 8; - ((ulg)get_byte()) << 16; - ((ulg)get_byte()) << 24; - - (void)get_byte(); /* Ignore extra flags for the moment */ - (void)get_byte(); /* Ignore OS type for the moment */ - - if ((flags & EXTRA_FIELD) != 0) { - unsigned len = (unsigned)get_byte(); - len |= ((unsigned)get_byte())<<8; - while (len--) (void)get_byte(); - } - - /* Get original file name if it was truncated */ - if ((flags & ORIG_NAME) != 0) { - if (to_stdout || part_nb > 1) { - /* Discard the old name */ - while (get_byte() != 0) /* null */ ; - } else { - } /* to_stdout */ - } /* orig_name */ - - /* Discard file comment if any */ - if ((flags & COMMENT) != 0) { - while (get_byte() != 0) /* null */ ; - } - } else - error("unknown compression method"); - return method; -} - void _bcopy(char *src, char *dst, int len) { - while (len--) *dst++ = *src++; + while (len--) *dst++ = *src++; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/mkprep.c linux/arch/ppc/boot/mkprep.c --- v2.1.78/linux/arch/ppc/boot/mkprep.c Mon Aug 18 18:19:43 1997 +++ linux/arch/ppc/boot/mkprep.c Mon Jan 12 15:18:13 1998 @@ -131,8 +131,8 @@ argptr++; /* skip elf header in input file */ - if ( !prep ) - lseek(in_fd, elfhdr_size, SEEK_SET); + /*if ( !prep )*/ + lseek(in_fd, elfhdr_size, SEEK_SET); /* write prep partition if necessary */ if ( prep ) @@ -164,7 +164,7 @@ bzero( block, sizeof block ); /* set entry point and boot image size skipping over elf header */ - *entry = cpu_to_le32(0x400+65536); + *entry = cpu_to_le32(0x400/*+65536*/); *length = cpu_to_le32(info.st_size+0x400); /* sets magic number for msdos partition (used by linux) */ diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/offset linux/arch/ppc/boot/offset --- v2.1.78/linux/arch/ppc/boot/offset Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/offset Mon Jan 12 15:18:13 1998 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`objdump -h $1 | grep $2 | grep -v zvmlinux| awk '{print $6}'` +echo "0x"$OFFSET diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/piggyback.c linux/arch/ppc/boot/piggyback.c --- v2.1.78/linux/arch/ppc/boot/piggyback.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/piggyback.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,64 @@ +#include + +extern long ce_exec_config[]; + +main(int argc, char *argv[]) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[8192]; + if (argc != 1) + { + fprintf(stderr, "usage: %s out-file\n", argv[0]); + exit(1); + } + fprintf(stdout, "#\n"); + fprintf(stdout, "# Miscellaneous data structures:\n"); + fprintf(stdout, "# WARNING - this file is automatically generated!\n"); + fprintf(stdout, "#\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\t.data\n"); + fprintf(stdout, "\t.globl input_data\n"); + fprintf(stdout, "input_data:\n"); + pos = 0; + cksum = 0; + while ((len = read(0, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + fprintf(stdout, "\t.long\t"); + } + fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + fprintf(stdout, " # %x \n", pos+i-12); + fflush(stdout); + } else + { + fprintf(stdout, ","); + } + } + if (cnt) + { + fprintf(stdout, "0\n"); + } + pos += len; + } + fprintf(stdout, "\t.globl input_len\n"); + fprintf(stdout, "input_len:\t.long\t0x%x\n", pos); + fflush(stdout); + fclose(stdout); + fprintf(stderr, "cksum = %x\n", cksum); + exit(0); +} + diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/size linux/arch/ppc/boot/size --- v2.1.78/linux/arch/ppc/boot/size Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/size Mon Jan 12 15:18:13 1998 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`objdump -h $1 | grep $2 | grep -v zvmlinux | awk '{print $3}'` +echo "0x"$OFFSET diff -u --recursive --new-file v2.1.78/linux/arch/ppc/boot/unzip.c linux/arch/ppc/boot/unzip.c --- v2.1.78/linux/arch/ppc/boot/unzip.c Mon Aug 4 16:25:36 1997 +++ linux/arch/ppc/boot/unzip.c Wed Dec 31 16:00:00 1969 @@ -1,182 +0,0 @@ -/* unzip.c -- decompress files in gzip or pkzip format. - * Copyright (C) 1992-1993 Jean-loup Gailly - * - * Adapted for Linux booting by Hannu Savolainen 1993 - * - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - * - * The code in this file is derived from the file funzip.c written - * and put in the public domain by Mark Adler. - */ - -/* - This version can extract files in gzip or pkzip format. - For the latter, only the first entry is extracted, and it has to be - either deflated or stored. - */ - -#ifndef lint -static char rcsid[] = "$Id: unzip.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $"; -#endif - -#include "gzip.h" -#include "crypt.h" - -#include - -/* PKZIP header definitions */ -#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */ -#define LOCFLG 6 /* offset of bit flag */ -#define CRPFLG 1 /* bit for encrypted entry */ -#define EXTFLG 8 /* bit for extended local header */ -#define LOCHOW 8 /* offset of compression method */ -#define LOCTIM 10 /* file mod time (for decryption) */ -#define LOCCRC 14 /* offset of crc */ -#define LOCSIZ 18 /* offset of compressed size */ -#define LOCLEN 22 /* offset of uncompressed length */ -#define LOCFIL 26 /* offset of file name field length */ -#define LOCEXT 28 /* offset of extra field length */ -#define LOCHDR 30 /* size of local header, including sig */ -#define EXTHDR 16 /* size of extended local header, inc sig */ - - -/* Globals */ - -int decrypt; /* flag to turn on decryption */ -char *key; /* not used--needed to link crypt.c */ -int pkzip = 0; /* set for a pkzip file */ -int extended = 0; /* set if extended local header */ - -/* =========================================================================== - * Check zip file and advance inptr to the start of the compressed data. - * Get ofname from the local header if necessary. - */ -int check_zipfile(in) - int in; /* input file descriptors */ -{ - uch *h = inbuf + inptr; /* first local header */ - - /* ifd = in; */ - - /* Check validity of local header, and skip name and extra fields */ - inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT); - - if (inptr > insize || LG(h) != LOCSIG) { - error("input not a zip"); - } - method = h[LOCHOW]; - if (method != STORED && method != DEFLATED) { - error("first entry not deflated or stored--can't extract"); - } - - /* If entry encrypted, decrypt and validate encryption header */ - if ((decrypt = h[LOCFLG] & CRPFLG) != 0) { - error("encrypted file\n"); - exit_code = ERROR; - return -1; - } - - /* Save flags for unzip() */ - extended = (h[LOCFLG] & EXTFLG) != 0; - pkzip = 1; - - /* Get ofname and time stamp from local header (to be done) */ - return 0; -} - -/* =========================================================================== - * Unzip in to out. This routine works on both gzip and pkzip files. - * - * IN assertions: the buffer inbuf contains already the beginning of - * the compressed data, from offsets inptr to insize-1 included. - * The magic header has already been checked. The output buffer is cleared. - */ -void unzip(in, out) - int in, out; /* input and output file descriptors */ -{ - ulg orig_crc = 0; /* original crc */ - ulg orig_len = 0; /* original uncompressed length */ - ulg _crc, _len; - int n; - uch buf[EXTHDR]; /* extended local header */ - - /* ifd = in; - ofd = out; */ - - updcrc(NULL, 0); /* initialize crc */ - - if (pkzip && !extended) { /* crc and length at the end otherwise */ - orig_crc = LG(inbuf + LOCCRC); - orig_len = LG(inbuf + LOCLEN); - } - - /* Decompress */ - if (method == DEFLATED) { - - int res = inflate(); - - if (res == 3) { - error("out of memory"); - } else if (res != 0) { - error("invalid compressed format"); - } - - } else if (pkzip && method == STORED) { - - register ulg n = LG(inbuf + LOCLEN); - - if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) { - - error("length mismatch"); - } - while (n--) { - uch c = (uch)get_byte(); -#ifdef CRYPT - if (decrypt) zdecode(c); -#endif - if (!test) put_char(c); - } - } else { - error("internal error, invalid method"); - } - - /* Get the crc and original length */ - if (!pkzip) { - /* crc32 (see algorithm.doc) - * uncompressed input size modulo 2^32 - */ - for (n = 0; n < 8; n++) { - buf[n] = (uch)get_byte(); /* may cause an error if EOF */ - } - orig_crc = LG(buf); - orig_len = LG(buf+4); - - } else if (extended) { /* If extended header, check it */ - /* signature - 4bytes: 0x50 0x4b 0x07 0x08 - * CRC-32 value - * compressed size 4-bytes - * uncompressed size 4-bytes - */ - for (n = 0; n < EXTHDR; n++) { - buf[n] = (uch)get_byte(); /* may cause an error if EOF */ - } - orig_crc = LG(buf+4); - orig_len = LG(buf+12); - } - - /* Validate decompression */ - if (orig_crc != (_crc = updcrc(outbuf, 0))) { - extern char input_data[]; - error("crc error"); - } - if (orig_len != bytes_out) { - error("length error"); - } - - /* Check if there are more entries in a pkzip file */ - if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) { - error("zip file has more than one entry"); - } - extended = pkzip = 0; /* for next file */ -} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile --- v2.1.78/linux/arch/ppc/chrpboot/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/Makefile Mon Jan 12 15:18:13 1998 @@ -0,0 +1,91 @@ +# Makefile for making ELF bootable images for booting on CHRP +# using Open Firmware. +# +# Geert Uytterhoeven September 1997 +# +# Based on coffboot by Paul Mackerras + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< +.S.s: + $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + +CFLAGS = -O -fno-builtin -DSTDC_HEADERS -I$(TOPDIR)/include +LD_ARGS = -T ../vmlinux.lds -Ttext 0x00800000 +OBJCOPY = $(CROSS_COMPILE)objcopy + +OBJS = crt0.o start.o main.o misc.o string.o zlib.o image.o # initrd.o +LIBS = $(TOPDIR)/lib/lib.a + + +all: $(TOPDIR)/zImage + +# +# Only build anything here if we're configured for CHRP +# -- cort +# +ifeq ($(CONFIG_CHRP),y) +znetboot: zImage + cp zImage /tftpboot/zImage.chrp + +znetboot.initrd: zImage.initrd + cp zImage.initrd /tftpboot/zImage.chrp + +floppy: zImage + mcopy zImage a:zImage + +piggyback: piggyback.c + $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c + +image.o: piggyback ../coffboot/vmlinux.gz + ./piggyback image < ../coffboot/vmlinux.gz | $(AS) -o image.o + +initrd.o: ramdisk.image.gz piggyback + ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o + +note.data : mknote + rm -f note.data + ./mknote > note.data + +zImage: $(OBJS) no_initrd.o note.data + $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) + objcopy zImage --add-section=.note=note.data zImage + +zImage.initrd: $(OBJS) initrd.o + $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) + +else +znetboot: + +znetboot.initrd: + +floppy: + +zImage: + +zImage.initrd: + +endif + +# just here to match coffboot/Makefile +vmlinux.coff: + +vmlinux.coff.initrd: + + +clean: + rm -f piggyback mknote note.data + rm -f $(OBJS) zImage + +fastdep: + $(TOPDIR)/scripts/mkdep *.[Sch] > .depend + +dep: + $(CPP) -M *.S *.c > .depend + diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/crt0.S linux/arch/ppc/chrpboot/crt0.S --- v2.1.78/linux/arch/ppc/chrpboot/crt0.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/crt0.S Mon Jan 12 15:18:13 1998 @@ -0,0 +1,20 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ + .text + .globl _start +_start: + lis 9,_start@h + lis 8,_etext@ha + addi 8,8,_etext@l +1: dcbf 0,9 + icbi 0,9 + addi 9,9,0x20 + cmplwi 0,9,8 + blt 1b + b start diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c --- v2.1.78/linux/arch/ppc/chrpboot/main.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/main.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,158 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include "nonstdio.h" +#include "zlib.h" + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +void gunzip(void *, int, unsigned char *, int *); + +#define get_16be(x) (*(unsigned short *)(x)) +#define get_32be(x) (*(unsigned *)(x)) + +#define RAM_START 0x90000000 +#define RAM_END 0x90800000 /* only 8M mapped with BATs */ + +#define RAM_FREE 0x90540000 /* after image of chrpboot */ +#define PROG_START 0x90010000 + +char *avail_ram; +char *end_avail; + +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; + + +chrpboot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("chrpboot starting\n\r"); + setup_bats(); + + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + printf("initial ramdisk at %x (%u bytes)\n\r", initrd_start, + initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + end_avail = (char *)initrd_start; + } else + end_avail = (char *) RAM_END; + im = image_data; + len = image_len; + dst = (void *) PROG_START; + + if (im[0] == 0x1f && im[1] == 0x8b) { + void *cp = (void *) RAM_FREE; + avail_ram = (void *) (RAM_FREE + ((len + 7) & -8)); + memcpy(cp, im, len); + printf("gunzipping... "); + gunzip(dst, 0x400000, cp, &len); + printf("done\n\r"); + + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + + sa = PROG_START+12; + printf("start address = 0x%x\n\r", sa); + +#if 0 + pause(); +#endif + (*(void (*)())sa)(a1, a2, prom, 0, 0); + + printf("returned?\n\r"); + + pause(); +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = (size + 7) & -8; + avail_ram += size; + if (avail_ram > end_avail) { + printf("oops... out of memory\n\r"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + 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(); + } + + 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\n\r", r); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/misc.S linux/arch/ppc/chrpboot/misc.S --- v2.1.78/linux/arch/ppc/chrpboot/misc.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/misc.S Mon Jan 12 15:18:13 1998 @@ -0,0 +1,50 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ + .text + +/* + * Use the BAT0 registers to map the 1st 8MB of RAM to 0x90000000. + */ + .globl setup_bats +setup_bats: + mfpvr 3 + rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */ + cmpi 0,3,1 + lis 4,0x9000 + bne 4f + ori 4,4,4 /* set up BAT registers for 601 */ + li 5,0x7f + b 5f +4: ori 4,4,0xff /* set up BAT registers for 604 */ + li 5,2 + mtdbatu 0,4 + mtdbatl 0,5 +5: mtibatu 0,4 + mtibatl 0,5 + isync + blr + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ + rlwinm. 4,4,27,5,31 + mtctr 4 + beqlr +1: dcbf 0,3 + icbi 0,3 + addi 3,3,0x20 + bdnz 1b + sync + isync + blr diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/mknote.c linux/arch/ppc/chrpboot/mknote.c --- v2.1.78/linux/arch/ppc/chrpboot/mknote.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/mknote.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,25 @@ +struct desc +{ + unsigned long namesz; + unsigned long descrsz; + unsigned long type; + char name[8]; + unsigned long real_mode; + unsigned long real_base; + unsigned long real_size; + unsigned long virt_base; + unsigned long virt_size; + unsigned long load_base; +}; + +int main(void) +{ + struct desc ns; + ns.namesz = 8; + ns.descrsz = 24; + ns.type = 0x1275; + strcpy(ns.name, "PowerPC"); + ns.load_base = -1; + write( 1, &ns, sizeof(struct desc)); + return 0; +} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/no_initrd.c linux/arch/ppc/chrpboot/no_initrd.c --- v2.1.78/linux/arch/ppc/chrpboot/no_initrd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/no_initrd.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,2 @@ +char initrd_data[1]; +int initrd_len = 0; diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/nonstdio.h linux/arch/ppc/chrpboot/nonstdio.h --- v2.1.78/linux/arch/ppc/chrpboot/nonstdio.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/nonstdio.h Mon Jan 12 15:18:13 1998 @@ -0,0 +1,18 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +typedef int FILE; +extern FILE *stdin, *stdout; +#define NULL ((void *)0) +#define EOF (-1) +#define fopen(n, m) NULL +#define fflush(f) 0 +#define fclose(f) 0 +extern char *fgets(); + +#define perror(s) printf("%s: no files!\n", (s)) diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/piggyback.c linux/arch/ppc/chrpboot/piggyback.c --- v2.1.78/linux/arch/ppc/chrpboot/piggyback.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/piggyback.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,65 @@ +#include + +extern long ce_exec_config[]; + +main(int argc, char *argv[]) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[8192]; + if (argc != 2) + { + fprintf(stderr, "usage: %s name out-file\n", + argv[0]); + exit(1); + } + fprintf(stdout, "#\n"); + fprintf(stdout, "# Miscellaneous data structures:\n"); + fprintf(stdout, "# WARNING - this file is automatically generated!\n"); + fprintf(stdout, "#\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\t.data\n"); + fprintf(stdout, "\t.globl %s_data\n", argv[1]); + fprintf(stdout, "%s_data:\n", argv[1]); + pos = 0; + cksum = 0; + while ((len = read(0, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + fprintf(stdout, "\t.long\t"); + } + fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + fprintf(stdout, " # %x \n", pos+i-12); + fflush(stdout); + } else + { + fprintf(stdout, ","); + } + } + if (cnt) + { + fprintf(stdout, "0\n"); + } + pos += len; + } + fprintf(stdout, "\t.globl %s_len\n", argv[1]); + fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); + fflush(stdout); + fclose(stdout); + fprintf(stderr, "cksum = %x\n", cksum); + exit(0); +} + diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/start.c linux/arch/ppc/chrpboot/start.c --- v2.1.78/linux/arch/ppc/chrpboot/start.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/start.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,282 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include + +int (*prom)(); + +void *chosen_handle; +void *stdin; +void *stdout; +void *stderr; + +void exit(void); +void *finddevice(const char *name); +int getprop(void *phandle, const char *name, void *buf, int buflen); + +void printk(char *fmt, ...); + +void +start(int a1, int a2, void *promptr) +{ + prom = (int (*)()) 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(); +} + +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; +} + +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; +} + +void +exit() +{ + struct prom_args { + char *service; + } args; + + for (;;) { + args.service = "exit"; + (*prom)(&args); + } +} + +void +pause() +{ + struct prom_args { + char *service; + } 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; +} + +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; +} + +int +putc(int c, void *f) +{ + char ch = c; + + if (c == '\n') + putc('\r', f); + return write(f, &ch, 1) == 1? c: -1; +} + +int +putchar(int c) +{ + return putc(c, stdout); +} + +int +fputs(char *str, void *f) +{ + int n = strlen(str); + + return write(f, str, n) == n? 0: -1; +} + +int +readchar() +{ + char ch; + + 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]; +static char *lineptr; +static int lineleft; + +int +getchar() +{ + 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; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +extern int vsprintf(char *buf, const char *fmt, va_list args); +static char sprint_buf[1024]; + +void +printk(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + write(stdout, sprint_buf, n); +} + +int +printf(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + write(stdout, sprint_buf, n); + return n; +} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/string.S linux/arch/ppc/chrpboot/string.S --- v2.1.78/linux/arch/ppc/chrpboot/string.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/string.S Mon Jan 12 15:18:13 1998 @@ -0,0 +1,206 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * 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. + */ +#define r0 0 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 + + .globl strcpy +strcpy: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strncpy +strncpy: + cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + blr + + .globl strcat +strcat: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r5) + cmpwi 0,r0,0 + bne 1b + addi r5,r5,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strcmp +strcmp: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r5) + cmpwi 1,r3,0 + lbzu r0,1(r4) + subf. r3,r0,r3 + beqlr 1 + beq 1b + blr + + .globl strlen +strlen: + addi r4,r3,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + bne 1b + subf r3,r3,r4 + blr + + .globl memset +memset: + rlwimi r4,r4,8,16,23 + rlwimi r4,r4,16,0,15 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + rlwinm r0,r5,32-2,2,31 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + + .globl bcopy +bcopy: + mr r6,r3 + mr r3,r4 + mr r4,r6 + b memcpy + + .globl memmove +memmove: + cmplw 0,r3,r4 + bgt backwards_memcpy + /* fall through */ + + .globl memcpy +memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl backwards_memcpy +backwards_memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl memcmp +memcmp: + cmpwi 0,r5,0 + blelr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r6) + lbzu r0,1(r4) + subf. r3,r0,r3 + bdnzt 2,1b + blr diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/zlib.c linux/arch/ppc/chrpboot/zlib.c --- v2.1.78/linux/arch/ppc/chrpboot/zlib.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/zlib.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,2143 @@ +/* + * This file is derived from various .h and .c files from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. See zlib.h for conditions of + * distribution and use. + * + * Changes that have been made include: + * - changed functions not used outside this file to "local" + * - added minCompression parameter to deflateInit2 + * - added Z_PACKET_FLUSH (see zlib.h for details) + * - added inflateIncomp + * + * $Id: zlib.c,v 1.1 1997/09/19 07:03:44 paulus Exp $ + */ + +/*+++++*/ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */ + +#define _Z_UTIL_H + +#include "zlib.h" + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#define FAR + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern char *z_errmsg[]; /* indexed by 1-zlib_error */ + +#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err) +/* To be used only when the state is known to be valid */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + + /* common constants */ + +#define DEFLATED 8 + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + + /* functions */ + +#include +#define zmemcpy memcpy +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include +# ifndef verbose +# define verbose 0 +# endif +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len)); + +/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */ +/* void zcfree OF((voidpf opaque, voidpf ptr)); */ + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr, size) \ + (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size)) +#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);} + +/* deflate.h -- internal compression state + * Copyright (C) 1995 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/*+++++*/ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +local inflate_blocks_statef * inflate_blocks_new OF(( + z_stream *z, + check_func c, /* check function */ + uInt w)); /* window size */ + +local int inflate_blocks OF(( + inflate_blocks_statef *, + z_stream *, + int)); /* initial return code */ + +local void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_stream *, + uLongf *)); /* check value on output */ + +local int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_stream *, + uLongf *)); /* check value on output */ + +local int inflate_addhistory OF(( + inflate_blocks_statef *, + z_stream *)); + +local int inflate_packet_flush OF(( + inflate_blocks_statef *)); + +/*+++++*/ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt Nalloc; /* number of these allocated here */ + Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit machines) */ + union { + uInt Base; /* literal, length base, or distance base */ + inflate_huft *Next; /* pointer to next level of table */ + } more; +}; + +#ifdef DEBUG_ZLIB + local uInt inflate_hufts; +#endif + +local int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + z_stream *)); /* for zalloc, zfree functions */ + +local int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_stream *)); /* for zalloc, zfree functions */ + +local int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *)); /* distance tree result */ + +local int inflate_trees_free OF(( + inflate_huft *, /* tables to free */ + z_stream *)); /* for zfree function */ + + +/*+++++*/ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +local inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_stream *)); + +local int inflate_codes OF(( + inflate_blocks_statef *, + z_stream *, + int)); + +local void inflate_codes_free OF(( + inflate_codes_statef *, + z_stream *)); + + +/*+++++*/ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* inflate private state */ +struct internal_state { + + /* mode */ + enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ + mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z) +z_stream *z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, &c); + Trace((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z) +z_stream *z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z, &c); + ZFREE(z, z->state, sizeof(struct internal_state)); + z->state = Z_NULL; + Trace((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2(z, w) +z_stream *z; +int w; +{ + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; +/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */ +/* if (z->zfree == Z_NULL) z->zfree = zcfree; */ + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Trace((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit(z) +z_stream *z; +{ + return inflateInit2(z, DEF_WBITS); +} + + +#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z, f) +z_stream *z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED) + { + z->state->mode = BAD; + z->msg = "unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = "invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + if ((b = NEXTBYTE) & 0x20) + { + z->state->mode = BAD; + z->msg = "invalid reserved bit"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = "incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib header ok\n")); + z->state->mode = BLOCKS; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) + r = inflate_packet_flush(z->state->blocks); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r != Z_STREAM_END) + return r; + r = Z_OK; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = "incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + + empty: + if (f != Z_PACKET_FLUSH) + return r; + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_DATA_ERROR; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ + +int inflateIncomp(z) +z_stream *z; +{ + if (z->state->mode != BLOCKS) + return Z_DATA_ERROR; + return inflate_addhistory(z->state->blocks, z); +} + + +int inflateSync(z) +z_stream *z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + if (*p == (Byte)(m < 2 ? 0 : 0xff)) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + +#undef NEEDBYTE +#undef NEXTBYTE + +/*+++++*/ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONEB, /* finished last block, done */ + BADB} /* got a data error--stuck here */ + mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + int nblens; /* # elements allocated at blens */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_huft *tl, *td; /* trees to free */ + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* And'ing with mask[n] masks the lower n bits */ +local uInt inflate_mask[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush OF(( + inflate_blocks_statef *, + z_stream *, + int)); + +/*+++++*/ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_stream *)); + + +/*+++++*/ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* Table for deflate from PKZIP's appnote.txt. */ +local uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +local void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_stream *z; +uLongf *c; +{ + if (s->checkfn != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + if (s->mode == CODES) + { + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + } + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(0L, Z_NULL, 0); + Trace((stderr, "inflate: blocks reset\n")); +} + + +local inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_stream *z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s, sizeof(struct inflate_blocks_state)); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Trace((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, &s->check); + return s; +} + + +local int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Trace((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Trace((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.tl = Z_NULL; /* don't try to free these */ + s->sub.decode.td = Z_NULL; + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Trace((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BADB; + z->msg = "invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if (((~b) >> 16) != (b & 0xffff)) + { + s->mode = BADB; + z->msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : TYPE; + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BADB; + z->msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (t < 19) + t = 19; + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.trees.nblens = t; + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, z); + if (t != Z_OK) + { + r = t; + if (r == Z_DATA_ERROR) + s->mode = BADB; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->word.what.Bits; + c = h->more.Base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + s->mode = BADB; + z->msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + inflate_trees_free(s->sub.trees.tb, z); + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BADB; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + inflate_trees_free(td, z); + inflate_trees_free(tl, z); + r = Z_MEM_ERROR; + LEAVE + } + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONEB; + case DONEB: + r = Z_STREAM_END; + LEAVE + case BADB: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +local int inflate_blocks_free(s, z, c) +inflate_blocks_statef *s; +z_stream *z; +uLongf *c; +{ + inflate_blocks_reset(s, z, c); + ZFREE(z, s->window, s->end - s->window); + ZFREE(z, s, sizeof(struct inflate_blocks_state)); + Trace((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ +local int inflate_addhistory(s, z) +inflate_blocks_statef *s; +z_stream *z; +{ + uLong b; /* bit buffer */ /* NOT USED HERE */ + uInt k; /* bits in bit buffer */ /* NOT USED HERE */ + uInt t; /* temporary storage */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + if (s->read != s->write) + return Z_STREAM_ERROR; + if (s->mode != TYPE) + return Z_DATA_ERROR; + + /* we're ready to rock */ + LOAD + /* while there is input ready, copy to output buffer, moving + * pointers as needed. + */ + while (n) { + t = n; /* how many to do */ + /* is there room until end of buffer? */ + if (t > m) t = m; + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, t); + zmemcpy(q, p, t); + q += t; + p += t; + n -= t; + z->total_out += t; + s->read = q; /* drag read pointer forward */ +/* WRAP */ /* expand WRAP macro by hand to handle s->read */ + if (q == s->end) { + s->read = q = s->window; + m = WAVAIL; + } + } + UPDATE + return Z_OK; +} + + +/* + * At the end of a Deflate-compressed PPP packet, we expect to have seen + * a `stored' block type value but not the (zero) length bytes. + */ +local int inflate_packet_flush(s) + inflate_blocks_statef *s; +{ + if (s->mode != LENS) + return Z_DATA_ERROR; + s->mode = TYPE; + return Z_OK; +} + + +/*+++++*/ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + uIntf *, /* list of base values for non-simple codes */ + uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + z_stream *)); /* for zalloc function */ + +local voidpf falloc OF(( + voidpf, /* opaque pointer (not used) */ + uInt, /* number of items */ + uInt)); /* size of item */ + +local void ffree OF(( + voidpf q, /* opaque pointer (not used) */ + voidpf p, /* what to free (not used) */ + uInt n)); /* number of bytes (not used) */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* actually lengths - 2; also see note #13 above about 258 */ +local uInt cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */ +local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local uInt cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ +#define N_MAX 288 /* maximum number of codes in any set */ + +#ifdef DEBUG_ZLIB + uInt inflate_hufts; +#endif + +local int huft_build(b, n, s, d, e, t, m, zs) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= N_MAX) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +uIntf *d; /* list of base values for non-simple codes */ +uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +z_stream *zs; /* for zalloc function */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (all zero length codes or an + over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + uInt v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (inflate_huft *)ZALLOC + (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) + { + if (h) + inflate_trees_free(u[0], zs); + return Z_MEM_ERROR; /* not enough memory */ + } + q->word.Nalloc = z + 1; +#ifdef DEBUG_ZLIB + inflate_hufts += z + 1; +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->next)) = Z_NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + r.next = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +local int inflate_trees_bits(c, bb, tb, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +z_stream *z; /* for zfree function */ +{ + int r; + + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR) + { + inflate_trees_free(*tb, z); + z->msg = "incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + return r; +} + + +local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_stream *z; /* for zfree function */ +{ + int r; + + /* build literal/length tree */ + if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK) + { + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed literal/length tree"; + else if (r == Z_BUF_ERROR) + { + inflate_trees_free(*tl, z); + z->msg = "incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + return r; + } + + /* build distance tree */ + if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK) + { + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed literal/length tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + inflate_trees_free(*td, z); + z->msg = "incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + inflate_trees_free(*tl, z); + return r; +#endif + } + + /* done */ + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +local int fixed_lock = 0; +local int fixed_built = 0; +#define FIXEDH 530 /* number of hufts used by fixed tables */ +local uInt fixed_left = FIXEDH; +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; + + +local voidpf falloc(q, n, s) +voidpf q; /* opaque pointer (not used) */ +uInt n; /* number of items */ +uInt s; /* size of item */ +{ + Assert(s == sizeof(inflate_huft) && n <= fixed_left, + "inflate_trees falloc overflow"); + if (q) s++; /* to make some compilers happy */ + fixed_left -= n; + return (voidpf)(fixed_mem + fixed_left); +} + + +local void ffree(q, p, n) +voidpf q; +voidpf p; +uInt n; +{ + Assert(0, "inflate_trees ffree called!"); + if (q) q = p; /* to make some compilers happy */ +} + + +local int inflate_trees_fixed(bl, bd, tl, td) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +{ + /* build fixed tables if not built already--lock out other instances */ + while (++fixed_lock > 1) + fixed_lock--; + if (!fixed_built) + { + int k; /* temporary variable */ + unsigned c[288]; /* length list for huft_build */ + z_stream z; /* for falloc function */ + + /* set up fake z_stream for memory routines */ + z.zalloc = falloc; + z.zfree = ffree; + z.opaque = Z_NULL; + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 7; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + + /* done */ + fixed_built = 1; + } + fixed_lock--; + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +local int inflate_trees_free(t, z) +inflate_huft *t; /* table to free */ +z_stream *z; /* for zfree function */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register inflate_huft *p, *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != Z_NULL) + { + q = (--p)->next; + ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft)); + p = q; + } + return Z_OK; +} + +/*+++++*/ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ + mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl, *td; +z_stream *z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +local int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = "invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +local void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_stream *z; +{ + ZFREE(z, c, sizeof(struct inflate_codes_state)); + Tracev((stderr, "inflate: codes free\n")); +} + +/*+++++*/ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt n; + Bytef *p, *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + + +/*+++++*/ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +local int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl, *td; +inflate_blocks_statef *s; +z_stream *z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + else + { + z->msg = "invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = "invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + + +/*+++++*/ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */ + +char *zlib_version = ZLIB_VERSION; + +char *z_errmsg[] = { +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +""}; + + +/*+++++*/ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf) {s1 += *buf++; s2 += s1;} +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); +#define DO16(buf) DO8(buf); DO8(buf); + +/* ========================================================================= */ +uLong adler32(adler, buf, len) + uLong adler; + Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + k -= 16; + } + if (k != 0) do { + DO1(buf); + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/chrpboot/zlib.h linux/arch/ppc/chrpboot/zlib.h --- v2.1.78/linux/arch/ppc/chrpboot/zlib.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/zlib.h Mon Jan 12 15:18:13 1998 @@ -0,0 +1,432 @@ +/* $Id: zlib.h,v 1.1 1997/09/19 07:03:47 paulus Exp $ */ + +/* + * This file is derived from zlib.h and zconf.h from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. + */ + +/* + * ==FILEVERSION 960122== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 0.95, Aug 16th, 1995. + + Copyright (C) 1995 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + */ + +#ifndef _ZLIB_H +#define _ZLIB_H + +/* #include "zconf.h" */ /* included directly here */ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */ + +/* + The library does not install any signal handler. It is recommended to + add at least a handler for SIGSEGV when decompressing; the library checks + the consistency of the input data whenever possible but may go nuts + for some forms of corrupted input. + */ + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints + * at addresses which are not a multiple of their size. + * Under DOS, -DFAR=far or -DFAR=__far may be needed. + */ + +#ifndef STDC +# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus) +# define STDC +# endif +#endif + +#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */ +# include +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +#ifndef FAR +# define FAR +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + 1 << (windowBits+2) + 1 << (memLevel+9) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +typedef Byte FAR Bytef; +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +/* end of original zconf.h */ + +#define ZLIB_VERSION "0.95P" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms may be added later and will have the same + stream interface. + + For compression the application must provide the output buffer and + may optionally provide the input buffer for optimization. For decompression, + the application must provide the input buffer and may optionally provide + the output buffer for optimization. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidp opaque; /* private data object passed to zalloc and zfree */ + + Byte data_type; /* best guess about the data type: ascii or binary */ + +} z_stream; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_FULL_FLUSH 2 +#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */ +#define Z_FINISH 4 +#define Z_PACKET_FLUSH 5 +/* See deflate() below for the usage of these constants */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +/* error codes for the compression/decompression functions */ + +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Used to set the data_type field */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +extern char *zlib_version; +/* The application can compare zlib_version and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + */ + + /* basic functions */ + +extern int inflateInit OF((z_stream *strm)); +/* + Initializes the internal stream state for decompression. The fields + zalloc and zfree must be initialized before by the caller. If zalloc and + zfree are set to Z_NULL, inflateInit updates them to use default allocation + functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory. msg is set to null if there is no error message. + inflateInit does not perform any decompression: this will be done by + inflate(). +*/ + + +extern int inflate OF((z_stream *strm, int flush)); +/* + Performs one or both of the following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() always provides as much output as possible + (until there is no more input data or no more space in the output buffer). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). + + If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, + inflate flushes as much output as possible to the output buffer. The + flushing behavior of inflate is not specified for values of the flush + parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the + current implementation actually flushes as much output as possible + anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data + has been consumed, it is expecting to see the length field of a stored + block; if not, it returns Z_DATA_ERROR. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + inflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if the end of the + compressed data has been reached and all uncompressed output has been + produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if + the stream structure was inconsistent (for example if next_in or next_out + was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no + progress is possible or if there was not enough room in the output buffer + when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then + call inflateSync to look for a good compression block. */ + + +extern int inflateEnd OF((z_stream *strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* advanced functions */ + +extern int inflateInit2 OF((z_stream *strm, + int windowBits)); +/* + This is another version of inflateInit with more compression options. The + fields next_out, zalloc and zfree must be initialized before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library (the value 16 will be allowed soon). The + default value is 15 if inflateInit is used instead. If a compressed stream + with a larger window size is given as input, inflate() will return with + the error code Z_DATA_ERROR instead of trying to allocate a larger window. + + If next_out is not null, the library will use this buffer for the history + buffer; the buffer must either be large enough to hold the entire output + data, or have at least 1<zImage +znetboot.initrd: vmlinux.gz -hack-coff: hack-coff.c - $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c +coffboot: vmlinux.gz + +zImage: vmlinux.gz + +zImage.initrd: vmlinux.gz + +vmlinux.coff: vmlinux.gz + +vmlinux.coff.initrd: vmlinux.gz + +floppy: vmlinux.gz + + + +endif -elfextract: elfextract.c - $(HOSTCC) $(HOSTCFLAGS) -o elfextract elfextract.c +vmlinux.gz: $(TOPDIR)/vmlinux + $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux + gzip -vf9 vmlinux clean: - rm -f elfextract hack-coff coffboot zImage vmlinux.coff + rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz fastdep: diff -u --recursive --new-file v2.1.78/linux/arch/ppc/coffboot/elfextract.c linux/arch/ppc/coffboot/elfextract.c --- v2.1.78/linux/arch/ppc/coffboot/elfextract.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/coffboot/elfextract.c Wed Dec 31 16:00:00 1969 @@ -1,98 +0,0 @@ -/* - * Extract the loadable program segment from an elf file. - * - * Copyright 1996 Paul Mackerras. - * - * 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. - */ -#include -#include - -FILE *fi, *fo; -char *ni, *no; -char buf[65536]; - -void -rd(void *buf, int len) -{ - int nr; - - nr = fread(buf, 1, len, fi); - if (nr == len) - return; - if (ferror(fi)) - fprintf(stderr, "%s: read error\n", ni); - else - fprintf(stderr, "%s: short file\n", ni); - exit(1); -} - -main(int ac, char **av) -{ - unsigned nb, len; - Elf32_Ehdr eh; - Elf32_Phdr ph; - - if (ac > 3 || ac > 1 && av[1][0] == '-') { - fprintf(stderr, "Usage: %s [elf-file [image-file]]\n", av[0]); - exit(0); - } - - fi = stdin; - ni = "(stdin)"; - fo = stdout; - no = "(stdout)"; - - if (ac > 1) { - ni = av[1]; - fi = fopen(ni, "rb"); - if (fi == NULL) { - perror(ni); - exit(1); - } - } - - rd(&eh, sizeof(eh)); - if (eh.e_ident[EI_MAG0] != ELFMAG0 - || eh.e_ident[EI_MAG1] != ELFMAG1 - || eh.e_ident[EI_MAG2] != ELFMAG2 - || eh.e_ident[EI_MAG3] != ELFMAG3) { - fprintf(stderr, "%s: not an ELF file\n", ni); - exit(1); - } - - fseek(fi, eh.e_phoff + (eh.e_phnum - 1) * sizeof(ph), 0); - rd(&ph, sizeof(ph)); - if (ph.p_type != PT_LOAD) { - fprintf(stderr, "%s: doesn't have a loadable segment\n", ni); - exit(1); - } - - if (ac > 2) { - no = av[2]; - fo = fopen(no, "wb"); - if (fo == NULL) { - perror(no); - exit(1); - } - } - - fseek(fi, ph.p_offset, 0); - for (len = ph.p_filesz; len != 0; len -= nb) { - nb = len; - if (nb > sizeof(buf)) - nb = sizeof(buf); - rd(buf, nb); - if (fwrite(buf, 1, nb, fo) != nb) { - fprintf(stderr, "%s: write error\n", no); - exit(1); - } - } - - fclose(fo); - fclose(fi); - exit(0); -} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/coffboot/start.c linux/arch/ppc/coffboot/start.c --- v2.1.78/linux/arch/ppc/coffboot/start.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/coffboot/start.c Mon Jan 12 15:18:13 1998 @@ -18,6 +18,7 @@ void exit(void); void *finddevice(const char *name); int getprop(void *phandle, const char *name, void *buf, int buflen); +void printk(char *fmt, ...); void start(int a1, int a2, void *promptr) diff -u --recursive --new-file v2.1.78/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.1.78/linux/arch/ppc/config.in Thu Dec 4 14:53:54 1997 +++ linux/arch/ppc/config.in Mon Jan 12 15:18:13 1998 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.19 1997/09/04 01:54:26 davem Exp $ +# $Id: config.in,v 1.36 1997/12/29 21:36:52 geert Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -7,13 +7,13 @@ mainmenu_option next_comment comment 'Platform support' define_bool CONFIG_PPC y - if [ "`uname`" != "Linux" -o "`uname -m`" != "ppc" ]; then define_bool CONFIG_CROSSCOMPILE y else define_bool CONFIG_NATIVE y fi +define_bool CONFIG_MACH_SPECIFIC y bool 'Build PowerMac Kernel (not PReP or CHRP)?' CONFIG_PMAC bool 'Build PReP Kernel (not PowerMac or CHRP)?' CONFIG_PREP bool 'Build CHRP Kernel (not PReP or PowerMac)?' CONFIG_CHRP @@ -39,9 +39,11 @@ if [ "$CONFIG_PREP" = "y" ]; then bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE fi +bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC bool 'Networking support' CONFIG_NET bool 'Sysctl support' CONFIG_SYSCTL bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT # only elf supported, a.out is not -- Cort define_bool CONFIG_BINFMT_ELF y @@ -49,39 +51,77 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'New unified console driver (EXPERIMENTAL)' CONFIG_ABSTRACT_CONSOLE +fi + if [ "$CONFIG_PMAC" = "y" ]; then - define_bool CONFIG_PMAC_CONSOLE y + if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then + define_bool CONFIG_FB y + bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC + else + define_bool CONFIG_PMAC_CONSOLE y + fi define_bool CONFIG_MAC_KEYBOARD y define_bool CONFIG_MAC_FLOPPY y - bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE - bool 'Include xmon kernel debugger' CONFIG_XMON +else +# if compiling specifically for prep or chrp, or supporting all arch's + if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then + bool 'Support for frame buffer devices' CONFIG_FB + bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC + else + bool 'Support for PowerMac console' CONFIG_PMAC_CONSOLE + fi + bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD + bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Support for PowerMac mouse (EXPERIMENTAL)' CONFIG_MACMOUSE fi +bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE +bool 'Include xmon kernel debugger' CONFIG_XMON -if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then - bool 'Support for ATI Mach64 display cards' CONFIG_ATY_VIDEO - bool 'Support for IMS Twin Turbo display card' CONFIG_IMSTT_VIDEO +if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then + if [ "$CONFIG_FB" != "y" ]; then + define_bool CONFIG_VGA_CONSOLE y + fi else - define_bool CONFIG_VGA_CONSOLE y + if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then + bool 'Support for Apple "control" display' CONFIG_CONTROL_VIDEO + bool 'Support for Apple "platinum" display' CONFIG_PLATINUM_VIDEO + bool 'Support for Apple "valkyrie" display' CONFIG_VALKYRIE_VIDEO + bool 'Support for ATI Mach64 display cards' CONFIG_ATY_VIDEO + bool 'Support for IMS Twin Turbo display card' CONFIG_IMSTT_VIDEO + bool 'Support for Chips 65550 display' CONFIG_CHIPS_VIDEO + else + define_bool CONFIG_VGA_CONSOLE y + fi fi endmenu source drivers/pnp/Config.in source drivers/block/Config.in +source drivers.new/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi mainmenu_option next_comment comment 'SCSI support' + tristate 'SCSI support' CONFIG_SCSI + if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in fi endmenu - if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment comment 'Network device support' - source net/Config.in + bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in @@ -93,6 +133,7 @@ mainmenu_option next_comment comment 'ISDN subsystem' + tristate 'ISDN support' CONFIG_ISDN if [ "$CONFIG_ISDN" != "n" ]; then source drivers/isdn/Config.in @@ -101,6 +142,7 @@ mainmenu_option next_comment comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' + bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then source drivers/cdrom/Config.in @@ -122,22 +164,17 @@ source fs/nls/Config.in +if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then + source drivers/video/Config.in +fi + source drivers/char/Config.in mainmenu_option next_comment comment 'Sound' + tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then source drivers/sound/Config.in fi endmenu - -#mainmenu_option next_comment -#comment 'Kernel hacking' -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -#bool 'Kernel profiling support' CONFIG_PROFILE -#if [ "$CONFIG_PROFILE" = "y" ]; then -# int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 -#fi -#endmenu - diff -u --recursive --new-file v2.1.78/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.1.78/linux/arch/ppc/defconfig Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/defconfig Mon Jan 12 15:18:13 1998 @@ -7,9 +7,11 @@ # CONFIG_PPC=y CONFIG_NATIVE=y +CONFIG_MACH_SPECIFIC=y # CONFIG_PMAC is not set CONFIG_PREP=y -CONFIG_MCOMMON=y +# CONFIG_CHRP is not set +CONFIG_COMMON=y # # General setup @@ -19,14 +21,21 @@ CONFIG_MODVERSIONS=y CONFIG_KERNELD=y CONFIG_PCI=y -CONFIG_PCI_OPTIMIZE=y +# CONFIG_PCI_OPTIMIZE is not set +CONFIG_PCI_OLD_PROC=y CONFIG_NET=y -CONFIG_SYSCTL=y +# CONFIG_SYSCTL is not set CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_BINFMT_JAVA is not set +# CONFIG_PMAC_CONSOLE is not set +# CONFIG_MAC_KEYBOARD is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_XMON is not set CONFIG_VGA_CONSOLE=y # @@ -49,7 +58,8 @@ # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_TRITON is not set # CONFIG_IDE_CHIPSETS is not set -CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y @@ -58,6 +68,45 @@ # CONFIG_BLK_DEV_HD is not set # +# NEW devices (io_request, all ALPHA and dangerous) +# +# CONFIG_IO_REQUEST is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ACCT is not set +# CONFIG_IP_MASQUERADE is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_RARP=y +# CONFIG_IP_NOSR is not set +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_AX25 is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_CPU_IS_SLOW is not set +# CONFIG_NET_SCHED is not set + +# # SCSI support # CONFIG_SCSI=y @@ -67,7 +116,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set # CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_CONSTANTS is not set # # SCSI low-level drivers @@ -111,46 +160,13 @@ # # Network device support # - -# -# Networking options -# -# CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ACCT is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_XTP is not set -# CONFIG_INET_PCTCP is not set -# CONFIG_INET_RARP is not set -CONFIG_PATH_MTU_DISCOVERY=y -# CONFIG_IP_NOSR is not set -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_AX25 is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_WAN_ROUTER is not set CONFIG_NETDEVICES=y # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set CONFIG_NET_ETHERNET=y -CONFIG_NET_VENDOR_3COM=y -# CONFIG_EL1 is not set -# CONFIG_EL2 is not set -# CONFIG_ELPLUS is not set -# CONFIG_EL16 is not set -CONFIG_EL3=y -# CONFIG_VORTEX is not set +# CONFIG_NET_VENDOR_3COM is not set CONFIG_LANCE=y # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set @@ -171,7 +187,7 @@ # CONFIG_FDDI is not set # CONFIG_DLCI is not set # CONFIG_PLIP is not set -CONFIG_PPP=y +CONFIG_PPP=m # CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set # CONFIG_TR is not set @@ -193,25 +209,30 @@ # CONFIG_QUOTA is not set # CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_VFAT_FS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET 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_PROC_FS=y CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y +# CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set -CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_ROMFS_FS is not set # CONFIG_AUTOFS_FS is not set # CONFIG_UFS_FS is not set -CONFIG_MAC_PARTITION=y +# CONFIG_MAC_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set # # Character devices @@ -241,6 +262,8 @@ # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_BT848 is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set diff -u --recursive --new-file v2.1.78/linux/arch/ppc/ignore linux/arch/ppc/ignore --- v2.1.78/linux/arch/ppc/ignore Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/ignore Wed Dec 31 16:00:00 1969 @@ -1,65 +0,0 @@ -.config -compile.h -.version -.objects -.blurb -*.cort -*.paul -*.old -.defines -version.h -find_name -checks -#* -.objects -.object_files -System.map -asm -.menuconfig* -CVS -ppc_defs.h -mk_defs -mkprep -*.s -.depend -.hdepend -*~ -*.o -znetboot -zvmlinux -vmlinux -zImage -hack-coff -coffboot -vmlinux.coff -.depend -.cvsignore -RCS -SCCS -CVS.adm -RCSLOG -cvslog.* -tags -TAGS -.make.state -.nse_depinfo -*~ -#* -.#* -,* -_$* -*$ -*.old -*.bak -*.BAK -*.orig -*.rej -*.a -*.olb -*.o -*.obj -*.so -*.exe -*.Z -*.elc -*.ln diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.1.78/linux/arch/ppc/kernel/Makefile Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/Makefile Mon Jan 12 15:18:13 1998 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.o: - $(CC) -D__ASSEMBLY__ -c $< -o $*.o + $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o O_TARGET := kernel.o O_OBJS := misc.o traps.o process.o signal.o syscalls.o \ @@ -19,6 +19,10 @@ residual.o prom.o OX_OBJS := ppc_ksyms.o +ifdef SMP +O_OBJS += smp.o +endif + all: head.o kernel.o head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h @@ -33,8 +37,11 @@ grep '^#define' mk_defs.s >>ppc_defs.h rm mk_defs.s +find_name : find_name.c + $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o find_name find_name.c + checks: checks.c - $(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c + $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c ./checks include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/checks.c linux/arch/ppc/kernel/checks.c --- v2.1.78/linux/arch/ppc/kernel/checks.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/checks.c Mon Jan 12 15:18:13 1998 @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.1.78/linux/arch/ppc/kernel/chrp_pci.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/chrp_pci.c Mon Jan 12 15:18:13 1998 @@ -13,11 +13,17 @@ #include #include #include +#include +#include /* LongTrail */ #define pci_config_addr(bus, dev, offset) \ - (0xfec00000 | ((bus)<<16) | ((dev)<<8) | (offset)) + (GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset)) +volatile struct Hydra *Hydra = NULL; + + +#if 1 int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { @@ -45,6 +51,7 @@ return PCIBIOS_SUCCESSFUL; } + int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { @@ -77,80 +84,207 @@ int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { - if (bus > 7) + if (bus > 7) return PCIBIOS_DEVICE_NOT_FOUND; out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val); return PCIBIOS_SUCCESSFUL; } +#else +volatile unsigned int *pci_config_address=(volatile unsigned int *)0xfec00cf8; +volatile unsigned char *pci_config_data=(volatile unsigned char *)0xfee00cfc; + +#define DEV_FN_MAX (31<<3) + +int chrp_pcibios_read_config_byte(unsigned char bus, + unsigned char dev_fn, + unsigned char offset, + unsigned char *val) +{ + if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; + out_be32(pci_config_address, + 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); + *val = in_8(pci_config_data+(offset&3)); + return PCIBIOS_SUCCESSFUL; +} -int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr) -{ - int num, devfn; - unsigned int x, vendev; - - if (vendor == 0xffff) - return PCIBIOS_BAD_VENDOR_ID; - vendev = (dev_id << 16) + vendor; - num = 0; - for (devfn = 0; devfn < 32; devfn++) { - chrp_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x); - if (x == vendev) { - if (index == num) { - *bus_ptr = 0; - *dev_fn_ptr = devfn<<3; - return PCIBIOS_SUCCESSFUL; - } - ++num; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; +int chrp_pcibios_read_config_word(unsigned char bus, + unsigned char dev_fn, + unsigned char offset, + unsigned short *val) +{ + if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; + if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER; + out_be32(pci_config_address, + 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); + *val = in_le16((volatile unsigned short *) + (pci_config_data+(offset&3))); + return PCIBIOS_SUCCESSFUL; } -int chrp_pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr) +int chrp_pcibios_read_config_dword(unsigned char bus, + unsigned char dev_fn, + unsigned char offset, + unsigned int *val) { - int devnr, x, num; + if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; + if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER; + out_be32(pci_config_address, + 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24)); + *val = in_le32((volatile unsigned int *)(pci_config_data)); + return PCIBIOS_SUCCESSFUL; +} - num = 0; - for (devnr = 0; devnr < 32; devnr++) { - chrp_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x); - if ((x>>8) == class_code) { - if (index == num) { - *bus_ptr = 0; - *dev_fn_ptr = devnr<<3; - return PCIBIOS_SUCCESSFUL; - } - ++num; +int chrp_pcibios_write_config_byte(unsigned char bus, + unsigned char dev_fn, + unsigned char offset, + unsigned char val) +{ + if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; + out_be32(pci_config_address, + 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); + out_8(pci_config_data+(offset&3),val); + return PCIBIOS_SUCCESSFUL; +} + +int chrp_pcibios_write_config_word(unsigned char bus, + unsigned char dev_fn, + unsigned char offset, + unsigned short val) +{ + if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; + if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER; + out_be32(pci_config_address, + 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); + out_le16((volatile unsigned short *)(pci_config_data+(offset&3)),val); + return PCIBIOS_SUCCESSFUL; +} + +int chrp_pcibios_write_config_dword(unsigned char bus, + unsigned char dev_fn, + unsigned char offset, + unsigned int val) +{ + if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; + if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER; + out_be32(pci_config_address, + 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24)); + out_le32((volatile unsigned int *)pci_config_data,val); + return PCIBIOS_SUCCESSFUL; +} +#endif + + /* + * Temporary fixes for PCI devices. These should be replaced by OF query + * code -- Geert + */ + +static u_char hydra_openpic_initsenses[] __initdata = { + 1, /* HYDRA_INT_SIO */ + 0, /* HYDRA_INT_SCSI_DMA */ + 0, /* HYDRA_INT_SCCA_TX_DMA */ + 0, /* HYDRA_INT_SCCA_RX_DMA */ + 0, /* HYDRA_INT_SCCB_TX_DMA */ + 0, /* HYDRA_INT_SCCB_RX_DMA */ + 1, /* HYDRA_INT_SCSI */ + 1, /* HYDRA_INT_SCCA */ + 1, /* HYDRA_INT_SCCB */ + 1, /* HYDRA_INT_VIA */ + 1, /* HYDRA_INT_ADB */ + 0, /* HYDRA_INT_ADB_NMI */ + /* all others are 1 (= default) */ +}; + +__initfunc(int hydra_init(void)) +{ + struct device_node *np; + + np = find_devices("mac-io"); + if (np == NULL || np->n_addrs == 0) { + printk(KERN_WARNING "Warning: no mac-io found\n"); + return 0; } - } - return PCIBIOS_DEVICE_NOT_FOUND; + Hydra = ioremap(np->addrs[0].address, np->addrs[0].size); + printk("Hydra Mac I/O at %x\n", np->addrs[0].address); + out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN | + HYDRA_FC_SCSI_CELL_EN | + HYDRA_FC_SCCA_ENABLE | + HYDRA_FC_SCCB_ENABLE | + HYDRA_FC_ARB_BYPASS | + HYDRA_FC_MPIC_ENABLE | + HYDRA_FC_SLOW_SCC_PCLK | + HYDRA_FC_MPIC_IS_MASTER)); + OpenPIC = (volatile struct OpenPIC *)&Hydra->OpenPIC; + OpenPIC_InitSenses = hydra_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses); + return 1; } -__initfunc(volatile struct Hydra *find_hydra(void)) + +extern int chrp_ide_irq; + +__initfunc(int w83c553f_init(void)) { u_char bus, dev; - volatile struct Hydra *hydra = 0; - if (chrp_pcibios_find_device(PCI_VENDOR_ID_APPLE, - PCI_DEVICE_ID_APPLE_HYDRA, 0, &bus, &dev) - == PCIBIOS_SUCCESSFUL) - chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, - (unsigned int *)&hydra); - return hydra; -} - -__initfunc(void hydra_post_openpic_init(void)) -{ - openpic_set_sense(HYDRA_INT_SCSI_DMA, 0); - openpic_set_sense(HYDRA_INT_SCCA_TX_DMA, 0); - openpic_set_sense(HYDRA_INT_SCCA_RX_DMA, 0); - openpic_set_sense(HYDRA_INT_SCCB_TX_DMA, 0); - openpic_set_sense(HYDRA_INT_SCCB_RX_DMA, 0); - openpic_set_sense(HYDRA_INT_SCSI, 1); - openpic_set_sense(HYDRA_INT_SCCA, 1); - openpic_set_sense(HYDRA_INT_SCCB, 1); - openpic_set_sense(HYDRA_INT_VIA, 1); - openpic_set_sense(HYDRA_INT_ADB, 1); - openpic_set_sense(HYDRA_INT_ADB_NMI, 0); + unsigned char t8; + unsigned short t16; + unsigned int t32; + if (pcibios_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_83C553, 0, &bus, &dev) + == PCIBIOS_SUCCESSFUL) { + dev++; + chrp_pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32); + if (t32 == (PCI_DEVICE_ID_WINBOND_82C105<<16) + PCI_VENDOR_ID_WINBOND) { +#if 0 + printk("Enabling SL82C105 IDE on W83C553F\n"); + /* + * FIXME: this doesn't help :-( + */ + + /* I/O mapping */ + chrp_pcibios_read_config_word(bus, dev, PCI_COMMAND, &t16); + t16 |= PCI_COMMAND_IO; + chrp_pcibios_write_config_word(bus, dev, PCI_COMMAND, t16); + + /* Standard IDE registers */ + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0, + 0xffffffff); + chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0, + 0x000001f0 | 1); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1, + 0xffffffff); + chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1, + 0x000003f4 | 1); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2, + 0xffffffff); + chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_2, &t32); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2, + 0x00000170 | 1); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3, + 0xffffffff); + chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_3, &t32); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3, + 0x00000374 | 1); + + /* IDE Bus Master Control */ + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4, + 0xffffffff); + chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_4, &t32); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4, + 0x1000 | 1); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5, + 0xffffffff); + chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_5, &t32); + chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5, + 0x1010 | 1); + + /* IDE Interrupt */ + chrp_pcibios_read_config_byte(bus, dev, PCI_INTERRUPT_LINE, &t8); + chrp_ide_irq = t8; +#endif + return 1; + } + } + return 0; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.1.78/linux/arch/ppc/kernel/chrp_setup.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/chrp_setup.c Mon Jan 12 15:18:13 1998 @@ -28,11 +28,20 @@ #include #include #include +#ifdef CONFIG_ABSTRACT_CONSOLE +#include +#endif #include #include #include #include +#include +#include +#include + +extern void hydra_init(void); +extern void w83c553f_init(void); /* for the mac fs */ kdev_t boot_dev; @@ -52,110 +61,103 @@ #endif -extern char saved_command_line[256]; +int chrp_ide_irq = 0; -long TotalMemory; - -int -chrp_get_cpuinfo(char *buffer) +void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) { - int pvr = _get_PVR(); - int len; - char *model; - - switch (pvr>>16) - { - case 1: - model = "601"; - break; - case 3: - model = "603"; - break; - case 4: - model = "604"; - break; - case 6: - model = "603e"; - break; - case 7: - model = "603ev"; - break; - case 9: - model = "604e"; - break; - default: - model = "unknown"; - break; - } + ide_ioreg_t port = base; + int i = 8; - len = sprintf(buffer, "PowerPC %s rev %d.%d\n", model, - (pvr & 0xff00) >> 8, pvr & 0xff); + while (i--) + *p++ = port++; + *p++ = base + 0x206; + if (irq != NULL) + *irq = chrp_ide_irq; +} - len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n", - (loops_per_sec+2500)/500000, - ((loops_per_sec+2500)/5000) % 100); +static const char *gg2_memtypes[4] = { + "FPM", "SDRAM", "EDO", "BEDO" +}; +static const char *gg2_cachesizes[4] = { + "256 KB", "512 KB", "1 MB", "Reserved" +}; +static const char *gg2_cachetypes[4] = { + "Asynchronous", "Reserved", "Flow-Through Synchronous", + "Pipelined Synchronous" +}; +static const char *gg2_cachemodes[4] = { + "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" +}; -#if 0 - /* - * Ooh's and aah's info about zero'd pages in idle task - */ - { - extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls; - len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) " - "current: %u (%uKb) hits: %u/%u (%lu%%)\n", - zerototal, (zerototal*PAGE_SIZE)>>10, - zerocount, (zerocount*PAGE_SIZE)>>10, - zeropage_hits,zeropage_calls, - /* : 1 below is so we don't div by zero */ - (zeropage_hits*100) / - ((zeropage_calls)?zeropage_calls:1)); +int +chrp_get_cpuinfo(char *buffer) +{ + int i, len, sdramen; + unsigned int t; + struct device_node *root; + const char *model = ""; + + root = find_path_device("/"); + if (root) + model = get_property(root, "model", NULL); + len = sprintf(buffer,"machine\t\t: CHRP %s\n", model); + + /* VLSI VAS96011/12 `Golden Gate 2' */ + /* Memory banks */ + sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_CTRL)) + >>31) & 1; + for (i = 0; i < (sdramen ? 4 : 6); i++) { + t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_BANK0+ + i*4)); + if (!(t & 1)) + continue; + switch ((t>>8) & 0x1f) { + case 0x1f: + model = "4 MB"; + break; + case 0x1e: + model = "8 MB"; + break; + case 0x1c: + model = "16 MB"; + break; + case 0x18: + model = "32 MB"; + break; + case 0x10: + model = "64 MB"; + break; + case 0x00: + model = "128 MB"; + break; + default: + model = "Reserved"; + break; + } + len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model, + gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); } -#endif + /* L2 cache */ + t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL)); + len += sprintf(buffer+len, "l2\t\t: %s %s (%s)\n", + gg2_cachesizes[(t>>7) & 3], gg2_cachetypes[(t>>2) & 3], + gg2_cachemodes[t & 3]); return len; } __initfunc(void -chrp_setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p)) +chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) { extern char cmd_line[]; - extern char _etext[], _edata[], _end[]; - extern int panic_timeout; - - /* Save unparsed command line copy for /proc/cmdline */ - strcpy( saved_command_line, cmd_line ); - *cmdline_p = cmd_line; - - *memory_start_p = (unsigned long) Hash+Hash_size; - (unsigned long *)*memory_end_p = (unsigned long *)(TotalMemory+KERNELBASE); /* init to some ~sane value until calibrate_delay() runs */ loops_per_sec = 50000000; - /* reboot on panic */ - panic_timeout = 180; - - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = (unsigned long) _etext; - init_task.mm->end_data = (unsigned long) _edata; - init_task.mm->brk = (unsigned long) _end; - aux_device_present = 0xaa; - - switch ( _machine ) - { - case _MACH_chrp: - ROOT_DEV = to_kdev_t(0x0801); /* sda1 */ - break; - } + + ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ #ifdef CONFIG_BLK_DEV_RAM -#if 0 - ROOT_DEV = to_kdev_t(0x0200); /* floppy */ - rd_prompt = 1; - rd_doload = 1; - rd_image_start = 0; -#endif /* initrd_start and size are setup by boot/head.S and kernel/head.S */ if ( initrd_start ) { @@ -177,4 +179,20 @@ request_region(0x40,0x20,"timer"); request_region(0x80,0x10,"dma page reg"); request_region(0xc0,0x20,"dma2"); + + /* PCI bridge config space access area - + * appears to be not in devtree on longtrail. */ + ioremap(GG2_PCI_CONFIG_BASE, 0x80000); + + /* + * Temporary fixes for PCI devices. + * -- Geert + */ + hydra_init(); /* Mac I/O */ + w83c553f_init(); /* PCI-ISA bridge and IDE */ + +#ifdef CONFIG_ABSTRACT_CONSOLE + /* Frame buffer device based console */ + conswitchp = &fb_con; +#endif } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c --- v2.1.78/linux/arch/ppc/kernel/chrp_time.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/chrp_time.c Mon Jan 12 15:18:13 1998 @@ -8,7 +8,6 @@ * copied and modified from intel version * */ -#include #include #include #include @@ -24,21 +23,41 @@ #include #include #include - +#include #include "time.h" +static int nvram_as1 = NVRAM_AS1; +static int nvram_as0 = NVRAM_AS0; +static int nvram_data = NVRAM_DATA; + +void chrp_time_init(void) +{ + struct device_node *rtcs; + int base; + + rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); + if (rtcs == NULL || rtcs->addrs == NULL) + return; + base = ((int *)rtcs->addrs)[2]; + nvram_as1 = 0; + nvram_as0 = base; + nvram_data = base + 1; +} + int chrp_cmos_clock_read(int addr) { - outb(addr>>8, NVRAM_AS1); - outb(addr, NVRAM_AS0); - return (inb(NVRAM_DATA)); + if (nvram_as1 != 0) + outb(addr>>8, nvram_as1); + outb(addr, nvram_as0); + return (inb(nvram_data)); } void chrp_cmos_clock_write(unsigned long val, int addr) { - outb(addr>>8, NVRAM_AS1); - outb(addr, NVRAM_AS0); - outb(val,NVRAM_DATA); + if (nvram_as1 != 0) + outb(addr>>8, nvram_as1); + outb(addr, nvram_as0); + outb(val, nvram_data); return; } @@ -50,7 +69,7 @@ unsigned char save_control, save_freq_select; struct rtc_time tm; - to_tm(nowtime, &tm); + to_tm(nowtime + 10*60*60, &tm); /* XXX for now */ save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ @@ -127,6 +146,31 @@ } if ((year += 1900) < 1970) year += 100; - return mktime(year, mon, day, hour, min, sec); + return mktime(year, mon, day, hour, min, sec) - 10*60*60 /* XXX for now */; } + +void chrp_calibrate_decr(void) +{ + struct device_node *cpu; + int freq, *fp, divisor; + + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + freq = 16666000; /* hardcoded default */ + cpu = find_type_devices("cpu"); + if (cpu != 0) { + fp = (int *) get_property(cpu, "timebase-frequency", NULL); + if (fp != 0) + freq = *fp; + } + + freq *= 60; /* try to make freq/1e6 an integer */ + divisor = 60; + printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; +} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/find_name.c linux/arch/ppc/kernel/find_name.c --- v2.1.78/linux/arch/ppc/kernel/find_name.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/find_name.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,47 @@ +#include +#include +#include +/* + * Finds a given address in the System.map and prints it out + * with its neighbors. -- Cort + */ + +void main(int argc, char **argv) +{ + unsigned long addr, cmp, i; + FILE *f; + char *ptr; + char s[256], last[256]; + + if ( argc < 2 ) + { + fprintf(stderr, "Usage: %s
\n", argv[0]); + exit(-1); + } + + for ( i = 1 ; argv[i] ; i++ ) + { + sscanf( argv[i], "%0x", &addr ); + /* adjust if addr is relative to kernelbase */ + if ( addr < PAGE_OFFSET ) + addr += PAGE_OFFSET; + + if ( (f = fopen( "System.map", "r" )) == NULL ) + { + perror("fopen()\n"); + exit(-1); + } + + while ( !feof(f) ) + { + fgets(s, 255 , f); + sscanf( s, "%0x", &cmp ); + if ( addr < cmp ) + break; + strcpy( last, s); + } + + printf( "%s", last); + } + fclose(f); +} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.1.78/linux/arch/ppc/kernel/head.S Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/head.S Mon Jan 12 15:18:13 1998 @@ -30,7 +30,50 @@ #include #include -#define SYNC() \ +#ifdef CONFIG_APUS +/* At CYBERBASEp we'll find the following sum: + * -KERNELBASE+CyberStormMemoryBase + */ +#define CYBERBASEp (0xfff00000) +#endif + +/* optimization for 603 to load the tlb directly from the linux table */ +#define NO_RELOAD_HTAB 1 + +CACHE_LINE_SIZE = 32 +LG_CACHE_LINE_SIZE = 5 + +#define TOPHYS(x) (x - KERNELBASE) + +/* + * Macros for storing registers into and loading registers from + * exception frames. + */ +#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) + +#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base) +#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) +#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) +#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) +#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) +#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) +#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base) +#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) +#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) +#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) +#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) +#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) + +#define SYNC \ sync; \ isync @@ -43,94 +86,16 @@ addi r4,r4,0x1000; \ bdnz 0b -#define TOPHYS(x) (x - KERNELBASE) +#define LOAD_BAT(n, offset, reg, RA, RB) \ + lwz RA,offset+0(reg); \ + lwz RB,offset+4(reg); \ + mtspr IBAT##n##U,RA; \ + mtspr IBAT##n##L,RB; \ + lwz RA,offset+8(reg); \ + lwz RB,offset+12(reg); \ + mtspr DBAT##n##U,RA; \ + mtspr DBAT##n##L,RB -/* this is a very kludgey way of loading up the BATs on the - prep system. I'll kill this horrible macro and write - something clean when I have a chance -- Cort - */ -#define LOAD_BATS(RA,RB) \ - mfspr RA,PVR ; \ - srwi RA,RA,16 ; \ - cmpi 0,RA,1 ; \ - beq 199f ; \ - /* load bats for 60x */ ; \ - lis RA,BAT0@h ; \ - ori RA,RA,BAT0@l ; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT0U,RB ; \ - mtspr DBAT0U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT0L,RB ; \ - mtspr DBAT0L,RB ; \ - lis RA,BAT1@h ; \ - ori RA,RA,BAT1@l ; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT1U,RB ; \ - mtspr DBAT1U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT1L,RB ; \ - mtspr DBAT1L,RB ; \ - lis RA,BAT2@h ; \ - ori RA,RA,BAT2@l ; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT2U,RB ; \ - mtspr DBAT2U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT2L,RB ; \ - mtspr DBAT2L,RB ; \ - lis RA,BAT3@h ; \ - ori RA,RA,BAT3@l ; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT3U,RB ; \ - mtspr DBAT3U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT3L,RB ; \ - mtspr DBAT3L,RB ; \ - b 200f ; \ -199: /*load bats for 601 */ ; \ - lis RA,BAT0_601@h ; \ - ori RA,RA,BAT0_601@l; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT0U,RB ; \ - mtspr DBAT0U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT0L,RB ; \ - mtspr DBAT0L,RB ; \ - lis RA,BAT1_601@h ; \ - ori RA,RA,BAT1_601@l; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT1U,RB ; \ - mtspr DBAT1U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT1L,RB ; \ - mtspr DBAT1L,RB ; \ - lis RA,BAT2_601@h ; \ - ori RA,RA,BAT2_601@l; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT2U,RB ; \ - mtspr DBAT2U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT2L,RB ; \ - mtspr DBAT2L,RB ; \ - lis RA,BAT3_601@h ; \ - ori RA,RA,BAT3_601@l; \ - addis RA,RA,-KERNELBASE@h;\ - lwz RB,0(RA) ; \ - mtspr IBAT3U,RB ; \ - mtspr DBAT3U,RB ; \ - lwz RB,4(RA) ; \ - mtspr IBAT3L,RB ; \ - mtspr DBAT3L,RB ; \ -200: - .text .globl _stext _stext: @@ -152,8 +117,8 @@ * managing the hash table. Interrupts are disabled. The stack * pointer (r1) points to just below the end of the half-meg region * from 0x380000 - 0x400000, which is mapped in already. - */ -/* PREP + * + * PREP * This is jumped to on prep systems right after the kernel is relocated * to its proper place in memory by the boot loader. The expected layout * of the regs is: @@ -172,30 +137,47 @@ __start: /* + * We have to do any OF calls before we map ourselves to KERNELBASE, + * because OF may have I/O devices mapped in in that area + * (particularly on CHRP). + */ + mr r31,r3 /* save parameters */ + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r29,r7 + bl prom_init + +/* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. */ - mfspr r9,PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 - lis r11,KERNELBASE@h - bne 4f - ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f - ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f - oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ - oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ - mtspr IBAT1U,r9 - mtspr IBAT1L,r10 - b 5f -4: ori r11,r11,0x1ff /* set up BAT registers for 604 */ - li r8,2 - mtspr DBAT0U,r11 - mtspr DBAT0L,r8 -5: mtspr IBAT0U,r11 - mtspr IBAT0L,r8 - isync + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpi 0,r9,1 + lis r11,KERNELBASE@h + bne 4f + ori r11,r11,4 /* set up BAT registers for 601 */ + li r8,0x7f + oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ + oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ + mtspr IBAT1U,r9 + mtspr IBAT1L,r10 + b 5f +4: ori r11,r11,0x1ff /* set up BAT registers for 604 */ +#ifndef CONFIG_APUS + li r8,2 +#else + lis r8,CYBERBASEp@h + lwz r8,0(r8) + addis r8,r8,KERNELBASE@h + addi r8,r8,2 +#endif + mtspr DBAT0U,r11 + mtspr DBAT0L,r8 +5: mtspr IBAT0U,r11 + mtspr IBAT0L,r8 + isync /* * we now have the 1st 16M of ram mapped with the bats. * prep needs the mmu to be turned on here, but pmac already has it on. @@ -247,6 +229,20 @@ #define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) #define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) +#ifndef CONFIG_APUS +#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h +#define tovirt(rd,rs,rt) addis rd,rs,KERNELBASE@h +#else +#define tophys(rd,rs,rt) \ + lis rt,CYBERBASEp@h; \ + lwz rt,0(rt); \ + add rd,rs,rt +#define tovirt(rd,rs,rt) \ + lis rt,CYBERBASEp@h; \ + lwz rt,0(rt); \ + sub rd,rs,rt +#endif + /* * Exception entry code. This code runs with address translation * turned off, i.e. using physical addresses. @@ -254,21 +250,15 @@ * task's thread_struct. */ #define EXCEPTION_PROLOG \ -0: mtspr SPRG0,r20; \ + mtspr SPRG0,r20; \ mtspr SPRG1,r21; \ mfcr r20; \ - mfspr r21,SRR1; /* test whether from user or kernel */\ - andi. r21,r21,MSR_PR; \ - mr r21,r1; /* from kernel - use current sp */\ - beq 1f; \ - mfspr r21,SPRG3; /* from user - load kernel sp */\ - lwz r21,KSP(r21); \ -1: addis r21,r21,-KERNELBASE@h; /* convert sp to physical */ \ + mfspr r21,SPRG2; /* exception stack to use from */ \ + cmpwi 0,r21,0; /* user mode or RTAS */ \ + bne 1f; \ + tophys(r21,r1,r21); /* use tophys(kernel sp) otherwise */ \ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\ - stw r1,GPR1(r21); \ - stw r1,0(r21); \ - addis r1,r21,KERNELBASE@h; /* set new kernel sp */ \ - stw r20,_CCR(r21); /* save registers */ \ +1: stw r20,_CCR(r21); /* save registers */ \ stw r22,GPR22(r21); \ stw r23,GPR23(r21); \ mfspr r20,SPRG0; \ @@ -282,9 +272,12 @@ mfspr r20,XER; \ stw r20,_XER(r21); \ mfspr r22,SRR0; \ - mfspr r23,SRR1; /* we can now take exceptions */\ + mfspr r23,SRR1; \ stw r0,GPR0(r21); \ + stw r1,GPR1(r21); \ stw r2,GPR2(r21); \ + stw r1,0(r21); \ + tovirt(r1,r21,r1); /* set new kernel sp */ \ SAVE_4GPRS(3, r21); /* * Note: code which follows this uses cr0.eq (set if from kernel), @@ -315,7 +308,7 @@ DataAccess: EXCEPTION_PROLOG mfspr r20,DSISR - andis. r0,r20,0x8470 /* weird error? */ + andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ mfspr r3,DAR /* into the hash table */ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ @@ -419,6 +412,47 @@ */ . = 0x1000 InstructionTLBMiss: +#ifdef NO_RELOAD_HTAB +/* + * r0: stored ctr + * r1: linux style pte ( later becomes ppc hardware pte ) + * r2: ptr to linux-style pte + * r3: scratch + */ + mfctr r0 + /* Get PTE (linux-style) and check access */ + mfspr r2,SPRG3 + lwz r2,PG_TABLES(r2) + tophys(r2,r2,r3) + mfspr r3,IMISS + rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ + lwz r2,0(r2) /* get pmd entry */ + rlwinm. r2,r2,0,0,19 /* extract address of pte page */ + beq- InstructionAddressInvalid /* return if no mapping */ + tophys(r2,r2,r1) + rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ + lwz r1,0(r2) /* get linux-style pte */ + /* setup access flags in r3 */ + mfmsr r3 + rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */ + ori r3,r3,1 /* set _PAGE_PRESENT bit in access */ + andc. r3,r3,r1 /* check access & ~permission */ + bne- InstructionAddressInvalid /* return if access not permitted */ + ori r1,r1,0x100 /* set _PAGE_ACCESSED in pte */ + stw r1,0(r2) /* update PTE (accessed bit) */ + /* Convert linux-style PTE to low word of PPC-style PTE */ + /* this computation could be done better -- Cort */ + rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ + rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ + ori r3,r3,0xe04 /* clear out reserved bits */ + andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */ + mtspr RPA,r1 + mfspr r3,IMISS + tlbli r3 + mfspr r3,SRR1 /* Need to restore CR0 */ + mtcrf 0x80,r3 + rfi +#else mfctr r0 /* Need to save this - CTR can't be touched! */ mfspr r2,HASH1 /* Get PTE pointer */ mfspr r3,ICMP /* Partial item compare value */ @@ -443,20 +477,25 @@ mfspr r2,HASH2 /* Get hash table pointer */ ori r3,r3,0x40 /* Set secondary hash */ b 00b /* Try lookup again */ +#endif /* NO_RELOAD_HTAB */ InstructionAddressInvalid: mfspr r3,SRR1 rlwinm r1,r3,9,6,6 /* Get load/store bit */ - addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */ - mtspr DSISR,r1 +#ifdef NO_RELOAD_HTAB + addis r1,r1,0x2000 +#else + addis r1,r1,0x4000 /* Set bit 1 -> PTE not found (in HTAB) */ +#endif /* NO_RELOAD_HTAB */ + mtspr DSISR,r1 /* (shouldn't be needed) */ mtctr r0 /* Restore CTR */ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ or r2,r2,r1 mtspr SRR1,r2 mfspr r1,IMISS /* Get failing address */ rlwinm. r2,r2,0,31,31 /* Check for little endian access */ - beq 20f /* Jump if big endian */ - xori r1,r1,3 -20: mtspr DAR,r1 /* Set fault address */ + rlwimi r2,r2,1,30,30 /* change 1 -> 3 */ + xor r1,r1,r2 + mtspr DAR,r1 /* Set fault address */ mfmsr r0 /* Restore "normal" registers */ xoris r0,r0,MSR_TGPR>>16 mtcrf 0x80,r3 /* Restore CR0 */ @@ -469,6 +508,48 @@ */ . = 0x1100 DataLoadTLBMiss: +#ifdef NO_RELOAD_HTAB +/* + * r0: stored ctr + * r1: linux style pte ( later becomes ppc hardware pte ) + * r2: ptr to linux-style pte + * r3: scratch + */ + mfctr r0 + /* Get PTE (linux-style) and check access */ + mfspr r2,SPRG3 + lwz r2,PG_TABLES(r2) + tophys(r2,r2,r3) + mfspr r3,DMISS + rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ + lwz r2,0(r2) /* get pmd entry */ + rlwinm. r2,r2,0,0,19 /* extract address of pte page */ + beq- DataAddressInvalid /* return if no mapping */ + tophys(r2,r2,r1) + rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ + lwz r1,0(r2) /* get linux-style pte */ + /* setup access flags in r3 */ + mfmsr r3 + rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */ + ori r3,r3,1 /* set _PAGE_PRESENT bit in access */ + /* save r2 and use it as scratch for the andc. */ + andc. r3,r3,r1 /* check access & ~permission */ + bne- DataAddressInvalid /* return if access not permitted */ + ori r1,r1,0x100 /* set _PAGE_ACCESSED in pte */ + stw r1,0(r2) /* update PTE (accessed bit) */ + /* Convert linux-style PTE to low word of PPC-style PTE */ + /* this computation could be done better -- Cort */ + rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ + rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ + ori r3,r3,0xe04 /* clear out reserved bits */ + andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */ + mtspr RPA,r1 + mfspr r3,DMISS + tlbld r3 + mfspr r3,SRR1 /* Need to restore CR0 */ + mtcrf 0x80,r3 + rfi +#else mfctr r0 /* Need to save this - CTR can't be touched! */ mfspr r2,HASH1 /* Get PTE pointer */ mfspr r3,DCMP /* Partial item compare value */ @@ -493,10 +574,15 @@ mfspr r2,HASH2 /* Get hash table pointer */ ori r3,r3,0x40 /* Set secondary hash */ b 00b /* Try lookup again */ +#endif /* NO_RELOAD_HTAB */ DataAddressInvalid: mfspr r3,SRR1 rlwinm r1,r3,9,6,6 /* Get load/store bit */ +#ifdef NO_RELOAD_HTAB + addis r1,r1,0x2000 +#else addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */ +#endif /* NO_RELOAD_HTAB */ mtspr DSISR,r1 mtctr r0 /* Restore CTR */ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ @@ -518,6 +604,48 @@ */ . = 0x1200 DataStoreTLBMiss: +#ifdef NO_RELOAD_HTAB +/* + * r0: stored ctr + * r1: linux style pte ( later becomes ppc hardware pte ) + * r2: ptr to linux-style pte + * r3: scratch + */ + mfctr r0 + /* Get PTE (linux-style) and check access */ + mfspr r2,SPRG3 + lwz r2,PG_TABLES(r2) + tophys(r2,r2,r3) + mfspr r3,DMISS + rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ + lwz r2,0(r2) /* get pmd entry */ + rlwinm. r2,r2,0,0,19 /* extract address of pte page */ + beq- DataAddressInvalid /* return if no mapping */ + tophys(r2,r2,r1) + rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ + lwz r1,0(r2) /* get linux-style pte */ + /* setup access flags in r3 */ + mfmsr r3 + rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */ + ori r3,r3,0x5 /* _PAGE_PRESENT|_PAGE_RW */ + /* save r2 and use it as scratch for the andc. */ + andc. r3,r3,r1 /* check access & ~permission */ + bne- DataAddressInvalid /* return if access not permitted */ + ori r1,r1,0x384 /* set _PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_RW|_PAGE_HWWRITE in pte */ + stw r1,0(r2) /* update PTE (accessed bit) */ + /* Convert linux-style PTE to low word of PPC-style PTE */ + /* this computation could be done better -- Cort */ + rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ + rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ + ori r3,r3,0xe04 /* clear out reserved bits */ + andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */ + mtspr RPA,r1 + mfspr r3,DMISS + tlbld r3 + mfspr r3,SRR1 /* Need to restore CR0 */ + mtcrf 0x80,r3 + rfi +#else mfctr r0 /* Need to save this - CTR can't be touched! */ mfspr r2,HASH1 /* Get PTE pointer */ mfspr r3,DCMP /* Partial item compare value */ @@ -542,6 +670,8 @@ mfspr r2,HASH2 /* Get hash table pointer */ ori r3,r3,0x40 /* Set secondary hash */ b 00b /* Try lookup again */ +#endif /* NO_RELOAD_HTAB */ + /* Instruction address breakpoint exception (on 603/604) */ STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) @@ -596,17 +726,23 @@ SAVE_8GPRS(12, r21) SAVE_8GPRS(24, r21) andi. r23,r23,MSR_PR - mfspr r23,SPRG3 /* if from user, fix up tss */ + mfspr r23,SPRG3 /* if from user, fix up tss.regs */ beq 2f addi r24,r1,STACK_FRAME_OVERHEAD stw r24,PT_REGS(r23) 2: addi r2,r23,-TSS /* set r2 to current */ - addis r2,r2,KERNELBASE@h + tovirt(r2,r2,r23) mflr r23 andi. r24,r23,0x3f00 /* get vector offset */ stw r24,TRAP(r21) li r22,0 stw r22,RESULT(r21) + mtspr SPRG2,r22 /* r1 is now kernel sp */ + addi r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */ + cmplw 0,r1,r2 + cmplw 1,r1,r24 + crand 1,1,4 + bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */ lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ mtspr SRR0,r24 @@ -616,28 +752,67 @@ rfi /* jump to handler, enable MMU */ /* + * On kernel stack overflow, load up an initial stack pointer + * and call StackOverflow(regs), which should not return. + */ +stack_ovf: + addi r3,r1,STACK_FRAME_OVERHEAD + lis r1,init_task_union@ha + addi r1,r1,init_task_union@l + addi r1,r1,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD + lis r24,StackOverflow@ha + addi r24,r24,StackOverflow@l + li r20,MSR_KERNEL + mtspr SRR0,r24 + mtspr SRR1,r20 + SYNC + rfi + +/* * Continuation of the floating-point unavailable handler. */ load_up_fpu: - bl giveup_fpu_unmapped - ori r23,r23,MSR_FP /* enable use of FP after return */ + +/* + * 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. + */ +#ifndef CONFIG_APUS + lis r6,-KERNELBASE@h +#else + lis r6,CYBERBASEp@h + lwz r6,0(r6) +#endif + addis r3,r6,last_task_used_math@ha + lwz r4,last_task_used_math@l(r3) + mfmsr r5 + ori r5,r5,MSR_FP + SYNC + mtmsr r5 /* enable use of fpu now */ + SYNC + cmpi 0,r4,0 + beq 1f + add r4,r4,r6 + addi r4,r4,TSS /* want TSS of last_task_used_math */ + SAVE_32FPRS(0, r4) + mffs fr0 + stfd fr0,TSS_FPSCR-4(r4) + lwz r5,PT_REGS(r4) + add r5,r5,r6 + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r20,MSR_FP + andc r4,r4,r20 /* disable FP for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) + +1: ori r23,r23,MSR_FP /* enable use of FP after return */ mfspr r5,SPRG3 /* current task's TSS (phys) */ lfd fr0,TSS_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) - -/* use last_task_used_math instead of fpu_tss */ - lis r3,last_task_used_math@ha - addis r3,r3,-KERNELBASE@h subi r4,r5,TSS - addis r4,r4,KERNELBASE@h + sub r4,r4,r6 stw r4,last_task_used_math@l(r3) -#if 0 - lis r3,fpu_tss@ha - addis r4,r5,KERNELBASE@h - addis r3,r3,-KERNELBASE@h - stw r4,fpu_tss@l(r3) -#endif /* restore registers and return */ lwz r3,_CCR(r21) lwz r4,_LINK(r21) @@ -672,27 +847,42 @@ * physical address of the hash table are known. These definitions * of Hash_base and Hash_bits below are just an example. */ +/* + * Note that the 603s won't come here, since the 603 + * loads tlb directly into the tlb from the linux tables, while + * others (601, 604, etc.) call hash_page() to load entries from + * the linux tables into the hash table. -- Cort + */ Hash_base = 0x180000 Hash_bits = 12 /* e.g. 256kB hash table */ Hash_msk = (((1 << Hash_bits) - 1) * 64) .globl hash_page hash_page: +#ifdef __SMP__ + lis r6,hash_table_lock@h + ori r6,r6,hash_table_lock@l + tophys(r6,r6,r2) +1011: lwarx r0,0,r6 + stwcx. r6,0,r6 + bne- 1011b + cmpi 0,r0,0 + bne 1011b +#endif /* __SMP__ */ /* Get PTE (linux-style) and check access */ - lwz r5,MM-TSS(r5) - addis r5,r5,-KERNELBASE@h /* get physical current->mm */ - lwz r5,PGD(r5) /* get current->mm->pgd */ - addis r5,r5,-KERNELBASE@h /* convert to phys addr */ + lwz r5,PG_TABLES(r5) + tophys(r5,r5,r2) /* convert to phys addr */ rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */ lwz r5,0(r5) /* get pmd entry */ rlwinm. r5,r5,0,0,19 /* extract address of pte page */ - beqlr- /* return if no mapping */ - addis r2,r5,-KERNELBASE@h + beq- hash_page_out /* return if no mapping */ + tophys(r2,r5,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ lwz r6,0(r2) /* get linux-style pte */ ori r4,r4,1 /* set _PAGE_PRESENT bit in access */ andc. r0,r4,r6 /* check access & ~permission */ - bnelr- /* return if access not permitted */ + bne- hash_page_out /* return if access not permitted */ + ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */ rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */ @@ -752,7 +942,7 @@ 10: mtctr r2 addi r3,r4,-8 /* search primary PTEG */ 1: lwzu r0,8(r3) /* get next PTE */ - cmpi 0,r0,0 /* empty? */ + srwi. r0,r0,31 /* only want to check valid bit */ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_empty @@ -765,24 +955,71 @@ addi r3,r3,-8 mtctr r2 2: lwzu r0,8(r3) - cmpi 0,r0,0 + srwi. r0,r0,31 /* only want to check valid bit */ bdnzf 2,2b beq+ found_empty /* Choose an arbitrary slot in the primary PTEG to overwrite */ +#if 0 xori r5,r5,0x40 /* clear H bit again */ lwz r2,next_slot@l(0) addi r2,r2,8 andi. r2,r2,0x38 stw r2,next_slot@l(0) add r3,r4,r2 +#else + /* now, allow 2nd hash as well as 1st */ + lwz r2,next_slot@l(0) + addi r2,r2,8 + andi. r2,r2,0x78 + stw r2,next_slot@l(0) + cmpi 0,0,r2,0x38 /* if it's the 2nd hash */ + bgt second_evict +first_evict: + xori r5,r5,0x40 /* clear H bit again */ + add r3,r4,r2 + b 11f +second_evict: + .globl hash_page_patch_D +hash_page_patch_D: + xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ + xori r3,r3,0xffc0 + subi r2,r2,0x40 + addi r3,r3,r2 +#endif +11: + /* update counter of evicted pages */ + lis r2,htab_evicts@h + ori r2,r2,htab_evicts@l + tophys(r2,r2,r4) + lwz r4,0(r2) + addi r4,r4,1 + stw r4,0(r2) /* Store PTE in PTEG */ found_empty: stw r5,0(r3) found_slot: stw r6,4(r3) + +/* + * Update the hash table miss count. We only want misses here + * that _are_ valid addresses and have a pte otherwise we don't + * count it as a reload. do_page_fault() takes care of bad addrs + * and entries that need linux-style pte's created. + * + * safe to use r2 here since we're not using it as current yet + * update the htab misses count + * -- Cort + */ + lis r2,htab_reloads@h + ori r2,r2,htab_reloads@l + tophys(r2,r2,r3) + lwz r3,0(r2) + addi r3,r3,1 + stw r3,0(r2) SYNC + /* Return from the exception */ lwz r3,_CCR(r21) lwz r4,_LINK(r21) @@ -790,6 +1027,13 @@ mtcrf 0xff,r3 mtlr r4 mtctr r5 +#ifdef __SMP__ + lis r5,hash_table_lock@h + ori r5,r5,hash_table_lock@l + tophys(r5,r5,r6) + li r6,0 + stw r6,0(r5) +#endif /* __SMP__ */ REST_GPR(0, r21) REST_2GPRS(1, r21) REST_4GPRS(3, r21) @@ -801,10 +1045,28 @@ lwz r21,GPR21(r21) SYNC rfi - + +hash_page_out: +#ifdef __SMP__ + lis r5,hash_table_lock@h + ori r5,r5,hash_table_lock@l + tophys(r5,r5,r6) + li r6,0 + stw r6,0(r5) +#endif /* __SMP__ */ + blr next_slot: .long 0 +#ifdef CONFIG_APUS + /* On APUS the first 0x4000 bytes of the kernel will be mapped + * at a different physical address than the rest. For this + * reason, the exception code cannot use relative branches to + * access the code below. + */ + . = 0x4000 +#endif + /* * This is where the main kernel code starts. */ @@ -831,23 +1093,24 @@ 10: sync mtspr HID0,r8 /* enable and invalidate caches */ + sync mtspr HID0,r11 /* enable caches */ sync isync cmpi 0,r9,4 /* check for 604 */ cmpi 1,r9,9 /* or 604e */ + cmpi 2,r9,10 /* or mach5 */ cror 2,2,6 + cror 2,2,10 bne 4f ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ - mtspr HID0,r11 /* superscalar exec & br history tbl */ + bne 2,5f + ori r11,r11,HID0_BTCD +5: mtspr HID0,r11 /* superscalar exec & br history tbl */ 4: /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l - /* ptr to phys current tss */ - addis r11,r2,-KERNELBASE@h - addi r11,r11,TSS /* init task's TSS */ - mtspr SPRG3,r11 /* stack */ addi r1,r2,TASK_UNION_SIZE li r0,0 @@ -869,10 +1132,14 @@ bdnz 3b 2: /* - * Initialize the prom stuff and the MMU. + * Decide what sort of machine this is and initialize the MMU. */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 bl identify_machine - bl prom_init bl MMU_init /* @@ -882,10 +1149,10 @@ */ lis r6,_SDR1@ha lwz r6,_SDR1@l(r6) - li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) lis r4,2f@h - addis r4,r4,-KERNELBASE@h ori r4,r4,2f@l + tophys(r4,r4,r3) + li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) mtspr SRR0,r4 mtspr SRR1,r3 rfi @@ -902,38 +1169,55 @@ addi r3,r3,1 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b - - lis r3,_machine@ha - addis r3,r3,-KERNELBASE@h - lwz r0,_machine@l(r3) - cmpi 0,r0,_MACH_Pmac - beq 99f -/* on prep reload the bats now that MMU_init() has setup them up -- Cort */ - LOAD_BATS(r3,r14) - b 100f - -/* on pmac clear the bats out */ -99: li r0,0 /* zot the BATs */ -#if 1 - mtspr IBAT0U,r0 - mtspr IBAT0L,r0 - mtspr DBAT0U,r0 - mtspr DBAT0L,r0 -#endif - mtspr IBAT1U,r0 - mtspr IBAT1L,r0 - mtspr DBAT1U,r0 - mtspr DBAT1L,r0 - mtspr IBAT2U,r0 - mtspr IBAT2L,r0 - mtspr DBAT2U,r0 - mtspr DBAT2L,r0 - mtspr IBAT3U,r0 - mtspr IBAT3L,r0 - mtspr DBAT3U,r0 - mtspr DBAT3L,r0 -100: +/* Load the BAT registers with the values set up by MMU_init. + MMU_init takes care of whether we're on a 601 or not. */ + lis r3,BATS@ha + addi r3,r3,BATS@l + tophys(r3,r3,r4) + LOAD_BAT(0,0,r3,r4,r5) + LOAD_BAT(1,16,r3,r4,r5) + LOAD_BAT(2,32,r3,r4,r5) + LOAD_BAT(3,48,r3,r4,r5) + +/* Set up for using our exception vectors */ + /* ptr to phys current tss */ + tophys(r4,r2,r4) + addi r4,r4,TSS /* init task's TSS */ + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ + +/* On CHRP copy exception vectors down to 0 */ + lis r5,_stext@ha + addi r5,r5,_stext@l + addis r5,r5,-KERNELBASE@h + cmpwi 0,r5,0 + beq 77f /* vectors are already at 0 */ + li r3,0x1000 + mtctr r3 + li r4,-4 + addi r5,r5,-4 +74: lwzu r0,4(r5) + stwu r0,4(r4) + bdnz 74b + /* need to flush/invalidate caches too */ + li r3,0x4000/CACHE_LINE_SIZE + li r4,0 + mtctr r3 +73: dcbst 0,r4 + addi r4,r4,CACHE_LINE_SIZE + bdnz 73b + sync + li r4,0 + mtctr r3 +72: icbi 0,r4 + addi r4,r4,CACHE_LINE_SIZE + bdnz 72b + sync + isync +77: + /* Now turn on the MMU for real! */ li r4,MSR_KERNEL lis r3,start_kernel@h @@ -947,25 +1231,25 @@ reset_SDR1: lis r6,_SDR1@ha lwz r6,_SDR1@l(r6) - mfmsr r3 - li r4,MSR_IR|MSR_DR - andc r3,r3,r4 + mfmsr r5 + li r4,0 + ori r4,r4,MSR_EE|MSR_IR|MSR_DR + andc r3,r5,r4 lis r4,2f@h - addis r4,r4,-KERNELBASE@h ori r4,r4,2f@l + tophys(r4,r4,r5) mtspr SRR0,r4 mtspr SRR1,r3 rfi 2: /* load new SDR1 */ - tlbia + tlbia mtspr SDR1,r6 /* turn the mmu back on */ - li r4,MSR_KERNEL mflr r3 mtspr SRR0,r3 - mtspr SRR1,r4 + mtspr SRR1,r5 rfi - + /* * FP unavailable trap from kernel - print a message, but let * the task use FP in the kernel until it returns to user mode. @@ -987,19 +1271,10 @@ * 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. - * (If giveup_fpu_unmapped uses any integer registers other than - * r3 - r6, the return code at load_up_fpu above will have - * to be adjusted.) */ -giveup_fpu_unmapped: - lis r6,-KERNELBASE@h - b 1f - .globl giveup_fpu giveup_fpu: - li r6,0 -1: - addis r3,r6,last_task_used_math@ha + lis r3,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) mfmsr r5 ori r5,r5,MSR_FP @@ -1008,7 +1283,6 @@ SYNC cmpi 0,r4,0 beqlr- /* if no previous owner, done */ - add r4,r4,r6 addi r4,r4,TSS /* want TSS of last_task_used_math */ li r5,0 stw r5,last_task_used_math@l(r3) @@ -1016,7 +1290,6 @@ mffs fr0 stfd fr0,TSS_FPSCR-4(r4) lwz r5,PT_REGS(r4) - add r5,r5,r6 lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5) li r4,MSR_FP andc r3,r3,r4 /* disable FP for previous task */ @@ -1104,12 +1377,12 @@ b 22b /* sys_sigreturn */ 10: addi r3,r1,STACK_FRAME_OVERHEAD - bl _EXTERN(sys_sigreturn) + bl sys_sigreturn cmpi 0,r3,0 /* Check for restarted system call */ bge int_return b 20b /* Traced system call support */ -50: bl _EXTERN(syscall_trace) +50: bl syscall_trace lwz r0,GPR0(r1) /* Restore original registers */ lwz r3,GPR3(r1) lwz r4,GPR4(r1) @@ -1144,7 +1417,7 @@ oris r10,r10,0x1000 stw r10,_CCR(r1) 60: stw r3,GPR3(r1) /* Update return value */ - bl _EXTERN(syscall_trace) + bl syscall_trace b int_return 66: li r3,ENOSYS b 52b @@ -1198,7 +1471,7 @@ stw r0,TRAP(r1) stw r1,KSP(r3) /* Set old stack pointer */ sync - addis r0,r4,-KERNELBASE@h + tophys(r0,r4,r3) mtspr SPRG3,r0 /* Update current TSS phys addr */ SYNC lwz r1,KSP(r4) /* Load new stack pointer */ @@ -1220,6 +1493,8 @@ /* * Trap exit. */ + .globl ret_from_syscall +ret_from_syscall: .globl int_return int_return: 0: mfmsr r30 /* Disable interrupts */ @@ -1245,34 +1520,31 @@ lwz r5,bh_active@l(r5) and. r4,r4,r5 beq+ 2f - ori r31,r30,MSR_EE /* re-enable interrupts */ - SYNC - mtmsr r31 - SYNC - bl _EXTERN(do_bottom_half) + bl do_bottom_half SYNC mtmsr r30 /* disable interrupts again */ SYNC 2: lwz r3,_MSR(r1) /* Returning to user mode? */ andi. r3,r3,MSR_PR - beq+ 10f /* no - no need to mess with stack */ + beq+ 10f /* if so, check need_resched and signals */ lis r3,need_resched@ha lwz r3,need_resched@l(r3) cmpi 0,r3,0 /* check need_resched flag */ beq+ 7f - bl _EXTERN(schedule) + bl schedule b 0b -7: lwz r3,BLOCKED(r2) /* Check for pending unblocked signals */ - lwz r5,SIGNAL(r2) - andc. r0,r5,r3 /* Lets thru any unblocked */ +7: lwz r5,SIGPENDING(r2) /* Check for pending unblocked signals */ + cmpwi 0,r5,0 beq+ 8f + li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD - bl _EXTERN(do_signal) + bl do_signal b 0b 8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ stw r4,TSS+KSP(r2) /* save kernel stack pointer */ -10: - lwz r2,_CTR(r1) + tophys(r3,r1,r3) + mtspr SPRG2,r3 /* phys exception stack pointer */ +10: lwz r2,_CTR(r1) lwz r0,_LINK(r1) mtctr r2 mtlr r0 @@ -1355,8 +1627,6 @@ * * flush_icache_range(unsigned long start, unsigned long stop) */ -CACHE_LINE_SIZE = 32 -LG_CACHE_LINE_SIZE = 5 _GLOBAL(flush_icache_range) mfspr r5,PVR rlwinm r5,r5,16,16,31 @@ -1417,6 +1687,28 @@ * given. */ _GLOBAL(flush_hash_segments) +#ifdef NO_RELOAD_HTAB +/* + * Bitmask of PVR numbers of 603-like chips, + * for which we don't use the hash table at all. + */ +#define PVR_603_LIKE 0x13000000 /* bits 3, 6, 7 set */ + + mfspr r0,PVR + rlwinm r0,r0,16,27,31 + lis r9,PVR_603_LIKE@h + rlwnm. r0,r9,r0,0,0 + bne 99f +#endif /* NO_RELOAD_HTAB */ +#ifdef __SMP__ + lis r6,hash_table_lock@h + ori r6,r6,hash_table_lock@l +1011: lwarx r0,0,r6 + stwcx. r6,0,r6 + bne- 1011b + cmpi 0,r0,0 + bne 1011b +#endif /* __SMP__ */ rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */ oris r3,r3,0x8000 /* set V bit */ rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */ @@ -1438,7 +1730,13 @@ stw r0,0(r5) /* invalidate entry */ 2: bdnz 1b /* continue with loop */ sync - tlbia +#ifdef __SMP__ + lis r5,hash_table_lock@h + ori r5,r5,hash_table_lock@l + li r6,0 + stw r6,0(r5) +#endif /* __SMP__ */ +99: tlbia isync blr @@ -1448,6 +1746,22 @@ * flush_hash_page(unsigned context, unsigned long va) */ _GLOBAL(flush_hash_page) +#ifdef NO_RELOAD_HTAB + mfspr r0,PVR + rlwinm r0,r0,16,27,31 + lis r9,PVR_603_LIKE@h + rlwnm. r0,r9,r0,0,0 + bne 99f +#endif /* NO_RELOAD_HTAB */ +#ifdef __SMP__ + lis r6,hash_table_lock@h + ori r6,r6,hash_table_lock@l +1011: lwarx r0,0,r6 + stwcx. r6,0,r6 + bne- 1011b + cmpi 0,r0,0 + bne 1011b +#endif /* __SMP__ */ rlwinm r3,r3,11,1,20 /* put context into vsid */ rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */ oris r3,r3,0x8000 /* set V (valid) bit */ @@ -1480,7 +1794,13 @@ 3: li r0,0 stw r0,0(r7) /* invalidate entry */ 4: sync - tlbie r4 /* in hw tlb too */ +#ifdef __SMP__ + lis r5,hash_table_lock@h + ori r5,r5,hash_table_lock@l + li r6,0 + stw r6,0(r5) +#endif /* __SMP__ */ +99: tlbie r4 /* in hw tlb too */ isync blr @@ -1491,200 +1811,221 @@ blr /* - * These exception handlers are used when we have called a prom - * routine after we have taken over the exception vectors and MMU. + * On CHRP, the Run-Time Abstraction Services (RTAS) have to be + * called with the MMU off. */ - .globl prom_exc_table -prom_exc_table: - .long TOPHYS(prom_exception) /* 0 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 400 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 800 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* c00 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1000 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1400 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1800 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1c00 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1000 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1400 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1800 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) /* 1c00 */ - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - .long TOPHYS(prom_exception) - -/* - * When we come in to these prom exceptions, r1 and lr have been - * saved in sprg1 and sprg2, and lr points to a word containing - * the vector offset. - */ -prom_exception: - mr r1,r21 /* save r21 */ - lis r21,prom_sp@ha /* get a stack to use */ - addis r21,r21,-KERNELBASE@h - lwz r21,prom_sp@l(r21) - addis r21,r21,-KERNELBASE@h /* convert to physical addr */ - subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD - stw r0,GPR0(r21) - stw r2,GPR2(r21) - stw r3,GPR3(r21) - stw r4,GPR4(r21) - stw r5,GPR5(r21) - stw r6,GPR6(r21) - stw r20,GPR20(r21) - stw r1,GPR21(r21) - stw r22,GPR22(r21) - stw r23,GPR23(r21) - mfspr r1,SPRG1 - stw r1,GPR1(r21) - mfcr r3 - mfspr r4,SPRG2 - stw r3,_CCR(r21) - stw r4,_LINK(r21) - mfctr r3 - mfspr r4,XER - stw r3,_CTR(r21) - stw r4,_XER(r21) - mfspr r22,SRR0 - mfspr r23,SRR1 - - /* at this point we have set things up pretty much exactly - how EXCEPTION_PROLOG does */ - mflr r3 - lwz r3,0(r3) /* get exception vector */ - stw r3,TRAP(r21) - cmpi 0,r3,0x300 /* was it a dsi? */ - bne 1f - - mfspr r20,DSISR /* here on data access exc. */ - andis. r0,r20,0x8470 /* weird error? */ - bne 3f /* if not, try to put a PTE */ - mfspr r3,DAR /* into the hash table */ - rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ - rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ - b 2f - -1: cmpi 0,r3,0x400 /* was it an isi? */ - bne 3f - andis. r0,r23,0x4000 /* if so, check if no pte found */ - beq 3f /* if so, try to put a PTE */ - mr r3,r22 /* into the hash table */ - rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ - mr r20,r23 /* SRR1 has reason bits */ -2: lis r5,prom_tss@ha /* phys addr of TSS */ - addis r5,r5,-KERNELBASE@h - lwz r5,prom_tss@l(r5) - bl hash_page - -3: addis r1,r21,KERNELBASE@h /* restore kernel stack ptr */ - addi r3,r1,INT_FRAME_SIZE+STACK_UNDERHEAD - stw r3,0(r21) /* set stack chain pointer */ - lis r5,prom_tss@ha - addis r5,r5,-KERNELBASE@h - lwz r5,prom_tss@l(r5) - mtspr SPRG3,r5 /* reset phys TSS pointer */ - lwz r4,TRAP(r21) /* the real exception vector */ - addi r3,r1,STACK_FRAME_OVERHEAD - li r20,MSR_KERNEL - bl transfer_to_handler - .long PromException - .long prom_int_return - - .comm prom_sp,4 - .comm prom_tss,4 - - .globl prom_int_return -prom_int_return: - lis r3,prom_exc_table@ha /* restore sprg3 for prom vectors */ - addi r3,r3,prom_exc_table@l + .globl enter_rtas +enter_rtas: + stwu r1,-16(r1) + mflr r0 + stw r0,20(r1) addis r3,r3,-KERNELBASE@h - mtspr SPRG3,r3 - b int_return + lis r4,rtas_data@ha + lwz r4,rtas_data@l(r4) + lis r6,1f@ha /* physical return address for rtas */ + addi r6,r6,1f@l + addis r6,r6,-KERNELBASE@h + subi r7,r1,INT_FRAME_SIZE+STACK_UNDERHEAD + addis r7,r7,-KERNELBASE@h + lis r8,rtas_entry@ha + lwz r8,rtas_entry@l(r8) + mfmsr r9 + stw r9,8(r1) + li r0,0 + ori r0,r0,MSR_EE|MSR_SE|MSR_BE + andc r0,r9,r0 + andi. r9,r9,MSR_ME|MSR_RI + sync /* disable interrupts so SRR0/1 */ + mtmsr r0 /* don't get trashed */ + mtlr r6 + mtspr SPRG2,r7 + mtspr SRR0,r8 + mtspr SRR1,r9 + rfi +1: addis r9,r1,-KERNELBASE@h + lwz r8,20(r9) /* get return address */ + lwz r9,8(r9) /* original msr value */ + li r0,0 + mtspr SPRG2,r0 + mtspr SRR0,r8 + mtspr SRR1,r9 + rfi /* return to caller */ + + .globl amhere +amhere: .long 0 + +#ifdef __SMP__ /* - * When entering the prom, we have to change to using a different - * set of exception vectors. + * Secondary processor begins executing here. */ - .globl enter_prom -enter_prom: - stwu r1,-32(r1) - mflr r0 - stw r0,36(r1) - stw r29,20(r1) - stw r30,24(r1) - stw r31,28(r1) - lis r8,prom_entry@ha - lwz r8,prom_entry@l(r8) - mfmsr r31 - andi. r0,r31,MSR_IP /* using our own vectors yet? */ - beq 1f /* if so, have to switch */ - mtlr r8 - blrl /* if not, can just charge ahead */ - b 2f -1: lis r9,prom_sp@ha /* save sp for exception handler */ - stw r1,prom_sp@l(r9) - mfspr r29,SPRG3 /* save physical tss pointer */ - lis r9,prom_tss@ha - stw r29,prom_tss@l(r9) - li r9,0 - ori r9,r9,MSR_EE - andc r30,r31,r9 - lis r9,prom_exc_table@ha /* set pointer to exception table */ - addi r9,r9,prom_exc_table@l - addis r9,r9,-KERNELBASE@h - ori r0,r31,MSR_IP + .globl secondary_entry +secondary_entry: + lis r0,amhere@h + ori r0,r0,amhere@l + addis r0,r0,-KERNELBASE@h + stw r0,0(r0) sync - mtmsr r30 /* disable interrupts */ - mtspr SPRG3,r9 /* while we update MSR_IP and sprg3 */ + isync + /* just like __start() with a few changes -- Cort */ + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpi 0,r9,1 + lis r11,KERNELBASE@h + bne 4f + ori r11,r11,4 /* set up BAT registers for 601 */ + li r8,0x7f + oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ + oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ + mtspr IBAT1U,r9 + mtspr IBAT1L,r10 + b 5f +4: ori r11,r11,0x1ff /* set up BAT registers for 604 */ + li r8,2 + mtspr DBAT0U,r11 + mtspr DBAT0L,r8 +5: mtspr IBAT0U,r11 + mtspr IBAT0L,r8 + isync +/* + * we now have the 1st 16M of ram mapped with the bats. + * prep needs the mmu to be turned on here, but pmac already has it on. + * this shouldn't bother the pmac since it just gets turned on again + * as we jump to our code at KERNELBASE. -- Cort + */ + mfmsr r0 + ori r0,r0,MSR_DR|MSR_IR + mtspr SRR1,r0 + lis r0,100f@h + ori r0,r0,100f@l + mtspr SRR0,r0 + SYNC + rfi /* enables MMU */ +100: + /* + * Enable caches and 604-specific features if necessary. + */ + mfspr r9,PVR + rlwinm r9,r9,16,16,31 + cmpi 0,r9,1 + beq 4f /* not needed for 601 */ + mfspr r11,HID0 + andi. r0,r11,HID0_DCE + ori r11,r11,HID0_ICE|HID0_DCE + ori r8,r11,HID0_ICFI + bne 3f /* don't invalidate the D-cache */ + ori r8,r8,HID0_DCI /* unless it wasn't enabled */ +3: + /* turn on dpm for 603 */ + cmpi 0,r9,3 + bne 10f + oris r11,r11,HID0_DPM@h +10: sync - mtmsr r0 /* start using exc. vectors in prom */ - mtlr r8 - blrl /* call prom */ + mtspr HID0,r8 /* enable and invalidate caches */ sync - mtmsr r30 /* disable interrupts again */ - mtspr SPRG3,r29 /* while we restore MSR_IP and sprg3 */ + mtspr HID0,r11 /* enable caches */ sync - mtmsr r31 /* reenable interrupts */ -2: lwz r0,36(r1) - mtlr r0 - lwz r29,20(r1) - lwz r30,24(r1) - lwz r31,28(r1) - lwz r1,0(r1) - blr + isync + cmpi 0,r9,4 /* check for 604 */ + cmpi 1,r9,9 /* or 604e */ + cmpi 2,r9,10 /* or mach5 */ + cror 2,2,6 + cror 2,2,10 + bne 4f + ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ + bne 2,5f + ori r11,r11,HID0_BTCD +5: mtspr HID0,r11 /* superscalar exec & br history tbl */ +4: + /* get ptr to current */ + lis r2,current_set@h + ori r2,r2,current_set@l + /* assume we're second processor for now */ + lwz r2,4(r2) + /* stack */ + addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) + +/* + * init_MMU on the first processor has setup the variables + * for us - all we need to do is load them -- Cort + */ + +/* + * Go back to running unmapped so we can load up new values + * for SDR1 (hash table pointer) and the segment registers + * and change to using our exception vectors. + */ + lis r6,_SDR1@ha + lwz r6,_SDR1@l(r6) + lis r4,2f@h + ori r4,r4,2f@l + tophys(r4,r4,r3) + li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) + mtspr SRR0,r4 + mtspr SRR1,r3 + rfi +/* Load up the kernel context */ +2: + SYNC /* Force all PTE updates to finish */ + tlbia /* Clear all TLB entries */ + mtspr SDR1,r6 + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + +/* Load the BAT registers with the values set up by MMU_init. + MMU_init takes care of whether we're on a 601 or not. */ + lis r3,BATS@ha + addi r3,r3,BATS@l + tophys(r3,r3,r4) + LOAD_BAT(0,0,r3,r4,r5) + LOAD_BAT(1,16,r3,r4,r5) + LOAD_BAT(2,32,r3,r4,r5) + LOAD_BAT(3,48,r3,r4,r5) +/* Set up for using our exception vectors */ + /* ptr to phys current tss */ + tophys(r4,r2,r4) + addi r4,r4,TSS /* init task's TSS */ + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ + + /* need to flush/invalidate caches too */ + li r3,0x4000/CACHE_LINE_SIZE + li r4,0 + mtctr r3 +73: dcbst 0,r4 + addi r4,r4,CACHE_LINE_SIZE + bdnz 73b + sync + li r4,0 + mtctr r3 +72: icbi 0,r4 + addi r4,r4,CACHE_LINE_SIZE + bdnz 72b + sync + isync +77: +/* Now turn on the MMU for real! */ + li r4,MSR_KERNEL + lis r3,start_secondary@h + ori r3,r3,start_secondary@l + mtspr SRR0,r3 + mtspr SRR1,r4 + rfi /* enable MMU and jump to start_kernel */ +/* should never return */ + .long 0 +#endif /* __SMP__ */ + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, @@ -1708,4 +2049,3 @@ .globl cmd_line cmd_line: .space 512 - diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.1.78/linux/arch/ppc/kernel/idle.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/idle.c Mon Jan 12 15:18:13 1998 @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.4 1997/08/23 22:46:01 cort Exp $ + * $Id: idle.c,v 1.13 1998/01/06 06:44:55 cort Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -31,40 +31,126 @@ #include #include #include +#include int zero_paged(void *unused); -int power_saved(void *unused); +void inline power_save(void); +void inline htab_reclaim(void); -asmlinkage int sys_idle(void) +int idled(void *unused) { int ret = -EPERM; - if (current->pid != 0) - goto out; - /* * want one per cpu since it would be nice to have all * processors who aren't doing anything * zero-ing pages since this daemon is lock-free * -- Cort */ - kernel_thread(zero_paged, NULL, 0); - /* no powersaving modes on 601 */ - /*if( (_get_PVR()>>16) != 1 ) - kernel_thread(power_saved, NULL, 0);*/ - - /* endless loop with no priority at all */ - current->priority = -100; - current->counter = -100; + /* kernel_thread(zero_paged, NULL, 0); */ + +#ifdef __SMP__ +printk("SMP %d: in idle. current = %s/%d\n", + current->processor,current->comm,current->pid); +#endif /* __SMP__ */ for (;;) { + /* endless loop with no priority at all */ + current->priority = -100; + current->counter = -100; + + /* endless idle loop with no priority at all */ + /* htab_reclaim(); */ schedule(); +#ifndef __SMP__ + /* can't do this on smp since second processor + will never wake up -- Cort */ + /* power_save(); */ +#endif /* __SMP__ */ } ret = 0; -out: return ret; } + +/* + * Mark 'zombie' pte's in the hash table as invalid. + * This improves performance for the hash table reload code + * a bit since we don't consider unused pages as valid. + * I haven't done any rigorous performance analysis yet + * so it's still experimental and turned off here. + * -- Cort + */ +void inline htab_reclaim(void) +{ + PTE *ptr, *start; + struct task_struct *p; + unsigned long valid = 0; + extern PTE *Hash, *Hash_end; + extern unsigned long Hash_size; + + /* if we don't have a htab */ + if ( Hash_size == 0 ) + return; + /*lock_dcache();*/ + + /* find a random place in the htab to start each time */ + start = &Hash[jiffies%(Hash_size/sizeof(ptr))]; + for ( ptr = start; ptr < Hash_end ; ptr++) + { + if ( ptr == start ) + return; + if ( ptr == Hash_end ) + ptr = Hash; + valid = 0; + if (!ptr->v) + continue; + for_each_task(p) + { + if ( need_resched ) + { + /*unlock_dcache();*/ + return; + } + /* if this vsid/context is in use */ + if ( (ptr->vsid >> 4) == p->mm->context ) + { + valid = 1; + break; + } + } + if ( valid ) + continue; + /* this pte isn't used */ + ptr->v = 0; + } + /*unlock_dcache();*/ +} + +/* + * Syscall entry into the idle task. -- Cort + */ +asmlinkage int sys_idle(void) +{ + if(current->pid != 0) + return -EPERM; + + idled(NULL); + return 0; /* should never execute this but it makes gcc happy -- Cort */ +} + +#ifdef __SMP__ +/* + * SMP entry into the idle task - calls the same thing as the + * non-smp versions. -- Cort + */ +int cpu_idle(void *unused) +{ + idled(unused); + return 0; +} +#endif /* __SMP__ */ + /* * vars for idle task zero'ing out pages */ @@ -105,7 +191,7 @@ atomic_inc((atomic_t *)&zeropage_hits); atomic_dec((atomic_t *)&zerocount); wake_up(&page_zerod_wait); - resched_force(); + need_resched = 1; /* zero out the pointer to next in the page */ *(unsigned long *)page = 0; @@ -120,7 +206,6 @@ * Zero's out pages until we need to resched or * we've reached the limit of zero'd pages. */ - int zero_paged(void *unused) { extern pte_t *get_pte( struct mm_struct *mm, unsigned long address ); @@ -129,14 +214,18 @@ pte_t *pte; sprintf(current->comm, "zero_paged (idle)"); - current->blocked = ~0UL; + /* current->blocked = ~0UL; */ +#ifdef __SMP__ + printk("Started zero_paged (cpu %d)\n", hard_smp_processor_id()); +#else printk("Started zero_paged\n"); +#endif /* __SMP__ */ __sti(); while ( 1 ) { - /* don't want to be pre-empted by swapper or power_saved */ + /* don't want to be pre-empted by swapper or power_save */ current->priority = -98; current->counter = -98; /* we don't want to run until we have something to do */ @@ -149,12 +238,9 @@ */ pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 ); if ( !pageptr ) - { - printk("!pageptr in zero_paged\n"); goto retry; - } - if ( resched_needed() ) + if ( need_resched ) schedule(); /* @@ -180,7 +266,7 @@ */ for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 ) { - if ( resched_needed() ) + if ( need_resched ) schedule(); *(unsigned long *)(bytecount + pageptr) = 0; } @@ -228,52 +314,30 @@ } } -int power_saved(void *unused) +void inline power_save(void) { unsigned long msr, hid0; - sprintf(current->comm, "power_saved (idle)"); - current->blocked = ~0UL; - - printk("Power saving daemon started\n"); + + /* no powersaving modes on the 601 */ + if( (_get_PVR()>>16) == 1 ) + return; __sti(); - while (1) - { - /* don't want to be pre-empted by swapper */ - current->priority = -99; - current->counter = -99; - /* go ahead and wakeup page_zerod() */ - wake_up(&page_zerod_wait); - schedule(); - asm volatile( - /* clear powersaving modes and set nap mode */ - "mfspr %3,1008 \n\t" - "andc %3,%3,%4 \n\t" - "or %3,%3,%5 \n\t" - "mtspr 1008,%3 \n\t" - /* enter the mode */ - "mfmsr %0 \n\t" - "oris %0,%0,%2 \n\t" - "sync \n\t" - "mtmsr %0 \n\t" - "isync \n\t" - : "=&r" (msr) - : "0" (msr), "i" (MSR_POW>>16), - "r" (hid0), - "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP), - "r" (HID0_NAP)); - /* - * The ibm carolina spec says that the eagle memory - * controller will detect the need for a snoop - * and wake up the processor so we don't need to - * check for cache operations that need to be - * snooped. The ppc book says the run signal - * must be asserted while napping for this though. - * - * Paul, what do you know about the pmac here? - * -- Cort - */ - schedule(); - } + asm volatile( + /* clear powersaving modes and set nap mode */ + "mfspr %3,1008 \n\t" + "andc %3,%3,%4 \n\t" + "or %3,%3,%5 \n\t" + "mtspr 1008,%3 \n\t" + /* enter the mode */ + "mfmsr %0 \n\t" + "oris %0,%0,%2 \n\t" + "sync \n\t" + "mtmsr %0 \n\t" + "isync \n\t" + : "=&r" (msr) + : "0" (msr), "i" (MSR_POW>>16), + "r" (hid0), + "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP), + "r" (HID0_NAP)); } - diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.1.78/linux/arch/ppc/kernel/irq.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/irq.c Mon Jan 12 15:18:13 1998 @@ -38,17 +38,22 @@ #include #include #include +#include #undef SHOW_IRQ -#define OPENPIC_DEBUG unsigned lost_interrupts = 0; unsigned int local_irq_count[NR_CPUS]; static struct irqaction irq_action[NR_IRQS]; static int spurious_interrupts = 0; -int __ppc_bh_counter; static unsigned int cached_irq_mask = 0xffffffff; static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +spinlock_t irq_controller_lock; +#ifdef __SMP__ +atomic_t __ppc_bh_counter = ATOMIC_INIT(0); +#else +int __ppc_bh_counter = 0; +#endif #define cached_21 (((char *)(&cached_irq_mask))[3]) #define cached_A1 (((char *)(&cached_irq_mask))[2]) @@ -57,7 +62,8 @@ * These are set to the appropriate functions by init_IRQ() */ void (*mask_and_ack_irq)(int irq_nr); -void (*set_irq_mask)(int irq_nr); +void (*mask_irq)(unsigned int irq_nr); +void (*unmask_irq)(unsigned int irq_nr); /* prep */ @@ -72,8 +78,6 @@ #define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */ #define PMAC_IRQ_MASK (~ld_le32(IRQ_ENABLE)) -/* chrp */ -volatile struct Hydra *Hydra = NULL; void i8259_mask_and_ack_irq(int irq_nr) { @@ -97,10 +101,14 @@ void pmac_mask_and_ack_irq(int irq_nr) { + unsigned long bit = 1UL << irq_nr; + spin_lock(&irq_controller_lock); - cached_irq_mask |= 1 << irq_nr; - out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr)); - out_le32(IRQ_ACK, 1U << irq_nr); + cached_irq_mask |= bit; + lost_interrupts &= ~bit; + out_le32(IRQ_ACK, bit); + out_le32(IRQ_ENABLE, ~cached_irq_mask); + out_le32(IRQ_ACK, bit); spin_unlock(&irq_controller_lock); } @@ -109,11 +117,10 @@ /* spinlocks are done by i8259_mask_and_ack() - Cort */ if (is_8259_irq(irq_nr)) i8259_mask_and_ack_irq(irq_nr); - openpic_eoi(0); } -void i8259_set_irq_mask(int irq_nr) +static void i8259_set_irq_mask(int irq_nr) { if (irq_nr > 7) { outb(cached_A1,0xA1); @@ -122,8 +129,10 @@ } } -void pmac_set_irq_mask(int irq_nr) +static void pmac_set_irq_mask(int irq_nr) { + unsigned long bit = 1UL << irq_nr; + /* this could be being enabled or disabled - so use cached_irq_mask */ out_le32(IRQ_ENABLE, ~cached_irq_mask /* enable all unmasked */ ); /* @@ -131,39 +140,53 @@ * when the device interrupt is already on *doesn't* set * the bit in the flag register or request another interrupt. */ - if ((ld_le32(IRQ_LEVEL) & (1UL<= 0; --irq) if (bits & (1U << irq)) break; @@ -246,30 +429,37 @@ * * This should go in the above mask/ack code soon. -- Cort */ - irq = (*(volatile unsigned char *)0xfec80000) & 0x0f; + irq = *(volatile unsigned char *)GG2_INT_ACK_SPECIAL; + /* + * Acknowledge as soon as possible to allow i8259 + * interrupt nesting + */ + openpic_eoi(0); + openpic_eoi_done = 1; } - else if (irq >= 64) + else if (irq >= OPENPIC_VEC_TIMER) { /* * OpenPIC interrupts >64 will be used for other purposes * like interprocessor interrupts and hardware errors */ -#ifdef OPENPIC_DEBUG - printk("OpenPIC interrupt %d\n", irq); -#endif - if (irq==99) + if (irq == OPENPIC_VEC_SPURIOUS) { + /* + * Spurious interrupts should never be + * acknowledged + */ spurious_interrupts++; - } - else { - /* - * Here we should process IPI timer - * for now the interrupt is dismissed. - */ + openpic_eoi_done = 1; + } else { + /* + * Here we should process IPI timer + * for now the interrupt is dismissed. + */ + } goto out; } break; - case _MACH_IBM: - case _MACH_Motorola: + case _MACH_prep: #if 1 outb(0x0C, 0x20); irq = inb(0x20) & 7; @@ -314,12 +504,11 @@ status = 0; action = irq_action + irq; kstat.interrupts[irq]++; - if ( action && action->handler) - { + if (action->handler) { if (!(action->flags & SA_INTERRUPT)) __sti(); status |= action->flags; - action->handler(irq, action->dev_id, regs); + action->handler(irq, action->dev_id, regs); /*if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq);*/ __cli(); /* in case the handler turned them on */ @@ -337,6 +526,8 @@ goto retry_cascade; /* do_bottom_half is called if necessary from int_return in head.S */ out: + if (_machine == _MACH_chrp && !openpic_eoi_done) + openpic_eoi(0); hardirq_exit(cpu); } @@ -369,6 +560,7 @@ restore_flags(flags); return 0; } + void free_irq(unsigned int irq, void *dev_id) { struct irqaction * action = irq + irq_action; @@ -411,17 +603,15 @@ { /* init master interrupt controller */ outb(0x11, 0x20); /* Start init sequence */ - outb(0x40, 0x21); /* Vector base */ - /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */ - outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */ + outb(0x00, 0x21); /* Vector base */ + outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ outb(0x01, 0x21); /* Select 8086 mode */ outb(0xFF, 0x21); /* Mask all */ /* init slave interrupt controller */ outb(0x11, 0xA0); /* Start init sequence */ - outb(0x48, 0xA1); /* Vector base */ - /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */ - outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */ + outb(0x08, 0xA1); /* Vector base */ + outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ outb(0x01, 0xA1); /* Select 8086 mode */ outb(0xFF, 0xA1); /* Mask all */ outb(cached_A1, 0xA1); @@ -439,17 +629,30 @@ { case _MACH_Pmac: mask_and_ack_irq = pmac_mask_and_ack_irq; - set_irq_mask = pmac_set_irq_mask; + mask_irq = pmac_mask_irq; + unmask_irq = pmac_unmask_irq; *IRQ_ENABLE = 0; #ifdef CONFIG_XMON request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0); #endif /* CONFIG_XMON */ break; - case _MACH_Motorola: - case _MACH_IBM: + case _MACH_chrp: + mask_and_ack_irq = chrp_mask_and_ack_irq; + mask_irq = chrp_mask_irq; + unmask_irq = chrp_unmask_irq; + ioremap(GG2_INT_ACK_SPECIAL, 1); + openpic_init(); + i8259_init(); +#ifdef CONFIG_XMON + request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI), + xmon_irq, 0, "NMI", 0); +#endif /* CONFIG_XMON */ + break; + case _MACH_prep: mask_and_ack_irq = i8259_mask_and_ack_irq; - set_irq_mask = i8259_set_irq_mask; + mask_irq = i8259_mask_irq; + unmask_irq = i8259_unmask_irq; i8259_init(); route_pci_interrupts(); @@ -472,46 +675,20 @@ /* * On Carolina, irq 15 and 13 must be level (scsi/ide/net). */ - if ( _machine == _MACH_IBM ) + if ( _prep_type == _PREP_IBM ) irq_mode2 |= 0xa0; /* * Sound on the Powerstack reportedly needs to be edge triggered */ - if ( _machine == _MACH_Motorola ) + if ( _prep_type == _PREP_Motorola ) { - /*irq_mode2 &= ~0x04L; + irq_mode2 &= ~0x04L; + irq_mode2 = 0xca; outb( irq_mode1 , 0x4d0 ); - outb( irq_mode2 , 0x4d1 );*/ + outb( irq_mode2 , 0x4d1 ); } } - break; - case _MACH_chrp: - mask_and_ack_irq = chrp_mask_and_ack_irq; - set_irq_mask = chrp_set_irq_mask; - if ((Hydra = find_hydra())) { - printk("Hydra Mac I/O at %p\n", Hydra); - out_le32(&Hydra->Feature_Control, HYDRA_FC_SCC_CELL_EN | - HYDRA_FC_SCSI_CELL_EN | - HYDRA_FC_SCCA_ENABLE | - HYDRA_FC_SCCB_ENABLE | - HYDRA_FC_ARB_BYPASS | - HYDRA_FC_MPIC_ENABLE | - HYDRA_FC_SLOW_SCC_PCLK | - HYDRA_FC_MPIC_IS_MASTER); - OpenPIC = (volatile struct OpenPIC *)&Hydra->OpenPIC; - } else if (!OpenPIC /* && find_xxx */) { - printk("Unknown openpic implementation\n"); - /* other OpenPIC implementations */ - /* ... */ - } - if (OpenPIC) - openpic_init(); - else - panic("No OpenPIC found"); - if (Hydra) - hydra_post_openpic_init(); - i8259_init(); break; } } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.1.78/linux/arch/ppc/kernel/misc.S Wed Sep 24 20:05:45 1997 +++ linux/arch/ppc/kernel/misc.S Mon Jan 12 15:18:13 1998 @@ -2,14 +2,16 @@ * This file contains miscellaneous low-level functions. * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * - * 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. + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * + * 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. * */ -#include #include #include #include @@ -26,7 +28,21 @@ addi r4,r4,0x1000; \ bdnz 0b -_TEXT() + .text + +/* + * Returns (address we're running at) - (address we were linked at) + * for use before the text and data are mapped to KERNELBASE. + */ +_GLOBAL(reloc_offset) + mflr r0 + bl 1f +1: mflr r3 + lis r4,1b@ha + addi r4,r4,1b@l + subf r3,r4,r3 + mtlr r0 + blr /* * Disable interrupts @@ -64,24 +80,6 @@ mtmsr r3 /* Update machine state */ blr -#if 0 -/* - * Restore 'flags' - * __restore_flags(long val) - */ -_GLOBAL(__restore_flags) - andi. r0,r3,MSR_EE /* enabling interrupts? */ - beq 2f - lis r4,lost_interrupts@ha - lwz r4,lost_interrupts@l(r4) - cmpi 0,r4,0 - bne do_lost_interrupts -2: sync /* Some chip revs have problems here... */ - mtmsr r3 - isync - blr -#endif - /* * We were about to enable interrupts but we have to simulate * some interrupts that were lost by enable_irq first. @@ -151,6 +149,13 @@ stwcx. r5,0,r4 /* Update with new value */ bne- 10b /* Retry if "reservation" (i.e. lock) lost */ blr +_GLOBAL(atomic_add_return) +10: lwarx r5,0,r4 /* Fetch old value & reserve */ + add r5,r5,r3 /* Perform 'add' operation */ + stwcx. r5,0,r4 /* Update with new value */ + bne- 10b /* Retry if "reservation" (i.e. lock) lost */ + mr r3,r5 + blr _GLOBAL(atomic_sub) 10: lwarx r5,0,r4 /* Fetch old value & reserve */ sub r5,r5,r3 /* Perform 'add' operation */ @@ -209,11 +214,29 @@ /* * I/O string operations * + * insb(port, buf, len) + * outsb(port, buf, len) * insw(port, buf, len) * outsw(port, buf, len) * insl(port, buf, len) * outsl(port, buf, len) */ +_GLOBAL(_insb) + mtctr r5 + subi r4,r4,1 +00: lbz r5,0(r3) + stbu r5,1(r4) + bdnz 00b + blr + +_GLOBAL(_outsb) + mtctr r5 + subi r4,r4,1 +00: lbzu r5,1(r4) + stb r5,0(r3) + bdnz 00b + blr + _GLOBAL(_insw) mtctr r5 subi r4,r4,2 @@ -325,6 +348,33 @@ stfs 0,0(r4) blr + +_GLOBAL(lock_dcache) + mfspr r3,PVR /* nop on 601 */ + rlwinm r3,r3,16,16,31 + cmpwi 0,r3,1 + beqlr- + mfspr r3,HID0 + ori r3,r3,HID0_DLOCK + mtspr HID0,r3 + sync + isync + blr + +_GLOBAL(unlock_dcache) + mfspr r3,PVR /* nop on 601 */ + rlwinm r3,r3,16,16,31 + cmpwi 0,r3,1 + beqlr- + mfspr r3,HID0 + li r4,HID0_DLOCK + andc r3,r3,r4 + mtspr HID0,r3 + sync + isync + blr + + /* * Create a kernel thread * __kernel_thread(flags, fn, arg) @@ -387,7 +437,7 @@ .long sys_mknod .long sys_chmod /* 15 */ .long sys_chown - .long sys_break + .long /*sys_break*/ sys_ni_syscall .long sys_stat .long sys_lseek .long sys_getpid /* 20 */ @@ -401,11 +451,11 @@ .long sys_fstat .long sys_pause .long sys_utime /* 30 */ - .long sys_stty - .long sys_gtty + .long /*sys_stty*/ sys_ni_syscall + .long /*sys_gtty*/ sys_ni_syscall .long sys_access .long sys_nice - .long sys_ftime /* 35 */ + .long /*sys_ftime*/ sys_ni_syscall /* 35 */ .long sys_sync .long sys_kill .long sys_rename @@ -414,7 +464,7 @@ .long sys_dup .long sys_pipe .long sys_times - .long sys_prof + .long /*sys_prof*/ sys_ni_syscall .long sys_brk /* 45 */ .long sys_setgid .long sys_getgid @@ -422,13 +472,13 @@ .long sys_geteuid .long sys_getegid /* 50 */ .long sys_acct - .long sys_phys - .long sys_lock + .long /*sys_phys*/ sys_ni_syscall + .long /*sys_lock*/ sys_ni_syscall .long sys_ioctl .long sys_fcntl /* 55 */ - .long sys_mpx + .long /*sys_mpx*/ sys_ni_syscall .long sys_setpgid - .long sys_ulimit + .long /*sys_ulimit*/ sys_ni_syscall .long sys_olduname .long sys_umask /* 60 */ .long sys_chroot @@ -468,7 +518,7 @@ .long sys_fchown /* 95 */ .long sys_getpriority .long sys_setpriority - .long sys_profil + .long /*sys_profil*/ sys_ni_syscall .long sys_statfs .long sys_fstatfs /* 100 */ .long sys_ioperm @@ -539,7 +589,8 @@ .long sys_query_module .long sys_poll .long sys_nfsservctl + .long sys_setresgid + .long sys_getresgid /* 170 */ .long sys_prctl - .long sys_debug .space (NR_syscalls-171)*4 diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c --- v2.1.78/linux/arch/ppc/kernel/mk_defs.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/mk_defs.c Mon Jan 12 15:18:13 1998 @@ -32,12 +32,12 @@ DEFINE(STATE, offsetof(struct task_struct, state)); DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task)); DEFINE(COUNTER, offsetof(struct task_struct, counter)); - DEFINE(BLOCKED, offsetof(struct task_struct, blocked)); - DEFINE(SIGNAL, offsetof(struct task_struct, signal)); + DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending)); DEFINE(TSS, offsetof(struct task_struct, tss)); - DEFINE(KSP, offsetof(struct thread_struct, ksp)); - /*DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));*/ DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct)); + DEFINE(KSP, offsetof(struct thread_struct, ksp)); + DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables)); DEFINE(PGD, offsetof(struct mm_struct, pgd)); DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c --- v2.1.78/linux/arch/ppc/kernel/openpic.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/openpic.c Mon Jan 12 15:18:13 1998 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,21 +29,12 @@ #undef REGISTER_DEBUG -#define VEC_TIMER 0x40 /* and up */ -#define VEC_IPI 0x50 /* and up */ -#define VEC_SOURCE 0x10 /* and up */ -#define VEC_SPURIOUS 99 +volatile struct OpenPIC *OpenPIC = NULL; +u_int OpenPIC_NumInitSenses __initdata = 0; +u_char *OpenPIC_InitSenses __initdata = NULL; - -volatile struct OpenPIC *OpenPIC; - -static u_int Version; static u_int NumProcessors; static u_int NumSources; -static u_int VendorID; -static u_int DeviceID; -static u_int Stepping; -static u_int TimerFrequency; /* @@ -181,24 +173,17 @@ * Initialize the OpenPIC */ -void openpic_init(void) +__initfunc(void openpic_init(void)) { u_int t, i; + u_int vendorid, devid, stepping, timerfreq; const char *version, *vendor, *device; - if (!OpenPIC) { - printk("No OpenPIC present\n"); - return; - } + if (!OpenPIC) + panic("No OpenPIC found"); t = openpic_read(&OpenPIC->Global.Feature_Reporting0); - Version = t & OPENPIC_FEATURE_VERSION_MASK; - NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> - OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; - NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> - OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; - - switch (Version) { + switch (t & OPENPIC_FEATURE_VERSION_MASK) { case 1: version = "1.0"; break; @@ -206,19 +191,23 @@ version = "1.2"; break; default: - version = "?.?"; + version = "?"; break; } + NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> + OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; + NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> + OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version, NumProcessors, NumSources, OpenPIC); t = openpic_read(&OpenPIC->Global.Vendor_Identification); - VendorID = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK; - DeviceID = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >> - OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT; - Stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >> + vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK; + devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >> + OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT; + stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >> OPENPIC_VENDOR_ID_STEPPING_SHIFT; - switch (VendorID) { + switch (vendorid) { case OPENPIC_VENDOR_ID_APPLE: vendor = "Apple"; break; @@ -226,7 +215,7 @@ vendor = "Unknown"; break; } - switch (DeviceID) { + switch (devid) { case OPENPIC_DEVICE_ID_APPLE_HYDRA: device = "Hydra"; break; @@ -234,20 +223,20 @@ device = "Unknown"; break; } - printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", VendorID, - vendor, DeviceID, device, Stepping); + printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid, + vendor, devid, device, stepping); - TimerFrequency = openpic_read(&OpenPIC->Global.Timer_Frequency); + timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); printk("OpenPIC timer frequency is "); - if (TimerFrequency) - printk("%d Hz\n", TimerFrequency); + if (timerfreq) + printk("%d Hz\n", timerfreq); else printk("not set\n"); /* Initialize timer interrupts */ for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { /* Disabled, Priority 0 */ - openpic_inittimer(i, 0, VEC_TIMER+i); + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); /* No processor */ openpic_maptimer(i, 0); } @@ -255,23 +244,24 @@ /* Initialize IPI interrupts */ for (i = 0; i < OPENPIC_NUM_IPI; i++) { /* Disabled, Priority 0 */ - openpic_initipi(i, 0, VEC_IPI+i); + openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); } /* Initialize external interrupts */ /* SIOint (8259 cascade) is special */ - openpic_initirq(0, 8, VEC_SOURCE, 1, 1); /* 0,1 gives interrupt storm */ + openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1); /* Processor 0 */ openpic_mapirq(0, 1<<0); for (i = 1; i < NumSources; i++) { /* Enabled, Priority 8 */ - openpic_initirq(i, 8, VEC_SOURCE+i, 0, 1); + openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0, + i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); /* Processor 0 */ openpic_mapirq(i, 1<<0); } /* Initialize the spurious interrupt */ - openpic_set_spurious(VEC_SPURIOUS); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, "OpenPIC cascade", NULL)) @@ -340,9 +330,6 @@ void openpic_eoi(u_int cpu) #endif { -#if 0 -printk("++openpic_eoi:\n"); -#endif check_arg_cpu(cpu); openpic_write(&OpenPIC->THIS_CPU.EOI, 0); } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.1.78/linux/arch/ppc/kernel/pci.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/pci.c Mon Jan 12 15:18:13 1998 @@ -1,22 +1,27 @@ /* - * $Id: pci.c,v 1.12 1997/08/27 05:05:28 cort Exp $ + * $Id: pci.c,v 1.18 1997/10/29 03:35:07 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ #include #include -/*#include */ +#include #include #include #include +#include +#include #include #include #include #include -unsigned long io_base; +#if !defined(CONFIG_MACH_SPECIFIC) +unsigned long isa_io_base; +unsigned long isa_mem_base; unsigned long pci_dram_offset; +#endif /* CONFIG_MACH_SPECIFIC */ /* * It would be nice if we could create a include/asm/pci.h and have just @@ -29,77 +34,56 @@ * -- Cort */ int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val); + unsigned char offset, unsigned char *val); int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val); + unsigned char offset, unsigned short *val); int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val); + unsigned char offset, unsigned int *val); int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val); + unsigned char offset, unsigned char val); int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val); + unsigned char offset, unsigned short val); int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val); -int (*ptr_pcibios_find_device)(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr); -int (*ptr_pcibios_find_class)(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr); + unsigned char offset, unsigned int val); extern int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val); + unsigned char offset, unsigned char *val); extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val); + unsigned char offset, unsigned short *val); extern int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val); + unsigned char offset, unsigned int *val); extern int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val); + unsigned char offset, unsigned char val); extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val); + unsigned char offset, unsigned short val); extern int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val); -extern int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr); -extern int pmac_pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr); + unsigned char offset, unsigned int val); extern int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val); + unsigned char offset, unsigned char *val); extern int chrp_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val); + unsigned char offset, unsigned short *val); extern int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val); + unsigned char offset, unsigned int *val); extern int chrp_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val); + unsigned char offset, unsigned char val); extern int chrp_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val); + unsigned char offset, unsigned short val); extern int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val); -extern int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr); -extern int chrp_pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr); + unsigned char offset, unsigned int val); extern int prep_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val); + unsigned char offset, unsigned char *val); extern int prep_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val); + unsigned char offset, unsigned short *val); extern int prep_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val); + unsigned char offset, unsigned int *val); extern int prep_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val); + unsigned char offset, unsigned char val); extern int prep_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val); + unsigned char offset, unsigned short val); extern int prep_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val); -extern int prep_pcibios_find_device(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr); -extern int prep_pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr); - + unsigned char offset, unsigned int val); int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) @@ -131,64 +115,94 @@ { return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val); } -int pcibios_find_device(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr) + +int pcibios_present(void) { - return ptr_pcibios_find_device(vendor,dev_id,index,bus_ptr,dev_fn_ptr); + return 1; } -int pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr) -{ - return ptr_pcibios_find_class(class_code,index,bus_ptr,dev_fn_ptr); + +int pcibios_find_device (unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->vendor == vendor && dev->device == device_id) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; } -int pcibios_present(void) +/* + * Given the class, find the n'th instance of that device + * in the system. + */ +int pcibios_find_class (unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) { - return 1; + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class == class_code) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; } + __initfunc(unsigned long -pcibios_init(unsigned long mem_start,unsigned long mem_end)) + pcibios_init(unsigned long mem_start,unsigned long mem_end)) +{ + return mem_start; +} + +__initfunc(void + setup_pci_ptrs(void)) { switch (_machine) { - case _MACH_Motorola: - case _MACH_IBM: + case _MACH_prep: ptr_pcibios_read_config_byte = prep_pcibios_read_config_byte; ptr_pcibios_read_config_word = prep_pcibios_read_config_word; ptr_pcibios_read_config_dword = prep_pcibios_read_config_dword; ptr_pcibios_write_config_byte = prep_pcibios_write_config_byte; ptr_pcibios_write_config_word = prep_pcibios_write_config_word; ptr_pcibios_write_config_dword = prep_pcibios_write_config_dword; - ptr_pcibios_find_device = prep_pcibios_find_device; - ptr_pcibios_find_class = prep_pcibios_find_class; break; - case _MACH_Pmac: + case _MACH_Pmac: ptr_pcibios_read_config_byte = pmac_pcibios_read_config_byte; ptr_pcibios_read_config_word = pmac_pcibios_read_config_word; ptr_pcibios_read_config_dword = pmac_pcibios_read_config_dword; ptr_pcibios_write_config_byte = pmac_pcibios_write_config_byte; ptr_pcibios_write_config_word = pmac_pcibios_write_config_word; ptr_pcibios_write_config_dword = pmac_pcibios_write_config_dword; - ptr_pcibios_find_device = pmac_pcibios_find_device; - ptr_pcibios_find_class = pmac_pcibios_find_class; break; - case _MACH_chrp: + case _MACH_chrp: ptr_pcibios_read_config_byte = chrp_pcibios_read_config_byte; ptr_pcibios_read_config_word = chrp_pcibios_read_config_word; ptr_pcibios_read_config_dword = chrp_pcibios_read_config_dword; ptr_pcibios_write_config_byte = chrp_pcibios_write_config_byte; ptr_pcibios_write_config_word = chrp_pcibios_write_config_word; ptr_pcibios_write_config_dword = chrp_pcibios_write_config_dword; - ptr_pcibios_find_device = chrp_pcibios_find_device; - ptr_pcibios_find_class = chrp_pcibios_find_class; break; } - return mem_start; } __initfunc(unsigned long -pcibios_fixup(unsigned long mem_start, unsigned long mem_end)) + pcibios_fixup(unsigned long mem_start, unsigned long mem_end)) { return mem_start; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.1.78/linux/arch/ppc/kernel/pmac_pci.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/pmac_pci.c Mon Jan 12 15:18:13 1998 @@ -135,11 +135,10 @@ bp = (struct bridge_data *) *mem_ptr; *mem_ptr += sizeof(struct bridge_data); bp->cfg_addr = (volatile unsigned int *) - (dev->addrs[0].address + 0x800000); + ioremap(dev->addrs[0].address + 0x800000, 0x1000); bp->cfg_data = (volatile unsigned char *) - (dev->addrs[0].address + 0xc00000); - bp->io_base = (void *) dev->addrs[0].address; - ioremap(dev->addrs[0].address, 0x800000); + ioremap(dev->addrs[0].address + 0xc00000, 0x1000); + bp->io_base = (void *) ioremap(dev->addrs[0].address, 0x10000); bp->bus_number = bus_range[0]; bp->max_bus = bus_range[1]; bp->next = bridge_list; @@ -328,96 +327,4 @@ udelay(2); out_le32((volatile unsigned int *)bp->cfg_data, val); return PCIBIOS_SUCCESSFUL; -} - -int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr) -{ - int bus, unit, fn, num, devfn; - unsigned int x, vendev; - unsigned char h; - - if (vendor == 0xffff) - return PCIBIOS_BAD_VENDOR_ID; - vendev = (dev_id << 16) + vendor; - num = 0; - for (bus = 0; bus <= max_bus; ++bus) { - if (bridges[bus] == 0) - continue; - unit = fn = 0; - if (bus == bridges[bus]->bus_number) - unit = 11; - while (unit < 32) { - devfn = PCI_DEVFN(unit, fn); - if (pcibios_read_config_dword(bus, devfn, - PCI_VENDOR_ID, &x) - == PCIBIOS_SUCCESSFUL && x == vendev) { - if (index == num) { - *bus_ptr = bus; - *dev_fn_ptr = devfn; - return PCIBIOS_SUCCESSFUL; - } - ++num; - } - if (fn != 0) { - if (++fn >= 8) { - ++unit; - fn = 0; - } - continue; - } - if (pcibios_read_config_byte(bus, devfn, - PCI_HEADER_TYPE, &h) - == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0) - ++fn; - else - ++unit; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - -int pmac_pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr) -{ - int bus, unit, fn, num, devfn; - unsigned int x; - unsigned char h; - - num = 0; - for (bus = 0; bus <= max_bus; ++bus) { - if (bridges[bus] == 0) - continue; - unit = fn = 0; - if (bus == bridges[bus]->bus_number) - unit = 11; - while (unit < 32) { - devfn = PCI_DEVFN(unit, fn); - if (pcibios_read_config_dword(bus, devfn, - PCI_CLASS_REVISION, &x) - == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) { - if (index == num) { - *bus_ptr = bus; - *dev_fn_ptr = devfn; - return PCIBIOS_SUCCESSFUL; - } - ++num; - } - if (fn != 0) { - if (++fn >= 8) { - ++unit; - fn = 0; - } - continue; - } - if (pcibios_read_config_byte(bus, devfn, - PCI_HEADER_TYPE, &h) - == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0) - ++fn; - else - ++unit; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.1.78/linux/arch/ppc/kernel/pmac_setup.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/pmac_setup.c Mon Jan 12 15:18:13 1998 @@ -37,12 +37,16 @@ #include #include #include +#ifdef CONFIG_ABSTRACT_CONSOLE +#include +#endif #include #include #include #include #include #include +#include #include "time.h" /* @@ -55,32 +59,18 @@ extern int root_mountflags; -extern char command_line[]; -extern char saved_command_line[256]; - unsigned char drive_info; #define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */ -extern unsigned long find_available_memory(void); +static void gc_init(const char *, int); -void pmac_setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +void +pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p) { - extern unsigned long *end_of_DRAM; struct device_node *cpu; int *fp; - strcpy(saved_command_line, command_line); - *cmdline_p = command_line; - - *memory_start_p = find_available_memory(); - *memory_end_p = (unsigned long) end_of_DRAM; - - set_prom_callback(); - - *memory_start_p = copy_device_tree(*memory_start_p, *memory_end_p); - /* Set loops_per_sec to a half-way reasonable value, for use until calibrate_delay gets called. */ cpu = find_type_devices("cpu"); @@ -90,6 +80,7 @@ switch (_get_PVR() >> 16) { case 4: /* 604 */ case 9: /* 604e */ + case 10: /* mach V (604ev5) */ case 20: /* 620 */ loops_per_sec = *fp; break; @@ -99,10 +90,33 @@ } else loops_per_sec = 50000000; } + + *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); + gc_init("gc", 0); + gc_init("ohare", 1); + +#ifdef CONFIG_ABSTRACT_CONSOLE + /* Frame buffer device based console */ + conswitchp = &fb_con; +#endif +} + +static void gc_init(const char *name, int isohare) +{ + struct device_node *np; + + for (np = find_devices(name); np != NULL; np = np->next) { + if (np->n_addrs > 0) + ioremap(np->addrs[0].address, np->addrs[0].size); + if (isohare) { + printk(KERN_INFO "Twiddling the magic ohare bits\n"); + out_le32(OMAGICPLACE, OMAGICCONT); + } + } } -char *bootpath; -char bootdevice[256]; +extern char *bootpath; +extern char *bootdevice; void *boot_host; int boot_target; int boot_part; @@ -111,31 +125,15 @@ unsigned long powermac_init(unsigned long mem_start, unsigned long mem_end) { - struct device_node *chosen_np, *ohare_np; - - mem_start = pmac_find_bridges(mem_start, mem_end); - ohare_np = find_devices("ohare"); - if (ohare_np != NULL) { - printk(KERN_INFO "Twiddling the magic ohare bits\n"); - out_le32(OMAGICPLACE, OMAGICCONT); - } pmac_nvram_init(); - via_cuda_init(); - pmac_read_rtc_time(); - pmac_find_display(); - bootpath = NULL; - chosen_np = find_devices("chosen"); - if (chosen_np != NULL) - bootpath = (char *) get_property(chosen_np, "bootpath", NULL); - if (bootpath != NULL) { - /* - * There's a bug in the prom. (Why am I not surprised.) - * If you pass a path like scsi/sd@1:0 to canon, it returns - * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 - * That is, the scsi target number doesn't get preserved. - */ - call_prom("canon", 3, 1, bootpath, bootdevice, sizeof(bootdevice)); + adb_init(); + if (_machine == _MACH_Pmac) { + pmac_read_rtc_time(); } +#ifdef CONFIG_PMAC_CONSOLE + pmac_find_display(); +#endif + return mem_start; } @@ -146,9 +144,17 @@ char *p; l = strlen(node->full_name); - if (strncmp(node->full_name, bootdevice, l) == 0 + if (bootpath != NULL && bootdevice != NULL + && strncmp(node->full_name, bootdevice, l) == 0 && (bootdevice[l] == '/' || bootdevice[l] == 0)) { boot_host = host; + /* + * There's a bug in OF 1.0.5. (Why am I not surprised.) + * If you pass a path like scsi/sd@1:0 to canon, it returns + * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 + * That is, the scsi target number doesn't get preserved. + * So we pick the target number out of bootpath and use that. + */ p = strstr(bootpath, "/sd@"); if (p != NULL) { p += 4; @@ -160,6 +166,28 @@ } } +#ifdef CONFIG_SCSI +/* Find the device number for the disk (if any) at target tgt + on host adaptor host. + XXX this really really should be in drivers/scsi/sd.c. */ +#include +#include "../../../drivers/scsi/scsi.h" +#include "../../../drivers/scsi/sd.h" +#include "../../../drivers/scsi/hosts.h" + +int sd_find_target(void *host, int tgt) +{ + Scsi_Disk *dp; + int i; + + for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) + if (dp->device != NULL && dp->device->host == host + && dp->device->id == tgt) + return MKDEV(SCSI_DISK_MAJOR, i << 4); + return 0; +} +#endif + void find_boot_device(void) { int dev; @@ -230,42 +258,8 @@ int pmac_get_cpuinfo(char *buffer) { - int pvr = _get_PVR(); - char *model; - struct device_node *cpu; - int l, *fp; - - l = 0; - cpu = find_type_devices("cpu"); - if (cpu != 0) { - fp = (int *) get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - l += sprintf(buffer, "%dMHz ", *fp / 1000000); - } - - switch (pvr>>16) { - case 1: - model = "601"; - break; - case 3: - model = "603"; - break; - case 4: - model = "604"; - break; - case 6: - model = "603e"; - break; - case 7: - model = "603ev"; - break; - case 9: - model = "604e"; - break; - default: - model = "unknown"; - break; - } - return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model, - (pvr & 0xff00) >> 8, pvr & 0xff); + int len; + /* should find motherboard type here as well */ + len = sprintf(buffer,"machine\t\t: PowerMac\n"); + return len; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c --- v2.1.78/linux/arch/ppc/kernel/pmac_support.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/pmac_support.c Mon Jan 12 15:18:13 1998 @@ -7,16 +7,18 @@ #include #include #include -#include #include #include /* - * Read and write the non-volatile RAM on PowerMacs. + * Read and write the non-volatile RAM on PowerMacs and CHRP machines. */ static int nvram_naddrs; static volatile unsigned char *nvram_addr; static volatile unsigned char *nvram_data; +static int nvram_mult; + +#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ void pmac_nvram_init(void) { @@ -29,8 +31,13 @@ return; } nvram_naddrs = dp->n_addrs; - if (nvram_naddrs == 1) { + if (_machine == _MACH_chrp && nvram_naddrs == 1) { + /* XXX for now */ + nvram_data = ioremap(0xf70e0000, NVRAM_SIZE); + nvram_mult = 1; + } else if (nvram_naddrs == 1) { nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; } else if (nvram_naddrs == 2) { nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); @@ -44,7 +51,7 @@ { switch (nvram_naddrs) { case 1: - return nvram_data[(addr & 0x1fff) << 4]; + return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]; case 2: *nvram_addr = addr >> 5; eieio(); @@ -57,7 +64,7 @@ { switch (nvram_naddrs) { case 1: - nvram_data[(addr & 0x1fff) << 4] = val; + nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val; break; case 2: *nvram_addr = addr >> 5; diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.1.78/linux/arch/ppc/kernel/pmac_time.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/pmac_time.c Mon Jan 12 15:18:13 1998 @@ -2,9 +2,7 @@ * Support for periodic interrupts (100 per second) and for getting * the current time from the RTC on Power Macintoshes. * - * At present, we use the decrementer register in the 601 CPU - * for our periodic interrupts. This will probably have to be - * changed for other processors. + * We use the decrementer register for our periodic interrupts. * * Paul Mackerras August 1996. * Copyright (C) 1996 Paul Mackerras. @@ -15,17 +13,79 @@ #include #include #include +#include #include #include #include #include "time.h" - /* Apparently the RTC stores seconds since 1 Jan 1904 */ #define RTC_OFFSET 2082844800 /* + * Calibrate the decrementer frequency with the VIA timer 1. + */ +#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ + +/* VIA registers */ +#define RS 0x200 /* skip between registers */ +#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ +#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ +#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ +#define ACR (11*RS) /* Auxiliary control register */ +#define IFR (13*RS) /* Interrupt flag register */ + +/* Bits in ACR */ +#define T1MODE 0xc0 /* Timer 1 mode */ +#define T1MODE_CONT 0x40 /* continuous interrupts */ + +/* Bits in IFR and IER */ +#define T1_INT 0x40 /* Timer 1 interrupt */ + +static int via_calibrate_decr(void) +{ + struct device_node *vias; + volatile unsigned char *via; + int count = VIA_TIMER_FREQ_6 / HZ; + unsigned int dstart, dend; + + vias = find_devices("via-cuda"); + if (vias == 0) + vias = find_devices("via-pmu"); + if (vias == 0 || vias->n_addrs == 0) + return 0; + via = (volatile unsigned char *) vias->addrs[0].address; + + /* set timer 1 for continuous interrupts */ + out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); + /* set the counter to a small value */ + out_8(&via[T1CH], 2); + /* set the latch to `count' */ + out_8(&via[T1LL], count); + out_8(&via[T1LH], count >> 8); + /* wait until it hits 0 */ + while ((in_8(&via[IFR]) & T1_INT) == 0) + ; + dstart = get_dec(); + /* clear the interrupt & wait until it hits 0 again */ + in_8(&via[T1CL]); + while ((in_8(&via[IFR]) & T1_INT) == 0) + ; + dend = get_dec(); + + decrementer_count = (dstart - dend) / 6; + count_period_num = 60; + count_period_den = decrementer_count * 6 * HZ / 100000; + + printk(KERN_INFO "via_calibrate_decr: decrementer_count = %u (%u ticks)\n", + decrementer_count, dstart - dend); + + return 1; +} + +/* * Query the OF and get the decr frequency. * This was taken from the pmac time_init() when merging the prep/pmac * time functions. @@ -35,6 +95,9 @@ struct device_node *cpu; int freq, *fp, divisor; + if (via_calibrate_decr()) + return; + /* * The cpu node should have a timebase-frequency property * to tell us the rate at which the decrementer counts. @@ -57,11 +120,11 @@ unsigned long pmac_get_rtc_time(void) { - struct cuda_request req; + struct adb_request req; /* Get the time from the RTC */ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME); - while (!req.got_reply) + while (!req.complete) cuda_poll(); if (req.reply_len != 7) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", @@ -84,4 +147,5 @@ { xtime.tv_sec = pmac_get_rtc_time(); xtime.tv_usec = 0; + last_rtc_update = xtime.tv_sec; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/ppc_asm.tmpl linux/arch/ppc/kernel/ppc_asm.tmpl --- v2.1.78/linux/arch/ppc/kernel/ppc_asm.tmpl Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/ppc_asm.tmpl Mon Jan 12 15:18:13 1998 @@ -1,27 +1,3 @@ -/* - * This file contains all the macros and symbols which define - * a PowerPC assembly language environment. - */ -#include -#define _TEXT()\ - .text - -#define _EXTERN(n) n - -#define SYMBOL_NAME(x) x - -#define _GLOBAL(n)\ - .globl n;\ -n: - -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif - -#define _ORG(n)\ - .org n - /* Register names */ #define r0 0 #define r1 1 @@ -88,102 +64,3 @@ #define fr29 29 #define fr30 30 #define fr31 31 - -/* Some special registers */ - -#define TBRU 269 /* Time base Upper/Lower (Reading) */ -#define TBRL 268 -#define TBWU 284 /* Time base Upper/Lower (Writing) */ -#define TBWL 285 -#define XER 1 -#define LR 8 -#define CTR 9 -#define HID0 1008 /* Hardware Implementation */ -#define PVR 287 /* Processor Version */ -#define IBAT0U 528 /* Instruction BAT #0 Upper/Lower */ -#define IBAT0L 529 -#define IBAT1U 530 /* Instruction BAT #1 Upper/Lower */ -#define IBAT1L 531 -#define IBAT2U 532 /* Instruction BAT #2 Upper/Lower */ -#define IBAT2L 533 -#define IBAT3U 534 /* Instruction BAT #3 Upper/Lower */ -#define IBAT3L 535 -#define DBAT0U 536 /* Data BAT #0 Upper/Lower */ -#define DBAT0L 537 -#define DBAT1U 538 /* Data BAT #1 Upper/Lower */ -#define DBAT1L 539 -#define DBAT2U 540 /* Data BAT #2 Upper/Lower */ -#define DBAT2L 541 -#define DBAT3U 542 /* Data BAT #3 Upper/Lower */ -#define DBAT3L 543 -#define DMISS 976 /* TLB Lookup/Refresh registers */ -#define DCMP 977 -#define HASH1 978 -#define HASH2 979 -#define IMISS 980 -#define ICMP 981 -#define RPA 982 -#define SDR1 25 /* MMU hash base register */ -#define DAR 19 /* Data Address Register */ -#define SPR0 272 /* Supervisor Private Registers */ -#define SPRG0 272 -#define SPR1 273 -#define SPRG1 273 -#define SPR2 274 -#define SPRG2 274 -#define SPR3 275 -#define SPRG3 275 -#define DSISR 18 -#define SRR0 26 /* Saved Registers (exception) */ -#define SRR1 27 -#define IABR 1010 /* Instruction Address Breakpoint */ -#define DEC 22 /* Decrementer */ -#define EAR 282 /* External Address Register */ - -/* Segment Registers */ -#define SR0 0 -#define SR1 1 -#define SR2 2 -#define SR3 3 -#define SR4 4 -#define SR5 5 -#define SR6 6 -#define SR7 7 -#define SR8 8 -#define SR9 9 -#define SR10 10 -#define SR11 11 -#define SR12 12 -#define SR13 13 -#define SR14 14 -#define SR15 15 - -#define curptr r2 - -/* - * Macros for storing registers into and loading registers from - * exception frames. - */ -#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) -#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) -#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) -#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) -#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) -#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) -#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) -#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) -#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) -#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) - -#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base) -#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) -#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) -#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) -#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) -#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) -#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base) -#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) -#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) -#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) -#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) -#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.1.78/linux/arch/ppc/kernel/ppc_htab.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/ppc_htab.c Mon Jan 12 15:18:13 1998 @@ -1,5 +1,5 @@ /* - * $Id: ppc_htab.c,v 1.7 1997/08/24 19:33:32 cort Exp $ + * $Id: ppc_htab.c,v 1.16 1997/11/17 18:25:04 cort Exp $ * * PowerPC hash table management proc entry. Will show information * about the current hash table and will allow changes to it. @@ -25,16 +25,19 @@ #include #include -static long ppc_htab_read(struct inode * inode, struct file * file, - char * buf, unsigned long nbytes); -static long ppc_htab_write(struct inode * inode, struct file * file, - const char * buffer, unsigned long count); -static long long ppc_htab_lseek(struct inode * inode, struct file * file, - long long offset, int orig); +static ssize_t ppc_htab_read(struct file * file, char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_htab_write(struct file * file, const char * buffer, + size_t count, loff_t *ppos); +static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig); extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern unsigned long _SDR1; +extern unsigned long htab_reloads; +extern unsigned long htab_evicts; +extern unsigned long pte_misses; +extern unsigned long pte_errors; static struct file_operations ppc_htab_operations = { ppc_htab_lseek, /* lseek */ @@ -72,24 +75,107 @@ NULL /* permission */ }; +/* these will go into processor.h when I'm done debugging -- Cort */ +#define MMCR0 952 +#define MMCR0_PMC1_CYCLES (0x1<<7) +#define MMCR0_PMC1_ICACHEMISS (0x5<<7) +#define MMCR0_PMC1_DTLB (0x6<<7) +#define MMCR0_PMC2_DCACHEMISS (0x6) +#define MMCR0_PMC2_CYCLES (0x1) +#define MMCR0_PMC2_ITLB (0x7) +#define MMCR0_PMC2_LOADMISSTIME (0x5) + +#define PMC1 953 +#define PMC2 954 + +char *pmc1_lookup(unsigned long mmcr0) +{ + switch ( mmcr0 & (0x7f<<7) ) + { + case 0x0: + return "none"; + case MMCR0_PMC1_CYCLES: + return "cycles"; + case MMCR0_PMC1_ICACHEMISS: + return "ic miss"; + case MMCR0_PMC1_DTLB: + return "dtlb miss"; + default: + return "unknown"; + } +} + +char *pmc2_lookup(unsigned long mmcr0) +{ + switch ( mmcr0 & 0x3f ) + { + case 0x0: + return "none"; + case MMCR0_PMC2_CYCLES: + return "cycles"; + case MMCR0_PMC2_DCACHEMISS: + return "dc miss"; + case MMCR0_PMC2_ITLB: + return "itlb miss"; + case MMCR0_PMC2_LOADMISSTIME: + return "load miss time"; + default: + return "unknown"; + } +} + /* * print some useful info about the hash table. This function * is _REALLY_ slow (see the nested for loops below) but nothing * in here should be really timing critical. -- Cort */ -static long ppc_htab_read(struct inode * inode, struct file * file, - char * buf, unsigned long nbytes) +static ssize_t ppc_htab_read(struct file * file, char * buf, + size_t count, loff_t *ppos) { + unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; int n = 0, valid; - unsigned int kptes = 0, overflow = 0, uptes = 0; + unsigned int kptes = 0, overflow = 0, uptes = 0, zombie_ptes = 0; PTE *ptr; struct task_struct *p; - char buffer[128]; - - if (nbytes < 0) + char buffer[512]; + + if (count < 0) return -EINVAL; + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + asm volatile ("mfspr %0,952 \n\t" + "mfspr %1,953 \n\t" + "mfspr %2,954 \n\t" + : "=r" (mmcr0), "=r" (pmc1), "=r" (pmc2) ); + n += sprintf( buffer + n, + "604 Performance Monitoring\n" + "MMCR0\t\t: %08lx %s%s ", + mmcr0, + ( mmcr0>>28 & 0x2 ) ? "(user mode counted)" : "", + ( mmcr0>>28 & 0x4 ) ? "(kernel mode counted)" : ""); + n += sprintf( buffer + n, + "\nPMC1\t\t: %08lx (%s)\n" + "PMC2\t\t: %08lx (%s)\n", + pmc1, pmc1_lookup(mmcr0), + pmc2, pmc2_lookup(mmcr0)); + break; + default: + break; + } + + + /* if we don't have a htab */ + if ( Hash_size == 0 ) + { + n += sprintf( buffer + n, "No Hash Table used\n"); + goto return_string; + } + /* * compute user/kernel pte's table this info can be * misleading since there can be valid (v bit set) entries @@ -97,11 +183,12 @@ * due to the way tlb invalidation is handled on the ppc * -- Cort */ - for ( ptr = Hash ; ptr < Hash_end ; ptr += sizeof(PTE)) + for ( ptr = Hash ; ptr < Hash_end ; ptr++) { if (ptr->v) { /* make sure someone is using this context/vsid */ + valid = 0; for_each_task(p) { if ( (ptr->vsid >> 4) == p->mm->context ) @@ -111,7 +198,10 @@ } } if ( !valid ) + { + zombie_ptes++; continue; + } /* user not allowed read or write */ if (ptr->pp == PP_RWXX) kptes++; @@ -122,7 +212,8 @@ } } - n += sprintf( buffer, + n += sprintf( buffer + n, + "PTE Hash Table Information\n" "Size\t\t: %luKb\n" "Buckets\t\t: %lu\n" "Address\t\t: %08lx\n" @@ -130,6 +221,7 @@ "User ptes\t: %u\n" "Kernel ptes\t: %u\n" "Overflows\t: %u\n" + "Zombies\t\t: %u\n" "Percent full\t: %%%lu\n", (unsigned long)(Hash_size>>10), (Hash_size/(sizeof(PTE)*8)), @@ -138,30 +230,233 @@ uptes, kptes, overflow, + zombie_ptes, ((kptes+uptes)*100) / (Hash_size/sizeof(PTE)) ); - if (file->f_pos >= strlen(buffer)) + n += sprintf( buffer + n, + "Reloads\t\t: %08lx\n" + "Evicts\t\t: %08lx\n" + "Non-error misses: %08lx\n" + "Error misses\t: %08lx\n", + htab_reloads, htab_evicts, pte_misses, pte_errors); + +return_string: + if (*ppos >= strlen(buffer)) return 0; - if (n > strlen(buffer) - file->f_pos) - n = strlen(buffer) - file->f_pos; - copy_to_user(buf, buffer + file->f_pos, n); - file->f_pos += n; + if (n > strlen(buffer) - *ppos) + n = strlen(buffer) - *ppos; + copy_to_user(buf, buffer + *ppos, n); + *ppos += n; return n; } /* - * Can't _yet_ adjust the hash table size while running. -- Cort + * Allow user to define performance counters and resize the hash table */ -static long -ppc_htab_write(struct inode * inode, struct file * file, - const char * buffer, unsigned long count) +static ssize_t ppc_htab_write(struct file * file, const char * buffer, + size_t count, loff_t *ppos) { - unsigned long size; - extern void reset_SDR1(void); - + unsigned long tmp; if ( current->uid != 0 ) return -EACCES; + /* don't set the htab size for now */ + if ( !strncmp( buffer, "size ", 5) ) + return -EBUSY; + + /* turn off performance monitoring */ + if ( !strncmp( buffer, "off", 3) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + asm volatile ("mtspr %0, %3 \n\t" + "mtspr %1, %3 \n\t" + "mtspr %2, %3 \n\t" + :: "i" (MMCR0), "i" (PMC1), "i" (PMC2), "r" (0)); + break; + default: + break; + } + + } + + if ( !strncmp( buffer, "reset", 5) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* reset PMC1 and PMC2 */ + asm volatile ( + "mtspr 953, %0 \n\t" + "mtspr 954, %0 \n\t" + :: "r" (0)); + break; + default: + break; + } + htab_reloads = 0; + htab_evicts = 0; + pte_misses = 0; + pte_errors = 0; + } + + if ( !strncmp( buffer, "user", 4) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* setup mmcr0 and clear the correct pmc */ + asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0)); + tmp &= ~(0x60000000); + tmp |= 0x20000000; + asm volatile ( + "mtspr %1,%0 \n\t" /* set new mccr0 */ + "mtspr %3,%4 \n\t" /* reset the pmc */ + "mtspr %5,%4 \n\t" /* reset the pmc2 */ + :: "r" (tmp), "i" (MMCR0), "i" (0), + "i" (PMC1), "r" (0), "i"(PMC2) ); + break; + default: + break; + } + } + + if ( !strncmp( buffer, "kernel", 6) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* setup mmcr0 and clear the correct pmc */ + asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0)); + tmp &= ~(0x60000000); + tmp |= 0x40000000; + asm volatile ( + "mtspr %1,%0 \n\t" /* set new mccr0 */ + "mtspr %3,%4 \n\t" /* reset the pmc */ + "mtspr %5,%4 \n\t" /* reset the pmc2 */ + :: "r" (tmp), "i" (MMCR0), "i" (0), + "i" (PMC1), "r" (0), "i"(PMC2) ); + break; + default: + break; + } + } + + /* PMC1 values */ + if ( !strncmp( buffer, "dtlb", 4) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* setup mmcr0 and clear the correct pmc */ + asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0)); + tmp &= ~(0x7f<<7); + tmp |= MMCR0_PMC1_DTLB; + asm volatile ( + "mtspr %1,%0 \n\t" /* set new mccr0 */ + "mtspr %3,%4 \n\t" /* reset the pmc */ + :: "r" (tmp), "i" (MMCR0), "i" (MMCR0_PMC1_DTLB), + "i" (PMC1), "r" (0) ); + } + } + + if ( !strncmp( buffer, "ic miss", 7) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* setup mmcr0 and clear the correct pmc */ + asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0)); + tmp &= ~(0x7f<<7); + tmp |= MMCR0_PMC1_ICACHEMISS; + asm volatile ( + "mtspr %1,%0 \n\t" /* set new mccr0 */ + "mtspr %3,%4 \n\t" /* reset the pmc */ + :: "r" (tmp), "i" (MMCR0), + "i" (MMCR0_PMC1_ICACHEMISS), "i" (PMC1), "r" (0)); + } + } + + /* PMC2 values */ + if ( !strncmp( buffer, "load miss time", 14) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* setup mmcr0 and clear the correct pmc */ + asm volatile( + "mfspr %0,%1\n\t" /* get current mccr0 */ + "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */ + "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */ + "mtspr %1,%0 \n\t" /* set new mccr0 */ + "mtspr %3,%4 \n\t" /* reset the pmc */ + : "=r" (tmp) + : "i" (MMCR0), "i" (MMCR0_PMC2_LOADMISSTIME), + "i" (PMC2), "r" (0) ); + } + } + + if ( !strncmp( buffer, "itlb", 4) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* setup mmcr0 and clear the correct pmc */ + asm volatile( + "mfspr %0,%1\n\t" /* get current mccr0 */ + "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */ + "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */ + "mtspr %1,%0 \n\t" /* set new mccr0 */ + "mtspr %3,%4 \n\t" /* reset the pmc */ + : "=r" (tmp) + : "i" (MMCR0), "i" (MMCR0_PMC2_ITLB), + "i" (PMC2), "r" (0) ); + } + } + + if ( !strncmp( buffer, "dc miss", 7) ) + { + switch ( _get_PVR()>>16 ) + { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* 604ev5 */ + /* setup mmcr0 and clear the correct pmc */ + asm volatile( + "mfspr %0,%1\n\t" /* get current mccr0 */ + "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */ + "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */ + "mtspr %1,%0 \n\t" /* set new mccr0 */ + "mtspr %3,%4 \n\t" /* reset the pmc */ + : "=r" (tmp) + : "i" (MMCR0), "i" (MMCR0_PMC2_DCACHEMISS), + "i" (PMC2), "r" (0) ); + } + } + + + return count; + +#if 0 /* resizing htab is a bit difficult right now -- Cort */ + unsigned long size; + extern void reset_SDR1(void); /* only know how to set size right now */ if ( strncmp( buffer, "size ", 5) ) @@ -196,14 +491,13 @@ flush_tlb_all(); reset_SDR1(); - printk("done\n"); +#endif return count; } static long long -ppc_htab_lseek(struct inode * inode, struct file * file, - long long offset, int orig) +ppc_htab_lseek(struct file * file, loff_t offset, int orig) { switch (orig) { case 0: diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.1.78/linux/arch/ppc/kernel/ppc_ksyms.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/ppc_ksyms.c Mon Jan 12 15:18:13 1998 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -14,23 +15,24 @@ #include #include #include +#include #include #include #include #include -void transfer_to_handler(); -void int_return(); -void syscall_trace(); -void do_IRQ(); -void MachineCheckException(); -void AlignmentException(); -void ProgramCheckException(); -void SingleStepException(); -void FloatingPointCheckException(); -void sys_sigreturn(); +extern void transfer_to_handler(void); +extern void int_return(void); +extern void syscall_trace(void); +extern void do_IRQ(struct pt_regs *regs); +extern void MachineCheckException(struct pt_regs *regs); +extern void AlignmentException(struct pt_regs *regs); +extern void ProgramCheckException(struct pt_regs *regs); +extern void SingleStepException(struct pt_regs *regs); +extern int sys_sigreturn(struct pt_regs *regs); extern unsigned lost_interrupts; extern void do_lost_interrupts(unsigned long); +extern int do_signal(sigset_t *, struct pt_regs *); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(syscall_trace); @@ -45,6 +47,12 @@ EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(lost_interrupts); EXPORT_SYMBOL(do_lost_interrupts); +EXPORT_SYMBOL(__ppc_bh_counter); + +#if !defined(CONFIG_MACH_SPECIFIC) +EXPORT_SYMBOL(isa_io_base); +EXPORT_SYMBOL(pci_dram_offset); +#endif EXPORT_SYMBOL(atomic_add); EXPORT_SYMBOL(atomic_sub); @@ -126,11 +134,12 @@ EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); +EXPORT_SYMBOL(adb_request); +EXPORT_SYMBOL(adb_autopoll); +EXPORT_SYMBOL(adb_register); EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_send_request); -EXPORT_SYMBOL(adb_register); EXPORT_SYMBOL(abort); -EXPORT_SYMBOL(call_prom); EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_path_device); diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.1.78/linux/arch/ppc/kernel/prep_pci.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/prep_pci.c Mon Jan 12 15:18:13 1998 @@ -1,5 +1,5 @@ /* - * $Id: prep_pci.c,v 1.7 1997/08/23 22:46:02 cort Exp $ + * $Id: prep_pci.c,v 1.12 1997/10/29 03:35:08 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -31,6 +31,83 @@ /* Tables for known hardware */ +/* Motorola PowerStackII - Utah */ +static char Utah_pci_IRQ_map[23] = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 4, /* Slot 2 - SCSI - NCR825A */ + 0, /* Slot 3 - unused */ + 1, /* Slot 4 - Ethernet - DEC2114x */ + 0, /* Slot 5 - unused */ + 2, /* Slot 6 - PCI Card slot #1 */ + 3, /* Slot 7 - PCI Card slot #2 */ + 4, /* Slot 8 - PCI Card slot #3 */ + 4, /* Slot 9 - PCI Bridge */ + /* added here in case we ever support PCI bridges */ + /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 4, /* Slot 12 - SCSI - NCR825A */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - enet */ + 0, /* Slot 15 - unused */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +static char Utah_pci_IRQ_routes[] = +{ + 0, /* Line 0 - Unused */ + 9, /* Line 1 */ + 11, /* Line 2 */ + 14, /* Line 3 */ + 15, /* Line 4 */ +}; + +/* Motorola PowerStackII - Omaha */ +/* no integrated SCSI or ethernet */ +static char Omaha_pci_IRQ_map[23] = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 3, /* Slot 2 - Winbond EIDE */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 1, /* Slot 6 - PCI slot 1 */ + 2, /* Slot 7 - PCI slot 2 */ + 3, /* Slot 8 - PCI slot 3 */ + 4, /* Slot 9 - PCI slot 4 */ /* needs indirect access */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 0, /* Slot 12 - unused */ + 0, /* Slot 13 - unused */ + 0, /* Slot 14 - unused */ + 0, /* Slot 15 - unused */ + 1, /* Slot 16 - PCI slot 1 */ + 2, /* Slot 17 - PCI slot 2 */ + 3, /* Slot 18 - PCI slot 3 */ + 4, /* Slot 19 - PCI slot 4 */ /* needs indirect access */ + 0, + 0, + 0, +}; + +static char Omaha_pci_IRQ_routes[] = +{ + 0, /* Line 0 - Unused */ + 9, /* Line 1 */ + 11, /* Line 2 */ + 14, /* Line 3 */ + 15 /* Line 4 */ +}; + /* Motorola PowerStack */ static char Blackhawk_pci_IRQ_map[16] = { @@ -323,59 +400,13 @@ return PCIBIOS_SUCCESSFUL; } -int prep_pcibios_find_device (unsigned short vendor, unsigned short device_id, - unsigned short index, unsigned char *bus, - unsigned char *devfn) -{ - unsigned int curr = 0; - struct pci_dev *dev; -/*printk("pcibios_find_device(): vendor %04x devid %04x index %d\n", - vendor,device_id,index);*/ - for (dev = pci_devices; dev; dev = dev->next) { -/*printk(" dev->vendor %04x dev->device %04x\n", - dev->vendor,dev->device);*/ - if (dev->vendor == vendor && dev->device == device_id) { - if (curr == index) { - *devfn = dev->devfn; - *bus = dev->bus->number; - return PCIBIOS_SUCCESSFUL; - } - ++curr; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - -/* - * Given the class, find the n'th instance of that device - * in the system. - */ -int prep_pcibios_find_class (unsigned int class_code, unsigned short index, - unsigned char *bus, unsigned char *devfn) -{ - unsigned int curr = 0; - struct pci_dev *dev; - - for (dev = pci_devices; dev; dev = dev->next) { - if (dev->class == class_code) { - if (curr == index) { - *devfn = dev->devfn; - *bus = dev->bus->number; - return PCIBIOS_SUCCESSFUL; - } - ++curr; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - __initfunc(unsigned long route_pci_interrupts(void)) { unsigned char *ibc_pirq = (unsigned char *)0x80800860; unsigned char *ibc_pcicon = (unsigned char *)0x80800840; int i; - if ( _machine == _MACH_Motorola) + if ( _prep_type == _PREP_Motorola) { switch (inb(0x800) & 0xF0) { @@ -385,18 +416,28 @@ Motherboard_routes = Genesis_pci_IRQ_routes; break; case 0x20: /* Series E */ - Motherboard_map_name = "Series E"; + Motherboard_map_name = "Powerstack (Series E)"; Motherboard_map = Comet_pci_IRQ_map; Motherboard_routes = Comet_pci_IRQ_routes; break; + case 0x50: /* PowerStackII Pro3000 */ + Motherboard_map_name = "Omaha (PowerStack II Pro3000)"; + Motherboard_map = Omaha_pci_IRQ_map; + Motherboard_routes = Omaha_pci_IRQ_routes; + case 0x60: /* PowerStackII Pro4000 */ + Motherboard_map_name = "Utah (Powerstack II Pro4000)"; + Motherboard_map = Utah_pci_IRQ_map; + Motherboard_routes = Utah_pci_IRQ_routes; + break; case 0x40: /* PowerStack */ default: /* Can't hurt, can it? */ + Motherboard_map_name = "Blackhawk (Powerstack)"; Motherboard_map = Blackhawk_pci_IRQ_map; Motherboard_routes = Blackhawk_pci_IRQ_routes; break; } - } else if ( _machine == _MACH_IBM ) + } else if ( _prep_type == _PREP_IBM ) { unsigned char pl_id; diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.1.78/linux/arch/ppc/kernel/prep_setup.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/prep_setup.c Mon Jan 12 15:18:13 1998 @@ -28,6 +28,9 @@ #include #include #include +#ifdef CONFIG_ABSTRACT_CONSOLE +#include +#endif #include #include @@ -36,15 +39,21 @@ #include #include +#ifdef CONFIG_SOUND +#include <../drivers/sound/sound_config.h> +#include <../drivers/sound/dev_table.h> +#endif + /* for the mac fs */ kdev_t boot_dev; +/* used in nasty hack for sound - see prep_setup_arch() -- Cort */ +long ppc_cs4232_dma, ppc_cs4232_dma2; +unsigned long empty_zero_page[1024]; extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern int probingmem; extern unsigned long loops_per_sec; - -unsigned long empty_zero_page[1024]; extern unsigned char aux_device_present; #ifdef CONFIG_BLK_DEV_RAM @@ -53,9 +62,6 @@ extern int rd_image_start; /* starting block # of image */ #endif - -extern char saved_command_line[256]; - void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) { ide_ioreg_t port = base; @@ -75,68 +81,25 @@ extern char *Motherboard_map_name; extern RESIDUAL res; int i; - int pvr = _get_PVR(); int len; - char *model; - - switch (pvr>>16) - { - case 1: - model = "601"; - break; - case 3: - model = "603"; - break; - case 4: - model = "604"; - break; - case 6: - model = "603e"; - break; - case 7: - model = "603ev"; - break; - default: - model = "unknown"; - break; - } #ifdef __SMP__ #define CD(X) (cpu_data[n].X) #else #define CD(X) (X) -#define CPUN 0 #endif - len = sprintf(buffer,"processor\t: %d\n" - "cpu\t\t: %s\n" - "revision\t: %d.%d\n" - "upgrade\t\t: %s\n" - "clock\t\t: %dMHz\n" - "bus clock\t: %dMHz\n" - "machine\t\t: %s (sn %s)\n" - "pci map\t\t: %s\n", - CPUN, - model, - MAJOR(pvr), MINOR(pvr), - (inb(IBM_EQUIP_PRESENT) & 2) ? "not upgrade" : "upgrade", - (res.VitalProductData.ProcessorHz > 1024) ? - res.VitalProductData.ProcessorHz>>20 : - res.VitalProductData.ProcessorHz, - (res.VitalProductData.ProcessorBusHz > 1024) ? - res.VitalProductData.ProcessorBusHz>>20 : - res.VitalProductData.ProcessorBusHz, - res.VitalProductData.PrintableModel, - res.VitalProductData.Serial, - Motherboard_map_name - ); - + len = sprintf(buffer,"machine\t\t: PReP %s\n",Motherboard_map_name); + + if ( res.ResidualLength == 0 ) + return len; + /* print info about SIMMs */ len += sprintf(buffer+len,"simms\t\t: "); for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ ) { if ( res.Memories[i].SIMMSize != 0 ) - len += sprintf(buffer+len,"%d:%dM ",i, + len += sprintf(buffer+len,"%d:%ldM ",i, (res.Memories[i].SIMMSize > 1024) ? res.Memories[i].SIMMSize>>20 : res.Memories[i].SIMMSize); @@ -148,11 +111,11 @@ switch(res.VitalProductData.TLBAttrib) { case CombinedTLB: - len += sprintf(buffer+len," %d entries\n", + len += sprintf(buffer+len," %ld entries\n", res.VitalProductData.TLBSize); break; case SplitTLB: - len += sprintf(buffer+len," (split I/D) %d/%d entries\n", + len += sprintf(buffer+len," (split I/D) %ld/%ld entries\n", res.VitalProductData.I_TLBSize, res.VitalProductData.D_TLBSize); break; @@ -166,12 +129,12 @@ switch(res.VitalProductData.CacheAttrib) { case CombinedCAC: - len += sprintf(buffer+len,"%dkB LineSize\n", + len += sprintf(buffer+len,"%ldkB LineSize %ldB\n", res.VitalProductData.CacheSize, res.VitalProductData.CacheLineSize); break; case SplitCAC: - len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n", + len += sprintf(buffer+len,"(split I/D) %ldkB/%ldkB Linesize %ldB/%ldB\n", res.VitalProductData.I_CacheSize, res.VitalProductData.D_CacheSize, res.VitalProductData.D_CacheLineSize, @@ -194,55 +157,18 @@ len += sprintf(buffer+len,"l2\t\t: not present\n"); } - - len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n", - CD(loops_per_sec+2500)/500000, - (CD(loops_per_sec+2500)/5000) % 100); - - /* - * Ooh's and aah's info about zero'd pages in idle task - */ - { - extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls; - len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) " - "current: %u (%uKb) hits: %u/%u (%lu%%)\n", - zerototal, (zerototal*PAGE_SIZE)>>10, - zerocount, (zerocount*PAGE_SIZE)>>10, - zeropage_hits,zeropage_calls, - /* : 1 below is so we don't div by zero */ - (zeropage_hits*100) / - ((zeropage_calls)?zeropage_calls:1)); - } return len; } __initfunc(void -prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p)) +prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) { extern char cmd_line[]; - extern char _etext[], _edata[], _end[]; - extern int panic_timeout; unsigned char reg; - /* Save unparsed command line copy for /proc/cmdline */ - strcpy( saved_command_line, cmd_line ); - *cmdline_p = cmd_line; - - *memory_start_p = (unsigned long) Hash+Hash_size; - (unsigned long *)*memory_end_p = (unsigned long *)(res.TotalMemory+KERNELBASE); - /* init to some ~sane value until calibrate_delay() runs */ loops_per_sec = 50000000; - /* reboot on panic */ - panic_timeout = 180; - - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = (unsigned long) _etext; - init_task.mm->end_data = (unsigned long) _edata; - init_task.mm->brk = (unsigned long) _end; - aux_device_present = 0xaa; /* Set up floppy in PS/2 mode */ outb(0x09, SIO_CONFIG_RA); @@ -250,24 +176,19 @@ reg = (reg & 0x3F) | 0x40; outb(reg, SIO_CONFIG_RD); outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ - - switch ( _machine ) + + /* we should determine this according to what we find! -- Cort */ + switch ( _prep_type ) { - case _MACH_IBM: + case _PREP_IBM: ROOT_DEV = to_kdev_t(0x0301); /* hda1 */ break; - case _MACH_Motorola: + case _PREP_Motorola: ROOT_DEV = to_kdev_t(0x0801); /* sda1 */ break; } #ifdef CONFIG_BLK_DEV_RAM -#if 0 - ROOT_DEV = to_kdev_t(0x0200); /* floppy */ - rd_prompt = 1; - rd_doload = 1; - rd_image_start = 0; -#endif /* initrd_start and size are setup by boot/head.S and kernel/head.S */ if ( initrd_start ) { @@ -282,13 +203,62 @@ #endif printk("Boot arguments: %s\n", cmd_line); - - print_residual_device_info(); - request_region(0x20,0x20,"pic1"); +#ifdef CONFIG_CS4232 + /* + * setup proper values for the cs4232 driver so we don't have + * to recompile for the motorola or ibm workstations sound systems. + * This is a really nasty hack, but unless we change the driver + * it's the only way to support both addrs from one binary. + * -- Cort + */ + if ( is_prep ) + { + extern struct card_info snd_installed_cards[]; + struct card_info *snd_ptr; + + for ( snd_ptr = snd_installed_cards; + snd_ptr < &snd_installed_cards[num_sound_cards]; + snd_ptr++ ) + { + if ( snd_ptr->card_type == SNDCARD_CS4232 ) + { + if ( _prep_type == _PREP_Motorola ) + { + snd_ptr->config.io_base = 0x830; + snd_ptr->config.irq = 10; + snd_ptr->config.dma = ppc_cs4232_dma = 6; + snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7; + } + if ( _prep_type == _PREP_IBM ) + { + snd_ptr->config.io_base = 0x530; + snd_ptr->config.irq = 5; + snd_ptr->config.dma = ppc_cs4232_dma = 1; + /* this is wrong - but leave it for now */ + snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7; + } + } + } + } +#endif /* CONFIG_CS4232 */ + + + /*print_residual_device_info();*/ + request_region(0x20,0x20,"pic1"); request_region(0xa0,0x20,"pic2"); request_region(0x00,0x20,"dma1"); request_region(0x40,0x20,"timer"); request_region(0x80,0x10,"dma page reg"); request_region(0xc0,0x20,"dma2"); + +#ifdef CONFIG_ABSTRACT_CONSOLE +#ifdef CONFIG_VGA_CONSOLE + conswitchp = &vga_con; +#endif +#ifdef CONFIG_FB + /* Frame buffer device based console */ + conswitchp = &fb_con; +#endif +#endif } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c --- v2.1.78/linux/arch/ppc/kernel/prep_time.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/prep_time.c Mon Jan 12 15:18:13 1998 @@ -56,9 +56,9 @@ int prep_cmos_clock_read(int addr) { - if ( _machine == _MACH_IBM ) + if ( _prep_type == _PREP_IBM ) return CMOS_READ(addr); - else if ( _machine == _MACH_Motorola ) + else if ( _prep_type == _PREP_Motorola ) { outb(clock_transl[addr]>>8, NVRAM_AS1); outb(clock_transl[addr], NVRAM_AS0); @@ -71,12 +71,12 @@ void prep_cmos_clock_write(unsigned long val, int addr) { - if ( _machine == _MACH_IBM ) + if ( _prep_type == _PREP_IBM ) { CMOS_WRITE(val,addr); return; } - else if ( _machine == _MACH_Motorola ) + else if ( _prep_type == _PREP_Motorola ) { outb(clock_transl[addr]>>8, NVRAM_AS1); outb(clock_transl[addr], NVRAM_AS0); diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.1.78/linux/arch/ppc/kernel/process.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/process.c Mon Jan 12 15:18:13 1998 @@ -1,15 +1,16 @@ + /* * linux/arch/ppc/kernel/process.c * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * * Derived from "arch/i386/kernel/process.c" * Copyright (C) 1995 Linus Torvalds * * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and * Paul Mackerras (paulus@cs.anu.edu.au) * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * * 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 @@ -38,15 +39,17 @@ #include #include #include +#include +#include int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs); void switch_to(struct task_struct *, struct task_struct *); -extern unsigned long _get_SP(void); +extern unsigned long _get_SP(void); +extern spinlock_t scheduler_lock; #undef SHOW_TASK_SWITCHES 1 #undef CHECK_STACK 1 -#undef IDLE_ZERO 1 unsigned long kernel_stack_top(struct task_struct *tsk) @@ -68,6 +71,9 @@ struct mm_struct init_mm = INIT_MM; union task_union init_task_union = { INIT_TASK }; +/* only used to get secondary processor up */ +struct task_struct *current_set[NR_CPUS] = {&init_task, }; + int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) { @@ -145,17 +151,30 @@ { struct thread_struct *new_tss, *old_tss; int s = _disable_interrupts(); - #if CHECK_STACK check_stack(prev); check_stack(new); #endif #ifdef SHOW_TASK_SWITCHES - printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n", - prev->comm,prev->pid,prev->tss.regs->nip, - new->comm,new->pid,new->tss.regs->nip,new->mm->context); + printk("%s/%d -> %s/%d cpu %d\n", + prev->comm,prev->pid, + new->comm,new->pid,new->processor); #endif +#ifdef __SMP__ + /* bad news if last_task_used_math changes processors right now -- Cort */ + if ( (last_task_used_math == new) && + (new->processor != new->last_processor) ) + panic("last_task_used_math switched processors"); + /* be noisy about processor changes for debugging -- Cort */ + if ( new->last_processor != new->processor ) + printk("switch_to(): changing cpu's %d -> %d %s/%d\n", + new->last_processor,new->processor, + new->comm,new->pid); + + prev->last_processor = prev->processor; + current_set[smp_processor_id()] = new; +#endif /* __SMP__ */ new_tss = &new->tss; old_tss = ¤t->tss; _switch(old_tss, new_tss, new->mm->context); @@ -181,7 +200,13 @@ printk("TASK = %p[%d] '%s' mm->pgd %p ", current, current->pid, current->comm, current->mm->pgd); printk("Last syscall: %ld ", current->tss.last_syscall); - printk("\nlast math %p\n", last_task_used_math); + printk("\nlast math %p", last_task_used_math); + +#ifdef __SMP__ + printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); +#endif /* __SMP__ */ + + printk("\n"); for (i = 0; i < 32; i++) { long r; @@ -226,7 +251,7 @@ struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; - + /* Copy registers */ childregs = ((struct pt_regs *) ((unsigned long)p + sizeof(union task_union) @@ -245,7 +270,6 @@ /* Provided stack is in user space */ childregs->gpr[1] = usp; } - p->tss.last_syscall = -1; /* @@ -321,6 +345,10 @@ lock_kernel(); ret = do_fork(SIGCHLD, regs->gpr[1], regs); +#if 0/*def __SMP__*/ + if ( ret ) /* drop scheduler lock in child */ + scheduler_lock.lock = 0L; +#endif /* __SMP__ */ unlock_kernel(); return ret; } @@ -332,6 +360,7 @@ int error; char * filename; + lock_kernel(); filename = getname((char *) a0); error = PTR_ERR(filename); if (IS_ERR(filename)) @@ -353,6 +382,16 @@ lock_kernel(); res = do_fork(clone_flags, regs->gpr[1], regs); +#ifdef __SMP__ + /* When we clone the idle task we keep the same pid but + * the return value of 0 for both causes problems. + * -- Cort + */ + if ((current->pid == 0) && (current == &init_task)) + res = 1; + if ( 0 /*res*/ ) /* drop scheduler lock in child */ + scheduler_lock.lock = 0L; +#endif /* __SMP__ */ unlock_kernel(); return res; } @@ -377,7 +416,6 @@ printk("\n"); } -#if 0 /* * Low level print for debugging - Cort */ @@ -394,15 +432,37 @@ return i; } -char *vidmem = (char *)0xC00B8000; int lines = 24, cols = 80; int orig_x = 0, orig_y = 0; void ll_puts(const char *s) { int x,y; + char *vidmem = (char *)(_ISA_MEM_BASE + 0xB8000) /*0xC00B8000*/; char c; + extern int mem_init_done; + + if ( mem_init_done ) /* assume this means we can printk */ + { + printk(s); + return; + } + +#if 0 + if ( have_of ) + { + prom_print(s); + return; + } +#endif + /* + * can't ll_puts on chrp without openfirmware yet. + * vidmem just needs to be setup for it. + * -- Cort + */ + if ( ! is_prep ) + return; x = orig_x; y = orig_y; @@ -430,4 +490,3 @@ orig_x = x; orig_y = y; } -#endif /* CONFIG_PREP */ diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.1.78/linux/arch/ppc/kernel/prom.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/prom.c Mon Jan 12 15:18:13 1998 @@ -8,33 +8,28 @@ * Paul Mackerras August 1996. * Copyright (C) 1996 Paul Mackerras. */ - #include #include #include #include -#include +#include #include #include #include -#define getpromprop(node, name, buf, len) \ - ((int)call_prom("getprop", 4, 1, (node), (name), (buf), (len))) - -ihandle prom_stdout; -ihandle prom_chosen; - -char command_line[256]; -int screen_initialized = 0; - -char prom_display_path[128]; +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This way we don't waste space storing + * things like "driver,AAPL,MacOS,PowerPC" properties. + */ +#define MAX_PROPERTY_LENGTH 1024 struct prom_args { const char *service; int nargs; int nret; void *args[10]; -} prom_args; +}; struct pci_address { unsigned a_hi; @@ -55,39 +50,83 @@ unsigned size_lo; }; -void (*prom_entry)(void *); -extern int prom_trashed; +char *prom_display_paths[FB_MAX] __initdata = { 0, }; +unsigned int prom_num_displays = 0; + +prom_entry prom = 0; +ihandle prom_chosen = 0, prom_stdout = 0; + +extern char *klimit; +char *bootpath = 0; +char *bootdevice = 0; -static int prom_callback(struct prom_args *); +unsigned int rtas_data = 0; +unsigned int rtas_entry = 0; + +static struct device_node *allnodes = 0; + +static void *call_prom(const char *service, int nargs, int nret, ...); +static void prom_print(const char *msg); +static void prom_exit(void); +static unsigned long copy_device_tree(unsigned long, unsigned long); static unsigned long inspect_node(phandle, struct device_node *, unsigned long, - unsigned long, unsigned long); -static void check_display(void); + unsigned long, struct device_node ***); +static unsigned long finish_node(struct device_node *, unsigned long, + unsigned long); +static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); -extern int pmac_display_supported(const char *); -extern void enter_prom(void *); +extern void enter_rtas(void *); +extern unsigned long reloc_offset(void); -void +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at, so + * references to extern and static variables must be relocated + * explicitly. The procedure reloc_offset() returns the the address + * we're currently running at minus the address we were linked at. + * (Note that strings count as static variables.) + * + * Because OF may have mapped I/O devices into the area starting at + * KERNELBASE, particularly on CHRP machines, we can't safely call + * OF once the kernel has been mapped to KERNELBASE. Therefore all + * OF calls should be done within prom_init(), and prom_init() + * and all routines called within it must be careful to relocate + * references as necessary. + * + * Note that the bss is cleared *after* prom_init runs, so we have + * to make sure that any static or extern variables it accesses + * are put in the data segment. + */ +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) +#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) - offset)) +#define RELOC(x) (*PTRRELOC(&(x))) + +#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) + +static void prom_exit() { struct prom_args args; + unsigned long offset = reloc_offset(); args.service = "exit"; args.nargs = 0; args.nret = 0; - enter_prom(&args); + RELOC(prom)(&args); for (;;) /* should never get here */ ; } -void * +static void * call_prom(const char *service, int nargs, int nret, ...) { va_list list; int i; + unsigned long offset = reloc_offset(); + struct prom_args prom_args; - if (prom_trashed) - panic("prom called after its memory was reclaimed"); prom_args.service = service; prom_args.nargs = nargs; prom_args.nret = nret; @@ -97,26 +136,26 @@ va_end(list); for (i = 0; i < nret; ++i) prom_args.args[i + nargs] = 0; - enter_prom(&prom_args); + RELOC(prom)(&prom_args); return prom_args.args[nargs]; } -void +static void prom_print(const char *msg) { const char *p, *q; - const char *crlf = "\r\n"; + unsigned long offset = reloc_offset(); - if (screen_initialized) - return; for (p = msg; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) ; if (q > p) - call_prom("write", 3, 1, prom_stdout, p, q - p); + call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout), + p, q - p); if (*q != 0) { ++q; - call_prom("write", 3, 1, prom_stdout, crlf, 2); + call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout), + RELOC("\r\n"), 2); } } } @@ -126,285 +165,311 @@ * handling exceptions and the MMU hash table for us. */ void -prom_init(char *params, int unused, void (*pp)(void *)) +prom_init(int r3, int r4, prom_entry pp) { + unsigned long mem; + ihandle prom_rtas; + unsigned int rtas_size; + unsigned long offset = reloc_offset(); + int l; + char *p, *d; + /* First get a handle for the stdout device */ - if ( ! have_of() ) - return; - prom_entry = pp; - prom_chosen = call_prom("finddevice", 1, 1, "/chosen"); - if (prom_chosen == (void *)-1) + RELOC(prom) = pp; + RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1, + RELOC("/chosen")); + if (RELOC(prom_chosen) == (void *)-1) + prom_exit(); + if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), + RELOC("stdout"), &RELOC(prom_stdout), + sizeof(prom_stdout)) <= 0) prom_exit(); - call_prom("getprop", 4, 1, prom_chosen, "stdout", &prom_stdout, - (void *) sizeof(prom_stdout)); - /* - * If we were booted via quik, params points to the physical address - * of the command-line parameters. - * If we were booted from an xcoff image (i.e. netbooted or - * booted from floppy), we get the command line from the bootargs - * property of the /chosen node. If an initial ramdisk is present, - * params and unused are used for initrd_start and initrd_size, - * otherwise they contain 0xdeadbeef. - */ - command_line[0] = 0; - if ((unsigned long) params >= 0x4000 - && (unsigned long) params < 0x800000 - && unused == 0) { - strncpy(command_line, params+KERNELBASE, sizeof(command_line)); - } else { -#ifdef CONFIG_BLK_DEV_INITRD - if ((unsigned long) params - KERNELBASE < 0x800000 - && unused != 0 && unused != 0xdeadbeef) { - initrd_start = (unsigned long) params; - initrd_end = initrd_start + unused; - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + /* Get the boot device and translate it to a full OF pathname. */ + mem = (unsigned long) RELOC(klimit) + offset; + p = (char *) mem; + l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), + RELOC("bootpath"), p, 1<<20); + if (l > 0) { + p[l] = 0; /* should already be null-terminated */ + RELOC(bootpath) = PTRUNRELOC(p); + mem += l + 1; + d = (char *) mem; + *d = 0; + call_prom(RELOC("canon"), 3, 1, p, d, 1<<20); + RELOC(bootdevice) = PTRUNRELOC(d); + mem = ALIGN(mem + strlen(d) + 1); + } + + mem = check_display(mem); + + prom_print(RELOC("copying OF device tree...")); + mem = copy_device_tree(mem, mem + (1<<20)); + prom_print(RELOC("done\n")); + + prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); + if (prom_rtas != (void *) -1) { + rtas_size = 0; + call_prom(RELOC("getprop"), 4, 1, prom_rtas, + RELOC("rtas-size"), &rtas_size, sizeof(rtas_size)); + prom_print(RELOC("instantiating rtas...")); + if (rtas_size == 0) { + RELOC(rtas_data) = 0; + } else { + mem = (mem + 4095) & -4096; /* round to page bdry */ + RELOC(rtas_data) = mem - KERNELBASE; + mem += rtas_size; } -#endif - call_prom("getprop", 4, 1, prom_chosen, "bootargs", - command_line, sizeof(command_line)); + RELOC(rtas_entry) = (unsigned int) + call_prom(RELOC("instantiate-rtas"), 1, 1, + RELOC(rtas_data)); + if (RELOC(rtas_entry) == -1) + prom_print(RELOC(" failed\n")); + else + prom_print(RELOC(" done\n")); } - command_line[sizeof(command_line) - 1] = 0; - check_display(); + RELOC(klimit) = (char *) (mem - offset); } /* * If we have a display that we don't know how to drive, * we will want to try to execute OF's open method for it - * later. However, OF may fall over if we do that after - * we've taken over the MMU and done set_prom_callback. + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. * So we check whether we will need to open the display, * and if so, open it now. */ -static void -check_display() +static unsigned long +check_display(unsigned long mem) { phandle node; ihandle ih; - char type[16], name[64], path[128]; + unsigned long offset = reloc_offset(); + char type[16], *path; for (node = 0; prom_next_node(&node); ) { type[0] = 0; - getpromprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, "display") != 0) - continue; - name[0] = 0; - getpromprop(node, "name", name, sizeof(name)); - if (pmac_display_supported(name)) - /* we have a supported display */ - return; - } - printk(KERN_INFO "No supported display found\n"); - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - getpromprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, "display") != 0) + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + if (strcmp(type, RELOC("display")) != 0) continue; /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - if ((int) call_prom("package-to-path", 3, 1, - node, path, sizeof(path) - 1) < 0) { - printk(KERN_WARNING "can't get path for display %p\n", - node); + path = (char *) mem; + memset(path, 0, 256); + if ((int) call_prom(RELOC("package-to-path"), 3, 1, + node, path, 255) < 0) continue; - } - ih = call_prom("open", 1, 1, path); + prom_print(RELOC("opening display ")); + prom_print(path); + ih = call_prom(RELOC("open"), 1, 1, path); if (ih == 0 || ih == (ihandle) -1) { - printk(KERN_WARNING "couldn't open display %s\n", - path); + prom_print(RELOC("... failed\n")); continue; } - printk(KERN_INFO "Opened display device %s using " - "Open Firmware\n", path); - strcpy(prom_display_path, path); - break; + prom_print(RELOC("... ok\n")); + mem += strlen(path) + 1; + RELOC(prom_display_paths[RELOC(prom_num_displays)++]) + = PTRUNRELOC(path); + if (RELOC(prom_num_displays) >= FB_MAX) + break; } + return ALIGN(mem); } static int prom_next_node(phandle *nodep) { phandle node; + unsigned long offset = reloc_offset(); if ((node = *nodep) != 0 - && (*nodep = call_prom("child", 1, 1, node)) != 0) + && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0) return 1; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) return 1; for (;;) { - if ((node = call_prom("parent", 1, 1, node)) == 0) + if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0) return 0; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) return 1; } } /* - * Callback routine for the PROM to call us. - * No services are implemented yet :-) - */ -static int -prom_callback(struct prom_args *argv) -{ - printk("uh oh, prom callback '%s' (%d/%d)\n", argv->service, - argv->nargs, argv->nret); - return -1; -} - -/* - * Register a callback with the Open Firmware PROM so it can ask - * us to map/unmap memory, etc. - */ -void -set_prom_callback() -{ - call_prom("set-callback", 1, 1, prom_callback); -} - -void -abort() -{ -#ifdef CONFIG_XMON - xmon(0); -#endif - prom_exit(); -} - -/* * Make a copy of the device tree from the PROM. */ - -static struct device_node *allnodes; -static struct device_node **allnextp; - -#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) - -unsigned long +static unsigned long copy_device_tree(unsigned long mem_start, unsigned long mem_end) { phandle root; - - root = call_prom("peer", 1, 1, (phandle)0); - if (root == (phandle)0) - panic("couldn't get device tree root\n"); - allnextp = &allnodes; - mem_start = inspect_node(root, 0, 0, mem_start, mem_end); + unsigned long new_start; + struct device_node **allnextp; + unsigned long offset = reloc_offset(); + + root = call_prom(RELOC("peer"), 1, 1, (phandle)0); + if (root == (phandle)0) { + prom_print(RELOC("couldn't get device tree root\n")); + prom_exit(); + } + allnextp = &RELOC(allnodes); + mem_start = ALIGN(mem_start); + new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); *allnextp = 0; - return mem_start; + return new_start; } static unsigned long -inspect_node(phandle node, struct device_node *dad, unsigned long base_address, - unsigned long mem_start, unsigned long mem_end) +inspect_node(phandle node, struct device_node *dad, + unsigned long mem_start, unsigned long mem_end, + struct device_node ***allnextpp) { - struct reg_property *reg, *rp; - struct pci_reg_property *pci_addrs; - int l, i; + int l; phandle child; struct device_node *np; struct property *pp, **prev_propp; - char *prev_name; + char *prev_name, *namep; + unsigned char *valp; + unsigned long offset = reloc_offset(); np = (struct device_node *) mem_start; mem_start += sizeof(struct device_node); memset(np, 0, sizeof(*np)); np->node = node; - *allnextp = np; - allnextp = &np->allnext; - np->parent = dad; + **allnextpp = PTRUNRELOC(np); + *allnextpp = &np->allnext; if (dad != 0) { + np->parent = PTRUNRELOC(dad); /* we temporarily use the `next' field as `last_child'. */ if (dad->next == 0) - dad->child = np; + dad->child = PTRUNRELOC(np); else - dad->next->sibling = np; + dad->next->sibling = PTRUNRELOC(np); dad->next = np; } /* get and store all properties */ prev_propp = &np->properties; - prev_name = 0; + prev_name = RELOC(""); for (;;) { pp = (struct property *) mem_start; - pp->name = (char *) (pp + 1); - if ((int) call_prom("nextprop", 3, 1, node, prev_name, - pp->name) <= 0) + namep = (char *) (pp + 1); + pp->name = PTRUNRELOC(namep); + if ((int) call_prom(RELOC("nextprop"), 3, 1, node, prev_name, + namep) <= 0) break; - mem_start = ALIGN((unsigned long)pp->name - + strlen(pp->name) + 1); - pp->value = (unsigned char *) mem_start; + mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + prev_name = namep; + valp = (unsigned char *) mem_start; + pp->value = PTRUNRELOC(valp); pp->length = (int) - call_prom("getprop", 4, 1, node, pp->name, pp->value, - mem_end - mem_start); + call_prom(RELOC("getprop"), 4, 1, node, namep, + valp, mem_end - mem_start); if (pp->length < 0) - panic("hey, where did property %s go?", pp->name); + continue; +#ifdef MAX_PROPERTY_LENGTH + if (pp->length > MAX_PROPERTY_LENGTH) + continue; /* ignore this property */ +#endif mem_start = ALIGN(mem_start + pp->length); - prev_name = pp->name; - *prev_propp = pp; + *prev_propp = PTRUNRELOC(pp); prev_propp = &pp->next; } *prev_propp = 0; + /* get the node's full name */ + l = (int) call_prom(RELOC("package-to-path"), 3, 1, node, + (char *) mem_start, mem_end - mem_start); + if (l >= 0) { + np->full_name = PTRUNRELOC((char *) mem_start); + *(char *)(mem_start + l) = 0; + mem_start = ALIGN(mem_start + l + 1); + } + + /* do all our children */ + child = call_prom(RELOC("child"), 1, 1, node); + while (child != (void *)0) { + mem_start = inspect_node(child, np, mem_start, mem_end, + allnextpp); + child = call_prom(RELOC("peer"), 1, 1, child); + } + + return mem_start; +} + +void +finish_device_tree(void) +{ + unsigned long mem = (unsigned long) klimit; + + mem = finish_node(allnodes, mem, 0UL); + printk(KERN_INFO "device tree used %lu bytes\n", + mem - (unsigned long) allnodes); + klimit = (char *) mem; +} + +static unsigned long +finish_node(struct device_node *np, unsigned long mem_start, + unsigned long base_address) +{ + struct reg_property *rp; + struct pci_reg_property *pci_addrs; + struct address_range *adr; + struct device_node *child; + int i, l; + np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); /* get all the device addresses and interrupts */ - reg = (struct reg_property *) mem_start; + adr = (struct address_range *) mem_start; pci_addrs = (struct pci_reg_property *) get_property(np, "assigned-addresses", &l); i = 0; if (pci_addrs != 0) { while ((l -= sizeof(struct pci_reg_property)) >= 0) { /* XXX assumes PCI addresses mapped 1-1 to physical */ - reg[i].address = pci_addrs[i].addr.a_lo; - reg[i].size = pci_addrs[i].size_lo; + adr[i].space = pci_addrs[i].addr.a_hi; + adr[i].address = pci_addrs[i].addr.a_lo; + adr[i].size = pci_addrs[i].size_lo; ++i; } } else { rp = (struct reg_property *) get_property(np, "reg", &l); if (rp != 0) { while ((l -= sizeof(struct reg_property)) >= 0) { - reg[i].address = rp[i].address + base_address; - reg[i].size = rp[i].size; + adr[i].space = 0; + adr[i].address = rp[i].address + base_address; + adr[i].size = rp[i].size; ++i; } } } if (i > 0) { - np->addrs = reg; + np->addrs = adr; np->n_addrs = i; - mem_start += i * sizeof(struct reg_property); + mem_start += i * sizeof(struct address_range); } np->intrs = (int *) get_property(np, "AAPL,interrupts", &l); + if (np->intrs == 0) + np->intrs = (int *) get_property(np, "interrupts", &l); if (np->intrs != 0) np->n_intrs = l / sizeof(int); - /* get the node's full name */ - l = (int) call_prom("package-to-path", 3, 1, node, - (char *) mem_start, mem_end - mem_start); - if (l >= 0) { - np->full_name = (char *) mem_start; - np->full_name[l] = 0; - mem_start = ALIGN(mem_start + l + 1); - } - - if (np->type != 0 && strcmp(np->type, "dbdma") == 0 && np->n_addrs > 0) + if (np->type != 0 && np->n_addrs > 0 + && (strcmp(np->type, "dbdma") == 0 + || strcmp(np->type, "mac-io") == 0)) base_address = np->addrs[0].address; - child = call_prom("child", 1, 1, node); - while (child != (void *)0) { - mem_start = inspect_node(child, np, base_address, - mem_start, mem_end); - child = call_prom("peer", 1, 1, child); - } + for (child = np->child; child != NULL; child = child->sibling) + mem_start = finish_node(child, mem_start, base_address); return mem_start; } /* - * Construct a return a list of the device_nodes with a given name. + * Construct and return a list of the device_nodes with a given name. */ struct device_node * find_devices(const char *name) @@ -423,7 +488,7 @@ } /* - * Construct a return a list of the device_nodes with a given type. + * Construct and return a list of the device_nodes with a given type. */ struct device_node * find_type_devices(const char *type) @@ -442,6 +507,31 @@ } /* + * Construct and return a list of the device_nodes with a given type + * and compatible property. + */ +struct device_node * +find_compatible_devices(const char *type, const char *compat) +{ + struct device_node *head, **prevp, *np; + const char *cp; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (type != NULL + && !(np->type != 0 && strcasecmp(np->type, type) == 0)) + continue; + cp = (char *) get_property(np, "compatible", NULL); + if (cp != NULL && strcasecmp(cp, compat) == 0) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = 0; + return head; +} + +/* * Find the device_node with a given full_name. */ struct device_node * @@ -456,6 +546,20 @@ } /* + * Find the device_node with a given phandle. + */ +struct device_node * +find_phandle(phandle ph) +{ + struct device_node *np; + + for (np = allnodes; np != 0; np = np->allnext) + if (np->node == ph) + return np; + return NULL; +} + +/* * Find a property with a given name for a given node * and return the value. */ @@ -521,4 +625,49 @@ pp->length); } } +} + +int +call_rtas(const char *service, int nargs, int nret, + unsigned long *outputs, ...) +{ + va_list list; + int i; + struct device_node *rtas; + int *tokp; + union { + unsigned long words[16]; + double align; + } u; + + rtas = find_devices("rtas"); + if (rtas == NULL) + return -1; + tokp = (int *) get_property(rtas, service, NULL); + if (tokp == NULL) { + printk(KERN_ERR "No RTAS service called %s\n", service); + return -1; + } + u.words[0] = *tokp; + u.words[1] = nargs; + u.words[2] = nret; + va_start(list, outputs); + for (i = 0; i < nargs; ++i) + u.words[i+3] = va_arg(list, unsigned long); + va_end(list); + enter_rtas(&u); + if (nret > 1 && outputs != NULL) + for (i = 0; i < nret-1; ++i) + outputs[i] = u.words[i+nargs+4]; + return u.words[nargs+3]; +} + +void +abort() +{ +#ifdef CONFIG_XMON + extern void xmon(void *); + xmon(0); +#endif + prom_exit(); } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.1.78/linux/arch/ppc/kernel/ptrace.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/ptrace.c Mon Jan 12 15:18:13 1998 @@ -32,6 +32,11 @@ #include /* + * Set of msr bits that gdb can change on behalf of a process. + */ +#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1) + +/* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. */ @@ -41,7 +46,7 @@ */ static inline long get_reg(struct task_struct *task, int regno) { - if (regno <= PT_CCR) + if (regno <= PT_MQ) return ((unsigned long *)task->tss.regs)[regno]; return (0); } @@ -52,7 +57,10 @@ static inline int put_reg(struct task_struct *task, int regno, unsigned long data) { - if (regno <= PT_CCR) { + if (regno <= PT_MQ) { + if (regno == PT_MSR) + data = (data & MSR_DEBUGCHANGE) + | (task->tss.regs->msr & ~MSR_DEBUGCHANGE); ((unsigned long *)task->tss.regs)[regno] = data; return 0; } @@ -408,13 +416,6 @@ if (addr == PT_ORIG_R3) goto out; -#if 0 /* Let this check be in 'put_reg' */ - if (addr == PT_SR) { - data &= SR_MASK; - data <<= 16; - data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); - } -#endif if (addr < PT_FPR0) { if (put_reg(child, addr, data)) goto out; @@ -433,7 +434,7 @@ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; @@ -465,7 +466,7 @@ case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; child->flags &= ~PF_TRACESYS; set_single_step(child); @@ -478,7 +479,7 @@ case PTRACE_DETACH: { /* detach a process that was attached. */ ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); @@ -516,9 +517,10 @@ * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ - if (current->exit_code) - current->signal |= (1 << (current->exit_code - 1)); - current->exit_code = 0; + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } out: unlock_kernel(); } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c --- v2.1.78/linux/arch/ppc/kernel/residual.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/residual.c Mon Jan 12 15:18:13 1998 @@ -1,11 +1,12 @@ /* - * $Id: residual.c,v 1.2 1997/08/25 06:54:56 cort Exp $ + * $Id: residual.c,v 1.5 1997/10/30 21:25:19 cort Exp $ * * Code to deal with the PReP residual data. * * Written by: Cort Dougan (cort@cs.nmt.edu) + * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es) */ - +#if 0 #include #include #include @@ -35,9 +36,585 @@ #include +const char * PnP_BASE_TYPES[]= { + "Reserved", + "MassStorageDevice", + "NetworkInterfaceController", + "DisplayController", + "MultimediaController", + "MemoryController", + "BridgeController", + "CommunicationsDevice", + "SystemPeripheral", + "InputDevice", + "ServiceProcessor" + }; + +/* Device Sub Type Codes */ + +const unsigned char * PnP_SUB_TYPES[] = { + "\001\000SCSIController", + "\001\001IDEController", + "\001\002FloppyController", + "\001\003IPIController", + "\001\200OtherMassStorageController", + "\002\000EthernetController", + "\002\001TokenRingController", + "\002\002FDDIController", + "\002\0x80OtherNetworkController", + "\003\000VGAController", + "\003\001SVGAController", + "\003\002XGAController", + "\003\200OtherDisplayController", + "\004\000VideoController", + "\004\001AudioController", + "\004\200OtherMultimediaController", + "\005\000RAM", + "\005\001FLASH", + "\005\200OtherMemoryDevice", + "\006\000HostProcessorBridge", + "\006\001ISABridge", + "\006\002EISABridge", + "\006\003MicroChannelBridge", + "\006\004PCIBridge", + "\006\005PCMCIABridge", + "\006\006VMEBridge", + "\006\200OtherBridgeDevice", + "\007\000RS232Device", + "\007\001ATCompatibleParallelPort", + "\007\200OtherCommunicationsDevice", + "\010\000ProgrammableInterruptController", + "\010\001DMAController", + "\010\002SystemTimer", + "\010\003RealTimeClock", + "\010\004L2Cache", + "\010\005NVRAM", + "\010\006PowerManagement", + "\010\007CMOS", + "\010\010OperatorPanel", + "\010\011ServiceProcessorClass1", + "\010\012ServiceProcessorClass2", + "\010\013ServiceProcessorClass3", + "\010\014GraphicAssist", + "\010\017SystemPlanar", + "\010\200OtherSystemPeripheral", + "\011\000KeyboardController", + "\011\001Digitizer", + "\011\002MouseController", + "\011\003TabletController", + "\011\0x80OtherInputController", + "\012\000GeneralMemoryController", + NULL +}; + +/* Device Interface Type Codes */ + +const unsigned char * PnP_INTERFACES[]= { + "\000\000\000General", + "\001\000\000GeneralSCSI", + "\001\001\000GeneralIDE", + "\001\001\001ATACompatible", + + "\001\002\000GeneralFloppy", + "\001\002\001Compatible765", + "\001\002\002NS398_Floppy", /* NS Super I/O wired to use index + register at port 398 and data + register at port 399 */ + "\001\002\003NS26E_Floppy", /* Ports 26E and 26F */ + "\001\002\004NS15C_Floppy", /* Ports 15C and 15D */ + "\001\002\005NS2E_Floppy", /* Ports 2E and 2F */ + "\001\002\006CHRP_Floppy", /* CHRP Floppy in PR*P system */ + + "\001\003\000GeneralIPI", + + "\002\000\000GeneralEther", + "\002\001\000GeneralToken", + "\002\002\000GeneralFDDI", + + "\003\000\000GeneralVGA", + "\003\001\000GeneralSVGA", + "\003\002\000GeneralXGA", + + "\004\000\000GeneralVideo", + "\004\001\000GeneralAudio", + "\004\001\001CS4232Audio", /* CS 4232 Plug 'n Play Configured */ + + "\005\000\000GeneralRAM", + /* This one is obviously wrong ! */ + "\005\000\000PCIMemoryController", /* PCI Config Method */ + "\005\000\001RS6KMemoryController", /* RS6K Config Method */ + "\005\001\000GeneralFLASH", + + "\006\000\000GeneralHostBridge", + "\006\001\000GeneralISABridge", + "\006\002\000GeneralEISABridge", + "\006\003\000GeneralMCABridge", + /* GeneralPCIBridge = 0, */ + "\006\004\000PCIBridgeDirect", + "\006\004\001PCIBridgeIndirect", + "\006\004\002PCIBridgeRS6K", + "\006\005\000GeneralPCMCIABridge", + "\006\006\000GeneralVMEBridge", + + "\007\000\000GeneralRS232", + "\007\000\001COMx", + "\007\000\002Compatible16450", + "\007\000\003Compatible16550", + "\007\000\004NS398SerPort", /* NS Super I/O wired to use index + register at port 398 and data + register at port 399 */ + "\007\000\005NS26ESerPort", /* Ports 26E and 26F */ + "\007\000\006NS15CSerPort", /* Ports 15C and 15D */ + "\007\000\007NS2ESerPort", /* Ports 2E and 2F */ + + "\007\001\000GeneralParPort", + "\007\001\001LPTx", + "\007\001\002NS398ParPort", /* NS Super I/O wired to use index + register at port 398 and data + register at port 399 */ + "\007\001\003NS26EParPort", /* Ports 26E and 26F */ + "\007\001\004NS15CParPort", /* Ports 15C and 15D */ + "\007\001\005NS2EParPort", /* Ports 2E and 2F */ + + "\010\000\000GeneralPIC", + "\010\000\001ISA_PIC", + "\010\000\002EISA_PIC", + "\010\000\003MPIC", + "\010\000\004RS6K_PIC", + + "\010\001\000GeneralDMA", + "\010\001\001ISA_DMA", + "\010\001\002EISA_DMA", + + "\010\002\000GeneralTimer", + "\010\002\001ISA_Timer", + "\010\002\002EISA_Timer", + "\010\003\000GeneralRTC", + "\010\003\001ISA_RTC", + + "\010\004\001StoreThruOnly", + "\010\004\002StoreInEnabled", + "\010\004\003RS6KL2Cache", + + "\010\005\000IndirectNVRAM", /* Indirectly addressed */ + "\010\005\001DirectNVRAM", /* Memory Mapped */ + "\010\005\002IndirectNVRAM24", /* Indirectly addressed - 24 bit */ + + "\010\006\000GeneralPowerManagement", + "\010\006\001EPOWPowerManagement", + "\010\006\002PowerControl", // d1378 + + "\010\007\000GeneralCMOS", + + "\010\010\000GeneralOPPanel", + "\010\010\001HarddiskLight", + "\010\010\002CDROMLight", + "\010\010\003PowerLight", + "\010\010\004KeyLock", + "\010\010\005ANDisplay", /* AlphaNumeric Display */ + "\010\010\006SystemStatusLED", /* 3 digit 7 segment LED */ + "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system */ + + "\010\011\000GeneralServiceProcessor", + "\010\012\000GeneralServiceProcessor", + "\010\013\000GeneralServiceProcessor", + + "\010\014\001TransferData", + "\010\014\002IGMC32", + "\010\014\003IGMC64", + + "\010\017\000GeneralSystemPlanar", /* 10/5/95 */ + NULL + }; + +static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType, + unsigned char SubType) { + const unsigned char ** s=PnP_SUB_TYPES; + while (*s && !((*s)[0]==BaseType + && (*s)[1]==SubType)) s++; + if (*s) return *s+2; + else return("Unknown !"); +}; + +static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType, + unsigned char SubType, + unsigned char Interface) { + const unsigned char ** s=PnP_INTERFACES; + while (*s && !((*s)[0]==BaseType + && (*s)[1]==SubType + && (*s)[2]==Interface)) s++; + if (*s) return *s+3; + else return NULL; +}; + +static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) { + int i, c; + char decomp[4]; +#define p pkt->S14_Pack.S14_Data.S14_PPCPack + switch(p.Type) { + case 1: + /* Decompress first 3 chars */ + c = *(unsigned short *)p.PPCData; + decomp[0]='A'-1+((c>>10)&0x1F); + decomp[1]='A'-1+((c>>5)&0x1F); + decomp[2]='A'-1+(c&0x1F); + decomp[3]=0; + printk(" Chip identification: %s%4.4X\n", + decomp, ld_le16((unsigned short *)(p.PPCData+2))); + break; + default: + printk(" Small vendor item type 0x%2.2x, data (hex): ", + p.Type); + for(i=0; iS1_Pack.Tag)) { + case PnPVersion: + printk(" PnPversion 0x%x.%x\n", + pkt->S1_Pack.Version[0], /* How to interpret version ? */ + pkt->S1_Pack.Version[1]); + break; +// case Logicaldevice: + break; +// case CompatibleDevice: + break; + case IRQFormat: +#define p pkt->S4_Pack + printk(" IRQ Mask 0x%4.4x, %s %s sensitive\n", + ld_le16((unsigned short *)p.IRQMask), + intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0], + intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]); +#undef p + break; + case DMAFormat: +#define p pkt->S5_Pack + printk(" DMA channel mask 0x%2.2x, info 0x%2.2x\n", + p.DMAMask, p.DMAInfo); +#undef p + break; + case StartDepFunc: + printk("Start dependant function:\n"); + break; + case EndDepFunc: + printk("End dependant function\n"); + break; + case IOPort: +#define p pkt->S8_Pack + printk(" Variable (%d decoded bits) I/O port\n" + " from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n", + p.IOInfo&ISAAddr16bit?16:10, + ld_le16((unsigned short *)p.RangeMin), + ld_le16((unsigned short *)p.RangeMax), + p.IOAlign, p.IONum); +#undef p + break; + case FixedIOPort: +#define p pkt->S9_Pack + printk(" Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n", + (p.Range[1]<<8)|p.Range[0], + ((p.Range[1]<<8)|p.Range[0])+p.IONum-1); +#undef p + break; + case Res1: + case Res2: + case Res3: + printk(" Undefined packet type %d!\n", + tag_small_item_name(pkt->S1_Pack.Tag)); + break; + case SmallVendorItem: + printsmallvendor(pkt,size); + break; + default: + printk(" Type 0x2.2x%d, size=%d\n", + pkt->S1_Pack.Tag, size); + break; + } +} + +static void printlargevendor(PnP_TAG_PACKET * pkt, int size) { + static const unsigned char * addrtype[] = {"I/O", "Memory", "System"}; + static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"}; + static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"}; + static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"}; + static const unsigned char * L2type[] = {"WriteThru", "CopyBack"}; + static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"}; + + int i; + char tmpstr[30], *t; +#define p pkt->L4_Pack.L4_Data.L4_PPCPack + switch(p.Type) { + case 2: + printk(" %d K %s %s L2 cache, %d/%d bytes line/sector size\n", + ld_le32((unsigned int *)p.PPCData), + L2type[p.PPCData[10]-1], + L2assoc[p.PPCData[4]-1], + ld_le16((unsigned short *)p.PPCData+3), + ld_le16((unsigned short *)p.PPCData+4)); + break; + case 3: + printk(" PCI Bridge parameters\n" + " ConfigBaseAddress %0x\n" + " ConfigBaseData %0x\n" + " Bus number %d\n", + ld_le32((unsigned int *)p.PPCData), + ld_le32((unsigned int *)(p.PPCData+8)), + p.PPCData[16]); + for(i=20; iS1_Pack.Tag)) { + case LargeVendorItem: + printlargevendor(pkt, size); + break; + default: + printk(" Type 0x2.2x%d, size=%d\n", + pkt->S1_Pack.Tag, size); + break; + } +} +static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) { + PnP_TAG_PACKET tmp; + if (pkt->S1_Pack.Tag== END_TAG) { + printk(" No packets describing %s resources.\n", cat); + return; + } + printk( " Packets describing %s resources:\n",cat); + do { + int size; + if (tag_type(pkt->S1_Pack.Tag)) { + size= 3 + + pkt->L1_Pack.Count0 + + pkt->L1_Pack.Count1*256; + printlargepacket(pkt, size); + } else { + size=tag_small_count(pkt->S1_Pack.Tag)+1; + printsmallpacket(pkt, size); + } + (unsigned char *) pkt+=size; + } while (pkt->S1_Pack.Tag != END_TAG); +} + +void print_residual_device_info(void) +{ + int i; + union _PnP_TAG_PACKET *pkt; + PPC_DEVICE *dev; +#define did dev->DeviceId +return; + + /* make sure we have residual data first */ + if ( res.ResidualLength == 0 ) + return; + + printk("Residual: %ld devices\n", res.ActualNumDevices); + for ( i = 0; + i < res.ActualNumDevices ; + i++) + { + char decomp[4], sn[20]; + const char * s; + dev = &res.Devices[i]; + s = PnP_INTERFACE_STR(did.BaseType, did.SubType, + did.Interface); + if(!s) { + sprintf(sn, "interface %d", did.Interface); + s=sn; + } + if ( did.BusId & PCIDEVICE ) + printk("PCI Device, Bus %d, DevFunc 0x%x:", + dev->BusAccess.PCIAccess.BusNumber, + dev->BusAccess.PCIAccess.DevFuncNumber); + if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:"); + if ( did.BusId & ISADEVICE ) + printk("ISA Device, Slot %d, LogicalDev %d:", + dev->BusAccess.ISAAccess.SlotNumber, + dev->BusAccess.ISAAccess.LogicalDevNumber); + if ( did.BusId & EISADEVICE ) printk("EISA Device:"); + if ( did.BusId & PROCESSORDEVICE ) + printk("ProcBus Device, Bus %d, BUID %d: ", + dev->BusAccess.ProcBusAccess.BusNumber, + dev->BusAccess.ProcBusAccess.BUID); + if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA "); + if ( did.BusId & VMEDEVICE ) printk("VME "); + if ( did.BusId & MCADEVICE ) printk("MCA "); + if ( did.BusId & MXDEVICE ) printk("MX "); + /* Decompress first 3 chars */ + decomp[0]='A'-1+((did.DevId>>26)&0x1F); + decomp[1]='A'-1+((did.DevId>>21)&0x1F); + decomp[2]='A'-1+((did.DevId>>16)&0x1F); + decomp[3]=0; + printk(" %s%4.4lX, %s, %s, %s\n", + decomp, did.DevId&0xffff, + PnP_BASE_TYPES[did.BaseType], + PnP_SUB_TYPE_STR(did.BaseType,did.SubType), + s); + printpackets( (union _PnP_TAG_PACKET *) + &res.DevicePnPHeap[dev->AllocatedOffset], "allocated"); + printpackets( (union _PnP_TAG_PACKET *) + &res.DevicePnPHeap[dev->PossibleOffset], "possible"); + printpackets( (union _PnP_TAG_PACKET *) + &res.DevicePnPHeap[dev->CompatibleOffset], "compatible"); + } +} + + + +static void printVPD(void) { +#define vpd res.VitalProductData + int ps=vpd.PageSize, i, j; + static const char* Usage[]={ + "FirmwareStack", "FirmwareHeap", "FirmwareCode", "BootImage", + "Free", "Unpopulated", "ISAAddr", "PCIConfig", + "IOMemory", "SystemIO", "SystemRegs", "PCIAddr", + "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other" + }; + static const unsigned char *FWMan[]={ + "IBM", "Motorola", "FirmWorks", "Bull" + }; + static const unsigned char *FWFlags[]={ + "Conventional", "OpenFirmware", "Diagnostics", "LowDebug", + "MultiBoot", "LowClient", "Hex41", "FAT", + "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path" + }; + static const unsigned char *ESM[]={ + "Port92", "PCIConfigA8", "FF001030", "????????" + }; + static const unsigned char *SIOM[]={ + "Port850", "????????", "PCIConfigA8", "????????" + }; + + printk("Model: %s\n",vpd.PrintableModel); + printk("Serial: %s\n", vpd.Serial); + printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]); + printk("FirmwareFlags:"); + for(j=0; j<12; j++) { + if (vpd.FirmwareSupports & (1<2 ? 2 : vpd.EndianSwitchMethod]); + printk("SpreadIOMethod: %s\n", + SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]); + printk("Processor/Bus frequencies (Hz): %ld/%ld\n", + vpd.ProcessorHz, vpd.ProcessorBusHz); + printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor); + printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps); + printk("Cache sector size, Lock granularity: %ld, %ld\n", + vpd.CoherenceBlockSize, vpd.GranuleSize); + for (i=0; i=0; j--) { + if (mask&(1< @@ -8,19 +8,31 @@ #include #include #include -#include +#include +#include +#include #include #include #include #include +#include +extern char cmd_line[512]; char saved_command_line[256]; unsigned char aux_device_present; +#if !defined(CONFIG_MACH_SPECIFIC) +unsigned long ISA_DMA_THRESHOLD; +unsigned long DMA_MODE_READ, DMA_MODE_WRITE; +int _machine; +#endif /* ! CONFIG_MACH_SPECIFIC */ + /* copy of the residual data */ RESIDUAL res; -int _machine; +int _prep_type; +/* if we have openfirmware */ +unsigned long have_of; /* * Perhaps we can put the pmac screen_info[] here @@ -28,7 +40,7 @@ * Until we get multiple-console support in here * that is. -- Cort */ -#if defined(CONFIG_CHRP) || defined(CONFIG_PREP ) +#if !defined(CONFIG_PMAC_CONSOLE) struct screen_info screen_info = { 0, 25, /* orig-x, orig-y */ { 0, 0 }, /* unused */ @@ -48,94 +60,20 @@ { return 0; } -int sd_find_target(void *a, int b) -{ - return 0; -} void pmac_find_display(void) { } - #endif -/* - * Find out what kind of machine we're on and save any data we need - * from the early boot process (devtree is copied on pmac by prom_init() ) - */ -unsigned long identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - extern unsigned long initrd_start, initrd_end; - extern char cmd_line[256]; -#ifdef CONFIG_PMAC /* cheat for now - perhaps a check for OF could tell us */ - _machine = _MACH_Pmac; -#endif /* CONFIG_PMAC */ -#ifdef CONFIG_PREP - /* make a copy of residual data */ - if ( r3 ) - memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL) ); - if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3)) - _machine = _MACH_IBM; - else - _machine = _MACH_Motorola; -#endif /* CONFIG_PREP */ -#ifdef CONFIG_CHRP - _machine = _MACH_chrp; -#endif /* CONFIG_CHRP */ - - switch (_machine) - { - case _MACH_Pmac: - io_base = 0; - pci_dram_offset = 0; - break; - case _MACH_IBM: - case _MACH_Motorola: - io_base = 0x80000000; - pci_dram_offset = 0x80000000; -#ifdef CONFIG_BLK_DEV_RAM - /* take care of initrd if we have one */ - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_RAM */ - /* take care of cmd line */ - if ( r6 ) - { - - *(char *)(r7+KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6+KERNELBASE)); - } - break; - case _MACH_chrp: - /* LongTrail */ - io_base = 0xf8000000; - pci_dram_offset = 0; - /* take care of initrd if we have one */ - if ( r4 ) { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } - /* take care of cmd line */ - if ( r6 ) { - *(char *)(r7+KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6+KERNELBASE)); - } - break; - default: - printk("Unknown machine type in identify_machine!\n"); - } - return 0; -} - /* cmd is ignored for now... */ void machine_restart(char *cmd) { - struct cuda_request req; + struct adb_request req; unsigned long flags; unsigned long i = 10000; +#if 0 + int err; +#endif switch(_machine) { @@ -144,8 +82,14 @@ for (;;) cuda_poll(); break; - case _MACH_IBM: - case _MACH_Motorola: + case _MACH_chrp: +#if 0 /* RTAS doesn't seem to work on Longtrail. + For now, do it the same way as the PReP. */ + err = call_rtas("system-reboot", 0, 1, NULL); + printk("RTAS system-reboot returned %d\n", err); + for (;;); +#endif + case _MACH_prep: _disable_interrupts(); /* set exception prefix high - to the prom */ @@ -160,25 +104,29 @@ while ( i != 0 ) i++; panic("restart failed\n"); break; - - case _MACH_chrp: - openpic_init_processor(1<<0); - break; } } void machine_power_off(void) { - struct cuda_request req; + struct adb_request req; +#if 0 + int err; +#endif - if ( _machine == _MACH_Pmac ) - { + switch (_machine) { + case _MACH_Pmac: cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); for (;;) cuda_poll(); - } - else /* prep or chrp */ - { + case _MACH_chrp: +#if 0 /* RTAS doesn't seem to work on Longtrail. + For now, do it the same way as the PReP. */ + err = call_rtas("power-off", 2, 1, NULL, 0, 0); + printk("RTAS system-reboot returned %d\n", err); + for (;;); +#endif + case _MACH_prep: machine_restart(NULL); } } @@ -202,38 +150,328 @@ { if ( _machine == _MACH_Pmac ) pmac_ide_init_hwif_ports(p,base,irq); - else /* prep */ + else /* prep or chrp */ prep_ide_init_hwif_ports(p,base,irq); } -/* - * Will merge more into here later -- Cort - */ int get_cpuinfo(char *buffer) { extern int pmac_get_cpuinfo(char *); extern int chrp_get_cpuinfo(char *); extern int prep_get_cpuinfo(char *); + unsigned long len = 0; + unsigned long bogosum = 0; + unsigned long i; +#ifdef __SMP__ + extern unsigned long cpu_present_map; + extern struct cpuinfo_PPC cpu_data[NR_CPUS]; +#define GET_PVR ((long int)(cpu_data[i].pvr)) +#define CD(x) (cpu_data[i].x) +#else +#define cpu_present_map 1L +#define smp_num_cpus 1 +#define GET_PVR ((long int)_get_PVR()) +#define CD(x) (x) +#endif + + for ( i = 0; i < smp_num_cpus ; i++ ) + { + if ( ! ( cpu_present_map & (1<> 16) + { + case 1: + len += sprintf(len+buffer, "601\n"); + break; + case 3: + len += sprintf(len+buffer, "603\n"); + break; + case 4: + len += sprintf(len+buffer, "604\n"); + break; + case 6: + len += sprintf(len+buffer, "603e\n"); + break; + case 7: + len += sprintf(len+buffer, "603ev\n"); + break; + case 8: + len += sprintf(len+buffer, "750 (Arthur)\n"); + break; + case 9: + len += sprintf(len+buffer, "604e\n"); + break; + case 10: + len += sprintf(len+buffer, "604ev5 (MachV)\n"); + break; + default: + len += sprintf(len+buffer, "unknown (%lu)\n", + GET_PVR>>16); + break; + } + + /* + * Assume here that all clock rates are the same in a + * smp system. -- Cort + */ + if ( have_of ) + { + struct device_node *cpu_node; + int *fp; + + cpu_node = find_type_devices("cpu"); + if ( !cpu_node ) break; + fp = (int *) get_property(cpu_node, "clock-frequency", NULL); + if ( !fp ) break; + len += sprintf(len+buffer, "clock\t\t: %dMHz\n", + *fp / 1000000); + } + + /* PREP's without residual data for some reason will give + incorrect values here */ + if ( is_prep ) + { + len += sprintf(len+buffer, "clock\t\t: "); + if ( res.ResidualLength ) + len += sprintf(len+buffer, "%ldMHz\n", + (res.VitalProductData.ProcessorHz > 1024) ? + res.VitalProductData.ProcessorHz>>20 : + res.VitalProductData.ProcessorHz); + else + len += sprintf(len+buffer, "???\n"); + } + + len += sprintf(len+buffer, "revision\t: %ld.%ld\n", + (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff); + + len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n", + (CD(loops_per_sec)+2500)/500000, + (CD(loops_per_sec)+2500)/5000 % 100); + bogosum += CD(loops_per_sec); + } + +#ifdef __SMP__ + if ( i ) + len += sprintf(buffer+len, "\n"); + len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n", + (bogosum+2500)/500000, + (bogosum+2500)/5000 % 100); +#endif /* __SMP__ */ + + /* + * Ooh's and aah's info about zero'd pages in idle task + */ + { + extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls; + len += sprintf(buffer+len,"zero pages\t: total %u (%luKb) " + "current: %u (%luKb) hits: %u/%u (%u%%)\n", + zerototal, (zerototal*PAGE_SIZE)>>10, + zerocount, (zerocount*PAGE_SIZE)>>10, + zeropage_hits,zeropage_calls, + /* : 1 below is so we don't div by zero */ + (zeropage_hits*100) / + ((zeropage_calls)?zeropage_calls:1)); + } switch (_machine) { case _MACH_Pmac: - return pmac_get_cpuinfo(buffer); + len += pmac_get_cpuinfo(buffer+len); break; - case _MACH_Motorola: - case _MACH_IBM: - return prep_get_cpuinfo(buffer); + case _MACH_prep: + len += prep_get_cpuinfo(buffer+len); break; case _MACH_chrp: - return chrp_get_cpuinfo(buffer); + len += chrp_get_cpuinfo(buffer+len); break; } - printk("Unknown machine %d in get_cpuinfo()\n",_machine); - return 0; + return len; } +/* + * Find out what kind of machine we're on and save any data we need + * from the early boot process (devtree is copied on pmac by prom_init() ) + */ +__initfunc(unsigned long +identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7)) +{ + extern unsigned long initrd_start, initrd_end; + extern setup_pci_ptrs(void); + unsigned long boot_sdr1; + ihandle prom_root; + unsigned char type[16], model[16]; + + asm("mfspr %0,25\n\t" :"=r" (boot_sdr1)); + + /* + * if we have a sdr1 then we have openfirmware + * and can ask it what machine we are (chrp/pmac/prep). + * otherwise we're definitely prep. -- Cort + */ + if ( !boot_sdr1 ) + { + /* we know for certain we're prep if no OF */ + have_of = 0; + /* make a copy of residual data */ + if ( r3 ) + memcpy((void *)&res,(void *)(r3+KERNELBASE), + sizeof(RESIDUAL)); +#ifndef CONFIG_MACH_SPECIFIC + _machine = _MACH_prep; +#endif /* CONFIG_MACH_SPECIFIC */ + } + else + { + /* + * init prom here, then ask the openfirmware + * what machine we are (prep/chrp/pmac). We don't use + * OF on prep just yet. -- Cort + */ +#ifndef CONFIG_PREP /* don't use OF on prep yet */ + have_of = 1; + /* prom_init has already been called from __start */ + finish_device_tree(); + + /* + * If we were booted via quik, r3 points to the physical + * address of the command-line parameters. + * If we were booted from an xcoff image (i.e. netbooted or + * booted from floppy), we get the command line from the + * bootargs property of the /chosen node. + * If an initial ramdisk is present, r3 and r4 + * are used for initrd_start and initrd_size, + * otherwise they contain 0xdeadbeef. + */ + cmd_line[0] = 0; + if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { + strncpy(cmd_line, (char *)r3 + KERNELBASE, + sizeof(cmd_line)); + } else { + struct device_node *chosen; + char *p; + +#ifdef CONFIG_BLK_DEV_INITRD + if (r3 - KERNELBASE < 0x800000 + && r4 != 0 && r4 != 0xdeadbeef) { + initrd_start = r3; + initrd_end = r3 + r4; + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + } +#endif + chosen = find_path_device("/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; +#endif /* CONFIG_PREP */ + +#ifndef CONFIG_MACH_SPECIFIC +#if 0 + prom_root = call_prom("finddevice", 1, 1, "/"); + call_prom("getprop", 4, 1, prom_root, "device_type", &type, + (void *) sizeof(type)); + call_prom("getprop", 4, 1, prom_root, "model", &type, + (void *) sizeof(model)); + if ( !strncmp("chrp", type,4) ) + { + _machine = _MACH_chrp; + } + else + { + /*if ( !strncmp("Power Macintosh", type,15) )*/ + _machine = _MACH_Pmac; + } +#else + +#ifdef CONFIG_CHRP + _machine = _MACH_chrp; +#endif /* CONFIG_CHRP */ +#ifdef CONFIG_PMAC + _machine = _MACH_Pmac; +#endif /* CONFIG_PMAC */ +#ifdef CONFIG_PREP + _machine = _MACH_Prep; +#endif /* CONFIG_PREP */ +#endif /* #if */ +#endif /* CONFIG_MACH_SPECIFIC */ + } + + /* so that pmac/chrp can use pci to find its console -- Cort */ + setup_pci_ptrs(); + + switch (_machine) + { + case _MACH_Pmac: +#if !defined(CONFIG_MACH_SPECIFIC) + isa_io_base = PMAC_ISA_IO_BASE; + isa_mem_base = PMAC_ISA_MEM_BASE; + pci_dram_offset = PMAC_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 1; + DMA_MODE_WRITE = 2; +#endif /* ! CONFIG_MACH_SPECIFIC */ + break; + case _MACH_prep: +#if !defined(CONFIG_MACH_SPECIFIC) + isa_io_base = PREP_ISA_IO_BASE; + isa_mem_base = PREP_ISA_MEM_BASE; + pci_dram_offset = PREP_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; +#endif /* ! CONFIG_MACH_SPECIFIC */ + /* figure out what kind of prep workstation we are */ + if ( res.ResidualLength != 0 ) + { + if ( !strncmp(res.VitalProductData.PrintableModel,"IBM",3) ) + _prep_type = 0x00; + else + _prep_type = 0x01; + } + else /* assume motorola if no residual (netboot?) */ + _prep_type = _PREP_Motorola; + +#ifdef CONFIG_BLK_DEV_RAM + /* take care of initrd if we have one */ + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_RAM */ + /* take care of cmd line */ + if ( r6 ) + { + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + break; + case _MACH_chrp: + /* LongTrail */ +#if !defined(CONFIG_MACH_SPECIFIC) + isa_io_base = CHRP_ISA_IO_BASE; + isa_mem_base = CHRP_ISA_MEM_BASE; + pci_dram_offset = CHRP_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; +#endif /* ! CONFIG_MACH_SPECIFIC */ + break; + default: + printk("Unknown machine type in identify_machine!\n"); + } + return 0; +} __initfunc(unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)) @@ -244,25 +482,41 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { - extern void pmac_setup_arch(char **, unsigned long *, unsigned long *); - extern void chrp_setup_arch(char **, unsigned long *, unsigned long *); - extern void prep_setup_arch(char **, unsigned long *, unsigned long *); + extern void pmac_setup_arch(unsigned long *, unsigned long *); + extern void chrp_setup_arch(unsigned long *, unsigned long *); + extern void prep_setup_arch(unsigned long *, unsigned long *); + extern int panic_timeout; + extern char _etext[], _edata[]; + extern char *klimit; + extern unsigned long find_available_memory(void); + extern unsigned long *end_of_DRAM; + + /* reboot on panic */ + panic_timeout = 180; - switch (_machine) - { + init_task.mm->start_code = PAGE_OFFSET; + init_task.mm->end_code = (unsigned long) _etext; + init_task.mm->end_data = (unsigned long) _edata; + init_task.mm->brk = (unsigned long) klimit; + + /* Save unparsed command line copy for /proc/cmdline */ + strcpy(saved_command_line, cmd_line); + *cmdline_p = cmd_line; + + *memory_start_p = find_available_memory(); + *memory_end_p = (unsigned long) end_of_DRAM; + + switch (_machine) { case _MACH_Pmac: - pmac_setup_arch(cmdline_p,memory_start_p,memory_end_p); + pmac_setup_arch(memory_start_p, memory_end_p); break; - case _MACH_Motorola: - case _MACH_IBM: - prep_setup_arch(cmdline_p,memory_start_p,memory_end_p); + case _MACH_prep: + prep_setup_arch(memory_start_p, memory_end_p); break; case _MACH_chrp: - return chrp_setup_arch(cmdline_p,memory_start_p,memory_end_p); + chrp_setup_arch(memory_start_p, memory_end_p); break; + default: + printk("Unknown machine %d in setup_arch()\n", _machine); } - printk("Unknown machine %d in setup_arch()\n",_machine); } - - - diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.1.78/linux/arch/ppc/kernel/signal.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/signal.c Mon Jan 12 15:18:13 1998 @@ -6,12 +6,12 @@ * * Derived from "arch/i386/kernel/signal.c" * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * * 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. - * */ #include @@ -24,45 +24,59 @@ #include #include #include +#include #include +#include #include +#include -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) - -#define DEBUG_SIGNALS -#undef DEBUG_SIGNALS +#define DEBUG_SIG 0 -#define PAUSE_AFTER_SIGNAL -#undef PAUSE_AFTER_SIGNAL +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +#define GP_REGS_SIZE MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs)) + +/* + * These are the flags in the MSR that the user is allowed to change + * by modifying the saved value of the MSR on the stack. SE and BE + * should not be in this list since gdb may want to change these. I.e, + * you should be able to step out of a signal handler to see what + * instruction executes next after the signal handler completes. + * Alternately, if you stepped into a signal handler, you should be + * able to continue 'til the next breakpoint from within the signal + * handler, even if the handler returns. + */ +#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) + +int do_signal(sigset_t *oldset, struct pt_regs *regs); +extern int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); /* - * atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs) +int +sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, + struct pt_regs *regs) { - unsigned long mask; + sigset_t saveset; + mask &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->gpr[3] = -EINTR; -#ifdef DEBUG_SIGNALS -printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set); -#endif while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(mask,regs)) { + if (do_signal(&saveset, regs)) /* * If a signal handler needs to be called, * do_signal() has set R3 to the signal number (the @@ -72,64 +86,134 @@ * R3, so it's still set to -EINTR (see above). */ return regs->gpr[3]; - } } } -/* - * These are the flags in the MSR that the user is allowed to change - * by modifying the saved value of the MSR on the stack. SE and BE - * should not be in this list since gdb may want to change these. I.e, - * you should be able to step out of a signal handler to see what - * instruction executes next after the signal handler completes. - * Alternately, if you stepped into a signal handler, you should be - * able to continue 'til the next breakpoint from within the signal - * handler, even if the handler returns. +int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, + int p7, struct pt_regs *regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->gpr[3] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return regs->gpr[3]; + } +} + +int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +/* + * When we have signals to deliver, we set up on the + * user stack, going down from the original stack pointer: + * a sigregs struct + * one or more sigcontext structs + * a gap of __SIGNAL_FRAMESIZE bytes + * + * Each of these things must be a multiple of 16 bytes in size. + * + * XXX ultimately we will have to stack up a siginfo and ucontext + * for each rt signal. */ -#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) +struct sigregs { + elf_gregset_t gp_regs; + double fp_regs[ELF_NFPREG]; + unsigned long tramp[2]; + /* Programs using the rs6000/xcoff abi can save up to 19 gp regs + and 18 fp regs below sp before decrementing it. */ + int abigap[56]; +}; /* - * This sets regs->esp even though we don't actually use sigstacks yet.. + * Do a signal return; undo the signal stack. */ -asmlinkage int sys_sigreturn(struct pt_regs *regs) +int sys_sigreturn(struct pt_regs *regs) { struct sigcontext_struct *sc, sigctx; + struct sigregs *sr; int ret; elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ + sigset_t set; + unsigned long prevsp; sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); if (copy_from_user(&sigctx, sc, sizeof(sigctx))) goto badframe; - current->blocked = sigctx.oldmask & _BLOCKABLE; - sc++; /* Pop signal 'context' */ -#ifdef DEBUG_SIGNALS - printk("Sig return - Regs: %p, sc: %p, sig: %d\n", sigctx.regs, sc, - sigctx.signal); + + set.sig[0] = sigctx.oldmask; +#if _NSIG_WORDS > 1 + set.sig[1] = sigctx._unused[3]; #endif + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + sc++; /* Look at next sigcontext */ if (sc == (struct sigcontext_struct *)(sigctx.regs)) { /* Last stacked signal - restore registers */ + sr = (struct sigregs *) sigctx.regs; if (last_task_used_math == current) giveup_fpu(); - if (copy_from_user(saved_regs, sigctx.regs, sizeof(saved_regs))) + if (copy_from_user(saved_regs, &sr->gp_regs, + sizeof(sr->gp_regs))) goto badframe; saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) | (saved_regs[PT_MSR] & MSR_USERCHANGE); - memcpy(regs, saved_regs, - MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs))); + memcpy(regs, saved_regs, GP_REGS_SIZE); - if (copy_from_user(current->tss.fpr, - (unsigned long *)sigctx.regs + ELF_NGREG, - ELF_NFPREG * sizeof(double))) + if (copy_from_user(current->tss.fpr, &sr->fp_regs, + sizeof(sr->fp_regs))) goto badframe; - if (regs->trap == 0x0C00 /* System Call! */ && - ((int)regs->result == -ERESTARTNOHAND || - (int)regs->result == -ERESTARTSYS || - (int)regs->result == -ERESTARTNOINTR)) { - regs->gpr[3] = regs->orig_gpr3; - regs->nip -= 4; /* Back up & retry system call */ - regs->result = 0; - } ret = regs->result; } else { @@ -137,87 +221,193 @@ regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE; if (copy_from_user(&sigctx, sc, sizeof(sigctx))) goto badframe; + sr = (struct sigregs *) sigctx.regs; regs->gpr[3] = ret = sigctx.signal; - regs->gpr[4] = (unsigned long) sigctx.regs; - regs->link = regs->gpr[4] + ELF_NGREG * sizeof(unsigned long) - + ELF_NFPREG * sizeof(double); + regs->gpr[4] = (unsigned long) sr; + regs->link = (unsigned long) &sr->tramp; regs->nip = sigctx.handler; + + if (get_user(prevsp, &sr->gp_regs[PT_R1]) + || put_user(prevsp, (unsigned long *) regs->gpr[1])) + goto badframe; } return ret; badframe: lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); - return -EFAULT; +} + +/* + * Set up a signal frame. + */ +static void +setup_frame(struct pt_regs *regs, struct sigregs *frame, + unsigned long newsp) +{ + struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp; + + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto badframe; + if (last_task_used_math == current) + giveup_fpu(); + if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) + || __copy_to_user(&frame->fp_regs, current->tss.fpr, + ELF_NFPREG * sizeof(double)) + || __put_user(0x38007777UL, &frame->tramp[0]) /* li r0,0x7777 */ + || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ + goto badframe; + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + + newsp -= __SIGNAL_FRAMESIZE; + if (put_user(regs->gpr[1], (unsigned long *)newsp) + || get_user(regs->nip, &sc->handler) + || get_user(regs->gpr[3], &sc->signal)) + goto badframe; + regs->gpr[1] = newsp; + regs->gpr[4] = (unsigned long) frame; + regs->link = (unsigned long) frame->tramp; + + return; + +badframe: +#if DEBUG_SIG + printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); +#endif + lock_kernel(); + do_exit(SIGSEGV); } +/* + * OK, we're invoking a handler + */ +static void +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, + unsigned long *newspp, unsigned long frame) +{ + struct sigcontext_struct *sc; + + if (regs->trap == 0x0C00 /* System Call! */ + && ((int)regs->result == -ERESTARTNOHAND || + ((int)regs->result == -ERESTARTSYS && + !(ka->sa.sa_flags & SA_RESTART)))) + regs->result = -EINTR; + + /* Put another sigcontext on the stack */ + *newspp -= sizeof(*sc); + sc = (struct sigcontext_struct *) *newspp; + if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) + goto badframe; + + if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) + || __put_user(oldset->sig[0], &sc->oldmask) +#if _NSIG_WORDS > 1 + || __put_user(oldset->sig[1], &sc->_unused[3]) +#endif + || __put_user((struct pt_regs *)frame, &sc->regs) + || __put_user(sig, &sc->signal)) + goto badframe; + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sigmask_lock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + } + return; + +badframe: +#if DEBUG_SIG + printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n", + regs, frame, *newspp); + printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); +#endif + lock_kernel(); + do_exit(SIGSEGV); +} /* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. - * - * Note that we go through the signals twice: once to check the signals that - * the kernel can handle, and then we build all the user-level signal handling - * stack-frames in one go after that. */ -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) +int do_signal(sigset_t *oldset, struct pt_regs *regs) { - unsigned long mask; - unsigned long handler_signal = 0; - unsigned long *frame = NULL; - unsigned long *trampoline; - unsigned long *regs_ptr; - double *fpregs_ptr; - unsigned long nip = 0; - unsigned long signr; - struct sigcontext_struct *sc; - struct sigaction * sa; - int bitno; + siginfo_t info; + struct k_sigaction *ka; + unsigned long frame, newsp; + + if (!oldset) + oldset = ¤t->blocked; + + newsp = frame = regs->gpr[1] - sizeof(struct sigregs); + + for (;;) { + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) + break; - mask = ~current->blocked; - while ((signr = current->signal & mask)) { -#if 0 - signr = ffz(~signr); /* Compute bit # */ -#else - for (bitno = 0; bitno < 32; bitno++) - if (signr & (1<signal &= ~(1<sig->action + signr; - signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); + + /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) continue; current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) continue; - if (_S(signr) & current->blocked) { - current->signal |= _S(signr); - spin_lock_irq(¤t->sigmask_lock); - spin_unlock_irq(¤t->sigmask_lock); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if (sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; - /* check for SIGCHLD: it's special */ - while (sys_waitpid(-1,NULL,WNOHANG) > 0) + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } - if (sa->sa_handler == SIG_DFL) { + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + + /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; + switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; @@ -225,49 +415,37 @@ case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; + /* FALLTHRU */ + case SIGSTOP: - if (current->flags & PF_PTRACED) - continue; current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & - SA_NOCLDSTOP)) + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: - case SIGIOT: case SIGFPE: case SIGSEGV: + case SIGABRT: case SIGFPE: case SIGSEGV: lock_kernel(); - if (current->binfmt && current->binfmt->core_dump) { - if (current->binfmt->core_dump(signr, regs)) - signr |= 0x80; - } + if (current->binfmt + && current->binfmt->core_dump + && current->binfmt->core_dump(signr, regs)) + exit_code |= 0x80; unlock_kernel(); - /* fall through */ - default: - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); + /* FALLTHRU */ + default: + lock_kernel(); + sigaddset(¤t->signal, signr); current->flags |= PF_SIGNALED; - - lock_kernel(); /* 8-( */ - do_exit(signr); - unlock_kernel(); + do_exit(exit_code); + /* NOTREACHED */ } } - /* - * OK, we're invoking a handler - */ - if (regs->trap == 0x0C00 /* System Call! */) { - if ((int)regs->result == -ERESTARTNOHAND || - ((int)regs->result == -ERESTARTSYS && - !(sa->sa_flags & SA_RESTART))) - (int)regs->result = -EINTR; - } - handler_signal |= 1 << (signr-1); - mask &= ~sa->sa_mask; + + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); } if (regs->trap == 0x0C00 /* System Call! */ && @@ -275,91 +453,13 @@ (int)regs->result == -ERESTARTSYS || (int)regs->result == -ERESTARTNOINTR)) { regs->gpr[3] = regs->orig_gpr3; - regs->nip -= 4; /* Back up & retry system call */ + regs->nip -= 4; /* Back up & retry system call */ regs->result = 0; } - if (!handler_signal) /* no handler will be called - return 0 */ - return 0; - - nip = regs->nip; - frame = (unsigned long *) regs->gpr[1]; - - /* - * Build trampoline code on stack, and save gp and fp regs. - * The 56 word hole is because programs using the rs6000/xcoff - * style calling sequence can save up to 19 gp regs and 18 fp regs - * on the stack before decrementing sp. - */ - frame -= 2 + 56; - trampoline = frame; - frame -= ELF_NFPREG * sizeof(double) / sizeof(unsigned long); - fpregs_ptr = (double *) frame; - frame -= ELF_NGREG; - regs_ptr = frame; - /* verify stack is valid for writing to */ - if (verify_area(VERIFY_WRITE, frame, - (ELF_NGREG + 2) * sizeof(long) - + ELF_NFPREG * sizeof(double))) - goto badframe; - if (last_task_used_math == current) - giveup_fpu(); - if (__copy_to_user(regs_ptr, regs, - MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs))) - || __copy_to_user(fpregs_ptr, current->tss.fpr, - ELF_NFPREG * sizeof(double)) - || __put_user(0x38007777UL, trampoline) /* li r0,0x7777 */ - || __put_user(0x44000002UL, trampoline+1)) /* sc */ - goto badframe; - - signr = 1; - sa = current->sig->action; - - for (mask = 1 ; mask ; sa++,signr++,mask += mask) { - if (mask > handler_signal) - break; - if (!(mask & handler_signal)) - continue; + if (newsp == frame) + return 0; /* no signals delivered */ - frame -= sizeof(struct sigcontext_struct) / sizeof(long); - if (verify_area(VERIFY_WRITE, frame, - sizeof(struct sigcontext_struct))) - goto badframe; - sc = (struct sigcontext_struct *)frame; - nip = (unsigned long) sa->sa_handler; - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if (__put_user(nip, &sc->handler) - || __put_user(oldmask, &sc->oldmask) - || __put_user(regs_ptr, &sc->regs) - || __put_user(signr, &sc->signal)) - goto badframe; - current->blocked |= sa->sa_mask; - regs->gpr[3] = signr; - regs->gpr[4] = (unsigned long) regs_ptr; - } - - frame -= __SIGNAL_FRAMESIZE / sizeof(unsigned long); - if (put_user(regs->gpr[1], frame)) - goto badframe; - regs->link = (unsigned long)trampoline; - regs->nip = nip; - regs->gpr[1] = (unsigned long) frame; - - /* The DATA cache must be flushed here to insure coherency */ - /* between the DATA & INSTRUCTION caches. Since we just */ - /* created an instruction stream using the DATA [cache] space */ - /* and since the instruction cache will not look in the DATA */ - /* cache for new data, we have to force the data to go on to */ - /* memory and flush the instruction cache to force it to look */ - /* there. The following function performs this magic */ - flush_icache_range((unsigned long) trampoline, - (unsigned long) (trampoline + 2)); + setup_frame(regs, (struct sigregs *) frame, newsp); return 1; - -badframe: - lock_kernel(); - do_exit(SIGSEGV); - unlock_kernel(); - return 0; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.1.78/linux/arch/ppc/kernel/smp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/smp.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,181 @@ +/* + * $Id: smp.c,v 1.8 1998/01/06 06:44:57 cort Exp $ + * + * Smp support for ppc. + * + * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great + * deal of code from the sparc and intel versions. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int smp_threads_ready = 0; +volatile int smp_commenced = 0; +int smp_num_cpus = 1; +unsigned long cpu_present_map = 0; +volatile int cpu_number_map[NR_CPUS]; +volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; +static unsigned char boot_cpu_id = 0; +struct cpuinfo_PPC cpu_data[NR_CPUS]; +struct klock_info klock_info = { KLOCK_CLEAR, 0 }; +volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */ + +volatile unsigned long hash_table_lock; + +int start_secondary(void *); + +extern void init_IRQ(void); +extern int cpu_idle(void *unused); + +void smp_boot_cpus(void) +{ + extern unsigned long secondary_entry[]; + extern struct task_struct *current_set[NR_CPUS]; + int i, timeout; + struct task_struct *p; + + printk("Entering SMP Mode...\n"); + cpu_present_map = 0; + for(i=0; i < NR_CPUS; i++) + cpu_number_map[i] = -1; + + smp_store_cpu_info(boot_cpu_id); + active_kernel_processor = boot_cpu_id; + current->processor = boot_cpu_id; + + cpu_present_map |= 1; + /* assume a 2nd processor for now */ + cpu_present_map |= (1 << 1); + smp_num_cpus = 2; + cpu_number_map[boot_cpu_id] = 0; + + /* create a process for second processor */ + kernel_thread(start_secondary, NULL, CLONE_PID); + cpu_number_map[1] = 1; + p = task[1]; + if ( !p ) + panic("No idle task for secondary processor\n"); + p->processor = 1; + current_set[1] = p; + /* setup entry point of secondary processor */ + *(volatile unsigned long *)(0xf2800000) + = (unsigned long)secondary_entry-KERNELBASE; + /* interrupt secondary to begin executing code */ + eieio(); + *(volatile unsigned long *)(0xf80000c0) = 0; + eieio(); + /* wait to see if the secondary made a callin (is actually up) */ + for ( timeout = 0; timeout < 1500 ; timeout++ ) + udelay(100); + if(cpu_callin_map[1]) { + cpu_number_map[1] = 1; + printk("Processor 1 found.\n"); + } else { + smp_num_cpus--; + printk("Processor %d is stuck.\n", 1); + } +{ + extern unsigned long amhere; + printk("amhere: %x\n", amhere); +} +} + +void smp_commence(void) +{ + printk("SMP %d: smp_commence()\n",current->processor); + /* + * Lets the callin's below out of their loop. + */ + local_flush_tlb_all(); + smp_commenced = 1; + local_flush_tlb_all(); +} + +/* intel needs this */ +void initialize_secondary(void) +{ +} + +/* Activate a secondary processor. */ +int start_secondary(void *unused) +{ + printk("SMP %d: start_secondary()\n",current->processor); + smp_callin(); + return cpu_idle(NULL); +} + +void smp_callin(void) +{ + printk("SMP %d: smp_callin()\n",current->processor); + /*calibrate_delay();*/ + smp_store_cpu_info(1); + + /* assume we're just the secondary processor for now */ + cpu_callin_map[1] = 1; + dcbf(&cpu_callin_map[1]); + + current->mm->mmap->vm_page_prot = PAGE_SHARED; + current->mm->mmap->vm_start = PAGE_OFFSET; + current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + + while(!smp_commenced) + barrier(); + __sti(); +} + +void smp_setup(char *str, int *ints) +{ + printk("SMP %d: smp_setup()\n",current->processor); +} + +void smp_message_pass(int target, int msg, unsigned long data, int wait) +{ + printk("SMP %d: sending smp message\n",current->processor); +#if 0 + if ( smp_processor_id() == 0 ) + { + /* interrupt secondary */ + *(volatile unsigned long *)(0xf80000c0) = 0; + } + else + { + /* interrupt primary */ + *(volatile unsigned long *)(0xf3019000); + } +#endif +} + +int setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + +__initfunc(void smp_store_cpu_info(int id)) +{ + struct cpuinfo_PPC *c = &cpu_data[id]; + + c->loops_per_sec = loops_per_sec; + c->pvr = _get_PVR(); +} + diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.1.78/linux/arch/ppc/kernel/syscalls.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/syscalls.c Mon Jan 12 15:18:13 1998 @@ -32,6 +32,8 @@ #include #include #include +#include + #include #include @@ -149,7 +151,7 @@ break; } case 1: /* iBCS2 emulator entry point */ - if (get_fs() != get_ds()) + if (!segment_eq(get_fs(), get_ds())) break; ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); @@ -206,7 +208,8 @@ if (fd >= NR_OPEN || !(file = current->files->fd[fd])) goto out; } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + /*flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);*/ ret = do_mmap(file, addr, len, prot, flags, offset); out: unlock_kernel(); @@ -236,4 +239,42 @@ return -EFAULT; } return sys_select(n, inp, outp, exp, tvp); +} + +asmlinkage int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +asmlinkage int sys_uname(struct old_utsname * name) +{ + if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + return 0; + return -EFAULT; +} + +asmlinkage int sys_olduname(struct oldold_utsname * name) +{ + int error; + + if (!name) + return -EFAULT; + if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + return -EFAULT; + + error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + error -= __put_user(0,name->sysname+__OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error -= __put_user(0,name->nodename+__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __put_user(0,name->release+__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __put_user(0,name->version+__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error = __put_user(0,name->machine+__OLD_UTS_LEN); + error = error ? -EFAULT : 0; + + return error; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.1.78/linux/arch/ppc/kernel/time.c Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/time.c Mon Jan 12 15:18:13 1998 @@ -1,5 +1,5 @@ /* - * $Id: time.c,v 1.10 1997/08/27 22:06:56 cort Exp $ + * $Id: time.c,v 1.17 1997/12/28 22:47:21 paulus Exp $ * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -41,22 +41,6 @@ unsigned count_period_num; /* 1 decrementer count equals */ unsigned count_period_den; /* count_period_num / count_period_den us */ -/* Accessor functions for the decrementer register. */ -inline unsigned long -get_dec(void) -{ - int ret; - - asm volatile("mfspr %0,22" : "=r" (ret) :); - return ret; -} - -inline void -set_dec(int val) -{ - asm volatile("mtspr 22,%0" : : "r" (val)); -} - /* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. @@ -125,22 +109,6 @@ void time_init(void) { - /* pmac hasn't yet called via_cuda_init() */ - if ( _machine != _MACH_Pmac ) - { - - if ( _machine == _MACH_chrp ) - xtime.tv_sec = chrp_get_rtc_time(); - else /* assume prep */ - xtime.tv_sec = prep_get_rtc_time(); - xtime.tv_usec = 0; - /* - * mark the rtc/on-chip timer as in sync - * so we don't update right away - */ - last_rtc_update = xtime.tv_sec; - } - if ((_get_PVR() >> 16) == 1) { /* 601 processor: dec counts down by 128 every 128ns */ decrementer_count = DECREMENTER_COUNT_601; @@ -148,22 +116,35 @@ count_period_den = COUNT_PERIOD_DEN_601; } - switch (_machine) - { + switch (_machine) { case _MACH_Pmac: - pmac_calibrate_decr(); + /* can't call pmac_get_rtc_time() yet, + because via-cuda isn't initialized yet. */ + if ((_get_PVR() >> 16) != 1) + pmac_calibrate_decr(); set_rtc_time = pmac_set_rtc_time; break; - case _MACH_IBM: - case _MACH_Motorola: - prep_calibrate_decr(); - set_rtc_time = prep_set_rtc_time; - break; case _MACH_chrp: - chrp_calibrate_decr(); + chrp_time_init(); + xtime.tv_sec = chrp_get_rtc_time(); + if ((_get_PVR() >> 16) != 1) + chrp_calibrate_decr(); set_rtc_time = chrp_set_rtc_time; break; + case _MACH_prep: + xtime.tv_sec = prep_get_rtc_time(); + prep_calibrate_decr(); + set_rtc_time = prep_set_rtc_time; + break; } + xtime.tv_usec = 0; + + /* + * mark the rtc/on-chip timer as in sync + * so we don't update right away + */ + last_rtc_update = xtime.tv_sec; + set_dec(decrementer_count); } @@ -180,7 +161,7 @@ unsigned long flags; save_flags(flags); - + #define TIMER0_COUNT 0x40 #define TIMER_CONTROL 0x43 /* set timer to periodic mode */ @@ -199,7 +180,7 @@ void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs) { - int freq, divisor; + unsigned long freq, divisor; static unsigned long t1 = 0, t2 = 0; if ( !t1 ) @@ -209,9 +190,14 @@ t2 = get_dec(); t2 = t1-t2; /* decr's in 1/HZ */ t2 = t2*HZ; /* # decrs in 1s - thus in Hz */ +if ( (t2>>20) > 100 ) +{ + printk("Decrementer frequency too high: %luMHz. Using 15MHz.\n",t2>>20); + t2 = 998700000/60; +} freq = t2 * 60; /* try to make freq/1e6 an integer */ divisor = 60; - printk("time_init: decrementer frequency = %d/%d (%luMHz)\n", + printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", freq, divisor,t2>>20); decrementer_count = freq / HZ / divisor; count_period_num = divisor; @@ -220,19 +206,6 @@ } } -void chrp_calibrate_decr(void) -{ - int freq, fp, divisor; - - fp = 16666000; /* hardcoded for now */ - freq = fp*60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; -} - /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 @@ -249,9 +222,9 @@ * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ -inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) +unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) { if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ @@ -266,3 +239,45 @@ )*60 + sec; /* finally seconds */ } +#define TICK_SIZE tick +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) +#define leapyear(year) ((year) % 4 == 0) +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +void to_tm(int tim, struct rtc_time * tm) +{ + register int i; + register long hms, day; + + day = tim / SECDAY; + hms = tim % SECDAY; + + /* Hours, minutes, seconds are easy */ + tm->tm_hour = hms / 3600; + tm->tm_min = (hms % 3600) / 60; + tm->tm_sec = (hms % 3600) % 60; + + /* Number of years in days */ + for (i = STARTOFTIME; day >= days_in_year(i); i++) + day -= days_in_year(i); + tm->tm_year = i; + + /* Number of months in days left */ + if (leapyear(tm->tm_year)) + days_in_month(FEBRUARY) = 29; + for (i = 1; day >= days_in_month(i); i++) + day -= days_in_month(i); + days_in_month(FEBRUARY) = 28; + tm->tm_mon = i; + + /* Days are what is left over (+1) from all that. */ + tm->tm_mday = day + 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/time.h linux/arch/ppc/kernel/time.h --- v2.1.78/linux/arch/ppc/kernel/time.h Thu Sep 4 17:07:29 1997 +++ linux/arch/ppc/kernel/time.h Mon Jan 12 15:18:13 1998 @@ -1,5 +1,5 @@ /* - * $Id: time.h,v 1.5 1997/08/27 22:06:58 cort Exp $ + * $Id: time.h,v 1.7 1997/12/28 22:47:24 paulus Exp $ * Common time prototypes and such for all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -9,17 +9,16 @@ #include /* time.c */ -__inline__ unsigned long get_dec(void); -__inline__ void set_dec(int val); void prep_calibrate_decr_handler(int, void *,struct pt_regs *); void prep_calibrate_decr(void); void pmac_calibrate_decr(void); -void chrp_calibrate_decr(void); extern unsigned decrementer_count; extern unsigned count_period_num; extern unsigned count_period_den; extern unsigned long mktime(unsigned int, unsigned int,unsigned int, - unsigned int, unsigned int, unsigned int); + unsigned int, unsigned int, unsigned int); +extern void to_tm(int tim, struct rtc_time * tm); +extern unsigned long last_rtc_update; /* pmac/prep/chrp_time.c */ unsigned long prep_get_rtc_time(void); @@ -29,46 +28,19 @@ int pmac_set_rtc_time(unsigned long nowtime); int chrp_set_rtc_time(unsigned long nowtime); void pmac_read_rtc_time(void); +void chrp_calibrate_decr(void); +void chrp_time_init(void); -#define TICK_SIZE tick -#define FEBRUARY 2 -#define STARTOFTIME 1970 -#define SECDAY 86400L -#define SECYR (SECDAY * 365) -#define leapyear(year) ((year) % 4 == 0) -#define days_in_year(a) (leapyear(a) ? 366 : 365) -#define days_in_month(a) (month_days[(a) - 1]) - -static int month_days[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -extern void inline to_tm(int tim, struct rtc_time * tm) +/* Accessor functions for the decrementer register. */ +static __inline__ unsigned int get_dec(void) { - register int i; - register long hms, day; + unsigned int ret; - day = tim / SECDAY; - hms = tim % SECDAY; + asm volatile("mfspr %0,22" : "=r" (ret) :); + return ret; +} - /* Hours, minutes, seconds are easy */ - tm->tm_hour = hms / 3600; - tm->tm_min = (hms % 3600) / 60; - tm->tm_sec = (hms % 3600) % 60; - - /* Number of years in days */ - for (i = STARTOFTIME; day >= days_in_year(i); i++) - day -= days_in_year(i); - tm->tm_year = i; - - /* Number of months in days left */ - if (leapyear(tm->tm_year)) - days_in_month(FEBRUARY) = 29; - for (i = 1; day >= days_in_month(i); i++) - day -= days_in_month(i); - days_in_month(FEBRUARY) = 28; - tm->tm_mon = i; - - /* Days are what is left over (+1) from all that. */ - tm->tm_mday = day + 1; +static __inline__ void set_dec(unsigned int val) +{ + asm volatile("mtspr 22,%0" : : "r" (val)); } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.1.78/linux/arch/ppc/kernel/traps.c Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/kernel/traps.c Mon Jan 12 15:18:13 1998 @@ -61,10 +61,10 @@ if (!user_mode(regs)) { show_regs(regs); - print_backtrace((unsigned long *)regs->gpr[1]); #ifdef CONFIG_XMON xmon(regs); #endif + print_backtrace((unsigned long *)regs->gpr[1]); panic("Exception in kernel pc %lx signal %d",regs->nip,signr); } force_sig(signr, current); @@ -103,10 +103,10 @@ printk("Unknown values in msr\n"); } show_regs(regs); - print_backtrace((unsigned long *)regs->gpr[1]); #ifdef CONFIG_XMON xmon(regs); #endif + print_backtrace((unsigned long *)regs->gpr[1]); panic("machine check"); } _exception(SIGSEGV, regs); @@ -186,15 +186,16 @@ } void -PromException(struct pt_regs *regs, int trap) +StackOverflow(struct pt_regs *regs) { - regs->trap = trap; + printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", + current, regs->gpr[1]); #ifdef CONFIG_XMON xmon(regs); #endif - printk("Exception %lx in prom at PC: %lx, SR: %lx\n", - regs->trap, regs->nip, regs->msr); - /* probably should turn up the toes here */ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("kernel stack overflow"); } void diff -u --recursive --new-file v2.1.78/linux/arch/ppc/lib/Makefile linux/arch/ppc/lib/Makefile --- v2.1.78/linux/arch/ppc/lib/Makefile Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/lib/Makefile Mon Jan 12 15:18:13 1998 @@ -8,4 +8,9 @@ O_TARGET = lib.o O_OBJS = checksum.o string.o strcase.o +ifdef SMP +O_OBJS += locks.o +endif + + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.78/linux/arch/ppc/lib/checksum.S linux/arch/ppc/lib/checksum.S --- v2.1.78/linux/arch/ppc/lib/checksum.S Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/lib/checksum.S Mon Jan 12 15:18:13 1998 @@ -13,10 +13,11 @@ */ #include +#include #include #include "../kernel/ppc_asm.tmpl" -_TEXT() + .text /* * ip_fast_csum(buf, len) -- Optimized for IP header @@ -140,7 +141,8 @@ 5: addze r3,r0 /* add in final carry */ blr -.section .fixup,"ax" +/* These shouldn't go in the fixup section, since that would + cause the ex_table addresses to get out of order. */ src_error_1: li r6,0 diff -u --recursive --new-file v2.1.78/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c --- v2.1.78/linux/arch/ppc/lib/locks.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/lib/locks.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,195 @@ +/* + * $Id: locks.c,v 1.7 1998/01/06 06:44:59 cort Exp $ + * + * Locks for smp ppc + * + * Written by Cort Dougan (cort@cs.nmt.edu) + */ + + +#include +#include +#include +#include +#include + +#define DEBUG_LOCKS 1 + +#undef INIT_STUCK +#define INIT_STUCK 10000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("spin_lock(%p) CPU#%d nip %08lx\n", lock, cpu, nip); stuck = INIT_STUCK; } + +void _spin_lock(spinlock_t *lock) +{ + unsigned long val, nip = (unsigned long)__builtin_return_address(0); + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + +again: + /* try expensive atomic load/store to get lock */ + __asm__ __volatile__( + "10: \n\t" + "lwarx %0,0,%1 \n\t" + "stwcx. %2,0,%1 \n\t" + "bne- 10b \n\t" + : "=r" (val) + : "r" (&(lock->lock)), "r" ( (cpu&3)|(nip&~3L) )); + if(val) { + /* try cheap load until it's free */ + while(lock->lock) { + STUCK; + barrier(); + } + goto again; + } +} + +void _spin_unlock(spinlock_t *lp) +{ + lp->lock = 0; +} + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("_read_lock(%p) CPU#%d\n", rw, cpu); stuck = INIT_STUCK; } + +/* + * Just like x86, implement read-write locks as a 32-bit counter + * with the high bit (sign) being the "write" bit. + * -- Cort + */ +void _read_lock(rwlock_t *rw) +{ + unsigned long stuck = INIT_STUCK; + int cpu = smp_processor_id(); + +again: + /* get our read lock in there */ + atomic_inc((atomic_t *) &(rw)->lock); + if ( (signed long)((rw)->lock) < 0) /* someone has a write lock */ + { + /* turn off our read lock */ + atomic_dec((atomic_t *) &(rw)->lock); + /* wait for the write lock to go away */ + while ((signed long)((rw)->lock) < 0) + { + STUCK; + } + /* try to get the read lock again */ + goto again; + } +} + +void _read_unlock(rwlock_t *rw) +{ +#ifdef DEBUG_LOCKS + if ( rw->lock == 0 ) + { + if ( current) + printk("_read_unlock(): %s/%d (nip %08lX) lock %lx", + current->comm,current->pid,current->tss.regs->nip, + rw->lock); + else + printk("no current\n"); + } +#endif /* DEBUG_LOCKS */ + atomic_dec((atomic_t *) &(rw)->lock); +} + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("write_lock(%p) CPU#%d lock %lx)\n", rw, cpu,rw->lock); stuck = INIT_STUCK; } + +void _write_lock(rwlock_t *rw) +{ + unsigned long stuck = INIT_STUCK; + int cpu = smp_processor_id(); + +again: + if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */ + { + while ( (rw)->lock & (1<<31) ) /* wait for write lock */ + { + STUCK; + } + goto again; + } + + if ( (rw)->lock & ~(1<<31)) /* someone has a read lock */ + { + /* clear our write lock and wait for reads to go away */ + clear_bit(31,&(rw)->lock); + while ( (rw)->lock & ~(1<<31) ) + { + STUCK; + } + goto again; + } +} + +void _write_unlock(rwlock_t *rw) +{ +#ifdef DEBUG_LOCKS + if ( !(rw->lock & (1<<31)) ) + { + if ( current) + printk("_write_lock(): %s/%d (nip %08lX) lock %lx", + current->comm,current->pid,current->tss.regs->nip, + rw->lock); + else + printk("no current\n"); + } +#endif /* DEBUG_LOCKS */ + clear_bit(31,&(rw)->lock); +} + +void __lock_kernel(struct task_struct *task) +{ +#ifdef DEBUG_LOCKS + if ( (signed long)(task->lock_depth) < 0 ) + { + printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n", + task->comm,task->pid,task->tss.regs->nip, + task->lock_depth); + } +#endif /* DEBUG_LOCKS */ + /* mine! */ + if ( atomic_inc_return((atomic_t *) &task->lock_depth) == 1 ) + klock_info.akp = smp_processor_id(); + /* my kernel mode! mine!!! */ +} + +void __unlock_kernel(struct task_struct *task) +{ +#ifdef DEBUG_LOCKS + if ( task->lock_depth == 0 ) + { + printk("__unlock_kernel(): %s/%d (nip %08lX) lock depth %x\n", + task->comm,task->pid,task->tss.regs->nip, + task->lock_depth); + klock_info.akp = NO_PROC_ID; + klock_info.kernel_flag = 0; + return; + } +#endif /* DEBUG_LOCKS */ + if ( atomic_dec_and_test((atomic_t *) &task->lock_depth) ) + { + klock_info.akp = NO_PROC_ID; + klock_info.kernel_flag = 0; + } +} + +void reacquire_kernel_lock(struct task_struct *task, int cpu,int depth) +{ + if (depth) + { + __cli(); + __lock_kernel(task); + task->lock_depth = depth; + __sti(); + } +} + diff -u --recursive --new-file v2.1.78/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S --- v2.1.78/linux/arch/ppc/lib/string.S Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/lib/string.S Mon Jan 12 15:18:13 1998 @@ -9,6 +9,7 @@ * 2 of the License, or (at your option) any later version. */ #include "../kernel/ppc_asm.tmpl" +#include #include .globl strcpy diff -u --recursive --new-file v2.1.78/linux/arch/ppc/mkdiff linux/arch/ppc/mkdiff --- v2.1.78/linux/arch/ppc/mkdiff Mon Aug 4 16:25:36 1997 +++ linux/arch/ppc/mkdiff Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -#!/bin/bash - -N=`basename $PWD` -date=`date +'%y%m%d'` -cd ../ -mkdir -p dist -echo Diff of: $N against $N.ORIG '->' $N-$date-ppc.patch -diff -uNr -X $N/arch/ppc/ignore $N.ORIG $N > dist/$N-$date-ppc.patch diff -u --recursive --new-file v2.1.78/linux/arch/ppc/mkdist linux/arch/ppc/mkdist --- v2.1.78/linux/arch/ppc/mkdist Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/mkdist Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -#!/bin/bash - -V=`egrep ^VERSION Makefile | awk '{print $3}'` -P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'` -S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'` -date=`date +'%y%m%d'` - -echo zImage-$V.$P.$S-$date -echo System.map-$V.$P.$S-$date - -rcp zImage charon:ppc/dist/kernel-images/zImage-$V.$P.$S-$date -rcp System.map charon:ppc/dist/kernel-images/System.map-$V.$P.$S-$date - diff -u --recursive --new-file v2.1.78/linux/arch/ppc/mktar linux/arch/ppc/mktar --- v2.1.78/linux/arch/ppc/mktar Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/mktar Wed Dec 31 16:00:00 1969 @@ -1,9 +0,0 @@ -#!/bin/bash - -V=`egrep ^VERSION Makefile | awk '{print $3}'` -P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'` -S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'` -date=`date +'%y%m%d'` -cd ../ -mkdir -p dist -tar -vzcf ppclinux-$V.$P.$S-$date.tar.gz -X linux/arch/ppc/ignore linux diff -u --recursive --new-file v2.1.78/linux/arch/ppc/mm/extable.c linux/arch/ppc/mm/extable.c --- v2.1.78/linux/arch/ppc/mm/extable.c Thu Sep 4 17:07:30 1997 +++ linux/arch/ppc/mm/extable.c Mon Jan 12 15:18:13 1998 @@ -16,17 +16,10 @@ const struct exception_table_entry *last, unsigned long value) { - const struct exception_table_entry *mid; - for ( mid = first; mid < last; mid++) - { - if ( mid->insn == value ) - return mid->fixup; - } - return 0; -#if 0 while (first <= last) { const struct exception_table_entry *mid; long diff; + mid = (last - first) / 2 + first; diff = mid->insn - value; if (diff == 0) @@ -36,7 +29,6 @@ else last = mid-1; } -#endif return 0; } diff -u --recursive --new-file v2.1.78/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.1.78/linux/arch/ppc/mm/fault.c Thu Sep 4 17:07:30 1997 +++ linux/arch/ppc/mm/fault.c Mon Jan 12 15:18:13 1998 @@ -37,11 +37,17 @@ #ifdef CONFIG_XMON extern void xmon(struct pt_regs *); -extern void (*xmon_fault_handler)(void); +extern void (*xmon_fault_handler)(struct pt_regs *); extern int xmon_dabr_match(struct pt_regs *); -int xmon_kernel_faults; +int xmon_kernel_faults = 0; #endif +unsigned long htab_reloads = 0; /* updated by head.S:hash_page() */ +unsigned long htab_evicts = 0; /* updated by head.S:hash_page() */ +unsigned long pte_misses = 0; /* updated by do_page_fault() */ +unsigned long pte_errors = 0; /* updated by do_page_fault() */ +unsigned int probingmem = 0; + extern void die_if_kernel(char *, struct pt_regs *, long); void bad_page_fault(struct pt_regs *, unsigned long); void do_page_fault(struct pt_regs *, unsigned long, unsigned long); @@ -56,9 +62,19 @@ struct vm_area_struct * vma; struct mm_struct *mm = current->mm; + /*printk("address: %08lx code: %08lx %s%s%s%s%s%s\n", + address,error_code, + (error_code&0x40000000)?"604 tlb&htab miss ":"", + (error_code&0x20000000)?"603 tlbmiss ":"", + (error_code&0x02000000)?"write ":"", + (error_code&0x08000000)?"prot ":"", + (error_code&0x95700000)?"I/O ":"", + (regs->trap == 0x400)?"instr":"data" + );*/ + #ifdef CONFIG_XMON if (xmon_fault_handler && regs->trap == 0x300) { - xmon_fault_handler(); + xmon_fault_handler(regs); return; } if (error_code & 0x00400000) { @@ -96,7 +112,7 @@ goto bad_area; good_area: - if (error_code & 0xb5700000) + if (error_code & 0x95700000) /* an error such as lwarx to I/O controller space, address matching DABR, eciwx, etc. */ goto bad_area; @@ -115,10 +131,18 @@ } handle_mm_fault(current, vma, address, error_code & 0x02000000); up(&mm->mmap_sem); + /* + * keep track of tlb+htab misses that are good addrs but + * just need pte's created via handle_mm_fault() + * -- Cort + */ + pte_misses++; return; bad_area: + up(&mm->mmap_sem); + pte_errors++; bad_page_fault(regs, address); } @@ -126,7 +150,32 @@ bad_page_fault(struct pt_regs *regs, unsigned long address) { unsigned long fixup; - +#if 0 + extern unsigned long video_mem_base; + extern unsigned long video_mem_term; + + /* + * Remap video IO areas for buggy X servers. + * The S3 server wants direct access to video memory + * at 0x8000 0000 and 0xc000 0000 on prep systems, but + * we don't allow that AND we remap the io areas so it's not + * even there! + * So, for this task only give a virtual=physical mapping of the + * video mem. + * -- Cort + */ + if ( is_prep && user_mode(regs) ) + { + printk("%s/%d: fault on %x\n", + current->comm,current->pid,address); + printk("mapping: %x -> %x\n", + address&PAGE_MASK, address&PAGE_MASK); + map_page(current,address&PAGE_MASK,address&PAGE_MASK, + _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE|_PAGE_NO_CACHE|_PAGE_WRITETHRU); + return; + } +#endif + if (user_mode(regs)) { force_sig(SIGSEGV, current); return; diff -u --recursive --new-file v2.1.78/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.1.78/linux/arch/ppc/mm/init.c Thu Sep 4 17:07:30 1997 +++ linux/arch/ppc/mm/init.c Mon Jan 12 15:18:13 1998 @@ -53,21 +53,11 @@ extern char etext[], _stext[]; extern char __init_begin, __init_end; extern RESIDUAL res; - -/* Hardwired MMU segments */ -#if defined(CONFIG_PREP) || defined(CONFIG_PMAC) -#define MMU_SEGMENT_1 0x80000000 -#define MMU_SEGMENT_2 0xc0000000 -#endif /* CONFIG_PREP || CONFIG_PMAC */ -#ifdef CONFIG_CHRP -#define MMU_SEGMENT_1 0xf0000000 /* LongTrail */ -#define MMU_SEGMENT_2 0xc0000000 -#endif /* CONFIG_CHRP */ - +char *klimit = _end; +struct device_node *memory_node; void *find_mem_piece(unsigned, unsigned); static void mapin_ram(void); -static void inherit_prom_translations(void); static void hash_init(void); static void *MMU_get_page(void); void map_page(struct task_struct *, unsigned long va, @@ -76,22 +66,16 @@ extern void show_net_buffers(void); extern unsigned long *find_end_of_memory(void); -/* - * this tells the prep system to map all of ram with the segregs - * instead of the bats. I'd like to get this to apply to the - * pmac as well then have everything use the bats -- Cort - */ -#undef MAP_RAM_WITH_SEGREGS 1 +extern struct task_struct *current_set[NR_CPUS]; /* - * these are used to setup the initial page tables - * They can waste up to an entire page since the - * I'll fix this shortly -- Cort + * this tells the system to map all of ram with the segregs + * (i.e. page tables) instead of the bats. */ -#define MAX_MMU_PAGES 16 -unsigned int probingmem = 0; -unsigned int mmu_pages_count = 0; -char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE]; +#undef MAP_RAM_WITH_SEGREGS 1 + +/* optimization for 603 to load the tlb directly from the linux table */ +#define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */ /* * BAD_PAGE is the page that is used for page faults when linux @@ -122,8 +106,12 @@ return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED)); } +/* + * The following stuff defines a data structure for representing + * areas of memory as an array of (address, length) pairs, and + * procedures for manipulating them. + */ #define MAX_MEM_REGIONS 32 -phandle memory_pkg; struct mem_pieces { int n_regions; @@ -134,34 +122,19 @@ struct mem_pieces prom_mem; static void get_mem_prop(char *, struct mem_pieces *); +static void sort_mem_pieces(struct mem_pieces *); +static void coalesce_mem_pieces(struct mem_pieces *); +static void append_mem_piece(struct mem_pieces *, unsigned, unsigned); static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int); static void print_mem_pieces(struct mem_pieces *); -unsigned long avail_start; - -/* - * Read in a property describing some pieces of memory. - */ static void -get_mem_prop(char *name, struct mem_pieces *mp) +sort_mem_pieces(struct mem_pieces *mp) { - int s, i; - - s = (int) call_prom("getprop", 4, 1, memory_pkg, name, - mp->regions, sizeof(mp->regions)); - if (s < sizeof(mp->regions[0])) { - printk("getprop /memory %s returned %d\n", name, s); - abort(); - } - mp->n_regions = s / sizeof(mp->regions[0]); + unsigned long a, s; + int i, j; - /* - * Make sure the pieces are sorted. - */ for (i = 1; i < mp->n_regions; ++i) { - unsigned long a, s; - int j; - a = mp->regions[i].address; s = mp->regions[i].size; for (j = i - 1; j >= 0; --j) { @@ -174,6 +147,41 @@ } } +static void +coalesce_mem_pieces(struct mem_pieces *mp) +{ + unsigned long a, e; + int i, j, d; + + d = 0; + for (i = 0; i < mp->n_regions; i = j) { + a = mp->regions[i].address; + e = a + mp->regions[i].size; + for (j = i + 1; j < mp->n_regions + && mp->regions[j].address <= e; ++j) + e = mp->regions[j].address + mp->regions[j].size; + mp->regions[d].address = a; + mp->regions[d].size = e - a; + ++d; + } + mp->n_regions = d; +} + +/* + * Add some memory to an array of pieces + */ +static void +append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size) +{ + struct reg_property *rp; + + if (mp->n_regions >= MAX_MEM_REGIONS) + return; + rp = &mp->regions[mp->n_regions++]; + rp->address = start; + rp->size = size; +} + /* * Remove some memory from an array of pieces */ @@ -244,6 +252,9 @@ printk("\n"); } +/* + * Scan a region for a piece of a given size with the required alignment. + */ void * find_mem_piece(unsigned size, unsigned align) { @@ -266,8 +277,32 @@ } /* - * Collect information about RAM and which pieces are already in use. - * At this point, we have the first 8MB mapped with a BAT. + * Read in a property describing some pieces of memory. + */ +static void +get_mem_prop(char *name, struct mem_pieces *mp) +{ + struct reg_property *rp; + int s; + + rp = (struct reg_property *) get_property(memory_node, name, &s); + if (rp == NULL) { + printk(KERN_ERR "error: couldn't get %s property on /memory\n", + name); + abort(); + } + mp->n_regions = s / sizeof(mp->regions[0]); + memcpy(mp->regions, rp, s); + + /* Make sure the pieces are sorted. */ + sort_mem_pieces(mp); + coalesce_mem_pieces(mp); +} + +/* + * On systems with Open Firmware, collect information about + * physical RAM and which pieces are already in use. + * At this point, we have (at least) the first 8MB mapped with a BAT. * Our text, data, bss use something over 1MB, starting at 0. * Open Firmware may be using 1MB at the 4MB point. */ @@ -275,18 +310,24 @@ { unsigned long a, total; unsigned long kstart, ksize; - extern char _stext[], _end[]; int i; - memory_pkg = call_prom("finddevice", 1, 1, "/memory"); - if (memory_pkg == (void *) -1) - panic("can't find memory package"); + memory_node = find_devices("memory"); + if (memory_node == NULL) { + printk(KERN_ERR "can't find memory node\n"); + abort(); + } /* * Find out where physical memory is, and check that it * starts at 0 and is contiguous. It seems that RAM is * always physically contiguous on Power Macintoshes, * because MacOS can't cope if it isn't. + * + * Supporting discontiguous physical memory isn't hard, + * it just makes the virtual <-> physical mapping functions + * more complicated (or else you end up wasting space + * in mem_map). */ get_mem_prop("reg", &phys_mem); if (phys_mem.n_regions == 0) @@ -295,15 +336,11 @@ if (a != 0) panic("RAM doesn't start at physical address 0"); total = phys_mem.regions[0].size; - for (i = 1; i < phys_mem.n_regions; ++i) { - a = phys_mem.regions[i].address; - if (a != total) { - printk("RAM starting at 0x%lx is not contiguous\n", a); - printk("Using RAM from 0 to 0x%lx\n", total-1); - phys_mem.n_regions = i; - break; - } - total += phys_mem.regions[i].size; + if (phys_mem.n_regions > 1) { + printk("RAM starting at 0x%x is not contiguous\n", + phys_mem.regions[1].address); + printk("Using RAM from 0 to 0x%lx\n", total-1); + phys_mem.n_regions = 1; } /* record which bits the prom is using */ @@ -320,9 +357,11 @@ * Make sure the kernel text/data/bss is in neither. */ kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(_end - _stext); + ksize = PAGE_ALIGN(klimit - _stext); remove_mem_piece(&phys_avail, kstart, ksize, 0); remove_mem_piece(&prom_mem, kstart, ksize, 0); + remove_mem_piece(&phys_avail, 0, 0x4000, 0); + remove_mem_piece(&prom_mem, 0, 0x4000, 0); return __va(total); } @@ -333,14 +372,13 @@ * that setup_arch returns, making sure that there are at * least 32 pages unused before this for MMU_get_page to use. */ +unsigned long avail_start; + unsigned long find_available_memory(void) { int i; unsigned long a, free; unsigned long start, end; - - if ( _machine != _MACH_Pmac ) - return 0; free = 0; for (i = 0; i < phys_avail.n_regions - 1; ++i) { @@ -382,8 +420,12 @@ #ifdef CONFIG_NET show_net_buffers(); #endif - printk("%-8s %3s %3s %8s %8s %8s %9s %8s\n", "Process", "Pid", "Cnt", + printk("%-8s %3s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Cnt", "Ctx", "Ctx<<4", "Last Sys", "pc", "task"); +#ifdef __SMP__ + printk(" %3s", "CPU"); +#endif /* __SMP__ */ + printk("\n"); for_each_task(p) { printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ", @@ -392,16 +434,28 @@ p->mm->context<<4, p->tss.last_syscall, user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip, (ulong)p); - if ( p == current ) - printk("current"); - if ( p == last_task_used_math ) { + int iscur = 0; +#ifdef __SMP__ + printk("%3d ", p->processor); + if ( (p->processor != NO_PROC_ID) && + (p == current_set[p->processor]) ) + +#else if ( p == current ) - printk(","); - printk("last math"); +#endif /* __SMP__ */ + { + iscur = 1; + printk("current"); + } + if ( p == last_task_used_math ) + { + if ( iscur ) + printk(","); + printk("last math"); + } + printk("\n"); } - - printk("\n"); } } @@ -415,9 +469,9 @@ /* * Grab some memory for bad_page and bad_pagetable to use. */ - empty_bad_page = start_mem; - empty_bad_page_table = start_mem + PAGE_SIZE; - start_mem += 2 * PAGE_SIZE; + empty_bad_page = PAGE_ALIGN(start_mem); + empty_bad_page_table = empty_bad_page + PAGE_SIZE; + start_mem = empty_bad_page + 2 * PAGE_SIZE; /* note: free_area_init uses its second argument to size the mem_map array. */ @@ -442,53 +496,37 @@ /* mark usable pages in the mem_map[] */ start_mem = PAGE_ALIGN(start_mem); - if ( _machine == _MACH_Pmac ) - { - remove_mem_piece(&phys_avail, __pa(avail_start), - start_mem - avail_start, 1); - - for (addr = KERNELBASE ; addr < end_mem; addr += PAGE_SIZE) - set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); - - for (i = 0; i < phys_avail.n_regions; ++i) { - a = (unsigned long) __va(phys_avail.regions[i].address); - lim = a + phys_avail.regions[i].size; - a = PAGE_ALIGN(a); - for (; a < lim; a += PAGE_SIZE) - clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); - } - phys_avail.n_regions = 0; - - /* free the prom's memory */ - for (i = 0; i < prom_mem.n_regions; ++i) { - a = (unsigned long) __va(prom_mem.regions[i].address); - lim = a + prom_mem.regions[i].size; - a = PAGE_ALIGN(a); - for (; a < lim; a += PAGE_SIZE) - clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); - } - prom_trashed = 1; - } - else /* prep */ - { - /* mark mem used by kernel as reserved, mark other unreserved */ - for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE) - { - /* skip hash table gap */ - if ( (addr > (ulong)_end) && (addr < (ulong)Hash)) - continue; - if ( addr < (ulong) /*Hash_end*/ start_mem ) - set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); - else - clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); - } + remove_mem_piece(&phys_avail, __pa(avail_start), + start_mem - avail_start, 1); + + for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) + set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); + + for (i = 0; i < phys_avail.n_regions; ++i) { + a = (unsigned long) __va(phys_avail.regions[i].address); + lim = a + phys_avail.regions[i].size; + a = PAGE_ALIGN(a); + for (; a < lim; a += PAGE_SIZE) + clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); + } + phys_avail.n_regions = 0; + + /* free the prom's memory - no-op on prep */ + for (i = 0; i < prom_mem.n_regions; ++i) { + a = (unsigned long) __va(prom_mem.regions[i].address); + lim = a + prom_mem.regions[i].size; + a = PAGE_ALIGN(a); + for (; a < lim; a += PAGE_SIZE) + clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); } + prom_trashed = 1; for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { if (PageReserved(mem_map + MAP_NR(addr))) { if (addr < (ulong) etext) codepages++; - else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end)) + else if (addr >= (unsigned long)&__init_begin + && addr < (unsigned long)&__init_end) initpages++; else if (addr < (ulong) start_mem) datapages++; @@ -497,7 +535,7 @@ atomic_set(&mem_map[MAP_NR(addr)].count, 1); #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start || - (addr < initrd_start || addr >= initrd_end)) + addr < (initrd_start & PAGE_MASK) || addr >= initrd_end) #endif /* CONFIG_BLK_DEV_INITRD */ free_page(addr); } @@ -512,31 +550,22 @@ } /* - * this should reclaim gap between _end[] and hash table - * as well as unused mmu_pages[] on prep systems. - * When I get around to it, I'll put initialization functions - * (called only at boot) in their own .section and free that -- Cort + * Unfortunately, we can't put initialization functions in their + * own section and free that at this point, because gas gets some + * relocations wrong if we do. :-( But this code is here for when + * gas gets fixed. */ void free_initmem(void) { unsigned long a; unsigned long num_freed_pages = 0; - /* free unused mmu_pages[] */ - a = PAGE_ALIGN( (unsigned long) mmu_pages) + (mmu_pages_count*PAGE_SIZE); - for ( ; a < PAGE_ALIGN((unsigned long)mmu_pages)+(MAX_MMU_PAGES*PAGE_SIZE); a += PAGE_SIZE ) - { - clear_bit( PG_reserved, &mem_map[MAP_NR(a)].flags ); - atomic_set(&mem_map[MAP_NR(a)].count, 1); - free_page(a); - num_freed_pages++; - } - a = (unsigned long)(&__init_begin); for (; a < (unsigned long)(&__init_end); a += PAGE_SIZE) { - mem_map[MAP_NR(a)].flags &= ~(1 << PG_reserved); + clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); atomic_set(&mem_map[MAP_NR(a)].count, 1); free_page(a); + num_freed_pages++; } printk ("Freeing unused kernel memory: %ldk freed\n", @@ -565,138 +594,72 @@ return; } -BAT BAT0 = -{ - { - MMU_SEGMENT_1>>17, /* bepi */ - BL_256M, /* bl */ - 1, /* vs -- supervisor mode valid */ - 1, /* vp -- user mode valid */ - }, - { - MMU_SEGMENT_1>>17, /* brpn */ - 1, /* write-through */ - 1, /* cache-inhibited */ - 0, /* memory coherence */ - 1, /* guarded */ - BPP_RW /* protection */ - } -}; -BAT BAT1 = -{ - { - MMU_SEGMENT_2>>17, /* bepi */ - BL_256M, /* bl */ - 1, /* vs */ - 1, /* vp */ - }, - { - MMU_SEGMENT_2>>17, /* brpn */ - 1, /* w */ - 1, /* i (cache disabled) */ - 0, /* m */ - 1, /* g */ - BPP_RW /* pp */ - } -}; -BAT BAT2 = -{ - { - 0x90000000>>17, /* bepi */ - BL_256M, /* this gets set to amount of phys ram */ - 1, /* vs */ - 0, /* vp */ - }, - { - 0x00000000>>17, /* brpn */ - 0, /* w */ - 0, /* i */ -#ifdef __SMP__ - 1, /* m */ -#else - 0, /* m */ -#endif - 0, /* g */ - BPP_RW /* pp */ - } -}; -BAT BAT3 = -{ - { - 0x00000000>>17, /* bepi */ - BL_256M, /* bl */ - 0, /* vs */ - 0, /* vp */ - }, - { - 0x00000000>>17, /* brpn */ - 0, /* w */ - 0, /* i (cache disabled) */ - 1, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } -}; +union ubat { /* BAT register values to be loaded */ + BAT bat; + P601_BAT bat_601; + u32 word[2]; +} BATS[4][2]; /* 4 pairs of IBAT, DBAT */ + +struct batrange { /* stores address ranges mapped by BATs */ + unsigned long start; + unsigned long limit; + unsigned long phys; +} bat_addrs[4]; -P601_BAT BAT0_601 = -{ - { - 0x80000000>>17, /* bepi */ - 1,1,0, /* wim */ - 1, 0, /* vs, vp */ - BPP_RW, /* pp */ - }, - { - 0x80000000>>17, /* brpn */ - 1, /* v */ - BL_8M, /* bl */ - } -}; - -P601_BAT BAT1_601 = -{ - { - MMU_SEGMENT_2>>17, /* bepi */ - 1,1,0, /* wim */ - 1, 0, /* vs, vp */ - BPP_RW, /* pp */ - }, - { - MMU_SEGMENT_2>>17, /* brpn */ - 1, /* v */ - BL_8M, /* bl */ - } -}; - -P601_BAT BAT2_601 = -{ - { - 0x90000000>>17, /* bepi */ - 0,0,0, /* wim */ - 1, 0, /* vs, vp */ - BPP_RW, /* pp */ - }, - { - 0x00000000>>17, /* brpn */ - 1, /* v */ - BL_8M, /* bl */ - } -}; - -P601_BAT BAT3_601 = +/* + * Set up one of the I/D BAT (block address translation) register pairs. + * The parameters are not checked; in particular size must be a power + * of 2 between 128k and 256M. + */ +void +setbat(int index, unsigned long virt, unsigned long phys, + unsigned int size, int flags) { - { - 0x90800000>>17, /* bepi */ - 0,0,0, /* wim */ - 1, 0, /* vs, vp */ - BPP_RW, /* pp */ - }, - { - 0x00800000>>17, /* brpn */ - 1, /* v */ - BL_8M, /* bl */ - } -}; + unsigned int bl; + int wimgxpp; + union ubat *bat = BATS[index]; + + bl = (size >> 17) - 1; + if ((_get_PVR() >> 16) != 1) { + /* 603, 604, etc. */ + /* Do DBAT first */ + wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE + | _PAGE_COHERENT | _PAGE_GUARDED); + wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX; + bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */ + bat[1].word[1] = phys | wimgxpp; + if (flags & _PAGE_USER) + bat[1].bat.batu.vp = 1; + if (flags & _PAGE_GUARDED) { + /* G bit must be zero in IBATs */ + bat[0].word[0] = bat[0].word[1] = 0; + } else { + /* make IBAT same as DBAT */ + bat[0] = bat[1]; + } + } else { + /* 601 cpu */ + if (bl > BL_8M) + bl = BL_8M; + wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE + | _PAGE_COHERENT); + wimgxpp |= (flags & _PAGE_RW)? + ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX; + bat->word[0] = virt | wimgxpp | 4; /* Ks=0, Ku=1 */ + bat->word[1] = phys | bl | 0x40; /* V=1 */ + } + + bat_addrs[index].start = virt; + bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1; + bat_addrs[index].phys = phys; +} + +#define IO_PAGE (_PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_RW) +#ifdef __SMP__ +#define RAM_PAGE (_PAGE_COHERENT | _PAGE_RW) +#else +#define RAM_PAGE (_PAGE_RW) +#endif /* * This finds the amount of physical ram and does necessary @@ -706,158 +669,76 @@ */ unsigned long *prep_find_end_of_memory(void) { - int i; - - if (res.TotalMemory == 0 ) + unsigned long kstart, ksize; + unsigned long total; + total = res.TotalMemory; + + if (total == 0 ) { /* * I need a way to probe the amount of memory if the residual * data doesn't contain it. -- Cort */ printk("Ramsize from residual data was 0 -- Probing for value\n"); - res.TotalMemory = 0x03000000; - printk("Ramsize default to be %ldM\n", res.TotalMemory>>20); + total = 0x02000000; + printk("Ramsize default to be %ldM\n", total>>20); } + append_mem_piece(&phys_mem, 0, total); + phys_avail = phys_mem; + kstart = __pa(_stext); /* should be 0 */ + ksize = PAGE_ALIGN(klimit - _stext); + remove_mem_piece(&phys_avail, kstart, ksize, 0); + remove_mem_piece(&phys_avail, 0, 0x4000, 0); - /* NOTE: everything below here is moving to mapin_ram() */ - - - /* - * if this is a 601, we can only map sizes of 8M with the BAT's - * so we have to map what we can't map with the bats with the segregs - * head.S will copy in the appropriate BAT's according to the processor - * since the 601_BAT{2,3} structures are already setup to map - * the first 16M correctly - * -- Cort - */ -#ifndef MAP_RAM_WITH_SEGREGS /* don't need to do it twice */ - if ( _get_PVR() == 1 ) - { - /* map in rest of ram with seg regs */ - if ( res.TotalMemory > 0x01000000 /* 16M */) - { - for (i = KERNELBASE+0x01000000; - i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE) - map_page(&init_task, i, __pa(i), - _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED); - } - } -#endif /* MAP_RAM_WITH_SEGREGS */ - -#ifdef MAP_RAM_WITH_SEGREGS - /* turn off bat mapping kernel since being done with segregs */ - memset(&BAT2, sizeof(BAT2), 0); - memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */ - memset(&BAT3_601, sizeof(BAT2), 0); - /* map all of ram for kernel with segregs */ - for (i = KERNELBASE; i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE) - { - if ( i < (unsigned long)etext ) - map_page(&init_task, i, __pa(i), - _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED); - else - map_page(&init_task, i, __pa(i), - _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED); - } -#endif /* MAP_RAM_WITH_SEGREGS */ - - return (__va(res.TotalMemory)); + return (__va(total)); } /* * Map in all of physical memory starting at KERNELBASE. */ -extern int n_mem_regions; -extern struct reg_property mem_regions[]; - #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) static void mapin_ram() { - int i; - unsigned long v, p, s, f; + int i; + unsigned long tot, bl, done; + unsigned long v, p, s, f; - if ( _machine == _MACH_Pmac ) - { - v = KERNELBASE; - for (i = 0; i < phys_mem.n_regions; ++i) { - p = phys_mem.regions[i].address; - for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { - f = _PAGE_PRESENT | _PAGE_ACCESSED; - if ((char *) v < _stext || (char *) v >= etext) - f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; - else - /* On the powerpc, no user access forces R/W kernel access */ - f |= _PAGE_USER; - map_page(&init_task, v, p, f); - v += PAGE_SIZE; - p += PAGE_SIZE; - } - } - } - else /* prep */ - { - /* setup the bat2 mapping to cover physical ram */ - BAT2.batu.bl = 0x1; /* 256k mapping */ - for ( f = 256*1024 /* 256k */ ; - (f <= res.TotalMemory) && (f <= 256*1024*1024); - f *= 2 ) - BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl; - /* - * let ibm get to the device mem from user mode since - * the X for them needs it right now -- Cort - */ - if ( _machine == _MACH_IBM ) - BAT0.batu.vp = BAT1.batu.vp = 1; - - } -} - -#define MAX_PROM_TRANSLATIONS 64 - -static struct translation_property prom_translations[MAX_PROM_TRANSLATIONS]; -int n_translations; -phandle mmu_pkg; -extern ihandle prom_chosen; - -static void inherit_prom_translations() -{ - int s, i, f; - unsigned long v, p, n; - struct translation_property *tp; - ihandle mmu_inst; - - if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu", - &mmu_inst, sizeof(mmu_inst)) != sizeof(mmu_inst)) - panic("couldn't get /chosen mmu property"); - mmu_pkg = call_prom("instance-to-package", 1, 1, mmu_inst); - if (mmu_pkg == (phandle) -1) - panic("couldn't get mmu package"); - s = (int) call_prom("getprop", 4, 1, mmu_pkg, "translations", - &prom_translations, sizeof(prom_translations)); - if (s < sizeof(prom_translations[0])) - panic("couldn't get mmu translations property"); - n_translations = s / sizeof(prom_translations[0]); - - for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) { - /* ignore stuff mapped down low */ - if (tp->virt < 0x10000000 && tp->phys < 0x10000000) - continue; - /* map PPC mmu flags to linux mm flags */ - f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU - | _PAGE_COHERENT | _PAGE_GUARDED)) - | pgprot_val(PAGE_KERNEL); - /* add these pages to the mappings */ - v = tp->virt; - p = tp->phys; - n = tp->size; - for (; n != 0; n -= PAGE_SIZE) { +#ifndef MAP_RAM_WITH_SEGREGS + /* Set up BAT2 and if necessary BAT3 to cover RAM. */ + tot = (unsigned long)end_of_DRAM - KERNELBASE; + for (bl = 128<<10; bl < 256<<20; bl <<= 1) + if (bl * 2 > tot) + break; + setbat(2, KERNELBASE, 0, bl, RAM_PAGE); + done = __pa(bat_addrs[2].limit) + 1; + if (done < tot) { + /* use BAT3 to cover a bit more */ + tot -= done; + for (bl = 128<<10; bl < 256<<20; bl <<= 1) + if (bl * 2 > tot) + break; + setbat(3, KERNELBASE+done, done, bl, RAM_PAGE); + } +#endif + + v = KERNELBASE; + for (i = 0; i < phys_mem.n_regions; ++i) { + p = phys_mem.regions[i].address; + for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { + f = _PAGE_PRESENT | _PAGE_ACCESSED; + if ((char *) v < _stext || (char *) v >= etext) + f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; + else + /* On the powerpc, no user access + forces R/W kernel access */ + f |= _PAGE_USER; map_page(&init_task, v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; } - } + } } /* @@ -866,56 +747,78 @@ static void hash_init(void) { int Hash_bits; - unsigned long h; + unsigned long h, ramsize; extern unsigned int hash_page_patch_A[], hash_page_patch_B[], - hash_page_patch_C[]; + hash_page_patch_C[], hash_page_patch_D[]; /* * Allow 64k of hash table for every 16MB of memory, * up to a maximum of 2MB. */ - for (h = 64<<10; h < (ulong)__pa(end_of_DRAM) / 256 && h < 2<<20; h *= 2) + ramsize = (ulong)end_of_DRAM - KERNELBASE; + for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2) ; Hash_size = h; Hash_mask = (h >> 6) - 1; - + +#ifdef NO_RELOAD_HTAB + /* shrink the htab since we don't use it on 603's -- Cort */ + switch (_get_PVR()>>16) { + case 3: /* 603 */ + case 6: /* 603e */ + case 7: /* 603ev */ + Hash_size = 0; + Hash_mask = 0; + break; + default: + /* on 601/4 let things be */ + break; + } +#endif /* NO_RELOAD_HTAB */ + /* Find some memory for the hash table. */ - if ( is_prep ) - /* align htab on a Hash_size boundry above _end[] */ - Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size); - else /* pmac */ + if ( Hash_size ) Hash = find_mem_piece(Hash_size, Hash_size); - + else + Hash = 0; + printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n", - __pa(end_of_DRAM) >> 20, Hash_size >> 10, Hash); - memset(Hash, 0, Hash_size); - Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); + ramsize >> 20, Hash_size >> 10, Hash); + if ( Hash_size ) + { + memset(Hash, 0, Hash_size); + Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); - /* - * Patch up the instructions in head.S:hash_page - */ - Hash_bits = ffz(~Hash_size) - 6; - hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) - | (__pa(Hash) >> 16); - hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) - | ((26 - Hash_bits) << 6); - if (Hash_bits > 16) - Hash_bits = 16; - hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) - | ((26 - Hash_bits) << 6); - hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) - | (Hash_mask >> 10); - hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) - | (Hash_mask >> 10); + /* + * Patch up the instructions in head.S:hash_page + */ + Hash_bits = ffz(~Hash_size) - 6; + hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) + | (__pa(Hash) >> 16); + hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) + | ((26 - Hash_bits) << 6); + if (Hash_bits > 16) + Hash_bits = 16; + hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) + | ((26 - Hash_bits) << 6); + hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) + | (Hash_mask >> 10); + hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) + | (Hash_mask >> 10); + hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff) + | (Hash_mask >> 10); + /* + * Ensure that the locations we've patched have been written + * out from the data cache and invalidated in the instruction + * cache, on those machines with split caches. + */ + flush_icache_range((unsigned long) hash_page_patch_A, + (unsigned long) (hash_page_patch_D + 1)); + } + else + Hash_end = 0; - /* - * Ensure that the locations we've patched have been written - * out from the data cache and invalidated in the instruction - * cache, on those machines with split caches. - */ - flush_icache_range((unsigned long) hash_page_patch_A, - (unsigned long) (hash_page_patch_C + 1)); } @@ -929,19 +832,40 @@ void MMU_init(void) { - if ( _machine == _MACH_Pmac ) + if (have_of) end_of_DRAM = pmac_find_end_of_memory(); - else /* prep and chrp */ + else /* prep */ end_of_DRAM = prep_find_end_of_memory(); - + hash_init(); _SDR1 = __pa(Hash) | (Hash_mask >> 10); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); - if ( _machine == _MACH_Pmac ) - /* Copy mappings from the prom */ - inherit_prom_translations(); + + /* + * Setup the bat mappings we're going to load that cover + * the io areas. RAM was mapped by mapin_ram(). + * -- Cort + */ + switch (_machine) { + case _MACH_prep: + setbat(0, 0x80000000, 0x80000000, 0x10000000, + IO_PAGE + ((_prep_type == _PREP_IBM)? _PAGE_USER: 0)); + setbat(1, 0xd0000000, 0xc0000000, 0x10000000, + IO_PAGE + ((_prep_type == _PREP_IBM)? _PAGE_USER: 0)); + break; + case _MACH_chrp: + setbat(0, 0xc0000000, 0xc0000000, 0x10000000, IO_PAGE); + setbat(1, 0xf8000000, 0xf8000000, 0x20000, IO_PAGE); + setbat(3, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + break; + case _MACH_Pmac: + setbat(0, 0xf3000000, 0xf3000000, 0x100000, IO_PAGE); + /* this is used to cover registers used by smp boards -- Cort */ + setbat(3, 0xf8000000, 0xf8000000, 0x100000, IO_PAGE); + break; + } } static void * @@ -954,18 +878,7 @@ if (p == 0) panic("couldn't get a page in MMU_get_page"); } else { - if ( is_prep || (_machine == _MACH_chrp) ) - { - mmu_pages_count++; - if ( mmu_pages_count > MAX_MMU_PAGES ) - printk("out of mmu pages!\n"); - p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+ - (mmu_pages_count+PAGE_SIZE)); - } - else /* pmac */ - { - p = find_mem_piece(PAGE_SIZE, PAGE_SIZE); - } + p = find_mem_piece(PAGE_SIZE, PAGE_SIZE); } memset(p, 0, PAGE_SIZE); return p; @@ -976,30 +889,15 @@ { unsigned long p, end = addr + size; - /* - * BAT mappings on prep cover this already so don't waste - * space with it. -- Cort - */ - if ( is_prep ) - if ( ((addr >= 0xc0000000) && (end < (0xc0000000+(256<<20)))) || - ((addr >= 0x80000000) && (end < (0x80000000+(256<<20)))) ) - return (void *)addr; for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE) - map_page(&init_task, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED); + map_page(&init_task, p, p, + pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED); return (void *) addr; } -extern void iounmap(unsigned long *addr) +void iounmap(unsigned long *addr) { - /* - * BAT mappings on prep cover this already so don't waste - * space with it. -- Cort - */ - if ( is_prep ) - if ( (((unsigned long)addr >= 0xc0000000) && ((unsigned long)addr < (0xc0000000+(256<<20)))) || - (((unsigned long)addr >= 0x80000000) && ((unsigned long)addr < (0x80000000+(256<<20)))) ) - return; - /* else unmap it */ + /* XXX todo */ } void @@ -1008,7 +906,7 @@ { pmd_t *pd; pte_t *pg; - + int b; if (tsk->mm->pgd == NULL) { /* Allocate upper level page map */ @@ -1017,7 +915,18 @@ /* Use upper 10 bits of VA to index the first level map */ pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT)); if (pmd_none(*pd)) { - /* Need to allocate second-level table */ + /* + * Need to allocate second-level table, but first + * check whether this address is already mapped by + * the BATs; if so, don't bother allocating the page. + */ + for (b = 0; b < 4; ++b) { + if (va >= bat_addrs[b].start + && va <= bat_addrs[b].limit) { + /* XXX should check the phys address matches */ + return; + } + } pg = (pte_t *) MMU_get_page(); pmd_val(*pd) = (unsigned long) pg; } @@ -1042,22 +951,14 @@ */ /* - * Flush all tlb/hash table entries except for the kernel's. - * We use the fact that only kernel mappings use VSIDs 0 - 15. + * Flush all tlb/hash table entries (except perhaps for those + * mapping RAM starting at PAGE_OFFSET, since they never change). */ void -flush_tlb_all(void) +local_flush_tlb_all(void) { - struct task_struct *tsk; - - read_lock(&tasklist_lock); - for_each_task(tsk) { - if (tsk->mm) - tsk->mm->context = NO_CONTEXT; - } - read_unlock(&tasklist_lock); - get_mmu_context(current); - set_context(current->mm->context); + memset(Hash, 0, Hash_size); + _tlbia(); } @@ -1067,7 +968,7 @@ * that might be in the hash table. */ void -flush_tlb_mm(struct mm_struct *mm) +local_flush_tlb_mm(struct mm_struct *mm) { mm->context = NO_CONTEXT; if (mm == current->mm) { @@ -1077,6 +978,16 @@ } } +void +local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + if (vmaddr < TASK_SIZE) + flush_hash_page(vma->vm_mm->context, vmaddr); + else + flush_hash_page(0, vmaddr); +} + + /* for each page addr in the range, call MMU_invalidate_page() if the range is very large and the hash table is small it might be faster to do a search of the hash table and just invalidate pages that are in the range @@ -1084,9 +995,16 @@ -- Cort */ void -flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { start &= PAGE_MASK; + + if (end - start > 20 * PAGE_SIZE) + { + flush_tlb_mm(mm); + return; + } + for (; start < end && start < TASK_SIZE; start += PAGE_SIZE) { flush_hash_page(mm->context, start); @@ -1117,4 +1035,58 @@ current->mm->context = MUNGE_CONTEXT(++next_mmu_context); set_context(current->mm->context); } + +#if 0 +/* + * Cache flush functions - these functions cause caches to be flushed + * on _all_ processors due to their use of dcbf. local_flush_cache_all() is + * the only function that will not act on all processors in the system. + * -- Cort + */ +void local_flush_cache_all(void) +{ +#if 0 + unsigned long hid0,tmp; + asm volatile( + "mfspr %0,1008 \n\t" + "mr %1,%0 \n\t" + "or %0,%2,%2 \n\t" + "mtspr 1008,%0 \n\t" + "sync \n\t" + "isync \n\t" + "andc %0,%0,%2 \n\t" + "mtspr 1008,%0 \n\t" + : "=r" (tmp), "=r" (hid0) + : "r" (HID0_ICFI|HID0_DCI) + ); +#endif +} + +void local_flush_cache_mm(struct mm_struct *mm) +{ + struct vm_area_struct *vma = NULL; + vma = mm->mmap; + while(vma) + { + local_flush_cache_range(mm,vma->vm_start,vma->vm_end); + vma = vma->vm_next; + } +} + +void local_flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + unsigned long i; + vmaddr = PAGE_ALIGN(vmaddr); + for ( i = vmaddr ; i <= (vmaddr+PAGE_SIZE); i += 32 ) + asm volatile("dcbf %0,%1\n\ticbi %0,%1\n\t" :: "r" (i), "r" (0)); +} + +void local_flush_cache_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + unsigned long i; + for ( i = start ; i <= end; i += 32 ) + asm volatile("dcbf %0,%1\n\ticbi %0,%1\n\t" :: "r" (i), "r" (0)); +} +#endif diff -u --recursive --new-file v2.1.78/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig --- v2.1.78/linux/arch/ppc/pmac_defconfig Mon Aug 18 18:19:44 1997 +++ linux/arch/ppc/pmac_defconfig Mon Jan 12 15:18:13 1998 @@ -1,17 +1,17 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # # # Platform support # +CONFIG_PPC=y CONFIG_NATIVE=y +CONFIG_MACH_SPECIFIC=y CONFIG_PMAC=y # CONFIG_PREP is not set -CONFIG_MCOMMON=y -# CONFIG_M601 is not set -# CONFIG_M603 is not set -# CONFIG_M604 is not set +# CONFIG_CHRP is not set +CONFIG_COMMON=y # # General setup @@ -24,6 +24,7 @@ CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y CONFIG_BINFMT_MISC=m @@ -32,7 +33,7 @@ CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_PROC_DEVICETREE=y -CONFIG_XMON=y +# CONFIG_XMON is not set CONFIG_ATY_VIDEO=y CONFIG_IMSTT_VIDEO=y @@ -46,10 +47,6 @@ # # CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_BLK_DEV_IDECD=y @@ -60,10 +57,6 @@ # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_TRITON is not set # CONFIG_IDE_CHIPSETS is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y @@ -73,22 +66,54 @@ # CONFIG_BLK_DEV_HD is not set # -# SCSI support +# NEW devices (io_request, all ALPHA and dangerous) # -CONFIG_SCSI=y +# CONFIG_IO_REQUEST is not set # -# SCSI support type (disk, tape, CD-ROM) +# Networking options # +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +CONFIG_NET_ALIAS=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ACCT is not set +# CONFIG_IP_MASQUERADE is not set +# CONFIG_IP_ROUTER is not set +CONFIG_NET_IPIP=m +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_RARP=y +CONFIG_IP_NOSR=y +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_AX25 is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_CPU_IS_SLOW is not set +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -125,58 +150,22 @@ CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=10 CONFIG_SCSI_MAC53C94=y -CONFIG_SCSI_QLOGIC_PMAC=m # # Network device support # - -# -# Networking options -# -# CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ACCT is not set -# CONFIG_IP_ROUTER is not set -CONFIG_NET_IPIP=m -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -# CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -# CONFIG_INET_PCTCP is not set -CONFIG_INET_RARP=y -CONFIG_PATH_MTU_DISCOVERY=y -CONFIG_IP_NOSR=y -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_AX25 is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_WAN_ROUTER is not set CONFIG_NETDEVICES=y # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_DEC_ELCP=m # 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_NET_ISA is not set # CONFIG_NET_EISA is not set # CONFIG_NET_POCKET is not set @@ -184,10 +173,6 @@ # CONFIG_DLCI is not set # CONFIG_PLIP is not set CONFIG_PPP=m - -# -# CCP compressors for PPP are only built as modules. -# # CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set # CONFIG_TR is not set @@ -209,18 +194,14 @@ # CONFIG_QUOTA is not set CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_UMSDOS_FS is not set +CONFIG_ISO9660_FS=y +# CONFIG_NLS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set -CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set @@ -234,6 +215,7 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y +# CONFIG_SOFTCURSOR is not set CONFIG_SERIAL=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set @@ -245,30 +227,12 @@ # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_BT848 is not set CONFIG_NVRAM=y # CONFIG_JOYSTICK is not set # # Sound # -CONFIG_SOUND=m -# CONFIG_PAS is not set -# CONFIG_SB is not set -# CONFIG_ADLIB is not set -# CONFIG_GUS is not set -# CONFIG_MPU401 is not set -# CONFIG_PSS is not set -# CONFIG_GUS16 is not set -# CONFIG_GUSMAX is not set -# CONFIG_MSS is not set -# CONFIG_SSCAPE is not set -# CONFIG_TRIX is not set -# CONFIG_MAD16 is not set -# CONFIG_CS4232 is not set -# CONFIG_MAUI is not set -# CONFIG_YM3812 is not set -CONFIG_LOWLEVEL_SOUND=y -# CONFIG_ACI_MIXER is not set -# CONFIG_AWE32_SYNTH is not set -# CONFIG_AEDSP16 is not set -CONFIG_AWACS=y +# CONFIG_SOUND is not set diff -u --recursive --new-file v2.1.78/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig --- v2.1.78/linux/arch/ppc/prep_defconfig Thu Sep 4 17:07:30 1997 +++ linux/arch/ppc/prep_defconfig Mon Jan 12 15:18:13 1998 @@ -7,9 +7,11 @@ # CONFIG_PPC=y CONFIG_NATIVE=y +CONFIG_MACH_SPECIFIC=y # CONFIG_PMAC is not set CONFIG_PREP=y -CONFIG_MCOMMON=y +# CONFIG_CHRP is not set +CONFIG_COMMON=y # # General setup @@ -19,14 +21,20 @@ CONFIG_MODVERSIONS=y CONFIG_KERNELD=y CONFIG_PCI=y -CONFIG_PCI_OPTIMIZE=y +# CONFIG_PCI_OPTIMIZE is not set CONFIG_NET=y -CONFIG_SYSCTL=y +# CONFIG_SYSCTL is not set CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_BINFMT_JAVA is not set +# CONFIG_PMAC_CONSOLE is not set +# CONFIG_MAC_KEYBOARD is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_XMON is not set CONFIG_VGA_CONSOLE=y # @@ -49,7 +57,7 @@ # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_TRITON is not set # CONFIG_IDE_CHIPSETS is not set -CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y @@ -58,6 +66,45 @@ # CONFIG_BLK_DEV_HD is not set # +# NEW devices (io_request, all ALPHA and dangerous) +# +# CONFIG_IO_REQUEST is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ACCT is not set +# CONFIG_IP_MASQUERADE is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_RARP=y +# CONFIG_IP_NOSR is not set +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_AX25 is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_CPU_IS_SLOW is not set +# CONFIG_NET_SCHED is not set + +# # SCSI support # CONFIG_SCSI=y @@ -67,7 +114,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set # CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_CONSTANTS is not set # # SCSI low-level drivers @@ -111,46 +158,13 @@ # # Network device support # - -# -# Networking options -# -# CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ACCT is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_XTP is not set -# CONFIG_INET_PCTCP is not set -# CONFIG_INET_RARP is not set -CONFIG_PATH_MTU_DISCOVERY=y -# CONFIG_IP_NOSR is not set -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_AX25 is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_WAN_ROUTER is not set CONFIG_NETDEVICES=y # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set CONFIG_NET_ETHERNET=y -CONFIG_NET_VENDOR_3COM=y -# CONFIG_EL1 is not set -# CONFIG_EL2 is not set -# CONFIG_ELPLUS is not set -# CONFIG_EL16 is not set -CONFIG_EL3=y -# CONFIG_VORTEX is not set +# CONFIG_NET_VENDOR_3COM is not set CONFIG_LANCE=y # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set @@ -171,7 +185,7 @@ # CONFIG_FDDI is not set # CONFIG_DLCI is not set # CONFIG_PLIP is not set -CONFIG_PPP=y +CONFIG_PPP=m # CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set # CONFIG_TR is not set @@ -193,25 +207,30 @@ # CONFIG_QUOTA is not set # CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_VFAT_FS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET 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_PROC_FS=y CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y +# CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set -CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_ROMFS_FS is not set # CONFIG_AUTOFS_FS is not set # CONFIG_UFS_FS is not set -CONFIG_MAC_PARTITION=y +# CONFIG_MAC_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set # # Character devices @@ -241,6 +260,8 @@ # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_BT848 is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set diff -u --recursive --new-file v2.1.78/linux/arch/sparc/ap1000/aplib.c linux/arch/sparc/ap1000/aplib.c --- v2.1.78/linux/arch/sparc/ap1000/aplib.c Wed Sep 24 20:05:46 1997 +++ linux/arch/sparc/ap1000/aplib.c Mon Jan 12 15:15:43 1998 @@ -455,7 +455,7 @@ while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) { tnet_check_completion(); - if (resched_needed()) + if (need_resched) break; if (signal_pending(current)) break; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/ap1000/mpp.c linux/arch/sparc/ap1000/mpp.c --- v2.1.78/linux/arch/sparc/ap1000/mpp.c Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/ap1000/mpp.c Mon Jan 12 15:15:43 1998 @@ -28,7 +28,7 @@ void mpp_schedule(struct cap_request *req) { mpp_current_task = req->data[0]; - resched_force(); + need_resched = 1; mark_bh(TQUEUE_BH); } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c --- v2.1.78/linux/arch/sparc/ap1000/msc.c Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/ap1000/msc.c Mon Jan 12 15:15:43 1998 @@ -338,7 +338,7 @@ #endif MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH); intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH); - resched_force(); + need_resched = 1; block_parallel_tasks = 1; mark_bh(TQUEUE_BH); } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/ap1000/timer.c linux/arch/sparc/ap1000/timer.c --- v2.1.78/linux/arch/sparc/ap1000/timer.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/ap1000/timer.c Mon Jan 12 15:15:43 1998 @@ -73,6 +73,7 @@ last_freerun = new_freerun; } +#ifdef CONFIG_PROFILE static void profile_interrupt(int irq, void *dev_id, struct pt_regs * regs) { @@ -96,6 +97,8 @@ } } +#endif + void ap_init_timers(void) { extern void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs); @@ -109,11 +112,13 @@ timer_interrupt, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL); - + +#ifdef CONFIG_PROFILE request_irq(APTIM0_IRQ, profile_interrupt, (SA_INTERRUPT | SA_STATIC_ALLOC), "profile", NULL); +#endif ap_clear_clock_irq(); diff -u --recursive --new-file v2.1.78/linux/arch/sparc/ap1000/tnet.c linux/arch/sparc/ap1000/tnet.c --- v2.1.78/linux/arch/sparc/ap1000/tnet.c Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/ap1000/tnet.c Mon Jan 12 15:15:43 1998 @@ -613,7 +613,7 @@ static void reschedule(void) { - resched_force(); + need_resched = 1; mark_bh(TQUEUE_BH); } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.1.78/linux/arch/sparc/config.in Tue Dec 2 16:45:17 1997 +++ linux/arch/sparc/config.in Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.38 1997/09/04 01:54:33 davem Exp $ +# $Id: config.in,v 1.51 1998/01/08 04:16:54 baccala Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -28,6 +28,7 @@ if [ "$CONFIG_AP1000" = "y" ]; then define_bool CONFIG_NO_KEYBOARD y + define_bool CONFIG_FDDI y define_bool CONFIG_APFDDI y define_bool CONFIG_APBLOCK y define_bool CONFIG_APBIF y @@ -39,6 +40,7 @@ define_bool CONFIG_SUN_MOUSE y define_bool CONFIG_SERIAL y define_bool CONFIG_SUN_SERIAL y + define_bool CONFIG_SERIAL_CONSOLE y define_bool CONFIG_SUN_KEYBOARD y define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y @@ -50,6 +52,7 @@ tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF @@ -78,6 +81,7 @@ fi tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +tristate 'Network block device support' CONFIG_BLK_DEV_NBD endmenu @@ -86,6 +90,15 @@ fi mainmenu_option next_comment +comment 'ISDN subsystem' + +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in +fi +endmenu + +mainmenu_option next_comment comment 'SCSI support' tristate 'SCSI support' CONFIG_SCSI @@ -116,6 +129,8 @@ fi endmenu +source drivers/fc4/Config.in + if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment comment 'Network device support' @@ -162,7 +177,9 @@ mainmenu_option next_comment comment 'Watchdog' -bool 'Software watchdog' CONFIG_SOFT_WATCHDOG +tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG +endmenu + mainmenu_option next_comment comment 'Kernel hacking' @@ -170,4 +187,5 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --recursive --new-file v2.1.78/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.1.78/linux/arch/sparc/defconfig Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/defconfig Mon Jan 12 15:15:43 1998 @@ -49,7 +49,6 @@ # CONFIG_SUN_OPENPROMIO=m CONFIG_SUN_MOSTEK_RTC=y -# CONFIG_SAB82532 is not set # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set @@ -62,6 +61,7 @@ CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y @@ -75,6 +75,8 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_MD_STRIPED=y +CONFIG_MD_MIRRORING=m +CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m @@ -82,41 +84,46 @@ # # Networking options # +CONFIG_PACKET=y CONFIG_NETLINK=y CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set CONFIG_FIREWALL=y # CONFIG_NET_SECURITY is not set CONFIG_NET_ALIAS=y +CONFIG_UNIX=y CONFIG_INET=y CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set CONFIG_IP_FIREWALL=y # CONFIG_IP_FIREWALL_NETLINK is not set # CONFIG_IP_FIREWALL_VERBOSE is not set +# CONFIG_IP_TRANSPARENT_PROXY is not set +# CONFIG_IP_ALWAYS_DEFRAG is not set +# CONFIG_IP_ACCT is not set CONFIG_IP_MASQUERADE=y # # Protocol-specific masquerading support will be built as modules. # -# CONFIG_IP_TRANSPARENT_PROXY is not set -# CONFIG_IP_ALWAYS_DEFRAG is not set -# CONFIG_IP_ACCT is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=m # CONFIG_ARPD is not set # CONFIG_SYN_COOKIES is not set -# CONFIG_XTP is not set # # (it is safe to leave these untouched) # -# CONFIG_INET_PCTCP is not set CONFIG_INET_RARP=m -# CONFIG_PATH_MTU_DISCOVERY is not set CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y CONFIG_IPV6=m +# CONFIG_IPV6_EUI64 is not set +# CONFIG_IPV6_NO_PB is not set # # @@ -125,13 +132,22 @@ # CONFIG_IPX_INTERN is not set # CONFIG_IPX_PPROP_ROUTING is not set CONFIG_ATALK=m -# CONFIG_IPDDP is not set # CONFIG_AX25 is not set CONFIG_X25=m # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_WAN_ROUTER is not set +# CONFIG_CPU_IS_SLOW is not set +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_HFQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_PFIFO=y +CONFIG_NET_SCH_PRIO=y # # SCSI support @@ -184,22 +200,20 @@ CONFIG_QUOTA=y CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m -# CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_RNFS_BOOTP=y -CONFIG_RNFS_RARP=y CONFIG_NFSD=m CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m -CONFIG_ISO9660_FS=y CONFIG_HPFS_FS=m CONFIG_SYSV_FS=m CONFIG_AFFS_FS=m @@ -212,6 +226,43 @@ # CONFIG_MAC_PARTITION is not set # +# Native Language Support +# +CONFIG_NLS=y +# CONFIG_NLS_CODEPAGE_437 is not set +# 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_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Watchdog +# +# CONFIG_SOFT_WATCHDOG is not set + +# # Kernel hacking # # CONFIG_PROFILE is not set +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.1.78/linux/arch/sparc/kernel/Makefile Tue May 13 22:41:03 1997 +++ linux/arch/sparc/kernel/Makefile Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $ +# $Id: Makefile,v 1.41 1997/11/19 15:11:59 jj Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -31,7 +31,7 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o +IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \ process.o signal.o ioport.o setup.o idprom.o \ sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \ diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.1.78/linux/arch/sparc/kernel/entry.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/entry.S Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.138 1997/04/15 09:00:50 davem Exp $ +/* $Id: entry.S,v 1.142 1998/01/07 06:33:47 baccala Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -92,8 +92,8 @@ /* Load new kgdb register set. */ LOAD_KGDB_GLOBALS(sp) LOAD_KGDB_INS(sp) - LOAD_KGDB_SREGS(sp, l0, l2) - wr %l0, 0x0, %y + LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) + wr %l4, 0x0, %y sethi %hi(in_trap_handler), %l4 ld [%lo(in_trap_handler) + %l4], %l5 @@ -108,7 +108,7 @@ STORE_PT_INS(sp) STORE_PT_GLOBALS(sp) STORE_PT_YREG(sp, g2) - STORE_PT_PRIV(sp, l1, l2, l3) + STORE_PT_PRIV(sp, l0, l1, l2) RESTORE_ALL @@ -283,7 +283,7 @@ */ .align 4 - .globl real_irq_entry + .globl real_irq_entry, patch_handler_irq real_irq_entry: SAVE_ALL @@ -299,6 +299,7 @@ wr %g2, PSR_ET, %psr WRITE_PAUSE mov %l7, %o0 ! irq level +patch_handler_irq: call C_LABEL(handler_irq) add %sp, REGWIN_SZ, %o1 ! pt_regs ptr wr %l0, PSR_ET, %psr @@ -1109,7 +1110,7 @@ call C_LABEL(do_ptrace) add %sp, REGWIN_SZ, %o0 - ld [%curptr + 0x14], %l5 + ld [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 be 1f nop @@ -1143,7 +1144,7 @@ call C_LABEL(do_sigpause) add %sp, REGWIN_SZ, %o1 - ld [%curptr + 0x14], %l5 + ld [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 be 1f nop @@ -1161,7 +1162,26 @@ call C_LABEL(do_sigsuspend) add %sp, REGWIN_SZ, %o0 - ld [%curptr + 0x14], %l5 + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be 1f + nop + + call C_LABEL(syscall_trace) + nop + +1: + /* We are returning to a signal handler. */ + RESTORE_ALL + + .align 4 + .globl C_LABEL(sys_rt_sigsuspend) +C_LABEL(sys_rt_sigsuspend): + /* Note: %o0, %o1 already have correct value... */ + call C_LABEL(do_rt_sigsuspend) + add %sp, REGWIN_SZ, %o2 + + ld [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 be 1f nop @@ -1179,7 +1199,7 @@ call C_LABEL(do_sigreturn) add %sp, REGWIN_SZ, %o0 - ld [%curptr + 0x14], %l5 + ld [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 be 1f nop @@ -1193,6 +1213,24 @@ */ RESTORE_ALL + .align 4 + .globl C_LABEL(sys_rt_sigreturn) +C_LABEL(sys_rt_sigreturn): + call C_LABEL(do_rt_sigreturn) + add %sp, REGWIN_SZ, %o0 + + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be 1f + nop + + call C_LABEL(syscall_trace) + nop + +1: + /* We are returning to a signal handler. */ + RESTORE_ALL + /* Now that we have a real sys_clone, sys_fork() is * implemented in terms of it. Our _real_ implementation * of SunOS vfork() will use sys_clone() instead. @@ -1301,7 +1339,7 @@ mov %i1, %o1 mov %i2, %o2 - ld [%curptr + 0x14], %l5 + ld [%curptr + AOFF_task_flags], %l5 mov %i3, %o3 andcc %l5, 0x20, %g0 mov %i4, %o4 @@ -1315,7 +1353,7 @@ .globl C_LABEL(ret_sys_call) C_LABEL(ret_sys_call): - ld [%curptr + 0x14], %l6 + ld [%curptr + AOFF_task_flags], %l6 cmp %o0, -ENOIOCTLCMD ld [%sp + REGWIN_SZ + PT_PSR], %g3 set PSR_C, %g2 diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v2.1.78/linux/arch/sparc/kernel/head.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc/kernel/head.S Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.83 1997/08/28 11:10:39 jj Exp $ +/* $Id: head.S,v 1.84 1997/11/19 15:12:01 jj Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -843,7 +843,7 @@ cmp %l1, 'm' ! Test for sun4d, sun4e ? be sun4m_init cmp %l1, 'd' ! Let us see how the beast will die - be sun4m_init + be sun4d_init nop /* Jump into mmu context zero. */ @@ -852,6 +852,17 @@ b sun4c_continue_boot nop + +sun4d_init: + /* Need to patch call to handler_irq */ + set C_LABEL(patch_handler_irq), %g4 + set C_LABEL(sun4d_handler_irq), %g5 + sethi %hi(0x40000000), %g3 ! call + sub %g5, %g4, %g5 + srl %g5, 2, %g5 + or %g5, %g3, %g5 + st %g5, [%g4] + /* Fall through to sun4m_init */ sun4m_init: /* XXX Fucking Cypress... */ diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.1.78/linux/arch/sparc/kernel/irq.c Thu May 15 16:48:01 1997 +++ linux/arch/sparc/kernel/irq.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.75 1997/05/08 20:57:37 davem Exp $ +/* $Id: irq.c,v 1.77 1997/11/19 15:33:05 jj Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -101,10 +101,10 @@ * */ #define MAX_STATIC_ALLOC 4 -static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; -static int static_irq_count = 0; +struct irqaction static_irqaction[MAX_STATIC_ALLOC]; +int static_irq_count = 0; -static struct irqaction *irq_action[NR_IRQS+1] = { +struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; @@ -114,6 +114,11 @@ int i, len = 0; struct irqaction * action; + if (sparc_cpu_model == sun4d) { + extern int sun4d_get_irq_list(char *); + + return sun4d_get_irq_list(buf); + } for (i = 0 ; i < (NR_IRQS+1) ; i++) { action = *(i + irq_action); if (!action) @@ -242,6 +247,11 @@ unsigned long flags; unsigned int cpu_irq; + if (sparc_cpu_model == sun4d) { + extern void sun4d_free_irq(unsigned int, void *); + + return sun4d_free_irq(irq, dev_id); + } cpu_irq = irq & NR_IRQS; action = *(cpu_irq + irq_action); if (cpu_irq > 14) { /* 14 irq levels on the sparc */ @@ -531,29 +541,28 @@ void handler_irq(int irq, struct pt_regs * regs) { struct irqaction * action; - unsigned int cpu_irq = irq & NR_IRQS; int cpu = smp_processor_id(); #ifdef __SMP__ extern void smp_irq_rotate(int cpu); #endif - disable_pil_irq(cpu_irq); + disable_pil_irq(irq); #ifdef __SMP__ /* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */ if(irq < 10) smp_irq_rotate(cpu); #endif - irq_enter(cpu, cpu_irq, regs); - action = *(cpu_irq + irq_action); - kstat.interrupts[cpu_irq]++; + irq_enter(cpu, irq, regs); + action = *(irq + irq_action); + kstat.interrupts[irq]++; do { if (!action || !action->handler) unexpected_irq(irq, 0, regs); action->handler(irq, action->dev_id, regs); action = action->next; } while (action); - irq_exit(cpu, cpu_irq); - enable_pil_irq(cpu_irq); + irq_exit(cpu, irq); + enable_pil_irq(irq); } #ifdef CONFIG_BLK_DEV_FD @@ -669,12 +678,22 @@ unsigned long flags; unsigned int cpu_irq; + if (sparc_cpu_model == sun4d) { + extern int sun4d_request_irq(unsigned int, + void (*)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); + return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); + } cpu_irq = irq & NR_IRQS; if(cpu_irq > 14) return -EINVAL; if (!handler) return -EINVAL; + + if (irqflags & SA_DCOOKIE) + dev_id = ((struct devid_cookie *)dev_id)->real_dev_id; + action = *(cpu_irq + irq_action); if (action) { if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { @@ -751,6 +770,7 @@ { extern void sun4c_init_IRQ( void ); extern void sun4m_init_IRQ( void ); + extern void sun4d_init_IRQ( void ); switch(sparc_cpu_model) { case sun4c: @@ -759,6 +779,10 @@ case sun4m: sun4m_init_IRQ(); + break; + + case sun4d: + sun4d_init_IRQ(); break; case ap1000: diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/muldiv.c linux/arch/sparc/kernel/muldiv.c --- v2.1.78/linux/arch/sparc/kernel/muldiv.c Mon Apr 14 16:28:07 1997 +++ linux/arch/sparc/kernel/muldiv.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: muldiv.c,v 1.4 1997/04/11 00:42:08 davem Exp $ +/* $Id: muldiv.c,v 1.5 1997/12/15 20:07:20 ecd Exp $ * muldiv.c: Hardware multiply/division illegal instruction trap * for sun4c/sun4 (which do not have those instructions) * @@ -69,18 +69,23 @@ ret; \ }) -static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) +static inline int +store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs) { struct reg_window *win; - if(!reg) - return NULL; - else if(reg < 16) - return ®s->u_regs[reg]; - win = (struct reg_window *) regs->u_regs[UREG_FP]; - return &win->locals[reg - 16]; + if (!reg) + return 0; + if (reg < 16) { + regs->u_regs[reg] = result; + return 0; + } else { + /* need to use put_user() in this case: */ + win = (struct reg_window *)regs->u_regs[UREG_FP]; + return (put_user(result, &win->locals[reg - 16])); + } } - + extern void handle_hw_divzero (struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr); @@ -90,7 +95,6 @@ unsigned int insn; int inst; unsigned int rs1, rs2, rdv; - unsigned long *rd; if (!pc) return -1; /* This happens to often, I think */ if (get_user (insn, (unsigned int *)pc)) return -1; @@ -109,7 +113,6 @@ rs2 = fetch_reg(rs2, regs); } rs1 = fetch_reg(rs1, regs); - rd = fetch_reg_addr(rdv, regs); switch (inst) { case 10: /* umul */ #ifdef DEBUG_MULDIV @@ -127,9 +130,8 @@ #ifdef DEBUG_MULDIV printk ("0x%x%08x\n", rs2, rs1); #endif - if (rd) { - if (put_user (rs1, rd)) return -1; - } + if (store_reg(rs1, rdv, regs)) + return -1; regs->y = rs2; break; case 11: /* smul */ @@ -148,9 +150,8 @@ #ifdef DEBUG_MULDIV printk ("0x%x%08x\n", rs2, rs1); #endif - if (rd) { - if (put_user (rs1, rd)) return -1; - } + if (store_reg(rs1, rdv, regs)) + return -1; regs->y = rs2; break; case 14: /* udiv */ @@ -179,8 +180,8 @@ #ifdef DEBUG_MULDIV printk ("0x%x\n", rs1); #endif - if (rd) - if (put_user (rs1, rd)) return -1; + if (store_reg(rs1, rdv, regs)) + return -1; break; case 15: /* sdiv */ #ifdef DEBUG_MULDIV @@ -208,8 +209,8 @@ #ifdef DEBUG_MULDIV printk ("0x%x\n", rs1); #endif - if (rd) - if (put_user (rs1, rd)) return -1; + if (store_reg(rs1, rdv, regs)) + return -1; break; } if (is_foocc (insn)) { diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.1.78/linux/arch/sparc/kernel/process.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc/kernel/process.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.100 1997/08/10 04:49:23 davem Exp $ +/* $Id: process.c,v 1.102 1997/12/01 03:36:31 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -120,7 +120,7 @@ } /* endless idle loop with no priority at all */ current->counter = -100; - if(!smp_commenced || resched_needed()) + if(!smp_commenced || need_resched) schedule(); } } @@ -197,7 +197,9 @@ rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } +#ifdef __SMP__ static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED; +#endif void show_backtrace(void) { diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.1.78/linux/arch/sparc/kernel/ptrace.c Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/kernel/ptrace.c Mon Jan 12 15:15:43 1998 @@ -799,7 +799,7 @@ addr = 1; case PTRACE_CONT: { /* restart after signal. */ - if ((unsigned long) data > NSIG) { + if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); goto out; } @@ -851,7 +851,7 @@ } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ - if ((unsigned long) data > NSIG) { + if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); goto out; } @@ -898,9 +898,7 @@ current->pid, current->exit_code); #endif if (current->exit_code) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= (1 << (current->exit_code - 1)); - spin_unlock_irq(¤t->sigmask_lock); + send_sig (current->exit_code, current, 1); + current->exit_code = 0; } - current->exit_code = 0; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v2.1.78/linux/arch/sparc/kernel/rtrap.S Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/kernel/rtrap.S Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.47 1997/08/10 04:49:24 davem Exp $ +/* $Id: rtrap.S,v 1.49 1997/12/14 23:24:24 ecd Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -65,27 +65,24 @@ wr %t_psr, 0x0, %psr b ret_trap_kernel - mov 1, %o0 + nop 1: - ld [%curptr + AOFF_task_processor], %o1 ld [%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2 - sll %o0, %o1, %o0 - - andcc %g2, %o0, %g0 + orcc %g2, %g0, %g0 be signal_p - nop + ld [%curptr + AOFF_task_sigpending], %g2 call C_LABEL(schedule) nop + ld [%curptr + AOFF_task_sigpending], %g2 signal_p: - ld [%curptr + AOFF_task_signal], %g2 - ld [%curptr + AOFF_task_blocked], %o0 - andncc %g2, %o0, %g0 - be,a ret_trap_continue + cmp %g2, 0 + bz,a ret_trap_continue ld [%sp + REGWIN_SZ + PT_PSR], %t_psr + clr %o0 mov %l5, %o2 mov %l6, %o3 call C_LABEL(do_signal) @@ -110,7 +107,8 @@ call C_LABEL(try_to_clear_window_buffer) add %sp, REGWIN_SZ, %o0 - b,a signal_p + b signal_p + ld [%curptr + AOFF_task_sigpending], %g2 ret_trap_nobufwins: /* Load up the user's out registers so we can pull @@ -179,7 +177,8 @@ call C_LABEL(do_memaccess_unaligned) nop - b,a signal_p + b signal_p + ld [%curptr + AOFF_task_sigpending], %g2 ret_trap_kernel: /* Will the rett land us in the invalid window? */ @@ -228,7 +227,8 @@ call C_LABEL(window_ret_fault) add %sp, REGWIN_SZ, %o0 - b,a signal_p + b signal_p + ld [%curptr + AOFF_task_sigpending], %g2 .globl C_LABEL(sun4c_rett_stackchk) C_LABEL(sun4c_rett_stackchk): diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.1.78/linux/arch/sparc/kernel/setup.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc/kernel/setup.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.85 1997/05/27 06:45:54 davem Exp $ +/* $Id: setup.c,v 1.87 1997/12/18 02:42:42 ecd Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -118,7 +119,9 @@ unsigned int boot_flags; #define BOOTME_DEBUG 0x1 #define BOOTME_SINGLE 0x2 -#define BOOTME_KGDB 0x4 +#define BOOTME_KGDBA 0x4 +#define BOOTME_KGDBB 0x8 +#define BOOTME_KGDB 0xc #ifdef CONFIG_SUN_CONSOLE extern char *console_fb_path; @@ -188,15 +191,14 @@ process_switch(*commands++); } else if (strlen(commands) >= 9 && !strncmp(commands, "kgdb=tty", 8)) { - boot_flags |= BOOTME_KGDB; switch (commands[8]) { #ifdef CONFIG_SUN_SERIAL case 'a': - rs_kgdb_hook(0); + boot_flags |= BOOTME_KGDBA; prom_printf("KGDB: Using serial line /dev/ttya.\n"); break; case 'b': - rs_kgdb_hook(1); + boot_flags |= BOOTME_KGDBB; prom_printf("KGDB: Using serial line /dev/ttyb.\n"); break; #endif @@ -207,7 +209,6 @@ #endif default: printk("KGDB: Unknown tty line.\n"); - boot_flags &= ~BOOTME_KGDB; break; } commands += 9; @@ -273,8 +274,6 @@ extern int root_mountflags; -extern void register_console(void (*proc)(const char *)); - char saved_command_line[256]; char reboot_command[256]; enum sparc_cpu sparc_cpu_model; @@ -283,6 +282,16 @@ static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } }; +static void prom_cons_write(struct console *con, const char *str, unsigned count) +{ + while (count--) + prom_printf("%c", *str++); +} + +static struct console prom_console = { + "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0 +}; + __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { @@ -335,7 +344,7 @@ printk("SUN4U\n"); break; case ap1000: - register_console((void (*) (const char *))prom_printf); + register_console(&prom_console); printk("AP1000\n"); packed = 1; break; @@ -345,16 +354,6 @@ }; boot_flags_init(*cmdline_p); - if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && - ((*(short *)linux_dbvec) != -1)) { - printk("Booted under KADB. Syncing trap table.\n"); - (*(linux_dbvec->teach_debugger))(); - } - if((boot_flags & BOOTME_KGDB)) { - set_debug_traps(); - prom_printf ("Breakpoint!\n"); - breakpoint(); - } idprom_init(); load_mmu(); @@ -410,6 +409,56 @@ } not_relevant: +#ifdef CONFIG_SUN_SERIAL + *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ +#endif + { + extern int serial_console; /* in console.c, of course */ +#if !CONFIG_SUN_SERIAL + serial_console = 0; +#else + switch (console_fb) { + case 0: /* Let get our io devices from prom */ + { + int idev = prom_query_input_device(); + int odev = prom_query_output_device(); + if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { + serial_console = 0; + } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { + serial_console = 1; + } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { + serial_console = 2; + } else { + prom_printf("Inconsistent console\n"); + prom_halt(); + } + } + break; + case 1: serial_console = 0; break; /* Force one of the framebuffers as console */ + case 2: serial_console = 1; break; /* Force ttya as console */ + case 3: serial_console = 2; break; /* Force ttyb as console */ + } +#endif + } + + if ((boot_flags & BOOTME_KGDBA)) { + rs_kgdb_hook(0); + } + if ((boot_flags & BOOTME_KGDBB)) { + rs_kgdb_hook(1); + } + + if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && + ((*(short *)linux_dbvec) != -1)) { + printk("Booted under KADB. Syncing trap table.\n"); + (*(linux_dbvec->teach_debugger))(); + } + if((boot_flags & BOOTME_KGDB)) { + set_debug_traps(); + prom_printf ("Breakpoint!\n"); + breakpoint(); + } + if (!root_flags) root_mountflags &= ~MS_RDONLY; ROOT_DEV = to_kdev_t(root_dev); @@ -443,37 +492,6 @@ init_task.mm->context = (unsigned long) NO_CONTEXT; init_task.tss.kregs = &fake_swapper_regs; -#ifdef CONFIG_SUN_SERIAL - *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ -#endif - { - extern int serial_console; /* in console.c, of course */ -#if !CONFIG_SUN_SERIAL - serial_console = 0; -#else - switch (console_fb) { - case 0: /* Let get our io devices from prom */ - { - int idev = prom_query_input_device(); - int odev = prom_query_output_device(); - if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { - serial_console = 0; - } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { - serial_console = 1; - } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { - serial_console = 2; - } else { - prom_printf("Inconsistent console\n"); - prom_halt(); - } - } - break; - case 1: serial_console = 0; break; /* Force one of the framebuffers as console */ - case 2: serial_console = 1; break; /* Force ttya as console */ - case 3: serial_console = 2; break; /* Force ttyb as console */ - } -#endif - } } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.1.78/linux/arch/sparc/kernel/signal.c Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/kernel/signal.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.75 1997/08/05 19:19:26 davem Exp $ +/* $Id: signal.c,v 1.77 1997/12/22 03:06:32 ecd Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -24,9 +24,7 @@ #include #include -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); @@ -35,7 +33,7 @@ void *fpqueue, unsigned long *fpqdepth); extern void fpload(unsigned long *fpregs, unsigned long *fsr); -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_o0, int ret_from_syscall); /* This turned off for production... */ @@ -56,12 +54,13 @@ * ---------------------------------- <-- New %sp */ struct signal_sframe { - struct reg_window sig_window; - int sig_num; - int sig_code; - struct sigcontext *sig_scptr; - int sig_address; - struct sigcontext sig_context; + struct reg_window sig_window; + int sig_num; + int sig_code; + struct sigcontext *sig_scptr; + int sig_address; + struct sigcontext sig_context; + unsigned int extramask[_NSIG_WORDS - 1]; }; /* @@ -75,6 +74,7 @@ __siginfo_t info; __siginfo_fpu_t *fpu_save; unsigned long insns [2] __attribute__ ((aligned (8))); + unsigned int extramask[_NSIG_WORDS - 1]; __siginfo_fpu_t fpu_state; }; @@ -86,13 +86,15 @@ * atomically swap in the new signal mask, and wait for a signal. * This is really tricky on the Sparc, watch out... */ -asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs) +asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs) { - unsigned long mask; + sigset_t saveset; + set &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, set); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->pc = regs->npc; @@ -112,7 +114,7 @@ */ regs->psr |= PSR_C; regs->u_regs[UREG_I0] = EINTR; - if (do_signal(mask, regs, 0, 0)) + if (do_signal(&saveset, regs, 0, 0)) return; } } @@ -127,6 +129,52 @@ _sigpause_common(regs->u_regs[UREG_I0], regs); } +asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, + struct pt_regs *regs) +{ + sigset_t oldset, set; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) { + regs->psr |= PSR_C; + regs->u_regs[UREG_I0] = EINVAL; + return; + } + + if (copy_from_user(&set, uset, sizeof(set))) { + regs->psr |= PSR_C; + regs->u_regs[UREG_I0] = EFAULT; + return; + } + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->pc = regs->npc; + regs->npc += 4; + + /* Condition codes and return value where set here for sigpause, + * and so got used by setup_frame, which again causes sigreturn() + * to return -EINTR. + */ + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + /* + * Return -EINTR and set condition code here, + * so the interrupted system call actually returns + * these. + */ + regs->psr |= PSR_C; + regs->u_regs[UREG_I0] = EINTR; + if (do_signal(&oldset, regs, 0, 0)) + return; + } +} static inline void restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) @@ -154,11 +202,12 @@ (sizeof(unsigned long *)))*16)); } -void do_new_sigreturn (struct pt_regs *regs) +static inline void do_new_sigreturn (struct pt_regs *regs) { struct new_signal_frame *sf; - unsigned long up_psr, pc, npc, mask; - + unsigned long up_psr, pc, npc; + sigset_t set; + sf = (struct new_signal_frame *) regs->u_regs [UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ @@ -173,7 +222,7 @@ if ((pc | npc) & 3) goto segv_and_exit; - + /* 2. Restore the state */ up_psr = regs->psr; copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)); @@ -181,28 +230,36 @@ /* User can only change condition codes and FPU enabling in %psr. */ regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | (regs->psr & (PSR_ICC | PSR_EF)); - + if (sf->fpu_save) restore_fpu_state(regs, sf->fpu_save); /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ - __get_user(mask, &sf->info.si_mask); - current->blocked = (mask & _BLOCKABLE); + if (__get_user(set.sig[0], &sf->info.si_mask) || + copy_from_user(&set.sig[1], &sf->extramask, + (_NSIG_WORDS-1) * sizeof(unsigned int))) + goto segv_and_exit; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); return; segv_and_exit: /* Ugh, we need to grab master lock in these rare cases ;-( */ lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); } asmlinkage void do_sigreturn(struct pt_regs *regs) { struct sigcontext *scptr; - unsigned long pc, npc, psr, mask; + unsigned long pc, npc, psr; + sigset_t set; synchronize_user_stack(); @@ -225,8 +282,17 @@ /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ - __get_user(mask, &scptr->sigc_mask); - current->blocked = (mask & _BLOCKABLE); + if (__get_user(set.sig[0], &scptr->sigc_mask) || + /* Note that scptr + 1 points to extramask */ + copy_from_user(&set.sig[1], scptr + 1, + (_NSIG_WORDS - 1) * sizeof(unsigned int))) + goto segv_and_exit; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); __get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack); current->tss.sstk_info.cur_status &= 1; @@ -248,11 +314,15 @@ /* Ugh, we need to grab master lock in these rare cases ;-( */ lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); +} + +asmlinkage void do_rt_sigreturn(struct pt_regs *regs) +{ + printk("XXX: FIXME: write do_rt_sigreturn\n"); } /* Checks if the fp is valid */ -int invalid_frame_pointer (void *fp, int fplen) +static inline int invalid_frame_pointer (void *fp, int fplen) { if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen) || @@ -263,8 +333,9 @@ return 0; } -static void setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, - struct pt_regs *regs, int signr, unsigned long oldmask) +static inline void +setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, + struct pt_regs *regs, int signr, sigset_t *oldset) { struct signal_sframe *sframep; struct sigcontext *sc; @@ -291,7 +362,9 @@ /* We've already made sure frame pointer isn't in kernel space... */ __put_user(old_status, &sc->sigc_onstack); - __put_user(oldmask, &sc->sigc_mask); + __put_user(oldset->sig[0], &sc->sigc_mask); + __copy_to_user(sframep->extramask, &oldset->sig[1], + (_NSIG_WORDS - 1) * sizeof(unsigned int)); __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); __put_user(pc, &sc->sigc_pc); __put_user(npc, &sc->sigc_npc); @@ -334,7 +407,6 @@ /* Ugh, we need to grab master lock in these rare cases ;-( */ lock_kernel(); do_exit(SIGILL); - unlock_kernel(); } @@ -369,8 +441,9 @@ current->used_math = 0; } -static void new_setup_frame(struct sigaction *sa, struct pt_regs *regs, - int signo, unsigned long oldmask) +static inline void +new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct new_signal_frame *sf; int sigframe_size; @@ -403,39 +476,51 @@ sf->fpu_save = NULL; } - __put_user(oldmask, &sf->info.si_mask); + __put_user(oldset->sig[0], &sf->info.si_mask); + __copy_to_user(sf->extramask, &oldset->sig[1], + (_NSIG_WORDS - 1) * sizeof(unsigned int)); copy_to_user(sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window)); - /* 3. return to kernel instructions */ - __put_user(0x821020d8, &sf->insns [0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02010, &sf->insns [1]); /* t 0x10 */ - - /* 4. signal handler back-trampoline and parameters */ + /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; - regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); - /* 5. signal handler */ - regs->pc = (unsigned long) sa->sa_handler; + /* 4. signal handler */ + regs->pc = (unsigned long) ka->sa.sa_handler; regs->npc = (regs->pc + 4); - /* Flush instruction space. */ - flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); + /* 5. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); + + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + + /* Flush instruction space. */ + flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); + } return; sigill_and_return: lock_kernel(); do_exit(SIGILL); - unlock_kernel(); } +static inline void +new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset, siginfo_t *info) +{ + printk("XXX: FIXME: new_setup_rt_frame unimplemented\n"); +} /* Setup a Solaris stack frame */ static inline void setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, - struct pt_regs *regs, int signr, unsigned long oldmask) + struct pt_regs *regs, int signr, sigset_t *oldset) { svr4_signal_frame_t *sfp; svr4_gregset_t *gr; @@ -443,6 +528,7 @@ svr4_mcontext_t *mc; svr4_gwindows_t *gw; svr4_ucontext_t *uc; + svr4_sigset_t setv; int window = 0; synchronize_user_stack(); @@ -470,7 +556,14 @@ * sc->sigc_onstack = old_status; * anyways, it does not look like it is used for anything at all. */ - __put_user(oldmask, &uc->sigmask.sigbits [0]); + setv.sigbits[0] = oldset->sig[0]; + setv.sigbits[1] = oldset->sig[1]; + if (_NSIG_WORDS >= 4) { + setv.sigbits[2] = oldset->sig[2]; + setv.sigbits[3] = oldset->sig[3]; + __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + } else + __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); /* Store registers */ __put_user(regs->pc, &((*gr) [SVR4_PC])); @@ -547,13 +640,13 @@ sigill_and_return: lock_kernel(); do_exit(SIGILL); - unlock_kernel(); } asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) { svr4_gregset_t *gr; svr4_mcontext_t *mc; + svr4_sigset_t setv; synchronize_user_stack(); @@ -566,9 +659,15 @@ /* Setup convenience variables */ mc = &uc->mcontext; gr = &mc->greg; - - /* We only have < 32 signals, fill the first slot only */ - __put_user(current->blocked, &uc->sigmask.sigbits [0]); + + setv.sigbits[0] = current->blocked.sig[0]; + setv.sigbits[1] = current->blocked.sig[1]; + if (_NSIG_WORDS >= 4) { + setv.sigbits[2] = current->blocked.sig[2]; + setv.sigbits[3] = current->blocked.sig[3]; + __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + } else + __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); /* Store registers */ __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]); @@ -593,8 +692,6 @@ sigsegv_and_return: lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); - return -EFAULT; } /* Set the context for a svr4 application, this is Solaris way to sigreturn */ @@ -602,7 +699,9 @@ { struct thread_struct *tp = ¤t->tss; svr4_gregset_t *gr; - unsigned long pc, npc, psr, mask; + unsigned long pc, npc, psr; + sigset_t set; + svr4_sigset_t setv; /* Fixme: restore windows, or is this already taken care of in * svr4_setup_frame when sync_user_windows is done? @@ -633,8 +732,19 @@ /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ - __get_user(mask, &c->sigmask.sigbits [0]); - current->blocked = (mask & _BLOCKABLE); + if (__copy_from_user(&setv, &c->sigmask, sizeof(svr4_sigset_t))) + goto sigsegv_and_return; + set.sig[0] = setv.sigbits[0]; + set.sig[1] = setv.sigbits[1]; + if (_NSIG_WORDS >= 4) { + set.sig[2] = setv.sigbits[2]; + set.sig[3] = setv.sigbits[3]; + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); regs->pc = pc; regs->npc = npc | 1; __get_user(regs->y, &((*gr) [SVR4_Y])); @@ -650,27 +760,29 @@ sigsegv_and_return: lock_kernel(); do_exit(SIGSEGV); - unlock_kernel(); - return -EFAULT; } -static inline void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs, - int svr4_signal) +static inline void +handle_signal(unsigned long signr, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, + int svr4_signal) { - if(svr4_signal) - setup_svr4_frame(sa, regs->pc, regs->npc, regs, signr, oldmask); + if (svr4_signal) + setup_svr4_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset); else { - if (current->tss.new_signal) - new_setup_frame (sa, regs, signr, oldmask); + if (ka->sa.sa_flags & SA_SIGINFO) + new_setup_rt_frame(ka, regs, signr, oldset, info); + else if (current->tss.new_signal) + new_setup_frame (ka, regs, signr, oldset); else - setup_frame(sa, regs->pc, regs->npc, regs, signr, oldmask); + setup_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset); } - if(sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) { + if(ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + if(!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sigmask_lock); - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked, signr); spin_unlock_irq(¤t->sigmask_lock); } } @@ -699,22 +811,25 @@ * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) { - unsigned long signr, mask = ~current->blocked; - struct sigaction *sa; + unsigned long signr; + struct k_sigaction *ka; + siginfo_t info; + int svr4_signal = current->personality == PER_SVR4; - - while ((signr = current->signal & mask) != 0) { - signr = ffz(~signr); + if (!oldset) + oldset = ¤t->blocked; + + for (;;) { spin_lock_irq(¤t->sigmask_lock); - current->signal &= ~(1 << signr); + signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); - sa = current->sig->action + signr; - signr++; + if (!signr) break; + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; @@ -729,15 +844,26 @@ current->exit_code = 0; if (signr == SIGSTOP) continue; - if (_S(signr) & current->blocked) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr); - spin_unlock_irq(¤t->sigmask_lock); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if(sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + + if(ka->sa.sa_handler == SIG_IGN) { if(signr != SIGCHLD) continue; @@ -750,7 +876,9 @@ ; continue; } - if(sa->sa_handler == SIG_DFL) { + if(ka->sa.sa_handler == SIG_DFL) { + unsigned long exit_code = signr; + if(current->pid == 1) continue; switch(signr) { @@ -758,8 +886,9 @@ continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: - /* The operations performed by is_orphaned_pgrp() - * are protected by the tasklist_lock. + /* The operations performed by + * is_orphaned_pgrp() are protected by + * the tasklist_lock. */ if (is_orphaned_pgrp(current->pgrp)) continue; @@ -771,7 +900,7 @@ current->exit_code = signr; /* notify_parent() is SMP safe */ - if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); @@ -782,7 +911,7 @@ if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); if(current->binfmt->core_dump(signr, regs)) - signr |= 0x80; + exit_code |= 0x80; unlock_kernel(); } #ifdef DEBUG_SIGNALS @@ -792,20 +921,16 @@ #endif /* fall through */ default: - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); - + lock_kernel(); + sigaddset(¤t->signal, signr); current->flags |= PF_SIGNALED; - - lock_kernel(); /* 8-( */ - do_exit(signr); - unlock_kernel(); + do_exit(exit_code); + /* NOT REACHED */ } } if(restart_syscall) - syscall_restart(orig_i0, regs, sa); - handle_signal(signr, sa, oldmask, regs, svr4_signal); + syscall_restart(orig_i0, regs, &ka->sa); + handle_signal(signr, ka, &info, oldset, regs, svr4_signal); return 1; } if(restart_syscall && diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.1.78/linux/arch/sparc/kernel/smp.c Mon Aug 18 18:19:44 1997 +++ linux/arch/sparc/kernel/smp.c Mon Jan 12 15:15:43 1998 @@ -558,7 +558,7 @@ /* Reschedule call back. */ void smp_reschedule_irq(void) { - resched_force(); + need_resched = 1; } /* Running cross calls. */ @@ -583,6 +583,8 @@ /* Protects counters touched during level14 ticker */ spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_PROFILE + /* 32-bit Sparc specific profiling function. */ static inline void sparc_do_profile(unsigned long pc) { @@ -601,6 +603,8 @@ } } +#endif + volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]={0,}; unsigned int prof_multiplier[NR_CPUS]; @@ -614,8 +618,10 @@ int cpu = smp_processor_id(); clear_profile_irq(mid_xlate[cpu]); +#ifdef CONFIG_PROFILE if(!user_mode(regs)) sparc_do_profile(regs->pc); +#endif if(!--prof_counter[cpu]) { int user = user_mode(regs); if(current->pid) { @@ -623,7 +629,7 @@ if(--current->counter < 0) { current->counter = 0; - resched_force(); + need_resched = 1; } spin_lock(&ticker_lock); diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v2.1.78/linux/arch/sparc/kernel/sparc-stub.c Sun Jan 26 02:07:07 1997 +++ linux/arch/sparc/kernel/sparc-stub.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: sparc-stub.c,v 1.20 1997/01/06 06:52:31 davem Exp $ +/* $Id: sparc-stub.c,v 1.22 1998/01/07 06:33:48 baccala Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux @@ -323,7 +323,23 @@ unsigned char ch; while (count-- > 0) { - ch = *mem++; + /* This assembler code is basically: ch = *mem++; + * except that we use the SPARC/Linux exception table + * mechanism (see how "fixup" works in kernel_mna_trap_fault) + * to arrange for a "return 0" upon a memory fault + */ + __asm__( + "1: ldub [%0], %1 + inc %0 + .section .fixup,#alloc,#execinstr + .align 4 + 2: retl + mov 0, %%o0 + .section __ex_table, #alloc + .align 4 + .word 1b, 2b + .text" + : "=r" (mem), "=r" (ch) : "0" (mem)); *buf++ = hexchars[ch >> 4]; *buf++ = hexchars[ch & 0xf]; } @@ -345,7 +361,19 @@ ch = hex(*buf++) << 4; ch |= hex(*buf++); - *mem++ = ch; + /* Assembler code is *mem++ = ch; with return 0 on fault */ + __asm__( + "1: stb %1, [%0] + inc %0 + .section .fixup,#alloc,#execinstr + .align 4 + 2: retl + mov 0, %%o0 + .section __ex_table, #alloc + .align 4 + .word 1b, 2b + .text" + : "=r" (mem) : "r" (ch) , "0" (mem)); } return mem; } @@ -387,13 +415,18 @@ /* In case GDB is started before us, ack any packets (presumably * "$?#xx") sitting there. + * + * I've found this code causes more problems than it solves, + * so that's why it's commented out. GDB seems to work fine + * now starting either before or after the kernel -bwb */ - +#if 0 while((c = getDebugChar()) != '$'); while((c = getDebugChar()) != '#'); c = getDebugChar(); /* eat first csum byte */ c = getDebugChar(); /* eat second csum byte */ putDebugChar('+'); /* ack it */ +#endif initialized = 1; /* connect! */ restore_flags(flags); diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.1.78/linux/arch/sparc/kernel/sparc_ksyms.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc/kernel/sparc_ksyms.c Mon Jan 12 15:15:43 1998 @@ -1,10 +1,12 @@ -/* $Id: sparc_ksyms.c,v 1.60 1997/06/17 13:25:13 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.61 1997/11/19 07:57:44 jj Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) */ +/* Tell string.h we don't want memcpy etc. as cpp defines */ +#define EXPORT_SYMTAB_STROPS #define PROMLIB_INTERNAL #include diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c --- v2.1.78/linux/arch/sparc/kernel/sun4d_irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc/kernel/sun4d_irq.c Mon Jan 12 15:15:43 1998 @@ -0,0 +1,483 @@ +/* $Id: sun4d_irq.c,v 1.3 1997/12/22 16:09:15 jj Exp $ + * arch/sparc/kernel/sun4d_irq.c: + * SS1000/SC2000 interrupt handling. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Heavily based on arch/sparc/kernel/irq.c. + */ + +#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 + +struct sun4d_timer_regs *sun4d_timers; +#define TIMER_IRQ 10 + +#define MAX_STATIC_ALLOC 4 +extern struct irqaction static_irqaction[MAX_STATIC_ALLOC]; +extern int static_irq_count; + +extern struct irqaction *irq_action[]; + +struct sbus_action { + struct irqaction *action; + unsigned char lock; + unsigned char active; + unsigned char disabled; +} *sbus_actions; + +static int pil_to_sbus[] = { + 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, +}; + +static int nsbi; + +int sun4d_get_irq_list(char *buf) +{ + int i, j = 0, k = 0, len = 0, sbusl; + struct irqaction * action; + + for (i = 0 ; i < NR_IRQS ; i++) { + sbusl = pil_to_sbus[i]; + if (!sbusl) { + action = *(i + irq_action); + if (!action) + continue; + } else { + for (j = 0; j < nsbi; j++) { + for (k = 0; k < 4; k++) + if ((action = sbus_actions [(j << 5) + (sbusl << 2) + k].action)) + goto found_it; + } + continue; + } +found_it: len += sprintf(buf+len, "%2d: %8d %c %s", + i, kstat.interrupts[i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + action = action->next; + for (;;) { + for (; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + if (!sbusl) break; + k++; + if (k < 4) + action = sbus_actions [(j << 5) + (sbusl << 2) + k].action; + else { + j++; + if (j == nsbi) break; + k = 0; + action = sbus_actions [(j << 5) + (sbusl << 2)].action; + } + } + len += sprintf(buf+len, "\n"); + } + return len; +} + +void sun4d_free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action, **actionp; + struct irqaction *tmp = NULL; + unsigned long flags; + + if (irq < 15) + actionp = irq + irq_action; + else + actionp = &(sbus_actions[irq - (1 << 5)].action); + action = *actionp; + if (!action) { + printk("Trying to free free IRQ%d\n",irq); + return; + } + if (dev_id) { + for (; action; action = action->next) { + if (action->dev_id == dev_id) + break; + tmp = action; + } + if (!action) { + printk("Trying to free free shared IRQ%d\n",irq); + return; + } + } else if (action->flags & SA_SHIRQ) { + printk("Trying to free shared IRQ%d with NULL device ID\n", irq); + return; + } + if (action->flags & SA_STATIC_ALLOC) + { + /* This interrupt is marked as specially allocated + * so it is a bad idea to free it. + */ + printk("Attempt to free statically allocated IRQ%d (%s)\n", + irq, action->name); + return; + } + + save_and_cli(flags); + if (action && tmp) + tmp->next = action->next; + else + *actionp = action->next; + + kfree_s(action, sizeof(struct irqaction)); + + if (!(*actionp)) + disable_irq(irq); + + restore_flags(flags); +} + +extern void unexpected_irq(int, void *, struct pt_regs *); + +void sun4d_handler_irq(int irq, struct pt_regs * regs) +{ + struct irqaction * action; + int cpu = smp_processor_id(); + /* SBUS IRQ level (1 - 7) */ + int sbusl = pil_to_sbus[irq]; + + /* FIXME: Is this necessary?? */ + cc_get_ipen(); + + cc_set_iclr(1 << irq); + + irq_enter(cpu, irq, regs); + kstat.interrupts[irq]++; + if (!sbusl) { + action = *(irq + irq_action); + if (!action) + unexpected_irq(irq, 0, regs); + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + } else { + int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff; + int lock; + int sbino; + struct sbus_action *actionp; + unsigned mask, slot; + int sbil = (sbusl << 2); + + bw_clear_intr_mask(sbusl, bus_mask); + + /* Loop for each pending SBI */ + for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) + if (bus_mask & 1) { + mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil); + mask &= (0xf << sbil); + actionp = sbus_actions + (sbino << 5) + (sbil); + /* Loop for each pending SBI slot */ + for (slot = (1 << sbil); mask; slot <<= 1, actionp++) + if (mask & slot) { + mask &= ~slot; + action = actionp->action; + __asm__ __volatile__ ("ldstub [%1 + 4], %0" + : "=r" (lock) : "r" (actionp)); + + if (!lock) { + if (!action) + unexpected_irq(irq, 0, regs); + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + actionp->lock = 0; + } else + actionp->active = 1; + release_sbi(SBI2DEVID(sbino), slot); + } + } + } + irq_exit(cpu, irq); +} + +int sun4d_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + struct irqaction *action, *tmp = NULL, **actionp; + unsigned long flags; + int sbusl; + unsigned int *ret = NULL; + struct linux_sbus_device *sdev = NULL; + + if(irq > 14) + return -EINVAL; + + if (!handler) + return -EINVAL; + + if (irqflags & SA_DCOOKIE) { + struct devid_cookie *d = (struct devid_cookie *)dev_id; + + dev_id = d->real_dev_id; + sdev = (struct linux_sbus_device *)d->bus_cookie; + ret = &d->ret_ino; + } + + sbusl = pil_to_sbus[irq]; + if (sbusl && !sdev) { + printk ("Attempt to register SBUS IRQ %d without DCOOKIE\n", irq); + return -EINVAL; + } + if (sbusl) { + actionp = &(sbus_actions[(sdev->my_bus->board << 5) + + (sbusl << 2) + sdev->slot].action); + *ret = ((sdev->my_bus->board + 1) << 5) + + (sbusl << 2) + sdev->slot; + } else + actionp = irq + irq_action; + action = *actionp; + + if (action) { + if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { + for (tmp = action; tmp->next; tmp = tmp->next); + } else { + return -EBUSY; + } + if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) { + printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq); + return -EBUSY; + } + action = NULL; /* Or else! */ + } + + save_and_cli(flags); + + /* If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + if (irqflags & SA_STATIC_ALLOC) + if (static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname); + + if (action == NULL) + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), + GFP_KERNEL); + + if (!action) { + restore_flags(flags); + return -ENOMEM; + } + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + if (tmp) + tmp->next = action; + else + *actionp = action; + + if (ret) irq = *ret; + + if (irq > NR_IRQS) { + struct sbus_action *s = sbus_actions + irq - (1 << 5); + + if (s->disabled) { + s->disabled = 0; + s->active = 0; + s->lock = 0; + } + } + + restore_flags(flags); + return 0; +} + +static void sun4d_disable_irq(unsigned int irq) +{ + struct sbus_action *s; + + if (irq < NR_IRQS) { + /* FIXME */ + printk ("Unable to disable IRQ %d\n", irq); + return; + } + s = sbus_actions + irq - (1 << 5); + + if (s->disabled) return; + s->disabled = 1; + __asm__ __volatile__ (" +1: ldstub [%0 + 4], %%g1 + orcc %%g1, 0, %%g0 + bne 1b" + : : "r" (s) : "g1", "cc"); +} + +static void sun4d_enable_irq(unsigned int irq) +{ + struct sbus_action *s; + struct irqaction *action; + + if (irq < NR_IRQS) + /* FIXME */ + return; + s = sbus_actions + irq - (1 << 5); + + if (!s->disabled) return; + action = s->action; + s->disabled = 0; + while (s->active) { + s->active = 0; + while (action) { + /* FIXME: Hope no sbus intr handler uses regs */ + action->handler(irq, action->dev_id, NULL); + action = action->next; + } + } + s->lock = 0; +} + +#ifdef __SMP__ + +/* +-------+-------------+-----------+------------------------------------+ + * | bcast | devid | sid | levels mask | + * +-------+-------------+-----------+------------------------------------+ + * 31 30 23 22 15 14 0 + */ +#define IGEN_MESSAGE(bcast, devid, sid, levels) \ + (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels)) + +static void sun4d_send_ipi(int cpu, int level) +{ + cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1))); +} + +static void sun4d_clear_ipi(int cpu, int level) +{ +} + +static void sun4d_set_udt(int cpu) +{ +} +#endif + +static void sun4d_clear_clock_irq(void) +{ + volatile unsigned int clear_intr; + clear_intr = sun4d_timers->l10_timer_limit; +} + +static void sun4d_clear_profile_irq(int cpu) +{ + bw_get_prof_limit(cpu); +} + +static void sun4d_load_profile_irq(int cpu, unsigned int limit) +{ + bw_set_prof_limit(cpu, limit); +} + +__initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))) +{ + int irq; + extern struct prom_cpuinfo linux_cpus[NCPUS]; + int cpu; + + /* Map the User Timer registers. */ + sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0, + PAGE_SIZE, "user timer", 0xf, 0x0); + + sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); + master_l10_counter = &sun4d_timers->l10_cur_count; + master_l10_limit = &sun4d_timers->l10_timer_limit; + + irq = request_irq(TIMER_IRQ, + counter_fn, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "timer", NULL); + if (irq) { + prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); + prom_halt(); + } + + /* Enable user timer free run for CPU 0 in BW */ + /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */ + + for(cpu = 0; cpu < NCPUS; cpu++) + sun4d_load_profile_irq(linux_cpus[cpu].mid, 0); +} + +__initfunc(unsigned long sun4d_init_sbi_irq(unsigned long memory_start)) +{ + struct linux_sbus *sbus; + struct sbus_action *s; + int i; + unsigned mask; + + nsbi = 0; + for_each_sbus(sbus) + nsbi++; + memory_start = ((memory_start + 7) & ~7); + sbus_actions = (struct sbus_action *)memory_start; + memory_start += (nsbi * 8 * 4 * sizeof(struct sbus_action)); + memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action))); + for (i = 0, s = sbus_actions; i < nsbi * 8 * 4; i++, s++) { + s->lock = 0xff; + s->disabled = 1; + } + for_each_sbus(sbus) { + /* Get rid of pending irqs from PROM */ + mask = acquire_sbi(sbus->devid, 0xffffffff); + if (mask) { + printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board); + release_sbi(sbus->devid, mask); + } + } + return memory_start; +} + +__initfunc(void sun4d_init_IRQ(void)) +{ + __cli(); + + enable_irq = sun4d_enable_irq; + disable_irq = sun4d_disable_irq; + clear_clock_irq = sun4d_clear_clock_irq; + clear_profile_irq = sun4d_clear_profile_irq; + load_profile_irq = sun4d_load_profile_irq; + init_timers = sun4d_init_timers; +#ifdef __SMP__ + set_cpu_int = (void (*) (int, int))sun4d_send_ipi; + clear_cpu_int = (void (*) (int, int))sun4d_clear_ipi; + set_irq_udt = (void (*) (int))sun4d_set_udt; +#endif + /* Cannot enable interrupts until OBP ticker is disabled. */ +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c --- v2.1.78/linux/arch/sparc/kernel/sun4m_irq.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/sun4m_irq.c Mon Jan 12 15:15:43 1998 @@ -163,7 +163,8 @@ sun4m_interrupts->clear = cpu_pil_to_imask[pil]; } -void sun4m_send_ipi(int cpu, int level) +#ifdef __SMP__ +static void sun4m_send_ipi(int cpu, int level) { unsigned long mask; @@ -171,7 +172,7 @@ sun4m_interrupts->cpu_intregs[cpu].set = mask; } -void sun4m_clear_ipi(int cpu, int level) +static void sun4m_clear_ipi(int cpu, int level) { unsigned long mask; @@ -179,10 +180,11 @@ sun4m_interrupts->cpu_intregs[cpu].clear = mask; } -void sun4m_set_udt(int cpu) +static void sun4m_set_udt(int cpu) { sun4m_interrupts->undirected_target = cpu; } +#endif #define OBIO_INTR 0x20 #define TIMER_IRQ (OBIO_INTR | 10) diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c --- v2.1.78/linux/arch/sparc/kernel/sunos_ioctl.c Mon Mar 17 14:54:21 1997 +++ linux/arch/sparc/kernel/sunos_ioctl.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl.c,v 1.28 1997/02/15 01:17:05 davem Exp $ +/* $Id: sunos_ioctl.c,v 1.29 1997/09/18 10:37:31 rth Exp $ * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -45,8 +45,8 @@ /* First handle an easy compat. case for tty ldisc. */ if(cmd == TIOCSETD) { - int *p, ntty = N_TTY; - int tmp, oldfs; + int *p, ntty = N_TTY, tmp; + mm_segment_t oldfs; p = (int *) arg; ret = -EFAULT; diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.1.78/linux/arch/sparc/kernel/sys_sparc.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/sys_sparc.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.35 1997/04/16 05:56:09 davem Exp $ +/* $Id: sys_sparc.c,v 1.38 1998/01/09 16:42:48 jj Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -248,52 +249,98 @@ unlock_kernel(); } -extern void check_pending(int signum); - asmlinkage int -sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction) +sparc_sigaction (int sig, const struct old_sigaction *act, + struct old_sigaction *oact) { - struct sigaction new_sa, *p; + struct k_sigaction new_ka, old_ka; + int ret; - if(signum < 0) { + if (sig < 0) { current->tss.new_signal = 1; - signum = -signum; + sig = -sig; } - if(signum<1 || signum>32) - return -EINVAL; - p = signum - 1 + current->sig->action; - if(action) { - if(verify_area(VERIFY_READ,action,sizeof(struct sigaction))) + if (act) { + unsigned long mask; + + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - if(copy_from_user(&new_sa, action, sizeof(struct sigaction))) - return -EFAULT; - if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { - if(verify_area(VERIFY_READ, new_sa.sa_handler, 1)) - return -EFAULT; - } + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + new_ka.ka_restorer = NULL; } - if (oldaction) { + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { /* In the clone() case we could copy half consistant * state to the user, however this could sleep and * deadlock us if we held the signal lock on SMP. So for * now I take the easy way out and do no locking. */ - if (copy_to_user(oldaction, p, sizeof(struct sigaction))) - return -EFAULT; + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } - if (action) { - spin_lock_irq(¤t->sig->siglock); - *p = new_sa; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); + return ret; +} + +asmlinkage int +sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, + void *restorer, size_t sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (act) { + new_ka.ka_restorer = restorer; + if (copy_from_user(&new_ka.sa, act, sizeof(*act))) + return -EFAULT; } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) + return -EFAULT; + } + + return ret; +} + +/* Just in case some old old binary calls this. */ +asmlinkage int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +asmlinkage int sys_getdomainname(char *name, int len) +{ + int nlen = strlen(system_utsname.domainname); + + if (nlen < len) + len = nlen; + if(len > __NEW_UTS_LEN) + return -EFAULT; + if(copy_to_user(name, system_utsname.domainname, len)) + return -EFAULT; return 0; } + #ifndef CONFIG_AP1000 /* only AP+ systems have sys_aplib */ diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.1.78/linux/arch/sparc/kernel/sys_sunos.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc/kernel/sys_sunos.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $ +/* $Id: sys_sunos.c,v 1.83 1997/12/14 23:24:28 ecd Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -348,35 +348,28 @@ { return SUNOS_NR_OPEN; } -#define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask) { - unsigned long flags; unsigned long old; - lock_kernel(); - save_and_cli(flags); - old = current->blocked; - current->blocked |= (blk_mask & _BLOCKABLE); - restore_flags(flags); - unlock_kernel(); + spin_lock_irq(¤t->sigmask_lock); + old = current->blocked.sig[0]; + current->blocked.sig[0] |= (blk_mask & _BLOCKABLE); + spin_unlock_irq(¤t->sigmask_lock); return old; } asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask) { - unsigned long flags; unsigned long retval; - lock_kernel(); - save_and_cli(flags); - retval = current->blocked; - current->blocked = newmask & _BLOCKABLE; - restore_flags(flags); - unlock_kernel(); + spin_lock_irq(¤t->sigmask_lock); + retval = current->blocked.sig[0]; + current->blocked.sig[0] = (newmask & _BLOCKABLE); + spin_unlock_irq(¤t->sigmask_lock); return retval; } @@ -430,8 +423,6 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) { struct file * file; - struct dentry * dentry; - struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; @@ -444,14 +435,6 @@ if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; @@ -464,7 +447,7 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(inode, file, &buf, sunos_filldir); + error = file->f_op->readdir(file, &buf, sunos_filldir); if (error < 0) goto out; lastdirent = buf.previous; @@ -520,8 +503,6 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep) { struct file * file; - struct dentry * dentry; - struct inode * inode; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; int error = -EBADF; @@ -534,14 +515,6 @@ if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; @@ -554,7 +527,7 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry); + error = file->f_op->readdir(file, &buf, sunos_filldirentry); if (error < 0) goto out; lastdirent = buf.previous; @@ -1254,58 +1227,47 @@ #define SUNOS_SV_INTERRUPT 2 -extern void check_pending(int signum); - -asmlinkage int sunos_sigaction(int signum, const struct sigaction *action, - struct sigaction *oldaction) +asmlinkage int +sunos_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) { - struct sigaction new_sa, *p; - const int sigaction_size = sizeof (struct sigaction) - sizeof (void *); + struct k_sigaction new_ka, old_ka; + int ret; current->personality |= PER_BSD; - if(signum < 1 || signum > 32) - return -EINVAL; - p = signum - 1 + current->sig->action; + if(act) { + old_sigset_t mask; - if(action) { - if(copy_from_user(&new_sa, action, sigaction_size)) - return -EFAULT; - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - memset(&new_sa, 0, sizeof(struct sigaction)); - if(copy_from_user(&new_sa, action, sigaction_size)) + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags)) return -EFAULT; - if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { - if(verify_area(VERIFY_READ, new_sa.sa_handler, 1)) - return -EFAULT; - } - new_sa.sa_flags ^= SUNOS_SV_INTERRUPT; + __get_user(mask, &act->sa_mask); + new_ka.sa.sa_restorer = NULL; + new_ka.ka_restorer = NULL; + siginitset(&new_ka.sa.sa_mask, mask); + new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; } - if (oldaction) { + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { /* In the clone() case we could copy half consistant * state to the user, however this could sleep and * deadlock us if we held the signal lock on SMP. So for * now I take the easy way out and do no locking. * But then again we don't support SunOS lwp's anyways ;-) */ - if (copy_to_user(oldaction, p, sigaction_size)) + old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags)) return -EFAULT; - - if (oldaction->sa_flags & SA_RESTART) - oldaction->sa_flags &= ~SA_RESTART; - else - oldaction->sa_flags |= SUNOS_SV_INTERRUPT; + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } - if (action) { - spin_lock_irq(¤t->sig->siglock); - *p = new_sa; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); - } - return 0; + return ret; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.1.78/linux/arch/sparc/kernel/systbls.S Wed Sep 24 20:05:46 1997 +++ linux/arch/sparc/kernel/systbls.S Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $ +/* $Id: systbls.S,v 1.68 1997/12/24 17:26:38 ecd Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -30,11 +30,11 @@ .long C_LABEL(sys_setuid), C_LABEL(sys_getuid) /*25*/ .long C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_pause) -/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty) - .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime) +/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup) - .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_profil) + .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid) .long C_LABEL(sys_signal), C_LABEL(sys_geteuid) /*50*/ .long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall) @@ -42,8 +42,8 @@ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink) .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot) .long C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize) - .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_pread) + .long C_LABEL(sys_pwrite), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap) .long C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups) @@ -54,10 +54,10 @@ .long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) -/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) +/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_rt_sigreturn) + .long C_LABEL(sys_rt_sigaction), C_LABEL(sys_rt_sigprocmask) + .long C_LABEL(sys_rt_sigpending), C_LABEL(sys_rt_sigtimedwait) + .long C_LABEL(sys_rt_sigqueueinfo), C_LABEL(sys_rt_sigsuspend) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) @@ -73,13 +73,13 @@ .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit) - .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_prctl) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) /*150*/ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_poll), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs) .long C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setdomainname) + .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) @@ -89,12 +89,12 @@ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_query_module) .long C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module) - .long C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break) - .long C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit) + .long C_LABEL(sys_personality), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask) /*200*/ .long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat) .long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname) + .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo) .long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone) @@ -102,7 +102,7 @@ .long C_LABEL(sys_create_module), C_LABEL(sys_delete_module) .long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush) .long C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid) - .long C_LABEL(sys_setfsgid), C_LABEL(sys_llseek), C_LABEL(sys_time) + .long C_LABEL(sys_setfsgid), C_LABEL(sys_select), C_LABEL(sys_time) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek) /* "We are the Knights of the Forest of Ni!!" */ @@ -125,7 +125,6 @@ .long C_LABEL(sys_fdatasync) .long C_LABEL(sys_nfsservctl) /*255*/ .long C_LABEL(sys_aplib) - .long C_LABEL(sys_prctl) .long C_LABEL(sys_nis_syscall) /* Now the SunOS syscall table. */ @@ -147,7 +146,7 @@ .long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat) .long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup) - .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sys_profil) + .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_getgid) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) /*50*/ .long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys) @@ -220,4 +219,3 @@ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) /*250*/ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib) - .long C_LABEL(sunos_nosys) diff -u --recursive --new-file v2.1.78/linux/arch/sparc/lib/memcpy.S linux/arch/sparc/lib/memcpy.S --- v2.1.78/linux/arch/sparc/lib/memcpy.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/lib/memcpy.S Mon Jan 12 15:15:43 1998 @@ -523,6 +523,15 @@ #endif /* FASTER_REVERSE */ +/* NOTE: This code is executed just for the cases, + where %src (=%o1) & 3 is != 0. + We need to align it to 4. So, for (%src & 3) + 1 we need to do ldub,lduh + 2 lduh + 3 just ldub + so even if it looks weird, the branches + are correct here. -jj + */ 78: /* dword_align */ andcc %o1, 1, %g0 diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile --- v2.1.78/linux/arch/sparc/mm/Makefile Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc/mm/Makefile Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.26 1997/06/24 15:48:06 jj Exp $ +# $Id: Makefile,v 1.27 1997/11/07 15:01:27 jj Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -10,7 +10,7 @@ O_TARGET := mm.o O_OBJS := fault.o init.o sun4c.o srmmu.o hypersparc.o viking.o \ tsunami.o loadmmu.o generic.o asyncd.o extable.o \ - turbosparc.o + turbosparc.o iommu.o io-unit.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c --- v2.1.78/linux/arch/sparc/mm/asyncd.c Thu May 15 16:48:02 1997 +++ linux/arch/sparc/mm/asyncd.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.10 1997/05/15 21:14:24 davem Exp $ +/* $Id: asyncd.c,v 1.11 1997/12/14 23:24:34 ecd Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -239,7 +239,8 @@ current->session = 1; current->pgrp = 1; sprintf(current->comm, "asyncd"); - current->blocked = ~0UL; /* block all signals */ + sigfillset(¤t->blocked); /* block all signals */ + recalc_sigpending(current); /* Give asyncd a realtime priority. */ current->policy = SCHED_FIFO; @@ -259,7 +260,9 @@ save_flags(flags); cli(); while (!async_queue) { - current->signal = 0; + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); interruptible_sleep_on(&asyncd_wait); } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S --- v2.1.78/linux/arch/sparc/mm/hypersparc.S Thu May 29 21:53:04 1997 +++ linux/arch/sparc/mm/hypersparc.S Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: hypersparc.S,v 1.10 1997/05/27 19:29:58 jj Exp $ +/* $Id: hypersparc.S,v 1.12 1997/11/27 15:42:30 jj Exp $ * hypersparc.S: High speed Hypersparc mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -135,8 +135,7 @@ mov SRMMU_CTX_REG, %g7 lda [%g7] ASI_M_MMUREGS, %o3 sta %o0, [%g7] ASI_M_MMUREGS - sethi %hi(PAGE_SIZE), %g7 /* XXX ick, stupid stalls... */ - sub %o2, %g7, %o0 + add %o2, -PAGE_SIZE, %o0 1: or %o0, 0x400, %g7 lda [%g7] ASI_M_FLUSH_PROBE, %g7 @@ -157,10 +156,9 @@ bne 2b sta %g0, [%o2 + %g5] ASI_M_FLUSH_PAGE 3: - sethi %hi(PAGE_SIZE), %g7 cmp %o2, %o1 bne 1b - sub %o2, %g7, %o0 + add %o2, -PAGE_SIZE, %o0 mov SRMMU_FAULT_STATUS, %g5 lda [%g5] ASI_M_MMUREGS, %g0 mov SRMMU_CTX_REG, %g7 @@ -191,10 +189,9 @@ or %o1, 0x400, %o5 lda [%o5] ASI_M_FLUSH_PROBE, %g1 orcc %g0, %g1, %g0 - sethi %hi(PAGE_SIZE), %g7 be 2f add %o4, %o4, %o5 - add %o1, %g7, %o1 + sub %o1, -PAGE_SIZE, %o1 add %o4, %o5, %g1 add %o4, %g1, %g2 add %o4, %g2, %g3 @@ -242,9 +239,8 @@ orcc %g5, 0, %g0 be 2f add %o4, %g1, %g2 - sethi %hi(PAGE_SIZE), %g5 add %o4, %g2, %g3 - add %o0, %g5, %o0 + sub %o0, -PAGE_SIZE, %o0 add %o4, %g3, %g4 add %o4, %g4, %g5 add %o4, %g5, %g7 diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.1.78/linux/arch/sparc/mm/init.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/mm/init.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.49 1997/04/17 21:49:31 jj Exp $ +/* $Id: init.c,v 1.50 1998/01/10 18:19:42 ecd Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -227,9 +227,10 @@ addr = KERNBASE; while(addr < start_mem) { #ifdef CONFIG_BLK_DEV_INITRD - if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) + if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) { mem_map[MAP_NR(addr)].flags &= ~(1< +#include +#include +#include +#include +#include +#include +#include +#include + +#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) + +#define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID) +#define MKIOPTE(phys) ((((phys)>>4) & IOUPTE_PAGE) | IOPERM) + +unsigned long sun4d_dma_base; +unsigned long sun4d_dma_vbase; +unsigned long sun4d_dma_size; +__initfunc(unsigned long +iounit_init(int sbi_node, int io_node, unsigned long memory_start, + unsigned long memory_end, struct linux_sbus *sbus)) +{ + iopte_t *xpt, *xptend; + unsigned long paddr; + struct iounit_struct *iounit; + struct linux_prom_registers iommu_promregs[PROMREG_MAX]; + + memory_start = LONG_ALIGN(memory_start); + iounit = (struct iounit_struct *)memory_start; + memory_start += sizeof(struct iounit_struct); + + prom_getproperty(sbi_node, "reg", (void *) iommu_promregs, + sizeof(iommu_promregs)); + prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3); + xpt = (iopte_t *) + sparc_alloc_io(iommu_promregs[2].phys_addr, 0, (PAGE_SIZE * 16), + "XPT", iommu_promregs[2].which_io, 0x0); + if(!xpt) panic("Cannot map External Page Table."); + + sbus->iommu = (struct iommu_struct *)iounit; + iounit->page_table = xpt; + + /* Initialize new table. */ + paddr = IOUNIT_DMA_BASE - sun4d_dma_base; + for (xptend = xpt + (sun4d_dma_size >> PAGE_SHIFT); + xpt < xptend; paddr++) + *xpt++ = MKIOPTE(paddr); + for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t); + xpt < xptend;) + *xpt++ = 0; + + return memory_start; +} + +static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) +{ + /* Viking MXCC is IO coherent, just need to translate the address to DMA handle */ +#ifdef IOUNIT_DEBUG + if ((((unsigned long) vaddr) & PAGE_MASK) < sun4d_dma_vaddr || + (((unsigned long) vaddr) & PAGE_MASK) + len > sun4d_dma_vbase + sun4d_dma_size) + panic("Using non-DMA memory for iounit_get_scsi_one"); +#endif + return (__u32)(sun4d_dma_base + mmu_v2p((long)vaddr)); +} + +static void iounit_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + /* Viking MXCC is IO coherent, just need to translate the address to DMA handle */ + for (; sz >= 0; sz--) { +#ifdef IOUNIT_DEBUG + unsigned long page = ((unsigned long) sg[sz].addr) & PAGE_MASK; + if (page < sun4d_dma_vbase || page + sg[sz].len > sun4d_dma_vbase + sun4d_dma_size) + panic("Using non-DMA memory for iounit_get_scsi_sgl"); +#endif + sg[sz].dvma_addr = (__u32) (sun4d_dma_base + mmu_v2p((long)sg[sz].addr));; + } +} + +static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus) +{ +} + +static void iounit_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ +} + +#ifdef CONFIG_SBUS +static void iounit_map_dma_area(unsigned long addr, int len) +{ + unsigned long page, end; + pgprot_t dvma_prot; + iopte_t *iopte; + struct linux_sbus *sbus; + + dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); + end = PAGE_ALIGN((addr + len)); + while(addr < end) { + page = get_free_page(GFP_KERNEL); + if(!page) { + prom_printf("alloc_dvma: Cannot get a dvma page\n"); + prom_halt(); + } else { + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + long i; + + pgdp = pgd_offset(init_task.mm, addr); + pmdp = pmd_offset(pgdp, addr); + ptep = pte_offset(pmdp, addr); + + set_pte(ptep, pte_val(mk_pte(page, dvma_prot))); + + i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); + + for_each_sbus(sbus) { + struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; + + iopte = (iopte_t *)(iounit->page_table + i); + *iopte = __iopte(MKIOPTE(mmu_v2p(page))); + } + } + addr += PAGE_SIZE; + } + flush_cache_all(); + flush_tlb_all(); +} +#endif + +static char *iounit_lockarea(char *vaddr, unsigned long len) +{ + return vaddr; +} + +static void iounit_unlockarea(char *vaddr, unsigned long len) +{ +} + +__initfunc(void ld_mmu_iounit(void)) +{ + mmu_lockarea = iounit_lockarea; + mmu_unlockarea = iounit_unlockarea; + + mmu_get_scsi_one = iounit_get_scsi_one; + mmu_get_scsi_sgl = iounit_get_scsi_sgl; + mmu_release_scsi_one = iounit_release_scsi_one; + mmu_release_scsi_sgl = iounit_release_scsi_sgl; + +#ifdef CONFIG_SBUS + mmu_map_dma_area = iounit_map_dma_area; +#endif +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c --- v2.1.78/linux/arch/sparc/mm/iommu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc/mm/iommu.c Mon Jan 12 15:15:43 1998 @@ -0,0 +1,284 @@ +/* $Id: iommu.c,v 1.4 1997/11/21 17:31:31 jj Exp $ + * iommu.c: IOMMU specific routines for memory management. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* srmmu.c */ +extern int viking_mxcc_present; +extern void (*flush_page_for_dma)(unsigned long page); +extern int flush_page_for_dma_global; +/* viking.S */ +extern void viking_flush_page(unsigned long page); +extern void viking_mxcc_flush_page(unsigned long page); + +#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) + +#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) +#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ) + +static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu, + unsigned long kern_end) +{ + unsigned long first = page_offset; + unsigned long last = kern_end; + iopte_t *iopte = iommu->page_table; + + iopte += ((first - iommu->start) >> PAGE_SHIFT); + while(first <= last) { + *iopte++ = __iopte(MKIOPTE(mmu_v2p(first))); + first += PAGE_SIZE; + } +} + +__initfunc(unsigned long +iommu_init(int iommund, unsigned long memory_start, + unsigned long memory_end, struct linux_sbus *sbus)) +{ + unsigned int impl, vers, ptsize; + unsigned long tmp; + struct iommu_struct *iommu; + struct linux_prom_registers iommu_promregs[PROMREG_MAX]; + + memory_start = LONG_ALIGN(memory_start); + iommu = (struct iommu_struct *) memory_start; + memory_start += sizeof(struct iommu_struct); + prom_getproperty(iommund, "reg", (void *) iommu_promregs, + sizeof(iommu_promregs)); + iommu->regs = (struct iommu_regs *) + sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3), + "IOMMU registers", iommu_promregs[0].which_io, 0x0); + if(!iommu->regs) + panic("Cannot map IOMMU registers."); + impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28; + vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24; + tmp = iommu->regs->control; + tmp &= ~(IOMMU_CTRL_RNGE); + switch(page_offset & 0xf0000000) { + case 0xf0000000: + tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); + iommu->plow = iommu->start = 0xf0000000; + break; + case 0xe0000000: + tmp |= (IOMMU_RNGE_512MB | IOMMU_CTRL_ENAB); + iommu->plow = iommu->start = 0xe0000000; + break; + case 0xd0000000: + case 0xc0000000: + tmp |= (IOMMU_RNGE_1GB | IOMMU_CTRL_ENAB); + iommu->plow = iommu->start = 0xc0000000; + break; + case 0xb0000000: + case 0xa0000000: + case 0x90000000: + case 0x80000000: + tmp |= (IOMMU_RNGE_2GB | IOMMU_CTRL_ENAB); + iommu->plow = iommu->start = 0x80000000; + break; + } + iommu->regs->control = tmp; + iommu_invalidate(iommu->regs); + iommu->end = 0xffffffff; + + /* Allocate IOMMU page table */ + ptsize = iommu->end - iommu->start + 1; + ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t); + + /* Stupid alignment constraints give me a headache. */ + memory_start = PAGE_ALIGN(memory_start); + memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1)); + iommu->lowest = iommu->page_table = (iopte_t *) memory_start; + memory_start += ptsize; + + /* Initialize new table. */ + flush_cache_all(); + memset(iommu->page_table, 0, ptsize); + iommu_map_dvma_pages_for_iommu(iommu, memory_end); + if(viking_mxcc_present) { + unsigned long start = (unsigned long) iommu->page_table; + unsigned long end = (start + ptsize); + while(start < end) { + viking_mxcc_flush_page(start); + start += PAGE_SIZE; + } + } else if(flush_page_for_dma == viking_flush_page) { + unsigned long start = (unsigned long) iommu->page_table; + unsigned long end = (start + ptsize); + while(start < end) { + viking_flush_page(start); + start += PAGE_SIZE; + } + } + flush_tlb_all(); + iommu->regs->base = mmu_v2p((unsigned long) iommu->page_table) >> 4; + iommu_invalidate(iommu->regs); + + sbus->iommu = iommu; + printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n", + impl, vers, iommu->page_table, ptsize); + return memory_start; +} + +static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct linux_sbus *sbus) +{ + return (__u32)vaddr; +} + +static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct linux_sbus *sbus) +{ + flush_page_for_dma(0); + return (__u32)vaddr; +} + +static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct linux_sbus *sbus) +{ + unsigned long page = ((unsigned long) vaddr) & PAGE_MASK; + + while(page < ((unsigned long)(vaddr + len))) { + flush_page_for_dma(page); + page += PAGE_SIZE; + } + return (__u32)vaddr; +} + +static void iommu_get_scsi_sgl_noflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + for (; sz >= 0; sz--) + sg[sz].dvma_addr = (__u32) (sg[sz].addr); +} + +static void iommu_get_scsi_sgl_gflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + flush_page_for_dma(0); + for (; sz >= 0; sz--) + sg[sz].dvma_addr = (__u32) (sg[sz].addr); +} + +static void iommu_get_scsi_sgl_pflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + unsigned long page, oldpage = 0; + + while(sz >= 0) { + page = ((unsigned long) sg[sz].addr) & PAGE_MASK; + if (oldpage == page) + page += PAGE_SIZE; /* We flushed that page already */ + while(page < (unsigned long)(sg[sz].addr + sg[sz].len)) { + flush_page_for_dma(page); + page += PAGE_SIZE; + } + sg[sz].dvma_addr = (__u32) (sg[sz].addr); + sz--; + oldpage = page - PAGE_SIZE; + } +} + +static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus) +{ +} + +static void iommu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ +} + +#ifdef CONFIG_SBUS +static void iommu_map_dma_area(unsigned long addr, int len) +{ + unsigned long page, end; + pgprot_t dvma_prot; + struct iommu_struct *iommu = SBus_chain->iommu; + iopte_t *iopte = iommu->page_table; + iopte_t *iopte_first = iopte; + + if(viking_mxcc_present) + dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); + else + dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV); + + iopte += ((addr - iommu->start) >> PAGE_SHIFT); + end = PAGE_ALIGN((addr + len)); + while(addr < end) { + page = get_free_page(GFP_KERNEL); + if(!page) { + prom_printf("alloc_dvma: Cannot get a dvma page\n"); + prom_halt(); + } else { + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + pgdp = pgd_offset(init_task.mm, addr); + pmdp = pmd_offset(pgdp, addr); + ptep = pte_offset(pmdp, addr); + + set_pte(ptep, pte_val(mk_pte(page, dvma_prot))); + + iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page)); + } + addr += PAGE_SIZE; + } + flush_cache_all(); + if(viking_mxcc_present) { + unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK; + unsigned long end = PAGE_ALIGN(((unsigned long) iopte)); + while(start < end) { + viking_mxcc_flush_page(start); + start += PAGE_SIZE; + } + } else if(flush_page_for_dma == viking_flush_page) { + unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK; + unsigned long end = PAGE_ALIGN(((unsigned long) iopte)); + while(start < end) { + viking_flush_page(start); + start += PAGE_SIZE; + } + } + flush_tlb_all(); + iommu_invalidate(iommu->regs); +} +#endif + +static char *iommu_lockarea(char *vaddr, unsigned long len) +{ + return vaddr; +} + +static void iommu_unlockarea(char *vaddr, unsigned long len) +{ +} + +__initfunc(void ld_mmu_iommu(void)) +{ + mmu_lockarea = iommu_lockarea; + mmu_unlockarea = iommu_unlockarea; + + if (!flush_page_for_dma) { + /* IO coherent chip */ + mmu_get_scsi_one = iommu_get_scsi_one_noflush; + mmu_get_scsi_sgl = iommu_get_scsi_sgl_noflush; + } else if (flush_page_for_dma_global) { + /* flush_page_for_dma flushes everything, no matter of what page is it */ + mmu_get_scsi_one = iommu_get_scsi_one_gflush; + mmu_get_scsi_sgl = iommu_get_scsi_sgl_gflush; + } else { + mmu_get_scsi_one = iommu_get_scsi_one_pflush; + mmu_get_scsi_sgl = iommu_get_scsi_sgl_pflush; + } + mmu_release_scsi_one = iommu_release_scsi_one; + mmu_release_scsi_sgl = iommu_release_scsi_sgl; + +#ifdef CONFIG_SBUS + mmu_map_dma_area = iommu_map_dma_area; +#endif +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.1.78/linux/arch/sparc/mm/srmmu.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc/mm/srmmu.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.151 1997/08/28 11:10:54 jj Exp $ +/* $Id: srmmu.c,v 1.156 1997/11/28 14:23:42 jj Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -25,11 +25,11 @@ #include #include #include -#include #include #include #include #include +#include /* Now the cpu specific definitions. */ #include @@ -47,6 +47,10 @@ extern unsigned long sparc_iobase_vaddr; +extern unsigned long sun4d_dma_base; +extern unsigned long sun4d_dma_size; +extern unsigned long sun4d_dma_vbase; + #ifdef __SMP__ #define FLUSH_BEGIN(mm) #define FLUSH_END @@ -55,10 +59,14 @@ #define FLUSH_END } #endif +static int phys_mem_contig; +long page_contig_offset; + static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp); static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep); -static void (*flush_page_for_dma)(unsigned long page); +void (*flush_page_for_dma)(unsigned long page); +int flush_page_for_dma_global = 1; static void (*flush_chunk)(unsigned long chunk); #ifdef __SMP__ static void (*local_flush_page_for_dma)(unsigned long page); @@ -93,37 +101,13 @@ #define srmmu_ahashfn(addr) ((addr) >> 24) -static int viking_mxcc_present = 0; - -void srmmu_frob_mem_map(unsigned long start_mem) -{ - unsigned long bank_start, bank_end; - unsigned long addr; - int i; - - /* First, mark all pages as invalid. */ - for(addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE) - mem_map[MAP_NR(addr)].flags |= (1<= KERNBASE) && - (bank_start < start_mem)) { - bank_start += PAGE_SIZE; - continue; - } - mem_map[MAP_NR(bank_start)].flags &= ~(1<= KERNBASE) return vaddr - KERNBASE; + return (vaddr - page_contig_offset); +} + +static inline unsigned long srmmu_c_p2v(unsigned long paddr) +{ + if (paddr < (0xfd000000 - KERNBASE)) return paddr + KERNBASE; + return (paddr + page_contig_offset); +} + /* In general all page table modifications should use the V8 atomic * swap instruction. This insures the mmu and the cpu are in sync * with respect to ref/mod bits in the page tables. @@ -158,6 +157,37 @@ /* Functions really use this, not srmmu_swap directly. */ #define srmmu_set_entry(ptr, newentry) srmmu_swap((unsigned long *) (ptr), (newentry)) +__initfunc(void srmmu_frob_mem_map(unsigned long start_mem)) +{ + unsigned long bank_start, bank_end; + unsigned long addr; + int i; + + /* First, mark all pages as invalid. */ + for(addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE) + mem_map[MAP_NR(addr)].flags |= (1<= KERNBASE) && + (bank_start < start_mem)) { + bank_start += PAGE_SIZE; + continue; + } + mem_map[MAP_NR(bank_start)].flags &= ~(1<= sun4d_dma_vbase + sun4d_dma_size) + clear_bit(PG_DMA, &mem_map[MAP_NR(addr)].flags); + } +} + /* The very generic SRMMU page table operations. */ static unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); } static unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); } @@ -181,6 +211,15 @@ static unsigned long srmmu_pte_page(pte_t pte) { return srmmu_device_memory(pte_val(pte))?~0:srmmu_p2v((pte_val(pte) & SRMMU_PTE_PMASK) << 4); } +static unsigned long srmmu_c_pgd_page(pgd_t pgd) +{ return srmmu_device_memory(pgd_val(pgd))?~0:srmmu_c_p2v((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); } + +static unsigned long srmmu_c_pmd_page(pmd_t pmd) +{ return srmmu_device_memory(pmd_val(pmd))?~0:srmmu_c_p2v((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); } + +static unsigned long srmmu_c_pte_page(pte_t pte) +{ return srmmu_device_memory(pte_val(pte))?~0:srmmu_c_p2v((pte_val(pte) & SRMMU_PTE_PMASK) << 4); } + static int srmmu_pte_none(pte_t pte) { return !(pte_val(pte) & 0xFFFFFFF); } static int srmmu_pte_present(pte_t pte) @@ -227,6 +266,9 @@ static pte_t srmmu_mk_pte(unsigned long page, pgprot_t pgprot) { return __pte(((srmmu_v2p(page)) >> 4) | pgprot_val(pgprot)); } +static pte_t srmmu_c_mk_pte(unsigned long page, pgprot_t pgprot) +{ return __pte(((srmmu_c_v2p(page)) >> 4) | pgprot_val(pgprot)); } + static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot) { return __pte(((page) >> 4) | pgprot_val(pgprot)); } @@ -250,6 +292,21 @@ set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) ptep) >> 4))); } +static void srmmu_c_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) +{ + set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) pgdp) >> 4))); +} + +static void srmmu_c_pgd_set(pgd_t * pgdp, pmd_t * pmdp) +{ + set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) pmdp) >> 4))); +} + +static void srmmu_c_pmd_set(pmd_t * pmdp, pte_t * ptep) +{ + set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) ptep) >> 4))); +} + static pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot) { return __pte((pte_val(pte) & SRMMU_CHG_MASK) | pgprot_val(newprot)); @@ -273,6 +330,18 @@ return (pte_t *) srmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); } +/* Find an entry in the second-level page table.. */ +static pmd_t *srmmu_c_pmd_offset(pgd_t * dir, unsigned long address) +{ + return (pmd_t *) srmmu_c_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); +} + +/* Find an entry in the third-level page table.. */ +static pte_t *srmmu_c_pte_offset(pmd_t * dir, unsigned long address) +{ + return (pte_t *) srmmu_c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); +} + /* This must update the context table entry for this process. */ static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) { @@ -560,7 +629,7 @@ pmd_set(pmd, BAD_PAGETABLE); return NULL; } - return (pte_t *) srmmu_pmd_page(*pmd) + address; + return (pte_t *) pmd_page(*pmd) + address; } static void srmmu_pmd_free_kernel(pmd_t *pmd) @@ -617,7 +686,7 @@ pmd_set(pmd, BAD_PAGETABLE); return NULL; } - return ((pte_t *) srmmu_pmd_page(*pmd)) + address; + return ((pte_t *) pmd_page(*pmd)) + address; } /* Real three-level page tables on SRMMU. */ @@ -646,7 +715,7 @@ pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); return NULL; } - return (pmd_t *) srmmu_pgd_page(*pgd) + address; + return (pmd_t *) pgd_page(*pgd) + address; } static void srmmu_pgd_free(pgd_t *pgd) @@ -789,8 +858,8 @@ physaddr &= PAGE_MASK; pgdp = srmmu_pgd_offset(init_task.mm, virt_addr); - pmdp = srmmu_pmd_offset(pgdp, virt_addr); - ptep = srmmu_pte_offset(pmdp, virt_addr); + pmdp = pmd_offset(pgdp, virt_addr); + ptep = pte_offset(pmdp, virt_addr); tmp = (physaddr >> 4) | SRMMU_ET_PTE; /* I need to test whether this is consistent over all @@ -814,23 +883,14 @@ pte_t *ptep; pgdp = srmmu_pgd_offset(init_task.mm, virt_addr); - pmdp = srmmu_pmd_offset(pgdp, virt_addr); - ptep = srmmu_pte_offset(pmdp, virt_addr); + pmdp = pmd_offset(pgdp, virt_addr); + ptep = pte_offset(pmdp, virt_addr); /* No need to flush uncacheable page. */ - set_pte(ptep, srmmu_mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED)); + set_pte(ptep, mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED)); flush_tlb_all(); } -static char *srmmu_lockarea(char *vaddr, unsigned long len) -{ - return vaddr; -} - -static void srmmu_unlockarea(char *vaddr, unsigned long len) -{ -} - /* This is used in many routines below. */ #define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask)) @@ -1131,10 +1191,12 @@ cypress_flush_page_to_ram(chunk); } +#if NOTUSED /* Cypress is also IO cache coherent. */ static void cypress_flush_page_for_dma(unsigned long page) { } +#endif /* Cypress has unified L2 VIPT, from which both instructions and data * are stored. It does not have an onboard icache of any sort, therefore @@ -1220,6 +1282,9 @@ extern void viking_flush_page(unsigned long page); extern void viking_mxcc_flush_page(unsigned long page); extern void viking_flush_chunk(unsigned long chunk); +extern void viking_c_flush_page(unsigned long page); +extern void viking_c_mxcc_flush_page(unsigned long page); +extern void viking_c_flush_chunk(unsigned long chunk); extern void viking_mxcc_flush_chunk(unsigned long chunk); extern void viking_flush_tlb_all(void); extern void viking_flush_tlb_mm(struct mm_struct *mm); @@ -1345,184 +1410,6 @@ srmmu_set_context(mm->context); } -/* IOMMU things go here. */ - -#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) - -#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) -#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ) - -static inline void srmmu_map_dvma_pages_for_iommu(struct iommu_struct *iommu, - unsigned long kern_end) -{ - unsigned long first = page_offset; - unsigned long last = kern_end; - iopte_t *iopte = iommu->page_table; - - iopte += ((first - iommu->start) >> PAGE_SHIFT); - while(first <= last) { - *iopte++ = __iopte(MKIOPTE(srmmu_v2p(first))); - first += PAGE_SIZE; - } -} - -unsigned long iommu_init(int iommund, unsigned long memory_start, - unsigned long memory_end, struct linux_sbus *sbus) -{ - unsigned int impl, vers, ptsize; - unsigned long tmp; - struct iommu_struct *iommu; - struct linux_prom_registers iommu_promregs[PROMREG_MAX]; - - memory_start = LONG_ALIGN(memory_start); - iommu = (struct iommu_struct *) memory_start; - memory_start += sizeof(struct iommu_struct); - prom_getproperty(iommund, "reg", (void *) iommu_promregs, - sizeof(iommu_promregs)); - iommu->regs = (struct iommu_regs *) - sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3), - "IOMMU registers", iommu_promregs[0].which_io, 0x0); - if(!iommu->regs) - panic("Cannot map IOMMU registers."); - impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28; - vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24; - tmp = iommu->regs->control; - tmp &= ~(IOMMU_CTRL_RNGE); - switch(page_offset & 0xf0000000) { - case 0xf0000000: - tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0xf0000000; - break; - case 0xe0000000: - tmp |= (IOMMU_RNGE_512MB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0xe0000000; - break; - case 0xd0000000: - case 0xc0000000: - tmp |= (IOMMU_RNGE_1GB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0xc0000000; - break; - case 0xb0000000: - case 0xa0000000: - case 0x90000000: - case 0x80000000: - tmp |= (IOMMU_RNGE_2GB | IOMMU_CTRL_ENAB); - iommu->plow = iommu->start = 0x80000000; - break; - } - iommu->regs->control = tmp; - iommu_invalidate(iommu->regs); - iommu->end = 0xffffffff; - - /* Allocate IOMMU page table */ - ptsize = iommu->end - iommu->start + 1; - ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t); - - /* Stupid alignment constraints give me a headache. */ - memory_start = PAGE_ALIGN(memory_start); - memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1)); - iommu->lowest = iommu->page_table = (iopte_t *) memory_start; - memory_start += ptsize; - - /* Initialize new table. */ - flush_cache_all(); - memset(iommu->page_table, 0, ptsize); - srmmu_map_dvma_pages_for_iommu(iommu, memory_end); - if(viking_mxcc_present) { - unsigned long start = (unsigned long) iommu->page_table; - unsigned long end = (start + ptsize); - while(start < end) { - viking_mxcc_flush_page(start); - start += PAGE_SIZE; - } - } else if(flush_page_for_dma == viking_flush_page) { - unsigned long start = (unsigned long) iommu->page_table; - unsigned long end = (start + ptsize); - while(start < end) { - viking_flush_page(start); - start += PAGE_SIZE; - } - } - flush_tlb_all(); - iommu->regs->base = srmmu_v2p((unsigned long) iommu->page_table) >> 4; - iommu_invalidate(iommu->regs); - - sbus->iommu = iommu; - printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n", - impl, vers, iommu->page_table, ptsize); - return memory_start; -} - -void iommu_sun4d_init(int sbi_node, struct linux_sbus *sbus) -{ - u32 *iommu; - struct linux_prom_registers iommu_promregs[PROMREG_MAX]; - - prom_getproperty(sbi_node, "reg", (void *) iommu_promregs, - sizeof(iommu_promregs)); - iommu = (u32 *) - sparc_alloc_io(iommu_promregs[2].phys_addr, 0, (PAGE_SIZE * 16), - "XPT", iommu_promregs[2].which_io, 0x0); - if(!iommu) - panic("Cannot map External Page Table."); - - /* Initialize new table. */ - flush_cache_all(); - memset(iommu, 0, 16 * PAGE_SIZE); - if(viking_mxcc_present) { - unsigned long start = (unsigned long) iommu; - unsigned long end = (start + 16 * PAGE_SIZE); - while(start < end) { - viking_mxcc_flush_page(start); - start += PAGE_SIZE; - } - } else if(flush_page_for_dma == viking_flush_page) { - unsigned long start = (unsigned long) iommu; - unsigned long end = (start + 16 * PAGE_SIZE); - while(start < end) { - viking_flush_page(start); - start += PAGE_SIZE; - } - } - flush_tlb_all(); - - sbus->iommu = (struct iommu_struct *)iommu; -} - -static __u32 srmmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) -{ - unsigned long page = ((unsigned long) vaddr) & PAGE_MASK; - - while(page < ((unsigned long)(vaddr + len))) { - flush_page_for_dma(page); - page += PAGE_SIZE; - } - return (__u32)vaddr; -} - -static void srmmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) -{ - unsigned long page; - - while(sz >= 0) { - page = ((unsigned long) sg[sz].addr) & PAGE_MASK; - while(page < (unsigned long)(sg[sz].addr + sg[sz].len)) { - flush_page_for_dma(page); - page += PAGE_SIZE; - } - sg[sz].dvma_addr = (__u32) (sg[sz].addr); - sz--; - } -} - -static void srmmu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus) -{ -} - -static void srmmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) -{ -} - static unsigned long mempool; /* NOTE: All of this startup code assumes the low 16mb (approx.) of @@ -1652,63 +1539,6 @@ } } -#ifdef CONFIG_SBUS -static void srmmu_map_dma_area(unsigned long addr, int len) -{ - unsigned long page, end; - pgprot_t dvma_prot; - struct iommu_struct *iommu = SBus_chain->iommu; - iopte_t *iopte = iommu->page_table; - iopte_t *iopte_first = iopte; - - if(viking_mxcc_present) - dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); - else - dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV); - - iopte += ((addr - iommu->start) >> PAGE_SHIFT); - end = PAGE_ALIGN((addr + len)); - while(addr < end) { - page = get_free_page(GFP_KERNEL); - if(!page) { - prom_printf("alloc_dvma: Cannot get a dvma page\n"); - prom_halt(); - } else { - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - pgdp = srmmu_pgd_offset(init_task.mm, addr); - pmdp = srmmu_pmd_offset(pgdp, addr); - ptep = srmmu_pte_offset(pmdp, addr); - - set_pte(ptep, pte_val(srmmu_mk_pte(page, dvma_prot))); - - iopte_val(*iopte++) = MKIOPTE(srmmu_v2p(page)); - } - addr += PAGE_SIZE; - } - flush_cache_all(); - if(viking_mxcc_present) { - unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK; - unsigned long end = PAGE_ALIGN(((unsigned long) iopte)); - while(start < end) { - viking_mxcc_flush_page(start); - start += PAGE_SIZE; - } - } else if(flush_page_for_dma == viking_flush_page) { - unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK; - unsigned long end = PAGE_ALIGN(((unsigned long) iopte)); - while(start < end) { - viking_flush_page(start); - start += PAGE_SIZE; - } - } - flush_tlb_all(); - iommu_invalidate(iommu->regs); -} -#endif - /* #define DEBUG_MAP_KERNEL */ #ifdef DEBUG_MAP_KERNEL @@ -2068,6 +1898,59 @@ srmmu_p2v_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry]; } + page_contig_offset = page_offset - (0xfd000000 - KERNBASE); + phys_mem_contig = 1; + for(entry = 0; srmmu_map[entry].size; entry++) + if (srmmu_map[entry].pbase != srmmu_c_v2p (srmmu_map[entry].vbase)) { + phys_mem_contig = 0; + break; + } + if (phys_mem_contig) { + printk ("SRMMU: Physical memory is contiguous, bypassing VA<->PA hashes\n"); + pte_page = srmmu_c_pte_page; + pmd_page = srmmu_c_pmd_page; + pgd_page = srmmu_c_pgd_page; + mk_pte = srmmu_c_mk_pte; + pte_offset = srmmu_c_pte_offset; + pmd_offset = srmmu_c_pmd_offset; + if (ctxd_set == srmmu_ctxd_set) + ctxd_set = srmmu_c_ctxd_set; + pgd_set = srmmu_c_pgd_set; + pmd_set = srmmu_c_pmd_set; + mmu_v2p = srmmu_c_v2p; + mmu_p2v = srmmu_c_p2v; + if (flush_chunk == viking_flush_chunk) + flush_chunk = viking_c_flush_chunk; + } + + if (sparc_cpu_model == sun4d) { + int i, j = -1; + unsigned long bank_start, bank_end; + + sun4d_dma_vbase = 0; + sun4d_dma_size = IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE; + for (i = 0; srmmu_map[i].size; i++) { + bank_start = srmmu_map[i].vbase; + bank_end = bank_start + srmmu_map[i].size; + if (bank_start <= KERNBASE && bank_end > KERNBASE) + j = i; + else if (srmmu_map[i].size >= sun4d_dma_size) { + sun4d_dma_vbase = srmmu_map[i].vbase; + break; + } + } + if (!sun4d_dma_vbase && j != -1) { + if (srmmu_map[j].size >= sun4d_dma_size + 0x1000000) + sun4d_dma_vbase = srmmu_map[j].vbase + 0x1000000; + else { + sun4d_dma_vbase = srmmu_map[j].vbase; + if (srmmu_map[j].size < sun4d_dma_size) + sun4d_dma_size = srmmu_map[j].size; + } + } + sun4d_dma_base = IOUNIT_DMA_BASE - srmmu_v2p(sun4d_dma_vbase); + } + return; /* SUCCESS! */ } @@ -2104,7 +1987,7 @@ physmem_mapped_contig = 0; /* for init.c:taint_real_pages() */ if (sparc_cpu_model == sun4d) - num_contexts = 65536; /* We now it is Viking */ + num_contexts = 65536; /* We know it is Viking */ else { /* Find the number of contexts on the srmmu. */ cpunode = prom_getchild(prom_root_node); @@ -2381,11 +2264,6 @@ hyper_flush_whole_icache(); clear = srmmu_get_faddr(); clear = srmmu_get_fstatus(); - -#ifdef __SMP__ - /* Avoid unnecessary cross calls. */ - flush_page_for_dma = local_flush_page_for_dma; -#endif } __initfunc(static void init_hypersparc(void)) @@ -2407,7 +2285,7 @@ flush_page_to_ram = hypersparc_flush_page_to_ram; flush_sig_insns = hypersparc_flush_sig_insns; - flush_page_for_dma = hypersparc_flush_page_for_dma; + flush_page_for_dma = NULL /* hypersparc_flush_page_for_dma */; flush_chunk = hypersparc_flush_chunk; /* local flush _only_ */ @@ -2480,7 +2358,7 @@ flush_page_to_ram = cypress_flush_page_to_ram; flush_sig_insns = cypress_flush_sig_insns; - flush_page_for_dma = cypress_flush_page_for_dma; + flush_page_for_dma = NULL /* cypress_flush_page_for_dma */; sparc_update_rootmmu_dir = cypress_update_rootmmu_dir; update_mmu_cache = srmmu_vac_update_mmu_cache; @@ -2671,7 +2549,7 @@ #endif flush_sig_insns = turbosparc_flush_sig_insns; - flush_page_for_dma = hypersparc_flush_page_for_dma; + flush_page_for_dma = NULL /* turbosparc_flush_page_for_dma */; poke_srmmu = poke_turbosparc; } @@ -2761,6 +2639,9 @@ #ifdef __SMP__ /* Avoid unnecessary cross calls. */ flush_cache_all = local_flush_cache_all; + flush_cache_mm = local_flush_cache_mm; + flush_cache_range = local_flush_cache_range; + flush_cache_page = local_flush_cache_page; flush_page_to_ram = local_flush_page_to_ram; flush_sig_insns = local_flush_sig_insns; flush_page_for_dma = local_flush_page_for_dma; @@ -2796,6 +2677,9 @@ * which we use the IOMMU. */ flush_page_for_dma = viking_flush_page; + /* Also, this is so far the only chip which actually uses + the page argument to flush_page_for_dma */ + flush_page_for_dma_global = 0; } else { srmmu_name = "TI Viking/MXCC"; viking_mxcc_present = 1; @@ -2803,7 +2687,7 @@ flush_chunk = viking_mxcc_flush_chunk; /* local flush _only_ */ /* MXCC vikings lack the DMA snooping bug. */ - flush_page_for_dma = viking_flush_page_for_dma; + flush_page_for_dma = NULL /* viking_flush_page_for_dma */; } flush_cache_all = viking_flush_cache_all; @@ -2951,9 +2835,12 @@ #endif -/* Load up routines and constants for sun4m mmu */ +/* Load up routines and constants for sun4m and sun4d mmu */ __initfunc(void ld_mmu_srmmu(void)) { + extern void ld_mmu_iommu(void); + extern void ld_mmu_iounit(void); + /* First the constants */ pmd_shift = SRMMU_PMD_SHIFT; pmd_size = SRMMU_PMD_SIZE; @@ -3031,18 +2918,7 @@ pte_mkyoung = srmmu_pte_mkyoung; update_mmu_cache = srmmu_update_mmu_cache; destroy_context = srmmu_destroy_context; - mmu_lockarea = srmmu_lockarea; - mmu_unlockarea = srmmu_unlockarea; - - mmu_get_scsi_one = srmmu_get_scsi_one; - mmu_get_scsi_sgl = srmmu_get_scsi_sgl; - mmu_release_scsi_one = srmmu_release_scsi_one; - mmu_release_scsi_sgl = srmmu_release_scsi_sgl; - -#ifdef CONFIG_SBUS - mmu_map_dma_area = srmmu_map_dma_area; -#endif - + mmu_info = srmmu_mmu_info; mmu_v2p = srmmu_v2p; mmu_p2v = srmmu_p2v; @@ -3085,6 +2961,11 @@ flush_tlb_page = smp_flush_tlb_page; flush_page_to_ram = smp_flush_page_to_ram; flush_sig_insns = smp_flush_sig_insns; - flush_page_for_dma = smp_flush_page_for_dma; + if (flush_page_for_dma) + flush_page_for_dma = smp_flush_page_for_dma; #endif + if (sparc_cpu_model == sun4d) + ld_mmu_iounit(); + else + ld_mmu_iommu(); } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/turbosparc.S linux/arch/sparc/mm/turbosparc.S --- v2.1.78/linux/arch/sparc/mm/turbosparc.S Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc/mm/turbosparc.S Mon Jan 12 15:15:43 1998 @@ -1,5 +1,5 @@ -/* $Id: turbosparc.S,v 1.1 1997/06/24 15:48:05 jj Exp $ - * turbosparc.S: High speed Hypersparc mmu/cache operations. +/* $Id: turbosparc.S,v 1.2 1997/11/26 13:27:59 jj Exp $ + * turbosparc.S: High speed TurboSparc mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --recursive --new-file v2.1.78/linux/arch/sparc/mm/viking.S linux/arch/sparc/mm/viking.S --- v2.1.78/linux/arch/sparc/mm/viking.S Thu May 15 16:48:02 1997 +++ linux/arch/sparc/mm/viking.S Mon Jan 12 15:15:43 1998 @@ -1,7 +1,8 @@ -/* $Id: viking.S,v 1.3 1997/05/04 10:02:14 ecd Exp $ +/* $Id: viking.S,v 1.6 1997/11/27 15:42:32 jj Exp $ * viking.S: High speed Viking cache/mmu operations * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -36,6 +37,20 @@ .globl viking_flush_tlb_all, viking_flush_tlb_mm .globl viking_flush_tlb_range, viking_flush_tlb_page + .globl viking_c_mxcc_flush_page + .globl viking_c_flush_page, viking_c_flush_chunk + +viking_c_flush_page: +viking_c_flush_chunk: + sethi %hi(KERNBASE), %g2 + cmp %o0, %g2 + bgeu 2f + sub %o0, %g2, %g3 + sethi %hi(C_LABEL(page_contig_offset)), %g2 + ld [%g2 + %lo(C_LABEL(page_contig_offset))], %g2 + ba 2f + sub %o0, %g2, %g3 + viking_flush_page: viking_flush_chunk: sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2 @@ -56,13 +71,14 @@ sub %o0, %o1, %g2 ld [%g3 + 4], %o0 add %g2, %o0, %g3 - srl %g3, 12, %g1 ! ppage >> 12 +2: srl %g3, 12, %g1 ! ppage >> 12 clr %o1 ! set counter, 0 - 127 sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3 sethi %hi(0x80000000), %o4 sethi %hi(VIKING_PTAG_VALID | VIKING_PTAG_DIRTY), %o5 - sethi %hi(PAGE_SIZE), %o0 + sethi %hi(2*PAGE_SIZE), %o0 + sethi %hi(PAGE_SIZE), %g7 clr %o2 ! block counter, 0 - 3 5: sll %o1, 5, %g4 @@ -83,20 +99,16 @@ add %g4, %o3, %g2 ! (KERNBASE + PAGE_SIZE) | (set << 5) ld [%g2], %g3 + ld [%g2 + %g7], %g3 add %g2, %o0, %g2 ld [%g2], %g3 + ld [%g2 + %g7], %g3 add %g2, %o0, %g2 ld [%g2], %g3 + ld [%g2 + %g7], %g3 add %g2, %o0, %g2 ld [%g2], %g3 - add %g2, %o0, %g2 - ld [%g2], %g3 - add %g2, %o0, %g2 - ld [%g2], %g3 - add %g2, %o0, %g2 - ld [%g2], %g3 - add %g2, %o0, %g2 - ld [%g2], %g3 + ld [%g2 + %g7], %g3 b 8f inc %o1 @@ -115,6 +127,15 @@ retl nop +viking_c_mxcc_flush_page: + sethi %hi(KERNBASE), %g2 + cmp %o0, %g2 + bgeu 2f + sub %o0, %g2, %g3 + sethi %hi(C_LABEL(page_contig_offset)), %g2 + ld [%g2 + %lo(C_LABEL(page_contig_offset))], %g2 + ba 2f + sub %o0, %g2, %g3 viking_mxcc_flush_page: sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2 @@ -134,17 +155,12 @@ ld [%g3], %o1 sub %o0, %o1, %g2 ld [%g3 + 4], %o0 - sethi %hi(PAGE_SIZE), %g4 add %g2, %o0, %g3 - add %g3, %g4, %g3 ! ppage + PAGE_SIZE - +2: sub %g3, -PAGE_SIZE, %g3 ! ppage + PAGE_SIZE mov 0x10, %g2 ! set cacheable bit - sethi %hi(MXCC_SRCSTREAM), %o2 - or %o2, %lo(MXCC_SRCSTREAM), %o2 - sethi %hi(MXCC_DESSTREAM), %o3 + sethi %hi(MXCC_SRCSTREAM), %o3 ! assume %hi(MXCC_SRCSTREAM) == %hi(MXCC_DESTSTREAM) + or %o3, %lo(MXCC_SRCSTREAM), %o2 or %o3, %lo(MXCC_DESSTREAM), %o3 - -5: sub %g3, MXCC_STREAM_SIZE, %g3 6: stda %g2, [%o2] ASI_M_MXCC @@ -168,7 +184,6 @@ nop viking_flush_tlb_all: - WINDOW_FLUSH(%g4, %g5) mov 0x400, %g1 retl sta %g0, [%g1] ASI_M_FLUSH_PROBE @@ -179,16 +194,15 @@ lda [%g1] ASI_M_MMUREGS, %g5 #ifndef __SMP__ cmp %o1, -1 - be viking_flush_tlb_mm_out + be 1f #endif - WINDOW_FLUSH(%g2, %g3) - mov 0x300, %g2 sta %o1, [%g1] ASI_M_MMUREGS sta %g0, [%g2] ASI_M_FLUSH_PROBE -viking_flush_tlb_mm_out: retl sta %g5, [%g1] ASI_M_MMUREGS +1: retl + nop viking_flush_tlb_range: mov SRMMU_CTX_REG, %g1 @@ -196,42 +210,39 @@ lda [%g1] ASI_M_MMUREGS, %g5 #ifndef __SMP__ cmp %o3, -1 - be viking_flush_tlb_range_out + be 2f #endif - WINDOW_FLUSH(%g2, %g3) - srl %o1, SRMMU_PGDIR_SHIFT, %o1 sta %o3, [%g1] ASI_M_MMUREGS sll %o1, SRMMU_PGDIR_SHIFT, %o1 sethi %hi(1 << SRMMU_PGDIR_SHIFT), %o4 add %o1, 0x200, %o1 sta %g0, [%o1] ASI_M_FLUSH_PROBE -1: - add %o1, %o4, %o1 +1: add %o1, %o4, %o1 cmp %o1, %o2 blu,a 1b sta %g0, [%o1] ASI_M_FLUSH_PROBE -viking_flush_tlb_range_out: retl sta %g5, [%g1] ASI_M_MMUREGS +2: retl + nop viking_flush_tlb_page: ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */ mov SRMMU_CTX_REG, %g1 ld [%o0 + AOFF_mm_context], %o3 - and %o1, PAGE_MASK, %o1 lda [%g1] ASI_M_MMUREGS, %g5 #ifndef __SMP__ cmp %o3, -1 - be viking_flush_tlb_page_out + be 1f #endif - WINDOW_FLUSH(%g2, %g3) - + and %o1, PAGE_MASK, %o1 sta %o3, [%g1] ASI_M_MMUREGS sta %g0, [%o1] ASI_M_FLUSH_PROBE -viking_flush_tlb_page_out: retl sta %g5, [%g1] ASI_M_MMUREGS +1: retl + nop viking_flush_page_to_ram: viking_flush_page_for_dma: diff -u --recursive --new-file v2.1.78/linux/arch/sparc/prom/ranges.c linux/arch/sparc/prom/ranges.c --- v2.1.78/linux/arch/sparc/prom/ranges.c Mon Mar 17 14:54:22 1997 +++ linux/arch/sparc/prom/ranges.c Mon Jan 12 15:15:43 1998 @@ -1,7 +1,8 @@ -/* $Id: ranges.c,v 1.8 1997/02/04 07:28:29 davem Exp $ +/* $Id: ranges.c,v 1.10 1997/12/19 12:37:18 jj Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -22,7 +23,9 @@ for(regc=0; regc < nregs; regc++) { for(rngc=0; rngc < nranges; rngc++) - if(regp[regc].which_io == rangep[rngc].ot_child_space) + if(regp[regc].which_io == rangep[rngc].ot_child_space && + regp[regc].phys_addr >= rangep[rngc].ot_child_base && + regp[regc].phys_addr + regp[regc].reg_size <= rangep[rngc].ot_child_base + rangep[rngc].or_size) break; /* Fount it */ if(rngc==nranges) /* oops */ prom_printf("adjust_regs: Could not find range with matching bus type...\n"); @@ -39,10 +42,15 @@ for(rng1c=0; rng1c < nranges1; rng1c++) { for(rng2c=0; rng2c < nranges2; rng2c++) - if(ranges1[rng1c].ot_child_space == - ranges2[rng2c].ot_child_space) break; + if(ranges1[rng1c].ot_parent_space == ranges2[rng2c].ot_child_space && + ranges1[rng1c].ot_parent_base >= ranges2[rng2c].ot_child_base && + ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size - ranges1[rng1c].ot_parent_base > 0U) + break; if(rng2c == nranges2) /* oops */ prom_printf("adjust_ranges: Could not find matching bus type...\n"); + else if (ranges1[rng1c].ot_parent_base + ranges1[rng1c].or_size > ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size) + ranges1[rng1c].or_size = + ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size - ranges1[rng1c].ot_parent_base; ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space; ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c --- v2.1.78/linux/arch/sparc/prom/tree.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc/prom/tree.c Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.19 1997/06/27 14:52:54 jj Exp $ +/* $Id: tree.c,v 1.22 1997/09/25 02:19:22 davem Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * @@ -229,36 +229,40 @@ return 0; } -/* Return the first property type for node 'node'. - */ -char * prom_firstprop(int node, char *buffer) +/* Interal version of nextprop that does not alter return values. */ +char * __prom_nextprop(int node, char * oprop) { unsigned long flags; - char *ret; + char *prop; - if(node == -1) return ""; - save_flags(flags); cli(); - ret = prom_nodeops->no_nextprop(node, (char *) 0x0); + save_and_cli(flags); + prop = prom_nodeops->no_nextprop(node, oprop); restore_current(); restore_flags(flags); - return ret; + + return prop; +} + +/* Return the first property name for node 'node'. */ +/* buffer is unused argument, but as v9 uses it, we need to have the same interface */ +char * prom_firstprop(int node, char *bufer) +{ + if (node == 0 || node == -1) + return ""; + + return __prom_nextprop(node, ""); } /* Return the property type string after property type 'oprop' - * at node 'node' . Returns NULL string if no more + * at node 'node' . Returns empty string if no more * property types for this node. */ char * prom_nextprop(int node, char *oprop, char *buffer) { - char *ret; - unsigned long flags; + if (node == 0 || node == -1) + return ""; - if(node == -1) return ""; - save_flags(flags); cli(); - ret = prom_nodeops->no_nextprop(node, oprop); - restore_current(); - restore_flags(flags); - return ret; + return __prom_nextprop(node, oprop); } int prom_finddevice(char *name) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile --- v2.1.78/linux/arch/sparc64/Makefile Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/Makefile Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.22 1997/08/29 15:51:53 jj Exp $ +# $Id: Makefile,v 1.24 1997/10/02 16:31:16 jj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -38,10 +38,18 @@ SUBDIRS += arch/sparc64/solaris endif +ifneq ($(CONFIG_MATHEMU),n) + SUBDIRS += arch/sparc64/math-emu +endif + CORE_FILES := arch/sparc64/kernel/kernel.o arch/sparc64/mm/mm.o $(CORE_FILES) ifeq ($(CONFIG_SOLARIS_EMUL),y) CORE_FILES += arch/sparc64/solaris/solaris.o +endif + +ifeq ($(CONFIG_MATHEMU),y) + CORE_FILES += arch/sparc64/math-emu/math-emu.o endif LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/boot/Makefile linux/arch/sparc64/boot/Makefile --- v2.1.78/linux/arch/sparc64/boot/Makefile Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/boot/Makefile Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 1997/08/29 11:08:34 davem Exp $ +# $Id: Makefile,v 1.4 1997/12/15 20:08:56 ecd Exp $ # Makefile for the Sparc64 boot stuff. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -12,7 +12,7 @@ boot: @echo "Nothing special to be done for 'boot' on Linux/UltraSPARC." -tftpboot.img: piggyback +tftpboot.img: piggyback $(TOPDIR)/vmlinux $(ROOT_IMG) $(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img ./piggyback tftpboot.img $(TOPDIR)/System.map $(ROOT_IMG) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.1.78/linux/arch/sparc64/config.in Tue Dec 2 16:45:18 1997 +++ linux/arch/sparc64/config.in Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.17 1997/09/04 01:54:43 davem Exp $ +# $Id: config.in,v 1.36 1998/01/10 19:04:30 ecd Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -39,6 +39,7 @@ define_bool CONFIG_SUN_MOUSE y define_bool CONFIG_SERIAL y define_bool CONFIG_SUN_SERIAL y + define_bool CONFIG_SERIAL_CONSOLE y define_bool CONFIG_SUN_KEYBOARD y define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y @@ -48,8 +49,10 @@ fi tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS +bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL bool 'Kernel support for Linux/Sparc 32bit binary compatibility' CONFIG_SPARC32_COMPAT tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF @@ -64,8 +67,25 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel Quad FPU (long double) and subnormal float/double emulation' CONFIG_MATHEMU +fi endmenu +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Parallel port support' CONFIG_PARPORT + if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_AX" != "n" ]; then + bool ' Support foreign hardware' CONFIG_PARPORT_OTHER + fi + dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT + if [ "$CONFIG_PRINTER" != "n" ]; then + bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK + fi + fi +fi + mainmenu_option next_comment comment 'Floppy, IDE, and other block devices' @@ -75,7 +95,8 @@ if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED -# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING + tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING + tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM @@ -84,6 +105,7 @@ fi tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +tristate 'Network block device support' CONFIG_BLK_DEV_NBD if [ "$CONFIG_PCI" = "y" ]; then tristate 'Ultra/PCI IDE disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE @@ -94,7 +116,7 @@ dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE define_bool CONFIG_IDE_CHIPSETS y - define_bool CONFIG_BLK_DEV_NS87415 y + define_bool CONFIG_BLK_DEV_NS87415_AX y fi fi @@ -144,12 +166,27 @@ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15 fi + dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI + if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then + bool ' detect and read serial NVRAMs' CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT + bool ' enable tagged command queueing' CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE + int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 12 + int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10 + if [ "$CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE" != "y" ]; then + bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' assume boards are SYMBIOS compatible' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + fi + fi fi endmenu fi endmenu +source drivers/fc4/Config.in + if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment comment 'Network device support' @@ -197,11 +234,18 @@ source fs/nls/Config.in mainmenu_option next_comment +comment 'Watchdog' + +tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG +endmenu + +mainmenu_option next_comment comment 'Kernel hacking' bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP endmenu diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.1.78/linux/arch/sparc64/defconfig Sun Sep 7 13:10:42 1997 +++ linux/arch/sparc64/defconfig Mon Jan 12 15:15:43 1998 @@ -11,8 +11,8 @@ # Loadable module support # CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KERNELD is not set +CONFIG_MODVERSIONS=y +CONFIG_KERNELD=y # # General setup @@ -30,6 +30,7 @@ CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y +CONFIG_PCI_OLD_PROC=y # # SBUS Frame Buffer support @@ -50,20 +51,27 @@ # CONFIG_SUN_OPENPROMIO=m CONFIG_SUN_MOSTEK_RTC=y -# CONFIG_SAB82532 is not set +CONFIG_SAB82532=y +# CONFIG_OBP_FLASH is not set # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_SPARC32_COMPAT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_AOUT32=y -CONFIG_BINFMT_JAVA=m CONFIG_BINFMT_MISC=m +CONFIG_BINFMT_JAVA=m CONFIG_SOLARIS_EMUL=m +CONFIG_MATHEMU=m +CONFIG_PARPORT=y +CONFIG_PARPORT_AX=y +CONFIG_PRINTER=y +CONFIG_PRINTER_READBACK=y # # Floppy, IDE, and other block devices @@ -72,9 +80,12 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=m CONFIG_MD_STRIPED=m +CONFIG_MD_MIRRORING=m +CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_IDE=y CONFIG_BLK_DEV_IDEDISK=y CONFIG_BLK_DEV_IDECD=y @@ -82,46 +93,60 @@ CONFIG_BLK_DEV_IDEFLOPPY=m # CONFIG_BLK_DEV_IDESCSI is not set CONFIG_IDE_CHIPSETS=y -CONFIG_BLK_DEV_NS87415=y +CONFIG_BLK_DEV_NS87415_AX=y # # Networking options # +CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set +CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set # CONFIG_IP_ACCT is not set +# CONFIG_IP_MASQUERADE is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set -# CONFIG_XTP is not set # # (it is safe to leave these untouched) # -# CONFIG_INET_PCTCP is not set CONFIG_INET_RARP=m -CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y CONFIG_IPV6=m +# CONFIG_IPV6_EUI64 is not set +# CONFIG_IPV6_NO_PB is not set # # # CONFIG_IPX=m # CONFIG_IPX_INTERN is not set -# CONFIG_IPX_PPROP_ROUTING is not set CONFIG_ATALK=m -# CONFIG_IPDDP is not set # CONFIG_AX25 is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_WAN_ROUTER is not set +# CONFIG_CPU_IS_SLOW is not set +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=y +CONFIG_NET_SCH_CSZ=y +CONFIG_NET_SCH_HFQ=y +CONFIG_NET_SCH_RED=y +CONFIG_NET_SCH_SFQ=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_PFIFO=y +CONFIG_NET_SCH_PRIO=y # # SCSI support @@ -154,6 +179,12 @@ # CONFIG_AIC7XXX_PAGE_ENABLE is not set # CONFIG_AIC7XXX_PROC_STATS is not set CONFIG_AIC7XXX_RESET_DELAY=5 +CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT=y +CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=12 +CONFIG_SCSI_NCR53C8XX_SYNC=10 +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set # # Network device support @@ -174,6 +205,7 @@ CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m CONFIG_DE4X5=y +CONFIG_CDROM=y # # Filesystems @@ -181,22 +213,21 @@ # CONFIG_QUOTA is not set CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m -# CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_RNFS_BOOTP=y -# CONFIG_RNFS_RARP is not set CONFIG_NFSD=m CONFIG_SUNRPC=y CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m -CONFIG_ISO9660_FS=y CONFIG_HPFS_FS=m CONFIG_SYSV_FS=m CONFIG_AFFS_FS=m @@ -209,7 +240,44 @@ # CONFIG_MAC_PARTITION is not set # +# Native Language Support +# +CONFIG_NLS=y +# CONFIG_NLS_CODEPAGE_437 is not set +# 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_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Watchdog +# +# CONFIG_SOFT_WATCHDOG is not set + +# # Kernel hacking # # CONFIG_PROFILE is not set +# CONFIG_MAGIC_SYSRQ is not set # CONFIG_EC_FLUSH_TRAP is not set diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.1.78/linux/arch/sparc64/kernel/Makefile Mon Aug 18 18:19:45 1997 +++ linux/arch/sparc64/kernel/Makefile Mon Jan 12 15:15:43 1998 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $ +# $Id: Makefile,v 1.35 1997/09/20 21:48:58 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -71,8 +71,8 @@ @rm -f tmp.[ci] #$(CC) -o check_asm check_asm.c # Until we can do this natively, a hack has to take place - $(CC) -mmedlow -S -o check_asm.s check_asm.c - $(HOSTCC) -o check_asm check_asm.s + $(CC) -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c + $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @rm -f check_asm.s # ./check_asm > asm_offsets.h diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.1.78/linux/arch/sparc64/kernel/binfmt_aout32.c Sat Oct 25 02:44:15 1997 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Mon Jan 12 15:15:44 1998 @@ -57,11 +57,12 @@ * macros to write out all the necessary info. */ #define DUMP_WRITE(addr,nr) \ -while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump +while (file.f_op->write(&file,(char *)(addr),(nr),&file.f_pos) != (nr)) \ + goto close_coredump #define DUMP_SEEK(offset) \ if (file.f_op->llseek) { \ - if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \ + if (file.f_op->llseek(&file,(offset),0) != (offset)) \ goto close_coredump; \ } else file.f_pos = (offset) @@ -81,7 +82,7 @@ struct dentry * dentry = NULL; struct inode * inode = NULL; struct file file; - unsigned short fs; + mm_segment_t fs; int has_dumped = 0; char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; @@ -256,7 +257,7 @@ unsigned long p = bprm->p; unsigned long fd_offset; unsigned long rlim; - int retval; +int retval; ex = *((struct exec *) bprm->buf); /* exec-header */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && @@ -285,8 +286,6 @@ return retval; /* OK, This is the point of no return */ - memcpy(¤t->tss.core_exec, &ex, sizeof(struct exec)); - current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); current->mm->end_data = ex.a_data + @@ -420,13 +419,13 @@ /* Seek into the file */ if (file->f_op->llseek) { - if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) + if ((error = file->f_op->llseek(file, 0, 0)) != 0) return -ENOEXEC; } else file->f_pos = 0; set_fs(KERNEL_DS); - error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex)); + error = file->f_op->read(file, (char *) &ex, sizeof(ex), &file->f_pos); set_fs(USER_DS); if (error != sizeof(ex)) return -ENOEXEC; diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/dtlb_miss.S linux/arch/sparc64/kernel/dtlb_miss.S --- v2.1.78/linux/arch/sparc64/kernel/dtlb_miss.S Mon Aug 18 18:19:45 1997 +++ linux/arch/sparc64/kernel/dtlb_miss.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $ +/* $Id: dtlb_miss.S,v 1.14 1997/10/14 01:48:28 davem Exp $ * dtlb_miss.S: Data TLB miss code, this is included directly * into the trap table. * @@ -53,10 +53,10 @@ /*0x24*/ srlx %g1, 1, %g1 ! PTE offset 2:/*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE - /*0x30*/ brlz,a,pt %g5, 1f ! Valid set? - /*0x34*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load - /*0x38*/ ba,a,pt %xcc, sparc64_dtlb_refbit_catch ! Nope... -1:/*0x3c*/ retry ! Trap return + /*0x30*/ brgez,pn %g5, sparc64_dtlb_refbit_catch ! Valid set? + /*0x34*/ nop ! delay + /*0x38*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load + /*0x3c*/ retry ! Trap return 3: /* ICACHE line 3 */ /*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c --- v2.1.78/linux/arch/sparc64/kernel/ebus.c Sun Sep 7 13:10:42 1997 +++ linux/arch/sparc64/kernel/ebus.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $ +/* $Id: ebus.c,v 1.17 1998/01/10 18:26:13 ecd Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -17,8 +17,15 @@ #include #include +#undef PROM_DEBUG #undef DEBUG_FILL_EBUS_DEV +#ifdef PROM_DEBUG +#define dprintf prom_printf +#else +#define dprintf printk +#endif + struct linux_ebus *ebus_chain = 0; extern void prom_ebus_ranges_init(struct linux_ebus *); @@ -36,8 +43,12 @@ #ifdef CONFIG_SUN_AUXIO extern void auxio_probe(void); #endif +#ifdef CONFIG_OBP_FLASH +extern int flash_init(void); +#endif -extern unsigned int psycho_irq_build(unsigned int full_ino); +extern unsigned int psycho_irq_build(struct linux_pbm_info *pbm, + unsigned int full_ino); static inline unsigned long ebus_alloc(unsigned long *memory_start, size_t size) @@ -47,6 +58,7 @@ *memory_start = (*memory_start + 7) & ~(7); mem = *memory_start; *memory_start += size; + memset((void *)mem, 0, size); return mem; } @@ -79,19 +91,19 @@ } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = psycho_irq_build(irqs[i]); + dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]); } #ifdef DEBUG_FILL_EBUS_DEV - printk("child '%s': address%s\n", dev->prom_name, + dprintf("child '%s': address%s\n", dev->prom_name, dev->num_addrs > 1 ? "es" : ""); for (i = 0; i < dev->num_addrs; i++) - printk(" %016lx\n", dev->base_address[i]); + dprintf(" %016lx\n", dev->base_address[i]); if (dev->num_irqs) { - printk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); for (i = 0; i < dev->num_irqs; i++) - printk(" %08x", dev->irqs[i]); - printk("\n"); + dprintf(" %08x", dev->irqs[i]); + dprintf("\n"); } #endif } @@ -121,7 +133,7 @@ for (i = 0; i < dev->num_addrs; i++) { n = (regs[i].which_io - 0x10) >> 2; - dev->base_address[i] = dev->parent->self->base_address[n]; + dev->base_address[i] = dev->bus->self->base_address[n]; dev->base_address[i] += (unsigned long)regs[i].phys_addr; } @@ -131,19 +143,19 @@ } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = psycho_irq_build(irqs[i]); + dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]); } #ifdef DEBUG_FILL_EBUS_DEV - printk("'%s': address%s\n", dev->prom_name, + dprintf("'%s': address%s\n", dev->prom_name, dev->num_addrs > 1 ? "es" : ""); for (i = 0; i < dev->num_addrs; i++) - printk(" %016lx\n", dev->base_address[i]); + dprintf(" %016lx\n", dev->base_address[i]); if (dev->num_irqs) { - printk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); for (i = 0; i < dev->num_irqs; i++) - printk(" %08x", dev->irqs[i]); - printk("\n"); + dprintf(" %08x", dev->irqs[i]); + dprintf("\n"); } #endif if ((node = prom_getchild(node))) { @@ -153,6 +165,7 @@ child = dev->children; child->next = 0; child->parent = dev; + child->bus = dev->bus; fill_ebus_child(node, child); while ((node = prom_getsibling(node))) { @@ -162,6 +175,7 @@ child = child->next; child->next = 0; child->parent = dev; + child->bus = dev->bus; fill_ebus_child(node, child); } } @@ -195,6 +209,9 @@ } if (!pdev) { printk("ebus: No EBus's found.\n"); +#ifdef PROM_DEBUG + dprintf("ebus: No EBus's found.\n"); +#endif return memory_start; } @@ -206,7 +223,10 @@ ebus->next = 0; while (ebusnd) { - printk("ebus%d:\n", num_ebus); + printk("ebus%d:", num_ebus); +#ifdef PROM_DEBUG + dprintf("ebus%d:", num_ebus); +#endif prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf)); ebus->prom_node = ebusnd; @@ -250,20 +270,34 @@ addr += (u64)rp->parent_phys_hi << 32UL; *base++ = (unsigned long)__va(addr); + printk(" %lx[%x]", (unsigned long)__va(addr), + regs[reg].size_lo); +#ifdef PROM_DEBUG + dprintf(" %lx[%x]", (unsigned long)__va(addr), + regs[reg].size_lo); +#endif break; } } + printk("\n"); +#ifdef PROM_DEBUG + dprintf("\n"); +#endif prom_ebus_ranges_init(ebus); nd = prom_getchild(ebusnd); + if (!nd) + goto next_ebus; + ebus->devices = (struct linux_ebus_device *) - ebus_alloc(&memory_start, sizeof(struct linux_ebus_device)); + ebus_alloc(&memory_start, + sizeof(struct linux_ebus_device)); dev = ebus->devices; dev->next = 0; dev->children = 0; - dev->parent = ebus; + dev->bus = ebus; memory_start = fill_ebus_device(nd, dev, memory_start); while ((nd = prom_getsibling(nd))) { @@ -273,10 +307,11 @@ dev = dev->next; dev->next = 0; dev->children = 0; - dev->parent = ebus; + dev->bus = ebus; memory_start = fill_ebus_device(nd, dev, memory_start); } + next_ebus: for (pdev = pdev->next; pdev; pdev = pdev->next) { if ((pdev->vendor == PCI_VENDOR_ID_SUN) && (pdev->device == PCI_DEVICE_ID_SUN_EBUS)) @@ -312,6 +347,9 @@ #ifdef CONFIG_SUN_AUXIO if (sparc_cpu_model == sun4u) auxio_probe(); +#endif +#ifdef CONFIG_OBP_FLASH + flash_init(); #endif #ifdef __sparc_v9__ if (sparc_cpu_model == sun4u) { diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.1.78/linux/arch/sparc64/kernel/entry.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/entry.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.65 1997/08/29 15:51:29 jj Exp $ +/* $Id: entry.S,v 1.76 1998/01/05 17:00:13 jj Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -121,7 +121,7 @@ .align 32 .globl do_fpdis do_fpdis: - ldx [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group sethi %hi(TSTATE_PEF), %g4 ! IEU0 sethi %hi(FPDIS_OFF), %g3 ! IEU1 wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles @@ -337,9 +337,28 @@ retl stx %o1, [%o0 + PT_V9_TSTATE] + .globl utrap, utrap_ill +utrap: brz,pn %g1, etrap + nop + save %sp, -128, %sp + rdpr %tstate, %l6 + rdpr %cwp, %l7 + andn %l6, TSTATE_CWP, %l6 + wrpr %l6, %l7, %tstate + rdpr %tpc, %l6 + rdpr %tnpc, %l7 + wrpr %g1, 0, %tnpc + done +utrap_ill: + call bad_trap + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + #ifdef CONFIG_BLK_DEV_FD .globl floppy_hardint floppy_hardint: + wr %g0, (1 << 11), %clear_softint sethi %hi(doing_pdma), %g1 ld [%g1 + %lo(doing_pdma)], %g2 brz,pn %g2, floppy_dosoftint @@ -404,8 +423,9 @@ sethi %hi(irq_action), %g1 or %g1, %lo(irq_action), %g1 ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq] - ldx [%g3 + 0x10], %g4 ! action->mask - st %g0, [%g4] ! SYSIO_ICLR_IDLE + ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr + ldx [%g4 + 0x18], %g4 ! bucket->iclr + stw %g0, [%g4] ! SYSIO_ICLR_IDLE membar #Sync ! probably not needed... retry @@ -446,14 +466,52 @@ cmp %g3, 1 bgu,a,pn %icc, winfix_mna rdpr %tpc, %g3 + mov DMMU_SFAR, %g4 + mov TLB_SFSR, %g5 sethi %hi(109f), %g7 + ldxa [%g4] ASI_DMMU, %g4 + ldxa [%g5] ASI_DMMU, %g5 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 call mem_address_unaligned add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 + .globl do_lddfmna +do_lddfmna: + mov DMMU_SFAR, %g4 + mov TLB_SFSR, %g5 + sethi %hi(109f), %g7 + ldxa [%g4] ASI_DMMU, %g4 + ldxa [%g5] ASI_DMMU, %g5 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call handle_lddfmna + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + + .globl do_stdfmna +do_stdfmna: + mov DMMU_SFAR, %g4 + mov TLB_SFSR, %g5 + sethi %hi(109f), %g7 + ldxa [%g4] ASI_DMMU, %g4 + ldxa [%g5] ASI_DMMU, %g5 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call handle_stdfmna + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + .globl breakpoint_trap breakpoint_trap: call sparc_breakpoint @@ -471,13 +529,13 @@ mov %o7, %l4 cmp %o0, NR_SYSCALLS blu,a,pt %icc, 1f - sll %o0, 0x3, %o0 + sll %o0, 0x2, %o0 sethi %hi(sunos_nosys), %l6 b,pt %xcc, 2f or %l6, %lo(sunos_nosys), %l6 1: sethi %hi(sunos_sys_table), %l7 or %l7, %lo(sunos_sys_table), %l7 - ldx [%l7 + %o0], %l6 + lduw [%l7 + %o0], %l6 2: mov %o1, %o0 mov %o2, %o1 mov %o3, %o2 @@ -526,7 +584,9 @@ add %sp, STACK_BIAS + REGWIN_SZ, %o0 .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall - .globl sys_sigsuspend, sys_sigreturn + .globl sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend + .globl sys_sigreturn, sys_rt_sigreturn + .globl sys32_sigreturn, sys32_rt_sigreturn .globl sys32_execve, sys_ptrace .align 32 sys_pipe: sethi %hi(sparc_pipe), %g1 @@ -546,42 +606,57 @@ add %sp, STACK_BIAS + REGWIN_SZ, %o0 jmpl %g1 + %lo(sparc32_execve), %g0 nop - - /* NOTE: %o0 has a correct value already */ -sys_sigpause: call do_sigpause - add %sp, STACK_BIAS + REGWIN_SZ, %o1 - ldx [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace +sys_memory_ordering: + sethi %hi(sparc_memory_ordering), %g1 + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + jmpl %g1 + %lo(sparc_memory_ordering), %g0 nop - ba,pt %xcc, rtrap - clr %l6 -linux_sparc_ni_syscall: - sethi %hi(sys_ni_syscall), %l7 - b,pt %xcc,syscall_is_too_hard - or %l7, %lo(sys_ni_syscall), %l7 - nop - .align 32 -sys_sigsuspend: call do_sigsuspend - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ldx [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace - nop - - ba,pt %xcc, rtrap - clr %l6 - +sys_sigsuspend: add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigsuspend + add %o7, 1f-.-4, %o7 + nop +sys_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */ + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + call do_rt_sigsuspend + add %o7, 1f-.-4, %o7 + nop +sys32_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */ + srl %o0, 0, %o0 + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + call do_rt_sigsuspend32 + add %o7, 1f-.-4, %o7 + /* NOTE: %o0 has a correct value already */ +sys_sigpause: add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call do_sigpause + add %o7, 1f-.-4, %o7 + nop +sys_sigreturn: add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigreturn + add %o7, 1f-.-4, %o7 + nop +sys32_sigreturn: + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigreturn32 + add %o7, 1f-.-4, %o7 + nop +sys_rt_sigreturn: + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_rt_sigreturn + add %o7, 1f-.-4, %o7 + nop +sys32_rt_sigreturn: + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_rt_sigreturn32 + add %o7, 1f-.-4, %o7 + nop +sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_ptrace + add %o7, 1f-.-4, %o7 + nop .align 32 -sys_sigreturn: call do_sigreturn - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ldx [%curptr + AOFF_task_flags], %l5 +1: ldx [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 be,pt %icc, rtrap clr %l6 @@ -591,19 +666,6 @@ ba,pt %xcc, rtrap clr %l6 - .align 32 -sys_ptrace: call do_ptrace - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ldx [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace - nop - - ba,pt %xcc, rtrap - clr %l6 - /* This is how fork() was meant to be done, 12 instruction entry. * * I questioned the following code briefly, let me clear things @@ -648,42 +710,94 @@ b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 +linux_sparc_ni_syscall: + sethi %hi(sys_ni_syscall), %l7 + b,pt %xcc, 4f + or %l7, %lo(sys_ni_syscall), %l7 + +linux_syscall_trace32: + call syscall_trace + nop + srl %i0, 0, %o0 + mov %i4, %o4 + srl %i1, 0, %o1 + srl %i2, 0, %o2 + b,pt %xcc, 2f + srl %i3, 0, %o3 + linux_syscall_trace: - call syscall_trace - nop - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 - b,pt %xcc, 2f - mov %i4, %o4 + call syscall_trace + nop + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + b,pt %xcc, 2f + mov %i4, %o4 + + + /* Linux 32-bit and SunOS system calls enter here... */ + .align 32 + .globl linux_sparc_syscall32 +linux_sparc_syscall32: + /* Direct access to user regs, must faster. */ + cmp %g1, NR_SYSCALLS ! IEU1 Group + bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI + srl %i0, 0, %o0 ! IEU0 + sll %g1, 2, %l4 ! IEU0 Group +#ifdef SYSCALL_TRACING + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call syscall_trace_entry + mov %g1, %o0 + srl %i0, 0, %o0 +#endif + mov %i4, %o4 ! IEU1 + lduw [%l7 + %l4], %l7 ! Load + srl %i1, 0, %o1 ! IEU0 Group + ldx [%curptr + AOFF_task_flags], %l0 ! Load + + mov %i5, %o5 ! IEU1 + srl %i2, 0, %o2 ! IEU0 Group + mov %i0, %l5 ! IEU1 + andcc %l0, 0x20, %g0 ! IEU1 Group + bne,pn %icc, linux_syscall_trace32 ! CTI + srl %i3, 0, %o3 ! IEU0 + call %l7 ! CTI Group brk forced + add %o7, 3f-.-4, %o7 ! IEU0 /* Linux native and SunOS system calls enter here... */ .align 32 - .globl linux_sparc_syscall, syscall_is_too_hard, ret_sys_call + .globl linux_sparc_syscall, ret_sys_call linux_sparc_syscall: /* Direct access to user regs, must faster. */ cmp %g1, NR_SYSCALLS ! IEU1 Group bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI mov %i0, %o0 ! IEU0 sll %g1, 2, %l4 ! IEU0 Group +#ifdef SYSCALL_TRACING + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call syscall_trace_entry + mov %g1, %o0 + mov %i0, %o0 +#endif mov %i1, %o1 ! IEU1 lduw [%l7 + %l4], %l7 ! Load -syscall_is_too_hard: - mov %i2, %o2 ! IEU0 Group - ldx [%curptr + AOFF_task_flags], %l5 ! Load +4: mov %i2, %o2 ! IEU0 Group + ldx [%curptr + AOFF_task_flags], %l0 ! Load - st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] mov %i3, %o3 ! IEU1 mov %i4, %o4 ! IEU0 Group - andcc %l5, 0x20, %g0 ! IEU1 2 bubbles + andcc %l0, 0x20, %g0 ! IEU1 Group+1 bubble bne,pn %icc, linux_syscall_trace ! CTI Group mov %i0, %l5 ! IEU0 2: call %l7 ! CTI Group brk forced mov %i5, %o5 ! IEU0 - stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] - +3: stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ret_sys_call: +#ifdef SYSCALL_TRACING + call syscall_trace_exit + add %sp, STACK_BIAS + REGWIN_SZ, %o1 +#endif ldx [%curptr + AOFF_task_flags], %l6 sra %o0, 0, %o0 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S --- v2.1.78/linux/arch/sparc64/kernel/etrap.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/etrap.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.37 1997/08/21 09:13:18 davem Exp $ +/* $Id: etrap.S,v 1.39 1997/10/24 11:57:47 jj Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -79,11 +79,11 @@ andcc %l0, FPRS_FEF, %g0 ! IEU1 Group be,pn %icc, 6f ! CTI st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group or %l4, %l0, %l4 ! IEU0 Group ba,pt %xcc, 3f ! CTI - st %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store + sth %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store 2: rd %fprs, %l0 ! Single Group+4bubbles andcc %l0, FPRS_FEF, %g0 ! IEU1 Group be,pn %icc, 6f ! CTI @@ -107,7 +107,7 @@ 5: membar #Sync ! Memory 6: wr %g0, 0x0, %fprs ! Single Group+4bubbles wrpr %g0, 0x0, %tl ! Single Group+4bubbles - mov %g1, %l1 ! IEU0 Group + andn %g1, PSTATE_MM, %l1 ! IEU0 Group mov %g4, %l4 ! IEU1 mov %g5, %l5 ! IEU0 Group mov %g7, %l2 ! IEU1 diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.1.78/linux/arch/sparc64/kernel/ioctl32.c Sun Sep 7 13:10:42 1997 +++ linux/arch/sparc64/kernel/ioctl32.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.18 1997/09/06 02:25:13 davem Exp $ +/* $Id: ioctl32.c,v 1.26 1997/12/15 15:11:02 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -19,11 +19,19 @@ #include #include #include +#include #include #include #include #include #include +#include + +#include +/* Ugly hack. */ +#undef __KERNEL__ +#include +#define __KERNEL__ #include #include @@ -44,7 +52,7 @@ static int w_long(unsigned int fd, unsigned int cmd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int err; unsigned long val; @@ -97,16 +105,24 @@ struct ifconf ifc; struct ifreq32 *ifr32; struct ifreq *ifr; - unsigned long old_fs; + mm_segment_t old_fs; unsigned int i, j; int err; if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32))) return -EFAULT; - ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq); - ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); - if (!ifc.ifc_buf) return -ENOMEM; + if(ifc32.ifcbuf == 0) { + ifc32.ifc_len = 0; + ifc.ifc_len = 0; + ifc.ifc_buf = NULL; + } else { + ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * + sizeof (struct ifreq); + ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); + if (!ifc.ifc_buf) + return -ENOMEM; + } ifr = ifc.ifc_req; ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { @@ -137,14 +153,15 @@ err = -EFAULT; } } - kfree (ifc.ifc_buf); + if(ifc.ifc_buf != NULL) + kfree (ifc.ifc_buf); return err; } static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) { struct ifreq ifr; - unsigned long old_fs; + mm_segment_t old_fs; int err; switch (cmd) { @@ -183,7 +200,7 @@ case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: - case SIOGIFINDEX: + case SIOCGIFINDEX: case SIOCGIFADDR: case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: @@ -250,16 +267,10 @@ char devname[16]; u32 rtdev; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); - if (get_user (r.rt_pad1, &(((struct rtentry32 *)A(arg))->rt_pad1)) || - copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) || + if (copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) || __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) || - __get_user (r.rt_pad2, &(((struct rtentry32 *)A(arg))->rt_pad2)) || - __get_user (r.rt_pad3, &(((struct rtentry32 *)A(arg))->rt_pad3)) || - __get_user (r.rt_tos, &(((struct rtentry32 *)A(arg))->rt_tos)) || - __get_user (r.rt_class, &(((struct rtentry32 *)A(arg))->rt_class)) || - __get_user (r.rt_pad4, &(((struct rtentry32 *)A(arg))->rt_pad4)) || __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) || __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) || __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) || @@ -277,116 +288,6 @@ return ret; } -struct nlmsghdr32 { - u32 nlmsg_len; /* Length of message including header */ - u32 nlmsg_type; /* Message type */ - u32 nlmsg_seq; /* Sequence number */ - u32 nlmsg_pid; /* Sending process PID */ - unsigned char nlmsg_data[0]; -}; - -struct in_rtmsg32 { - struct in_addr rtmsg_prefix; - struct in_addr rtmsg_gateway; - unsigned rtmsg_flags; - u32 rtmsg_mtu; - u32 rtmsg_window; - unsigned short rtmsg_rtt; - short rtmsg_metric; - unsigned char rtmsg_tos; - unsigned char rtmsg_class; - unsigned char rtmsg_prefixlen; - unsigned char rtmsg_reserved; - int rtmsg_ifindex; -}; - -struct in_ifmsg32 { - struct sockaddr ifmsg_lladdr; - struct in_addr ifmsg_prefix; - struct in_addr ifmsg_brd; - unsigned ifmsg_flags; - u32 ifmsg_mtu; - short ifmsg_metric; - unsigned char ifmsg_prefixlen; - unsigned char ifmsg_reserved; - int ifmsg_index; - char ifmsg_name[16]; -}; - -static inline int rtmsg_ioctl(unsigned int fd, u32 arg) -{ - struct { - struct nlmsghdr n; - union { - struct in_rtmsg rt; - struct in_ifmsg iff; - struct in_rtctlmsg ctl; - struct in_rtrulemsg rule; - } u; - } nn; - char *p; - int ret; - unsigned long old_fs = get_fs(); - - if (get_user (nn.n.nlmsg_len, &(((struct nlmsghdr32 *)A(arg))->nlmsg_len)) || - __get_user (nn.n.nlmsg_type, &(((struct nlmsghdr32 *)A(arg))->nlmsg_type)) || - __get_user (nn.n.nlmsg_seq, &(((struct nlmsghdr32 *)A(arg))->nlmsg_seq)) || - __get_user (nn.n.nlmsg_pid, &(((struct nlmsghdr32 *)A(arg))->nlmsg_pid)) || - __get_user (nn.n.nlmsg_data[0], &(((struct nlmsghdr32 *)A(arg))->nlmsg_data[0]))) - return -EFAULT; - p = ((char *)(&nn.n)) + sizeof(struct nlmsghdr); - arg += sizeof(struct nlmsghdr32); - switch (nn.n.nlmsg_type) { - case RTMSG_NEWRULE: - case RTMSG_DELRULE: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtrulemsg) - - sizeof(struct in_rtmsg) + sizeof(struct in_rtmsg32)) - return -EINVAL; - if (copy_from_user (p, (struct in_rtrulemsg *)A(arg), sizeof(struct in_rtrulemsg) - sizeof(struct in_rtmsg))) - return -EFAULT; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtrulemsg); - p += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg); - arg += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg); - goto newroute; - case RTMSG_NEWROUTE: - case RTMSG_DELROUTE: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtmsg)) - return -EINVAL; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtmsg); -newroute: - if (copy_from_user (p, (struct in_rtmsg32 *)A(arg), 2*sizeof(struct in_addr) + sizeof(unsigned)) || - __get_user (((struct in_rtmsg *)p)->rtmsg_mtu, &((struct in_rtmsg32 *)A(arg))->rtmsg_mtu) || - __get_user (((struct in_rtmsg *)p)->rtmsg_window, &((struct in_rtmsg32 *)A(arg))->rtmsg_window) || - copy_from_user (&(((struct in_rtmsg *)p)->rtmsg_rtt), &((struct in_rtmsg32 *)A(arg))->rtmsg_rtt, - 2 * sizeof(short) + 4 + sizeof(int))) - return -EFAULT; - break; - case RTMSG_NEWDEVICE: - case RTMSG_DELDEVICE: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_ifmsg)) - return -EINVAL; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_ifmsg); - if (copy_from_user (p, (struct in_ifmsg32 *)A(arg), - sizeof(struct sockaddr) + 2*sizeof(struct in_addr) + sizeof(unsigned)) || - __get_user (((struct in_ifmsg *)p)->ifmsg_mtu, &((struct in_ifmsg32 *)A(arg))->ifmsg_mtu) || - copy_from_user (&(((struct in_ifmsg *)p)->ifmsg_metric), &((struct in_ifmsg32 *)A(arg))->ifmsg_metric, - sizeof(short) + 2 + sizeof(int) + 16)) - return -EFAULT; - break; - case RTMSG_CONTROL: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtctlmsg)) - return -EINVAL; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtctlmsg); - if (copy_from_user (p, (struct in_rtctlmsg *)A(arg), sizeof(struct in_rtctlmsg))) - return -EFAULT; - break; - } - set_fs (KERNEL_DS); - ret = sys_ioctl (fd, SIOCRTMSG, (long)&(nn.n)); - set_fs (old_fs); - return ret; -} - struct hd_geometry32 { unsigned char heads; unsigned char sectors; @@ -396,7 +297,7 @@ static inline int hdio_getgeo(unsigned int fd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); struct hd_geometry geo; int err; @@ -428,7 +329,7 @@ int ret; char red[256], green[256], blue[256]; u32 r, g, b; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); if (get_user(f.index, &(((struct fbcmap32 *)A(arg))->index)) || __get_user(f.count, &(((struct fbcmap32 *)A(arg))->count)) || @@ -480,7 +381,7 @@ char image[128], mask[128]; u32 r, g, b; u32 m, i; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); if (copy_from_user (&f, (struct fbcursor32 *)A(arg), 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)) || __get_user(f.size.fbx, &(((struct fbcursor32 *)A(arg))->size.fbx)) || @@ -516,7 +417,7 @@ static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); unsigned long kval; unsigned int *uvp; int error; @@ -533,6 +434,328 @@ return error; } +struct floppy_struct32 { + unsigned int size; + unsigned int sect; + unsigned int head; + unsigned int track; + unsigned int stretch; + unsigned char gap; + unsigned char rate; + unsigned char spec1; + unsigned char fmt_gap; + const __kernel_caddr_t32 name; +}; + +struct floppy_drive_params32 { + char cmos; + u32 max_dtr; + u32 hlt; + u32 hut; + u32 srt; + u32 spinup; + u32 spindown; + unsigned char spindown_offset; + unsigned char select_delay; + unsigned char rps; + unsigned char tracks; + u32 timeout; + unsigned char interleave_sect; + struct floppy_max_errors max_errors; + char flags; + char read_track; + short autodetect[8]; + int checkfreq; + int native_format; +}; + +struct floppy_drive_struct32 { + signed char flags; + u32 spinup_date; + u32 select_date; + u32 first_read_date; + short probed_format; + short track; + short maxblock; + short maxtrack; + int generation; + int keep_data; + int fd_ref; + int fd_device; + int last_checked; + __kernel_caddr_t32 dmabuf; + int bufblocks; +}; + +struct floppy_fdc_state32 { + int spec1; + int spec2; + int dtr; + unsigned char version; + unsigned char dor; + u32 address; + unsigned int rawcmd:2; + unsigned int reset:1; + unsigned int need_configure:1; + unsigned int perp_mode:2; + unsigned int has_fifo:1; + unsigned int driver_version; + unsigned char track[4]; +}; + +struct floppy_write_errors32 { + unsigned int write_errors; + u32 first_error_sector; + int first_error_generation; + u32 last_error_sector; + int last_error_generation; + unsigned int badness; +}; + +#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) +#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) +#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) +#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) +#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) +#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) +#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) +#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) +#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} fd_ioctl_trans_table[] = { + { FDSETPRM32, FDSETPRM }, + { FDDEFPRM32, FDDEFPRM }, + { FDGETPRM32, FDGETPRM }, + { FDSETDRVPRM32, FDSETDRVPRM }, + { FDGETDRVPRM32, FDGETDRVPRM }, + { FDGETDRVSTAT32, FDGETDRVSTAT }, + { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, + { FDGETFDCSTAT32, FDGETFDCSTAT }, + { FDWERRORGET32, FDWERRORGET } +}; + +#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) + +static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +{ + mm_segment_t old_fs = get_fs(); + void *karg; + unsigned int kcmd = 0; + int i, err; + + for (i = 0; i < NR_FD_IOCTL_TRANS; i++) + if (cmd == fd_ioctl_trans_table[i].cmd32) { + kcmd = fd_ioctl_trans_table[i].cmd; + break; + } + if (!kcmd) + return -EINVAL; + + switch (cmd) { + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + { + struct floppy_struct *f; + + f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_struct)); + if (!karg) + return -ENOMEM; + if (cmd == FDGETPRM32) + break; + if (__get_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || + __get_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || + __get_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || + __get_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || + __get_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || + __get_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || + __get_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || + __get_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || + __get_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || + __get_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDSETDRVPRM32: + case FDGETDRVPRM32: + { + struct floppy_drive_params *f; + + f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_params)); + if (!karg) + return -ENOMEM; + if (cmd == FDGETDRVPRM32) + break; + if (__get_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || + __get_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || + __get_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || + __get_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || + __get_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || + __get_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || + __get_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || + __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || + __get_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || + __get_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || + __get_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || + __get_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || + __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || + __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)A(arg))->max_errors, sizeof(f->max_errors)) || + __get_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || + __get_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || + __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)A(arg))->autodetect, sizeof(f->autodetect)) || + __get_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || + __get_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_struct)); + if (!karg) + return -ENOMEM; + break; + case FDGETFDCSTAT32: + karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_fdc_state)); + if (!karg) + return -ENOMEM; + break; + case FDWERRORGET32: + karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_write_errors)); + if (!karg) + return -ENOMEM; + break; + default: + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) { + kfree(karg); + return err; + } + switch (cmd) { + case FDGETPRM32: + { + struct floppy_struct *f = karg; + + if (__put_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || + __put_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || + __put_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || + __put_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || + __put_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || + __put_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || + __put_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || + __put_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || + __put_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || + __put_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETDRVPRM32: + { + struct floppy_drive_params *f = karg; + + if (__put_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || + __put_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || + __put_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || + __put_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || + __put_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || + __put_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || + __put_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || + __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || + __put_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || + __put_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || + __put_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || + __put_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || + __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || + __copy_to_user(&((struct floppy_drive_params32 *)A(arg))->max_errors, &f->max_errors, sizeof(f->max_errors)) || + __put_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || + __put_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || + __copy_to_user(((struct floppy_drive_params32 *)A(arg))->autodetect, f->autodetect, sizeof(f->autodetect)) || + __put_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || + __put_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + { + struct floppy_drive_struct *f = karg; + + if (__put_user(f->flags, &((struct floppy_drive_struct32 *)A(arg))->flags) || + __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)A(arg))->spinup_date) || + __put_user(f->select_date, &((struct floppy_drive_struct32 *)A(arg))->select_date) || + __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)A(arg))->first_read_date) || + __put_user(f->probed_format, &((struct floppy_drive_struct32 *)A(arg))->probed_format) || + __put_user(f->track, &((struct floppy_drive_struct32 *)A(arg))->track) || + __put_user(f->maxblock, &((struct floppy_drive_struct32 *)A(arg))->maxblock) || + __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)A(arg))->maxtrack) || + __put_user(f->generation, &((struct floppy_drive_struct32 *)A(arg))->generation) || + __put_user(f->keep_data, &((struct floppy_drive_struct32 *)A(arg))->keep_data) || + __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)A(arg))->fd_ref) || + __put_user(f->fd_device, &((struct floppy_drive_struct32 *)A(arg))->fd_device) || + __put_user(f->last_checked, &((struct floppy_drive_struct32 *)A(arg))->last_checked) || + __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)A(arg))->dmabuf) || + __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)A(arg))->bufblocks)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETFDCSTAT32: + { + struct floppy_fdc_state *f = karg; + + if (__put_user(f->spec1, &((struct floppy_fdc_state32 *)A(arg))->spec1) || + __put_user(f->spec2, &((struct floppy_fdc_state32 *)A(arg))->spec2) || + __put_user(f->dtr, &((struct floppy_fdc_state32 *)A(arg))->dtr) || + __put_user(f->version, &((struct floppy_fdc_state32 *)A(arg))->version) || + __put_user(f->dor, &((struct floppy_fdc_state32 *)A(arg))->dor) || + __put_user(f->address, &((struct floppy_fdc_state32 *)A(arg))->address) || + __copy_to_user((char *)&((struct floppy_fdc_state32 *)A(arg))->address + + sizeof(((struct floppy_fdc_state32 *)A(arg))->address), + (char *)&f->address + sizeof(f->address), sizeof(int)) || + __put_user(f->driver_version, &((struct floppy_fdc_state32 *)A(arg))->driver_version) || + __copy_to_user(((struct floppy_fdc_state32 *)A(arg))->track, f->track, sizeof(f->track))) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDWERRORGET32: + { + struct floppy_write_errors *f = karg; + + if (__put_user(f->write_errors, &((struct floppy_write_errors32 *)A(arg))->write_errors) || + __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)A(arg))->first_error_sector) || + __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)A(arg))->first_error_generation) || + __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)A(arg))->last_error_sector) || + __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)A(arg))->last_error_generation) || + __put_user(f->badness, &((struct floppy_write_errors32 *)A(arg))->badness)) { + kfree(karg); + return -EFAULT; + } + break; + } + default: + break; + } + kfree(karg); + return 0; +} + struct ppp_option_data32 { __kernel_caddr_t32 ptr; __u32 length; @@ -540,14 +763,28 @@ }; #define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) -static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +struct ppp_idle32 { + __kernel_time_t32 xmit_idle; + __kernel_time_t32 recv_idle; +}; +#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) + +static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); struct ppp_option_data32 data32; struct ppp_option_data data; - int err; + struct ppp_idle32 idle32; + struct ppp_idle idle; + unsigned int kcmd; + void *karg; + int err = 0; switch (cmd) { + case PPPIOCGIDLE32: + kcmd = PPPIOCGIDLE; + karg = &idle; + break; case PPPIOCSCOMPRESS32: if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32))) return -EFAULT; @@ -555,33 +792,163 @@ if (!data.ptr) return -ENOMEM; if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) { - err = -EFAULT; - goto out; + kfree(data.ptr); + return -EFAULT; } data.length = data32.length; data.transmit = data32.transmit; + kcmd = PPPIOCSCOMPRESS; + karg = &data; break; default: printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", (int)fd, (unsigned int)cmd, (unsigned int)arg); return -EINVAL; } - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&data); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); set_fs (old_fs); - if (err) - goto out; switch (cmd) { + case PPPIOCGIDLE32: + if (err) + return err; + idle32.xmit_idle = idle.xmit_idle; + idle32.recv_idle = idle.recv_idle; + if (copy_to_user((struct ppp_idle32 *)A(arg), &idle32, sizeof(struct ppp_idle32))) + return -EFAULT; + break; case PPPIOCSCOMPRESS32: + kfree(data.ptr); + break; default: break; } -out: - kfree(data.ptr); return err; } + +struct mtget32 { + __u32 mt_type; + __u32 mt_resid; + __u32 mt_dsreg; + __u32 mt_gstat; + __u32 mt_erreg; + __kernel_daddr_t32 mt_fileno; + __kernel_daddr_t32 mt_blkno; +}; +#define MTIOCGET32 _IOR('m', 2, struct mtget32) + +struct mtpos32 { + __u32 mt_blkno; +}; +#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) + +struct mtconfiginfo32 { + __u32 mt_type; + __u32 ifc_type; + __u16 irqnr; + __u16 dmanr; + __u16 port; + __u32 debug; + __u32 have_dens:1; + __u32 have_bsf:1; + __u32 have_fsr:1; + __u32 have_bsr:1; + __u32 have_eod:1; + __u32 have_seek:1; + __u32 have_tell:1; + __u32 have_ras1:1; + __u32 have_ras2:1; + __u32 have_ras3:1; + __u32 have_qfa:1; + __u32 pad1:5; + char reserved[10]; +}; +#define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) +#define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) + +static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +{ + mm_segment_t old_fs = get_fs(); + struct mtconfiginfo info; + struct mtget get; + struct mtpos pos; + unsigned long kcmd; + void *karg; + int err = 0; + + switch(cmd) { + case MTIOCPOS32: + kcmd = MTIOCPOS; + karg = &pos; + break; + case MTIOCGET32: + kcmd = MTIOCGET; + karg = &get; + break; + case MTIOCGETCONFIG32: + kcmd = MTIOCGETCONFIG; + karg = &info; + break; + case MTIOCSETCONFIG32: + kcmd = MTIOCSETCONFIG; + karg = &info; + if (__get_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || + __get_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || + __get_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || + __get_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || + __get_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || + __get_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || + __copy_from_user((char *)&info.debug + sizeof(info.debug), + (char *)&((struct mtconfiginfo32 *)A(arg))->debug + + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), + sizeof(__u32))) + return -EFAULT; + break; + default: + printk("mt_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) + return err; + switch (cmd) { + case MTIOCPOS32: + if (__put_user(pos.mt_blkno, &((struct mtpos32 *)A(arg))->mt_blkno)) + return -EFAULT; + break; + case MTIOCGET32: + if (__put_user(get.mt_type, &((struct mtget32 *)A(arg))->mt_type) || + __put_user(get.mt_resid, &((struct mtget32 *)A(arg))->mt_resid) || + __put_user(get.mt_dsreg, &((struct mtget32 *)A(arg))->mt_dsreg) || + __put_user(get.mt_gstat, &((struct mtget32 *)A(arg))->mt_gstat) || + __put_user(get.mt_erreg, &((struct mtget32 *)A(arg))->mt_erreg) || + __put_user(get.mt_fileno, &((struct mtget32 *)A(arg))->mt_fileno) || + __put_user(get.mt_blkno, &((struct mtget32 *)A(arg))->mt_blkno)) + return -EFAULT; + break; + case MTIOCGETCONFIG32: + if (__put_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || + __put_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || + __put_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || + __put_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || + __put_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || + __put_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || + __copy_to_user((char *)&((struct mtconfiginfo32 *)A(arg))->debug + + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), + (char *)&info.debug + sizeof(info.debug), sizeof(__u32))) + return -EFAULT; + break; + case MTIOCSETCONFIG32: + break; + } + return 0; +} + + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct file * filp; @@ -617,7 +984,7 @@ case SIOCSIFHWADDR: case SIOCADDMULTI: case SIOCDELMULTI: - case SIOGIFINDEX: + case SIOCGIFINDEX: case SIOCGIFMAP: case SIOCSIFMAP: case SIOCGIFADDR: @@ -628,6 +995,8 @@ case SIOCSIFDSTADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: + case SIOCSIFPFLAGS: + case SIOCGIFPFLAGS: case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: @@ -639,10 +1008,12 @@ error = routing_ioctl(fd, cmd, arg); goto out; - case SIOCRTMSG: - error = rtmsg_ioctl(fd, arg); + case SIOCRTMSG: /* Note SIOCRTMSG is no longer, so this is safe and + * the user would have seen just an -EINVAL anyways. + */ + error = -EINVAL; goto out; - + case HDIO_GETGEO: error = hdio_getgeo(fd, arg); goto out; @@ -671,6 +1042,30 @@ error = hdio_ioctl_trans(fd, cmd, arg); goto out; + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + case FDSETDRVPRM32: + case FDGETDRVPRM32: + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + case FDGETFDCSTAT32: + case FDWERRORGET32: + error = fd_ioctl_trans(fd, cmd, (unsigned long)arg); + goto out; + + case PPPIOCGIDLE32: + case PPPIOCSCOMPRESS32: + error = ppp_ioctl_trans(fd, cmd, arg); + goto out; + + case MTIOCGET32: + case MTIOCPOS32: + case MTIOCGETCONFIG32: + case MTIOCSETCONFIG32: + error = mt_ioctl_trans(fd, cmd, arg); + goto out; + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ @@ -751,13 +1146,22 @@ case BLKROGET: /* 0x02 -- Floppy ioctls */ + case FDMSGON: + case FDMSGOFF: case FDSETEMSGTRESH: case FDFLUSH: + case FDWERRORCLR: case FDSETMAXERRS: case FDGETMAXERRS: case FDGETDRVTYP: case FDEJECT: - /* XXX The rest need struct floppy_* translations. */ + case FDCLRPRM: + case FDFMTBEG: + case FDFMTEND: + case FDRESET: + case FDTWADDLE: + case FDFMTTRK: + case FDRAWCMD: /* 0x12 */ case BLKRRPART: @@ -807,6 +1211,15 @@ case KIOCSRATE: case KIOCGRATE: + /* Big S */ + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_DOORLOCK: + case SCSI_IOCTL_DOORUNLOCK: + case SCSI_IOCTL_TEST_UNIT_READY: + case SCSI_IOCTL_TAGGED_ENABLE: + case SCSI_IOCTL_TAGGED_DISABLE: + case SCSI_IOCTL_GET_BUS_NUMBER: + /* Big V */ case VT_SETMODE: case VT_GETMODE: @@ -829,6 +1242,9 @@ case RTCGET: case RTCSET: + /* Little m */ + case MTIOCTOP: + /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have * embedded pointers in the arg which we'd need to clean up... */ @@ -860,9 +1276,11 @@ case SIOCSARP: case SIOCGARP: case SIOCDARP: +#if 0 /* XXX No longer exist in new routing code. XXX */ case OLD_SIOCSARP: case OLD_SIOCGARP: case OLD_SIOCDARP: +#endif case SIOCSRARP: case SIOCGRARP: case SIOCDRARP: @@ -887,12 +1305,7 @@ case PPPIOCSNPMODE: case PPPIOCGDEBUG: case PPPIOCSDEBUG: - case PPPIOCGIDLE: error = sys_ioctl (fd, cmd, (unsigned long)arg); - goto out; - - case PPPIOCSCOMPRESS32: - error = ppp_ioctl (fd, cmd, (unsigned long)arg); goto out; default: diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.1.78/linux/arch/sparc64/kernel/irq.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/irq.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.39 1997/08/31 03:11:18 davem Exp $ +/* $Id: irq.c,v 1.47 1998/01/10 18:26:17 ecd Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -57,6 +57,7 @@ unsigned int ino; unsigned int *imap; unsigned int *iclr; + unsigned char *imap_refcnt; }; #define INO_HASHSZ (NUM_HARD_IVECS >> 2) @@ -114,9 +115,15 @@ } #if 0 #ifdef CONFIG_PCI - len += sprintf(buf + len, "ISTAT: PCI[%016lx] OBIO[%016lx]\n", - psycho_root->psycho_regs->pci_istate, - psycho_root->psycho_regs->obio_istate); + { + struct linux_psycho *p; + for (p = psycho_root; p; p = p->next) + len += sprintf(buf + len, + "ISTAT[%d]: PCI[%016lx] OBIO[%016lx]\n", + p->index, + p->psycho_regs->pci_istate, + p->psycho_regs->obio_istate); + } #endif #endif return len; @@ -229,10 +236,10 @@ 13, /* Audio Record */ 14, /* Audio Playback */ 15, /* PowerFail */ - 12, /* Keyboard/Mouse/Serial */ + 9, /* Keyboard/Mouse/Serial */ 11, /* Floppy */ 2, /* Spare Hardware */ - 12, /* Keyboard */ + 9, /* Keyboard */ 4, /* Mouse */ 12, /* Serial */ 10, /* Timer 0 */ @@ -411,7 +418,7 @@ offset += ((unsigned long)pregs); *imap = ((unsigned int *)offset) + 1; *iclr = (unsigned int *) - (((unsigned long)pregs) + psycho_imap_offset(irq)); + (((unsigned long)pregs) + psycho_iclr_offset(irq)); return; } #endif @@ -449,10 +456,17 @@ unsigned int **imap, unsigned int **iclr, unsigned int irq) { - struct linux_psycho *psycho = psycho_root; - struct psycho_regs *pregs = psycho->psycho_regs; + struct linux_psycho *psycho; + struct psycho_regs *pregs; unsigned long addr, imoff; + psycho = psycho_by_index((irq & PCI_IRQ_BUSNO) >> PCI_IRQ_BUSNO_SHFT); + if (!psycho) { + printk("get_irq_translations: BAD PSYCHO BUSNO[%x]\n", irq); + panic("Bad PSYCHO IRQ frobnication..."); + } + pregs = psycho->psycho_regs; + addr = (unsigned long) &pregs->imap_a_slot0; imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT; addr = addr + imoff; @@ -515,7 +529,7 @@ unsigned long flags; unsigned int *imap, *iclr; void *bus_id = NULL; - int ivindex, ivindex_fixup, cpu_irq = -1; + int ivindex, ivindex_fixup, cpu_irq = -1, pending; if(!handler) return -EINVAL; @@ -605,7 +619,10 @@ return -ENOMEM; } + pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0); ivector_to_mask[ivindex] = (1 << cpu_irq); + if(pending) + ivector_to_mask[ivindex] |= 0x80000000; if(dcookie) { dcookie->ret_ino = ivindex; @@ -625,6 +642,11 @@ *(cpu_irq + irq_action) = action; enable_irq(ivindex); + + /* We ate the IVEC already, this makes sure it does not get lost. */ + if(pending) + set_softint(1 << cpu_irq); + restore_flags(flags); #ifdef __SMP__ if(irqs_have_been_distributed) @@ -638,6 +660,7 @@ struct irqaction *action; struct irqaction *tmp = NULL; unsigned long flags; + unsigned int *imap = NULL; unsigned int cpu_irq; int ivindex = -1; @@ -685,8 +708,8 @@ if(action->flags & SA_IMAP_MASKED) { struct ino_bucket *bucket = (struct ino_bucket *)action->mask; - unsigned int *imap = bucket->imap; + imap = bucket->imap; if(imap != NULL) { ivindex = bucket->ino; ivector_to_mask[ivindex] = 0; @@ -696,8 +719,27 @@ } kfree(action); - if(ivindex != -1) - disable_irq(ivindex); + + if(ivindex != -1) { + struct ino_bucket *bp; + int i, count = 0; + + /* The trick is that we can't turn the thing off when there + * are potentially other sub-irq level references. + */ + if(imap != NULL) { + for(i = 0; i < INO_HASHSZ; i++) { + bp = ino_hash[i]; + while(bp) { + if(bp->imap == imap) + count++; + bp = bp->next; + } + } + } + if(count < 2) + disable_irq(ivindex); + } restore_flags(flags); } @@ -863,12 +905,21 @@ void report_spurious_ivec(struct pt_regs *regs) { extern unsigned long ivec_spurious_cookie; - static int times = 0; +#if 0 printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n", ivec_spurious_cookie, regs->tpc); - if(times++ > 1) - prom_halt(); +#endif + + /* We can actually see this on Ultra/PCI PCI cards, which are bridges + * to other devices. Here a single IMAP enabled potentially multiple + * unique interrupt sources (which each do have a unique ICLR register. + * + * So what we do is just register that the IVEC arrived, when registered + * for real the request_irq() code will check the high bit and signal + * a local CPU interrupt for it. + */ + ivector_to_mask[ivec_spurious_cookie] |= (0x80000000); } void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs) @@ -899,6 +950,7 @@ void handler_irq(int irq, struct pt_regs *regs) { + struct ino_bucket *bucket = NULL; struct irqaction *action; int cpu = smp_processor_id(); @@ -911,20 +963,19 @@ unexpected_irq(irq, 0, regs); } else { do { - struct ino_bucket *bucket = NULL; - unsigned int ino = 0; + unsigned long *swmask = NULL; if(action->flags & SA_IMAP_MASKED) { bucket = (struct ino_bucket *)action->mask; - ino = bucket->ino; - if(!(ivector_to_mask[ino] & 0x80000000)) + swmask = &ivector_to_mask[bucket->ino]; + if(!(*swmask & 0x80000000)) continue; } action->handler(irq, action->dev_id, regs); - if(bucket) { - ivector_to_mask[ino] &= ~(0x80000000); + if(swmask) { + *swmask &= ~(0x80000000); *(bucket->iclr) = SYSIO_ICLR_IDLE; } } while((action = action->next) != NULL); @@ -938,12 +989,14 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) { struct irqaction *action = *(irq + irq_action); + struct ino_bucket *bucket; int cpu = smp_processor_id(); irq_enter(cpu, irq); + bucket = (struct ino_bucket *)action->mask; floppy_interrupt(irq, dev_cookie, regs); - if(action->flags & SA_IMAP_MASKED) - *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE; + ivector_to_mask[bucket->ino] &= ~(0x80000000); + *(bucket->iclr) = SYSIO_ICLR_IDLE; irq_exit(cpu, irq); } #endif @@ -975,28 +1028,60 @@ int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char *name) + unsigned long irqflags, const char *name, void *dev_id) { struct irqaction *action; + struct devid_cookie *dcookie = NULL; + struct ino_bucket *bucket = NULL; unsigned long flags; - unsigned int cpu_irq, *imap, *iclr; - int ivindex = -1; - - /* XXX This really is not the way to do it, the "right way" - * XXX is to have drivers set SA_SBUS or something like that - * XXX in irqflags and we base our decision here on whether - * XXX that flag bit is set or not. - * - * In this case nobody can have a fast interrupt at the level - * where TICK interrupts live. - */ - if(irq == 14) - return -EINVAL; - cpu_irq = sysio_ino_to_pil[irq]; + unsigned int *imap, *iclr; + void *bus_id = NULL; + int ivindex, ivindex_fixup, cpu_irq = -1; if(!handler) return -EINVAL; - imap = sysio_irq_to_imap(irq); + + imap = iclr = NULL; + ivindex_fixup = 0; +#ifdef CONFIG_PCI + if(PCI_IRQ_P(irq)) { + pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); + } else +#endif + if(irqflags & SA_DCOOKIE) { + if(!dev_id) { + printk("request_fast_irq: SA_DCOOKIE but dev_id is NULL!\n"); + panic("Bogus irq registry."); + } + dcookie = dev_id; + dev_id = dcookie->real_dev_id; + cpu_irq = dcookie->pil; + imap = dcookie->imap; + iclr = dcookie->iclr; + bus_id = dcookie->bus_cookie; + get_irq_translations(&cpu_irq, &ivindex_fixup, &imap, + &iclr, bus_id, irqflags, irq); + } else { + /* XXX NOTE: This code is maintained for compatability until I can + * XXX verify that all drivers sparc64 will use are updated + * XXX to use the new IRQ registry dcookie interface. -DaveM + */ + if(irq == 14) + cpu_irq = irq; + else + cpu_irq = sysio_ino_to_pil[irq]; + imap = sysio_irq_to_imap(irq); + if(!imap) { + printk("request_irq: BAD, null imap for old style " + "irq registry IRQ[%x].\n", irq); + panic("Bad IRQ registery..."); + } + iclr = sysio_imap_to_iclr(imap); + } + + ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + ivindex += ivindex_fixup; + action = *(cpu_irq + irq_action); if(action) { if(action->flags & SA_SHIRQ) @@ -1023,28 +1108,35 @@ } install_fast_irq(cpu_irq, handler); - if(imap) { - ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); - ivector_to_mask[ivindex] = (1 << cpu_irq); - iclr = sysio_imap_to_iclr(imap); - action->mask = (unsigned long) iclr; - irqflags |= SA_IMAP_MASKED; - add_ino_hash(ivindex, imap, iclr, irqflags); - } else - action->mask = 0; + bucket = add_ino_hash(ivindex, imap, iclr, irqflags); + if(!bucket) { + kfree(action); + restore_flags(flags); + return -ENOMEM; + } + + ivector_to_mask[ivindex] = (1 << cpu_irq); + if(dcookie) { + dcookie->ret_ino = ivindex; + dcookie->ret_pil = cpu_irq; + } + + action->mask = (unsigned long) bucket; action->handler = handler; - action->flags = irqflags; + action->flags = irqflags | SA_IMAP_MASKED; action->dev_id = NULL; action->name = name; action->next = NULL; *(cpu_irq + irq_action) = action; - - if(ivindex != -1) - enable_irq(ivindex); + enable_irq(ivindex); restore_flags(flags); +#ifdef __SMP__ + if(irqs_have_been_distributed) + distribute_irqs(); +#endif return 0; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/itlb_miss.S linux/arch/sparc64/kernel/itlb_miss.S --- v2.1.78/linux/arch/sparc64/kernel/itlb_miss.S Mon Apr 14 16:28:09 1997 +++ linux/arch/sparc64/kernel/itlb_miss.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: itlb_miss.S,v 1.10 1997/03/26 12:24:18 davem Exp $ +/* $Id: itlb_miss.S,v 1.11 1997/10/14 01:48:25 davem Exp $ * itlb_miss.S: Instruction TLB miss code, this is included directly * into the trap table. * @@ -23,10 +23,10 @@ /*0x24*/ srlx %g1, 1, %g1 ! PTE offset /*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD 2:/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE - /*0x30*/ brlz,a,pt %g5, 1f ! Valid set? - /*0x34*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load - /*0x38*/ ba,a,pt %xcc, sparc64_itlb_refbit_catch ! Nope... -1:/*0x3c*/ retry ! Trap return + /*0x30*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set? + /*0x34*/ nop ! delay + /*0x38*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load + /*0x3c*/ retry ! Trap return 3: /* ICACHE line 3 */ /*0x40*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.1.78/linux/arch/sparc64/kernel/process.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/process.c Mon Jan 12 15:15:44 1998 @@ -1,9 +1,9 @@ -/* $Id: process.c,v 1.42 1997/08/19 14:17:55 jj Exp $ +/* $Id: process.c,v 1.50 1998/01/09 16:39:33 jj Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ /* @@ -39,6 +39,8 @@ #include #include +/* #define VERBOSE_SHOWREGS */ + #define PGTCACHE_HIGH_WATER 50 #define PGTCACHE_LOW_WATER 25 @@ -98,7 +100,7 @@ } barrier(); current->counter = -100; - if(resched_needed()) + if(need_resched) schedule(); barrier(); } @@ -166,7 +168,7 @@ { struct reg_window32 *rw; struct reg_window32 r_w; - unsigned long old_fs; + mm_segment_t old_fs; __asm__ __volatile__ ("flushw"); rw = (struct reg_window32 *)((long)(unsigned)regs->u_regs[14]); @@ -192,7 +194,7 @@ { struct reg_window *rw; struct reg_window r_w; - unsigned long old_fs; + mm_segment_t old_fs; if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) { __asm__ __volatile__ ("flushw"); @@ -311,8 +313,30 @@ #endif } +#ifdef VERBOSE_SHOWREGS +static void idump_from_user (unsigned int *pc) +{ + int i; + int code; + + if((((unsigned long) pc) & 3)) + return; + + pc -= 3; + for(i = -3; i < 6; i++) { + get_user(code, pc); + printk("%c%08x%c",i?' ':'<',code,i?' ':'>'); + pc++; + } + printk("\n"); +} +#endif + void show_regs(struct pt_regs *regs) { +#ifdef VERBOSE_SHOWREGS + extern long etrap, etraptl1; +#endif __show_regs(regs); #ifdef __SMP__ { @@ -321,6 +345,17 @@ smp_report_regs(); } #endif + +#ifdef VERBOSE_SHOWREGS + if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && + regs->u_regs[14] >= (long)current - PAGE_SIZE && + regs->u_regs[14] < (long)current + 6 * PAGE_SIZE) { + printk ("*********parent**********\n"); + __show_regs((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ)); + idump_from_user(((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ))->tpc); + printk ("*********endpar**********\n"); + } +#endif } void show_regs32(struct pt_regs32 *regs) @@ -352,29 +387,35 @@ printk("sig_address: 0x%016lx\n", tss->sig_address); printk("sig_desc: 0x%016lx\n", tss->sig_desc); printk("ksp: 0x%016lx\n", tss->ksp); - printk("kpc: 0x%016lx\n", tss->kpc); + printk("kpc: 0x%08x\n", tss->kpc); - for (i = 0; i < NSWINS; i++) { - if (!tss->rwbuf_stkptrs[i]) - continue; - printk("reg_window[%d]:\n", i); - printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]); + if (tss->w_saved) { + for (i = 0; i < NSWINS; i++) { + if (!tss->rwbuf_stkptrs[i]) + continue; + printk("reg_window[%d]:\n", i); + printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]); + } + printk("w_saved: 0x%04x\n", tss->w_saved); } - printk("w_saved: 0x%08lx\n", tss->w_saved); printk("sstk_info.stack: 0x%016lx\n", (unsigned long)tss->sstk_info.the_stack); printk("sstk_info.status: 0x%016lx\n", (unsigned long)tss->sstk_info.cur_status); printk("flags: 0x%08x\n", tss->flags); - printk("current_ds: 0x%016lx\n", tss->current_ds); - - /* XXX missing: core_exec */ + printk("current_ds: 0x%016lx\n", tss->current_ds.seg); } /* Free current thread data structures etc.. */ void exit_thread(void) { + if (current->tss.utraps) { + if (current->tss.utraps[0] < 2) + kfree (current->tss.utraps); + else + current->tss.utraps[0]--; + } } void flush_thread(void) @@ -540,9 +581,9 @@ memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size); p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; #ifdef __SMP__ - p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8; + p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_smpfork)) - 0x8; #else - p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8; + p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_syscall)) - 0x8; #endif p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP; @@ -569,6 +610,8 @@ return -EFAULT; p->tss.kregs->u_regs[UREG_FP] = csp; } + if (p->tss.utraps) + p->tss.utraps[0]++; } /* Set the return value for the child. */ @@ -595,7 +638,6 @@ dump->regs.y = regs->y; /* fuck me plenty */ memcpy(&dump->regs.regs[0], ®s->u_regs[1], (sizeof(unsigned long) * 15)); - dump->uexec = current->tss.core_exec; dump->u_tsize = (((unsigned long) current->mm->end_code) - ((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1); dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))); diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c --- v2.1.78/linux/arch/sparc64/kernel/psycho.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/psycho.c Mon Jan 12 15:15:44 1998 @@ -1,7 +1,8 @@ -/* $Id: psycho.c,v 1.22 1997/08/31 03:51:40 davem Exp $ +/* $Id: psycho.c,v 1.31 1998/01/10 18:26:15 ecd Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) */ #include @@ -11,6 +12,16 @@ #include #include /* for sanity check... */ +#undef PROM_DEBUG +#undef FIXUP_REGS_DEBUG +#undef FIXUP_IRQ_DEBUG + +#ifdef PROM_DEBUG +#define dprintf prom_printf +#else +#define dprintf printk +#endif + #ifndef CONFIG_PCI int pcibios_present(void) @@ -49,6 +60,28 @@ #include struct linux_psycho *psycho_root = NULL; +struct linux_psycho **psycho_index_map; +int linux_num_psycho = 0; +static struct linux_pbm_info *bus2pbm[256]; + +static int pbm_read_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char *value); +static int pbm_read_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short *value); +static int pbm_read_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int *value); +static int pbm_write_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char value); +static int pbm_write_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short value); +static int pbm_write_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int value); /* This is used to make the scan_bus in the generic PCI code be * a nop, as we need to control the actual bus probing sequence. @@ -69,10 +102,22 @@ unsigned long control, i; unsigned long *iopte; + /* + * Invalidate TLB Entries. + */ + control = psycho->psycho_regs->iommu_control; + control |= IOMMU_CTRL_DENAB; + psycho->psycho_regs->iommu_control = control; + for(i = 0; i < 16; i++) { + psycho->psycho_regs->iommu_data[i] = 0; + } + control &= ~(IOMMU_CTRL_DENAB); + psycho->psycho_regs->iommu_control = control; + memory_start = (tsbbase + ((32 * 1024) * 8)); iopte = (unsigned long *)tsbbase; - for(i = 0; i < (65536 / 2); i++) { + for(i = 0; i < (32 * 1024); i++) { *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); *iopte |= (i << 16); @@ -94,21 +139,26 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) { struct linux_prom64_registers pr_regs[3]; + struct linux_psycho *psycho; char namebuf[128]; u32 portid; int node; printk("PSYCHO: Probing for controllers.\n"); +#ifdef PROM_DEBUG + dprintf("PSYCHO: Probing for controllers.\n"); +#endif memory_start = long_align(memory_start); node = prom_getchild(prom_root_node); while((node = prom_searchsiblings(node, "pci")) != 0) { - struct linux_psycho *psycho = (struct linux_psycho *)memory_start; struct linux_psycho *search; struct linux_pbm_info *pbm = NULL; u32 busrange[2]; int err, is_pbm_a; + psycho = (struct linux_psycho *)memory_start; + portid = prom_getintdefault(node, "upa-portid", 0xff); for(search = psycho_root; search; search = search->next) { if(search->upa_portid == portid) { @@ -123,7 +173,8 @@ } } - memory_start = long_align(memory_start + sizeof(struct linux_psycho)); + memory_start = long_align(memory_start + + sizeof(struct linux_psycho)); memset(psycho, 0, sizeof(*psycho)); @@ -131,8 +182,12 @@ psycho_root = psycho; psycho->upa_portid = portid; + psycho->index = linux_num_psycho++; - /* Map in PSYCHO register set and report the presence of this PSYCHO. */ + /* + * Map in PSYCHO register set and report the presence + * of this PSYCHO. + */ err = prom_getproperty(node, "reg", (char *)&pr_regs[0], sizeof(pr_regs)); if(err == 0 || err == -1) { @@ -141,7 +196,10 @@ prom_halt(); } - /* Third REG in property is base of entire PSYCHO register space. */ + /* + * Third REG in property is base of entire PSYCHO + * register space. + */ psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff), NULL, sizeof(struct psycho_regs), "PSYCHO Registers", @@ -154,12 +212,19 @@ printk("PSYCHO: Found controller, main regs at %p\n", psycho->psycho_regs); -#if 0 - printk("PSYCHO: Interrupt retry [%016lx]\n", - psycho->psycho_regs->irq_retry); +#ifdef PROM_DEBUG + dprintf("PSYCHO: Found controller, main regs at %p\n", + psycho->psycho_regs); #endif + psycho->psycho_regs->irq_retry = 0xff; +#if 0 + psycho->psycho_regs->ecc_control |= 1; + psycho->psycho_regs->sbuf_a_control = 0; + psycho->psycho_regs->sbuf_b_control = 0; +#endif + /* Now map in PCI config space for entire PSYCHO. */ psycho->pci_config_space = sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000), @@ -172,7 +237,12 @@ } /* Report some more info. */ - printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space); + printk("PSYCHO: PCI config space at %p\n", + psycho->pci_config_space); +#ifdef PROM_DEBUG + dprintf("PSYCHO: PCI config space at %p\n", + psycho->pci_config_space); +#endif memory_start = psycho_iommu_init(psycho, memory_start); @@ -223,6 +293,13 @@ prom_halt(); } + psycho_index_map = (struct linux_psycho **)long_align(memory_start); + memory_start = long_align(memory_start + linux_num_psycho + * sizeof(struct linux_psycho *)); + + for (psycho = psycho_root; psycho; psycho = psycho->next) + psycho_index_map[psycho->index] = psycho; + return memory_start; } @@ -361,18 +438,118 @@ return pci_init_alloc(sizeof(struct pcidev_cookie)); } + +static void +pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus) +{ + unsigned int devfn, l, class; + unsigned char hdr_type = 0; + + for (devfn = 0; devfn < 0xff; ++devfn) { + if (PCI_FUNC(devfn) == 0) { + pbm_read_config_byte(pbm, bus, devfn, + PCI_HEADER_TYPE, &hdr_type); + } else if (!(hdr_type & 0x80)) { + /* not a multi-function device */ + continue; + } + + /* Check if there is anything here. */ + pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l); + if (l == 0xffffffff || l == 0x00000000) { + hdr_type = 0; + continue; + } + + /* See if this is a bridge device. */ + pbm_read_config_dword(pbm, bus, devfn, + PCI_CLASS_REVISION, &class); + + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { + unsigned int buses; + + pbm_read_config_dword(pbm, bus, devfn, + PCI_PRIMARY_BUS, &buses); + + /* + * First reconfigure everything underneath the bridge. + */ + pbm_reconfigure_bridges(pbm, (buses >> 8) & 0xff); + + /* + * Unconfigure this bridges bus numbers, + * pci_scan_bus() will fix this up properly. + */ + buses &= 0xff000000; + pbm_write_config_dword(pbm, bus, devfn, + PCI_PRIMARY_BUS, buses); + } + } +} + +static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus) +{ + unsigned int nbus; + + /* + * First, reconfigure all bridge devices underneath this pbm. + */ + pbm_reconfigure_bridges(pbm, pbm->pci_first_busno); + + /* + * Now reconfigure the pbm to it's new bus number and set up + * our bus2pbm mapping for this pbm. + */ + nbus = pbm->pci_last_busno - pbm->pci_first_busno; + + pbm_write_config_byte(pbm, pbm->pci_first_busno, 0, 0x40, bus); + + pbm->pci_first_busno = bus; + pbm_write_config_byte(pbm, bus, 0, 0x41, 0xff); + + do { + bus2pbm[bus++] = pbm; + } while (nbus--); +} + + static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart) { + static struct pci_bus *pchain = NULL; struct pci_bus *pbus = &pbm->pci_bus; + static unsigned char busno = 0; /* PSYCHO PBM's include child PCI bridges in bus-range property, * but we don't scan each of those ourselves, Linux generic PCI * probing code will find child bridges and link them into this * pbm's root PCI device hierarchy. */ - pbus->number = pbm->pci_first_busno; + + pbus->number = pbus->secondary = busno; pbus->sysdata = pbm; + + pbm_fixup_busno(pbm, busno); + pbus->subordinate = pci_scan_bus(pbus, mstart); + + /* + * Set the maximum subordinate bus of this pbm. + */ + pbm->pci_last_busno = pbus->subordinate; + pbm_write_config_byte(pbm, busno, 0, 0x41, pbm->pci_last_busno); + + busno = pbus->subordinate + 1; + + /* + * Fixup the chain of primary PCI busses. + */ + if (pchain) { + pchain->next = &pbm->pci_bus; + pchain = pchain->next; + } else { + pchain = &pci_root; + memcpy(pchain, &pbm->pci_bus, sizeof(pci_root)); + } } static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, @@ -433,8 +610,6 @@ pdev_cookie_fillin(pbm, pdev); } -/* #define RECORD_ASSIGNMENTS_DEBUG */ - /* Walk PROM device tree under PBM, looking for 'assigned-address' * properties, and recording them in pci_vma's linked in via * PBM->assignments. @@ -534,8 +709,6 @@ assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node)); } -/* #define FIXUP_REGS_DEBUG */ - static void fixup_regs(struct pci_dev *pdev, struct linux_pbm_info *pbm, struct linux_prom_pci_registers *pregs, @@ -556,12 +729,14 @@ if(bustype == 0) { /* Config space cookie, nothing to do. */ if(preg != 0) - prom_printf("fixup_doit: strange, config space not 0\n"); + printk("%s: strange, config space not 0\n", + __FUNCTION__); continue; } else if(bustype == 3) { /* XXX add support for this... */ - prom_printf("fixup_doit: Warning, ignoring 64-bit PCI " - "memory space, tell DaveM.\n"); + printk("%s: Warning, ignoring 64-bit PCI memory space, " + "tell Eddie C. Dost (ecd@skynet.be).\n", + __FUNCTION__); continue; } bsreg = (pregs[preg].phys_hi & 0xff); @@ -574,8 +749,13 @@ if((bsreg < PCI_BASE_ADDRESS_0) || (bsreg > (PCI_BASE_ADDRESS_5 + 4)) || (bsreg & 3)) { - prom_printf("fixup_doit: Warning, ignoring bogus basereg [%x]\n", - bsreg); + printk("%s: [%04x:%04x]: " + "Warning, ignoring bogus basereg [%x]\n", + __FUNCTION__, pdev->vendor, pdev->device, bsreg); + printk(" PROM reg: %08x.%08x.%08x %08x.%08x\n", + pregs[preg].phys_hi, pregs[preg].phys_mid, + pregs[preg].phys_lo, pregs[preg].size_hi, + pregs[preg].size_lo); continue; } @@ -740,22 +920,22 @@ pdev->devfn, PCI_COMMAND, &l); #ifdef FIXUP_REGS_DEBUG - prom_printf("["); + dprintf("["); #endif if(IO_seen) { #ifdef FIXUP_REGS_DEBUG - prom_printf("IO "); + dprintf("IO "); #endif l |= PCI_COMMAND_IO; } if(MEM_seen) { #ifdef FIXUP_REGS_DEBUG - prom_printf("MEM"); + dprintf("MEM"); #endif l |= PCI_COMMAND_MEMORY; } #ifdef FIXUP_REGS_DEBUG - prom_printf("]"); + dprintf("]"); #endif pcibios_write_config_dword(pdev->bus->number, pdev->devfn, @@ -763,7 +943,7 @@ } #ifdef FIXUP_REGS_DEBUG - prom_printf("REG_FIXUP[%s]: ", pci_strdev(pdev->vendor, pdev->device)); + dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device); for(preg = 0; preg < 6; preg++) { if(pdev->base_address[preg] != 0) prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]); @@ -814,7 +994,7 @@ } /* Exported for EBUS probing layer. */ -unsigned int psycho_irq_build(unsigned int full_ino) +unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino) { unsigned long imap_off, ign, ino; @@ -906,11 +1086,9 @@ } imap_off -= imap_offset(imap_a_slot0); - return pci_irq_encode(imap_off, 0 /* XXX */, ign, ino); + return pci_irq_encode(imap_off, pbm->parent->index, ign, ino); } -/* #define FIXUP_IRQ_DEBUG */ - static void fixup_irq(struct pci_dev *pdev, struct linux_pbm_info *pbm, int node) @@ -920,24 +1098,30 @@ int err; #ifdef FIXUP_IRQ_DEBUG - printk("fixup_irq[%s:%s]: ", - pci_strvendor(pdev->vendor), - pci_strdev(pdev->vendor, pdev->device)); + dprintf("fixup_irq[%04x:%04x]: ", pdev->vendor, pdev->device); #endif err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq)); if(err == 0 || err == -1) { - prom_printf("fixup_irq: No interrupts property for dev[%s:%s]\n", - pci_strvendor(pdev->vendor), - pci_strdev(pdev->vendor, pdev->device)); + prom_printf("fixup_irq: No interrupts property for dev[%04x:%04x]\n", + pdev->vendor, pdev->device); prom_halt(); } /* See if fully specified already (ie. for onboard devices like hme) */ if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { - pdev->irq = psycho_irq_build(prom_irq); + pdev->irq = psycho_irq_build(pbm, prom_irq); +#ifdef FIXUP_IRQ_DEBUG + dprintf("fully specified prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); +#endif + /* See if onboard device interrupt (i.e. bit 5 set) */ + } else if((prom_irq & PSYCHO_IMAP_INO) & 0x20) { + pdev->irq = psycho_irq_build(pbm, + (pbm->parent->upa_portid << 6) + | prom_irq); #ifdef FIXUP_IRQ_DEBUG - printk("fully specified prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); + dprintf("partially specified prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); #endif } else { unsigned int bus, slot, line; @@ -952,20 +1136,25 @@ if(pbm == &pbm->parent->pbm_A) slot = (pdev->devfn >> 3) - 1; else - slot = ((pdev->devfn >> 3) >> 1) - 1; + slot = (pdev->devfn >> 3) - 2; } else { /* Underneath a bridge, use slot number of parent * bridge. */ - slot = (pdev->bus->self->devfn >> 3) - 1; + if(pbm == &pbm->parent->pbm_A) + slot = (pdev->bus->self->devfn >> 3) - 1; + else + slot = (pdev->bus->self->devfn >> 3) - 2; /* Use low slot number bits of child as IRQ line. */ - line = ((pdev->devfn >> 3) & 3); + line = (line + ((pdev->devfn >> 3) - 4)) % 4; } slot = (slot << 2); - pdev->irq = psycho_irq_build((((portid << 6) & PSYCHO_IMAP_IGN) | - (bus | slot | line))); + pdev->irq = psycho_irq_build(pbm, + (((portid << 6) & PSYCHO_IMAP_IGN) + | (bus | slot | line))); + #ifdef FIXUP_IRQ_DEBUG do { unsigned char iline, ipin; @@ -978,15 +1167,24 @@ pdev->devfn, PCI_INTERRUPT_LINE, &iline); - printk("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] " - "iline[%x] ipin[%x] prom_irq[%x]", - portid, bus>>4, slot>>2, line, pdev->irq, - iline, ipin, prom_irq); + dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] " + "iline[%x] ipin[%x] prom_irq[%x]", + portid, bus>>4, slot>>2, line, pdev->irq, + iline, ipin, prom_irq); } while(0); #endif } + + /* + * Write the INO to config space PCI_INTERRUPT_LINE. + */ + (void)pcibios_write_config_byte(pdev->bus->number, + pdev->devfn, + PCI_INTERRUPT_LINE, + pdev->irq & PCI_IRQ_INO); + #ifdef FIXUP_IRQ_DEBUG - printk("\n"); + dprintf("\n"); #endif } @@ -1093,15 +1291,11 @@ /* Second, fixup base address registers and IRQ lines... */ fixup_addr_irq(&psycho->pbm_A); fixup_addr_irq(&psycho->pbm_B); - -#if 0 - prom_halt(); -#endif } unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end) { - struct linux_psycho *psycho = psycho_root; + struct linux_psycho *psycho; pci_probe_enable = 1; @@ -1117,11 +1311,13 @@ * XXX apps that need to get at PCI configuration space. */ - /* Probe busses under PBM A. */ - pbm_probe(&psycho->pbm_A, &memory_start); + for (psycho = psycho_root; psycho; psycho = psycho->next) { + /* Probe busses under PBM B. */ + pbm_probe(&psycho->pbm_B, &memory_start); - /* Probe busses under PBM B. */ - pbm_probe(&psycho->pbm_B, &memory_start); + /* Probe busses under PBM A. */ + pbm_probe(&psycho->pbm_A, &memory_start); + } pci_init_alloc_init(&memory_start); @@ -1130,15 +1326,17 @@ * sysdata with a pointer to the PBM (for pci_bus's) or * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's). */ - fill_in_pbm_cookies(&psycho->pbm_A); - fill_in_pbm_cookies(&psycho->pbm_B); + for (psycho = psycho_root; psycho; psycho = psycho->next) { + fill_in_pbm_cookies(&psycho->pbm_A); + fill_in_pbm_cookies(&psycho->pbm_B); + + /* See what OBP has taken care of already. */ + record_assignments(&psycho->pbm_A); + record_assignments(&psycho->pbm_B); - /* See what OBP has taken care of already. */ - record_assignments(&psycho->pbm_A); - record_assignments(&psycho->pbm_B); - - /* Now, fix it all up. */ - psycho_final_fixup(psycho); + /* Now, fix it all up. */ + psycho_final_fixup(psycho); + } pci_init_alloc_fini(); @@ -1153,113 +1351,124 @@ * XXX space exists, on Ultra we can have many of them, especially with * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire. */ -static char *pci_mkaddr(unsigned char bus, unsigned char device_fn, - unsigned char where) +static void * +pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus, + unsigned char devfn, unsigned char where) { - unsigned long ret = (unsigned long) psycho_root->pci_config_space; + unsigned long ret; + + if (!pbm) + return NULL; + + ret = (unsigned long) pbm->parent->pci_config_space; ret |= (1 << 24); - ret |= ((bus & 0xff) << 16); - ret |= ((device_fn & 0xff) << 8); - ret |= (where & 0xfc); - return (unsigned char *)ret; + ret |= (bus << 16); + ret |= (devfn << 8); + ret |= where; + + return (void *)ret; } -static inline int out_of_range(unsigned char bus, unsigned char device_fn) +static inline int +out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn) { - return ((bus == 0 && PCI_SLOT(device_fn) > 4) || - (bus == 1 && PCI_SLOT(device_fn) > 6) || + return (((pbm == &pbm->parent->pbm_B) && PCI_SLOT(devfn) > 4) || + ((pbm == &pbm->parent->pbm_A) && PCI_SLOT(devfn) > 6) || (pci_probe_enable == 0)); } -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) -{ - unsigned char *addr = pci_mkaddr(bus, device_fn, where); - unsigned int word, trapped; +static int +pbm_read_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char *value) +{ + unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where); + unsigned int trapped; + unsigned char byte; *value = 0xff; - if(out_of_range(bus, device_fn)) + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (out_of_range(pbm, bus, devfn)) return PCIBIOS_SUCCESSFUL; pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" - "lduwa [%1] %2, %0\n\t" + "lduba [%1] %2, %0\n\t" "membar #Sync" - : "=r" (word) + : "=r" (byte) : "r" (addr), "i" (ASI_PL)); pci_poke_in_progress = 0; trapped = pci_poke_faulted; pci_poke_faulted = 0; - if(!trapped) { - switch(where & 3) { - case 0: - *value = word & 0xff; - break; - case 1: - *value = (word >> 8) & 0xff; - break; - case 2: - *value = (word >> 16) & 0xff; - break; - case 3: - *value = (word >> 24) & 0xff; - break; - }; - } + if(!trapped) + *value = byte; return PCIBIOS_SUCCESSFUL; } -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) -{ - unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where); - unsigned int word, trapped; +static int +pbm_read_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short *value) +{ + unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where); + unsigned int trapped; + unsigned short word; *value = 0xffff; - if(out_of_range(bus, device_fn)) + if (!addr) return PCIBIOS_SUCCESSFUL; + if (out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_read_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" - "lduwa [%1] %2, %0\n\t" + "lduha [%1] %2, %0\n\t" "membar #Sync" : "=r" (word) : "r" (addr), "i" (ASI_PL)); pci_poke_in_progress = 0; trapped = pci_poke_faulted; pci_poke_faulted = 0; - if(!trapped) { - switch(where & 3) { - case 0: - *value = word & 0xffff; - break; - case 2: - *value = (word >> 16) & 0xffff; - break; - default: - printk("pcibios_read_config_word: misaligned " - "reg [%x]\n", where); - break; - }; - } + if(!trapped) + *value = word; return PCIBIOS_SUCCESSFUL; } -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +static int +pbm_read_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int *value) { - unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where); + unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where); unsigned int word, trapped; *value = 0xffffffff; - if(out_of_range(bus, device_fn)) + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_read_config_dword: misaligned reg [%x]\n", + where); return PCIBIOS_SUCCESSFUL; + } pci_poke_in_progress = 1; pci_poke_faulted = 0; @@ -1276,12 +1485,17 @@ return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +static int +pbm_write_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char value) { - unsigned char *addr = pci_mkaddr(bus, device_fn, where); + unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where); - if(out_of_range(bus, device_fn)) + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (out_of_range(pbm, bus, devfn)) return PCIBIOS_SUCCESSFUL; pci_poke_in_progress = 1; @@ -1299,14 +1513,25 @@ return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +static int +pbm_write_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short value) { - unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where); + unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where); - if(out_of_range(bus, device_fn)) + if (!addr) return PCIBIOS_SUCCESSFUL; + if (out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_write_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_poke_in_progress = 1; __asm__ __volatile__("membar #Sync\n\t" "stha %0, [%1] %2\n\t" @@ -1317,14 +1542,25 @@ return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +static int +pbm_write_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int value) { - unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where); + unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where); - if(out_of_range(bus, device_fn)) + if (!addr) return PCIBIOS_SUCCESSFUL; + if (out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_write_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_poke_in_progress = 1; __asm__ __volatile__("membar #Sync\n\t" "stwa %0, [%1] %2\n\t" @@ -1335,6 +1571,42 @@ return PCIBIOS_SUCCESSFUL; } +int pcibios_read_config_byte (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char *value) +{ + return pbm_read_config_byte(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_read_config_word (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short *value) +{ + return pbm_read_config_word(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_read_config_dword (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int *value) +{ + return pbm_read_config_dword(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char value) +{ + return pbm_write_config_byte(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_write_config_word (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short value) +{ + return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int value) +{ + return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value); +} + asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, @@ -1346,19 +1618,22 @@ unsigned int uint; int err = 0; + if(!suser()) + return -EPERM; + lock_kernel(); switch(len) { case 1: pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, buf); + put_user(ubyte, (unsigned char *)buf); break; case 2: pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, buf); + put_user(ushort, (unsigned short *)buf); break; case 4: pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, buf); + put_user(uint, (unsigned int *)buf); break; default: @@ -1380,6 +1655,9 @@ unsigned short ushort; unsigned int uint; int err = 0; + + if(!suser()) + return -EPERM; lock_kernel(); switch(len) { diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.1.78/linux/arch/sparc64/kernel/ptrace.c Mon Aug 18 18:19:45 1997 +++ linux/arch/sparc64/kernel/ptrace.c Mon Jan 12 15:15:44 1998 @@ -309,12 +309,14 @@ } if(offset >= 16 && offset < 784) { offset -= 16; offset >>= 2; - pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); + if (t->w_saved) + pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); return; } if(offset >= 784 && offset < 832) { offset -= 784; offset >>= 2; - pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); + if (t->w_saved) + pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); return; } switch(offset) { @@ -399,12 +401,14 @@ goto failure; if(offset >= 16 && offset < 784) { offset -= 16; offset >>= 2; - *(((unsigned long *)(&t->reg_window[0]))+offset) = value; + if (t->w_saved) + *(((unsigned long *)(&t->reg_window[0]))+offset) = value; goto success; } if(offset >= 784 && offset < 832) { offset -= 784; offset >>= 2; - *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; + if (t->w_saved) + *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; goto success; } switch(offset) { @@ -964,7 +968,7 @@ addr = 1; case PTRACE_CONT: { /* restart after signal. */ - if (data > NSIG) { + if (data > _NSIG) { pt_error_return(regs, EIO); goto out; } @@ -1016,7 +1020,7 @@ } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ - if ((unsigned long) data > NSIG) { + if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); goto out; } @@ -1063,10 +1067,7 @@ current->pid, current->exit_code); #endif if (current->exit_code) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= (1 << (current->exit_code - 1)); - spin_unlock_irq(¤t->sigmask_lock); + send_sig (current->exit_code, current, 1); + current->exit_code = 0; } - - current->exit_code = 0; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.1.78/linux/arch/sparc64/kernel/rtrap.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/rtrap.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.33 1997/08/21 09:13:22 davem Exp $ +/* $Id: rtrap.S,v 1.37 1997/12/11 15:14:54 jj Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -55,11 +55,11 @@ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 1: membar #Sync ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr -rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 +rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2 ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 - mov %g6, %l6 + mov %g6, %o5 ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4 ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5 ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6 @@ -88,10 +88,10 @@ wrpr %o2, %g0, %tnpc mov PRIMARY_CONTEXT, %l7 brnz,pn %l3, kern_rtt - mov SECONDARY_CONTEXT, %l5 + mov SECONDARY_CONTEXT, %o4 stxa %l0, [%l7] ASI_DMMU - stxa %l0, [%l5] ASI_DMMU - flush %l6 + stxa %l0, [%o4] ASI_DMMU + flush %o5 rdpr %wstate, %l1 rdpr %otherwin, %l2 @@ -106,30 +106,25 @@ retry kern_rtt: restore retry -to_user: lduw [%g6 + AOFF_task_processor], %o0 - mov 1, %o1 - sethi %hi(need_resched), %l0 +to_user: sethi %hi(need_resched), %l0 ldx [%l0 + %lo(need_resched)], %l0 - sllx %o1, %o0, %o1 wrpr %l7, PSTATE_IE, %pstate - andcc %o1, %l0, %g0 - be,pt %xcc, check_signal - ldx [%g6 + AOFF_task_signal], %l0 + orcc %g0, %l0, %g0 + be,a,pt %xcc, check_signal + lduw [%g6 + AOFF_task_sigpending], %l0 call schedule nop - ldx [%g6 + AOFF_task_signal], %l0 - nop -check_signal: ldx [%g6 + AOFF_task_blocked], %o0 - ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 - andncc %l0, %o0, %g0 - be,pt %xcc, check_user_wins - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + lduw [%g6 + AOFF_task_sigpending], %l0 +check_signal: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 + brz,a,pt %l0, check_user_wins + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + clr %o0 mov %l5, %o2 mov %l6, %o3 call do_signal add %sp, STACK_BIAS + REGWIN_SZ, %o1 - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 clr %l6 check_user_wins:brz,pt %o2, 1f sethi %hi(TSTATE_PEF), %o3 @@ -142,7 +137,7 @@ be,a,pt %icc, rt_continue andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3 - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2 + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2 wr %g0, FPRS_FEF, %fprs wr %o3, 0, %gsr andcc %l2, SPARC_FLAG_USEDFPUL, %g0 diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.1.78/linux/arch/sparc64/kernel/setup.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/setup.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.12 1997/08/28 02:23:19 ecd Exp $ +/* $Id: setup.c,v 1.18 1997/12/18 02:43:00 ecd Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -37,6 +37,10 @@ #include #include +#ifdef CONFIG_IP_PNP +#include +#endif + struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ { 0, 0, }, /* unused */ @@ -236,20 +240,35 @@ char saved_command_line[256]; char reboot_command[256]; -#ifdef CONFIG_ROOT_NFS -extern char nfs_root_addrs[]; -#endif - unsigned long phys_base; static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; +#if 0 +#include + +static void prom_cons_write(struct console *con, const char *str, unsigned count) +{ + while (count--) + prom_printf("%c", *str++); +} + +static struct console prom_console = { + "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0 +}; +#endif + __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { + extern int serial_console; /* in console.c, of course */ unsigned long lowest_paddr; int total, i; +#if 0 + register_console(&prom_console); +#endif + /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); @@ -330,62 +349,58 @@ init_task.mm->context = (unsigned long) NO_CONTEXT; init_task.tss.kregs = &fake_swapper_regs; -#ifdef CONFIG_ROOT_NFS - if (!*nfs_root_addrs) { +#ifdef CONFIG_IP_PNP + if (!ic_set_manually) { int chosen = prom_finddevice ("/chosen"); u32 cl, sv, gw; - char *p = nfs_root_addrs; cl = prom_getintdefault (chosen, "client-ip", 0); sv = prom_getintdefault (chosen, "server-ip", 0); gw = prom_getintdefault (chosen, "gateway-ip", 0); if (cl && sv) { - strcpy (p, in_ntoa (cl)); - p += strlen (p); - *p++ = ':'; - strcpy (p, in_ntoa (sv)); - p += strlen (p); - *p++ = ':'; - if (gw) { - strcpy (p, in_ntoa (gw)); - p += strlen (p); - } - strcpy (p, "::::none"); + ic_myaddr = cl; + ic_servaddr = sv; + if (gw) + ic_gateway = gw; + ic_bootp_flag = ic_rarp_flag = 0; } } #endif #ifdef CONFIG_SUN_SERIAL - *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ -#endif - { - extern int serial_console; /* in console.c, of course */ -#if !CONFIG_SUN_SERIAL - serial_console = 0; -#else - switch (console_fb) { - case 0: /* Let's get our io devices from prom */ - { - int idev = prom_query_input_device(); - int odev = prom_query_output_device(); - if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { - serial_console = 0; - } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { - serial_console = 1; - } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { - serial_console = 2; - } else { - prom_printf("Inconsistent console\n"); - prom_halt(); - } + switch (console_fb) { + case 0: /* Let's get our io devices from prom */ + { + int idev = prom_query_input_device(); + int odev = prom_query_output_device(); + if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { + serial_console = 0; + } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { + serial_console = 1; + } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { + serial_console = 2; + } else { + prom_printf("Inconsistent console: " + "input %d, output %d\n", + idev, odev); + prom_halt(); } - break; - case 1: serial_console = 0; break; /* Force one of the framebuffers as console */ - case 2: serial_console = 1; break; /* Force ttya as console */ - case 3: serial_console = 2; break; /* Force ttyb as console */ } -#endif + break; + case 1: /* Force one of the framebuffers as console */ + serial_console = 0; + break; + case 2: /* Force ttya as console */ + serial_console = 1; + break; + case 3: /* Force ttyb as console */ + serial_console = 2; + break; } + *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ +#else + serial_console = 0; +#endif } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.1.78/linux/arch/sparc64/kernel/signal.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/signal.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.24 1997/09/02 20:53:03 davem Exp $ +/* $Id: signal.c,v 1.27 1997/12/15 15:04:44 jj Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -26,15 +26,14 @@ #include #include #include +#include -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_o0, int ret_from_syscall); /* This turned off for production... */ @@ -61,8 +60,20 @@ if((pc | npc) & 3) goto do_sigsegv; if(regs->u_regs[UREG_I1]) { - __get_user(current->blocked, &ucp->uc_sigmask); - current->blocked &= _BLOCKABLE; + sigset_t set; + + if (_NSIG_WORDS == 1) { + if (__get_user(set.sig[0], &ucp->uc_sigmask.sig[0])) + goto do_sigsegv; + } else { + if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(sigset_t))) + goto do_sigsegv; + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); } regs->tpc = pc; regs->tnpc = npc; @@ -132,7 +143,11 @@ regs->tpc = regs->tnpc; regs->tnpc += 4; - __put_user(current->blocked, &ucp->uc_sigmask); + if (_NSIG_WORDS == 1) + __put_user(current->blocked.sig[0], (unsigned long *)&ucp->uc_sigmask); + else + __copy_to_user(&ucp->uc_sigmask, ¤t->blocked, sizeof(sigset_t)); + __put_user(regs->tstate, &((*grp)[MC_TSTATE])); __put_user(regs->tpc, &((*grp)[MC_PC])); __put_user(regs->tnpc, &((*grp)[MC_NPC])); @@ -198,31 +213,45 @@ __siginfo_t info; __siginfo_fpu_t * fpu_save; unsigned int insns [2]; + unsigned long extramask[_NSIG_WORDS-1]; + __siginfo_fpu_t fpu_state; +}; + +struct rt_signal_frame { + struct sparc_stackf ss; + siginfo_t info; + struct pt_regs regs; + sigset_t mask; + __siginfo_fpu_t * fpu_save; + unsigned int insns [2]; __siginfo_fpu_t fpu_state; }; /* Align macros */ #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) +#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) /* * atomically swap in the new signal mask, and wait for a signal. * This is really tricky on the Sparc, watch out... */ -asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs) +asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs) { - unsigned long mask; + sigset_t saveset; #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { - extern asmlinkage void _sigpause32_common(unsigned int, + extern asmlinkage void _sigpause32_common(old_sigset_t32, struct pt_regs *); _sigpause32_common(set, regs); return; } #endif + set &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, set); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->tpc = regs->tnpc; @@ -242,7 +271,7 @@ */ regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); regs->u_regs[UREG_I0] = EINTR; - if (do_signal(mask, regs, 0, 0)) + if (do_signal(&saveset, regs, 0, 0)) return; } } @@ -257,6 +286,50 @@ _sigpause_common(regs->u_regs[UREG_I0], regs); } +asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, struct pt_regs *regs) +{ + sigset_t oldset, set; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) { + regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); + regs->u_regs[UREG_I0] = EINVAL; + return; + } + if (copy_from_user(&set, uset, sizeof(set))) { + regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); + regs->u_regs[UREG_I0] = EFAULT; + return; + } + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->tpc = regs->tnpc; + regs->tnpc += 4; + + /* Condition codes and return value where set here for sigpause, + * and so got used by setup_frame, which again causes sigreturn() + * to return -EINTR. + */ + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + /* + * Return -EINTR and set condition code here, + * so the interrupted system call actually returns + * these. + */ + regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); + regs->u_regs[UREG_I0] = EINTR; + if (do_signal(&oldset, regs, 0, 0)) + return; + } +} static inline void restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) @@ -282,47 +355,100 @@ struct new_signal_frame *sf; unsigned long tpc, tnpc, tstate; __siginfo_fpu_t *fpu_save; - unsigned long mask; + sigset_t set; -#ifdef CONFIG_SPARC32_COMPAT - if (current->tss.flags & SPARC_FLAG_32BIT) { - extern asmlinkage void do_sigreturn32(struct pt_regs *); - return do_sigreturn32(regs); - } -#endif synchronize_user_stack (); sf = (struct new_signal_frame *) (regs->u_regs [UREG_FP] + STACK_BIAS); /* 1. Make sure we are not getting garbage from the user */ - if (verify_area (VERIFY_READ, sf, sizeof (*sf))) + if (((unsigned long) sf) & 3) + goto segv; + + if (get_user(tpc, &sf->info.si_regs.tpc) || + __get_user(tnpc, &sf->info.si_regs.tnpc) || + ((tpc | tnpc) & 3)) + goto segv; + + regs->tpc = tpc; + regs->tnpc = tnpc; + + /* 2. Restore the state */ + if (__get_user(regs->y, &sf->info.si_regs.y) || + __get_user(tstate, &sf->info.si_regs.tstate) || + copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs))) + goto segv; + + /* User can only change condition codes in %tstate. */ + regs->tstate &= ~(TSTATE_ICC); + regs->tstate |= (tstate & TSTATE_ICC); + + if (__get_user(fpu_save, &sf->fpu_save)) + goto segv; + if (fpu_save) + restore_fpu_state(regs, &sf->fpu_state); + if (__get_user(set.sig[0], &sf->info.si_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &sf->extramask, + sizeof(sf->extramask)))) goto segv; + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + return; +segv: + lock_kernel(); + do_exit(SIGSEGV); +} + +void do_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_signal_frame *sf; + unsigned long tpc, tnpc, tstate; + __siginfo_fpu_t *fpu_save; + sigset_t set; + + synchronize_user_stack (); + sf = (struct rt_signal_frame *) + (regs->u_regs [UREG_FP] + STACK_BIAS); + + /* 1. Make sure we are not getting garbage from the user */ if (((unsigned long) sf) & 3) goto segv; - get_user(tpc, &sf->info.si_regs.tpc); - __get_user(tnpc, &sf->info.si_regs.tnpc); - if ((tpc | tnpc) & 3) + if (get_user(tpc, &sf->regs.tpc) || + __get_user(tnpc, &sf->regs.tnpc) || + ((tpc | tnpc) & 3)) goto segv; regs->tpc = tpc; regs->tnpc = tnpc; /* 2. Restore the state */ - __get_user(regs->y, &sf->info.si_regs.y); - __get_user(tstate, &sf->info.si_regs.tstate); - copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs)); + if (__get_user(regs->y, &sf->regs.y) || + __get_user(tstate, &sf->regs.tstate) || + copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs))) + goto segv; /* User can only change condition codes in %tstate. */ regs->tstate &= ~(TSTATE_ICC); regs->tstate |= (tstate & TSTATE_ICC); - __get_user(fpu_save, &sf->fpu_save); + if (__get_user(fpu_save, &sf->fpu_save)) + goto segv; if (fpu_save) restore_fpu_state(regs, &sf->fpu_state); - __get_user(mask, &sf->info.si_mask); - current->blocked = mask & _BLOCKABLE; + + if (__copy_from_user(&set, &sf->mask, sizeof(sigset_t))) + goto segv; + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); return; segv: lock_kernel(); @@ -364,8 +490,8 @@ } static inline void -new_setup_frame(struct sigaction *sa, struct pt_regs *regs, - int signo, unsigned long oldmask) +new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct new_signal_frame *sf; int sigframe_size; @@ -398,33 +524,122 @@ __put_user(0, &sf->fpu_save); } - __put_user(oldmask, &sf->info.si_mask); + __put_user(oldset->sig[0], &sf->info.si_mask); + if (_NSIG_WORDS > 1) + __copy_to_user(sf->extramask, &oldset->sig[1], sizeof(sf->extramask)); copy_in_user((u64 *)sf, (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), sizeof(struct reg_window)); - /* 3. return to kernel instructions */ - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */ + /* 3. signal handler back-trampoline and parameters */ + regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; + regs->u_regs[UREG_I0] = signo; + regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + + /* 5. signal handler */ + regs->tpc = (unsigned long) ka->sa.sa_handler; + regs->tnpc = (regs->tpc + 4); + + /* 4. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ + unsigned long address = ((unsigned long)&(sf->insns[0])); + pgd_t *pgdp = pgd_offset(current->mm, address); + pmd_t *pmdp = pmd_offset(pgdp, address); + pte_t *ptep = pte_offset(pmdp, address); + + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */ + + if(pte_present(*ptep)) { + unsigned long page = pte_page(*ptep); + + __asm__ __volatile__(" + membar #StoreStore + flush %0 + %1" + : : "r" (page), "r" (address & (PAGE_SIZE - 1)) + : "memory"); + } + } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); +} + +static inline void +setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset, siginfo_t *info) +{ + struct rt_signal_frame *sf; + int sigframe_size; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + sigframe_size = RT_ALIGNEDSZ; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + sigframe_size -= sizeof(__siginfo_fpu_t); - /* 4. signal handler back-trampoline and parameters */ + sf = (struct rt_signal_frame *) + (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size); + + if (invalid_frame_pointer (sf, sigframe_size)) + goto sigill; + + if (current->tss.w_saved != 0) { + printk ("%s[%d]: Invalid user stack frame for " + "signal delivery.\n", current->comm, current->pid); + goto sigill; + } + + /* 2. Save the current process state */ + copy_to_user(&sf->regs, regs, sizeof (*regs)); + + if (current->tss.flags & SPARC_FLAG_USEDFPU) { + save_fpu_state(regs, &sf->fpu_state); + __put_user((u64)&sf->fpu_state, &sf->fpu_save); + } else { + __put_user(0, &sf->fpu_save); + } + + copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); + + copy_in_user((u64 *)sf, + (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), + sizeof(struct reg_window)); + + copy_to_user(&sf->info, info, sizeof(siginfo_t)); + + /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; - regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); /* 5. signal handler */ - regs->tpc = (unsigned long) sa->sa_handler; + regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); - /* Flush instruction space. */ - { + /* 4. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); pmd_t *pmdp = pmd_offset(pgdp, address); pte_t *ptep = pte_offset(pmdp, address); + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x82102065, &sf->insns[0]); /* mov __NR_rt_sigreturn, %g1 */ + __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */ + if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -442,15 +657,21 @@ do_exit(SIGILL); } -static inline void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs) +static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, + siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) { - new_setup_frame(sa, regs, signr, oldmask); - if(sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) { + if(ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(ka, regs, signr, oldset, info); + else + new_setup_frame(ka, regs, signr, oldset); + if(ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + if(!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sigmask_lock); - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,signr); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } } @@ -479,28 +700,30 @@ * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, - unsigned long orig_i0, int restart_syscall) +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, + unsigned long orig_i0, int restart_syscall) { - unsigned long signr, mask = ~current->blocked; - struct sigaction *sa; + unsigned long signr; + siginfo_t info; + struct k_sigaction *ka; + + if (!oldset) + oldset = ¤t->blocked; #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { - extern asmlinkage int do_signal32(unsigned long, struct pt_regs *, + extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *, unsigned long, int); - return do_signal32(oldmask, regs, orig_i0, restart_syscall); + return do_signal32(oldset, regs, orig_i0, restart_syscall); } #endif - while ((signr = current->signal & mask) != 0) { - signr = ffz(~signr); - + for (;;) { spin_lock_irq(¤t->sigmask_lock); - current->signal &= ~(1 << signr); + signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) break; - sa = current->sig->action + signr; - signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; @@ -511,15 +734,26 @@ current->exit_code = 0; if (signr == SIGSTOP) continue; - if (_S(signr) & current->blocked) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr); - spin_unlock_irq(¤t->sigmask_lock); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if(sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + + if(ka->sa.sa_handler == SIG_IGN) { if(signr != SIGCHLD) continue; @@ -532,7 +766,9 @@ ; continue; } - if(sa->sa_handler == SIG_DFL) { + if(ka->sa.sa_handler == SIG_DFL) { + unsigned long exit_code = signr; + if(current->pid == 1) continue; switch(signr) { @@ -548,7 +784,7 @@ continue; current->state = TASK_STOPPED; current->exit_code = signr; - if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); @@ -559,7 +795,7 @@ if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); if(current->binfmt->core_dump(signr, regs)) - signr |= 0x80; + exit_code |= 0x80; unlock_kernel(); } #ifdef DEBUG_SIGNALS @@ -569,20 +805,16 @@ #endif /* fall through */ default: - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); - - current->flags |= PF_SIGNALED; - lock_kernel(); - do_exit(signr); - unlock_kernel(); + sigaddset(¤t->signal, signr); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOT REACHED */ } } if(restart_syscall) - syscall_restart(orig_i0, regs, sa); - handle_signal(signr, sa, oldmask, regs); + syscall_restart(orig_i0, regs, &ka->sa); + handle_signal(signr, ka, &info, oldset, regs); return 1; } if(restart_syscall && diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.1.78/linux/arch/sparc64/kernel/signal32.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/signal32.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.30 1997/08/29 15:51:33 jj Exp $ +/* $Id: signal32.c,v 1.34 1997/12/15 15:04:49 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -26,14 +26,12 @@ #include #include -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); -asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, +asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs, unsigned long orig_o0, int ret_from_syscall); /* This turned off for production... */ @@ -60,6 +58,7 @@ /* struct sigcontext32 * */ u32 sig_scptr; int sig_address; struct sigcontext32 sig_context; + unsigned extramask[_NSIG_WORDS32 - 1]; }; /* @@ -72,24 +71,38 @@ __siginfo32_t info; /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; + unsigned extramask[_NSIG_WORDS32 - 1]; + __siginfo_fpu_t fpu_state; +}; + +struct rt_signal_frame32 { + struct sparc_stackf32 ss; + siginfo_t32 info; + struct pt_regs32 regs; + sigset_t32 mask; + /* __siginfo_fpu32_t * */ u32 fpu_save; + unsigned int insns [2]; __siginfo_fpu_t fpu_state; }; /* Align macros */ #define SF_ALIGNEDSZ (((sizeof(struct signal_sframe32) + 7) & (~7))) #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) +#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) /* * atomically swap in the new signal mask, and wait for a signal. * This is really tricky on the Sparc, watch out... */ -asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs) +asmlinkage void _sigpause32_common(old_sigset_t32 set, struct pt_regs *regs) { - unsigned int mask; + sigset_t saveset; + set &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, set); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->tpc = regs->tnpc; @@ -109,7 +122,58 @@ */ regs->tstate |= TSTATE_ICARRY; regs->u_regs[UREG_I0] = EINTR; - if (do_signal32(mask, regs, 0, 0)) + if (do_signal32(&saveset, regs, 0, 0)) + return; + } +} + +asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs *regs) +{ + sigset_t oldset, set; + sigset_t32 set32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (((__kernel_size_t32)sigsetsize) != sizeof(sigset_t)) { + regs->tstate |= TSTATE_ICARRY; + regs->u_regs[UREG_I0] = EINVAL; + return; + } + if (copy_from_user(&set32, (void *)(long)uset, sizeof(set32))) { + regs->tstate |= TSTATE_ICARRY; + regs->u_regs[UREG_I0] = EFAULT; + return; + } + switch (_NSIG_WORDS) { + case 4: set.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32); + case 3: set.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32); + case 2: set.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32); + case 1: set.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->tpc = regs->tnpc; + regs->tnpc += 4; + + /* Condition codes and return value where set here for sigpause, + * and so got used by setup_frame, which again causes sigreturn() + * to return -EINTR. + */ + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + /* + * Return -EINTR and set condition code here, + * so the interrupted system call actually returns + * these. + */ + regs->tstate |= TSTATE_ICARRY; + regs->u_regs[UREG_I0] = EINTR; + if (do_signal32(&oldset, regs, 0, 0)) return; } } @@ -134,7 +198,9 @@ { struct new_signal_frame32 *sf; unsigned int psr; - unsigned pc, npc, fpu_save, mask; + unsigned pc, npc, fpu_save; + sigset_t set; + unsigned seta[_NSIG_WORDS32]; regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; @@ -177,16 +243,23 @@ regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); -#if 0 - if (psr & PSR_EF) - regs->tstate |= TSTATE_PEF; -#endif - __get_user(fpu_save, &sf->fpu_save); if (fpu_save) restore_fpu_state32(regs, &sf->fpu_state); - __get_user(mask, &sf->info.si_mask); - current->blocked = mask & _BLOCKABLE; + if (__get_user(seta[0], &sf->info.si_mask) || + copy_from_user(seta+1, &sf->extramask, (_NSIG_WORDS32 - 1) * sizeof(unsigned))) + goto segv; + switch (_NSIG_WORDS) { + case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); + case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32); + case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32); + case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); return; segv: lock_kernel(); @@ -197,7 +270,8 @@ { struct sigcontext32 *scptr; unsigned pc, npc, psr; - unsigned long mask; + sigset_t set; + unsigned seta[_NSIG_WORDS32]; synchronize_user_stack(); if (current->tss.new_signal) @@ -216,8 +290,22 @@ if((pc | npc) & 3) goto segv; /* Nice try. */ - __get_user(mask, &scptr->sigc_mask); - current->blocked = (mask & _BLOCKABLE); + if (__get_user(seta[0], &scptr->sigc_mask) || + /* Note that scptr + 1 points to extramask */ + copy_from_user(seta+1, scptr + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned))) + goto segv; + switch (_NSIG_WORDS) { + case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); + case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32); + case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32); + case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + __get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack); current->tss.sstk_info.cur_status &= 1; regs->tpc = pc; @@ -236,6 +324,78 @@ do_exit (SIGSEGV); } +asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) +{ + struct rt_signal_frame32 *sf; + unsigned int psr; + unsigned pc, npc, fpu_save; + sigset_t set; + sigset_t32 seta; + + synchronize_user_stack(); + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; + sf = (struct rt_signal_frame32 *) regs->u_regs [UREG_FP]; + + /* 1. Make sure we are not getting garbage from the user */ + if (verify_area (VERIFY_READ, sf, sizeof (*sf)) || + (((unsigned long) sf) & 3)) + goto segv; + + get_user(pc, &sf->regs.pc); + __get_user(npc, &sf->regs.npc); + + if ((pc | npc) & 3) + goto segv; + + regs->tpc = pc; + regs->tnpc = npc; + + /* 2. Restore the state */ + __get_user(regs->y, &sf->regs.y); + __get_user(psr, &sf->regs.psr); + + __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]); + __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]); + __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]); + __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]); + __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]); + __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]); + __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]); + __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]); + __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]); + __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]); + __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]); + __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]); + __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]); + __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]); + __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]); + + /* User can only change condition codes in %tstate. */ + regs->tstate &= ~(TSTATE_ICC); + regs->tstate |= psr_to_tstate_icc(psr); + + __get_user(fpu_save, &sf->fpu_save); + if (fpu_save) + restore_fpu_state32(regs, &sf->fpu_state); + if (copy_from_user(&seta, &sf->mask, sizeof(sigset_t32))) + goto segv; + switch (_NSIG_WORDS) { + case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32); + case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32); + case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32); + case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + return; +segv: + lock_kernel(); + do_exit(SIGSEGV); +} + /* Checks if the fp is valid */ static int invalid_frame_pointer(void *fp, int fplen) { @@ -246,10 +406,12 @@ static void setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, - struct pt_regs *regs, int signr, unsigned long oldmask) + struct pt_regs *regs, int signr, sigset_t *oldset) { struct signal_sframe32 *sframep; struct sigcontext32 *sc; + unsigned seta[_NSIG_WORDS32]; + #if 0 int window = 0; #endif @@ -278,7 +440,19 @@ /* We've already made sure frame pointer isn't in kernel space... */ __put_user(old_status, &sc->sigc_onstack); - __put_user(oldmask, &sc->sigc_mask); + + switch (_NSIG_WORDS) { + case 4: seta[7] = (oldset->sig[3] >> 32); + seta[6] = oldset->sig[3]; + case 3: seta[5] = (oldset->sig[2] >> 32); + seta[4] = oldset->sig[2]; + case 2: seta[3] = (oldset->sig[1] >> 32); + seta[2] = oldset->sig[1]; + case 1: seta[1] = (oldset->sig[0] >> 32); + seta[0] = oldset->sig[0]; + } + __put_user(seta[0], &sc->sigc_mask); + __copy_to_user(sframep->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); __put_user(pc, &sc->sigc_pc); __put_user(npc, &sc->sigc_npc); @@ -346,13 +520,14 @@ regs->tstate &= ~TSTATE_PEF; } -static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, - int signo, unsigned long oldmask) +static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct new_signal_frame32 *sf; int sigframe_size; u32 psr; int i; + unsigned seta[_NSIG_WORDS32]; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -397,33 +572,47 @@ __put_user(0, &sf->fpu_save); } - __put_user(oldmask, &sf->info.si_mask); + switch (_NSIG_WORDS) { + case 4: seta[7] = (oldset->sig[3] >> 32); + seta[6] = oldset->sig[3]; + case 3: seta[5] = (oldset->sig[2] >> 32); + seta[4] = oldset->sig[2]; + case 2: seta[3] = (oldset->sig[1] >> 32); + seta[2] = oldset->sig[1]; + case 1: seta[1] = (oldset->sig[0] >> 32); + seta[0] = oldset->sig[0]; + } + __put_user(seta[0], &sf->info.si_mask); + __copy_to_user(sf->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); copy_in_user((u32 *)sf, (u32 *)(regs->u_regs[UREG_FP]), sizeof(struct reg_window32)); - /* 3. return to kernel instructions */ - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ - - /* 4. signal handler back-trampoline and parameters */ + /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; - regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); - /* 5. signal handler */ - regs->tpc = (unsigned long) sa->sa_handler; + /* 4. signal handler */ + regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); - /* Flush instruction space. */ - { + /* 5. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); pmd_t *pmdp = pmd_offset(pgdp, address); pte_t *ptep = pte_offset(pmdp, address); + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -444,7 +633,7 @@ /* Setup a Solaris stack frame */ static inline void setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, - struct pt_regs *regs, int signr, unsigned long oldmask) + struct pt_regs *regs, int signr, sigset_t *oldset) { svr4_signal_frame_t *sfp; svr4_gregset_t *gr; @@ -452,6 +641,7 @@ svr4_mcontext_t *mc; svr4_gwindows_t *gw; svr4_ucontext_t *uc; + svr4_sigset_t setv; #if 0 int window = 0; #endif @@ -485,8 +675,15 @@ * sc->sigc_onstack = old_status; * anyways, it does not look like it is used for anything at all. */ - __put_user(oldmask, &uc->sigmask.sigbits [0]); - + setv.sigbits[0] = oldset->sig[0]; + setv.sigbits[1] = (oldset->sig[0] >> 32); + if (_NSIG_WORDS >= 2) { + setv.sigbits[2] = oldset->sig[1]; + setv.sigbits[3] = (oldset->sig[1] >> 32); + __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + } else + __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); + /* Store registers */ __put_user(regs->tpc, &((*gr) [SVR4_PC])); __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); @@ -572,11 +769,12 @@ { svr4_gregset_t *gr; svr4_mcontext_t *mc; + svr4_sigset_t setv; int i; synchronize_user_stack(); if (current->tss.w_saved){ - printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved); + printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved); lock_kernel(); do_exit (SIGSEGV); } @@ -586,9 +784,15 @@ /* Setup convenience variables */ mc = &uc->mcontext; gr = &mc->greg; - - /* We only have < 32 signals, fill the first slot only */ - __put_user(current->blocked, &uc->sigmask.sigbits [0]); + + setv.sigbits[0] = current->blocked.sig[0]; + setv.sigbits[1] = (current->blocked.sig[0] >> 32); + if (_NSIG_WORDS >= 2) { + setv.sigbits[2] = current->blocked.sig[1]; + setv.sigbits[3] = (current->blocked.sig[1] >> 32); + __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + } else + __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); /* Store registers */ __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); @@ -622,6 +826,8 @@ struct thread_struct *tp = ¤t->tss; svr4_gregset_t *gr; u32 pc, npc, psr; + sigset_t set; + svr4_sigset_t setv; int i; /* Fixme: restore windows, or is this already taken care of in @@ -630,7 +836,7 @@ flush_user_windows(); if (tp->w_saved){ - printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved); + printk ("Uh oh, w_saved is: 0x%x\n", tp->w_saved); goto sigsegv; } if (((unsigned long) c) & 3){ @@ -654,8 +860,16 @@ /* Retrieve information from passed ucontext */ /* note that nPC is ored a 1, this is used to inform entry.S */ /* that we don't want it to mess with our PC and nPC */ - __get_user(current->blocked, &c->sigmask.sigbits [0]); - current->blocked &= _BLOCKABLE; + if (copy_from_user (&setv, &c->sigmask, sizeof(svr4_sigset_t))) + goto sigsegv; + set.sig[0] = setv.sigbits[0] | (((long)setv.sigbits[1]) << 32); + if (_NSIG_WORDS >= 2) + set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32); + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); regs->tpc = pc; regs->tnpc = npc | 1; __get_user(regs->y, &((*gr) [SVR4_Y])); @@ -678,23 +892,137 @@ do_exit(SIGSEGV); } -static inline void handle_signal32(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs, +static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, + unsigned long signr, sigset_t *oldset, + siginfo_t *info) +{ + struct rt_signal_frame32 *sf; + int sigframe_size; + u32 psr; + int i; + sigset_t32 seta; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + sigframe_size = RT_ALIGNEDSZ; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + sigframe_size -= sizeof(__siginfo_fpu_t); + + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; + sf = (struct rt_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size); + + if (invalid_frame_pointer (sf, sigframe_size)) { +#ifdef DEBUG_SIGNALS + printk("rt_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n", + current->comm, current->pid, sf, sigframe_size); +#endif + goto sigill; + } + + if (current->tss.w_saved != 0) { +#ifdef DEBUG_SIGNALS + printk ("%s[%d]: Invalid user stack frame for " + "signal delivery.\n", current->comm, current->pid); +#endif + goto sigill; + } + + /* 2. Save the current process state */ + put_user(regs->tpc, &sf->regs.pc); + __put_user(regs->tnpc, &sf->regs.npc); + __put_user(regs->y, &sf->regs.y); + psr = tstate_to_psr (regs->tstate); + if(current->tss.flags & SPARC_FLAG_USEDFPU) + psr |= PSR_EF; + __put_user(psr, &sf->regs.psr); + for (i = 0; i < 16; i++) + __put_user(regs->u_regs[i], &sf->regs.u_regs[i]); + + if (psr & PSR_EF) { + save_fpu_state32(regs, &sf->fpu_state); + __put_user((u64)&sf->fpu_state, &sf->fpu_save); + } else { + __put_user(0, &sf->fpu_save); + } + + switch (_NSIG_WORDS) { + case 4: seta.sig[7] = (oldset->sig[3] >> 32); + seta.sig[6] = oldset->sig[3]; + case 3: seta.sig[5] = (oldset->sig[2] >> 32); + seta.sig[4] = oldset->sig[2]; + case 2: seta.sig[3] = (oldset->sig[1] >> 32); + seta.sig[2] = oldset->sig[1]; + case 1: seta.sig[1] = (oldset->sig[0] >> 32); + seta.sig[0] = oldset->sig[0]; + } + __copy_to_user(&sf->mask, &seta, sizeof(sigset_t)); + + copy_in_user((u32 *)sf, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); + + /* 3. signal handler back-trampoline and parameters */ + regs->u_regs[UREG_FP] = (unsigned long) sf; + regs->u_regs[UREG_I0] = signr; + regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + + /* 4. signal handler */ + regs->tpc = (unsigned long) ka->sa.sa_handler; + regs->tnpc = (regs->tpc + 4); + + /* 5. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ + unsigned long address = ((unsigned long)&(sf->insns[0])); + pgd_t *pgdp = pgd_offset(current->mm, address); + pmd_t *pmdp = pmd_offset(pgdp, address); + pte_t *ptep = pte_offset(pmdp, address); + + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + + if(pte_present(*ptep)) { + unsigned long page = pte_page(*ptep); + + __asm__ __volatile__(" + membar #StoreStore + flush %0 + %1" + : : "r" (page), "r" (address & (PAGE_SIZE - 1)) + : "memory"); + } + } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); +} + +static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, + siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs, int svr4_signal) { if(svr4_signal) - setup_svr4_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask); + setup_svr4_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset); else { - if (current->tss.new_signal) - new_setup_frame32(sa, regs, signr, oldmask); + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame32(ka, regs, signr, oldset, info); + else if (current->tss.new_signal) + new_setup_frame32(ka, regs, signr, oldset); else - setup_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask); + setup_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset); } - if(sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) { + if(ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + if(!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sigmask_lock); - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,signr); spin_unlock_irq(¤t->sigmask_lock); } } @@ -723,22 +1051,22 @@ * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, +asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) { - unsigned long signr, mask = ~current->blocked; - struct sigaction *sa; + unsigned long signr; + struct k_sigaction *ka; + siginfo_t info; + int svr4_signal = current->personality == PER_SVR4; - while ((signr = current->signal & mask) != 0) { - signr = ffz(~signr); - + for (;;) { spin_lock_irq(¤t->sigmask_lock); - current->signal &= ~(1 << signr); + signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) break; - sa = current->sig->action + signr; - signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; @@ -749,15 +1077,26 @@ current->exit_code = 0; if (signr == SIGSTOP) continue; - if (_S(signr) & current->blocked) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr); - spin_unlock_irq(¤t->sigmask_lock); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if(sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + + if(ka->sa.sa_handler == SIG_IGN) { if(signr != SIGCHLD) continue; @@ -770,7 +1109,9 @@ ; continue; } - if(sa->sa_handler == SIG_DFL) { + if(ka->sa.sa_handler == SIG_DFL) { + unsigned long exit_code = signr; + if(current->pid == 1) continue; switch(signr) { @@ -786,7 +1127,7 @@ continue; current->state = TASK_STOPPED; current->exit_code = signr; - if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); @@ -797,7 +1138,7 @@ if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); if(current->binfmt->core_dump(signr, regs)) - signr |= 0x80; + exit_code |= 0x80; unlock_kernel(); } #ifdef DEBUG_SIGNALS @@ -807,20 +1148,16 @@ #endif /* fall through */ default: - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); - - current->flags |= PF_SIGNALED; - lock_kernel(); - do_exit(signr); - unlock_kernel(); + sigaddset(¤t->signal, signr); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOT REACHED */ } } if(restart_syscall) - syscall_restart32(orig_i0, regs, sa); - handle_signal32(signr, sa, oldmask, regs, svr4_signal); + syscall_restart32(orig_i0, regs, &ka->sa); + handle_signal32(signr, ka, &info, oldset, regs, svr4_signal); return 1; } if(restart_syscall && diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.1.78/linux/arch/sparc64/kernel/smp.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/smp.c Mon Jan 12 15:15:44 1998 @@ -3,6 +3,7 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #define __KERNEL_SYSCALLS__ #include @@ -346,7 +348,7 @@ spin_lock(&scheduler_lock); get_new_mmu_context(mm, &tlb_context_cache); mm->cpu_vm_mask = (1UL << smp_processor_id()); - if(current->tss.current_ds) { + if(segment_eq(current->tss.current_ds,USER_DS)) { u32 ctx = mm->context & 0x1fff; current->tss.ctx = ctx; @@ -473,6 +475,7 @@ static inline void sparc64_do_profile(unsigned long pc) { +#ifdef CONFIG_PROFILE if(prof_buffer && current->pid) { extern int _stext; @@ -483,6 +486,7 @@ pc = prof_len - 1; atomic_inc((atomic_t *)&prof_buffer[pc]); } +#endif } static unsigned long real_tick_offset, current_tick_offset; @@ -510,7 +514,7 @@ update_one_process(current, 1, user, !user); if(--current->counter < 0) { current->counter = 0; - resched_force(); + need_resched = 1; } if(user) { diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.1.78/linux/arch/sparc64/kernel/sparc64_ksyms.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Jan 12 15:15:44 1998 @@ -1,10 +1,12 @@ -/* $Id: sparc64_ksyms.c,v 1.21 1997/09/03 12:29:07 jj Exp $ +/* $Id: sparc64_ksyms.c,v 1.27 1997/11/19 07:57:46 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) */ +/* Tell string.h we don't want memcpy etc. as cpp defines */ +#define EXPORT_SYMTAB_STROPS #define PROMLIB_INTERNAL #include @@ -12,6 +14,7 @@ #include #include #include +#include #include #include @@ -30,10 +33,14 @@ #include #include #include +#include #ifdef CONFIG_SBUS #include #include #endif +#ifdef CONFIG_PCI +#include +#endif #include #include @@ -43,6 +50,7 @@ short revents; }; +extern void die_if_kernel(char *str, struct pt_regs *regs); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); @@ -68,6 +76,7 @@ extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs); extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg); +extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -123,6 +132,10 @@ EXPORT_SYMBOL(SBus_chain); EXPORT_SYMBOL(dma_chain); #endif +#if CONFIG_PCI +EXPORT_SYMBOL(ebus_chain); +EXPORT_SYMBOL(pci_devices); +#endif /* Solaris/SunOS binary compatibility */ EXPORT_SYMBOL(_sigpause_common); @@ -131,6 +144,9 @@ /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); +/* math-emu wants this */ +EXPORT_SYMBOL(die_if_kernel); + /* prom symbols */ EXPORT_SYMBOL(idprom); EXPORT_SYMBOL(prom_root_node); @@ -188,6 +204,10 @@ EXPORT_SYMBOL(linux_cpus); EXPORT_SYMBOL(sys_ioctl); EXPORT_SYMBOL(sys32_ioctl); +#endif + +#ifdef CONFIG_MATHEMU_MODULE +EXPORT_SYMBOL(handle_mathemu); #endif /* Special internal versions of library functions. */ diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/sunos_ioctl32.c linux/arch/sparc64/kernel/sunos_ioctl32.c --- v2.1.78/linux/arch/sparc64/kernel/sunos_ioctl32.c Thu Jul 17 10:06:04 1997 +++ linux/arch/sparc64/kernel/sunos_ioctl32.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl32.c,v 1.4 1997/07/17 02:20:43 davem Exp $ +/* $Id: sunos_ioctl32.c,v 1.5 1997/09/18 10:37:57 rth Exp $ * sunos_ioctl32.c: SunOS ioctl compatability on sparc64. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -100,7 +100,7 @@ goto out; if(cmd == TIOCSETD) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int *p, ntty = N_TTY; int tmp; diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/sys32.S linux/arch/sparc64/kernel/sys32.S --- v2.1.78/linux/arch/sparc64/kernel/sys32.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/sys32.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: sys32.S,v 1.3 1997/08/22 20:11:47 davem Exp $ +/* $Id: sys32.S,v 1.4 1997/09/09 17:13:29 jj Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * @@ -8,8 +8,7 @@ .text .align 32 - .globl sys32_mmap, sys32_mprotect, sys32_munmap, sys32_msync - .globl sys32_mlock, sys32_munlock, sys32_mremap, sparc32_brk + .globl sys32_mmap sys32_mmap: srl %o0, 0, %o0 ! IEU0 Group sethi %hi(0xffffffff), %g2 ! IEU1 @@ -22,153 +21,15 @@ and %o5, %g2, %o5 ! IEU0 Group call sys_mmap ! CTI Group brk forced mov %g1, %o7 ! IEU0 Group (regdep) -sys32_mprotect: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - srl %o2, 0, %o2 - call sys_mprotect - mov %g1, %o7 -sys32_munmap: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_munmap - mov %g1, %o7 -sparc32_brk: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_brk - mov %g1, %o7 -sys32_msync: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_msync - mov %g1, %o7 -sys32_mlock: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_mlock - mov %g1, %o7 -sys32_munlock: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_munlock - mov %g1, %o7 -sys32_mremap: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - srl %o2, 0, %o2 - srl %o3, 0, %o3 - call sys_mremap - mov %g1, %o7 .align 32 - .globl sys32_read, sys32_write, sys32_open, sys32_access - .globl sys32_chdir, sys32_lseek, sys32_llseek, sys32_poll - .globl sys32_readlink, sys32_unlink, sys32_rmdir, sys32_symlink - .globl sys32_link, sys32_rename, sys32_truncate, sys32_ftruncate - .globl sys32_chroot, sys32_chmod, sys32_chown, sys32_creat - .globl sys32_mkdir, sys32_mknod, sys32_ustat -sys32_read: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_read - mov %g1, %o7 -sys32_write: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_write - mov %g1, %o7 -sys32_open: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_open - mov %g1, %o7 -sys32_access: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_access - mov %g1, %o7 -sys32_chdir: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_chdir - mov %g1, %o7 + .globl sys32_lseek + .globl sys32_chmod, sys32_chown, sys32_mknod sys32_lseek: sra %o1, 0, %o1 mov %o7, %g1 call sys_lseek mov %g1, %o7 -sys32_llseek: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - srl %o3, 0, %o3 - call sys_llseek - mov %g1, %o7 -sys32_poll: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_poll - mov %g1, %o7 -sys32_readlink: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_readlink - mov %g1, %o7 -sys32_unlink: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_unlink - mov %g1, %o7 -sys32_rmdir: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_rmdir - mov %g1, %o7 -sys32_symlink: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_symlink - mov %g1, %o7 -sys32_link: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_link - mov %g1, %o7 -sys32_rename: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_rename - mov %g1, %o7 - nop -sys32_truncate: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_truncate - mov %g1, %o7 -sys32_ftruncate: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_ftruncate - mov %g1, %o7 -sys32_chroot: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_chroot - mov %g1, %o7 sys32_chmod: sll %o1, 16, %o1 mov %o7, %g1 @@ -185,16 +46,6 @@ srl %o2, 16, %o2 call sys_chown mov %g1, %o7 -sys32_creat: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_creat - mov %g1, %o7 -sys32_mkdir: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_mkdir - mov %g1, %o7 sys32_mknod: sll %o2, 16, %o2 mov %o7, %g1 @@ -202,50 +53,9 @@ srl %o2, 16, %o2 call sys_mknod mov %g1, %o7 -sys32_ustat: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_ustat - mov %g1, %o7 .align 32 - .globl sys32_bind, sys32_accept, sys32_connect, sys32_getsockname - .globl sys32_getpeername, sys32_send, sys32_sendto, sys32_recv - .globl sys32_recvfrom, sys32_setsockopt, sys32_getsockopt -sys32_bind: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_bind - mov %g1, %o7 -sys32_accept: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_accept - mov %g1, %o7 -sys32_connect: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_connect - mov %g1, %o7 -sys32_getsockname: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_getsockname - mov %g1, %o7 -sys32_getpeername: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_getpeername - mov %g1, %o7 -sys32_send: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_send - mov %g1, %o7 + .globl sys32_sendto, sys32_recvfrom, sys32_getsockopt sys32_sendto: srl %o1, 0, %o1 mov %o7, %g1 @@ -253,12 +63,6 @@ srl %o4, 0, %o4 call sys_sendto mov %g1, %o7 -sys32_recv: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_recv - mov %g1, %o7 sys32_recvfrom: srl %o1, 0, %o1 mov %o7, %g1 @@ -267,11 +71,6 @@ srl %o5, 0, %o5 call sys_recvfrom mov %g1, %o7 -sys32_setsockopt: - srl %o3, 0, %o3 - mov %o7, %g1 - call sys_setsockopt - mov %g1, %o7 sys32_getsockopt: srl %o3, 0, %o3 mov %o7, %g1 @@ -279,111 +78,9 @@ call sys_setsockopt mov %g1, %o7 - .globl sys32_bdflush, sys32_uselib, sys32_umount, sys32_syslog - .globl sys32_personality, sys32_waitpid - .globl sys32_sched_setscheduler - .globl sys32_sched_setparam, sys32_sched_getparam, sys32_signal - .globl sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname - .globl sys32_sethostname, sys32_gethostname, sys32_setdomainname - .globl sys32_time, sys32_swapoff, sys32_swapon - .globl sys32_create_module, sys32_init_module, sys32_delete_module + .globl sys32_bdflush sys32_bdflush: sra %o1, 0, %o1 mov %o7, %g1 call sys_bdflush - mov %g1, %o7 -sys32_uselib: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_uselib - mov %g1, %o7 -sys32_umount: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_umount - mov %g1, %o7 -sys32_syslog: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_syslog - mov %g1, %o7 -sys32_personality: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_personality - mov %g1, %o7 -sys32_waitpid: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_waitpid - mov %g1, %o7 -sys32_sched_setscheduler: - srl %o2, 0, %o2 - mov %o7, %g1 - call sys_sched_setscheduler - mov %g1, %o7 -sys32_sched_setparam: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_sched_setparam - mov %g1, %o7 -sys32_sched_getparam: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_sched_getparam - mov %g1, %o7 -sys32_signal: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_signal - mov %g1, %o7 -sys32_reboot: - srl %o3, 0, %o3 - mov %o7, %g1 - call sys_reboot - mov %g1, %o7 -sys32_acct: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_acct - mov %g1, %o7 -sys32_newuname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_newuname - mov %g1, %o7 -sys32_olduname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_olduname - mov %g1, %o7 -sys32_sethostname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_sethostname - mov %g1, %o7 -sys32_gethostname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_gethostname - mov %g1, %o7 -sys32_setdomainname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_setdomainname - mov %g1, %o7 -sys32_time: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_time - mov %g1, %o7 -sys32_swapoff: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_swapoff - mov %g1, %o7 -sys32_swapon: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_swapon mov %g1, %o7 diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.1.78/linux/arch/sparc64/kernel/sys_sparc.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/sys_sparc.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.5 1997/09/03 12:29:05 jj Exp $ +/* $Id: sys_sparc.c,v 1.9 1997/12/11 15:15:44 jj Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -16,11 +16,14 @@ #include #include #include +#include #include #include +#include #include #include +#include /* XXX Make this per-binary type, this way we can detect the type of * XXX a binary. Every Sparc executable calls this very early on. @@ -219,39 +222,16 @@ extern void check_pending(int signum); -asmlinkage int -sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction) +asmlinkage int sys_getdomainname(char *name, int len) { - struct sigaction new_sa, *p; + int nlen = strlen(system_utsname.domainname); - if(signum < 0) { - current->tss.new_signal = 1; - signum = -signum; - } - if (signum<1 || signum>32) - return -EINVAL; - p = signum - 1 + current->sig->action; - if (action) { - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - if(copy_from_user(&new_sa, action, sizeof(struct sigaction))) - return -EFAULT; - if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { - int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); - if (err) - return err; - } - } - if (oldaction) { - if (copy_to_user(oldaction, p, sizeof(struct sigaction))) - return -EFAULT; - } - if (action) { - spin_lock_irq(¤t->sig->siglock); - *p = new_sa; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); - } + if (nlen < len) + len = nlen; + if(len > __NEW_UTS_LEN) + return -EFAULT; + if(copy_to_user(name, system_utsname.domainname, len)) + return -EFAULT; return 0; } @@ -271,4 +251,117 @@ send_sig(SIGSEGV, current, 1); unlock_kernel(); return 0; +} + +asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, utrap_handler_t new_d, + utrap_handler_t *old_p, utrap_handler_t *old_d) +{ + if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31) + return -EINVAL; + if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) { + if (old_p) { + if (!current->tss.utraps) + put_user_ret(NULL, old_p, -EFAULT); + else + put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT); + } + if (old_d) + put_user_ret(NULL, old_d, -EFAULT); + return 0; + } + lock_kernel(); + if (!current->tss.utraps) { + current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); + if (!current->tss.utraps) return -ENOMEM; + current->tss.utraps[0] = 1; + memset(current->tss.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long)); + } else { + if ((utrap_handler_t)current->tss.utraps[type] != new_p && current->tss.utraps[0] > 1) { + long *p = current->tss.utraps; + + current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); + if (!current->tss.utraps) { + current->tss.utraps = p; + return -ENOMEM; + } + p[0]--; + current->tss.utraps[0] = 1; + memcpy(current->tss.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long)); + } + } + if (old_p) + put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT); + if (old_d) + put_user_ret(NULL, old_d, -EFAULT); + current->tss.utraps[type] = (long)new_p; + unlock_kernel(); + return 0; +} + +long sparc_memory_ordering(unsigned long model, struct pt_regs *regs) +{ + if (model >= 3) + return -EINVAL; + regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14); + return 0; +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + new_ka.ka_restorer = NULL; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, + void *restorer, size_t sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (act) { + new_ka.ka_restorer = restorer; + if (copy_from_user(&new_ka.sa, act, sizeof(*act))) + return -EFAULT; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) + return -EFAULT; + } + + return ret; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.1.78/linux/arch/sparc64/kernel/sys_sparc32.c Wed Dec 10 11:12:43 1997 +++ linux/arch/sparc64/kernel/sys_sparc32.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.55 1997/09/04 01:54:51 davem Exp $ +/* $Id: sys_sparc32.c,v 1.71 1997/12/11 15:15:11 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include @@ -253,7 +255,7 @@ case SEMCTL: { union semun fourth; void *pad; - unsigned long old_fs; + mm_segment_t old_fs; struct semid_ds s; err = -EINVAL; @@ -336,7 +338,7 @@ err = -EFAULT; } if (!err) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_msgsnd (first, p, second, third); set_fs (old_fs); @@ -348,7 +350,7 @@ case MSGRCV: { struct msgbuf *p; - unsigned long old_fs; + mm_segment_t old_fs; long msgtyp = fifth; if (!version) { @@ -398,7 +400,7 @@ case MSGCTL: { struct msqid_ds m; - unsigned long old_fs; + mm_segment_t old_fs; switch (second) { case IPC_INFO: @@ -482,7 +484,7 @@ case SHMCTL: { struct shmid_ds s; - unsigned long old_fs; + mm_segment_t old_fs; switch (second) { case IPC_INFO: @@ -590,7 +592,7 @@ case F_SETLKW: { struct flock f; - unsigned long old_fs; + mm_segment_t old_fs; long ret; if(get_flock(&f, (struct flock32 *)A(arg))) @@ -625,7 +627,7 @@ int cmds = cmd >> SUBCMDSHIFT; int err; struct dqblk d; - unsigned long old_fs; + mm_segment_t old_fs; char *spec; switch (cmds) { @@ -685,7 +687,7 @@ { int ret; struct statfs s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); char *pth; pth = getname32 (path); @@ -707,7 +709,7 @@ { int ret; struct statfs s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fstatfs(fd, &s); @@ -723,7 +725,7 @@ { struct utimbuf32 { __kernel_time_t32 actime, modtime; }; struct utimbuf t; - unsigned long old_fs; + mm_segment_t old_fs; int ret; char *filenam; @@ -746,14 +748,15 @@ struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; }; -typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long); +typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *); -static long do_readv_writev32(int type, struct inode *inode, struct file *file, +static long do_readv_writev32(int type, struct file *file, const struct iovec32 *vector, u32 count) { unsigned long tot_len; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov=iovstack, *ivp; + struct inode *inode; long retval, i; IO_fn_t fn; @@ -789,6 +792,7 @@ i--; } + inode = file->f_dentry->d_inode; retval = locks_verify_area((type == VERIFY_READ) ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, file->f_pos, tot_len); @@ -828,7 +832,7 @@ len = ivp->iov_len; ivp++; count--; - nr = fn(inode, file, base, len); + nr = fn(file, base, len, &file->f_pos); if (nr < 0) { if (retval) break; @@ -847,69 +851,53 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count) { struct file *file; - struct dentry *dentry; - struct inode *inode; - long err = -EBADF; + long ret = -EBADF; lock_kernel(); - if(fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if(!file) - goto out; + goto bad_file; if(!(file->f_mode & 1)) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - - err = do_readv_writev32(VERIFY_WRITE, inode, file, + ret = do_readv_writev32(VERIFY_WRITE, file, (struct iovec32 *)A(vector), count); + if (ret > 0) + current->io_usage += ret; + out: + fput(file); +bad_file: unlock_kernel(); - return err; + return ret; } asmlinkage long sys32_writev(int fd, u32 vector, u32 count) { - int error = -EBADF; struct file *file; - struct dentry *dentry; - struct inode *inode; + int ret = -EBADF; lock_kernel(); - if(fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if(!file) - goto out; + goto bad_file; if(!(file->f_mode & 2)) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - - down(&inode->i_sem); - error = do_readv_writev32(VERIFY_READ, inode, file, + down(&file->f_dentry->d_inode->i_sem); + ret = do_readv_writev32(VERIFY_READ, file, (struct iovec32 *)A(vector), count); - up(&inode->i_sem); + up(&file->f_dentry->d_inode->i_sem); + if (ret > 0) + current->io_usage += ret; + out: + fput(file); +bad_file: unlock_kernel(); - return error; + return ret; } /* readdir & getdents */ @@ -951,8 +939,6 @@ { int error = -EBADF; struct file * file; - struct dentry * dentry; - struct inode * inode; struct readdir_callback32 buf; lock_kernel(); @@ -963,14 +949,6 @@ if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - buf.count = 0; buf.dirent = (struct old_linux_dirent32 *)A(dirent); @@ -978,7 +956,7 @@ if (!file->f_op || !file->f_op->readdir) goto out; - error = file->f_op->readdir(inode, file, &buf, fillonedir); + error = file->f_op->readdir(file, &buf, fillonedir); if (error < 0) goto out; error = buf.count; @@ -1028,8 +1006,6 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) { struct file * file; - struct dentry * dentry; - struct inode *inode; struct linux_dirent32 * lastdirent; struct getdents_callback32 buf; int error = -EBADF; @@ -1042,14 +1018,6 @@ if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - buf.current_dir = (struct linux_dirent32 *) A(dirent); buf.previous = NULL; buf.count = count; @@ -1059,7 +1027,7 @@ if (!file->f_op || !file->f_op->readdir) goto out; - error = file->f_op->readdir(inode, file, &buf, filldir); + error = file->f_op->readdir(file, &buf, filldir); if (error < 0) goto out; lastdirent = buf.previous; @@ -1088,7 +1056,7 @@ if (ufdset) { unsigned long odd; - if (verify_area(VERIFY_WRITE, ufdset, nn*sizeof(u32))) + if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32))) return -EFAULT; odd = n & 1UL; @@ -1104,12 +1072,12 @@ if (odd) __get_user(*fdset, ufdset); } else { - /* Tricky, must clear full unsigned long in the kernel - fdset at the end, this makes sure that actually - happens. */ + /* Tricky, must clear full unsigned long in the + * kernel fdset at the end, this makes sure that + * actually happens. + */ memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32)); } - return 0; } @@ -1168,7 +1136,7 @@ goto out; if (n > KFDS_NR) n = KFDS_NR; - + nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32)); if ((ret = get_fd_set32(nn, fds->in, inp)) || (ret = get_fd_set32(nn, fds->out, outp)) || @@ -1196,7 +1164,7 @@ goto out; if (!ret) { ret = -ERESTARTNOHAND; - if (current->signal & ~current->blocked) + if (signal_pending(current)) goto out; ret = 0; } @@ -1237,7 +1205,7 @@ int ret; struct stat s; char *filenam; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); filenam = getname32 (filename); ret = PTR_ERR(filenam); @@ -1259,7 +1227,7 @@ int ret; struct stat s; char *filenam; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); filenam = getname32 (filename); ret = PTR_ERR(filenam); @@ -1280,7 +1248,7 @@ { int ret; struct stat s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); @@ -1290,29 +1258,11 @@ return ret; } -extern asmlinkage int sys_sysfs(int option, ...); +extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2); -asmlinkage int sys32_sysfs(int option, ...) +asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2) { - va_list args; - unsigned int x; - int ret = -EINVAL; - - va_start(args, option); - switch (option) { - case 1: - ret = sys_sysfs(option, (const char *)A(va_arg(args, u32))); - break; - case 2: - x = va_arg(args, unsigned int); - ret = sys_sysfs(option, x, (char *)A(va_arg(args, u32))); - break; - case 3: - ret = sys_sysfs(option); - break; - } - va_end(args); - return ret; + return sys_sysfs(option, arg1, arg2); } struct ncp_mount_data32 { @@ -1347,17 +1297,7 @@ struct smb_mount_data32 { int version; - unsigned int fd; __kernel_uid_t32 mounted_uid; - struct sockaddr_in addr; - char server_name[17]; - char client_name[17]; - char service[64]; - char root_path[64]; - char username[64]; - char password[64]; - char domain[64]; - unsigned short max_xmit; __kernel_uid_t32 uid; __kernel_gid_t32 gid; __kernel_mode_t32 file_mode; @@ -1434,7 +1374,7 @@ (void *)A(data)); } else { unsigned long dev_page, dir_page, data_page; - int old_fs; + mm_segment_t old_fs; err = copy_mount_stuff_to_kernel((const void *)A(dev_name), &dev_page); if(err) @@ -1527,7 +1467,7 @@ struct rusage r; int ret; unsigned int status; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); @@ -1558,7 +1498,7 @@ { struct sysinfo s; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_sysinfo(&s); @@ -1589,7 +1529,7 @@ { struct timespec t; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_sched_rr_get_interval(pid, &t); @@ -1606,7 +1546,7 @@ { struct timespec t; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if (get_user (t.tv_sec, &(((struct timespec32 *)A(rqtp))->tv_sec)) || __get_user (t.tv_nsec, &(((struct timespec32 *)A(rqtp))->tv_nsec))) @@ -1622,34 +1562,235 @@ return ret; } -extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset); +extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset); asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset) { - sigset_t s; + old_sigset_t s; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); - if (set && get_user (s, (sigset_t32 *)A(set))) return -EFAULT; + if (set && get_user (s, (old_sigset_t32 *)A(set))) return -EFAULT; set_fs (KERNEL_DS); ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); set_fs (old_fs); - if (oset && put_user (s, (sigset_t32 *)A(oset))) return -EFAULT; - return ret; + if (ret) return ret; + if (oset && put_user (s, (old_sigset_t32 *)A(oset))) return -EFAULT; + return 0; } -extern asmlinkage int sys_sigpending(sigset_t *set); +extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize); -asmlinkage int sys32_sigpending(u32 set) +asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t32 sigsetsize) { sigset_t s; + sigset_t32 s32; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); + + if (set) { + if (copy_from_user (&s32, (sigset_t32 *)A(set), sizeof(sigset_t32))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + } + set_fs (KERNEL_DS); + ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sigsetsize); + set_fs (old_fs); + if (ret) return ret; + if (oset) { + switch (_NSIG_WORDS) { + case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; + case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; + case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; + case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; + } + if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32))) + return -EFAULT; + } + return 0; +} + +extern asmlinkage int sys_sigpending(old_sigset_t *set); + +asmlinkage int sys32_sigpending(u32 set) +{ + old_sigset_t s; + int ret; + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_sigpending(&s); set_fs (old_fs); - if (put_user (s, (sigset_t32 *)A(set))) return -EFAULT; + if (put_user (s, (old_sigset_t32 *)A(set))) return -EFAULT; + return ret; +} + +extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize); + +asmlinkage int sys32_rt_sigpending(u32 set, __kernel_size_t32 sigsetsize) +{ + sigset_t s; + sigset_t32 s32; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_rt_sigpending(&s, sigsetsize); + set_fs (old_fs); + if (!ret) { + switch (_NSIG_WORDS) { + case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; + case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; + case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; + case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; + } + if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32))) + return -EFAULT; + } + return ret; +} + +siginfo_t32 * +siginfo64to32(siginfo_t32 *d, siginfo_t *s) +{ + memset (&d, 0, sizeof(siginfo_t32)); + d->si_signo = s->si_signo; + d->si_errno = s->si_errno; + d->si_code = s->si_code; + if (s->si_signo >= SIGRTMIN) { + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + /* XXX: Ouch, how to find this out??? */ + d->si_int = s->si_int; + } else switch (s->si_signo) { + /* XXX: What about POSIX1.b timers */ + case SIGCHLD: + d->si_pid = s->si_pid; + d->si_status = s->si_status; + d->si_utime = s->si_utime; + d->si_stime = s->si_stime; + break; + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + d->si_addr = (long)(s->si_addr); + /* XXX: Do we need to translate this from sparc64 to sparc32 traps? */ + d->si_trapno = s->si_trapno; + break; + case SIGPOLL: + d->si_band = s->si_band; + d->si_fd = s->si_fd; + break; + default: + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + break; + } + return d; +} + +siginfo_t * +siginfo32to64(siginfo_t *d, siginfo_t32 *s) +{ + d->si_signo = s->si_signo; + d->si_errno = s->si_errno; + d->si_code = s->si_code; + if (s->si_signo >= SIGRTMIN) { + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + /* XXX: Ouch, how to find this out??? */ + d->si_int = s->si_int; + } else switch (s->si_signo) { + /* XXX: What about POSIX1.b timers */ + case SIGCHLD: + d->si_pid = s->si_pid; + d->si_status = s->si_status; + d->si_utime = s->si_utime; + d->si_stime = s->si_stime; + break; + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + d->si_addr = (void *)A(s->si_addr); + /* XXX: Do we need to translate this from sparc32 to sparc64 traps? */ + d->si_trapno = s->si_trapno; + break; + case SIGPOLL: + d->si_band = s->si_band; + d->si_fd = s->si_fd; + break; + default: + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + break; + } + return d; +} + +extern asmlinkage int +sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, + const struct timespec *uts, size_t sigsetsize); + +asmlinkage int +sys32_rt_sigtimedwait(u32 uthese, u32 uinfo, + u32 uts, __kernel_size_t32 sigsetsize) +{ + sigset_t s; + sigset_t32 s32; + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs(); + siginfo_t info; + siginfo_t32 info32; + + if (copy_from_user (&s32, (sigset_t32 *)A(uthese), sizeof(sigset_t32))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + if (uts) { + if (get_user (t.tv_sec, &(((struct timespec32 *)A(uts))->tv_sec)) || + __get_user (t.tv_nsec, &(((struct timespec32 *)A(uts))->tv_nsec))) + return -EFAULT; + } + set_fs (KERNEL_DS); + ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + set_fs (old_fs); + if (ret >= 0 && uinfo) { + if (copy_to_user ((siginfo_t32 *)A(uinfo), siginfo64to32(&info32, &info), sizeof(siginfo_t32))) + return -EFAULT; + } + return ret; +} + +extern asmlinkage int +sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); + +asmlinkage int +sys32_rt_sigqueueinfo(int pid, int sig, u32 uinfo) +{ + siginfo_t info; + siginfo_t32 info32; + int ret; + mm_segment_t old_fs = get_fs(); + + if (copy_from_user (&info32, (siginfo_t32 *)A(uinfo), sizeof(siginfo_t32))) + return -EFAULT; + /* XXX: Is this correct? */ + siginfo32to64(&info, &info32); + set_fs (KERNEL_DS); + ret = sys_rt_sigqueueinfo(pid, sig, &info); + set_fs (old_fs); return ret; } @@ -1684,7 +1825,7 @@ { uid_t a, b, c; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_getresuid(&a, &b, &c); @@ -1696,6 +1837,49 @@ return ret; } +extern asmlinkage int sys_setregid(gid_t rgid, gid_t egid); + +asmlinkage int sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) +{ + gid_t srgid, segid; + + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + return sys_setregid(srgid, segid); +} + +extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); + +asmlinkage int sys32_setresgid(__kernel_gid_t32 rgid, + __kernel_gid_t32 egid, + __kernel_gid_t32 sgid) +{ + gid_t srgid, segid, ssgid; + + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); + return sys_setresgid(srgid, segid, ssgid); +} + +extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); + +asmlinkage int sys32_getresgid(u32 rgid, u32 egid, u32 sgid) +{ + gid_t a, b, c; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_getresgid(&a, &b, &c); + set_fs (old_fs); + if (put_user (a, (__kernel_gid_t32 *)A(rgid)) || + put_user (b, (__kernel_gid_t32 *)A(egid)) || + put_user (c, (__kernel_gid_t32 *)A(sgid))) + return -EFAULT; + return ret; +} + struct tms32 { __kernel_clock_t32 tms_utime; __kernel_clock_t32 tms_stime; @@ -1709,7 +1893,7 @@ { struct tms t; long ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_times(tbuf ? &t : NULL); @@ -1729,7 +1913,7 @@ { gid_t gl[NGROUPS]; int ret, i; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_getgroups(gidsetsize, gl); @@ -1747,7 +1931,7 @@ { gid_t gl[NGROUPS]; int ret, i; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; @@ -1774,7 +1958,7 @@ { struct rlimit r; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_getrlimit(resource, &r); @@ -1792,7 +1976,7 @@ { struct rlimit r; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if (resource >= RLIM_NLIMITS) return -EINVAL; if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) || @@ -1814,7 +1998,7 @@ { struct rusage r; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_getrusage(who, &r); @@ -1854,7 +2038,7 @@ { struct timex t; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if (get_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) || __get_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) || @@ -2158,21 +2342,19 @@ AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL -extern asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen); -extern asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen); -extern asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen); -extern asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len); -extern asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len); -extern asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, - unsigned flags); +extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); +extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); +extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen); +extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len); +extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len); +extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags); extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len); -extern asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, - unsigned flags); +extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags); extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len); -extern asmlinkage int sys32_setsockopt(int fd, int level, int optname, - u32 optval, int optlen); +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); extern asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen); @@ -2199,31 +2381,31 @@ case SYS_SOCKET: return sys_socket(a0, a1, a[2]); case SYS_BIND: - return sys32_bind(a0, a1, a[2]); + return sys_bind(a0, (struct sockaddr *)A(a1), a[2]); case SYS_CONNECT: - return sys32_connect(a0, a1, a[2]); + return sys_connect(a0, (struct sockaddr *)A(a1), a[2]); case SYS_LISTEN: return sys_listen(a0, a1); case SYS_ACCEPT: - return sys32_accept(a0, a1, a[2]); + return sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); case SYS_GETSOCKNAME: - return sys32_getsockname(a0, a1, a[2]); + return sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); case SYS_GETPEERNAME: - return sys32_getpeername(a0, a1, a[2]); + return sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); case SYS_SOCKETPAIR: return sys_socketpair(a0, a1, a[2], (int *)A(a[3])); case SYS_SEND: - return sys32_send(a0, a1, a[2], a[3]); + return sys_send(a0, (void *)A(a1), a[2], a[3]); case SYS_SENDTO: return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]); case SYS_RECV: - return sys32_recv(a0, a1, a[2], a[3]); + return sys_recv(a0, (void *)A(a1), a[2], a[3]); case SYS_RECVFROM: return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); case SYS_SHUTDOWN: return sys_shutdown(a0,a1); case SYS_SETSOCKOPT: - return sys32_setsockopt(a0, a1, a[2], a[3], a[4]); + return sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]); case SYS_GETSOCKOPT: return sys32_getsockopt(a0, a1, a[2], a[3], a[4]); case SYS_SENDMSG: @@ -2236,51 +2418,88 @@ extern void check_pending(int signum); -asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction) +asmlinkage int sys32_sigaction (int sig, u32 act, u32 oact) { - struct sigaction32 new_sa, old_sa; - struct sigaction *p; + struct k_sigaction new_ka, old_ka; + int ret; - if(signum < 0) { + if(sig < 0) { current->tss.new_signal = 1; - signum = -signum; + sig = -sig; } - if (signum<1 || signum>32) - return -EINVAL; - p = signum - 1 + current->sig->action; - if (action) { - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32))) - return -EFAULT; - if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL && - ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) { - int err = verify_area(VERIFY_READ, - (__sighandler_t)A(new_sa.sa_handler), 1); - if (err) - return err; - } - } - if (oldaction) { - old_sa.sa_handler = (unsigned)(u64)(p->sa_handler); - old_sa.sa_mask = (sigset_t32)(p->sa_mask); - old_sa.sa_flags = (unsigned)(p->sa_flags); - old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer); - if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32))) - return -EFAULT; - } - if (action) { - spin_lock_irq(¤t->sig->siglock); - p->sa_handler = (__sighandler_t)A(new_sa.sa_handler); - p->sa_mask = (sigset_t)(new_sa.sa_mask); - p->sa_flags = new_sa.sa_flags; - p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer); - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); - } - return 0; + + if (act) { + old_sigset_t32 mask; + + if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) || + __get_user((long)new_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(act))->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags); + __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask); + new_ka.ka_restorer = NULL; + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) || + __put_user((long)old_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(oact))->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask); + } + + return ret; } +asmlinkage int +sys32_rt_sigaction(int sig, u32 act, u32 oact, + u32 restorer, __kernel_size_t32 sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + sigset_t32 set32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t32)) + return -EINVAL; + + if (act) { + if (get_user((long)new_ka.sa.sa_handler, &((struct sigaction32 *)A(act))->sa_handler) || + __copy_from_user(&set32, &((struct sigaction32 *)A(act))->sa_mask, sizeof(sigset_t32))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); + case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32); + case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32); + case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); + } + __get_user(new_ka.sa.sa_flags, &((struct sigaction32 *)A(act))->sa_flags); + __get_user((long)new_ka.sa.sa_restorer, &((struct sigaction32 *)A(act))->sa_restorer); + new_ka.ka_restorer = (void *)(long)restorer; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + switch (_NSIG_WORDS) { + case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3]; + case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2]; + case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1]; + case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0]; + } + if (put_user((long)old_ka.sa.sa_handler, &((struct sigaction32 *)A(oact))->sa_handler) || + __copy_to_user(&((struct sigaction32 *)A(oact))->sa_mask, &set32, sizeof(sigset_t32))) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &((struct sigaction32 *)A(oact))->sa_flags); + __put_user((long)old_ka.sa.sa_restorer, &((struct sigaction32 *)A(oact))->sa_restorer); + } + + return ret; +} + + /* * count32() counts the number of arguments/envelopes */ @@ -2476,7 +2695,7 @@ asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv) { char *buff; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); size_t val; int ret, i, j; unsigned long *p; @@ -2544,7 +2763,7 @@ if (!ret && val) { char *strings = buff + ((unsigned long *)buff)[1]; j = *(p - 1) - ((unsigned long *)buff)[1]; - j = j + strlen (buff + j) + 1; + j = j + strlen (strings + j) + 1; if (bufsize < j) { bufsiz = 0; goto qmsym_toshort; @@ -2597,7 +2816,7 @@ { int len, i; struct kernel_sym *tbl; - unsigned long old_fs; + mm_segment_t old_fs; len = sys_get_kernel_syms(NULL); if (!table) return len; @@ -2858,7 +3077,7 @@ union nfsctl_res32 *res32 = (union nfsctl_res32 *)A(u_resp); struct nfsctl_arg *karg = NULL; union nfsctl_res *kres = NULL; - unsigned long oldfs; + mm_segment_t oldfs; int err; karg = kmalloc(sizeof(*karg), GFP_USER); @@ -3003,7 +3222,7 @@ { char *kfilename; struct timeval ktvs[2]; - unsigned long old_fs; + mm_segment_t old_fs; int ret; kfilename = getname32(filename); @@ -3023,4 +3242,88 @@ putname32(kfilename); } return ret; +} + +/* These are here just in case some old sparc32 binary calls it. */ +asmlinkage int sys32_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +/* PCI config space poking. */ +extern asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf); + +extern asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf); + +asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +{ + return sys_pciconfig_read((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)A(ubuf)); +} + +asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +{ + return sys_pciconfig_write((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)A(ubuf)); +} + +extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5); + +asmlinkage int sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) +{ + return sys_prctl(option, + (unsigned long) arg2, + (unsigned long) arg3, + (unsigned long) arg4, + (unsigned long) arg5); +} + + +extern asmlinkage int sys_newuname(struct new_utsname * name); + +asmlinkage int sys32_newuname(struct new_utsname * name) +{ + int ret = sys_newuname(name); + + if (current->personality == PER_LINUX32 && !ret) { + ret = copy_to_user(name->machine, "sparc\0\0", 8); + } + return ret; +} + +extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, + size_t count, loff_t pos); + +extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf, + size_t count, loff_t pos); + +typedef __kernel_ssize_t32 ssize_t32; + +asmlinkage ssize_t32 sys32_pread(unsigned int fd, u32 ubuf, + __kernel_size_t32 count, u32 pos) +{ + return sys_pread(fd, (char *) A(ubuf), count, pos); +} + +asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, u32 ubuf, + __kernel_size_t32 count, u32 pos) +{ + return sys_pwrite(fd, (char *) A(ubuf), count, pos); } diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.1.78/linux/arch/sparc64/kernel/sys_sunos32.c Thu Jul 17 10:06:04 1997 +++ linux/arch/sparc64/kernel/sys_sunos32.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.3 1997/07/17 02:20:48 davem Exp $ +/* $Id: sys_sunos32.c,v 1.7 1997/12/11 15:15:19 jj Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -297,35 +297,28 @@ return SUNOS_NR_OPEN; } -#define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage u32 sunos_sigblock(u32 blk_mask) { - unsigned long flags; u32 old; - lock_kernel(); - save_and_cli(flags); - old = (u32) current->blocked; - current->blocked |= (blk_mask & _BLOCKABLE); - restore_flags(flags); - unlock_kernel(); + spin_lock_irq(¤t->sigmask_lock); + old = (u32) current->blocked.sig[0]; + current->blocked.sig[0] |= (blk_mask & _BLOCKABLE); + spin_unlock_irq(¤t->sigmask_lock); return old; } asmlinkage u32 sunos_sigsetmask(u32 newmask) { - unsigned long flags; u32 retval; - lock_kernel(); - save_and_cli(flags); - retval = (u32) current->blocked; - current->blocked = (newmask & _BLOCKABLE); - restore_flags(flags); - unlock_kernel(); + spin_lock_irq(¤t->sigmask_lock); + retval = (u32) current->blocked.sig[0]; + current->blocked.sig[0] = (newmask & _BLOCKABLE); + spin_unlock_irq(¤t->sigmask_lock); return retval; } @@ -379,8 +372,6 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) { struct file * file; - struct dentry * dentry; - struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; @@ -394,14 +385,6 @@ if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; @@ -415,7 +398,7 @@ buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(inode, file, &buf, sunos_filldir); + error = file->f_op->readdir(file, &buf, sunos_filldir); if (error < 0) goto out; lastdirent = buf.previous; @@ -472,8 +455,6 @@ int cnt, u32 u_basep) { struct file * file; - struct dentry * dentry; - struct inode * inode; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; int error = -EBADF; @@ -488,14 +469,6 @@ if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; @@ -509,7 +482,7 @@ buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry); + error = file->f_op->readdir(file, &buf, sunos_filldirentry); if (error < 0) goto out; lastdirent = buf.previous; @@ -1140,7 +1113,7 @@ struct sparc_stackf32 *sp; struct msqid_ds kds; struct msgbuf *kmbuf; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); u32 arg5; int rval; @@ -1264,7 +1237,8 @@ asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3) { struct shmid_ds ksds; - unsigned long raddr, old_fs = get_fs(); + unsigned long raddr; + mm_segment_t old_fs = get_fs(); int rval; lock_kernel(); @@ -1328,20 +1302,20 @@ return ret; } -extern asmlinkage int sys32_read(unsigned int fd, u32 buf, int count); -extern asmlinkage int sys32_write(unsigned int fd, u32 buf,int count); -extern asmlinkage int sys32_recv(int fd, u32 ubuf, int size, unsigned flags); -extern asmlinkage int sys32_send(int fd, u32 buff, int len, unsigned flags); -extern asmlinkage int sys32_accept(int fd, u32 sa, u32 addrlen); +extern asmlinkage int sys_read(unsigned int fd, char *buf, unsigned long count); +extern asmlinkage int sys_write(unsigned int fd, char *buf, unsigned long count); +extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags); +extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags); +extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen); extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count); extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count); -asmlinkage int sunos_read(unsigned int fd, u32 buf, int count) +asmlinkage int sunos_read(unsigned int fd, u32 buf, u32 count) { int ret; lock_kernel(); - ret = check_nonblock(sys32_read(fd, buf, count), fd); + ret = check_nonblock(sys_read(fd, (char *)A(buf), count), fd); unlock_kernel(); return ret; } @@ -1356,12 +1330,12 @@ return ret; } -asmlinkage int sunos_write(unsigned int fd, u32 buf, int count) +asmlinkage int sunos_write(unsigned int fd, u32 buf, u32 count) { int ret; lock_kernel(); - ret = check_nonblock(sys32_write(fd, buf, count), fd); + ret = check_nonblock(sys_write(fd, (char *)A(buf), count), fd); unlock_kernel(); return ret; } @@ -1381,7 +1355,7 @@ int ret; lock_kernel(); - ret = check_nonblock(sys32_recv(fd, ubuf, size, flags), fd); + ret = check_nonblock(sys_recv(fd, (void *)A(ubuf), size, flags), fd); unlock_kernel(); return ret; } @@ -1391,7 +1365,7 @@ int ret; lock_kernel(); - ret = check_nonblock(sys32_send(fd, buff, len, flags), fd); + ret = check_nonblock(sys_send(fd, (void *)A(buff), len, flags), fd); unlock_kernel(); return ret; } @@ -1401,78 +1375,48 @@ int ret; lock_kernel(); - ret = check_nonblock(sys32_accept(fd, sa, addrlen), fd); + ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa), (int *)A(addrlen)), fd); unlock_kernel(); return ret; } #define SUNOS_SV_INTERRUPT 2 -extern void check_pending(int signum); - -asmlinkage int sunos_sigaction(int signum, u32 action, u32 oldaction) +asmlinkage int sunos_sigaction (int sig, u32 act, u32 oact) { - struct sigaction32 new_sa, old_sa; - struct sigaction *p; - const int sigaction_size = sizeof (struct sigaction32) - sizeof (u32); + struct k_sigaction new_ka, old_ka; + int ret; current->personality |= PER_BSD; - if(signum < 1 || signum > 32) - return -EINVAL; - p = signum - 1 + current->sig->action; + if (act) { + old_sigset_t32 mask; - if(action) { - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - memset(&new_sa, 0, sizeof(struct sigaction32)); - if(copy_from_user(&new_sa, (struct sigaction32 *)A(action), - sigaction_size)) + if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) || + __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags)) return -EFAULT; - if (((__sighandler_t)A(new_sa.sa_handler) != SIG_DFL) && - (__sighandler_t)A(new_sa.sa_handler) != SIG_IGN) { - if(verify_area(VERIFY_READ, - (__sighandler_t)A(new_sa.sa_handler), 1)) - return -EFAULT; - } - new_sa.sa_flags ^= SUNOS_SV_INTERRUPT; + __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask); + new_ka.sa.sa_restorer = NULL; + new_ka.ka_restorer = NULL; + siginitset(&new_ka.sa.sa_mask, mask); + new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; } - if (oldaction) { - /* In the clone() case we could copy half consistant - * state to the user, however this could sleep and - * deadlock us if we held the signal lock on SMP. So for - * now I take the easy way out and do no locking. - * But then again we don't support SunOS lwp's anyways ;-) - */ - old_sa.sa_handler = (unsigned)(u64)(p->sa_handler); - old_sa.sa_mask = (sigset_t32)(p->sa_mask); - old_sa.sa_flags = (unsigned)(p->sa_flags); - - if (old_sa.sa_flags & SA_RESTART) - old_sa.sa_flags &= ~SA_RESTART; - else - old_sa.sa_flags |= SUNOS_SV_INTERRUPT; - if (copy_to_user((struct sigaction32 *)A(oldaction), - &old_sa, sigaction_size)) - return -EFAULT; - } + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (action) { - spin_lock_irq(¤t->sig->siglock); - p->sa_handler = (__sighandler_t)A(new_sa.sa_handler); - p->sa_mask = (sigset_t)(new_sa.sa_mask); - p->sa_flags = new_sa.sa_flags; - p->sa_restorer = (void (*)(void))0; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); + if (!ret && oact) { + old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; + if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) || + __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags)) + return -EFAULT; + __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask); } - return 0; -} + return ret; +} -extern asmlinkage int sys32_setsockopt(int fd, int level, int optname, - u32 optval, int optlen); +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); extern asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen); @@ -1488,7 +1432,7 @@ if (tr_opt >=2 && tr_opt <= 6) tr_opt += 30; } - ret = sys32_setsockopt(fd, level, tr_opt, optval, optlen); + ret = sys_setsockopt(fd, level, tr_opt, (char *)A(optval), optlen); unlock_kernel(); return ret; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.1.78/linux/arch/sparc64/kernel/systbls.S Wed Sep 24 20:05:46 1997 +++ linux/arch/sparc64/kernel/systbls.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.24 1997/08/22 20:12:06 davem Exp $ +/* $Id: systbls.S,v 1.37 1997/12/24 17:27:31 ecd Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -17,58 +17,58 @@ .globl sys_call_table32 sys_call_table32: -/*0*/ .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write -/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link -/*10*/ .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod -/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek +/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write +/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod +/*15*/ .word sys32_chmod, sys32_chown, sparc_brk, sys_nis_syscall, sys32_lseek /*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause -/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice - .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall -/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil - .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid -/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl - .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve -/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize - .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect +/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys32_pause +/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice + .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall +/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall + .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid +/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl + .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys32_execve +/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize + .word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_nis_syscall +/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys_munmap, sys_mprotect .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups /*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall - .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall + .word sys_swapon, sys32_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall /*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*100*/ .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending + .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall /*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall /*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod - .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate -/*130*/ .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate +/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit - .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount -/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall - .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall + .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write +/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_umount +/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall + .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname -/*190*/ .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock - .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask -/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir - .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall -/*210*/ .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo - .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex +/*190*/ .word sys32_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask +/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir + .word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall +/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo + .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex /*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall - .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall -/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall +/*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall + .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall +/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep -/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl - .word sys_aplib, sys_prctl +/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl + .word sys_aplib /* Now the 64-bit native Linux syscall table. */ @@ -81,23 +81,23 @@ /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod /*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek /*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause -/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice - .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall -/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil +/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_nis_syscall +/*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice + .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_nis_syscall +/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid -/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl +/*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize - .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups /*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall /*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept -/*100*/ .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind - .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*100*/ .word sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending + .word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall /*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall /*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod @@ -105,29 +105,29 @@ /*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit - .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write +/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount -/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall +/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname -/*190*/ .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock - .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask +/*190*/ .word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_sigaction, sys_sgetmask /*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall /*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex /*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall +/*230*/ .word sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_aplib, sys_prctl + .word sys_aplib /* Now the 32-bit SunOS syscall table. */ @@ -136,40 +136,40 @@ sunos_sys_table: /*0*/ .word sunos_indir, sys_exit, sys_fork .word sunos_read, sunos_write, sunos_open - .word sys_close, sunos_wait4, sys32_creat - .word sys32_link, sys32_unlink, sunos_execv - .word sys32_chdir, sunos_nosys, sys32_mknod + .word sys_close, sunos_wait4, sys_creat + .word sys_link, sys_unlink, sunos_execv + .word sys_chdir, sunos_nosys, sys32_mknod .word sys32_chmod, sys32_chown, sunos_brk .word sunos_nosys, sys32_lseek, sunos_getpid .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_getuid, sunos_nosys, sys_ptrace .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sunos_nosys - .word sys32_access, sunos_nosys, sunos_nosys + .word sys_access, sunos_nosys, sunos_nosys .word sys_sync, sys_kill, sys32_newstat .word sunos_nosys, sys32_newlstat, sys_dup - .word sys_pipe, sunos_nosys, sys_profil + .word sys_pipe, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sunos_getgid .word sunos_nosys, sunos_nosys -/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys - .word sunos_mctl, sunos_ioctl, sys32_reboot - .word sunos_nosys, sys32_symlink, sys32_readlink - .word sys32_execve, sys_umask, sys32_chroot +/*50*/ .word sunos_nosys, sys_acct, sunos_nosys + .word sunos_mctl, sunos_ioctl, sys_reboot + .word sunos_nosys, sys_symlink, sys_readlink + .word sys32_execve, sys_umask, sys_chroot .word sys32_newfstat, sunos_nosys, sys_getpagesize - .word sys32_msync, sys_vfork, sunos_nosys + .word sys_msync, sys_vfork, sunos_nosys .word sunos_nosys, sunos_sbrk, sunos_sstk - .word sunos_mmap, sunos_vadvise, sys32_munmap - .word sys32_mprotect, sunos_madvise, sys_vhangup + .word sunos_mmap, sunos_vadvise, sys_munmap + .word sys_mprotect, sunos_madvise, sys_vhangup .word sunos_nosys, sunos_mincore, sys32_getgroups .word sys32_setgroups, sys_getpgrp, sunos_setpgrp - .word sys32_setitimer, sunos_nosys, sys32_swapon - .word sys32_getitimer, sys32_gethostname, sys32_sethostname + .word sys32_setitimer, sunos_nosys, sys_swapon + .word sys32_getitimer, sys_gethostname, sys_sethostname .word sunos_getdtablesize, sys_dup2, sunos_nop .word sys32_fcntl, sunos_select, sunos_nop .word sys_fsync, sys_setpriority, sys_socket - .word sys32_connect, sunos_accept + .word sys_connect, sunos_accept /*100*/ .word sys_getpriority, sunos_send, sunos_recv - .word sunos_nosys, sys32_bind, sunos_setsockopt + .word sunos_nosys, sys_bind, sunos_setsockopt .word sys_listen, sunos_nosys, sunos_sigaction .word sunos_sigblock, sunos_sigsetmask, sys_sigpause .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg @@ -177,21 +177,21 @@ .word sunos_getsockopt, sunos_nosys, sunos_readv .word sunos_writev, sys32_settimeofday, sys_fchown .word sys_fchmod, sys32_recvfrom, sys32_setreuid - .word sys_setregid, sys32_rename, sys32_truncate - .word sys32_ftruncate, sys_flock, sunos_nosys + .word sys_setregid, sys_rename, sys_truncate + .word sys_ftruncate, sys_flock, sunos_nosys .word sys32_sendto, sys_shutdown, sys_socketpair - .word sys32_mkdir, sys32_rmdir, sys32_utimes - .word sys_sigreturn, sunos_nosys, sys32_getpeername + .word sys_mkdir, sys_rmdir, sys32_utimes + .word sys32_sigreturn, sunos_nosys, sys_getpeername .word sunos_gethostid, sunos_nosys, sys32_getrlimit .word sys32_setrlimit, sunos_killpg, sunos_nosys .word sunos_nosys, sunos_nosys -/*150*/ .word sys32_getsockname, sunos_nosys, sunos_nosys - .word sys32_poll, sunos_nosys, sunos_nosys +/*150*/ .word sys_getsockname, sunos_nosys, sunos_nosys + .word sys_poll, sunos_nosys, sunos_nosys .word sunos_getdirentries, sys32_statfs, sys32_fstatfs - .word sys32_umount, sunos_nosys, sunos_nosys - .word sunos_getdomainname, sys32_setdomainname + .word sys_umount, sunos_nosys, sunos_nosys + .word sunos_getdomainname, sys_setdomainname .word sunos_nosys, sys32_quotactl, sunos_nosys - .word sunos_mount, sys32_ustat, sunos_semsys + .word sunos_mount, sys_ustat, sunos_semsys .word sunos_nosys, sunos_shmsys, sunos_audit .word sunos_nosys, sunos_getdents, sys_setsid .word sys_fchdir, sunos_nosys, sunos_nosys @@ -221,4 +221,3 @@ .word sunos_nosys, sunos_nosys /*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sys_aplib - .word sunos_nosys diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c --- v2.1.78/linux/arch/sparc64/kernel/traps.c Mon Aug 18 18:19:45 1997 +++ linux/arch/sparc64/kernel/traps.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $ +/* $Id: traps.c,v 1.44 1998/01/09 16:39:35 jj Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -26,9 +26,13 @@ #include #include #include +#ifdef CONFIG_KERNELD +#include +#endif /* #define SYSCALL_TRACING */ /* #define VERBOSE_SYSCALL_TRACING */ +/* #define DEBUG_FPU */ #ifdef SYSCALL_TRACING #ifdef VERBOSE_SYSCALL_TRACING @@ -125,8 +129,9 @@ int i; #endif - if(strcmp(current->comm, "bash.sunos")) - return; +#if 0 + if (!current->pid) return; +#endif printk("SYS[%s:%d]: PC(%016lx) <%3d> ", current->comm, current->pid, regs->tpc, (int)g1); #ifdef VERBOSE_SYSCALL_TRACING @@ -141,12 +146,20 @@ for(i = 0; i < sdp->num_args; i++) { if(i) printk(","); - if(!sdp->arg_is_string[i]) - printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); - else { - strncpy_from_user(scall_strbuf, - (char *)regs->u_regs[UREG_I0 + i], - 512); + if(!sdp->arg_is_string[i]) { + if (current->tss.flags & SPARC_FLAG_32BIT) + printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); + else + printk("%016lx", regs->u_regs[UREG_I0 + i]); + } else { + if (current->tss.flags & SPARC_FLAG_32BIT) + strncpy_from_user(scall_strbuf, + (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff), + 512); + else + strncpy_from_user(scall_strbuf, + (char *)regs->u_regs[UREG_I0 + i], + 512); printk("%s", scall_strbuf); } } @@ -157,7 +170,9 @@ unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) { - if(!strcmp(current->comm, "bash.sunos")) +#if 0 + if (current->pid) +#endif printk("ret[%016lx]\n", retval); return retval; } @@ -192,6 +207,24 @@ void data_access_exception (struct pt_regs *regs) { + if (regs->tstate & TSTATE_PRIV) { + /* Test if this comes from uaccess places. */ + unsigned long fixup, g2; + + g2 = regs->u_regs[UREG_G2]; + if ((fixup = search_exception_table (regs->tpc, &g2))) { + /* Ouch, somebody is trying ugly VM hole tricks on us... */ +#ifdef DEBUG_EXCEPTIONS + printk("Exception: PC<%016lx> faddr\n", regs->tpc); + printk("EX_TABLE: insn<%016lx> fixup<%016lx> " + "g2<%016lx>\n", regs->tpc, fixup, g2); +#endif + regs->tpc = fixup; + regs->tnpc = regs->tpc + 4; + regs->u_regs[UREG_G2] = g2; + return; + } + } send_sig(SIGSEGV, current, 1); } @@ -271,11 +304,46 @@ void do_fpieee(struct pt_regs *regs) { +#ifdef DEBUG_FPU + struct fpustate *f = FPUSTATE; + + printk("fpieee %016lx\n", f->fsr); +#endif do_fpe_common(regs); } +#ifdef CONFIG_MATHEMU_MODULE +volatile int (*handle_mathemu)(struct pt_regs *, struct fpustate *) = NULL; +#else +extern int do_mathemu(struct pt_regs *, struct fpustate *); +#endif + void do_fpother(struct pt_regs *regs) { + struct fpustate *f = FPUSTATE; + int ret = 0; + + switch ((f->fsr & 0x1c000)) { + case (2 << 14): /* unfinished_FPop */ + case (3 << 14): /* unimplemented_FPop */ +#ifdef CONFIG_MATHEMU_MODULE +#ifdef CONFIG_KERNELD + if (!handle_mathemu) + request_module("math-emu"); +#endif + if (handle_mathemu) + ret = handle_mathemu(regs, f); +#else +#ifdef CONFIG_MATHEMU + ret = do_mathemu(regs, f); +#endif +#endif + break; + } + if (ret) return; +#ifdef DEBUG_FPU + printk("fpother %016lx\n", f->fsr); +#endif do_fpe_common(regs); } @@ -298,7 +366,7 @@ int i; if((((unsigned long) pc) & 3)) - return; + return; for(i = -3; i < 6; i++) printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>'); @@ -332,33 +400,51 @@ (rw->ins[6] + STACK_BIAS); } } - printk("Instruction DUMP:"); - instruction_dump ((unsigned int *) regs->tpc); + if(regs->tstate & TSTATE_PRIV) { + printk("Instruction DUMP:"); + instruction_dump ((unsigned int *) regs->tpc); + } lock_kernel(); /* Or else! */ if(regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); do_exit(SIGSEGV); } +extern int handle_popc(u32 insn, struct pt_regs *regs); +extern int handle_ldq_stq(u32 insn, struct pt_regs *regs); + void do_illegal_instruction(struct pt_regs *regs) { unsigned long pc = regs->tpc; unsigned long tstate = regs->tstate; + u32 insn; if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); + if(current->tss.flags & SPARC_FLAG_32BIT) + pc = (u32)pc; + if (get_user(insn, (u32 *)pc) != -EFAULT) { + if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ { + if (handle_popc(insn, regs)) + return; + } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ { + if (handle_ldq_stq(insn, regs)) + return; + } + } current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); } -void mem_address_unaligned(struct pt_regs *regs) +void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) { if(regs->tstate & TSTATE_PRIV) { extern void kernel_unaligned_trap(struct pt_regs *regs, - unsigned int insn); + unsigned int insn, + unsigned long sfar, unsigned long sfsr); - return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc)); + return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr); } else { current->tss.sig_address = regs->tpc; current->tss.sig_desc = SUBSIG_PRIVINST; @@ -390,22 +476,6 @@ send_sig(SIGILL, current, 1); } -/* XXX User may want to be allowed to do this. XXX */ - -void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long tstate) -{ - if(regs->tstate & TSTATE_PRIV) { - printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc, - regs->u_regs[UREG_RETPC]); - die_if_kernel("BOGUS", regs); - /* die_if_kernel("Kernel MNA access", regs); */ - } - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGBUS, current, 1); -} - void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { @@ -463,19 +533,9 @@ die_if_kernel("TL1: IRQ Exception", regs); } -void do_lddfmna(struct pt_regs *regs) -{ - die_if_kernel("TL0: LDDF Exception", regs); -} - void do_lddfmna_tl1(struct pt_regs *regs) { die_if_kernel("TL1: LDDF Exception", regs); -} - -void do_stdfmna(struct pt_regs *regs) -{ - die_if_kernel("TL0: STDF Exception", regs); } void do_stdfmna_tl1(struct pt_regs *regs) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S --- v2.1.78/linux/arch/sparc64/kernel/ttable.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/ttable.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.20 1997/08/29 15:51:39 jj Exp $ +/* $Id: ttable.S,v 1.22 1997/10/16 07:07:46 jj Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -33,8 +33,8 @@ tl0_dae: TRAP(do_dae) tl0_resv033: BTRAP(0x33) tl0_mna: TRAP_NOSAVE(do_mna) -tl0_lddfmna: TRAP(do_lddfmna) -tl0_stdfmna: TRAP(do_stdfmna) +tl0_lddfmna: TRAP_NOSAVE(do_lddfmna) +tl0_stdfmna: TRAP_NOSAVE(do_stdfmna) tl0_privact: TRAP(do_privact) tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d) tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) @@ -106,10 +106,14 @@ tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e) tl0_resv10f: BTRAP(0x10f) tl0_linux32: LINUX_32BIT_SYSCALL_TRAP -tl0_linux64: LINUX_64BIT_SYSCALL_TRAP -tl0_resv112: BTRAP(0x112) BTRAP(0x113) BTRAP(0x114) BTRAP(0x115) BTRAP(0x116) -tl0_resv117: BTRAP(0x117) BTRAP(0x118) BTRAP(0x119) BTRAP(0x11a) BTRAP(0x11b) -tl0_resv11c: BTRAP(0x11c) BTRAP(0x11d) BTRAP(0x11e) BTRAP(0x11f) +tl0_oldlinux64: LINUX_64BIT_SYSCALL_TRAP +tl0_resv112: TRAP_UTRAP(UT_TRAP_INSTRUCTION_18,0x112) TRAP_UTRAP(UT_TRAP_INSTRUCTION_19,0x113) +tl0_resv114: TRAP_UTRAP(UT_TRAP_INSTRUCTION_20,0x114) TRAP_UTRAP(UT_TRAP_INSTRUCTION_21,0x115) +tl0_resv116: TRAP_UTRAP(UT_TRAP_INSTRUCTION_22,0x116) TRAP_UTRAP(UT_TRAP_INSTRUCTION_23,0x117) +tl0_resv118: TRAP_UTRAP(UT_TRAP_INSTRUCTION_24,0x118) TRAP_UTRAP(UT_TRAP_INSTRUCTION_25,0x119) +tl0_resv11a: TRAP_UTRAP(UT_TRAP_INSTRUCTION_26,0x11a) TRAP_UTRAP(UT_TRAP_INSTRUCTION_27,0x11b) +tl0_resv11c: TRAP_UTRAP(UT_TRAP_INSTRUCTION_28,0x11c) TRAP_UTRAP(UT_TRAP_INSTRUCTION_29,0x11d) +tl0_resv11e: TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f) tl0_getcc: GETCC_TRAP tl0_setcc: SETCC_TRAP tl0_resv122: BTRAP(0x122) BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126) @@ -127,7 +131,8 @@ tl0_resv15a: BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e) tl0_resv15f: BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163) tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168) -tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) BTRAP(0x16d) +tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) +tl0_linux64: LINUX_64BIT_SYSCALL_TRAP tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) tl0_resv170: BTRAP(0x170) BTRAP(0x171) #ifdef CONFIG_EC_FLUSH_TRAP diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c --- v2.1.78/linux/arch/sparc64/kernel/unaligned.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/kernel/unaligned.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.4 1997/08/19 15:25:11 jj Exp $ +/* $Id: unaligned.c,v 1.8 1997/10/14 16:21:24 jj Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -17,6 +17,8 @@ #include #include #include +#include +#include /* #define DEBUG_MNA */ @@ -24,8 +26,8 @@ load, /* ld, ldd, ldh, ldsh */ store, /* st, std, sth, stsh */ both, /* Swap, ldstub, cas, ... */ - fpload, - fpstore, + fpld, + fpst, invalid, }; @@ -101,34 +103,52 @@ return imm << 51 >> 51; } -static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) +static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) { - struct reg_window *win; - + unsigned long value; + if(reg < 16) return (!reg ? 0 : regs->u_regs[reg]); - - /* Ho hum, the slightly complicated case. */ - win = (struct reg_window *) regs->u_regs[UREG_FP]; - return win->locals[reg - 16]; /* yes, I know what this does... */ + if (regs->tstate & TSTATE_PRIV) { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + value = win->locals[reg - 16]; + } else if (current->tss.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + get_user(value, &win32->locals[reg - 16]); + } else { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + get_user(value, &win->locals[reg - 16]); + } + return value; } -static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) +static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) { - struct reg_window *win; - if(reg < 16) return ®s->u_regs[reg]; - win = (struct reg_window *) regs->u_regs[UREG_FP]; - return &win->locals[reg - 16]; + if (regs->tstate & TSTATE_PRIV) { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + return &win->locals[reg - 16]; + } else if (current->tss.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + return (unsigned long *)&win32->locals[reg - 16]; + } else { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + return &win->locals[reg - 16]; + } } static inline unsigned long compute_effective_address(struct pt_regs *regs, - unsigned int insn) + unsigned int insn, unsigned int rd) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; - unsigned int rd = (insn >> 25) & 0x1f; if(insn & 0x2000) { maybe_flush_windows(rs1, 0, rd); @@ -326,7 +346,7 @@ unsigned long fixup = search_exception_table (regs->tpc, &g2); if (!fixup) { - unsigned long address = compute_effective_address(regs, insn); + unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); if(address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler"); } else @@ -344,7 +364,7 @@ regs->u_regs [UREG_G2] = g2; } -asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) +asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) { enum direction dir = decode_direction(insn); int size = decode_access_size(insn); @@ -365,7 +385,7 @@ : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7", "cc"); } else { - unsigned long addr = compute_effective_address(regs, insn); + unsigned long addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); #ifdef DEBUG_MNA printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n", @@ -401,117 +421,243 @@ unlock_kernel(); } -#if 0 /* XXX: Implement user mna some day */ -static inline int ok_for_user(struct pt_regs *regs, unsigned int insn, - enum direction dir) -{ - unsigned int reg; - int retval, check = (dir == load) ? VERIFY_READ : VERIFY_WRITE; - int size = ((insn >> 19) & 3) == 3 ? 8 : 4; - - if((regs->pc | regs->npc) & 3) - return 0; +static char popc_helper[] = { +0, 1, 1, 2, 1, 2, 2, 3, +1, 2, 2, 3, 2, 3, 3, 4, +}; - /* Must verify_area() in all the necessary places. */ -#define WINREG_ADDR(regnum) ((void *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum))) - retval = 0; - reg = (insn >> 25) & 0x1f; - if(reg >= 16) { - retval = verify_area(check, WINREG_ADDR(reg - 16), size); - if(retval) - return retval; +int handle_popc(u32 insn, struct pt_regs *regs) +{ + u64 value; + int ret, i, rd = ((insn >> 25) & 0x1f); + + if (insn & 0x2000) { + maybe_flush_windows(0, 0, rd); + value = sign_extend_imm13(insn); + } else { + maybe_flush_windows(0, insn & 0x1f, rd); + value = fetch_reg(insn & 0x1f, regs); } - reg = (insn >> 14) & 0x1f; - if(reg >= 16) { - retval = verify_area(check, WINREG_ADDR(reg - 16), size); - if(retval) - return retval; + for (ret = 0, i = 0; i < 16; i++) { + ret += popc_helper[value & 0xf]; + value >>= 4; } - if(!(insn & 0x2000)) { - reg = (insn & 0x1f); - if(reg >= 16) { - retval = verify_area(check, WINREG_ADDR(reg - 16), size); - if(retval) - return retval; + if(rd < 16) { + if (rd) + regs->u_regs[rd] = ret; + } else { + if (current->tss.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + put_user(ret, &win32->locals[rd - 16]); + } else { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + get_user(ret, &win->locals[rd - 16]); } } - return retval; -#undef WINREG_ADDR + advance(regs); + return 1; } -void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault"); +extern void do_fpother(struct pt_regs *regs); +extern void do_privact(struct pt_regs *regs); +extern void data_access_exception(struct pt_regs *regs); + +int handle_ldq_stq(u32 insn, struct pt_regs *regs) +{ + unsigned long addr = compute_effective_address(regs, insn, 0); + int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + struct fpustate *f = FPUSTATE; + int asi = decode_asi(insn, regs); + int flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + + f->fsr &= ~0x1c000; + if (freg & 3) { + f->fsr |= (6 << 14) /* invalid_fp_register */; + do_fpother(regs); + return 0; + } + if (insn & 0x200000) { + /* STQ */ + u64 first = 0, second = 0; + + if (current->tss.flags & flag) { + first = *(u64 *)&f->regs[freg]; + second = *(u64 *)&f->regs[freg+2]; + } + if (asi < 0x80) { + do_privact(regs); + return 1; + } + switch (asi) { + case ASI_P: + case ASI_S: break; + case ASI_PL: + case ASI_SL: + { + /* Need to convert endians */ + u64 tmp = __swab64p(&first); + + first = __swab64p(&second); + second = tmp; + break; + } + default: + data_access_exception(regs); + return 1; + } + if (put_user (first >> 32, (u32 *)addr) || + __put_user ((u32)first, (u32 *)(addr + 4)) || + __put_user (second >> 32, (u32 *)(addr + 8)) || + __put_user ((u32)second, (u32 *)(addr + 12))) { + data_access_exception(regs); + return 1; + } + } else { + /* LDQ */ + u32 first, second, third, fourth; -void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) -{ - current->tss.sig_address = regs->pc; - current->tss.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGBUS, current, 1); + if (asi < 0x80) { + do_privact(regs); + return 1; + } else if (asi > ASI_SNFL) { + data_access_exception(regs); + return 1; + } + if (get_user (first, (u32 *)addr) || + __get_user (second, (u32 *)(addr + 4)) || + __get_user (third, (u32 *)(addr + 8)) || + __get_user (fourth, (u32 *)(addr + 12))) { + if (asi & 0x2) /* NF */ { + first = 0; second = 0; third = 0; fourth = 0; + } else { + data_access_exception(regs); + return 1; + } + } + if (asi & 0x8) /* Little */ { + u32 tmp = le32_to_cpup(&first); + + first = le32_to_cpup(&fourth); + fourth = tmp; + tmp = le32_to_cpup(&second); + second = le32_to_cpup(&third); + third = tmp; + } + regs->fprs |= FPRS_FEF; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { + current->tss.flags |= SPARC_FLAG_USEDFPU; + f->fsr = 0; + f->gsr = 0; + } + if (!(current->tss.flags & flag)) { + if (freg < 32) + memset(f->regs, 0, 32*sizeof(u32)); + else + memset(f->regs+32, 0, 32*sizeof(u32)); + } + f->regs[freg] = first; + f->regs[freg+1] = second; + f->regs[freg+2] = third; + f->regs[freg+3] = fourth; + current->tss.flags |= flag; + } + advance(regs); + return 1; } -asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) +void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) { - enum direction dir; - - lock_kernel(); - if(!(current->tss.flags & SPARC_FLAG_UNALIGNED) || - (((insn >> 30) & 3) != 3)) - goto kill_user; - dir = decode_direction(insn); - if(!ok_for_user(regs, insn, dir)) { - goto kill_user; - } else { - int size = decode_access_size(insn); - unsigned long addr; - - if(floating_point_load_or_store_p(insn)) { - printk("User FPU load/store unaligned unsupported.\n"); - goto kill_user; + unsigned long pc = regs->tpc; + unsigned long tstate = regs->tstate; + u32 insn; + u32 first, second; + u64 value; + u8 asi, freg; + int flag; + struct fpustate *f = FPUSTATE; + + if(tstate & TSTATE_PRIV) + die_if_kernel("lddfmna from kernel", regs); + if(current->tss.flags & SPARC_FLAG_32BIT) + pc = (u32)pc; + if (get_user(insn, (u32 *)pc) != -EFAULT) { + asi = sfsr >> 16; + if (asi > ASI_SNFL) + goto daex; + if (get_user(first, (u32 *)sfar) || + get_user(second, (u32 *)(sfar + 4))) { + if (asi & 0x2) /* NF */ { + first = 0; second = 0; + } else + goto daex; } - - addr = compute_effective_address(regs, insn); - switch(dir) { - case load: - do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), - size, (unsigned long *) addr, - decode_signedness(insn), - user_unaligned_trap_fault); - break; - - case store: - do_integer_store(((insn>>25)&0x1f), size, - (unsigned long *) addr, regs, - user_unaligned_trap_fault); - break; - - case both: - do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), - (unsigned long *) addr, - user_unaligned_trap_fault); - break; - - default: - unaligned_panic("Impossible user unaligned trap."); - - __asm__ __volatile__ ("\n" -"user_unaligned_trap_fault:\n\t" - "mov %0, %%o0\n\t" - "call user_mna_trap_fault\n\t" - " mov %1, %%o1\n\t" - : - : "r" (regs), "r" (insn) - : "o0", "o1", "o2", "o3", "o4", "o5", "o7", - "g1", "g2", "g3", "g4", "g5", "g7", "cc"); - goto out; + freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + value = (((u64)first) << 32) | second; + if (asi & 0x8) /* Little */ + value = __swab64p(&value); + flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + regs->fprs |= FPRS_FEF; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { + current->tss.flags |= SPARC_FLAG_USEDFPU; + f->fsr = 0; + f->gsr = 0; } - advance(regs); - goto out; + if (!(current->tss.flags & flag)) { + if (freg < 32) + memset(f->regs, 0, 32*sizeof(u32)); + else + memset(f->regs+32, 0, 32*sizeof(u32)); + } + *(u64 *)(f->regs + freg) = value; + current->tss.flags |= flag; + } else { +daex: data_access_exception(regs); + return; } + advance(regs); + return; +} -kill_user: - current->tss.sig_address = regs->pc; - current->tss.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGBUS, current, 1); -out: - unlock_kernel(); +void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) +{ + unsigned long pc = regs->tpc; + unsigned long tstate = regs->tstate; + u32 insn; + u64 value; + u8 asi, freg; + int flag; + struct fpustate *f = FPUSTATE; + + if(tstate & TSTATE_PRIV) + die_if_kernel("stdfmna from kernel", regs); + if(current->tss.flags & SPARC_FLAG_32BIT) + pc = (u32)pc; + if (get_user(insn, (u32 *)pc) != -EFAULT) { + freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + asi = sfsr >> 16; + value = 0; + flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + if (asi > ASI_SNFL) + goto daex; + if (current->tss.flags & flag) + value = *(u64 *)&f->regs[freg]; + switch (asi) { + case ASI_P: + case ASI_S: break; + case ASI_PL: + case ASI_SL: + value = __swab64p(&value); break; + default: goto daex; + } + if (put_user (value >> 32, (u32 *)sfar) || + __put_user ((u32)value, (u32 *)(sfar + 4))) + goto daex; + } else { +daex: data_access_exception(regs); + return; + } + advance(regs); + return; } -#endif diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S --- v2.1.78/linux/arch/sparc64/kernel/winfixup.S Mon Aug 18 18:19:45 1997 +++ linux/arch/sparc64/kernel/winfixup.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $ +/* $Id: winfixup.S,v 1.22 1997/10/24 11:57:48 jj Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -48,6 +48,10 @@ * most things are where they need to be, we also have the address * which triggered the fault handy as well. * + * Also note that we must preserve %l5 and %l6. If the user was + * returning from a system call, we must make it look this way + * after we process the fill fault on the users stack. + * * First, get into the window where the original restore was executed. */ @@ -65,15 +69,23 @@ rdpr %pstate, %l1 ! Prepare to change globals. mov %g6, %o7 ! Get current. - mov %g5, %l5 ! Fault address - clr %l4 ! It was a load, not a store + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + srlx %g5, PAGE_SHIFT, %o1 ! Fault address wrpr %g0, 0x0, %tl ! Out of trap levels. wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate sethi %uhi(PAGE_OFFSET), %g4 ! Prepare page_offset global reg mov %o7, %g6 - b,pt %xcc, window_scheisse_merge ! And merge. + sllx %g4, 32, %g4 ! and finish it... + clr %o2 - sllx %g4, 32, %g4 ! and finish it... + /* This is the same as below, except we handle this a bit special + * since we must preserve %l5 and %l6, see comment above. + */ + sllx %o1, PAGE_SHIFT, %o1 + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + b,pt %xcc, rtrap + nop ! yes, nop is correct /* Be very careful about usage of the alternate globals here. * You cannot touch %g4/%g5 as that has the fault information @@ -84,59 +96,59 @@ * do not touch %g7 or %g2 so we handle the two cases fine. */ spill_fixup: - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 andcc %g1, SPARC_FLAG_32BIT, %g0 - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + sll %g1, 3, %g3 add %g6, %g3, %g3 stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] sll %g1, 7, %g3 - bne,pt %xcc, 1f add %g6, %g3, %g3 stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] + stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] - stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] b,pt %xcc, 2f stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] 1: stw %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + stw %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04] stw %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] stw %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c] stw %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - stw %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14] stw %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] stw %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c] stw %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + stw %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24] stw %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] stw %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c] stw %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - stw %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34] stw %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] stw %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c] 2: add %g1, 1, %g1 - stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] + + sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] rdpr %tstate, %g1 andcc %g1, TSTATE_PRIV, %g0 saved - and %g1, TSTATE_CWP, %g1 be,a,pn %xcc, window_scheisse_from_user_common or %g4, 0x4, %g4 ! we know it was a write @@ -146,7 +158,6 @@ sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 -window_scheisse_merge: srlx %l5, PAGE_SHIFT, %o1 and %l4, 0x4, %o2 @@ -173,10 +184,15 @@ andcc %g1, TSTATE_PRIV, %g0 be,pt %xcc, window_mna_from_user_common and %g1, TSTATE_CWP, %g1 + + /* Please, see fill_fixup commentary about why we must preserve + * %l5 and %l6 to preserve absolute correct semantics. + */ rdpr %wstate, %g2 ! Grab user mode wstate. wrpr %g1, %cwp ! Get into the right window. sll %g2, 3, %g2 ! NORMAL-->OTHER wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + wrpr %g2, 0x0, %wstate ! This must be consistant. wrpr %g0, 0x0, %otherwin ! We know this. mov PRIMARY_CONTEXT, %g1 ! Change contexts... @@ -185,23 +201,28 @@ rdpr %pstate, %l1 ! Prepare to change globals. mov %g4, %o5 ! Setup args for mov %g5, %o4 ! final call to do_sparc64_fault. + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + mov %g6, %o7 ! Stash away current. wrpr %g0, 0x0, %tl ! Out of trap levels. wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg. mov %o7, %g6 ! Get current back. - b,pt %xcc, window_mna_merge ! And merge. - sllx %g4, 32, %g4 ! Finish it. + sllx %g4, 32, %g4 ! Finish it. + call mem_address_unaligned + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + b,pt %xcc, rtrap + nop ! yes, the nop is correct spill_fixup_mna: - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 andcc %g1, SPARC_FLAG_32BIT, %g0 - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 sll %g1, 3, %g3 add %g6, %g3, %g3 stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] - sll %g1, 7, %g3 + sll %g1, 7, %g3 bne,pt %xcc, 1f add %g6, %g3, %g3 stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] @@ -209,8 +230,8 @@ stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] @@ -218,8 +239,8 @@ stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] - stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] + stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] b,pt %xcc, 2f @@ -227,16 +248,15 @@ 1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] add %g1, 1, %g1 -2: stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] +2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] rdpr %tstate, %g1 - nop andcc %g1, TSTATE_PRIV, %g0 saved @@ -248,7 +268,6 @@ sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 -window_mna_merge: call mem_address_unaligned add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S --- v2.1.78/linux/arch/sparc64/lib/checksum.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/lib/checksum.S Mon Jan 12 15:15:44 1998 @@ -35,204 +35,6 @@ /* I think I have an erection... Once _AGAIN_ the SunSoft * engineers are caught asleep at the keyboard, tsk tsk... */ -#define CSUMCOPY_ECACHE_LOAD(off, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldxa [%src + off + 0x00] %asi, t0; \ - ldxa [%src + off + 0x08] %asi, t1; \ - ldxa [%src + off + 0x10] %asi, t2; \ - ldxa [%src + off + 0x18] %asi, t3; \ - ldxa [%src + off + 0x20] %asi, t4; \ - ldxa [%src + off + 0x28] %asi, t5; \ - ldxa [%src + off + 0x30] %asi, t6; \ - ldxa [%src + off + 0x38] %asi, t7; \ - nop; nop; /* DO NOT TOUCH THIS!!!!! */ - -#define CSUMCOPY_EC_STALIGNED_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \ - stx t0, [%dst + off - 0x40]; \ - addcc %sum, t0, %sum; \ - bcc,pt %xcc, 11f; \ - ldxa [%src + off + 0x00] %asi, t0; \ - add %sum, 1, %sum; \ -11: stx t1, [%dst + off - 0x38]; \ - addcc %sum, t1, %sum; \ - bcc,pt %xcc, 12f; \ - ldxa [%src + off + 0x08] %asi, t1; \ - add %sum, 1, %sum; \ -12: stx t2, [%dst + off - 0x30]; \ - addcc %sum, t2, %sum; \ - bcc,pt %xcc, 13f; \ - ldxa [%src + off + 0x10] %asi, t2; \ - add %sum, 1, %sum; \ -13: stx t3, [%dst + off - 0x28]; \ - addcc %sum, t3, %sum; \ - bcc,pt %xcc, 14f; \ - ldxa [%src + off + 0x18] %asi, t3; \ - add %sum, 1, %sum; \ -14: stx t4, [%dst + off - 0x20]; \ - addcc %sum, t4, %sum; \ - bcc,pt %xcc, 15f; \ - ldxa [%src + off + 0x20] %asi, t4; \ - add %sum, 1, %sum; \ -15: stx t5, [%dst + off - 0x18]; \ - addcc %sum, t5, %sum; \ - bcc,pt %xcc, 16f; \ - ldxa [%src + off + 0x28] %asi, t5; \ - add %sum, 1, %sum; \ -16: stx t6, [%dst + off - 0x10]; \ - addcc %sum, t6, %sum; \ - bcc,pt %xcc, 17f; \ - ldxa [%src + off + 0x30] %asi, t6; \ - add %sum, 1, %sum; \ -17: stx t7, [%dst + off - 0x08]; \ - addcc %sum, t7, %sum; \ - bcc,pt %xcc, 18f; \ - ldxa [%src + off + 0x38] %asi, t7; \ - add %sum, 1, %sum; \ -18: - -#define CSUMCOPY_EC_STUNALIGN_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \ - stw t0, [%dst + off - 0x3c]; \ - addcc %sum, t0, %sum; \ - srlx t0, 32, t0; \ - stw t0, [%dst + off - 0x40]; \ - bcc,pt %xcc, 21f; \ - ldxa [%src + off + 0x00] %asi, t0; \ - add %sum, 1, %sum; \ -21: stw t1, [%dst + off - 0x34]; \ - addcc %sum, t1, %sum; \ - srlx t1, 32, t1; \ - stw t1, [%dst + off - 0x38]; \ - bcc,pt %xcc, 22f; \ - ldxa [%src + off + 0x08] %asi, t1; \ - add %sum, 1, %sum; \ -22: stw t2, [%dst + off - 0x2c]; \ - addcc %sum, t2, %sum; \ - srlx t2, 32, t2; \ - stw t2, [%dst + off - 0x30]; \ - bcc,pt %xcc, 23f; \ - ldxa [%src + off + 0x10] %asi, t2; \ - add %sum, 1, %sum; \ -23: stw t3, [%dst + off - 0x24]; \ - addcc %sum, t3, %sum; \ - srlx t3, 32, t3; \ - stw t3, [%dst + off - 0x28]; \ - bcc,pt %xcc, 24f; \ - ldxa [%src + off + 0x18] %asi, t3; \ - add %sum, 1, %sum; \ -24: stw t4, [%dst + off - 0x1c]; \ - addcc %sum, t4, %sum; \ - srlx t4, 32, t4; \ - stw t4, [%dst + off - 0x20]; \ - bcc,pt %xcc, 25f; \ - ldxa [%src + off + 0x20] %asi, t4; \ - add %sum, 1, %sum; \ -25: stw t5, [%dst + off - 0x14]; \ - addcc %sum, t5, %sum; \ - srlx t5, 32, t5; \ - stw t5, [%dst + off - 0x18]; \ - bcc,pt %xcc, 26f; \ - ldxa [%src + off + 0x28] %asi, t5; \ - add %sum, 1, %sum; \ -26: stw t6, [%dst + off - 0x0c]; \ - addcc %sum, t6, %sum; \ - srlx t6, 32, t6; \ - stw t6, [%dst + off - 0x10]; \ - bcc,pt %xcc, 27f; \ - ldxa [%src + off + 0x30] %asi, t6; \ - add %sum, 1, %sum; \ -27: stw t7, [%dst + off - 0x04]; \ - addcc %sum, t7, %sum; \ - srlx t7, 32, t7; \ - stw t7, [%dst + off - 0x08]; \ - bcc,pt %xcc, 28f; \ - ldxa [%src + off + 0x38] %asi, t7; \ - add %sum, 1, %sum; \ -28: - -#define CSUMCOPY_EC_STALIGNED(off, t0, t1, t2, t3, t4, t5, t6, t7) \ - addcc %sum, t0, %sum; \ - bcc,pt %xcc, 31f; \ - stx t0, [%dst + off + 0x00]; \ - add %sum, 1, %sum; \ -31: addcc %sum, t1, %sum; \ - bcc,pt %xcc, 32f; \ - stx t1, [%dst + off + 0x08]; \ - add %sum, 1, %sum; \ -32: addcc %sum, t2, %sum; \ - bcc,pt %xcc, 33f; \ - stx t2, [%dst + off + 0x10]; \ - add %sum, 1, %sum; \ -33: addcc %sum, t3, %sum; \ - bcc,pt %xcc, 34f; \ - stx t3, [%dst + off + 0x18]; \ - add %sum, 1, %sum; \ -34: addcc %sum, t4, %sum; \ - bcc,pt %xcc, 35f; \ - stx t4, [%dst + off + 0x20]; \ - add %sum, 1, %sum; \ -35: addcc %sum, t5, %sum; \ - bcc,pt %xcc, 36f; \ - stx t5, [%dst + off + 0x28]; \ - add %sum, 1, %sum; \ -36: addcc %sum, t6, %sum; \ - bcc,pt %xcc, 37f; \ - stx t6, [%dst + off + 0x30]; \ - add %sum, 1, %sum; \ -37: addcc %sum, t7, %sum; \ - bcc,pt %xcc, 38f; \ - stx t7, [%dst + off + 0x38]; \ - add %sum, 1, %sum; \ -38: - -#define CSUMCOPY_EC_STUNALIGN(off, t0, t1, t2, t3, t4, t5, t6, t7) \ - stw t0, [%dst + off + 0x04]; \ - addcc %sum, t0, %sum; \ - srlx t0, 32, t0; \ - bcc,pt %xcc, 41f; \ - stw t0, [%dst + off + 0x00]; \ - add %sum, 1, %sum; \ -41: stw t1, [%dst + off + 0x0c]; \ - addcc %sum, t1, %sum; \ - srlx t1, 32, t1; \ - bcc,pt %xcc, 42f; \ - stw t1, [%dst + off + 0x08]; \ - add %sum, 1, %sum; \ -42: stw t2, [%dst + off + 0x14]; \ - addcc %sum, t2, %sum; \ - srlx t2, 32, t2; \ - bcc,pt %xcc, 43f; \ - stw t2, [%dst + off + 0x10]; \ - add %sum, 1, %sum; \ -43: stw t3, [%dst + off + 0x1c]; \ - addcc %sum, t3, %sum; \ - srlx t3, 32, t3; \ - bcc,pt %xcc, 44f; \ - stw t3, [%dst + off + 0x18]; \ - add %sum, 1, %sum; \ -44: stw t4, [%dst + off + 0x24]; \ - addcc %sum, t4, %sum; \ - srlx t4, 32, t4; \ - bcc,pt %xcc, 45f; \ - stw t4, [%dst + off + 0x20]; \ - add %sum, 1, %sum; \ -45: stw t5, [%dst + off + 0x2c]; \ - addcc %sum, t5, %sum; \ - srlx t5, 32, t5; \ - bcc,pt %xcc, 46f; \ - stw t5, [%dst + off + 0x28]; \ - add %sum, 1, %sum; \ -46: stw t6, [%dst + off + 0x34]; \ - addcc %sum, t6, %sum; \ - srlx t6, 32, t6; \ - bcc,pt %xcc, 47f; \ - stw t6, [%dst + off + 0x30]; \ - add %sum, 1, %sum; \ -47: stw t7, [%dst + off + 0x3c]; \ - addcc %sum, t7, %sum; \ - srlx t7, 32, t7; \ - bcc,pt %xcc, 48f; \ - stw t7, [%dst + off + 0x38]; \ - add %sum, 1, %sum; \ -48: #define CSUMCOPY_LASTCHUNK(off, t0, t1) \ ldxa [%src - off - 0x08] %asi, t0; \ @@ -296,6 +98,7 @@ add %sum, 1, %sum ! IEU1 cc_fixit: + cmp %len, 6 ! IEU1 Group bl,a,pn %icc, ccte ! CTI andcc %len, 0xf, %g7 ! IEU1 Group andcc %src, 2, %g0 ! IEU1 Group @@ -316,17 +119,17 @@ sll %g3, 16, %g3 ! IEU0 Group srl %sum, 16, %sum ! IEU0 Group or %g3, %sum, %sum ! IEU0 Group (regdep) -1: be,pt %icc, cc_dword_aligned ! CTI - andn %len, 0xff, %g2 ! IEU1 +1: be,pt %icc, ccmerge ! CTI + andcc %len, 0xf0, %g1 ! IEU1 lduwa [%src + 0x00] %asi, %g4 ! Load Group sub %len, 4, %len ! IEU0 add %src, 4, %src ! IEU1 add %dst, 4, %dst ! IEU0 Group addcc %g4, %sum, %sum ! IEU1 Group + 1 bubble stw %g4, [%dst - 0x4] ! Store - bcc,pt %xcc, cc_dword_aligned ! CTI - andn %len, 0xff, %g2 ! IEU0 Group - b,pt %xcc, cc_dword_aligned ! CTI 4 clocks (mispredict) + bcc,pt %xcc, ccmerge ! CTI + andcc %len, 0xf0, %g1 ! IEU1 Group + b,pt %xcc, ccmerge ! CTI 4 clocks (mispredict) add %sum, 1, %sum ! IEU0 .align 32 @@ -342,26 +145,8 @@ cmp %len, 256 ! IEU1 Group bgeu,pt %icc, csum_partial_copy_vis ! CTI andcc %src, 7, %g0 ! IEU1 Group - be,pt %icc, cc_dword_aligned ! CTI - andn %len, 0xff, %g2 ! IEU0 - b,pt %xcc, cc_fixit ! CTI Group - cmp %len, 6 ! IEU1 -cc_dword_aligned: - brz,pn %g2, 3f ! CTI Group - andcc %dst, 4, %g0 ! IEU1 Group (brz uses IEU1) - be,pn %icc, ccdbl + 4 ! CTI -5: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STUNALIGN_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STUNALIGN_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STUNALIGN_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STUNALIGN( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) -10: - sub %len, 256, %len ! IEU0 Group - add %src, 256, %src ! IEU1 - andncc %len, 0xff, %g0 ! IEU1 Group - bne,pt %icc, 5b ! CTI - add %dst, 256, %dst ! IEU0 -3: andcc %len, 0xf0, %g1 ! IEU1 Group + bne,pn %icc, cc_fixit ! CTI + andcc %len, 0xf0, %g1 ! IEU1 Group ccmerge:be,pn %icc, ccte ! CTI andcc %len, 0xf, %g7 ! IEU1 Group sll %g1, 2, %o4 ! IEU0 @@ -396,19 +181,6 @@ add %o0, 1, %o0 ! IEU1 4 clocks (mispredict) 1: retl ! CTI Group brk forced sllx %g4, 32,%g4 ! IEU0 Group -ccdbl: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STALIGNED_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STALIGNED_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STALIGNED_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) - CSUMCOPY_EC_STALIGNED( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) -11: - sub %len, 256, %len ! IEU0 Group - add %src, 256, %src ! IEU1 - andncc %len, 0xff, %g0 ! IEU1 Group - bne,pt %icc, ccdbl ! CTI - add %dst, 256, %dst ! IEU0 - b,pt %xcc, ccmerge ! CTI Group - andcc %len, 0xf0, %g1 ! IEU1 ccslow: mov 0, %g5 brlez,pn %len, 4f diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/lib/strncpy_from_user.S linux/arch/sparc64/lib/strncpy_from_user.S --- v2.1.78/linux/arch/sparc64/lib/strncpy_from_user.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/lib/strncpy_from_user.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,5 @@ -/* strncpy_from_user.S: Sparc64 strncpy from userspace. +/* $Id: strncpy_from_user.S,v 1.5 1997/09/08 11:29:23 jj Exp $ + * strncpy_from_user.S: Sparc64 strncpy from userspace. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -6,6 +7,10 @@ #include #include + .data + .align 8 +0: .xword 0x0101010101010101 + .text .align 4 @@ -14,41 +19,117 @@ * -EFAULT for an exception * count if we hit the buffer limit * bytes copied if we hit a null byte + * (without the null byte) + * + * This implementation assumes: + * %o1 is 8 aligned => !(%o2 & 7) + * %o0 is 8 aligned (if not, it will be slooooow, but will work) + * + * This is optimized for the common case: + * in my stats, 90% of src are 8 aligned (even on sparc32) + * and average length is 18 or so. */ .globl __strncpy_from_user __strncpy_from_user: /* %o0=dest, %o1=src, %o2=count */ - brlez,pn %o2, 3f + sethi %hi(0b), %o5 ! IEU0 Group + andcc %o1, 7, %g0 ! IEU1 + bne,pn %icc, 30f ! CTI + ldx [%o5 + %lo(0b)], %o4 ! Load Group +60: ldxa [%o1] ASI_S, %g1 ! Load Group + add %o1, %o2, %o1 ! IEU0 + subcc %g0, %o2, %o3 ! IEU1 + bgeu,pn %xcc, 10f ! CTI + sllx %o4, 7, %o5 ! IEU0 Group + add %o0, %o2, %o0 ! IEU1 +1: sub %g1, %o4, %g2 ! IEU0 Group + stx %g1, [%o0 + %o3] ! Store + andcc %g2, %o5, %g0 ! IEU1 Group + bne,pn %xcc, 5f ! CTI + add %o3, 8, %o3 ! IEU0 + brlz,a,pt %o3, 1b ! CTI(IEU1) Group +61: ldxa [%o1 + %o3] ASI_S, %g1 ! Load +10: retl ! CTI Group + mov %o2, %o0 ! IEU0 +5: srlx %g2, 32, %g7 ! IEU0 Group + sethi %hi(0xff00), %g5 ! IEU1 + andcc %g7, %o5, %g0 ! IEU1 Group + be,pn %icc, 2f ! CTI + or %g5, %lo(0xff00), %g5 ! IEU0 + srlx %g1, 48, %g7 ! IEU0 Group + andcc %g7, %g5, %g0 ! IEU1 Group + be,pn %icc, 50f ! CTI + andcc %g7, 0xff, %g0 ! IEU1 Group + be,pn %icc, 51f ! CTI + srlx %g1, 32, %g7 ! IEU0 + andcc %g7, %g5, %g0 ! IEU1 Group + be,pn %icc, 52f ! CTI + andcc %g7, 0xff, %g0 ! IEU1 Group + be,pn %icc, 53f ! CTI +2: andcc %g2, %o5, %g0 ! IEU1 Group + be,pn %icc, 2f ! CTI + srl %g1, 16, %g7 ! IEU0 + andcc %g7, %g5, %g0 ! IEU1 Group + be,pn %icc, 54f ! CTI + andcc %g7, 0xff, %g0 ! IEU1 Group + be,pn %icc, 55f ! CTI + andcc %g1, %g5, %g0 ! IEU1 Group + be,pn %icc, 56f ! CTI + andcc %g1, 0xff, %g0 ! IEU1 Group + be,a,pn %icc, 57f ! CTI + add %o2, %o3, %o0 ! IEU0 +2: brlz,a,pt %o3, 1b ! CTI(IEU1) Group +62: ldxa [%o1 + %o3] ASI_S, %g1 ! Load + retl ! CTI Group + mov %o2, %o0 ! IEU0 +50: add %o2, %o3, %o0 + retl + sub %o0, 8, %o0 +51: add %o2, %o3, %o0 + retl + sub %o0, 7, %o0 +52: add %o2, %o3, %o0 + retl + sub %o0, 6, %o0 +53: add %o2, %o3, %o0 + retl + sub %o0, 5, %o0 +54: add %o2, %o3, %o0 + retl + sub %o0, 4, %o0 +55: add %o2, %o3, %o0 + retl + sub %o0, 3, %o0 +56: add %o2, %o3, %o0 + retl + sub %o0, 2, %o0 +57: retl + sub %o0, 1, %o0 +30: brlez,pn %o2, 3f add %o1, %o2, %o1 sub %g0, %o2, %o3 add %o0, %o2, %o0 -10: - lduba [%o1 + %o3] ASI_S, %o4 -1: - brz,pn %o4, 2f +63: lduba [%o1 + %o3] ASI_S, %o4 +1: brz,pn %o4, 2f stb %o4, [%o0 + %o3] addcc %o3, 1, %o3 bne,pt %xcc, 1b -11: - lduba [%o1 + %o3] ASI_S, %o4 - retl +64: lduba [%o1 + %o3] ASI_S, %o4 +3: retl mov %o2, %o0 -2: - add %o3, 1, %o3 - retl +2: retl add %o2, %o3, %o0 -3: - retl - clr %o0 .section .fixup,#alloc,#execinstr .align 4 -4: - retl +4: retl mov -EFAULT, %o0 .section __ex_table,#alloc .align 4 - .word 10b, 4b - .word 11b, 4b + .word 60b, 4b + .word 61b, 4b + .word 62b, 4b + .word 63b, 4b + .word 64b, 4b diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/Makefile linux/arch/sparc64/math-emu/Makefile --- v2.1.78/linux/arch/sparc64/math-emu/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/Makefile Mon Jan 12 15:15:44 1998 @@ -0,0 +1,33 @@ +# +# Makefile for the FPU Quad (long double) instruction emulation. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := math-emu.o +O_OBJS := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o \ + fmovq.o fmulq.o fnegq.o fqtoi.o fqtox.o fsubq.o \ + fxtoq.o fdtoq.o fstoq.o fqtos.o fqtod.o fsqrtq.o \ + fcmpq.o fcmpeq.o udivmodti4.o \ + fsqrts.o fsqrtd.o fadds.o faddd.o fsubs.o fsubd.o \ + fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o \ + fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o + +ifeq ($(CONFIG_MATHEMU),m) +M_OBJS := $(O_TARGET) +endif + +.S.s: + $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + +.S.o: + $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + +ifneq ($(CONFIG_MATHEMU),y) +do_it_all: +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/double.h linux/arch/sparc64/math-emu/double.h --- v2.1.78/linux/arch/sparc64/math-emu/double.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/double.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,129 @@ +/* + * Definitions for IEEE Double Precision + */ + +#if _FP_W_TYPE_SIZE < 32 +#error "Here's a nickle kid. Go buy yourself a real computer." +#endif + +#if _FP_W_TYPE_SIZE < 64 +#define _FP_FRACTBITS_D (2 * _FP_W_TYPE_SIZE) +#else +#define _FP_FRACTBITS_D _FP_W_TYPE_SIZE +#endif + +#define _FP_FRACBITS_D 53 +#define _FP_FRACXBITS_D (_FP_FRACTBITS_D - _FP_FRACBITS_D) +#define _FP_WFRACBITS_D (_FP_WORKBITS + _FP_FRACBITS_D) +#define _FP_WFRACXBITS_D (_FP_FRACTBITS_D - _FP_WFRACBITS_D) +#define _FP_EXPBITS_D 11 +#define _FP_EXPBIAS_D 1023 +#define _FP_EXPMAX_D 2047 + +#define _FP_QNANBIT_D \ + ((_FP_W_TYPE)1 << (_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE) +#define _FP_IMPLBIT_D \ + ((_FP_W_TYPE)1 << (_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE) +#define _FP_OVERFLOW_D \ + ((_FP_W_TYPE)1 << _FP_WFRACBITS_D % _FP_W_TYPE_SIZE) + +#if _FP_W_TYPE_SIZE < 64 + +union _FP_UNION_D +{ + double flt; + struct { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned sign : 1; + unsigned exp : _FP_EXPBITS_D; + unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; + unsigned frac0 : _FP_W_TYPE_SIZE; +#else + unsigned frac0 : _FP_W_TYPE_SIZE; + unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; + unsigned exp : _FP_EXPBITS_D; + unsigned sign : 1; +#endif + } bits __attribute__((packed)); +}; + +#define FP_DECL_D(X) _FP_DECL(2,X) +#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val) +#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_2(D,val,X) + +#define FP_UNPACK_D(X,val) \ + do { \ + _FP_UNPACK_RAW_2(D,X,val); \ + _FP_UNPACK_CANONICAL(D,2,X); \ + } while (0) + +#define FP_PACK_D(val,X) \ + do { \ + _FP_PACK_CANONICAL(D,2,X); \ + _FP_PACK_RAW_2(D,val,X); \ + } while (0) + +#define FP_NEG_D(R,X) _FP_NEG(D,2,R,X) +#define FP_ADD_D(R,X,Y) _FP_ADD(D,2,R,X,Y) +#define FP_SUB_D(R,X,Y) _FP_SUB(D,2,R,X,Y) +#define FP_MUL_D(R,X,Y) _FP_MUL(D,2,R,X,Y) +#define FP_DIV_D(R,X,Y) _FP_DIV(D,2,R,X,Y) +#define FP_SQRT_D(R,X) _FP_SQRT(D,2,R,X) + +#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,2,r,X,Y,un) +#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,2,r,X,Y) + +#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,2,r,X,rsz,rsg) +#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,2,X,r,rs,rt) + +#else + +union _FP_UNION_D +{ + double flt; + struct { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned sign : 1; + unsigned exp : _FP_EXPBITS_D; + unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); +#else + unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); + unsigned exp : _FP_EXPBITS_D; + unsigned sign : 1; +#endif + } bits __attribute__((packed)); +}; + +#define FP_DECL_D(X) _FP_DECL(1,X) +#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val) +#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_1(D,val,X) + +#define FP_UNPACK_D(X,val) \ + do { \ + _FP_UNPACK_RAW_1(D,X,val); \ + _FP_UNPACK_CANONICAL(D,1,X); \ + } while (0) + +#define FP_PACK_D(val,X) \ + do { \ + _FP_PACK_CANONICAL(D,1,X); \ + _FP_PACK_RAW_1(D,val,X); \ + } while (0) + +#define FP_NEG_D(R,X) _FP_NEG(D,1,R,X) +#define FP_ADD_D(R,X,Y) _FP_ADD(D,1,R,X,Y) +#define FP_SUB_D(R,X,Y) _FP_SUB(D,1,R,X,Y) +#define FP_MUL_D(R,X,Y) _FP_MUL(D,1,R,X,Y) +#define FP_DIV_D(R,X,Y) _FP_DIV(D,1,R,X,Y) +#define FP_SQRT_D(R,X) _FP_SQRT(D,1,R,X) + +/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by + the target machine. */ + +#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,1,r,X,Y,un) +#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,1,r,X,Y) + +#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,1,r,X,rsz,rsg) +#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,1,X,r,rs,rt) + +#endif /* W_TYPE_SIZE < 64 */ diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fabsq.c linux/arch/sparc64/math-emu/fabsq.c --- v2.1.78/linux/arch/sparc64/math-emu/fabsq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fabsq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,19 @@ +#include "soft-fp.h" +#include "quad.h" + +int FABSQ(unsigned long *rd, unsigned long *rs2) +{ +/* + FP_DECL_Q(A); FP_DECL_Q(R); + + __FP_UNPACK_Q(A, rs2); + _FP_FRAC_COPY_2(R, A); + R_c = A_c; + R_e = A_e; + R_s = 0; + __FP_PACK_Q(rd, R); + */ + rd[0] = rs2[0] & 0x7fffffffffffffffUL; + rd[1] = rs2[1]; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/faddd.c linux/arch/sparc64/math-emu/faddd.c --- v2.1.78/linux/arch/sparc64/math-emu/faddd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/faddd.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "double.h" + +int FADDD(void *rd, void *rs2, void *rs1) +{ + FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); + + __FP_UNPACK_D(A, rs1); + __FP_UNPACK_D(B, rs2); + FP_ADD_D(R, A, B); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/faddq.c linux/arch/sparc64/math-emu/faddq.c --- v2.1.78/linux/arch/sparc64/math-emu/faddq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/faddq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" + +int FADDQ(void *rd, void *rs2, void *rs1) +{ + FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); + + __FP_UNPACK_Q(A, rs1); + __FP_UNPACK_Q(B, rs2); + FP_ADD_Q(R, A, B); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fadds.c linux/arch/sparc64/math-emu/fadds.c --- v2.1.78/linux/arch/sparc64/math-emu/fadds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fadds.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "single.h" + +int FADDS(void *rd, void *rs2, void *rs1) +{ + FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); + + __FP_UNPACK_S(A, rs1); + __FP_UNPACK_S(B, rs2); + FP_ADD_S(R, A, B); + __FP_PACK_S(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fcmpeq.c linux/arch/sparc64/math-emu/fcmpeq.c --- v2.1.78/linux/arch/sparc64/math-emu/fcmpeq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fcmpeq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,28 @@ +#include "soft-fp.h" +#include "quad.h" + +int FCMPEQ(void *rd, void *rs2, void *rs1) +{ + FP_DECL_Q(A); FP_DECL_Q(B); + long ret; + int fccno = ((long)rd) & 3; + unsigned long fsr; + + rd = (void *)(((long)rd)&~3); + __FP_UNPACK_Q(A, rs1); + __FP_UNPACK_Q(B, rs2); + FP_CMP_Q(ret, A, B, 3); + switch (ret) { + case 1: ret = 2; break; + case -1: ret = 1; break; + } + fsr = *(unsigned long *)rd; + switch (fccno) { + case 0: fsr &= ~0xc00; fsr |= (ret << 10); break; + case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break; + case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break; + case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; + } + *(unsigned long *)rd = fsr; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fcmpq.c linux/arch/sparc64/math-emu/fcmpq.c --- v2.1.78/linux/arch/sparc64/math-emu/fcmpq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fcmpq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,28 @@ +#include "soft-fp.h" +#include "quad.h" + +int FCMPQ(void *rd, void *rs2, void *rs1) +{ + FP_DECL_Q(A); FP_DECL_Q(B); + long ret; + int fccno = ((long)rd) & 3; + unsigned long fsr; + + rd = (void *)(((long)rd)&~3); + __FP_UNPACK_Q(A, rs1); + __FP_UNPACK_Q(B, rs2); + FP_CMP_Q(ret, A, B, 3); + switch (ret) { + case 1: ret = 2; break; + case -1: ret = 1; break; + } + fsr = *(unsigned long *)rd; + switch (fccno) { + case 0: fsr &= ~0xc00; fsr |= (ret << 10); break; + case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break; + case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break; + case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; + } + *(unsigned long *)rd = fsr; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdivd.c linux/arch/sparc64/math-emu/fdivd.c --- v2.1.78/linux/arch/sparc64/math-emu/fdivd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdivd.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "double.h" + +int FDIVD(void *rd, void *rs2, void *rs1) +{ + FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); + + __FP_UNPACK_D(A, rs1); + __FP_UNPACK_D(B, rs2); + FP_DIV_D(R, A, B); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdivq.c linux/arch/sparc64/math-emu/fdivq.c --- v2.1.78/linux/arch/sparc64/math-emu/fdivq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdivq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" + +int FDIVQ(void *rd, void *rs2, void *rs1) +{ + FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); + + __FP_UNPACK_Q(A, rs1); + __FP_UNPACK_Q(B, rs2); + FP_DIV_Q(R, A, B); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdivs.c linux/arch/sparc64/math-emu/fdivs.c --- v2.1.78/linux/arch/sparc64/math-emu/fdivs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdivs.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "single.h" + +int FDIVS(void *rd, void *rs2, void *rs1) +{ + FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); + + __FP_UNPACK_S(A, rs1); + __FP_UNPACK_S(B, rs2); + FP_DIV_S(R, A, B); + __FP_PACK_S(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdmulq.c linux/arch/sparc64/math-emu/fdmulq.c --- v2.1.78/linux/arch/sparc64/math-emu/fdmulq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdmulq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,16 @@ +#include "soft-fp.h" +#include "quad.h" +#include "double.h" + +int FDMULQ(void *rd, void *rs2, void *rs1) +{ + FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); + + __FP_UNPACK_D(IN, rs1); + FP_CONV(Q,D,2,1,A,IN); + __FP_UNPACK_D(IN, rs2); + FP_CONV(Q,D,2,1,B,IN); + FP_MUL_Q(R, A, B); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdtoi.c linux/arch/sparc64/math-emu/fdtoi.c --- v2.1.78/linux/arch/sparc64/math-emu/fdtoi.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdtoi.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "double.h" + +int FDTOI(unsigned *rd, void *rs2) +{ + FP_DECL_D(A); + unsigned r; + + __FP_UNPACK_D(A, rs2); + FP_TO_INT_D(r, A, 32, 1); + *rd = r; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdtoq.c linux/arch/sparc64/math-emu/fdtoq.c --- v2.1.78/linux/arch/sparc64/math-emu/fdtoq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdtoq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" +#include "double.h" + +int FDTOQ(void *rd, void *rs2) +{ + FP_DECL_D(A); FP_DECL_Q(R); + + __FP_UNPACK_D(A, rs2); + FP_CONV(Q,D,2,1,R,A); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdtos.c linux/arch/sparc64/math-emu/fdtos.c --- v2.1.78/linux/arch/sparc64/math-emu/fdtos.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdtos.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int FDTOS(void *rd, void *rs2) +{ + FP_DECL_D(A); FP_DECL_S(R); + + __FP_UNPACK_D(A, rs2); + FP_CONV(S,D,1,1,R,A); + __FP_PACK_S(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fdtox.c linux/arch/sparc64/math-emu/fdtox.c --- v2.1.78/linux/arch/sparc64/math-emu/fdtox.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fdtox.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "double.h" + +int FDTOX(unsigned long *rd, void *rs2) +{ + FP_DECL_D(A); + unsigned long r; + + __FP_UNPACK_D(A, rs2); + FP_TO_INT_D(r, A, 64, 1); + *rd = r; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fitoq.c linux/arch/sparc64/math-emu/fitoq.c --- v2.1.78/linux/arch/sparc64/math-emu/fitoq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fitoq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,12 @@ +#include "soft-fp.h" +#include "quad.h" + +int FITOQ(void *rd, void *rs2) +{ + FP_DECL_Q(R); + int a = *(int *)rs2; + + FP_FROM_INT_Q(R, a, 32, int); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fmovq.c linux/arch/sparc64/math-emu/fmovq.c --- v2.1.78/linux/arch/sparc64/math-emu/fmovq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fmovq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,6 @@ +int FMOVQ(unsigned long *rd, unsigned long *rs2) +{ + rd[0] = rs2[0]; + rd[1] = rs2[1]; + return 0; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fmuld.c linux/arch/sparc64/math-emu/fmuld.c --- v2.1.78/linux/arch/sparc64/math-emu/fmuld.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fmuld.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "double.h" + +int FMULD(void *rd, void *rs2, void *rs1) +{ + FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); + + __FP_UNPACK_D(A, rs1); + __FP_UNPACK_D(B, rs2); + FP_MUL_D(R, A, B); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fmulq.c linux/arch/sparc64/math-emu/fmulq.c --- v2.1.78/linux/arch/sparc64/math-emu/fmulq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fmulq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" + +int FMULQ(void *rd, void *rs2, void *rs1) +{ + FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); + + __FP_UNPACK_Q(A, rs1); + __FP_UNPACK_Q(B, rs2); + FP_MUL_Q(R, A, B); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fmuls.c linux/arch/sparc64/math-emu/fmuls.c --- v2.1.78/linux/arch/sparc64/math-emu/fmuls.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fmuls.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "single.h" + +int FMULS(void *rd, void *rs2, void *rs1) +{ + FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); + + __FP_UNPACK_S(A, rs1); + __FP_UNPACK_S(B, rs2); + FP_MUL_S(R, A, B); + __FP_PACK_S(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fnegq.c linux/arch/sparc64/math-emu/fnegq.c --- v2.1.78/linux/arch/sparc64/math-emu/fnegq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fnegq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,18 @@ +#include "soft-fp.h" +#include "quad.h" + +int FNEGQ(unsigned long *rd, unsigned long *rs2) +{ +/* + FP_DECL_Q(A); FP_DECL_Q(R); + + __FP_UNPACK_Q(A, rs2); + FP_NEG_Q(R, A); + __FP_PACK_Q(rd, R); + */ + rd[0] = rs2[0] ^ 0x8000000000000000UL; + rd[1] = rs2[1]; + return 1; +} + + diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fqtod.c linux/arch/sparc64/math-emu/fqtod.c --- v2.1.78/linux/arch/sparc64/math-emu/fqtod.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fqtod.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" +#include "double.h" + +int FQTOD(void *rd, void *rs2) +{ + FP_DECL_Q(A); FP_DECL_D(R); + + __FP_UNPACK_Q(A, rs2); + FP_CONV(D,Q,1,2,R,A); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fqtoi.c linux/arch/sparc64/math-emu/fqtoi.c --- v2.1.78/linux/arch/sparc64/math-emu/fqtoi.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fqtoi.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" + +int FQTOI(unsigned *rd, void *rs2) +{ + FP_DECL_Q(A); + unsigned r; + + __FP_UNPACK_Q(A, rs2); + FP_TO_INT_Q(r, A, 32, 1); + *rd = r; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fqtos.c linux/arch/sparc64/math-emu/fqtos.c --- v2.1.78/linux/arch/sparc64/math-emu/fqtos.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fqtos.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" +#include "single.h" + +int FQTOS(void *rd, void *rs2) +{ + FP_DECL_Q(A); FP_DECL_S(R); + + __FP_UNPACK_Q(A, rs2); + FP_CONV(S,Q,1,2,R,A); + __FP_PACK_S(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fqtox.c linux/arch/sparc64/math-emu/fqtox.c --- v2.1.78/linux/arch/sparc64/math-emu/fqtox.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fqtox.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" + +int FQTOX(unsigned long *rd, void *rs2) +{ + FP_DECL_Q(A); + unsigned long r; + + __FP_UNPACK_Q(A, rs2); + FP_TO_INT_Q(r, A, 64, 1); + *rd = r; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fsmuld.c linux/arch/sparc64/math-emu/fsmuld.c --- v2.1.78/linux/arch/sparc64/math-emu/fsmuld.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fsmuld.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,16 @@ +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int FSMULD(void *rd, void *rs2, void *rs1) +{ + FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); + + __FP_UNPACK_S(IN, rs1); + FP_CONV(D,S,1,1,A,IN); + __FP_UNPACK_S(IN, rs2); + FP_CONV(D,S,1,1,B,IN); + FP_MUL_D(R, A, B); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fsqrtd.c linux/arch/sparc64/math-emu/fsqrtd.c --- v2.1.78/linux/arch/sparc64/math-emu/fsqrtd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fsqrtd.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,12 @@ +#include "soft-fp.h" +#include "double.h" + +int FSQRTD(void *rd, void *rs2) +{ + FP_DECL_D(A); FP_DECL_D(R); + + __FP_UNPACK_D(A, rs2); + FP_SQRT_D(R, A); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fsqrtq.c linux/arch/sparc64/math-emu/fsqrtq.c --- v2.1.78/linux/arch/sparc64/math-emu/fsqrtq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fsqrtq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,12 @@ +#include "soft-fp.h" +#include "quad.h" + +int FSQRTQ(void *rd, void *rs2) +{ + FP_DECL_Q(A); FP_DECL_Q(R); + + __FP_UNPACK_Q(A, rs2); + FP_SQRT_Q(R, A); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fsqrts.c linux/arch/sparc64/math-emu/fsqrts.c --- v2.1.78/linux/arch/sparc64/math-emu/fsqrts.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fsqrts.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,12 @@ +#include "soft-fp.h" +#include "single.h" + +int FSQRTS(void *rd, void *rs2) +{ + FP_DECL_S(A); FP_DECL_S(R); + + __FP_UNPACK_S(A, rs2); + FP_SQRT_S(R, A); + __FP_PACK_S(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fstod.c linux/arch/sparc64/math-emu/fstod.c --- v2.1.78/linux/arch/sparc64/math-emu/fstod.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fstod.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int FSTOD(void *rd, void *rs2) +{ + FP_DECL_S(A); FP_DECL_D(R); + + __FP_UNPACK_S(A, rs2); + FP_CONV(D,S,1,1,R,A); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fstoi.c linux/arch/sparc64/math-emu/fstoi.c --- v2.1.78/linux/arch/sparc64/math-emu/fstoi.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fstoi.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "single.h" + +int FSTOI(unsigned *rd, void *rs2) +{ + FP_DECL_S(A); + unsigned r; + + __FP_UNPACK_S(A, rs2); + FP_TO_INT_S(r, A, 32, 1); + *rd = r; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fstoq.c linux/arch/sparc64/math-emu/fstoq.c --- v2.1.78/linux/arch/sparc64/math-emu/fstoq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fstoq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "quad.h" +#include "single.h" + +int FSTOQ(void *rd, void *rs2) +{ + FP_DECL_S(A); FP_DECL_Q(R); + + __FP_UNPACK_S(A, rs2); + FP_CONV(Q,S,2,1,R,A); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fstox.c linux/arch/sparc64/math-emu/fstox.c --- v2.1.78/linux/arch/sparc64/math-emu/fstox.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fstox.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,13 @@ +#include "soft-fp.h" +#include "single.h" + +int FSTOX(unsigned long *rd, void *rs2) +{ + FP_DECL_S(A); + unsigned long r; + + __FP_UNPACK_S(A, rs2); + FP_TO_INT_S(r, A, 64, 1); + *rd = r; + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fsubd.c linux/arch/sparc64/math-emu/fsubd.c --- v2.1.78/linux/arch/sparc64/math-emu/fsubd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fsubd.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,15 @@ +#include "soft-fp.h" +#include "double.h" + +int FSUBD(void *rd, void *rs2, void *rs1) +{ + FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); + + __FP_UNPACK_D(A, rs1); + __FP_UNPACK_D(B, rs2); + if (B_c != FP_CLS_NAN) + B_s ^= 1; + FP_ADD_D(R, A, B); + __FP_PACK_D(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fsubq.c linux/arch/sparc64/math-emu/fsubq.c --- v2.1.78/linux/arch/sparc64/math-emu/fsubq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fsubq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,15 @@ +#include "soft-fp.h" +#include "quad.h" + +int FSUBQ(void *rd, void *rs2, void *rs1) +{ + FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); + + __FP_UNPACK_Q(A, rs1); + __FP_UNPACK_Q(B, rs2); + if (B_c != FP_CLS_NAN) + B_s ^= 1; + FP_ADD_Q(R, A, B); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fsubs.c linux/arch/sparc64/math-emu/fsubs.c --- v2.1.78/linux/arch/sparc64/math-emu/fsubs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fsubs.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,15 @@ +#include "soft-fp.h" +#include "single.h" + +int FSUBS(void *rd, void *rs2, void *rs1) +{ + FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); + + __FP_UNPACK_S(A, rs1); + __FP_UNPACK_S(B, rs2); + if (B_c != FP_CLS_NAN) + B_s ^= 1; + FP_ADD_S(R, A, B); + __FP_PACK_S(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/fxtoq.c linux/arch/sparc64/math-emu/fxtoq.c --- v2.1.78/linux/arch/sparc64/math-emu/fxtoq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/fxtoq.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,12 @@ +#include "soft-fp.h" +#include "quad.h" + +int FXTOQ(void *rd, void *rs2) +{ + FP_DECL_Q(R); + long a = *(long *)rs2; + + FP_FROM_INT_Q(R, a, 64, long); + __FP_PACK_Q(rd, R); + return 1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/math.c linux/arch/sparc64/math-emu/math.c --- v2.1.78/linux/arch/sparc64/math-emu/math.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/math.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,209 @@ +/* $Id: math.c,v 1.3 1997/10/15 07:28:55 jj Exp $ + * arch/sparc64/math-emu/math.c + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Emulation routines originate from soft-fp package, which is part + * of glibc and has appropriate copyrights in it. + */ + +#include +#include +#include + +#include +#include +#include + +#define FLOATFUNC(x) extern int x(void *,void *,void *); + +FLOATFUNC(FMOVQ) +FLOATFUNC(FNEGQ) +FLOATFUNC(FABSQ) +FLOATFUNC(FSQRTQ) +FLOATFUNC(FADDQ) +FLOATFUNC(FSUBQ) +FLOATFUNC(FMULQ) +FLOATFUNC(FDIVQ) +FLOATFUNC(FDMULQ) +FLOATFUNC(FQTOX) +FLOATFUNC(FXTOQ) +FLOATFUNC(FQTOS) +FLOATFUNC(FQTOD) +FLOATFUNC(FITOQ) +FLOATFUNC(FSTOQ) +FLOATFUNC(FDTOQ) +FLOATFUNC(FQTOI) +FLOATFUNC(FCMPQ) +FLOATFUNC(FCMPEQ) + +FLOATFUNC(FSQRTS) +FLOATFUNC(FSQRTD) +FLOATFUNC(FADDS) +FLOATFUNC(FADDD) +FLOATFUNC(FSUBS) +FLOATFUNC(FSUBD) +FLOATFUNC(FMULS) +FLOATFUNC(FMULD) +FLOATFUNC(FDIVS) +FLOATFUNC(FDIVD) +FLOATFUNC(FSMULD) +FLOATFUNC(FSTOX) +FLOATFUNC(FDTOX) +FLOATFUNC(FDTOS) +FLOATFUNC(FSTOD) +FLOATFUNC(FSTOI) +FLOATFUNC(FDTOI) + +int do_mathemu(struct pt_regs *regs, struct fpustate *f) +{ + unsigned long pc = regs->tpc; + unsigned long tstate = regs->tstate; + u32 insn = 0; + int type = 0; /* 01 is single, 10 is double, 11 is quad, + 000011 is rs1, 001100 is rs2, 110000 is rd (00 in rd is fcc) + 111100000000 tells which ftt may that happen in */ + int freg; + static u64 zero[2] = { 0L, 0L }; + int flags; + int (*func)(void *,void *,void *) = NULL; + + if(tstate & TSTATE_PRIV) + die_if_kernel("FPQuad from kernel", regs); + MOD_INC_USE_COUNT; + if(current->tss.flags & SPARC_FLAG_32BIT) + pc = (u32)pc; + if (get_user(insn, (u32 *)pc) != -EFAULT) { + if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ { + switch ((insn >> 5) & 0x1ff) { + /* QUAD - ftt == 3 */ + case 0x003: type = 0x33c; func = FMOVQ; break; + case 0x007: type = 0x33c; func = FNEGQ; break; + case 0x00b: type = 0x33c; func = FABSQ; break; + case 0x02b: type = 0x33c; func = FSQRTQ; break; + case 0x043: type = 0x33f; func = FADDQ; break; + case 0x047: type = 0x33f; func = FSUBQ; break; + case 0x04b: type = 0x33f; func = FMULQ; break; + case 0x04f: type = 0x33f; func = FDIVQ; break; + case 0x06e: type = 0x33a; func = FDMULQ; break; + case 0x083: type = 0x32c; func = FQTOX; break; + case 0x08c: type = 0x338; func = FXTOQ; break; + case 0x0c7: type = 0x31c; func = FQTOS; break; + case 0x0cb: type = 0x32c; func = FQTOD; break; + case 0x0cc: type = 0x334; func = FITOQ; break; + case 0x0cd: type = 0x334; func = FSTOQ; break; + case 0x0ce: type = 0x338; func = FDTOQ; break; + case 0x0d3: type = 0x31c; func = FQTOI; break; + /* SUBNORMAL - ftt == 2 */ + case 0x029: type = 0x214; func = FSQRTS; break; + case 0x02a: type = 0x228; func = FSQRTD; break; + case 0x041: type = 0x215; func = FADDS; break; + case 0x042: type = 0x22a; func = FADDD; break; + case 0x045: type = 0x215; func = FSUBS; break; + case 0x046: type = 0x22a; func = FSUBD; break; + case 0x049: type = 0x215; func = FMULS; break; + case 0x04a: type = 0x22a; func = FMULD; break; + case 0x04d: type = 0x215; func = FDIVS; break; + case 0x04e: type = 0x22a; func = FDIVD; break; + case 0x069: type = 0x225; func = FSMULD; break; + case 0x081: type = 0x224; func = FSTOX; break; + case 0x082: type = 0x228; func = FDTOX; break; + case 0x0c6: type = 0x218; func = FDTOS; break; + case 0x0c9: type = 0x224; func = FSTOD; break; + case 0x0d1: type = 0x214; func = FSTOI; break; + case 0x0d2: type = 0x218; func = FDTOI; break; + } + } + else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ { + switch ((insn >> 5) & 0x1ff) { + case 0x053: type = 0x30f; func = FCMPQ; break; + case 0x057: type = 0x30f; func = FCMPEQ; break; + } + } + } + if (type) { + void *rs1 = NULL, *rs2 = NULL, *rd = NULL; + + freg = (f->fsr >> 14) & 0xf; + if (freg != (type >> 8)) + goto err; + f->fsr &= ~0x1c000; + freg = ((insn >> 14) & 0x1f); + switch (type & 0x3) { + case 3: if (freg & 2) { + f->fsr |= (6 << 14) /* invalid_fp_register */; + goto err; + } + case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); + case 1: rs1 = (void *)&f->regs[freg]; + flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + if (!(current->tss.flags & flags)) + rs1 = (void *)&zero; + break; + } + freg = (insn & 0x1f); + switch ((type >> 2) & 0x3) { + case 3: if (freg & 2) { + f->fsr |= (6 << 14) /* invalid_fp_register */; + goto err; + } + case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); + case 1: rs2 = (void *)&f->regs[freg]; + flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + if (!(current->tss.flags & flags)) + rs2 = (void *)&zero; + break; + } + freg = ((insn >> 25) & 0x1f); + switch ((type >> 4) & 0x3) { + case 0: rd = (void *)(((long)&f->fsr) | (freg & 3)); break; + case 3: if (freg & 2) { + f->fsr |= (6 << 14) /* invalid_fp_register */; + goto err; + } + case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); + case 1: rd = (void *)&f->regs[freg]; + flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + regs->fprs |= FPRS_FEF; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { + current->tss.flags |= SPARC_FLAG_USEDFPU; + f->fsr = 0; + f->gsr = 0; + } + if (!(current->tss.flags & flags)) { + if (freg < 32) + memset(f->regs, 0, 32*sizeof(u32)); + else + memset(f->regs+32, 0, 32*sizeof(u32)); + } + current->tss.flags |= flags; + break; + } + func(rd, rs2, rs1); + regs->tpc = regs->tnpc; + regs->tnpc += 4; + MOD_DEC_USE_COUNT; + return 1; + } +err: MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Jakub Jelinek (jj@sunsite.mff.cuni.cz), Richard Henderson (rth@cygnus.com)"); +MODULE_DESCRIPTION("FPU emulation module"); + +extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); + +int init_module(void) +{ + handle_mathemu = do_mathemu; + return 0; +} + +void cleanup_module(void) +{ + handle_mathemu = NULL; +} +#endif diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/op-1.h linux/arch/sparc64/math-emu/op-1.h --- v2.1.78/linux/arch/sparc64/math-emu/op-1.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/op-1.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,245 @@ +/* + * Basic one-word fraction declaration and manipulation. + */ + +#define _FP_FRAC_DECL_1(X) _FP_W_TYPE X##_f +#define _FP_FRAC_COPY_1(D,S) (D##_f = S##_f) +#define _FP_FRAC_SET_1(X,I) (X##_f = I) +#define _FP_FRAC_HIGH_1(X) (X##_f) +#define _FP_FRAC_LOW_1(X) (X##_f) +#define _FP_FRAC_WORD_1(X,w) (X##_f) + +#define _FP_FRAC_ADDI_1(X,I) (X##_f += I) +#define _FP_FRAC_SLL_1(X,N) \ + do { \ + if (__builtin_constant_p(N) && (N) == 1) \ + X##_f += X##_f; \ + else \ + X##_f <<= (N); \ + } while (0) +#define _FP_FRAC_SRL_1(X,N) (X##_f >>= N) + +/* Right shift with sticky-lsb. */ +#define _FP_FRAC_SRS_1(X,N,sz) __FP_FRAC_SRS_1(X##_f, N, sz) + +#define __FP_FRAC_SRS_1(X,N,sz) \ + (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1 \ + ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0))) + +#define _FP_FRAC_ADD_1(R,X,Y) (R##_f = X##_f + Y##_f) +#define _FP_FRAC_SUB_1(R,X,Y) (R##_f = X##_f - Y##_f) +#define _FP_FRAC_CLZ_1(z, X) __FP_CLZ(z, X##_f) + +/* Predicates */ +#define _FP_FRAC_NEGP_1(X) ((_FP_WS_TYPE)X##_f < 0) +#define _FP_FRAC_ZEROP_1(X) (X##_f == 0) +#define _FP_FRAC_OVERP_1(fs,X) (X##_f & _FP_OVERFLOW_##fs) +#define _FP_FRAC_EQ_1(X, Y) (X##_f == Y##_f) +#define _FP_FRAC_GE_1(X, Y) (X##_f >= Y##_f) +#define _FP_FRAC_GT_1(X, Y) (X##_f > Y##_f) + +#define _FP_ZEROFRAC_1 0 +#define _FP_MINFRAC_1 1 + +/* + * Unpack the raw bits of a native fp value. Do not classify or + * normalize the data. + */ + +#define _FP_UNPACK_RAW_1(fs, X, val) \ + do { \ + union _FP_UNION_##fs _flo; _flo.flt = (val); \ + \ + X##_f = _flo.bits.frac; \ + X##_e = _flo.bits.exp; \ + X##_s = _flo.bits.sign; \ + } while (0) + + +/* + * Repack the raw bits of a native fp value. + */ + +#define _FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs _flo; \ + \ + _flo.bits.frac = X##_f; \ + _flo.bits.exp = X##_e; \ + _flo.bits.sign = X##_s; \ + \ + (val) = _flo.flt; \ + } while (0) + + +/* + * Multiplication algorithms: + */ + +/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the + multiplication immediately. */ + +#define _FP_MUL_MEAT_1_imm(fs, R, X, Y) \ + do { \ + R##_f = X##_f * Y##_f; \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ + } while (0) + +/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ + +#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit) \ + do { \ + _FP_W_TYPE _Z_f0, _Z_f1; \ + doit(_Z_f1, _Z_f0, X##_f, Y##_f); \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ + R##_f = _Z_f0; \ + } while (0) + +/* Finally, a simple widening multiply algorithm. What fun! */ + +#define _FP_MUL_MEAT_1_hard(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1; \ + \ + /* split the words in half */ \ + _xh = X##_f >> (_FP_W_TYPE_SIZE/2); \ + _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ + _yh = Y##_f >> (_FP_W_TYPE_SIZE/2); \ + _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ + \ + /* multiply the pieces */ \ + _z_f0 = _xl * _yl; \ + _a_f0 = _xh * _yl; \ + _a_f1 = _xl * _yh; \ + _z_f1 = _xh * _yh; \ + \ + /* reassemble into two full words */ \ + if ((_a_f0 += _a_f1) < _a_f1) \ + _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2); \ + _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2); \ + _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2); \ + _FP_FRAC_ADD_2(_z, _z, _a); \ + \ + /* normalize */ \ + _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs); \ + R##_f = _z_f0; \ + } while (0) + + +/* + * Division algorithms: + */ + +/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the + division immediately. Give this macro either _FP_DIV_HELP_imm for + C primitives or _FP_DIV_HELP_ldiv for the ISO function. Which you + choose will depend on what the compiler does with divrem4. */ + +#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit) \ + do { \ + _FP_W_TYPE _q, _r; \ + X##_f <<= (X##_f < Y##_f \ + ? R##_e--, _FP_WFRACBITS_##fs \ + : _FP_WFRACBITS_##fs - 1); \ + doit(_q, _r, X##_f, Y##_f); \ + R##_f = _q | (_r != 0); \ + } while (0) + +/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd + that may be useful in this situation. This first is for a primitive + that requires normalization, the second for one that does not. Look + for UDIV_NEEDS_NORMALIZATION to tell which your machine needs. */ + +#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _nh, _nl, _q, _r; \ + \ + /* Normalize Y -- i.e. make the most significant bit set. */ \ + Y##_f <<= _FP_WFRACXBITS_##fs - 1; \ + \ + /* Shift X op correspondingly high, that is, up one full word. */ \ + if (X##_f <= Y##_f) \ + { \ + _nl = 0; \ + _nh = X##_f; \ + } \ + else \ + { \ + R##_e++; \ + _nl = X##_f << (_FP_W_TYPE_SIZE-1); \ + _nh = X##_f >> 1; \ + } \ + \ + udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ + R##_f = _q | (_r != 0); \ + } while (0) + +#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _nh, _nl, _q, _r; \ + if (X##_f < Y##_f) \ + { \ + R##_e--; \ + _nl = X##_f << _FP_WFRACBITS_##fs; \ + _nh = X##_f >> _FP_WFRACXBITS_##fs; \ + } \ + else \ + { \ + _nl = X##_f << (_FP_WFRACBITS_##fs - 1); \ + _nh = X##_f >> (_FP_WFRACXBITS_##fs + 1); \ + } \ + udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ + R##_f = _q | (_r != 0); \ + } while (0) + + +/* + * Square root algorithms: + * We have just one right now, maybe Newton approximation + * should be added for those machines where division is fast. + */ + +#define _FP_SQRT_MEAT_1(R, S, T, X, q) \ + do { \ + while (q) \ + { \ + T##_f = S##_f + q; \ + if (T##_f <= X##_f) \ + { \ + S##_f = T##_f + q; \ + X##_f -= T##_f; \ + R##_f += q; \ + } \ + _FP_FRAC_SLL_1(X, 1); \ + q >>= 1; \ + } \ + } while (0) + +/* + * Assembly/disassembly for converting to/from integral types. + * No shifting or overflow handled here. + */ + +#define _FP_FRAC_ASSEMBLE_1(r, X, rsize) (r = X##_f) +#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize) (X##_f = r) + + +/* + * Convert FP values between word sizes + */ + +#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S) \ + do { \ + D##_f = S##_f; \ + if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs) \ + _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + else \ + D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \ + } while (0) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/op-2.h linux/arch/sparc64/math-emu/op-2.h --- v2.1.78/linux/arch/sparc64/math-emu/op-2.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/op-2.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,408 @@ +/* + * Basic two-word fraction declaration and manipulation. + */ + +#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1 +#define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1) +#define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I) +#define _FP_FRAC_HIGH_2(X) (X##_f1) +#define _FP_FRAC_LOW_2(X) (X##_f0) +#define _FP_FRAC_WORD_2(X,w) (X##_f##w) + +#define _FP_FRAC_SLL_2(X,N) \ + do { \ + if ((N) < _FP_W_TYPE_SIZE) \ + { \ + if (__builtin_constant_p(N) && (N) == 1) \ + { \ + X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0); \ + X##_f0 += X##_f0; \ + } \ + else \ + { \ + X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \ + X##_f0 <<= (N); \ + } \ + } \ + else \ + { \ + X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE); \ + X##_f0 = 0; \ + } \ + } while (0) + +#define _FP_FRAC_SRL_2(X,N) \ + do { \ + if ((N) < _FP_W_TYPE_SIZE) \ + { \ + X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N)); \ + X##_f1 >>= (N); \ + } \ + else \ + { \ + X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE); \ + X##_f1 = 0; \ + } \ + } while (0) + +/* Right shift with sticky-lsb. */ +#define _FP_FRAC_SRS_2(X,N,sz) \ + do { \ + if ((N) < _FP_W_TYPE_SIZE) \ + { \ + X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) | \ + (__builtin_constant_p(N) && (N) == 1 \ + ? X##_f0 & 1 \ + : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0)); \ + X##_f1 >>= (N); \ + } \ + else \ + { \ + X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \ + (((X##_f1 << (sz - (N))) | X##_f0) != 0)); \ + X##_f1 = 0; \ + } \ + } while (0) + +#define _FP_FRAC_ADDI_2(X,I) \ + __FP_FRAC_ADDI_2(X##_f1, X##_f0, I) + +#define _FP_FRAC_ADD_2(R,X,Y) \ + __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) + +#define _FP_FRAC_SUB_2(R,X,Y) \ + __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) + +#define _FP_FRAC_CLZ_2(R,X) \ + do { \ + if (X##_f1) \ + __FP_CLZ(R,X##_f1); \ + else \ + { \ + __FP_CLZ(R,X##_f0); \ + R += _FP_W_TYPE_SIZE; \ + } \ + } while(0) + +/* Predicates */ +#define _FP_FRAC_NEGP_2(X) ((_FP_WS_TYPE)X##_f1 < 0) +#define _FP_FRAC_ZEROP_2(X) ((X##_f1 | X##_f0) == 0) +#define _FP_FRAC_OVERP_2(fs,X) (X##_f1 & _FP_OVERFLOW_##fs) +#define _FP_FRAC_EQ_2(X, Y) (X##_f1 == Y##_f1 && X##_f0 == Y##_f0) +#define _FP_FRAC_GT_2(X, Y) \ + (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 > Y##_f0) +#define _FP_FRAC_GE_2(X, Y) \ + (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 >= Y##_f0) + +#define _FP_ZEROFRAC_2 0, 0 +#define _FP_MINFRAC_2 0, 1 + +/* + * Internals + */ + +#define __FP_FRAC_SET_2(X,I1,I0) (X##_f0 = I0, X##_f1 = I1) + +#define __FP_CLZ_2(R, xh, xl) \ + do { \ + if (xh) \ + __FP_CLZ(R,xl); \ + else \ + { \ + __FP_CLZ(R,xl); \ + R += _FP_W_TYPE_SIZE; \ + } \ + } while(0) + +#if 0 + +#ifndef __FP_FRAC_ADDI_2 +#define __FP_FRAC_ADDI_2(xh, xl, i) \ + (xh += ((xl += i) < i)) +#endif +#ifndef __FP_FRAC_ADD_2 +#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \ + (rh = xh + yh + ((rl = xl + yl) < xl)) +#endif +#ifndef __FP_FRAC_SUB_2 +#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \ + (rh = xh - yh - ((rl = xl - yl) > xl)) +#endif + +#else + +#undef __FP_FRAC_ADDI_2 +#define __FP_FRAC_ADDI_2(xh, xl, i) add_ssaaaa(xh, xl, xh, xl, 0, i) +#undef __FP_FRAC_ADD_2 +#define __FP_FRAC_ADD_2 add_ssaaaa +#undef __FP_FRAC_SUB_2 +#define __FP_FRAC_SUB_2 sub_ddmmss + +#endif + +/* + * Unpack the raw bits of a native fp value. Do not classify or + * normalize the data. + */ + +#define _FP_UNPACK_RAW_2(fs, X, val) \ + do { \ + union _FP_UNION_##fs _flo; _flo.flt = (val); \ + \ + X##_f0 = _flo.bits.frac0; \ + X##_f1 = _flo.bits.frac1; \ + X##_e = _flo.bits.exp; \ + X##_s = _flo.bits.sign; \ + } while (0) + + +/* + * Repack the raw bits of a native fp value. + */ + +#define _FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs _flo; \ + \ + _flo.bits.frac0 = X##_f0; \ + _flo.bits.frac1 = X##_f1; \ + _flo.bits.exp = X##_e; \ + _flo.bits.sign = X##_s; \ + \ + (val) = _flo.flt; \ + } while (0) + + +/* + * Multiplication algorithms: + */ + +/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ + +#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit) \ + do { \ + _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ + \ + doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \ + doit(_b_f1, _b_f0, X##_f0, Y##_f1); \ + doit(_c_f1, _c_f0, X##_f1, Y##_f0); \ + doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \ + \ + __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _b_f1, _b_f0, 0); \ + __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _c_f1, _c_f0, 0); \ + \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ + R##_f0 = _FP_FRAC_WORD_4(_z,0); \ + R##_f1 = _FP_FRAC_WORD_4(_z,1); \ + } while (0) + +#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _x[2], _y[2], _z[4]; \ + _x[0] = X##_f0; _x[1] = X##_f1; \ + _y[0] = Y##_f0; _y[1] = Y##_f1; \ + \ + mpn_mul_n(_z, _x, _y, 2); \ + \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs); \ + R##_f0 = _z[0]; \ + R##_f1 = _z[1]; \ + } while (0) + + +/* + * Division algorithms: + */ + +#define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y) \ + do { \ + extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], \ + _FP_W_TYPE n1, _FP_W_TYPE n0, \ + _FP_W_TYPE d1, _FP_W_TYPE d0); \ + _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0; \ + _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0; \ + _FP_W_TYPE _rmem[2], _qmem[2]; \ + \ + if (_FP_FRAC_GT_2(X, Y)) \ + { \ + R##_e++; \ + _n_f3 = X##_f1 >> 1; \ + _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1; \ + _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1); \ + _n_f0 = 0; \ + } \ + else \ + { \ + _n_f3 = X##_f1; \ + _n_f2 = X##_f0; \ + _n_f1 = _n_f0 = 0; \ + } \ + \ + /* Normalize, i.e. make the most significant bit of the \ + denominator set. */ \ + _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs - 1); \ + \ + /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4 \ + primitive snagged from libgcc2.c. */ \ + \ + _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1); \ + _q_f1 = _qmem[0]; \ + umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0); \ + _r_f1 = _rmem[0]; \ + _r_f0 = _n_f1; \ + if (_FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f1--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f1--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + } \ + } \ + _FP_FRAC_SUB_2(_r, _r, _m); \ + \ + _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1); \ + _q_f0 = _qmem[0]; \ + umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0); \ + _r_f1 = _rmem[0]; \ + _r_f0 = _n_f0; \ + if (_FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f0--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f0--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + } \ + } \ + _FP_FRAC_SUB_2(_r, _r, _m); \ + \ + R##_f1 = _q_f1; \ + R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0); \ + } while (0) + + +#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _x[4], _y[2], _z[4]; \ + _y[0] = Y##_f0; _y[1] = Y##_f1; \ + _x[0] = _x[3] = 0; \ + if (_FP_FRAC_GT_2(X, Y)) \ + { \ + R##_e++; \ + _x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) | \ + X##_f1 >> (_FP_W_TYPE_SIZE - \ + (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE))); \ + _x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE); \ + } \ + else \ + { \ + _x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) | \ + X##_f1 >> (_FP_W_TYPE_SIZE - \ + (_FP_WFRACBITS - _FP_W_TYPE_SIZE))); \ + _x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE); \ + } \ + \ + (void) mpn_divrem (_z, 0, _x, 4, _y, 2); \ + R##_f1 = _z[1]; \ + R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0); \ + } while (0) + + +/* + * Square root algorithms: + * We have just one right now, maybe Newton approximation + * should be added for those machines where division is fast. + */ + +#define _FP_SQRT_MEAT_2(R, S, T, X, q) \ + do { \ + while (q) \ + { \ + T##_f1 = S##_f1 + q; \ + if (T##_f1 <= X##_f1) \ + { \ + S##_f1 = T##_f1 + q; \ + X##_f1 -= T##_f1; \ + R##_f1 += q; \ + } \ + _FP_FRAC_SLL_2(X, 1); \ + q >>= 1; \ + } \ + q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ + while (q) \ + { \ + T##_f0 = S##_f0 + q; \ + T##_f1 = S##_f1; \ + if (T##_f1 < X##_f1 || \ + (T##_f1 == X##_f1 && T##_f0 < X##_f0)) \ + { \ + S##_f0 = T##_f0 + q; \ + if (((_FP_WS_TYPE)T##_f0) < 0 && \ + ((_FP_WS_TYPE)S##_f0) >= 0) \ + S##_f1++; \ + _FP_FRAC_SUB_2(X, X, T); \ + R##_f0 += q; \ + } \ + _FP_FRAC_SLL_2(X, 1); \ + q >>= 1; \ + } \ + } while (0) + + +/* + * Assembly/disassembly for converting to/from integral types. + * No shifting or overflow handled here. + */ + +#define _FP_FRAC_ASSEMBLE_2(r, X, rsize) \ + do { \ + if (rsize <= _FP_W_TYPE_SIZE) \ + r = X##_f0; \ + else \ + { \ + r = X##_f1; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f0; \ + } \ + } while (0) + +#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize) \ + do { \ + X##_f0 = r; \ + X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ + } while (0) + +/* + * Convert FP values between word sizes + */ + +#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S) \ + do { \ + _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + D##_f = S##_f0; \ + } while (0) + +#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S) \ + do { \ + D##_f0 = S##_f; \ + D##_f1 = 0; \ + _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ + } while (0) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/op-4.h linux/arch/sparc64/math-emu/op-4.h --- v2.1.78/linux/arch/sparc64/math-emu/op-4.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/op-4.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,78 @@ +/* + * Basic four-word fraction declaration and manipulation. + */ + +#define _FP_FRAC_DECL_4(X) _FP_W_TYPE X##_f[4] +#define _FP_FRAC_COPY_4(D,S) \ + (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1], \ + D##_f[2] = S##_f[2], D##_f[3] = S##_f[3]) +#define _FP_FRAC_SET_4(X,I) __FP_FRAC_SET_4(X, I) +#define _FP_FRAC_HIGH_4(X) (X##_f[3]) +#define _FP_FRAC_LOW_4(X) (X##_f[0]) +#define _FP_FRAC_WORD_4(X,w) (X##_f[w]) + +#define _FP_FRAC_SLL_4(X,N) \ + do { \ + _FP_I_TYPE _up, _down, _skip, _i; \ + _skip = (N) / _FP_W_TYPE_SIZE; \ + _up = (N) % _FP_W_TYPE_SIZE; \ + _down = _FP_W_TYPE_SIZE - _up; \ + for (_i = 3; _i > _skip; --_i) \ + X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \ + X##_f[_i] <<= _up; \ + for (--_i; _i >= 0; --_i) \ + X##_f[_i] = 0; \ + } while (0) + +#define _FP_FRAC_SRL_4(X,N) \ + do { \ + _FP_I_TYPE _up, _down, _skip, _i; \ + _skip = (N) / _FP_W_TYPE_SIZE; \ + _down = (N) % _FP_W_TYPE_SIZE; \ + _up = _FP_W_TYPE_SIZE - _down; \ + for (_i = 0; _i < 4-_skip; ++_i) \ + X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ + X##_f[_i] >>= _down; \ + for (++_i; _i < 4; ++_i) \ + X##_f[_i] = 0; \ + } while (0) + + +/* Right shift with sticky-lsb. */ +#define _FP_FRAC_SRS_4(X,N,size) \ + do { \ + _FP_I_TYPE _up, _down, _skip, _i; \ + _FP_W_TYPE _s; \ + _skip = (N) / _FP_W_TYPE_SIZE; \ + _down = (N) % _FP_W_TYPE_SIZE; \ + _up = _FP_W_TYPE_SIZE - _down; \ + for (_s = _i = 0; _i < _skip; ++_i) \ + _s |= X##_f[_i]; \ + _s = X##_f[_i] << _up; \ + X##_f[0] = X##_f[_skip] >> _down | X##_f[_skip+1] << _up | (_s != 0); \ + for (_i = 1; _i < 4-_skip; ++_i) \ + X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ + X##_f[_i] >>= _down; \ + for (++_i; _i < 4; ++_i) \ + X##_f[_i] = 0; \ + } while (0) + +#define _FP_FRAC_ADD_4(R,X,Y) \ + __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \ + X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ + Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) + +/* + * Internals + */ + +#define __FP_FRAC_SET_4(X,I3,I2,I1,I0) \ + (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0) + +#ifndef __FP_FRAC_ADD_4 +#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ + (r0 = x0 + y0, \ + r1 = x1 + y1 + (r0 < x0), \ + r2 = x2 + y2 + (r1 < x1), \ + r3 = x3 + y3 + (r2 < x2)) +#endif diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/op-common.h linux/arch/sparc64/math-emu/op-common.h --- v2.1.78/linux/arch/sparc64/math-emu/op-common.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/op-common.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,628 @@ +#define _FP_DECL(wc, X) \ + _FP_I_TYPE X##_c, X##_s, X##_e; \ + _FP_FRAC_DECL_##wc(X) + +/* + * Finish truely unpacking a native fp value by classifying the kind + * of fp value and normalizing both the exponent and the fraction. + */ + +#define _FP_UNPACK_CANONICAL(fs, wc, X) \ +do { \ + switch (X##_e) \ + { \ + default: \ + _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs; \ + _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \ + X##_e -= _FP_EXPBIAS_##fs; \ + X##_c = FP_CLS_NORMAL; \ + break; \ + \ + case 0: \ + if (_FP_FRAC_ZEROP_##wc(X)) \ + X##_c = FP_CLS_ZERO; \ + else \ + { \ + /* a denormalized number */ \ + _FP_I_TYPE _shift; \ + _FP_FRAC_CLZ_##wc(_shift, X); \ + _shift -= _FP_FRACXBITS_##fs; \ + _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ + X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ + X##_c = FP_CLS_NORMAL; \ + } \ + break; \ + \ + case _FP_EXPMAX_##fs: \ + if (_FP_FRAC_ZEROP_##wc(X)) \ + X##_c = FP_CLS_INF; \ + else \ + /* we don't differentiate between signaling and quiet nans */ \ + X##_c = FP_CLS_NAN; \ + break; \ + } \ +} while (0) + + +/* + * Before packing the bits back into the native fp result, take care + * of such mundane things as rounding and overflow. Also, for some + * kinds of fp values, the original parts may not have been fully + * extracted -- but that is ok, we can regenerate them now. + */ + +#define _FP_PACK_CANONICAL(fs, wc, X) \ +do { \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + X##_e += _FP_EXPBIAS_##fs; \ + if (X##_e > 0) \ + { \ + _FP_ROUND(wc, X); \ + if (_FP_FRAC_OVERP_##wc(fs, X)) \ + { \ + _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \ + X##_e++; \ + } \ + else \ + _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ + if (X##_e >= _FP_EXPMAX_##fs) \ + { \ + /* overflow to infinity */ \ + X##_e = _FP_EXPMAX_##fs; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + } \ + } \ + else \ + { \ + /* we've got a denormalized number */ \ + X##_e = -X##_e + 1; \ + if (X##_e <= _FP_WFRACBITS_##fs) \ + { \ + _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ + _FP_ROUND(wc, X); \ + X##_e = _FP_FRAC_OVERP_##wc(fs, X); \ + _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ + } \ + else \ + { \ + /* underflow to zero */ \ + X##_e = 0; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + } \ + } \ + break; \ + \ + case FP_CLS_ZERO: \ + X##_e = 0; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + break; \ + \ + case FP_CLS_INF: \ + X##_e = _FP_EXPMAX_##fs; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + break; \ + \ + case FP_CLS_NAN: \ + X##_e = _FP_EXPMAX_##fs; \ + if (!_FP_KEEPNANFRACP) \ + { \ + _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \ + X##_s = 0; \ + } \ + else \ + _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \ + break; \ + } \ +} while (0) + + +/* + * Main addition routine. The input values should be cooked. + */ + +#define _FP_ADD(fs, wc, R, X, Y) \ +do { \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + { \ + /* shift the smaller number so that its exponent matches the larger */ \ + _FP_I_TYPE diff = X##_e - Y##_e; \ + \ + if (diff < 0) \ + { \ + diff = -diff; \ + if (diff <= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ + else if (!_FP_FRAC_ZEROP_##wc(X)) \ + _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ + else \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + R##_e = Y##_e; \ + } \ + else \ + { \ + if (diff > 0) \ + { \ + if (diff <= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ + else if (!_FP_FRAC_ZEROP_##wc(Y)) \ + _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \ + else \ + _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc); \ + } \ + R##_e = X##_e; \ + } \ + \ + R##_c = FP_CLS_NORMAL; \ + \ + if (X##_s == Y##_s) \ + { \ + R##_s = X##_s; \ + _FP_FRAC_ADD_##wc(R, X, Y); \ + if (_FP_FRAC_OVERP_##wc(fs, R)) \ + { \ + _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ + R##_e++; \ + } \ + } \ + else \ + { \ + R##_s = X##_s; \ + _FP_FRAC_SUB_##wc(R, X, Y); \ + if (_FP_FRAC_ZEROP_##wc(R)) \ + { \ + /* return an exact zero */ \ + if (FP_ROUNDMODE == FP_RND_MINF) \ + R##_s |= Y##_s; \ + else \ + R##_s &= Y##_s; \ + R##_c = FP_CLS_ZERO; \ + } \ + else \ + { \ + if (_FP_FRAC_NEGP_##wc(R)) \ + { \ + _FP_FRAC_SUB_##wc(R, Y, X); \ + R##_s = Y##_s; \ + } \ + \ + /* renormalize after subtraction */ \ + _FP_FRAC_CLZ_##wc(diff, R); \ + diff -= _FP_WFRACXBITS_##fs; \ + if (diff) \ + { \ + R##_e -= diff; \ + _FP_FRAC_SLL_##wc(R, diff); \ + } \ + } \ + } \ + break; \ + } \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + R##_e = X##_e; \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_s = X##_s; \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + R##_e = Y##_e; \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_s = Y##_s; \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + if (X##_s != Y##_s) \ + { \ + /* +INF + -INF => NAN */ \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + R##_s = X##_s ^ Y##_s; \ + R##_c = FP_CLS_NAN; \ + break; \ + } \ + /* FALLTHRU */ \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + R##_s = X##_s; \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + R##_s = Y##_s; \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + /* make sure the sign is correct */ \ + if (FP_ROUNDMODE == FP_RND_MINF) \ + R##_s = X##_s | Y##_s; \ + else \ + R##_s = X##_s & Y##_s; \ + R##_c = FP_CLS_ZERO; \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +/* + * Main negation routine. FIXME -- when we care about setting exception + * bits reliably, this will not do. We should examine all of the fp classes. + */ + +#define _FP_NEG(fs, wc, R, X) \ + do { \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_c = X##_c; \ + R##_e = X##_e; \ + R##_s = 1 ^ X##_s; \ + } while (0) + + +/* + * Main multiplication routine. The input values should be cooked. + */ + +#define _FP_MUL(fs, wc, R, X, Y) \ +do { \ + R##_s = X##_s ^ Y##_s; \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + R##_c = FP_CLS_NORMAL; \ + R##_e = X##_e + Y##_e + 1; \ + \ + _FP_MUL_MEAT_##fs(R,X,Y); \ + \ + if (_FP_FRAC_OVERP_##wc(fs, R)) \ + _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ + else \ + R##_e--; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + R##_s = X##_s; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + R##_s = Y##_s; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +/* + * Main division routine. The input values should be cooked. + */ + +#define _FP_DIV(fs, wc, R, X, Y) \ +do { \ + R##_s = X##_s ^ Y##_s; \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + R##_c = FP_CLS_NORMAL; \ + R##_e = X##_e - Y##_e; \ + \ + _FP_DIV_MEAT_##fs(R,X,Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + R##_s = X##_s; \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + R##_c = FP_CLS_ZERO; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +/* + * Main differential comparison routine. The inputs should be raw not + * cooked. The return is -1,0,1 for normal values, 2 otherwise. + */ + +#define _FP_CMP(fs, wc, ret, X, Y, un) \ + do { \ + /* NANs are unordered */ \ + if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ + || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ + { \ + ret = un; \ + } \ + else \ + { \ + /* Force -0 -> +0 */ \ + if (!X##_e && _FP_FRAC_ZEROP_##wc(X)) X##_s = 0; \ + if (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) X##_s = 0; \ + \ + if (X##_s != Y##_s) \ + ret = X##_s ? -1 : 1; \ + else if (X##_e > Y##_e) \ + ret = X##_s ? -1 : 1; \ + else if (X##_e < Y##_e) \ + ret = X##_s ? 1 : -1; \ + else if (_FP_FRAC_GT_##wc(X, Y)) \ + ret = X##_s ? -1 : 1; \ + else if (_FP_FRAC_GT_##wc(Y, X)) \ + ret = X##_s ? 1 : -1; \ + else \ + ret = 0; \ + } \ + } while (0) + + +/* Simplification for strict equality. */ + +#define _FP_CMP_EQ(fs, wc, ret, X, Y) \ + do { \ + /* NANs are unordered */ \ + if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ + || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ + { \ + ret = 1; \ + } \ + else \ + { \ + ret = !(X##_e == Y##_e \ + && _FP_FRAC_EQ_##wc(X, Y) \ + && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \ + } \ + } while (0) + +/* + * Main square root routine. The input value should be cooked. + */ + +#define _FP_SQRT(fs, wc, R, X) \ +do { \ + _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \ + _FP_W_TYPE q; \ + switch (X##_c) \ + { \ + case FP_CLS_NAN: \ + R##_s = 0; \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + break; \ + case FP_CLS_INF: \ + if (X##_s) \ + { \ + R##_s = 0; \ + R##_c = FP_CLS_NAN; /* sNAN */ \ + } \ + else \ + { \ + R##_s = 0; \ + R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \ + } \ + break; \ + case FP_CLS_ZERO: \ + R##_s = X##_s; \ + R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \ + break; \ + case FP_CLS_NORMAL: \ + R##_s = 0; \ + if (X##_s) \ + { \ + R##_c = FP_CLS_NAN; /* sNAN */ \ + break; \ + } \ + R##_c = FP_CLS_NORMAL; \ + if (X##_e & 1) \ + _FP_FRAC_SLL_##wc(X, 1); \ + R##_e = X##_e >> 1; \ + _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc); \ + _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc); \ + q = _FP_OVERFLOW_##fs; \ + _FP_FRAC_SLL_##wc(X, 1); \ + _FP_SQRT_MEAT_##wc(R, S, T, X, q); \ + _FP_FRAC_SRL_##wc(R, 1); \ + } \ + } while (0) + +/* + * Convert from FP to integer + */ + +#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ + do { \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + if (X##_e < 0) \ + { \ + case FP_CLS_NAN: \ + case FP_CLS_ZERO: \ + r = 0; \ + } \ + else if (X##_e >= rsize - (rsigned != 0)) \ + { \ + case FP_CLS_INF: \ + if (rsigned) \ + { \ + r = 1; \ + r <<= rsize - 1; \ + r -= 1 - X##_s; \ + } \ + else \ + { \ + r = 0; \ + if (!X##_s) \ + r = ~r; \ + } \ + } \ + else \ + { \ + if (_FP_W_TYPE_SIZE*wc < rsize) \ + { \ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + r <<= X##_e - _FP_WFRACBITS_##fs; \ + } \ + else \ + { \ + if (X##_e >= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ + else \ + _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + } \ + if (rsigned && X##_s) \ + r = -r; \ + } \ + break; \ + } \ + } while (0) + +#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \ + do { \ + if (r) \ + { \ + X##_c = FP_CLS_NORMAL; \ + \ + if ((X##_s = (r < 0))) \ + r = -r; \ + /* Note that `r' is now considered unsigned, so we don't have \ + to worry about the single signed overflow case. */ \ + \ + if (rsize <= _FP_W_TYPE_SIZE) \ + __FP_CLZ(X##_e, r); \ + else \ + __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), \ + (_FP_W_TYPE)r); \ + if (rsize < _FP_W_TYPE_SIZE) \ + X##_e -= (_FP_W_TYPE_SIZE - rsize); \ + X##_e = rsize - X##_e - 1; \ + \ + if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \ + __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize); \ + r &= ~((_FP_W_TYPE)1 << X##_e); \ + _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize); \ + _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ + } \ + else \ + { \ + X##_c = FP_CLS_ZERO, X##_s = 0; \ + } \ + } while (0) + + +#define FP_CONV(dfs,sfs,dwc,swc,D,S) \ + do { \ + _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \ + D##_e = S##_e; \ + D##_c = S##_c; \ + D##_s = S##_s; \ + } while (0) + +/* + * Helper primitives. + */ + +/* Count leading zeros in a word. */ + +#ifndef __FP_CLZ +#define __FP_CLZ(r, x) \ + do { \ + _FP_W_TYPE _t = (x); \ + r = _FP_W_TYPE_SIZE - 1; \ + if (_t > 0xffffffff) r -= 32; \ + if (_t > 0xffffffff) _t >>= 32; \ + if (_t > 0xffff) r -= 16; \ + if (_t > 0xffff) _t >>= 16; \ + if (_t > 0xff) r -= 8; \ + if (_t > 0xff) _t >>= 8; \ + if (_t & 0xf0) r -= 4; \ + if (_t & 0xf0) _t >>= 4; \ + if (_t & 0xc) r -= 2; \ + if (_t & 0xc) _t >>= 2; \ + if (_t & 0x2) r -= 1; \ + } while (0) +#endif + +#define _FP_DIV_HELP_imm(q, r, n, d) \ + do { \ + q = n / d, r = n % d; \ + } while (0) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/quad.h linux/arch/sparc64/math-emu/quad.h --- v2.1.78/linux/arch/sparc64/math-emu/quad.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/quad.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,71 @@ +/* + * Definitions for IEEE Quad Precision + */ + +#if _FP_W_TYPE_SIZE < 64 +#error "Only stud muffins allowed, schmuck." +#endif + +#define _FP_FRACTBITS_Q (2*_FP_W_TYPE_SIZE) + +#define _FP_FRACBITS_Q 113 +#define _FP_FRACXBITS_Q (_FP_FRACTBITS_Q - _FP_FRACBITS_Q) +#define _FP_WFRACBITS_Q (_FP_WORKBITS + _FP_FRACBITS_Q) +#define _FP_WFRACXBITS_Q (_FP_FRACTBITS_Q - _FP_WFRACBITS_Q) +#define _FP_EXPBITS_Q 15 +#define _FP_EXPBIAS_Q 16383 +#define _FP_EXPMAX_Q 32767 + +#define _FP_QNANBIT_Q \ + ((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-2) % _FP_W_TYPE_SIZE) +#define _FP_IMPLBIT_Q \ + ((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-1) % _FP_W_TYPE_SIZE) +#define _FP_OVERFLOW_Q \ + ((_FP_W_TYPE)1 << (_FP_WFRACBITS_Q % _FP_W_TYPE_SIZE)) + +union _FP_UNION_Q +{ + long double flt /* __attribute__((mode(TF))) */ ; + struct { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned sign : 1; + unsigned exp : _FP_EXPBITS_Q; + unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE; + unsigned long frac0 : _FP_W_TYPE_SIZE; +#else + unsigned long frac0 : _FP_W_TYPE_SIZE; + unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE; + unsigned exp : _FP_EXPBITS_Q; + unsigned sign : 1; +#endif + } bits; +}; + +#define FP_DECL_Q(X) _FP_DECL(2,X) +#define FP_UNPACK_RAW_Q(X,val) _FP_UNPACK_RAW_2(Q,X,val) +#define FP_PACK_RAW_Q(val,X) _FP_PACK_RAW_2(Q,val,X) + +#define FP_UNPACK_Q(X,val) \ + do { \ + _FP_UNPACK_RAW_2(Q,X,val); \ + _FP_UNPACK_CANONICAL(Q,2,X); \ + } while (0) + +#define FP_PACK_Q(val,X) \ + do { \ + _FP_PACK_CANONICAL(Q,2,X); \ + _FP_PACK_RAW_2(Q,val,X); \ + } while (0) + +#define FP_NEG_Q(R,X) _FP_NEG(Q,2,R,X) +#define FP_ADD_Q(R,X,Y) _FP_ADD(Q,2,R,X,Y) +#define FP_SUB_Q(R,X,Y) _FP_SUB(Q,2,R,X,Y) +#define FP_MUL_Q(R,X,Y) _FP_MUL(Q,2,R,X,Y) +#define FP_DIV_Q(R,X,Y) _FP_DIV(Q,2,R,X,Y) +#define FP_SQRT_Q(R,X) _FP_SQRT(Q,2,R,X) + +#define FP_CMP_Q(r,X,Y,un) _FP_CMP(Q,2,r,X,Y,un) +#define FP_CMP_EQ_Q(r,X,Y) _FP_CMP_EQ(Q,2,r,X,Y) + +#define FP_TO_INT_Q(r,X,rsz,rsg) _FP_TO_INT(Q,2,r,X,rsz,rsg) +#define FP_FROM_INT_Q(X,r,rs,rt) _FP_FROM_INT(Q,2,X,r,rs,rt) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/sfp-machine.h linux/arch/sparc64/math-emu/sfp-machine.h --- v2.1.78/linux/arch/sparc64/math-emu/sfp-machine.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/sfp-machine.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,225 @@ +/* Machine-dependent software floating-point definitions. Sparc64 version. + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define _FP_W_TYPE_SIZE 64 +#define _FP_W_TYPE unsigned long +#define _FP_WS_TYPE signed long +#define _FP_I_TYPE long + +#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_imm(S,R,X,Y) +#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_Q(R,X,Y) _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm) + +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm) +#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y) +#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y) + +#define _FP_NANFRAC_S _FP_QNANBIT_S +#define _FP_NANFRAC_D _FP_QNANBIT_D +#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0 + +#define _FP_KEEPNANFRACP 1 +#define _FP_CHOOSENAN(fs, wc, R, X, Y) \ + do { \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R,Y); \ + R##_c = FP_CLS_NAN; \ + } while (0) + +#define __FP_UNPACK_RAW_1(fs, X, val) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + X##_f = _flo->bits.frac; \ + X##_e = _flo->bits.exp; \ + X##_s = _flo->bits.sign; \ + } while (0) + +#define __FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac = X##_f; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#define __FP_UNPACK_RAW_2(fs, X, val) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + X##_f0 = _flo->bits.frac0; \ + X##_f1 = _flo->bits.frac1; \ + X##_e = _flo->bits.exp; \ + X##_s = _flo->bits.sign; \ + } while (0) + +#define __FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f0; \ + _flo->bits.frac1 = X##_f1; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#define __FP_UNPACK_S(X,val) \ + do { \ + __FP_UNPACK_RAW_1(S,X,val); \ + _FP_UNPACK_CANONICAL(S,1,X); \ + } while (0) + +#define __FP_PACK_S(val,X) \ + do { \ + _FP_PACK_CANONICAL(S,1,X); \ + __FP_PACK_RAW_1(S,val,X); \ + } while (0) + +#define __FP_UNPACK_D(X,val) \ + do { \ + __FP_UNPACK_RAW_1(D,X,val); \ + _FP_UNPACK_CANONICAL(D,1,X); \ + } while (0) + +#define __FP_PACK_D(val,X) \ + do { \ + _FP_PACK_CANONICAL(D,1,X); \ + __FP_PACK_RAW_1(D,val,X); \ + } while (0) + +#define __FP_UNPACK_Q(X,val) \ + do { \ + __FP_UNPACK_RAW_2(Q,X,val); \ + _FP_UNPACK_CANONICAL(Q,2,X); \ + } while (0) + +#define __FP_PACK_Q(val,X) \ + do { \ + _FP_PACK_CANONICAL(Q,2,X); \ + __FP_PACK_RAW_2(Q,val,X); \ + } while (0) + +#include +#include + +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %4,%5,%1 + add %2,%3,%0 + bcs,a,pn %%xcc, 1f + add %0, 1, %0 + 1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "r" ((UDItype)(ah)), \ + "r" ((UDItype)(bh)), \ + "r" ((UDItype)(al)), \ + "r" ((UDItype)(bl)) \ + : "cc") + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %4,%5,%1 + sub %2,%3,%0 + bcs,a,pn %%xcc, 1f + sub %0, 1, %0 + 1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "r" ((UDItype)(ah)), \ + "r" ((UDItype)(bh)), \ + "r" ((UDItype)(al)), \ + "r" ((UDItype)(bl)) \ + : "cc") + +#define umul_ppmm(wh, wl, u, v) \ + do { \ + long tmp1 = 0, tmp2 = 0, tmp3 = 0; \ + __asm__ ("mulx %2,%3,%1 + srlx %2,32,%4 + srl %3,0,%5 + mulx %4,%5,%6 + srlx %3,32,%4 + srl %2,0,%5 + mulx %4,%5,%5 + srlx %2,32,%4 + add %5,%6,%6 + srlx %3,32,%5 + mulx %4,%5,%4 + srlx %6,32,%5 + add %4,%5,%0" \ + : "=r" ((UDItype)(wh)), \ + "=&r" ((UDItype)(wl)) \ + : "r" ((UDItype)(u)), \ + "r" ((UDItype)(v)), \ + "r" ((UDItype)(tmp1)), \ + "r" ((UDItype)(tmp2)), \ + "r" ((UDItype)(tmp3)) \ + : "cc"); \ + } while (0) + +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ + __d1 = (d >> 32); \ + __d0 = (USItype)d; \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = (__r1 << 32) | (n0 >> 32); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */ \ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = (__r0 << 32) | ((USItype)n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) (__q1 << 32) | __q0; \ + (r) = __r0; \ + } while (0) + +#define UDIV_NEEDS_NORMALIZATION 1 + +#define abort() \ + return 0 + +#ifdef __BIG_ENDIAN +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/single.h linux/arch/sparc64/math-emu/single.h --- v2.1.78/linux/arch/sparc64/math-emu/single.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/single.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,66 @@ +/* + * Definitions for IEEE Single Precision + */ + +#if _FP_W_TYPE_SIZE < 32 +#error "Here's a nickle kid. Go buy yourself a real computer." +#endif + +#define _FP_FRACBITS_S 24 +#define _FP_FRACXBITS_S (_FP_W_TYPE_SIZE - _FP_FRACBITS_S) +#define _FP_WFRACBITS_S (_FP_WORKBITS + _FP_FRACBITS_S) +#define _FP_WFRACXBITS_S (_FP_W_TYPE_SIZE - _FP_WFRACBITS_S) +#define _FP_EXPBITS_S 8 +#define _FP_EXPBIAS_S 127 +#define _FP_EXPMAX_S 255 +#define _FP_QNANBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2)) +#define _FP_IMPLBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1)) +#define _FP_OVERFLOW_S ((_FP_W_TYPE)1 << (_FP_WFRACBITS_S)) + +/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be + chosen by the target machine. */ + +union _FP_UNION_S +{ + float flt; + struct { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned sign : 1; + unsigned exp : _FP_EXPBITS_S; + unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); +#else + unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); + unsigned exp : _FP_EXPBITS_S; + unsigned sign : 1; +#endif + } bits __attribute__((packed)); +}; + +#define FP_DECL_S(X) _FP_DECL(1,X) +#define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val) +#define FP_PACK_RAW_S(val,X) _FP_PACK_RAW_1(S,val,X) + +#define FP_UNPACK_S(X,val) \ + do { \ + _FP_UNPACK_RAW_1(S,X,val); \ + _FP_UNPACK_CANONICAL(S,1,X); \ + } while (0) + +#define FP_PACK_S(val,X) \ + do { \ + _FP_PACK_CANONICAL(S,1,X); \ + _FP_PACK_RAW_1(S,val,X); \ + } while (0) + +#define FP_NEG_S(R,X) _FP_NEG(S,1,R,X) +#define FP_ADD_S(R,X,Y) _FP_ADD(S,1,R,X,Y) +#define FP_SUB_S(R,X,Y) _FP_SUB(S,1,R,X,Y) +#define FP_MUL_S(R,X,Y) _FP_MUL(S,1,R,X,Y) +#define FP_DIV_S(R,X,Y) _FP_DIV(S,1,R,X,Y) +#define FP_SQRT_S(R,X) _FP_SQRT(S,1,R,X) + +#define FP_CMP_S(r,X,Y,un) _FP_CMP(S,1,r,X,Y,un) +#define FP_CMP_EQ_S(r,X,Y) _FP_CMP_EQ(S,1,r,X,Y) + +#define FP_TO_INT_S(r,X,rsz,rsg) _FP_TO_INT(S,1,r,X,rsz,rsg) +#define FP_FROM_INT_S(X,r,rs,rt) _FP_FROM_INT(S,1,X,r,rs,rt) diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/soft-fp.h linux/arch/sparc64/math-emu/soft-fp.h --- v2.1.78/linux/arch/sparc64/math-emu/soft-fp.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/soft-fp.h Mon Jan 12 15:15:44 1998 @@ -0,0 +1,83 @@ +#ifndef SOFT_FP_H +#define SOFT_FP_H + +#include "sfp-machine.h" + +#define _FP_WORKBITS 3 +#define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3) +#define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2) +#define _FP_WORK_GUARD ((_FP_W_TYPE)1 << 1) +#define _FP_WORK_STICKY ((_FP_W_TYPE)1 << 0) + +#ifndef FP_RND_NEAREST +# define FP_RND_NEAREST 0 +# define FP_RND_ZERO 1 +# define FP_RND_PINF 2 +# define FP_RND_MINF 3 +# define FP_ROUNDMODE FP_RND_NEAREST +#endif + +#define _FP_ROUND_NEAREST(wc, X) \ + do { \ + if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ + } while(0) + +#define _FP_ROUND_ZERO(wc, X) + +#define _FP_ROUND_PINF(wc, X) \ + do { \ + if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ + } while (0) + +#define _FP_ROUND_MINF(wc, X) \ + do { \ + if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ + } while (0) + +#define _FP_ROUND(wc, X) \ + switch (FP_ROUNDMODE) \ + { \ + case FP_RND_NEAREST: \ + _FP_ROUND_NEAREST(wc,X); \ + break; \ + case FP_RND_ZERO: \ + _FP_ROUND_ZERO(wc,X); \ + break; \ + case FP_RND_PINF: \ + _FP_ROUND_PINF(wc,X); \ + break; \ + case FP_RND_MINF: \ + _FP_ROUND_MINF(wc,X); \ + break; \ + } + +#define FP_CLS_NORMAL 0 +#define FP_CLS_ZERO 1 +#define FP_CLS_INF 2 +#define FP_CLS_NAN 3 + +#define _FP_CLS_COMBINE(x,y) (((x) << 2) | (y)) + +#include "op-1.h" +#include "op-2.h" +#include "op-4.h" +#include "op-common.h" + +/* Sigh. Silly things longlong.h needs. */ +#define UWtype _FP_W_TYPE +#define W_TYPE_SIZE _FP_W_TYPE_SIZE + +typedef int SItype __attribute__((mode(SI))); +typedef int DItype __attribute__((mode(DI))); +typedef unsigned int USItype __attribute__((mode(SI))); +typedef unsigned int UDItype __attribute__((mode(DI))); +#if _FP_W_TYPE_SIZE == 32 +typedef unsigned int UHWtype __attribute__((mode(HI))); +#elif _FP_W_TYPE_SIZE == 64 +typedef USItype UHWtype; +#endif + +#endif diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/math-emu/udivmodti4.c linux/arch/sparc64/math-emu/udivmodti4.c --- v2.1.78/linux/arch/sparc64/math-emu/udivmodti4.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/math-emu/udivmodti4.c Mon Jan 12 15:15:44 1998 @@ -0,0 +1,191 @@ +/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ + +#include "soft-fp.h" + +#undef count_leading_zeros +#define count_leading_zeros __FP_CLZ + +void +_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], + _FP_W_TYPE n1, _FP_W_TYPE n0, + _FP_W_TYPE d1, _FP_W_TYPE d0) +{ + _FP_W_TYPE q0, q1, r0, r1; + _FP_I_TYPE b, bm; + + if (d1 == 0) + { +#if !UDIV_NEEDS_NORMALIZATION + if (d0 > n1) + { + /* 0q = nn / 0D */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + udiv_qrnnd (q1, n1, 0, n1, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + } + + r0 = n0; + r1 = 0; + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of SI_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + _FP_W_TYPE n2; + + /* Normalize. */ + + b = _FP_W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + r0 = n0 >> bm; + r1 = 0; +#endif /* UDIV_NEEDS_NORMALIZATION */ + } + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + r0 = n0; + r1 = n1; + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + r0 = n0; + r1 = n1; + } + else + { + _FP_W_TYPE m1, m0, n2; + + /* Normalize. */ + + b = _FP_W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + sub_ddmmss (n1, n0, n1, n0, m1, m0); + r0 = (n1 << b) | (n0 >> bm); + r1 = n1 >> bm; + } + } + } + + q[0] = q0; q[1] = q1; + r[0] = r0, r[1] = r1; +} diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c --- v2.1.78/linux/arch/sparc64/mm/asyncd.c Thu May 15 16:48:02 1997 +++ linux/arch/sparc64/mm/asyncd.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.2 1997/05/15 21:14:32 davem Exp $ +/* $Id: asyncd.c,v 1.3 1997/12/11 15:15:58 jj Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -239,7 +239,9 @@ current->session = 1; current->pgrp = 1; sprintf(current->comm, "asyncd"); - current->blocked = ~0UL; /* block all signals */ + + sigfillset(¤t->blocked); /* block all signals */ + recalc_sigpending(current); /* Give asyncd a realtime priority. */ current->policy = SCHED_FIFO; @@ -259,7 +261,9 @@ save_flags(flags); cli(); while (!async_queue) { - current->signal = 0; + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); interruptible_sleep_on(&asyncd_wait); } diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.1.78/linux/arch/sparc64/mm/init.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/mm/init.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.55 1997/08/24 01:22:29 davem Exp $ +/* $Id: init.c,v 1.60 1998/01/10 18:19:51 ecd Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -116,9 +116,10 @@ /* IOMMU support, the ideas are right, the code should be cleaned a bit still... */ /* This keeps track of pages used in sparc_alloc_dvma() invocations. */ -static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, }; -static unsigned long dvma_pages_current_offset = 0; -static int dvma_pages_current_index = 0; +/* NOTE: All of these are inited to 0 in bss, don't need to make data segment bigger */ +static unsigned long dvma_map_pages[0x10000000 >> 16]; +static unsigned long dvma_pages_current_offset; +static int dvma_pages_current_index; /* #define E3000_DEBUG */ @@ -664,8 +665,9 @@ { pte_t *pte; - pte = (pte_t *) get_free_page(GFP_KERNEL); + pte = (pte_t *) __get_free_page(GFP_KERNEL); if(pte) { + clear_page((unsigned long)pte); pmd_set(pmd, pte); return pte + offset; } @@ -834,7 +836,7 @@ allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_VADDR + 0x4000000); allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000); inherit_prom_mappings(); - + /* Ok, we can use our TLB miss and window trap handlers safely. */ setup_tba((unsigned long)init_mm.pgd); @@ -854,9 +856,9 @@ membar("#Sync"); inherit_locked_prom_mappings(1); - + flush_tlb_all(); - + start_mem = free_area_init(PAGE_ALIGN(mempool), end_mem); return device_scan (PAGE_ALIGN (start_mem)); @@ -881,6 +883,8 @@ if((phys_addr >= base) && (phys_addr < limit) && ((phys_addr + PAGE_SIZE) < limit)) mem_map[MAP_NR(addr)].flags &= ~(1<= 0xf0000000) + mem_map[MAP_NR(addr)].flags &= ~(1<= initrd_start && addr < initrd_end) + if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) { mem_map[MAP_NR(addr)].flags &= ~(1< 0) { buffer [i] = 0; if (!strcmp (buffer, "sbus")) - break; + goto getit; } } + if ((pci = prom_getparent (node))) { + i = prom_getproperty (pci, "name", buffer, len); + if (i > 0) { + buffer [i] = 0; + if (!strcmp (buffer, "pci")) + goto getit; + } + pci = 0; + } + if ((ebus = prom_getparent (node))) { + i = prom_getproperty (ebus, "name", buffer, len); + if (i > 0) { + buffer[i] = 0; + if (!strcmp (buffer, "ebus")) + goto getit; + } + ebus = 0; + } + if ((ide = prom_getparent (node))) { + i = prom_getproperty (ide, "name", buffer, len); + if (i > 0) { + buffer [i] = 0; + if (!strcmp (buffer, "ide")) + goto getit; + } + ide = 0; + } +getit: i = prom_getproperty (node, "name", buffer, len); if (i <= 0) { buffer [0] = 0; @@ -220,8 +249,28 @@ if (sbus) { reg = (struct linux_prom_registers *)reg64; sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr); + } else if (pci) { + int dev, fn; + reg = (struct linux_prom_registers *)reg64; + fn = (reg[0].which_io >> 8) & 0x07; + dev = (reg[0].which_io >> 11) & 0x1f; + if (fn) + sprintf (buffer, "@%x,%x", dev, fn); + else + sprintf (buffer, "@%x", dev); + } else if (ebus) { + reg = (struct linux_prom_registers *)reg64; + sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr); + } else if (ide) { + reg = (struct linux_prom_registers *)reg64; + sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr); + } else if (i == 4) { /* Happens on 8042's children on Ultra/PCI. */ + reg = (struct linux_prom_registers *)reg64; + sprintf (buffer, "@%x", reg[0].which_io); } else { - sprintf (buffer, "@%x,%x", (unsigned int)(reg64[0].phys_addr >> 36), (unsigned int)(reg64[0].phys_addr)); + sprintf (buffer, "@%x,%x", + (unsigned int)(reg64[0].phys_addr >> 36), + (unsigned int)(reg64[0].phys_addr)); } return 0; } @@ -318,9 +367,9 @@ prom_pathtoinode(char *path) { int node, inst; - + inst = prom_devopen (path); - if (inst == -1) return 0; + if (inst == 0) return 0; node = prom_inst2pkg (inst); prom_devclose (inst); if (node == -1) return 0; diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/Makefile linux/arch/sparc64/solaris/Makefile --- v2.1.78/linux/arch/sparc64/solaris/Makefile Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/Makefile Mon Jan 12 15:15:44 1998 @@ -11,13 +11,14 @@ O_OBJS := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o ifeq ($(CONFIG_SOLARIS_EMUL),m) M_OBJS := $(O_TARGET) +CPPFLAGS = $(MODFLAGS) endif .S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + $(CPP) -D__ASSEMBLY__ $(CPPFLAGS) -ansi $< -o $*.s .S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(CPPFLAGS) -ansi -c $< -o $*.o ifneq ($(CONFIG_SOLARIS_EMUL),y) do_it_all: diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/entry64.S linux/arch/sparc64/solaris/entry64.S --- v2.1.78/linux/arch/sparc64/solaris/entry64.S Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/entry64.S Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: entry64.S,v 1.3 1997/09/03 12:29:12 jj Exp $ +/* $Id: entry64.S,v 1.4 1997/09/09 17:13:50 jj Exp $ * entry64.S: Solaris syscall emulation entry point. * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -25,12 +25,12 @@ solaris_syscall_trace: call syscall_trace nop - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 + srl %i0, 0, %o0 + mov %i4, %o4 + srl %i1, 0, %o1 + mov %i5, %o5 b,pt %xcc, 2f - mov %i4, %o4 + srl %i2, 0, %o2 solaris_sucks: /* Solaris is a big system which needs to be able to do all the things @@ -41,6 +41,7 @@ mov %i2, %i1 srl %o0, 0, %o0 mov %i3, %i2 + movrz %g1, 256, %g1 /* Ensure we don't loop forever */ mov %i4, %i3 mov %i5, %i4 ba,pt %xcc, solaris_sparc_syscall @@ -55,7 +56,7 @@ call solaris_register nop ba,pt %xcc, 1f - mov %i0, %o0 + mov %i4, %o4 linux_syscall_for_solaris: sll %l7, 2, %l4 @@ -66,46 +67,35 @@ .align 32 .globl solaris_sparc_syscall solaris_sparc_syscall: -#ifdef DEBUG_SOLARIS - mov %g1, %o0 - call entry_printk - add %sp, STACK_BIAS + REGWIN_SZ, %o1 -#endif ldub [%g6 + AOFF_task_personality + ASIZ_task_personality - 1], %l0 cmp %g1, 255 bg,pn %icc, solaris_unimplemented srl %g1, 0, %g1 sethi %hi(solaris_sys_table), %l7 brz,pn %g1, solaris_sucks - mov %i0, %o0 + mov %i4, %o4 sll %g1, 2, %l4 cmp %l0, 1 bne,pn %icc, solaris_reg -1: mov %i1, %o1 +1: srl %i0, 0, %o0 lduw [%l7 + %l4], %l7 - mov %i2, %o2 + srl %i1, 0, %o1 ldx [%g6 + AOFF_task_flags], %l5 -! st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] cmp %l7, NR_SYSCALLS bleu,a,pn %xcc, linux_syscall_for_solaris sethi %hi(sys_call_table32), %l6 andcc %l7, 1, %g0 bne,a,pn %icc, 10f add %sp, STACK_BIAS + REGWIN_SZ, %o0 -10: mov %i3, %o3 - mov %i4, %o4 +10: srl %i2, 0, %o2 + mov %i5, %o5 andn %l7, 3, %l7 andcc %l5, 0x20, %g0 bne,pn %icc, solaris_syscall_trace mov %i0, %l5 2: call %l7 - mov %i5, %o5 + srl %i3, 0, %o3 ret_from_solaris: -#ifdef DEBUG_SOLARIS - call exit_printk - mov %o0, %l0 - mov %l0, %o0 -#endif stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ldx [%g6 + AOFF_task_flags], %l6 sra %o0, 0, %o0 diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c --- v2.1.78/linux/arch/sparc64/solaris/fs.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/fs.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: fs.c,v 1.4 1997/09/04 15:46:26 jj Exp $ +/* $Id: fs.c,v 1.6 1997/10/13 03:54:05 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -82,7 +83,7 @@ int ret; struct stat s; char *filenam; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int (*sys_newstat)(char *,struct stat *) = (int (*)(char *,struct stat *))SYS(stat); @@ -110,7 +111,7 @@ int ret; struct stat s; char *filenam; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int (*sys_newlstat)(char *,struct stat *) = (int (*)(char *,struct stat *))SYS(lstat); @@ -136,7 +137,7 @@ { int ret; struct stat s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int (*sys_newfstat)(unsigned,struct stat *) = (int (*)(unsigned,struct stat *))SYS(fstat); @@ -187,7 +188,7 @@ { int ret; struct statfs s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int (*sys_statfs)(const char *,struct statfs *) = (int (*)(const char *,struct statfs *))SYS(statfs); struct sol_statfs *ss = (struct sol_statfs *)A(buf); @@ -229,7 +230,7 @@ { int ret; struct statfs s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int (*sys_fstatfs)(unsigned,struct statfs *) = (int (*)(unsigned,struct statfs *))SYS(fstatfs); struct sol_statfs *ss = (struct sol_statfs *)A(buf); @@ -276,7 +277,7 @@ static int report_statvfs(struct inode *inode, u32 buf) { struct statfs s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int error; struct sol_statvfs *ss = (struct sol_statvfs *)A(buf); @@ -418,7 +419,7 @@ case SOL_F_SETLKW: { struct flock f; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); switch (cmd) { case SOL_F_GETLK: cmd = F_GETLK; break; @@ -515,16 +516,7 @@ newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } - if (inode->i_sb && inode->i_sb->dq_op) { - inode->i_sb->dq_op->initialize(inode, -1); - error = -EDQUOT; - if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) - goto out; - error = notify_change(inode, &newattrs); - if (error) - inode->i_sb->dq_op->transfer(inode, &newattrs, 1); - } else - error = notify_change(inode, &newattrs); + DQUOT_TRANSFER(inode, newattrs); out: return error; } @@ -690,7 +682,7 @@ int (*sys_llseek)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int) = (int (*)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int))SYS(_llseek); int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); loff_t retval; set_fs(KERNEL_DS); diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/ioctl.c linux/arch/sparc64/solaris/ioctl.c --- v2.1.78/linux/arch/sparc64/solaris/ioctl.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/ioctl.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: ioctl.c,v 1.2 1997/09/04 00:59:22 davem Exp $ +/* $Id: ioctl.c,v 1.4 1997/09/18 10:38:24 rth Exp $ * ioctl.c: Solaris ioctl emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,9 @@ case B460800: baud = 6; break; case B614400: baud = 7; break; case B921600: baud = 8; break; - /* case B1843200: baud = 9; break; */ +#if 0 + case B1843200: baud = 9; break; +#endif } cflag |= 0x200000 | baud; } @@ -120,7 +123,7 @@ { int ret; struct solaris_termio s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); if (copy_from_user (&s, (struct solaris_termio *)A(arg), sizeof(struct solaris_termio))) return -EFAULT; @@ -135,7 +138,7 @@ { int ret; struct solaris_termios s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_ioctl(fd, cmd, (unsigned long)&s); @@ -156,7 +159,7 @@ { int ret; struct solaris_termios s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_ioctl(fd, TCGETS, (unsigned long)&s); @@ -232,7 +235,7 @@ { char *p; int ret; - unsigned long old_fs; + mm_segment_t old_fs; struct strioctl si; switch (cmd & 0xff) { @@ -275,6 +278,117 @@ } return -ENOSYS; } + +static inline int solaris_s(unsigned int fd, unsigned int cmd, u32 arg) +{ + switch (cmd & 0xff) { + case 0: /* SIOCSHIWAT */ + case 2: /* SIOCSLOWAT */ + return 0; /* We don't support them */ + case 1: /* SIOCGHIWAT */ + case 3: /* SIOCGLOWAT */ + put_user_ret (0, (u32 *)A(arg), -EFAULT); + return 0; /* Lie */ + case 7: /* SIOCATMARK */ + return sys_ioctl(fd, SIOCATMARK, arg); + case 8: /* SIOCSPGRP */ + return sys_ioctl(fd, SIOCSPGRP, arg); + case 9: /* SIOCGPGRP */ + return sys_ioctl(fd, SIOCGPGRP, arg); + } + return -ENOSYS; +} + +static inline int solaris_r(unsigned int fd, unsigned int cmd, u32 arg) +{ + switch (cmd & 0xff) { + case 10: /* SIOCADDRT */ + return sys32_ioctl(fd, SIOCADDRT, arg); + case 11: /* SIOCDELRT */ + return sys32_ioctl(fd, SIOCDELRT, arg); + } + return -ENOSYS; +} + +static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg) +{ + switch (cmd & 0xff) { + case 12: /* SIOCSIFADDR */ + return sys32_ioctl(fd, SIOCSIFADDR, arg); + case 13: /* SIOCGIFADDR */ + return sys32_ioctl(fd, SIOCGIFADDR, arg); + case 14: /* SIOCSIFDSTADDR */ + return sys32_ioctl(fd, SIOCSIFDSTADDR, arg); + case 15: /* SIOCGIFDSTADDR */ + return sys32_ioctl(fd, SIOCGIFDSTADDR, arg); + case 16: /* SIOCSIFFLAGS */ + return sys32_ioctl(fd, SIOCSIFFLAGS, arg); + case 17: /* SIOCGIFFLAGS */ + return sys32_ioctl(fd, SIOCGIFFLAGS, arg); + case 18: /* SIOCSIFMEM */ + return sys32_ioctl(fd, SIOCSIFMEM, arg); + case 19: /* SIOCGIFMEM */ + return sys32_ioctl(fd, SIOCGIFMEM, arg); + case 20: /* SIOCGIFCONF */ + return sys32_ioctl(fd, SIOCGIFCONF, arg); + case 21: /* SIOCSIFMTU */ + return sys32_ioctl(fd, SIOCSIFMTU, arg); + case 22: /* SIOCGIFMTU */ + return sys32_ioctl(fd, SIOCGIFMTU, arg); + case 23: /* SIOCGIFBRDADDR */ + return sys32_ioctl(fd, SIOCGIFBRDADDR, arg); + case 24: /* SIOCSIFBRDADDR */ + return sys32_ioctl(fd, SIOCSIFBRDADDR, arg); + case 25: /* SIOCGIFNETMASK */ + return sys32_ioctl(fd, SIOCGIFNETMASK, arg); + case 26: /* SIOCSIFNETMASK */ + return sys32_ioctl(fd, SIOCSIFNETMASK, arg); + case 27: /* SIOCGIFMETRIC */ + return sys32_ioctl(fd, SIOCGIFMETRIC, arg); + case 28: /* SIOCSIFMETRIC */ + return sys32_ioctl(fd, SIOCSIFMETRIC, arg); + case 30: /* SIOCSARP */ + return sys32_ioctl(fd, SIOCSARP, arg); + case 31: /* SIOCGARP */ + return sys32_ioctl(fd, SIOCGARP, arg); + case 32: /* SIOCDARP */ + return sys32_ioctl(fd, SIOCDARP, arg); + case 52: /* SIOCGETNAME */ + case 53: /* SIOCGETPEER */ + { + struct sockaddr uaddr; + int uaddr_len = sizeof(struct sockaddr), ret; + long args[3]; + mm_segment_t old_fs = get_fs(); + int (*sys_socketcall)(int, unsigned long *) = + (int (*)(int, unsigned long *))SYS(socketcall); + + args[0] = fd; args[1] = (long)&uaddr; args[2] = (long)&uaddr_len; + set_fs(KERNEL_DS); + ret = sys_socketcall(((cmd & 0xff) == 52) ? SYS_GETSOCKNAME : SYS_GETPEERNAME, + args); + set_fs(old_fs); + if (ret >= 0) + copy_to_user_ret((char *)A(arg), &uaddr, uaddr_len, -EFAULT); + return ret; + } +#if 0 + case 86: /* SIOCSOCKSYS */ + return socksys_syscall(fd, arg); +#endif + case 87: /* SIOCGIFNUM */ + { + struct device *d; + int i = 0; + + for (d = dev_base; d; d = d->next) i++; + put_user_ret (i, (int *)A(arg), -EFAULT); + return 0; + } + } + return -ENOSYS; +} + /* }}} */ asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg) @@ -288,15 +402,13 @@ filp = current->files->fd[fd]; if(!filp) goto out; - if (!filp->f_op || !filp->f_op->ioctl) { - error = sys_ioctl (fd, cmd, (unsigned long)arg); - goto out; - } - error = -EFAULT; switch ((cmd >> 8) & 0xff) { case 'S': error = solaris_S(fd, cmd, arg); break; case 'T': error = solaris_T(fd, cmd, arg); break; + case 'i': error = solaris_i(fd, cmd, arg); break; + case 'r': error = solaris_r(fd, cmd, arg); break; + case 's': error = solaris_s(fd, cmd, arg); break; case 't': error = solaris_t(fd, cmd, arg); break; default: error = -ENOSYS; diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/ipc.c linux/arch/sparc64/solaris/ipc.c --- v2.1.78/linux/arch/sparc64/solaris/ipc.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/ipc.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: ipc.c,v 1.1 1997/09/03 12:29:29 jj Exp $ +/* $Id: ipc.c,v 1.2 1997/09/18 10:38:27 rth Exp $ * ipc.c: Solaris IPC emulation * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -53,7 +53,7 @@ { int (*sys_ipc)(unsigned,int,int,unsigned long,void *,long) = (int (*)(unsigned,int,int,unsigned long,void *,long))SYS(ipc); - unsigned long old_fs; + mm_segment_t old_fs; unsigned long raddr; int ret; diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c --- v2.1.78/linux/arch/sparc64/solaris/misc.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/misc.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.4 1997/09/04 14:57:31 jj Exp $ +/* $Id: misc.c,v 1.6 1997/12/14 23:40:15 ecd Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -283,7 +283,7 @@ linux_cpus[smp_processor_id()].prom_node, "clock-frequency", 167000000); #ifdef __SMP__ - case SOLARIS_CONFIG_NPROC_CONF: return NCPUS; + case SOLARIS_CONFIG_NPROC_CONF: return NR_CPUS; case SOLARIS_CONFIG_NPROC_ONLN: return smp_num_cpus; #else case SOLARIS_CONFIG_NPROC_CONF: return 1; @@ -446,18 +446,3 @@ } #endif -#ifdef DEBUG_SOLARIS -void entry_printk(int sysno, struct pt_regs *regs) -{ - printk ("Entering %d\n", sysno); - printk ("%08x %08x %08x %08x\n", (int)regs->u_regs[UREG_I0], - (int)regs->u_regs[UREG_I1], - (int)regs->u_regs[UREG_I2], - (int)regs->u_regs[UREG_I3]); -} - -void exit_printk(unsigned long ret) -{ - printk ("Returning %016lx\n", ret); -} -#endif diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/signal.c linux/arch/sparc64/solaris/signal.c --- v2.1.78/linux/arch/sparc64/solaris/signal.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/signal.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.2 1997/09/03 12:29:19 jj Exp $ +/* $Id: signal.c,v 1.5 1997/12/15 15:04:59 jj Exp $ * signal.c: Signal emulation for Solaris * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -74,11 +74,11 @@ { struct sigaction sa, old; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) = (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction); - sa.sa_mask = 0L; + sigemptyset(&sa.sa_mask); sa.sa_restorer = NULL; sa.sa_handler = (__sighandler_t)A(arg); sa.sa_flags = 0; @@ -99,13 +99,14 @@ { if (arg != 2) /* HOLD */ { spin_lock_irq(¤t->sigmask_lock); - current->blocked &= ~_S(sig); + sigdelsetmask(¤t->blocked, _S(sig)); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); return sig_handler (sig, arg, 0); } else { - sigset_t n = _S(sig) & _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); - current->blocked |= n; + sigaddsetmask(¤t->blocked, (_S(sig) & ~_BLOCKABLE)); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); return 0; } @@ -119,7 +120,8 @@ static inline long solaris_sigrelse(int sig) { spin_lock_irq(¤t->sigmask_lock); - current->blocked &= ~_S(sig); + sigdelsetmask(¤t->blocked, _S(sig)); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); return 0; } @@ -162,14 +164,14 @@ u32 x; int sig; - *q = 0L; + sigemptyset(q); x = p[0]; for (i = 1; i <= SOLARIS_NSIGNALS; i++) { if (x & 1) { sig = solaris_to_linux_signals[i]; if (sig == -1) return -EINVAL; - *q |= 1L << (sig - 1); + sigaddsetmask(q, (1L << (sig - 1))); } x >>= 1; if (i == 32) @@ -181,14 +183,12 @@ static inline int mapout(sigset_t *q, u32 *p) { int i; - sigset_t x; int sig; p[0] = 0; p[1] = 0; - x = *q; - for (i = 1; i <= 32; i++, x >>= 1) { - if (x & 1) { + for (i = 1; i <= 32; i++) { + if (sigismember(q, sigmask(i))) { sig = linux_to_solaris_signals[i]; if (sig == -1) return -EINVAL; @@ -199,13 +199,12 @@ } } return 0; - } asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out) { sigset_t in_s, *ins, out_s, *outs; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int ret; int (*sys_sigprocmask)(int,sigset_t *,sigset_t *) = (int (*)(int,sigset_t *,sigset_t *))SYS(sigprocmask); @@ -243,7 +242,7 @@ if (copy_from_user (tmp, (sol_sigset_t *)A(mask), 2*sizeof(u32))) return -EFAULT; if (mapin (tmp, &s)) return -EINVAL; - return (long)s; + return (long)s.sig[0]; } struct sol_sigaction { @@ -258,7 +257,7 @@ u32 tmp, tmp2[4]; struct sigaction s, s2; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) = (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction); @@ -311,12 +310,13 @@ u32 tmp[4]; switch (which) { case 1: /* sigpending */ - lock_kernel(); - s = current->blocked & current->signal; - unlock_kernel(); + spin_lock_irq(¤t->sigmask_lock); + sigandsets(&s, ¤t->blocked, ¤t->signal); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); break; case 2: /* sigfillset - I just set signals which have linux equivalents */ - s = 0x7fffffff; + sigfillset(&s); break; default: return -EINVAL; } diff -u --recursive --new-file v2.1.78/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c --- v2.1.78/linux/arch/sparc64/solaris/socksys.c Thu Sep 4 17:07:30 1997 +++ linux/arch/sparc64/solaris/socksys.c Mon Jan 12 15:15:44 1998 @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.1 1997/09/03 12:29:27 jj Exp $ +/* $Id: socksys.c,v 1.2 1997/09/08 11:29:38 jj Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ static int socksys_open(struct inode * inode, struct file * filp) { int family, type, protocol, fd; + struct dentry *dentry; int (*sys_socket)(int,int,int) = (int (*)(int,int,int))SUNOS(97); @@ -68,6 +70,17 @@ } fd = sys_socket(family, type, protocol); if (fd < 0) return fd; + dentry = filp->f_dentry; + filp->f_dentry = current->files->fd[fd]->f_dentry; + filp->f_dentry->d_inode->i_rdev = inode->i_rdev; + filp->f_dentry->d_inode->i_flock = inode->i_flock; + filp->f_dentry->d_inode->u.socket_i.file = filp; + filp->f_op = &socksys_file_ops; + dput(dentry); + FD_CLR(fd, ¤t->files->close_on_exec); + FD_CLR(fd, ¤t->files->open_fds); + put_filp(current->files->fd[fd]); + current->files->fd[fd] = NULL; return 0; } diff -u --recursive --new-file v2.1.78/linux/drivers/block/README.fd linux/drivers/block/README.fd --- v2.1.78/linux/drivers/block/README.fd Tue Nov 18 17:22:07 1997 +++ linux/drivers/block/README.fd Mon Jan 12 14:57:50 1998 @@ -85,16 +85,20 @@ This is needed on HP Omnibooks, which don't have a workable DMA channel for the floppy driver. This option is also useful if you frequently get "Unable to allocate DMA memory" messages. - Indeed, dma memory needs to be continuous in physical, and is - thus harder to find, whereas non-dma buffers may be allocated - in virtual memory. However, I advise against this if you have - an FDC without a FIFO (8272A or 82072). 82072A and later are - OK. You also need at least a 486 to use nodma. + Indeed, dma memory needs to be continuous in physical memory, + and is thus harder to find, whereas non-dma buffers may be + allocated in virtual memory. However, I advise against this if + you have an FDC without a FIFO (8272A or 82072). 82072A and + later are OK). You also need at least a 486 to use nodma. If you use nodma mode, I suggest you also set the FIFO threshold to 10 or lower, in order to limit the number of data transfer interrupts. - - floppy=dma + + If you have a FIFO-able FDC, the floppy driver automatically + falls back on non DMA mode if no DMA-able memory can be found. + If you want to avoid this, explicitely ask for 'yesdma'. + + floppy=yesdma Tells the floppy driver that a workable DMA channel is available (the default). diff -u --recursive --new-file v2.1.78/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.78/linux/drivers/block/floppy.c Tue Jan 6 09:37:33 1998 +++ linux/drivers/block/floppy.c Mon Jan 12 14:57:50 1998 @@ -148,11 +148,32 @@ #include #include -static int use_virtual_dma=0; /* virtual DMA for Intel */ +static int can_use_virtual_dma=2; +/* ======= + * can use virtual DMA: + * 0 = use of virtual DMA disallowed by config + * 1 = use of virtual DMA prescribed by config + * 2 = no virtual DMA preference configured. By default try hard DMA, + * but fall back on virtual DMA when not enough memory available + */ + +static int use_virtual_dma=0; +/* ======= + * use virtual DMA + * 0 using hard DMA + * 1 using virtual DMA + * This variable is set to virtual when a DMA mem problem arises, and + * reset back in floppy_grab_irq_and_dma. + * It is not safe to reset it in other circumstances, because the floppy + * driver may have several buffers in use at once, and we do currently not + * record each buffers capabilities + */ + static unsigned short virtual_dma_port=0x3f0; void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs); static int set_dor(int fdc, char mask, char data); static inline int __get_order(unsigned long size); +#define K_64 0x10000 /* 64KB */ #include @@ -189,6 +210,20 @@ #define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size)) #endif +static inline void fallback_on_nodma_alloc(char **addr, size_t l) +{ +#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA + if(*addr) + return; /* we have the memory */ + if(can_use_virtual_dma != 2) + return; /* no fallback allowed */ + printk("DMA memory shortage. Temporarily falling back on virtual DMA\n"); + *addr = (char *) nodma_mem_alloc(l); +#else + return; +#endif +} + /* End dma memory related stuff */ static unsigned int fake_change = 0; @@ -258,7 +293,6 @@ */ #define MAX_DISK_SIZE 4 /* 3984*/ -#define K_64 0x10000 /* 64KB */ /* * globals used by 'result()' @@ -1015,17 +1049,20 @@ FDCS->reset=1; return; } - if (CROSS_64KB(raw_cmd->kernel_data, raw_cmd->length)) { - printk("DMA crossing 64-K boundary %p-%p\n", - raw_cmd->kernel_data, - raw_cmd->kernel_data + raw_cmd->length); +#endif + INT_OFF; + fd_disable_dma(); +#ifdef fd_dma_setup + if(fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length, + (raw_cmd->flags & FD_RAW_READ)? + DMA_MODE_READ : DMA_MODE_WRITE, + FDCS->address) < 0) { + INT_ON; cont->done(0); FDCS->reset=1; return; } -#endif - INT_OFF; - fd_disable_dma(); +#else fd_clear_dma_ff(); fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length); fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)? @@ -1034,6 +1071,7 @@ fd_set_dma_count(raw_cmd->length); virtual_dma_port = FDCS->address; fd_enable_dma(); +#endif INT_ON; floppy_disable_hlt(); } @@ -1844,19 +1882,29 @@ DPRINT("calling disk change from floppy_ready\n"); } #endif - if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) && disk_change(current_drive) && !DP->select_delay) twaddle(); /* this clears the dcl on certain drive/controller * combinations */ +#ifdef fd_chose_dma_mode + if ((raw_cmd->flags & FD_RAW_READ) || + (raw_cmd->flags & FD_RAW_WRITE)) + fd_chose_dma_mode(raw_cmd->kernel_data, + raw_cmd->length); +#endif + if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){ perpendicular_mode(); fdc_specify(); /* must be done here because of hut, hlt ... */ seek_floppy(); - } else + } else { + if ((raw_cmd->flags & FD_RAW_READ) || + (raw_cmd->flags & FD_RAW_WRITE)) + fdc_specify(); setup_rw_floppy(); + } } static void floppy_start(void) @@ -2403,6 +2451,7 @@ #endif } +#if 0 static inline int check_dma_crossing(char *start, unsigned long length, char *message) { @@ -2413,6 +2462,7 @@ } else return 0; } +#endif /* * Formulate a read/write request. @@ -2571,9 +2621,9 @@ indirect, direct, sector_t); return 0; } - check_dma_crossing(raw_cmd->kernel_data, +/* check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, - "end of make_raw_request [1]"); + "end of make_raw_request [1]");*/ return 2; } } @@ -2619,8 +2669,8 @@ raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1; raw_cmd->length <<= 9; #ifdef FLOPPY_SANITY_CHECK - check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, - "end of make_raw_request"); + /*check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, + "end of make_raw_request");*/ if ((raw_cmd->length < current_count_sectors << 9) || (raw_cmd->kernel_data != CURRENT->buffer && CT(COMMAND) == FD_WRITE && @@ -3008,6 +3058,8 @@ if (ptr->length <= 0) return -EINVAL; ptr->kernel_data =(char*)fd_dma_mem_alloc(ptr->length); + fallback_on_nodma_alloc(&ptr->kernel_data, + ptr->length); if (!ptr->kernel_data) return -ENOMEM; ptr->buffer_length = ptr->length; @@ -3578,18 +3630,22 @@ try = 32; /* Only 24 actually useful */ tmp=(char *)fd_dma_mem_alloc(1024 * try); - if (!tmp) { + if (!tmp && !floppy_track_buffer) { try >>= 1; /* buffer only one side */ INFBOUND(try, 16); tmp= (char *)fd_dma_mem_alloc(1024*try); } - if (!tmp) { + if(!tmp && !floppy_track_buffer) { + fallback_on_nodma_alloc(&tmp, 2048 * try); + } + if (!tmp && !floppy_track_buffer) { DPRINT("Unable to allocate DMA memory\n"); RETERR(ENXIO); } - if (floppy_track_buffer) - fd_dma_mem_free((unsigned long)tmp,try*1024); - else { + if (floppy_track_buffer) { + if(tmp) + fd_dma_mem_free((unsigned long)tmp,try*1024); + } else { buffer_min = buffer_max = -1; floppy_track_buffer = tmp; max_buffer_sectors = try; @@ -3886,9 +3942,9 @@ { "silent_dcl_clear", floppy_set_flags, 0, 1, FD_SILENT_DCL_CLEAR }, { "debug", floppy_set_flags, 0, 1, FD_DEBUG }, - { "nodma", 0, &use_virtual_dma, 1, 0 }, - { "omnibook", 0, &use_virtual_dma, 1, 0 }, - { "dma", 0, &use_virtual_dma, 0, 0 }, + { "nodma", 0, &can_use_virtual_dma, 1, 0 }, + { "omnibook", 0, &can_use_virtual_dma, 1, 0 }, + { "yesdma", 0, &can_use_virtual_dma, 0, 0 }, { "fifo_depth", 0, &fifo_depth, 0xa, 0 }, { "nofifo", 0, &no_fifo, 0x20, 0 }, @@ -3937,6 +3993,7 @@ static int have_no_fdc= -EIO; + __initfunc(int floppy_init(void)) { int i,unit,drive; @@ -3972,6 +4029,7 @@ #endif } + use_virtual_dma = can_use_virtual_dma & 1; fdc_state[0].address = FDC1; if (fdc_state[0].address == -1) { unregister_blkdev(MAJOR_NR,"fd"); @@ -4017,6 +4075,8 @@ FDCS->address = -1; continue; } + if(can_use_virtual_dma == 2 && FDCS->version < FDC_82072A) + can_use_virtual_dma = 0; have_no_fdc = 0; /* Not all FDCs seem to be able to handle the version command @@ -4032,7 +4092,7 @@ initialising=0; if (have_no_fdc) { DPRINT("no floppy controllers found\n"); - unregister_blkdev(MAJOR_NR,"fd"); + unregister_blkdev(MAJOR_NR,"fd"); } return have_no_fdc; } @@ -4063,6 +4123,7 @@ usage_count--; return -1; } + for (fdc=0; fdc< N_FDC; fdc++){ if (FDCS->address != -1){ if (check_region(FDCS->address, 6) < 0 || diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.1.78/linux/drivers/block/ide-cd.c Tue Jan 6 09:37:33 1998 +++ linux/drivers/block/ide-cd.c Sat Jan 10 10:42:55 1998 @@ -2772,6 +2772,17 @@ return nslots; } +static void ide_cdrom_add_settings(ide_drive_t *drive) +{ + int major = HWIF(drive)->major; + int minor = drive->select.b.unit << PARTN_BITS; + + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); +} + static int ide_cdrom_setup (ide_drive_t *drive) { @@ -2884,6 +2895,7 @@ info->devinfo.handle = NULL; return 1; } + ide_cdrom_add_settings(drive); return 0; } @@ -2942,13 +2954,6 @@ return 0; } -int ide_cdrom_init (void); -static ide_module_t ide_cdrom_module = { - IDE_DRIVER_MODULE, - ide_cdrom_init, - NULL -}; - static ide_driver_t ide_cdrom_driver = { "ide-cdrom", /* name */ IDECD_VERSION, /* version */ @@ -2969,6 +2974,13 @@ NULL /* proc */ }; +int ide_cdrom_init (void); +static ide_module_t ide_cdrom_module = { + IDE_DRIVER_MODULE, + ide_cdrom_init, + &ide_cdrom_driver, + NULL +}; #ifdef MODULE int init_module (void) @@ -2981,7 +2993,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_cdrom, &ide_cdrom_driver, failed)) != NULL) + while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL) if (ide_cdrom_cleanup (drive)) { printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; @@ -2997,7 +3009,7 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_cdrom, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk ("%s: Can't allocate a cdrom structure\n", drive->name); diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.1.78/linux/drivers/block/ide-disk.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-disk.c Sat Jan 10 10:42:55 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.03 Nov 30, 1997 + * linux/drivers/block/ide-disk.c Version 1.04 Jan 7, 1998 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -13,11 +13,12 @@ * Version 1.00 move disk only code from ide.c to ide-disk.c * support optional byte-swapping of all data * Version 1.01 fix previous byte-swapping code - * Verions 1.02 remove ", LBA" from drive identification msgs - * Verions 1.03 fix display of id->buf_size for big-endian + * Version 1.02 remove ", LBA" from drive identification msgs + * Version 1.03 fix display of id->buf_size for big-endian + * Version 1.04 add /proc configurable settings and S.M.A.R.T support */ -#define IDEDISK_VERSION "1.03" +#define IDEDISK_VERSION "1.04" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -372,17 +373,13 @@ { MOD_INC_USE_COUNT; if (drive->removable && drive->usage == 1) { - byte door_lock[] = {WIN_DOORLOCK,0,0,0}; - struct request rq; check_disk_change(inode->i_rdev); - ide_init_drive_cmd (&rq); - rq.buffer = door_lock; /* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - (void) ide_do_drive_cmd(drive, &rq, ide_wait); + (void) ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL); } return 0; } @@ -390,12 +387,8 @@ static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive) { if (drive->removable && !drive->usage) { - byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0}; - struct request rq; invalidate_buffers(inode->i_rdev); - ide_init_drive_cmd (&rq); - rq.buffer = door_unlock; - (void) ide_do_drive_cmd(drive, &rq, ide_wait); + (void) ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL); } MOD_DEC_USE_COUNT; } @@ -481,18 +474,106 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +static int smart_enable(ide_drive_t *drive) +{ + return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL); +} + +static int get_smart_values(ide_drive_t *drive, byte *buf) +{ + (void) smart_enable(drive); + return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf); +} + +static int get_smart_thresholds(ide_drive_t *drive, byte *buf) +{ + (void) smart_enable(drive); + return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf); +} + +static int proc_idedisk_read_smart_thresholds + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *)data; + int len = 0, i = 0; + + if (!get_smart_thresholds(drive, page)) { + unsigned short *val = ((unsigned short *)page) + 2; + char *out = ((char *)val) + (SECTOR_WORDS * 4); + page = out; + do { + out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); + val += 1; + } while (i < (SECTOR_WORDS * 2)); + len = out - page; + } + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_idedisk_read_smart_values + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *)data; + int len = 0, i = 0; + + if (!get_smart_values(drive, page)) { + unsigned short *val = ((unsigned short *)page) + 2; + char *out = ((char *)val) + (SECTOR_WORDS * 4); + page = out; + do { + out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); + val += 1; + } while (i < (SECTOR_WORDS * 2)); + len = out - page; + } + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + static ide_proc_entry_t idedisk_proc[] = { { "cache", proc_idedisk_read_cache, NULL }, { "geometry", proc_ide_read_geometry, NULL }, + { "smart_values", proc_idedisk_read_smart_values, NULL }, + { "smart_thresholds", proc_idedisk_read_smart_thresholds, NULL }, { NULL, NULL, NULL } }; -int idedisk_init (void); -static ide_module_t idedisk_module = { - IDE_DRIVER_MODULE, - idedisk_init, - NULL -}; +static int set_multcount(ide_drive_t *drive, int arg) +{ + struct request rq; + + if (drive->special.b.set_multmode) + return -EBUSY; + ide_init_drive_cmd (&rq); + drive->mult_req = arg; + drive->special.b.set_multmode = 1; + (void) ide_do_drive_cmd (drive, &rq, ide_wait); + return (drive->mult_count == arg) ? 0 : -EIO; +} + +static int set_nowerr(ide_drive_t *drive, int arg) +{ + drive->nowerr = arg; + drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; + return 0; +} + +static void idedisk_add_settings(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + int major = HWIF(drive)->major; + int minor = drive->select.b.unit << PARTN_BITS; + + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); + ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); + ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); + ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 2, &drive->mult_count, set_multcount); + ide_add_setting(drive, "nowerr", SETTING_RW, HDIO_GET_NOWERR, HDIO_SET_NOWERR, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr); + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + +} /* * IDE subdriver functions, registered with ide.c @@ -517,6 +598,14 @@ idedisk_proc /* proc */ }; +int idedisk_init (void); +static ide_module_t idedisk_module = { + IDE_DRIVER_MODULE, + idedisk_init, + &idedisk_driver, + NULL +}; + static int idedisk_cleanup (ide_drive_t *drive) { return ide_unregister_subdriver(drive); @@ -527,6 +616,8 @@ struct hd_driveid *id = drive->id; unsigned long capacity, check; + idedisk_add_settings(drive); + if (id == NULL) return; @@ -615,7 +706,7 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_disk, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) { /* SunDisk drives: ignore "second" drive; can mess up non-Sun systems! FIXME */ struct hd_driveid *id = drive->id; @@ -650,7 +741,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_disk, &idedisk_driver, failed)) != NULL) + while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) if (idedisk_cleanup (drive)) { printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); failed++; diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.1.78/linux/drivers/block/ide-floppy.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-floppy.c Sat Jan 10 10:42:55 1998 @@ -1327,6 +1327,20 @@ return 0; } +static void idefloppy_add_settings(ide_drive_t *drive) +{ + int major = HWIF(drive)->major; + int minor = drive->select.b.unit << PARTN_BITS; + + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); + ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + +} + /* * Driver initialization. */ @@ -1351,6 +1365,7 @@ } (void) idefloppy_get_capacity (drive); + idefloppy_add_settings(drive); } static int idefloppy_cleanup (ide_drive_t *drive) @@ -1369,13 +1384,6 @@ { NULL, NULL, NULL } }; -int idefloppy_init (void); -static ide_module_t idefloppy_module = { - IDE_DRIVER_MODULE, - idefloppy_init, - NULL -}; - /* * IDE subdriver functions, registered with ide.c */ @@ -1399,6 +1407,14 @@ idefloppy_proc /* proc */ }; +int idefloppy_init (void); +static ide_module_t idefloppy_module = { + IDE_DRIVER_MODULE, + idefloppy_init, + &idefloppy_driver, + NULL +}; + /* * idefloppy_init will register the driver for each floppy. */ @@ -1409,7 +1425,7 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_floppy, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) { if (!idefloppy_identify_device (drive, drive->id)) { printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); continue; @@ -1442,7 +1458,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_floppy, &idefloppy_driver, failed)) != NULL) + while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) if (idefloppy_cleanup (drive)) { printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.1.78/linux/drivers/block/ide-probe.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-probe.c Sat Jan 10 10:42:55 1998 @@ -624,6 +624,11 @@ for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ; hwif->gd = *gdp = gd; /* link onto tail of list */ + + for (unit = 0; unit < units; ++unit) { + if (hwif->drives[unit].present) + ide_add_generic_settings(hwif->drives + unit); + } } static int hwif_init (ide_hwif_t *hwif) diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.1.78/linux/drivers/block/ide-proc.c Fri Jan 2 14:37:01 1998 +++ linux/drivers/block/ide-proc.c Sat Jan 10 10:42:55 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-proc.c Version 1.02 December 31, 1997 + * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 * * Copyright (C) 1997-1998 Mark Lord */ @@ -38,8 +38,15 @@ * If there is an error *anywhere* in the string of registers/data * then *none* of the writes will be performed. * - * Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY - * (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the + * Drive/Driver settings can be retrieved by reading the drive's + * "settings" files. e.g. "cat /proc/ide0/hda/settings" + * To write a new value "val" into a specific setting "name", use: + * echo "name:val" >/proc/ide/ide0/hda/settings + * + * Also useful, "cat /proc/ide0/hda/[identify, smart_values, + * smart_thresholds, capabilities]" will issue an IDENTIFY / + * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS / + * SENSE CAPABILITIES command to /dev/hda, and then dump out the * returned data as 256 16-bit words. The "hdparm" utility will * be updated someday soon to use this mechanism. * @@ -80,6 +87,16 @@ return digit; } +static int ide_getdigit(char c) +{ + int digit; + if (isdigit(c)) + digit = c - '0'; + else + digit = -1; + return digit; +} + static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg) { char errbuf[16]; @@ -237,6 +254,24 @@ return xx_xx_parse_error(start, startn, msg); } +static int proc_ide_read_drivers + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *out = page; + int len; + ide_module_t *p = ide_modules; + ide_driver_t *driver; + + while (p) { + driver = (ide_driver_t *) p->info; + if (p->type == IDE_DRIVER_MODULE && driver) + out += sprintf(out, "%s version %s\n", driver->name, driver->version); + p = p->next; + } + len = out - page; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + static int proc_ide_read_config (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -325,22 +360,9 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_get_identify (ide_drive_t *drive, byte *buf) +static int proc_ide_get_identify(ide_drive_t *drive, byte *buf) { - struct request rq; - byte *end; - - ide_init_drive_cmd(&rq); - rq.buffer = buf; - *buf++ = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY; - *buf++ = 0; - *buf++ = 0; - *buf++ = 1; - end = buf + (SECTOR_WORDS * 4); - while (buf != end) - *buf++ = 0; /* pre-zero it, in case identify fails */ - (void) ide_do_drive_cmd(drive, &rq, ide_wait); - return 0; + return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf); } static int proc_ide_read_identify @@ -366,25 +388,130 @@ (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *) data; - int major = HWIF(drive)->major; - int minor = drive->select.b.unit << PARTN_BITS; + ide_settings_t *setting = (ide_settings_t *) drive->settings; char *out = page; - int len; + int len, rc, mul_factor, div_factor; - out += sprintf(out,"multcount %i\n", drive->mult_count); - out += sprintf(out,"io_32bit %i\n", drive->io_32bit); - out += sprintf(out,"unmaskirq %i\n", drive->unmask); - out += sprintf(out,"using_dma %i\n", drive->using_dma); - out += sprintf(out,"nowerr %i\n", drive->bad_wstat == BAD_R_STAT); - out += sprintf(out,"keepsettings %i\n", drive->keep_settings); - out += sprintf(out,"nice %i/%i/%i\n", drive->nice0, drive->nice1, drive->nice2); - out += sprintf(out,"dsc_overlap %i\n", drive->dsc_overlap); - out += sprintf(out,"max_sectors %i\n", max_sectors[major][minor]); - out += sprintf(out,"readahead %i\n", max_readahead[major][minor] / 1024); + out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); + out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); + while(setting) { + mul_factor = setting->mul_factor; + div_factor = setting->div_factor; + out += sprintf(out, "%-24s", setting->name); + if ((rc = ide_read_setting(drive, setting)) >= 0) + out += sprintf(out, "%-16d", rc * mul_factor / div_factor); + else + out += sprintf(out, "%-16s", "write-only"); + out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); + if (setting->rw & SETTING_READ) + out += sprintf(out, "r"); + if (setting->rw & SETTING_WRITE) + out += sprintf(out, "w"); + out += sprintf(out, "\n"); + setting = setting->next; + } len = out - page; PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +#define MAX_LEN 30 + +static int proc_ide_write_settings + (struct file *file, const char *buffer, unsigned long count, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + ide_hwif_t *hwif = HWIF(drive); + char name[MAX_LEN + 1]; + int for_real = 0, len; + unsigned long n, flags; + const char *start = NULL; + ide_settings_t *setting; + + if (!suser()) + return -EACCES; + + /* + * Skip over leading whitespace + */ + while (count && isspace(*buffer)) { + --count; + ++buffer; + } + /* + * Do one full pass to verify all parameters, + * then do another to actually write the pci regs. + */ + save_flags(flags); + do { + const char *p; + if (for_real) { + unsigned long timeout = jiffies + (3 * HZ); + ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup); + ide_hwgroup_t *mategroup = NULL; + if (hwif->mate && hwif->mate->hwgroup) + mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); + cli(); /* ensure all PCI writes are done together */ + while (mygroup->active || (mategroup && mategroup->active)) { + restore_flags(flags); + if (0 < (signed long)(jiffies - timeout)) { + printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name); + return -EBUSY; + } + cli(); + } + } + p = buffer; + n = count; + while (n > 0) { + int d, digits; + unsigned int val = 0; + start = p; + + while (n > 0 && *p != ':') { + --n; + p++; + } + if (*p != ':') + goto parse_error; + len = IDE_MIN(p - start, MAX_LEN); + strncpy(name, start, IDE_MIN(len, MAX_LEN)); + name[len] = 0; + + if (n > 0) { + --n; + p++; + } else + goto parse_error; + + digits = 0; + while (n > 0 && (d = ide_getdigit(*p)) >= 0) { + val = (val * 10) + d; + --n; + ++p; + ++digits; + } + if (n > 0 && !isspace(*p)) + goto parse_error; + while (n > 0 && isspace(*p)) { + --n; + ++p; + } + setting = ide_find_setting_by_name(drive, name); + if (!setting) + goto parse_error; + + if (for_real) + ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); + } + } while (!for_real++); + restore_flags(flags); + return count; +parse_error: + restore_flags(flags); + printk("proc_ide_write_settings(): parse error\n"); + return -EINVAL; +} + int proc_ide_read_capacity (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -437,6 +564,18 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +static int proc_ide_write_driver + (struct file *file, const char *buffer, unsigned long count, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + + if (!suser()) + return -EACCES; + if (ide_replace_subdriver(drive, buffer)) + return -EINVAL; + return count; +} + static int proc_ide_read_media (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -461,13 +600,12 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } - static ide_proc_entry_t generic_drive_entries[] = { - { "driver", proc_ide_read_driver, NULL }, + { "driver", proc_ide_read_driver, proc_ide_write_driver }, { "identify", proc_ide_read_identify, NULL }, { "media", proc_ide_read_media, NULL }, { "model", proc_ide_read_dmodel, NULL }, - { "settings", proc_ide_read_settings, NULL }, + { "settings", proc_ide_read_settings, proc_ide_write_settings }, { NULL, NULL, NULL } }; @@ -497,9 +635,16 @@ } } -static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent) +static int proc_ide_readlink(struct proc_dir_entry *de, char *page) +{ + int n = (de->name[2] - 'a') / 2; + return sprintf(page, "ide%d/%s", n, de->name); +} + +static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent, struct proc_dir_entry *root) { int d; + struct proc_dir_entry *ent; for (d = 0; d < MAX_DRIVES; d++) { ide_drive_t *drive = &hwif->drives[d]; @@ -509,6 +654,12 @@ drive->proc = create_proc_entry(drive->name, S_IFDIR, parent); if (drive->proc) ide_add_proc_entries(drive, generic_drive_entries); + + ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, root); + if (!ent) return; + ent->data = drive; + ent->readlink_proc = proc_ide_readlink; + ent->nlink = 1; } } @@ -555,14 +706,18 @@ ent->data = hwif; ent->read_proc = proc_ide_read_type; - create_proc_ide_drives(hwif, hwif_ent); + create_proc_ide_drives(hwif, hwif_ent, parent); } } void proc_ide_init(void) { - struct proc_dir_entry *ent; - ent = create_proc_entry("ide", S_IFDIR, 0); + struct proc_dir_entry *root, *ent; + root = create_proc_entry("ide", S_IFDIR, 0); + if (!root) return; + create_proc_ide_interfaces(root); + + ent = create_proc_entry("drivers", 0, root); if (!ent) return; - create_proc_ide_interfaces(ent); + ent->read_proc = proc_ide_read_drivers; } diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.1.78/linux/drivers/block/ide-tape.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-tape.c Sat Jan 10 10:42:55 1998 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-tape.c Version 1.12 Dec 7, 1997 + * linux/drivers/block/ide-tape.c Version 1.13 Jan 2, 1998 * - * Copyright (C) 1995, 1996 Gadi Oxman + * Copyright (C) 1995 - 1998 Gadi Oxman * * This driver was constructed as a student project in the software laboratory * of the faculty of electrical engineering in the Technion - Israel's @@ -211,6 +211,7 @@ * of bytes written to the tape was not an integral * number of tape blocks. * Add support for INTERRUPT DRQ devices. + * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well: @@ -320,7 +321,7 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ -#define IDETAPE_VERSION "1.12" +#define IDETAPE_VERSION "1.13" #include #include @@ -675,7 +676,7 @@ */ int nr_stages; /* Number of currently used stages */ int nr_pending_stages; /* Number of pending stages */ - int max_stages; /* We will not allocate more than this number of stages */ + int max_stages, min_pipeline, max_pipeline; /* We will not allocate more than this number of stages */ idetape_stage_t *first_stage; /* The first stage which will be removed from the pipeline */ idetape_stage_t *active_stage; /* The currently active stage */ idetape_stage_t *next_stage; /* Will be serviced after the currently active request */ @@ -1409,12 +1410,15 @@ static void idetape_increase_max_pipeline_stages (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; + int increase = (tape->max_pipeline - tape->min_pipeline) / 10; #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_increase_max_pipeline_stages\n"); #endif /* IDETAPE_DEBUG_LOG */ - tape->max_stages = IDE_MIN (tape->max_stages + IDETAPE_INCREASE_STAGES_RATE, IDETAPE_MAX_PIPELINE_STAGES); + tape->max_stages += increase; + tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline); + tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline); } /* @@ -2520,7 +2524,7 @@ while (tape->first_stage != NULL) idetape_remove_stage_head (drive); tape->nr_pending_stages = 0; - tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + tape->max_stages = tape->min_pipeline; } /* @@ -2610,7 +2614,7 @@ * as some systems are constantly on, and the system load * can be totally different on the next backup). */ - tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + tape->max_stages = tape->min_pipeline; #if IDETAPE_DEBUG_BUGS if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) { printk (KERN_ERR "ide-tape: ide-tape pipeline bug\n"); @@ -3460,6 +3464,15 @@ capabilities->speed = ntohs (capabilities->speed); capabilities->buffer_size = ntohs (capabilities->buffer_size); + if (!capabilities->speed) { + printk("ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name); + capabilities->speed = 650; + } + if (!capabilities->max_speed) { + printk("ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name); + capabilities->max_speed = 650; + } + tape->capabilities = *capabilities; /* Save us a copy */ tape->tape_block_size = capabilities->blk512 ? 512:1024; #if IDETAPE_DEBUG_LOG @@ -3493,6 +3506,24 @@ #endif /* IDETAPE_DEBUG_LOG */ } +static void idetape_add_settings(ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + +/* + * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function + */ + ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL); + ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); + ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL); + ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); + ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL); + ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL); + ide_add_setting(drive, "stage", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL); + ide_add_setting(drive, "tdsc", SETTING_RW, -1, -1, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL); + ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); +} + /* * ide_setup is called to: * @@ -3521,7 +3552,9 @@ tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor; tape->chrdev_direction = idetape_direction_none; tape->pc = tape->pc_stack; - tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + tape->min_pipeline = IDETAPE_MIN_PIPELINE_STAGES; + tape->max_pipeline = IDETAPE_MAX_PIPELINE_STAGES; + tape->max_stages = tape->min_pipeline; *((unsigned short *) &gcw) = drive->id->config; if (gcw.drq_type == 1) set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags); @@ -3577,6 +3610,8 @@ drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size, tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024, tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":""); + + idetape_add_settings(drive); } static int idetape_cleanup (ide_drive_t *drive) @@ -3605,18 +3640,6 @@ return 0; } -static int proc_idetape_read_buffer - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->capabilities.buffer_size / 2); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static int proc_idetape_read_name (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -3629,72 +3652,11 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_idetape_read_pipeline - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->max_stages * tape->stage_size / 1024); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - -static int proc_idetape_read_speed - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->capabilities.speed); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - -static int proc_idetape_read_stage - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->stage_size / 1024); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - -static int proc_idetape_read_tdsc - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%lu\n", tape->best_dsc_rw_frequency * 1000 / HZ); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static ide_proc_entry_t idetape_proc[] = { - { "buffer", proc_idetape_read_buffer, NULL }, { "name", proc_idetape_read_name, NULL }, - { "pipeline", proc_idetape_read_pipeline, NULL }, - { "speed", proc_idetape_read_speed, NULL }, - { "stage", proc_idetape_read_stage, NULL }, - { "tdsc", proc_idetape_read_tdsc, NULL }, { NULL, NULL, NULL } }; -int idetape_init (void); - -static ide_module_t idetape_module = { - IDE_DRIVER_MODULE, - idetape_init, - NULL -}; - /* * IDE subdriver functions, registered with ide.c */ @@ -3718,6 +3680,14 @@ idetape_proc /* proc */ }; +int idetape_init (void); +static ide_module_t idetape_module = { + IDE_DRIVER_MODULE, + idetape_init, + &idetape_driver, + NULL +}; + /* * Our character device supporting functions, passed to register_chrdev. */ @@ -3751,7 +3721,7 @@ for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) idetape_chrdevs[minor].drive = NULL; - if ((drive = ide_scan_devices (ide_tape, NULL, failed++)) == NULL) { + if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { ide_register_module (&idetape_module); MOD_DEC_USE_COUNT; return 0; @@ -3780,7 +3750,7 @@ idetape_setup (drive, tape, minor); idetape_chrdevs[minor].drive = drive; supported++; failed--; - } while ((drive = ide_scan_devices (ide_tape, NULL, failed++)) != NULL); + } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL); if (!idetape_chrdev_present && !supported) { unregister_chrdev (IDETAPE_MAJOR, "ht"); } else diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.78/linux/drivers/block/ide.c Sun Dec 21 22:36:13 1997 +++ linux/drivers/block/ide.c Sat Jan 10 10:42:55 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.11 December 5, 1997 + * linux/drivers/block/ide.c Version 6.12 January 2, 1998 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -98,6 +98,8 @@ * Version 6.11 fix probe error in ide_scan_devices() * fix ancient "jiffies" polling bugs * mask all hwgroup interrupts on each irq entry + * Version 6.12 integrate ioctl and proc interfaces + * fix parsing of "idex=" command line parameter * * Some additional driver compile-time options are in ide.h * @@ -151,7 +153,7 @@ /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ -static ide_module_t *ide_modules = NULL; +ide_module_t *ide_modules = NULL; /* * This is declared extern in ide.h, for access by other IDE modules: @@ -809,7 +811,8 @@ { struct request *rq = HWGROUP(drive)->rq; byte *args = (byte *) rq->buffer; - byte test, stat = GET_STAT(); + byte stat = GET_STAT(); + int retries = 10; ide_sti(); if ((stat & DRQ_STAT) && args && args[3]) { @@ -817,12 +820,11 @@ drive->io_32bit = 0; ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS); drive->io_32bit = io_32bit; - stat = GET_STAT(); + while (((stat = GET_STAT()) & BUSY_STAT) && retries--) + udelay(100); } - test = stat; - if (drive->media == ide_cdrom) - test = stat &~BUSY_STAT; - if (OK_STAT(test,READY_STAT,BAD_STAT)) + + if (OK_STAT(stat, READY_STAT, BAD_STAT)) ide_end_drive_cmd (drive, stat, GET_ERR()); else ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ @@ -901,6 +903,10 @@ printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n", drive->name, args[0], args[1], args[2], args[3]); #endif + if (args[0] == WIN_SMART) { + OUT_BYTE(0x4f, IDE_LCYL_REG); + OUT_BYTE(0xc2, IDE_HCYL_REG); + } OUT_BYTE(args[2],IDE_FEATURE_REG); ide_cmd(drive, args[0], args[1], &drive_cmd_intr); return; @@ -1556,6 +1562,22 @@ return 0; } +int ide_replace_subdriver(ide_drive_t *drive, const char *driver) +{ + if (!drive->present || drive->busy || drive->usage) + goto abort; + if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) + goto abort; + strncpy(drive->driver_req, driver, 9); + ide_init_module(IDE_DRIVER_MODULE); + drive->driver_req[0] = 0; + ide_init_module(IDE_DRIVER_MODULE); + if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) + return 0; +abort: + return 1; +} + void ide_unregister (unsigned int index) { struct gendisk *gd, **gdp; @@ -1697,20 +1719,229 @@ return hwif->present ? index : -1; } +void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) +{ + ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; + + while ((*p) && strcmp((*p)->name, name) < 0) + p = &((*p)->next); + if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL) + goto abort; + memset(setting, 0, sizeof(*setting)); + if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) + goto abort; + strcpy(setting->name, name); setting->rw = rw; + setting->read_ioctl = read_ioctl; setting->write_ioctl = write_ioctl; + setting->data_type = data_type; setting->min = min; + setting->max = max; setting->mul_factor = mul_factor; + setting->div_factor = div_factor; setting->data = data; + setting->set = set; setting->next = *p; + if (drive->driver) + setting->auto_remove = 1; + *p = setting; + return; +abort: + if (setting) + kfree(setting); +} + +void ide_remove_setting(ide_drive_t *drive, char *name) +{ + ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting; + + while ((*p) && strcmp((*p)->name, name)) + p = &((*p)->next); + if ((setting = (*p)) == NULL) + return; + (*p) = setting->next; + kfree(setting->name); + kfree(setting); +} + +static ide_settings_t *ide_find_setting_by_ioctl(ide_drive_t *drive, int cmd) +{ + ide_settings_t *setting = drive->settings; + + while (setting) { + if (setting->read_ioctl == cmd || setting->write_ioctl == cmd) + break; + setting = setting->next; + } + return setting; +} + +ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) +{ + ide_settings_t *setting = drive->settings; + + while (setting) { + if (strcmp(setting->name, name) == 0) + break; + setting = setting->next; + } + return setting; +} + +static void auto_remove_settings(ide_drive_t *drive) +{ + ide_settings_t *setting; +repeat: + setting = drive->settings; + while (setting) { + if (setting->auto_remove) { + ide_remove_setting(drive, setting->name); + goto repeat; + } + setting = setting->next; + } +} + +int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) +{ + if (!(setting->rw & SETTING_READ)) + return -EINVAL; + switch(setting->data_type) { + case TYPE_BYTE: + return *((u8 *) setting->data); + case TYPE_SHORT: + return *((u16 *) setting->data); + case TYPE_INT: + case TYPE_INTA: + return *((u32 *) setting->data); + default: + return -EINVAL; + } +} + +int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) +{ + unsigned long flags; + int i, rc = 0; + u32 *p; + + if (!suser()) + return -EACCES; + if (!(setting->rw & SETTING_WRITE)) + return -EPERM; + if (val < setting->min || val > setting->max) + return -EINVAL; + save_flags(flags); + cli(); + if (setting->set) + rc = setting->set(drive, val); + else switch (setting->data_type) { + case TYPE_BYTE: + *((u8 *) setting->data) = val; + break; + case TYPE_SHORT: + *((u16 *) setting->data) = val; + break; + case TYPE_INT: + *((u32 *) setting->data) = val; + break; + case TYPE_INTA: + p = (u32 *) setting->data; + for (i = 0; i < 1 << PARTN_BITS; i++, p++) + *p = val; + break; + } + restore_flags(flags); + return rc; +} + +static int set_io_32bit(ide_drive_t *drive, int arg) +{ + drive->io_32bit = arg; +#ifdef CONFIG_BLK_DEV_DTC2278 + if (HWIF(drive)->chipset == ide_dtc2278) + HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg; +#endif /* CONFIG_BLK_DEV_DTC2278 */ + return 0; +} + +static int set_using_dma(ide_drive_t *drive, int arg) +{ + if (!drive->driver || !DRIVER(drive)->supports_dma) + return -EPERM; + if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) + return -EPERM; + if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) + return -EIO; + return 0; +} + +static int set_pio_mode(ide_drive_t *drive, int arg) +{ + struct request rq; + + if (!HWIF(drive)->tuneproc) + return -ENOSYS; + if (drive->special.b.set_tune) + return -EBUSY; + ide_init_drive_cmd(&rq); + drive->tune_req = (byte) arg; + drive->special.b.set_tune = 1; + (void) ide_do_drive_cmd (drive, &rq, ide_wait); + return 0; +} + +void ide_add_generic_settings(ide_drive_t *drive) +{ +/* + * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function + */ + ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit); + ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL); + ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL); + ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode); + ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL); + ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL); + ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma); +} + +int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf) +{ + struct request rq; + byte buffer[4]; + + if (!buf) + buf = buffer; + memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors); + ide_init_drive_cmd(&rq); + rq.buffer = buf; + *buf++ = cmd; + *buf++ = nsect; + *buf++ = feature; + *buf++ = sectors; + return ide_do_drive_cmd(drive, &rq, ide_wait); +} + static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err, major, minor; ide_drive_t *drive; - unsigned long flags; struct request rq; kdev_t dev; + ide_settings_t *setting; if (!inode || !(dev = inode->i_rdev)) return -EINVAL; major = MAJOR(dev); minor = MINOR(dev); if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENODEV; + + if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) { + if (cmd == setting->read_ioctl) { + err = ide_read_setting(drive, setting); + return err >= 0 ? put_user(err, (long *) arg) : err; + } else { + if ((MINOR(inode->i_rdev) & PARTN_MASK)) + return -EINVAL; + return ide_write_setting(drive, setting, arg); + } + } + ide_init_drive_cmd (&rq); switch (cmd) { case HDIO_GETGEO: @@ -1730,54 +1961,13 @@ invalidate_buffers(inode->i_rdev); return 0; - case BLKRASET: - if (!suser()) return -EACCES; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg); - case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); - case BLKFRASET: - if (!suser()) return -EACCES; - max_readahead[major][minor] = arg; - return 0; - - case BLKFRAGET: - return put_user(max_readahead[major][minor], (long *) arg); - - case BLKSECTSET: - if (!suser()) return -EACCES; - if (!arg || arg > 0xff) return -EINVAL; - max_sectors[major][minor] = arg; - return 0; - - case BLKSECTGET: - return put_user(max_sectors[major][minor], (long *) arg); - case BLKRRPART: /* Re-read partition tables */ if (!suser()) return -EACCES; return ide_revalidate_disk(inode->i_rdev); - case HDIO_GET_KEEPSETTINGS: - return put_user(drive->keep_settings, (long *) arg); - - case HDIO_GET_UNMASKINTR: - return put_user(drive->unmask, (long *) arg); - - case HDIO_GET_DMA: - return put_user(drive->using_dma, (long *) arg); - - case HDIO_GET_32BIT: - return put_user(drive->io_32bit, (long *) arg); - - case HDIO_GET_MULTCOUNT: - return put_user(drive->mult_count, (long *) arg); - case HDIO_GET_IDENTITY: if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; @@ -1792,99 +1982,13 @@ #endif return 0; - case HDIO_GET_NOWERR: - return put_user(drive->bad_wstat == BAD_R_STAT, (long *) arg); - case HDIO_GET_NICE: - { - long nice = 0; - - nice |= drive->dsc_overlap << IDE_NICE_DSC_OVERLAP; - nice |= drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP; - nice |= drive->nice0 << IDE_NICE_0; - nice |= drive->nice1 << IDE_NICE_1; - nice |= drive->nice2 << IDE_NICE_2; - return put_user(nice, (long *) arg); - } - - case HDIO_SET_DMA: - if (!suser()) return -EACCES; - if (drive->driver != NULL && !DRIVER(drive)->supports_dma) - return -EPERM; - if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) - return -EPERM; - case HDIO_SET_KEEPSETTINGS: - case HDIO_SET_UNMASKINTR: - case HDIO_SET_NOWERR: - if (arg > 1) - return -EINVAL; - case HDIO_SET_32BIT: - if (!suser()) return -EACCES; - if ((MINOR(inode->i_rdev) & PARTN_MASK)) - return -EINVAL; - save_flags(flags); - cli(); - switch (cmd) { - case HDIO_SET_DMA: - if (!(HWIF(drive)->dmaproc)) { - restore_flags(flags); - return -EPERM; - } - if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) { - restore_flags(flags); - return -EIO; - } - break; - case HDIO_SET_KEEPSETTINGS: - drive->keep_settings = arg; - break; - case HDIO_SET_UNMASKINTR: - if (arg && drive->no_unmask) { - restore_flags(flags); - return -EPERM; - } - drive->unmask = arg; - break; - case HDIO_SET_NOWERR: - drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - break; - case HDIO_SET_32BIT: - if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) { - restore_flags(flags); - return -EINVAL; - } - if (arg && drive->no_io_32bit) { - restore_flags(flags); - return -EPERM; - } - drive->io_32bit = arg; -#ifdef CONFIG_BLK_DEV_DTC2278 - if (HWIF(drive)->chipset == ide_dtc2278) - HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg; -#endif /* CONFIG_BLK_DEV_DTC2278 */ - break; - } - restore_flags(flags); - return 0; - - case HDIO_SET_MULTCOUNT: - if (!suser()) return -EACCES; - if (MINOR(inode->i_rdev) & PARTN_MASK) - return -EINVAL; - if (drive->id && arg > drive->id->max_multsect) - return -EINVAL; - save_flags(flags); - cli(); - if (drive->special.b.set_multmode) { - restore_flags(flags); - return -EBUSY; - } - drive->mult_req = arg; - drive->special.b.set_multmode = 1; - restore_flags(flags); - (void) ide_do_drive_cmd (drive, &rq, ide_wait); - return (drive->mult_count == arg) ? 0 : -EIO; - + return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | + drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP | + drive->nice0 << IDE_NICE_0 | + drive->nice1 << IDE_NICE_1 | + drive->nice2 << IDE_NICE_2, + (long *) arg); case HDIO_DRIVE_CMD: { byte args[4], *argbuf = args; @@ -1901,31 +2005,13 @@ return -ENOMEM; memcpy(argbuf, args, 4); } - rq.buffer = argbuf; - err = ide_do_drive_cmd(drive, &rq, ide_wait); + err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); if (copy_to_user((void *)arg, argbuf, argsize)) err = -EFAULT; if (argsize > 4) kfree(argbuf); return err; } - case HDIO_SET_PIO_MODE: - if (!suser()) return -EACCES; - if (MINOR(inode->i_rdev) & PARTN_MASK) - return -EINVAL; - if (!HWIF(drive)->tuneproc) - return -ENOSYS; - save_flags(flags); - cli(); - if (drive->special.b.set_tune) { - restore_flags(flags); - return -EBUSY; - } - drive->tune_req = (byte) arg; - drive->special.b.set_tune = 1; - restore_flags(flags); - (void) ide_do_drive_cmd (drive, &rq, ide_wait); - return 0; case HDIO_SCAN_HWIF: { @@ -2223,7 +2309,7 @@ if (i > 0 || i <= -7) { /* is parameter a chipset name? */ if (hwif->chipset != ide_unknown) goto bad_option; /* chipset already specified */ - if (i != -7 && hw != 0) + if (i <= -7 && hw != 0) goto bad_hwif; /* chipset drivers are for "ide0=" only */ if (ide_hwifs[hw^1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ @@ -2578,7 +2664,7 @@ if (d->special == NULL) d->special = default_special; } -ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n) +ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n) { unsigned int unit, index, i; @@ -2588,12 +2674,15 @@ search: for (index = 0, i = 0; index < MAX_HWIFS; ++index) { ide_hwif_t *hwif = &ide_hwifs[index]; - if (hwif->present) { - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present && drive->media == media && drive->driver == driver && ++i > n) - return drive; - } + if (!hwif->present) + continue; + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + char *req = drive->driver_req; + if (*req && !strstr(name, req)) + continue; + if (drive->present && drive->media == media && drive->driver == driver && ++i > n) + return drive; } } return NULL; @@ -2642,6 +2731,7 @@ } ide_remove_proc_entries(drive, DRIVER(drive)->proc); ide_remove_proc_entries(drive, generic_subdriver_entries); + auto_remove_settings(drive); drive->driver = NULL; restore_flags(flags); return 0; @@ -2735,6 +2825,8 @@ EXPORT_SYMBOL(ide_stall_queue); EXPORT_SYMBOL(ide_add_proc_entries); EXPORT_SYMBOL(ide_remove_proc_entries); +EXPORT_SYMBOL(ide_add_setting); +EXPORT_SYMBOL(ide_remove_setting); EXPORT_SYMBOL(proc_ide_read_geometry); EXPORT_SYMBOL(ide_register); diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v2.1.78/linux/drivers/block/ide.h Fri Jan 2 14:37:01 1998 +++ linux/drivers/block/ide.h Mon Jan 12 16:43:36 1998 @@ -206,23 +206,23 @@ special_t special; /* special action flags */ unsigned present : 1; /* drive is physically present */ unsigned noprobe : 1; /* from: hdx=noprobe */ - unsigned keep_settings : 1; /* restore settings after drive reset */ + byte keep_settings; /* restore settings after drive reset */ unsigned busy : 1; /* currently doing revalidate_disk() */ unsigned removable : 1; /* 1 if need to do check_media_change */ - unsigned using_dma : 1; /* disk is using dma for read/write */ + byte using_dma; /* disk is using dma for read/write */ unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ - unsigned unmask : 1; /* flag: okay to unmask other irqs */ + byte unmask; /* flag: okay to unmask other irqs */ unsigned no_unmask : 1; /* disallow setting unmask bit */ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ unsigned nobios : 1; /* flag: do not probe bios for drive */ - unsigned slow : 1; /* flag: slow data port */ + byte slow; /* flag: slow data port */ unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ unsigned revalidate : 1; /* request revalidation */ - unsigned bswap : 1; /* flag: byte swap data */ - unsigned dsc_overlap : 1; /* flag: DSC overlap */ + byte bswap; /* flag: byte swap data */ + byte dsc_overlap; /* flag: DSC overlap */ unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ - unsigned nice1 : 1; /* flag: give potential excess bandwidth */ + byte nice1; /* flag: give potential excess bandwidth */ unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ #if FAKE_FDISK_FOR_EZDRIVE unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */ @@ -236,6 +236,7 @@ byte tune_req; /* requested drive tuning setting */ byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ byte bad_wstat; /* used for ignoring WRERR_STAT */ + byte nowerr; /* used for ignoring WRERR_STAT */ byte sect0; /* offset of first sector for DM6:DDO */ byte usage; /* current "open()" count for drive */ byte head; /* "real" number of heads */ @@ -253,6 +254,8 @@ void *driver; /* (ide_driver_t *) */ void *driver_data; /* extra driver data */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ + void *settings; /* /proc/ide/ drive settings */ + char driver_req[10]; /* requests specific driver */ } ide_drive_t; /* @@ -362,6 +365,43 @@ } ide_hwgroup_t; /* + * configurable drive settings + */ + +#define TYPE_INT 0 +#define TYPE_INTA 1 +#define TYPE_BYTE 2 +#define TYPE_SHORT 3 + +#define SETTING_READ (1 << 0) +#define SETTING_WRITE (1 << 1) +#define SETTING_RW (SETTING_READ | SETTING_WRITE) + +typedef int (ide_procset_t)(ide_drive_t *, int); +typedef struct ide_settings_s { + char *name; + int rw; + int read_ioctl; + int write_ioctl; + int data_type; + int min; + int max; + int mul_factor; + int div_factor; + void *data; + ide_procset_t *set; + int auto_remove; + struct ide_settings_s *next; +} ide_settings_t; + +void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); +void ide_remove_setting(ide_drive_t *drive, char *name); +ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name); +int ide_read_setting(ide_drive_t *t, ide_settings_t *setting); +int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val); +void ide_add_generic_settings(ide_drive_t *drive); + +/* * /proc/ide interface */ typedef struct { @@ -407,6 +447,7 @@ typedef void (ide_pre_reset_proc)(ide_drive_t *); typedef unsigned long (ide_capacity_proc)(ide_drive_t *); typedef void (ide_special_proc)(ide_drive_t *); +typedef void (ide_setting_proc)(ide_drive_t *); typedef struct ide_driver_s { const char *name; @@ -442,6 +483,7 @@ typedef struct ide_module_s { int type; ide_module_init_proc *init; + void *info; struct ide_module_s *next; } ide_module_t; @@ -455,6 +497,7 @@ */ #ifndef _IDE_C extern ide_hwif_t ide_hwifs[]; /* master data repository */ +extern ide_module_t *ide_modules; #endif /* @@ -588,6 +631,11 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); /* + * Issue ATA command and wait for completion. + */ +int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf); + +/* * ide_system_bus_speed() returns what we think is the system VESA/PCI * bus speed (in MHz). This is used for calculating interface PIO timings. * The default is 40 for known PCI systems, 50 otherwise. @@ -651,9 +699,10 @@ int ide_register_module (ide_module_t *module); void ide_unregister_module (ide_module_t *module); -ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n); +ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n); int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); int ide_unregister_subdriver (ide_drive_t *drive); +int ide_replace_subdriver(ide_drive_t *drive, const char *driver); #ifdef CONFIG_BLK_DEV_IDEPCI unsigned long ide_find_free_region (unsigned short size) __init; diff -u --recursive --new-file v2.1.78/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.78/linux/drivers/char/Config.in Fri Jan 2 14:37:02 1998 +++ linux/drivers/char/Config.in Mon Jan 12 14:46:16 1998 @@ -110,7 +110,10 @@ fi tristate 'Video For Linux' CONFIG_VIDEO_DEV dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV -dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV + dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV +fi dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV tristate '/dev/nvram support' CONFIG_NVRAM tristate 'PC joystick support' CONFIG_JOYSTICK diff -u --recursive --new-file v2.1.78/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.78/linux/drivers/char/Makefile Sun Dec 21 22:36:13 1997 +++ linux/drivers/char/Makefile Mon Jan 12 14:46:16 1998 @@ -317,6 +317,14 @@ endif endif +ifeq ($(CONFIG_VIDEO_CQCAM),y) +L_OBJS += c-qcam.o +else + ifeq ($(CONFIG_VIDEO_CQCAM),m) + M_OBJS += c-qcam.o + endif +endif + ifeq ($(CONFIG_VIDEO_PMS),y) L_OBJS += pms.o else diff -u --recursive --new-file v2.1.78/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.1.78/linux/drivers/char/acquirewdt.c Wed Dec 10 11:12:43 1997 +++ linux/drivers/char/acquirewdt.c Mon Jan 12 15:12:42 1998 @@ -46,7 +46,6 @@ #define WDT_STOP 0x43 #define WDT_START 0x443 -#define WATCHDOG_MINOR 130 #define WD_TIMO (100*60) /* 1 minute */ @@ -181,7 +180,7 @@ static struct miscdevice acq_miscdev= { WATCHDOG_MINOR, - "Acquire WDT", + "watchdog", &acq_fops }; diff -u --recursive --new-file v2.1.78/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.78/linux/drivers/char/bttv.c Tue Jan 6 09:37:33 1998 +++ linux/drivers/char/bttv.c Mon Jan 12 14:46:27 1998 @@ -523,21 +523,21 @@ static struct tunertype tuners[] = { {"Temic PAL", TEMIC, PAL, - 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2}, + 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 623}, {"Philips PAL_I", Philips, PAL_I, - 16*140.25,16*463.25,0x00,0x00,0x00,0x00,0x00}, + 16*140.25,16*463.25,0x00,0x00,0x00,0x00,0x00, 623}, {"Philips NTSC", Philips, NTSC, - 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0}, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0, 732}, {"Philips SECAM", Philips, SECAM, - 16*168.25,16*447.25,0xA3,0x93,0x33,0x8e,0xc0}, + 16*168.25,16*447.25,0xA3,0x93,0x33,0x8e,0xc0, 623}, {"NoTuner", NoTuner, NOTUNER, - 0 ,0 ,0x00,0x00,0x00,0x00,0x00}, + 0 ,0 ,0x00,0x00,0x00,0x00,0x00, 0}, {"Philips PAL", Philips, PAL, - 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0}, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0, 623}, {"Temic NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2}, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 732}, {"TEMIC PAL_I", TEMIC, PAL_I, - 0 ,0 ,0x00,0x00,0x00,0x00,0xc2}, + 0 ,0 ,0x00,0x00,0x00,0x00,0xc2, 623}, }; /* @@ -553,6 +553,7 @@ audio(btv, AUDIO_MUTE); udelay(AUDIO_MUTE_DELAY); + if (freq < tun->thresh1) config = tun->VHF_L; else if (freq < tun->thresh2) @@ -560,9 +561,17 @@ else config = tun->UHF; - div=freq+623; /* div=((freq+16*38.9));*/ - + if(freq < tun->thresh1) + config = tun->VHF_L; + else if(freq < tun->thresh2) + config = tun->VHF_H; + else + config=tun->UHF; + + div=freq+tun->IFPCoff; + div&=0x7fff; + if (I2CWrite(btv, btv->tuneradr, (div>>8)&0x7f, div&0xff, 1)<0) return; I2CWrite(btv, btv->tuneradr, tun->config, config, 1); diff -u --recursive --new-file v2.1.78/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.1.78/linux/drivers/char/bw-qcam.c Tue Jan 6 09:37:33 1998 +++ linux/drivers/char/bw-qcam.c Mon Jan 12 14:46:16 1998 @@ -1,7 +1,10 @@ /* * QuickCam Driver For Video4Linux. * + * This version only works as a module. + * * Video4Linux conversion work by Alan Cox. + * Parport compatibility by Phil Blundell. */ /* qcam-lib.c -- Library for programming with the Connectix QuickCam. @@ -44,41 +47,41 @@ #include #include #include +#include #include #include #include -#include -#include +#include #include -#include #include +#include #include #include "bw-qcam.h" extern __inline__ int read_lpstatus(struct qcam_device *q) { - return inb_p(q->port+1); + return parport_read_status(q->pport); } extern __inline__ int read_lpcontrol(struct qcam_device *q) { - return inb_p(q->port+2); + return parport_read_control(q->pport); } extern __inline__ int read_lpdata(struct qcam_device *q) { - return inb_p(q->port); + return parport_read_data(q->pport); } extern __inline__ void write_lpdata(struct qcam_device *q, int d) { - outb_p(d, q->port); + parport_write_data(q->pport, d); } -extern __inline__ void write_lpcontrol(struct qcam_device *q,int d) +extern __inline__ void write_lpcontrol(struct qcam_device *q, int d) { - outb(d, q->port+2); + parport_write_control(q->pport, d); } static int qc_waithand(struct qcam_device *q, int val); @@ -122,21 +125,25 @@ /* Initialize the QuickCam driver control structure. This is where * defaults are set for people who don't have a config file.*/ -static struct qcam_device *qcam_init(int port) +static struct qcam_device *qcam_init(struct parport *port) { struct qcam_device *q; - if(check_region(port,3)) - { - printk(KERN_ERR "qcam: I/O port 0x%03X in use.\n", port); + q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + + q->pport = port; + q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, + NULL, 0, NULL); + if (q->pdev == NULL) + { + printk(KERN_ERR "bw-qcam: couldn't register for %s.\n", + port->name); + kfree(q); return NULL; } - q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); - memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - q->port = port; /* Port 0 == Autoprobe */ q->port_mode = (QC_ANY | QC_NOTSET); q->width = 320; q->height = 240; @@ -295,7 +302,7 @@ /* Be liberal in what you accept... */ - if (count > 20 && count < 250) + if (count > 30 && count < 200) return 1; /* found */ else return 0; /* not found */ @@ -742,7 +749,9 @@ qcam->bpp = p.depth; qc_setscanmode(qcam); + parport_claim_or_block(qcam->pdev); qc_set(qcam); + parport_release(qcam->pdev); return 0; } case VIDIOCSWIN: @@ -816,9 +825,11 @@ { struct qcam_device *qcam=(struct qcam_device *)v; int len; + parport_claim_or_block(qcam->pdev); /* Probably should have a semaphore against multiple users */ qc_reset(qcam); len=qc_capture(qcam, buf,count); + parport_release(qcam->pdev); return len; } @@ -840,72 +851,83 @@ 0 }; +#define MAX_CAMS 4 +static struct qcam_device *qcams[MAX_CAMS]; +static unsigned int num_cams = 0; -#ifdef MODULE - -int io=0x378; - -MODULE_PARM(io,"i"); +int init_bwqcam(struct parport *port) +{ + struct qcam_device *qcam; -static struct qcam_device *qcam; + if (num_cams == MAX_CAMS) + { + printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); + return -ENOSPC; + } -int init_module(void) -{ - qcam=qcam_init(io); + qcam=qcam_init(port); if(qcam==NULL) return -ENODEV; + parport_claim_or_block(qcam->pdev); + qc_reset(qcam); if(qc_detect(qcam)==0) { + parport_release(qcam->pdev); + parport_unregister_device(qcam->pdev); kfree(qcam); - printk(KERN_ERR "bw_qcam: No quickcam detected at 0x%03X\n", io); return -ENODEV; } qc_calibrate(qcam); + + parport_release(qcam->pdev); - printk(KERN_INFO "Connectix Quickcam at 0x%03X\n", qcam->port); + printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); if(video_register_device(&qcam->vdev)==-1) + { + parport_unregister_device(qcam->pdev); + kfree(qcam); return -ENODEV; + } + + qcams[num_cams++] = qcam; + return 0; } -void cleanup_module(void) +void close_bwqcam(struct qcam_device *qcam) { video_unregister_device(&qcam->vdev); + parport_unregister_device(qcam->pdev); kfree(qcam); } -#else +#ifdef MODULE +int init_module(void) +{ + struct parport *port; + + for (port = parport_enumerate(); port; port=port->next) + init_bwqcam(port); -void init_bw_qcams(void) + return (num_cams)?0:-ENODEV; +} + +void cleanup_module(void) { - int io_ports[3]={0x278,0x378, 0x3BC}; - struct qcam_device *qcam; - int i; - - for(i=0;i<3;i++) - { - qcam=qcam_init(io_ports[i]); - if(qcam==NULL) - continue; - - qc_reset(qcam); - - if(qc_detect(qcam)==0) - { - kfree(qcam); - continue; - } - qc_calibrate(qcam); - - printk(KERN_INFO "Connectix Quickcam at 0x%03X\n", qcam->port); - - if(video_register_device(&qcam->vdev)==-1) - return -ENODEV; - } + unsigned int i; + for (i = 0; i < num_cams; i++) + close_bwqcam(qcams[i]); } +#else +__initfunc(int init_bwqcams(struct video_init *unused)) +{ + struct parport *port; + for (port = parport_enumerate(); port; port=port->next) + init_bwqcam(port); +} #endif diff -u --recursive --new-file v2.1.78/linux/drivers/char/bw-qcam.h linux/drivers/char/bw-qcam.h --- v2.1.78/linux/drivers/char/bw-qcam.h Fri Jan 2 14:37:02 1998 +++ linux/drivers/char/bw-qcam.h Mon Jan 12 14:46:16 1998 @@ -50,11 +50,12 @@ struct qcam_device { struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; int width, height; int bpp; int mode; int contrast, brightness, whitebal; - int port; int port_mode; int transfer_scale; int top, left; diff -u --recursive --new-file v2.1.78/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.1.78/linux/drivers/char/c-qcam.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/c-qcam.c Mon Jan 12 14:46:16 1998 @@ -0,0 +1,775 @@ +/* + * Video4Linux: Colour QuickCam driver + * + * Philip Blundell , December 30 1997 + * + * Largely untested (seems to work at 24bpp with a bidirectional port, + * though). + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "c-qcam.h" + +static __inline__ void qcam_set_ack(struct qcam_device *qcam, unsigned int i) +{ + /* note: the QC specs refer to the PCAck pin by voltage, not + software level. PC ports have builtin inverters. */ + parport_frob_control(qcam->pport, 8, i?8:0); +} + +static __inline__ unsigned int qcam_ready1(struct qcam_device *qcam) +{ + return (parport_read_status(qcam->pport) & 0x8)?1:0; + +} + +static __inline__ unsigned int qcam_ready2(struct qcam_device *qcam) +{ + return (parport_read_data(qcam->pport) & 0x1)?1:0; +} + +static inline unsigned int qcam_await_ready1(struct qcam_device *qcam, int value) +{ + unsigned long oldjiffies = jiffies; + unsigned int i; + + for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); ) + if (qcam_ready1(qcam) == value) + return 0; + + /* If the camera didn't respond within 1/25 second, poll slowly + for a while. */ + for (i = 0; i < 50; i++) + { + if (qcam_ready1(qcam) == value) + return 0; + current->state=TASK_INTERRUPTIBLE; + current->timeout = jiffies+HZ/10; + schedule(); + } + + /* Probably somebody pulled the plug out. Not much we can do. */ + printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value, + parport_read_status(qcam->pport), + parport_read_control(qcam->pport)); + return 1; +} + +static inline unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) +{ + unsigned long oldjiffies = jiffies; + unsigned int i; + + for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); ) + if (qcam_ready2(qcam) == value) + return 0; + + /* If the camera didn't respond within 1/25 second, poll slowly + for a while. */ + for (i = 0; i < 50; i++) + { + if (qcam_ready2(qcam) == value) + return 0; + current->state=TASK_INTERRUPTIBLE; + current->timeout = jiffies+HZ/10; + schedule(); + } + + /* Probably somebody pulled the plug out. Not much we can do. */ + printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value, + parport_read_status(qcam->pport), + parport_read_control(qcam->pport), + parport_read_data(qcam->pport)); + return 1; +} + +static inline int qcam_read_data(struct qcam_device *qcam) +{ + unsigned int idata; + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) return -1; + idata = parport_read_status(qcam->pport) & 0xf0; + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) return -1; + idata |= (parport_read_status(qcam->pport) >> 4); + return idata; +} + +static int qcam_write_data(struct qcam_device *qcam, unsigned int data) +{ + unsigned int idata; + parport_write_data(qcam->pport, data); + idata = qcam_read_data(qcam); + if (data != idata) + { + printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, + idata); + return 1; + } + return 0; +} + +static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data) +{ + if (qcam_write_data(qcam, cmd)) + return -1; + if (qcam_write_data(qcam, data)) + return -1; + return 0; +} + +static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd) +{ + if (qcam_write_data(qcam, cmd)) + return -1; + return qcam_read_data(qcam); +} + +static int qc_detect(struct qcam_device *qcam) +{ + unsigned int stat, ostat, i, count = 0; + + parport_write_control(qcam->pport, 0xc); + + /* look for a heartbeat */ + ostat = stat = parport_read_status(qcam->pport); + for (i=0; i<250; i++) + { + udelay(1000); + stat = parport_read_status(qcam->pport); + if (ostat != stat) + { + if (++count >= 3) return 1; + ostat = stat; + } + } + + /* no (or flatline) camera, give up */ + return 0; +} + +static void qc_reset(struct qcam_device *qcam) +{ + parport_write_control(qcam->pport, 0xc); + parport_write_control(qcam->pport, 0x8); + udelay(1000); + parport_write_control(qcam->pport, 0xc); + udelay(1000); +} + +/* Reset the QuickCam and program for brightness, contrast, + * white-balance, and resolution. */ + +static void qc_setup(struct qcam_device *q) +{ + qc_reset(q); + + /* Set the brightness. */ + qcam_set(q, 11, q->brightness); + + /* Set the height. */ + qcam_set(q, 17, q->height); + + /* Set the width. */ + qcam_set(q, 19, q->width/2); + + /* Set top and left. */ + qcam_set(q, 0xd, q->top); + qcam_set(q, 0xf, q->left); + + /* Set contrast and white balance. */ + qcam_set(q, 0x19, q->contrast); + qcam_set(q, 0x1f, q->whitebal); + + /* Set the speed. */ + qcam_set(q, 45, 2); +} + +/* Read some bytes from the camera and put them in the buffer. + nbytes should be a multiple of 3, because bidirectional mode gives + us three bytes at a time. */ + +static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) +{ + unsigned int bytes = 0; + qcam_set_ack(q, 0); + if (q->bidirectional) + { + /* It's a bidirectional port */ + while (bytes < nbytes) + { + unsigned int lo1, hi1, lo2, hi2; + if (qcam_await_ready2(q, 1)) return bytes; + lo1 = parport_read_data(q->pport) >> 1; + hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(q, 1); + if (qcam_await_ready2(q, 0)) return bytes; + lo2 = parport_read_data(q->pport) >> 1; + hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(q, 0); + buf[bytes++] = (lo1 | ((hi1 & 1)<<7)); + buf[bytes++] = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1); + buf[bytes++] = (lo2 | ((hi2 & 1)<<7)); + } + } + else + { + /* It's a unidirectional port */ + while (bytes < nbytes) + { + unsigned int hi, lo; + if (qcam_await_ready1(q, 1)) return bytes; + hi = (parport_read_status(q->pport) & 0xf0); + qcam_set_ack(q, 1); + if (qcam_await_ready1(q, 0)) return bytes; + lo = (parport_read_status(q->pport) & 0xf0); + qcam_set_ack(q, 0); + /* flip some bits; cqcam gets this wrong */ + buf[bytes++] = (hi | lo) ^ 0x88; + } + } + return bytes; +} + +/* Convert the data the camera gives us into the desired output format. + At the moment this is a no-op because read_bytes() does all the + required stuff, for 24bpp at least. */ +static size_t qcam_munge_buffer(struct qcam_device *q, char *inbuf, size_t inlen, char *outbuf, size_t outlen) +{ + size_t outptr = 0; + switch (q->bpp) + { + case 24: + while (inlen && (outptr <= (outlen-3))) + { + unsigned char r, g, b; + r = inbuf[0]; + g = inbuf[1]; + b = inbuf[2]; + put_user(r, outbuf+(outptr++)); + put_user(g, outbuf+(outptr++)); + put_user(b, outbuf+(outptr++)); + inlen -= 3; + inbuf += 3; + } + break; + default: + printk("c-qcam: can't convert this format (%d).\n", q->bpp); + return 0; + } + return outptr; +} + +static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) +{ + unsigned int tbpp = 0, tdecimation = 0, lines, pixelsperline, bitsperxfer; + unsigned int is_bi_dir = q->bidirectional; + size_t wantlen, outptr = 0; + char *tmpbuf = kmalloc(768, GFP_KERNEL); + if (tmpbuf == NULL) + { + printk(KERN_ERR "cqcam: couldn't allocate a buffer.\n"); + return -ENOMEM; + } + + /* Wait for camera to become ready */ + for (;;) + { + int i = qcam_get(q, 41); + if (i == -1) { + qc_setup(q); + kfree(tmpbuf); + return -EIO; + } + if (i & 0x80) + schedule(); + else + break; + } + + switch (q->bpp) + { + case 24: tbpp = QC_24BPP; break; + case 32: tbpp = QC_32BPP; break; + case 16: tbpp = QC_16BPP; break; + default: printk("qcam: Bad bpp.\n"); + } + switch (q->transfer_scale) { + case 1: tdecimation = QC_1_1; break; + case 2: tdecimation = QC_2_1; break; + case 4: tdecimation = QC_4_1; break; + default: printk("qcam: Bad decimation.\n"); + } + + qcam_set(q, 7, (tbpp | tdecimation) + ((is_bi_dir)?1:0) + 1); + + lines = q->height / q->transfer_scale; + pixelsperline = q->width / q->transfer_scale; + bitsperxfer = (is_bi_dir) ? 24 : 8; + + if (is_bi_dir) + { + /* Turn the port around */ + parport_frob_control(q->pport, 0x20, 0x20); + udelay(3000); + qcam_set_ack(q, 0); + if (qcam_await_ready1(q, 1)) { + kfree(tmpbuf); + qc_setup(q); + return -EIO; + } + qcam_set_ack(q, 1); + if (qcam_await_ready1(q, 0)) { + kfree(tmpbuf); + qc_setup(q); + return -EIO; + } + } + + wantlen = lines * pixelsperline * q->bpp / 8; + + while (wantlen) + { + size_t t, s, o; + s = (wantlen > 768)?768:wantlen; + t = qcam_read_bytes(q, tmpbuf, s); + if (outptr < len) + { + o = qcam_munge_buffer(q, tmpbuf, t, buf + outptr, + len - outptr); + outptr += o; + } + wantlen -= t; + if (t < s) + break; + if (need_resched) + schedule(); + } + + len = outptr; + + if (wantlen) + { + printk("qcam: short read.\n"); + if (is_bi_dir) + parport_frob_control(q->pport, 0x20, 0); + qc_setup(q); + kfree(tmpbuf); + return len; + } + + if (is_bi_dir) + { + int l; + do { + l = qcam_read_bytes(q, tmpbuf, 3); + if (need_resched) + schedule(); + } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + qcam_set_ack(q, 0); + if (qcam_await_ready1(q, 1)) + { + printk("qcam: no ack after EOF\n"); + parport_frob_control(q->pport, 0x20, 0); + qc_setup(q); + kfree(tmpbuf); + return len; + } + parport_frob_control(q->pport, 0x20, 0); + udelay(3000); + qcam_set_ack(q, 1); + if (qcam_await_ready1(q, 0)) + { + printk("qcam: no ack to port turnaround\n"); + qc_setup(q); + kfree(tmpbuf); + return len; + } + } + else + { + int l; + do { + l = qcam_read_bytes(q, tmpbuf, 1); + if (need_resched) + schedule(); + } while (l && tmpbuf[0] == 0x7e); + l = qcam_read_bytes(q, tmpbuf+1, 2); + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + } + + kfree(tmpbuf); + + qcam_write_data(q, 0); + + return len; +} + +/* + * Video4linux interfacing + */ + +static int qcam_open(struct video_device *dev, int flags) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void qcam_close(struct video_device *dev) +{ + MOD_DEC_USE_COUNT; +} + +static int qcam_init_done(struct video_device *dev) +{ + return 0; +} + +static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct qcam_device *qcam=(struct qcam_device *)dev; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name, "Quickcam"); + b.type = VID_TYPE_CAPTURE|VID_TYPE_SCALES; + b.channels = 1; + b.audios = 0; + b.maxwidth = 320; + b.maxheight = 240; + b.minwidth = 80; + b.minheight = 60; + if(copy_to_user(arg, &b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.channel!=0) + return -EINVAL; + v.flags=0; + v.tuners=0; + /* Good question.. its composite or SVHS so.. */ + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "Camera"); + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSCHAN: + { + int v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v!=0) + return -EINVAL; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + strcpy(v.name, "Format"); + v.rangelow=0; + v.rangehigh=0; + v.flags= 0; + v.mode = VIDEO_MODE_AUTO; + if(copy_to_user(arg,&v,sizeof(v))!=0) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + if(v.mode!=VIDEO_MODE_AUTO) + return -EINVAL; + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p; + p.colour=0x8000; + p.hue=0x8000; + p.brightness=qcam->brightness<<8; + p.contrast=qcam->contrast<<8; + p.whiteness=qcam->whitebal<<8; + p.depth=qcam->bpp; + p.palette=VIDEO_PALETTE_RGB24; + if(copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + if(copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + + if (p.palette != VIDEO_PALETTE_RGB24) + return -EINVAL; + + /* + * Now load the camera. + */ + qcam->brightness = p.brightness>>8; + qcam->contrast = p.contrast>>8; + qcam->whitebal = p.whiteness>>8; + qcam->bpp = p.depth; + + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + if(copy_from_user(&vw, arg,sizeof(vw))) + return -EFAULT; + if(vw.flags) + return -EINVAL; + if(vw.clipcount) + return -EINVAL; + if(vw.height<60||vw.height>240) + return -EINVAL; + if(vw.width<80||vw.width>320) + return -EINVAL; + + qcam->width = 320; + qcam->height = 240; + qcam->transfer_scale = 4; + + if(vw.width>=160 && vw.height>=120) + { + qcam->transfer_scale = 2; + } + if(vw.width>=320 && vw.height>=240) + { + qcam->width = 320; + qcam->height = 240; + qcam->transfer_scale = 1; + } + /* Ok we figured out what to use from our wide choice */ + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + vw.x=0; + vw.y=0; + vw.width=qcam->width/qcam->transfer_scale; + vw.height=qcam->height/qcam->transfer_scale; + vw.chromakey=0; + vw.flags=0; + if(copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + return -EINVAL; + case VIDIOCGFBUF: + return -EINVAL; + case VIDIOCSFBUF: + return -EINVAL; + case VIDIOCKEY: + return 0; + case VIDIOCGFREQ: + return -EINVAL; + case VIDIOCSFREQ: + return -EINVAL; + case VIDIOCGAUDIO: + return -EINVAL; + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static long qcam_read(struct video_device *v, char *buf, unsigned long count, int noblock) +{ + struct qcam_device *qcam=(struct qcam_device *)v; + int len; + parport_claim_or_block(qcam->pdev); + /* Probably should have a semaphore against multiple users */ + len = qc_capture(qcam, buf,count); + parport_release(qcam->pdev); + return len; +} + +/* video device template */ +static struct video_device qcam_template= +{ + "Colour Quickcam", + VID_TYPE_CAPTURE, + VID_HARDWARE_QCAM_C, + qcam_open, + qcam_close, + qcam_read, + qcam_write, + qcam_ioctl, + NULL, + qcam_init_done, + NULL, + 0, + 0 +}; + +/* Initialize the QuickCam driver control structure. */ + +static struct qcam_device *qcam_init(struct parport *port) +{ + struct qcam_device *q; + + q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + + q->pport = port; + q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, + NULL, 0, NULL); + + q->bidirectional = (q->pport->modes & PARPORT_MODE_PCPS2)?1:0; + + if (q->pdev == NULL) + { + printk(KERN_ERR "c-qcam: couldn't register for %s.\n", + port->name); + kfree(q); + return NULL; + } + + memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); + + q->width = 320; + q->height = 240; + q->bpp = 32; + q->transfer_scale = 1; + q->contrast = 192; + q->brightness = 240; + q->whitebal = 128; + q->top = 1; + q->left = 14; + return q; +} + +#define MAX_CAMS 4 +static struct qcam_device *qcams[MAX_CAMS]; +static unsigned int num_cams = 0; + +int init_cqcam(struct parport *port) +{ + struct qcam_device *qcam; + + if (num_cams == MAX_CAMS) + { + printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); + return -ENOSPC; + } + + qcam = qcam_init(port); + if (qcam==NULL) + return -ENODEV; + + parport_claim_or_block(qcam->pdev); + + qc_reset(qcam); + + if (qc_detect(qcam)==0) + { + parport_release(qcam->pdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + qc_setup(qcam); + + parport_release(qcam->pdev); + + printk(KERN_INFO "Connectix Colour Quickcam on %s\n", + qcam->pport->name); + + if (video_register_device(&qcam->vdev)==-1) + { + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + qcams[num_cams++] = qcam; + + return 0; +} + +void close_cqcam(struct qcam_device *qcam) +{ + video_unregister_device(&qcam->vdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); +} + +#ifdef MODULE +int init_module(void) +{ + struct parport *port; + + for (port = parport_enumerate(); port; port=port->next) + init_cqcam(port); + + return (num_cams)?0:-ENODEV; +} + +void cleanup_module(void) +{ + unsigned int i; + for (i = 0; i < num_cams; i++) + close_cqcam(qcams[i]); +} +#else +__initfunc(int init_colour_qcams(struct video_init *unused)) +{ + struct parport *port; + + for (port = parport_enumerate(); port; port=port->next) + init_cqcam(port); +} +#endif diff -u --recursive --new-file v2.1.78/linux/drivers/char/c-qcam.h linux/drivers/char/c-qcam.h --- v2.1.78/linux/drivers/char/c-qcam.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/c-qcam.h Mon Jan 12 14:46:16 1998 @@ -0,0 +1,18 @@ +struct qcam_device { + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + int width, height; + int bpp; + int contrast, brightness, whitebal; + int transfer_scale; + int top, left; + unsigned int bidirectional; +}; + +#define QC_1_1 0 +#define QC_2_1 2 +#define QC_4_1 4 +#define QC_16BPP 8 +#define QC_32BPP 16 +#define QC_24BPP 24 diff -u --recursive --new-file v2.1.78/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.1.78/linux/drivers/char/pcwd.c Tue Dec 23 16:30:59 1997 +++ linux/drivers/char/pcwd.c Mon Jan 12 15:12:42 1998 @@ -33,6 +33,7 @@ * 971210 Disable board on initialisation in case board already ticking. * 971222 Changed open/close for temperature handling * Michael Meskes . + * 980112 Used minor numbers from include/linux/miscdevice.h */ #include @@ -67,10 +68,6 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; #define WD_VER "1.0 (11/18/96)" -#define WD_MINOR 130 /* Minor device number */ -#ifndef TEMP_MINOR -#define TEMP_MINOR 131 /* Uses the same as WDT */ -#endif /* * It should be noted that PCWD_REVISION_B was removed because A and B @@ -382,7 +379,7 @@ { switch (MINOR(ino->i_rdev)) { - case WD_MINOR: + case WATCHDOG_MINOR: if (is_open) return -EBUSY; MOD_INC_USE_COUNT; @@ -424,7 +421,7 @@ static int pcwd_close(struct inode *ino, struct file *filep) { MOD_DEC_USE_COUNT; - if (MINOR(ino->i_rdev)==WD_MINOR) + if (MINOR(ino->i_rdev)==WATCHDOG_MINOR) { is_open = 0; #ifndef CONFIG_WATCHDOG_NOWAYOUT @@ -527,8 +524,8 @@ }; static struct miscdevice pcwd_miscdev = { - WD_MINOR, - "pcwatchdog", + WATCHDOG_MINOR, + "watchdog", &pcwd_fops }; diff -u --recursive --new-file v2.1.78/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v2.1.78/linux/drivers/char/psaux.c Sat Oct 25 02:44:15 1997 +++ linux/drivers/char/psaux.c Mon Jan 12 15:13:24 1998 @@ -30,6 +30,9 @@ * 3-Jul-96, 22-Aug-96 Roman Hodek * * Cleanup by Martin Mares, 01-Jun-97 (now uses the new PC kbd include) + * + * Renamed misc. name to "psaux",more in keeping with Documentation/devices.txt + * 13-Jan-1998, Richard Gooch */ /* Uncomment the following line if your mouse needs initialization. */ @@ -589,7 +592,7 @@ * forget about the Aux port and use the *_qp functions. */ static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "ps2aux", &psaux_fops + PSMOUSE_MINOR, "psaux", &psaux_fops }; __initfunc(int psaux_init(void)) diff -u --recursive --new-file v2.1.78/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.1.78/linux/drivers/char/softdog.c Wed Dec 10 11:12:43 1997 +++ linux/drivers/char/softdog.c Mon Jan 12 15:12:42 1998 @@ -37,7 +37,6 @@ #include #include -#define WATCHDOG_MINOR 130 #define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ static int soft_margin = TIMER_MARGIN; /* in seconds */ @@ -177,7 +176,7 @@ static struct miscdevice softdog_miscdev= { WATCHDOG_MINOR, - "softdog", + "watchdog", &softdog_fops }; diff -u --recursive --new-file v2.1.78/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.1.78/linux/drivers/char/videodev.c Mon Dec 1 12:04:12 1997 +++ linux/drivers/char/videodev.c Mon Jan 12 14:46:16 1998 @@ -52,11 +52,14 @@ #ifdef CONFIG_VIDEO_BT848 {"bttv", init_bttv_cards}, #endif +#ifdef CONFIG_VIDEO_CQCAM + {"c-qcam", init_colour_qcams}, +#endif #ifdef CONFIG_VIDEO_BWQCAM - {"bttv", init_bw_qcams}, + {"bw-qcam", init_bw_qcams}, #endif #ifdef CONFIG_VIDEO_PMS - {"bttv", init_pms_cards}, + {"PMS", init_pms_cards}, #endif {"end", NULL} }; diff -u --recursive --new-file v2.1.78/linux/drivers/char/wd501p.h linux/drivers/char/wd501p.h --- v2.1.78/linux/drivers/char/wd501p.h Thu Dec 12 06:51:09 1996 +++ linux/drivers/char/wd501p.h Mon Jan 12 15:12:42 1998 @@ -20,9 +20,6 @@ */ #include - -#define WATCHDOG_MINOR 130 /* Watchdog timer */ -#define TEMP_MINOR 131 /* Temperature Sensor */ #define WDT_COUNT0 (io+0) #define WDT_COUNT1 (io+1) diff -u --recursive --new-file v2.1.78/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.1.78/linux/drivers/char/wdt.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/char/wdt.c Mon Jan 12 15:12:42 1998 @@ -333,7 +333,7 @@ static struct miscdevice wdt_miscdev= { WATCHDOG_MINOR, - "wdt", + "watchdog", &wdt_fops }; diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/Config.in linux/drivers/fc4/Config.in --- v2.1.78/linux/drivers/fc4/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/Config.in Mon Jan 12 15:19:36 1998 @@ -0,0 +1,17 @@ +# +# FC4 device configuration +# +mainmenu_option next_comment +comment 'Fibre Channel support' + +tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4 m +if [ ! "$CONFIG_FC4" = "n" ]; then + comment 'FC4 drivers' + tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC m + comment 'FC4 targets' + dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO "$CONFIG_SCSI" +else + define_bool CONFIG_FC4_SOC n + define_bool CONFIG_SCSI_PLUTO n +fi +endmenu diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/Makefile linux/drivers/fc4/Makefile --- v2.1.78/linux/drivers/fc4/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/Makefile Mon Jan 12 15:19:36 1998 @@ -0,0 +1,39 @@ +# File: drivers/fc4/Makefile +# +# Makefile for the Linux Fibre Channel device drivers. +# + +L_TARGET := fc4.a +M_OBJS := +MOD_LIST_NAME := FC4_MODULES + +include ../../.config + +ifeq ($(CONFIG_FC4),y) + FC4 = fc.o + ifeq ($(CONFIG_MODULES),y) + O_TARGET := fc_n_syms.o + O_OBJS := fc.o + OX_OBJS := fc_syms.o + FC4 := $(O_TARGET) + endif + L_OBJS += $(FC4) +else + ifeq ($(CONFIG_FC4),m) + MIX_OBJS += fc_syms.o + M_OBJS += fc4.o + endif +endif + +ifeq ($(CONFIG_FC4_SOC),y) +L_OBJS += soc.o +else + ifeq ($(CONFIG_FC4_SOC),m) + M_OBJS += soc.o + endif +endif + +include $(TOPDIR)/Rules.make + +fc4.o: $(MIX_OBJS) fc.o + $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) fc.o diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/fc.c linux/drivers/fc4/fc.c --- v2.1.78/linux/drivers/fc4/fc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/fc.c Mon Jan 12 15:19:36 1998 @@ -0,0 +1,688 @@ +/* fc.c: Generic Fibre Channel and FC4 SCSI driver. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 Jiri Hanika (geo@ff.cuni.cz) + * + * Sources: + * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 + * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "fcp_scsi.h" +#include "../scsi/hosts.h" + +/* #define FCDEBUG */ + +#define fc_printk printk ("%s: ", fc->name); printk + +#ifdef FCDEBUG +#define FCD(x) fc_printk x; +#define FCND(x) printk ("FC: "); printk x; +#else +#define FCD(x) +#define FCND(x) +#endif + +#ifdef __sparc__ +static inline void *fc_dma_alloc(long size, char *name, dma_handle *dma) +{ + return (void *) sparc_dvma_malloc (size, "FCP SCSI cmd & rsp queues", dma); +} + +static inline dma_handle fc_sync_dma_entry(void *buf, int len, fc_channel *fc) +{ + return mmu_get_scsi_one (buf, len, fc->dev->my_bus); +} + +static inline void fc_sync_dma_exit(void *buf, long size, fc_channel *fc) +{ + mmu_release_scsi_one ((u32)(long)buf, size, fc->dev->my_bus); +} + +static inline void fc_sync_dma_entry_sg(struct scatterlist *list, int count, fc_channel *fc) +{ + mmu_get_scsi_sgl((struct mmu_sglist *)list, count - 1, fc->dev->my_bus); +} + +static inline void fc_sync_dma_exit_sg(struct scatterlist *list, int count, fc_channel *fc) +{ + mmu_release_scsi_sgl ((struct mmu_sglist *)list, count - 1, fc->dev->my_bus); +} +#else +#error Port this +#endif + +#define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp)) +#define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->host->hostdata[0])) +#define SC_FCMND(fcmnd) ((Scsi_Cmnd *)((long)fcmnd - (long)&(((Scsi_Cmnd *)0)->SCp))) + +static void fcp_scsi_insert_queue (fc_channel *fc, int no, fcp_cmnd *fcmd) +{ + if (!fc->scsi_que[no]) { + fc->scsi_que[no] = fcmd; + fcmd->next = fcmd; + fcmd->prev = fcmd; + } else { + fc->scsi_que[no]->prev->next = fcmd; + fcmd->prev = fc->scsi_que[no]->prev; + fc->scsi_que[no]->prev = fcmd; + fcmd->next = fc->scsi_que[no]; + } +} + +static void fcp_scsi_remove_queue (fc_channel *fc, int no, fcp_cmnd *fcmd) +{ + if (fcmd == fcmd->next) { + fc->scsi_que[no] = NULL; + return; + } + if (fcmd == fc->scsi_que[no]) + fc->scsi_que[no] = fcmd->next; + fcmd->prev->next = fcmd->next; + fcmd->next->prev = fcmd->prev; +} + +fc_channel *fc_channels = NULL; + +#define LSMAGIC 0x2a3b4d2a +typedef struct { + /* Must be first */ + struct semaphore sem; + int magic; + int count; + logi *logi; + fcp_cmnd *fcmds; + atomic_t todo; + struct timer_list timer; + int grace[1]; +} ls; + +#define LSOMAGIC 0x2a3c4e3c +typedef struct { + /* Must be first */ + struct semaphore sem; + int magic; + int count; + fcp_cmnd *fcmds; + atomic_t todo; + struct timer_list timer; +} lso; + +static void fcp_login_timeout(unsigned long data) +{ + ls *l = (ls *)data; + FCND(("Login timeout\n")) + up(&l->sem); +} + +static void fcp_login_done(fc_channel *fc, int i, int status) +{ + fcp_cmnd *fcmd; + logi *plogi; + fc_hdr *fch; + ls *l = (ls *)fc->ls; + + FCD(("Login done %d %d\n", i, status)) + if (i < l->count) { + if (fc->state == FC_STATE_FPORT_OK) { + FCD(("Additional FPORT_OK received with status %d\n", status)) + return; + } + switch (status) { + case FC_STATUS_OK: /* Oh, we found a fabric */ + case FC_STATUS_P_RJT: /* Oh, we haven't found any */ + fc->state = FC_STATE_FPORT_OK; + fcmd = l->fcmds + i; + plogi = l->logi + 3 * i; + fc_sync_dma_exit (plogi, 3 * sizeof(logi), fc); + plogi->code = LS_PLOGI; + memcpy (&plogi->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn)); + memcpy (&plogi->node_wwn, &fc->wwn_node, sizeof(fc_wwn)); + memcpy (&plogi->common, fc->common_svc, sizeof(common_svc_parm)); + memcpy (&plogi->class1, fc->class_svcs, 3*sizeof(svc_parm)); + fch = &fcmd->fch; + fcmd->token += l->count; + fcmd->rsp += sizeof(logi); + FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, fc->did); + FILL_FCHDR_SID(fch, fc->sid); +#ifdef FCDEBUG + { + int i; + unsigned *x = (unsigned *)plogi; + printk ("logi: "); + for (i = 0; i < 21; i++) + printk ("%08x ", x[i]); + printk ("\n"); + } +#endif + fc_sync_dma_entry (plogi, 3 * sizeof(logi), fc); + if (fc->hw_enque (fc, fcmd)) + printk ("FC: Cannot enque PLOGI packet on %s\n", fc->name); + break; + case FC_STATUS_ERR_OFFLINE: + fc->state = FC_STATE_MAYBEOFFLINE; + FCD (("FC is offline %d\n", l->grace[i])) + break; + default: + printk ("FLOGI failed for %s with status %d\n", fc->name, status); + /* Do some sort of error recovery here */ + break; + } + } else { + i -= l->count; + if (fc->state != FC_STATE_FPORT_OK) { + FCD(("Unexpected N-PORT rsp received")) + return; + } + switch (status) { + case FC_STATUS_OK: + plogi = l->logi + 3 * i; + fc_sync_dma_exit (plogi, 3 * sizeof(logi), fc); + if (!fc->wwn_dest.lo && !fc->wwn_dest.hi) { + memcpy (&fc->wwn_dest, &plogi[1].node_wwn, sizeof(fc_wwn)); + FCD(("Dest WWN %08x%08x\n", *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo)) + } else if (fc->wwn_dest.lo != plogi[1].node_wwn.lo || + fc->wwn_dest.hi != plogi[1].node_wwn.hi) { + printk ("%s: mismatch in wwns. Got %08x%08x, expected %08x%08x\n", + fc->name, + *(u32 *)&plogi[1].node_wwn, plogi[1].node_wwn.lo, + *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo); + } + fc->state = FC_STATE_ONLINE; + printk ("%s: ONLINE\n", fc->name); + if (atomic_dec_and_test (&l->todo)) + up(&l->sem); + break; + case FC_STATUS_ERR_OFFLINE: + fc->state = FC_STATE_OFFLINE; + fc_sync_dma_exit (l->logi + 3 * i, 3 * sizeof(logi), fc); + printk ("%s: FC is offline\n", fc->name); + if (atomic_dec_and_test (&l->todo)) + up(&l->sem); + break; + default: + printk ("PLOGI failed for %s with status %d\n", fc->name, status); + /* Do some sort of error recovery here */ + break; + } + } +} + +void fcp_register(fc_channel *fc, u8 type, int unregister) +{ + int size, i; + + if (type == TYPE_SCSI_FCP) { + if (!unregister) { + fc->scsi_cmd_pool = + (fcp_cmd *) fc_dma_alloc (fc->can_queue * (sizeof (fcp_cmd) + fc->rsp_size), + "FCP SCSI cmd & rsp queues", &fc->dma_scsi_cmd); + fc->scsi_rsp_pool = (char *)(fc->scsi_cmd_pool + fc->can_queue); + fc->dma_scsi_rsp = fc->dma_scsi_cmd + fc->can_queue * sizeof (fcp_cmd); + fc->scsi_bitmap_end = ((fc->can_queue + 63) & ~63); + size = fc->scsi_bitmap_end / 8; + fc->scsi_bitmap = kmalloc (size, GFP_KERNEL); + memset (fc->scsi_bitmap, 0, size); + for (i = fc->can_queue; i < fc->scsi_bitmap_end; i++) + set_bit (i, fc->scsi_bitmap); + fc->scsi_free = fc->can_queue; + fc->token_tab = (fcp_cmnd **)kmalloc(fc->can_queue * sizeof(fcp_cmnd*), GFP_KERNEL); + } else { + fc->scsi_name[0] = 0; + kfree (fc->scsi_bitmap); + kfree (fc->token_tab); + } + } else + printk ("FC: %segistering unknown type %02x\n", unregister ? "Unr" : "R", type); +} + +static void fcp_scsi_done(Scsi_Cmnd *SCpnt); + +static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hdr *fch) +{ + fcp_cmnd *fcmd; + fcp_rsp *rsp; + int host_status; + Scsi_Cmnd *SCpnt; + int sense_len; + int rsp_status; + + fcmd = fc->token_tab[token]; + if (!fcmd) return; + rsp = (fcp_rsp *) (fc->scsi_rsp_pool + fc->rsp_size * token); + SCpnt = SC_FCMND(fcmd); + + if (SCpnt->done != fcp_scsi_done) + return; + + rsp_status = rsp->fcp_status; + switch (status) { + case FC_STATUS_OK: + host_status=DID_OK; + + if (rsp_status & FCP_STATUS_RESID) { +#ifdef FCDEBUG + FCD(("Resid %d\n", rsp->fcp_resid)) + { + fcp_cmd *cmd = fc->scsi_cmd_pool + token; + int i; + + printk ("Command "); + for (i = 0; i < sizeof(fcp_cmd); i+=4) + printk ("%08x ", *(u32 *)(((char *)cmd)+i)); + printk ("\nResponse "); + for (i = 0; i < fc->rsp_size; i+=4) + printk ("%08x ", *(u32 *)(((char *)rsp)+i)); + printk ("\n"); + } +#endif + } + + if (rsp_status & FCP_STATUS_SENSE_LEN) { + sense_len = rsp->fcp_sense_len; + if (sense_len > sizeof(SCpnt->sense_buffer)) sense_len = sizeof(SCpnt->sense_buffer); + memcpy(SCpnt->sense_buffer, ((char *)(rsp+1)), sense_len); + } + + if (fcmd->data) { + if (SCpnt->use_sg) + fc_sync_dma_exit_sg((struct scatterlist *)SCpnt->buffer, SCpnt->use_sg, fc); + else + fc_sync_dma_exit(SCpnt->request_buffer, SCpnt->request_bufflen, fc); + } + break; + default: + host_status=DID_ERROR; + FCD(("Wrong FC status %d for token %d\n", status, token)) + break; + } + + if (status_byte(rsp_status) == QUEUE_FULL) { + printk ("%s: (%d,%d) Received rsp_status 0x%x\n", fc->name, SCpnt->channel, SCpnt->target, rsp_status); + } + + SCpnt->result = (host_status << 16) | (rsp_status & 0xff); + SCpnt->done = fcmd->done; + fcmd->done=NULL; + clear_bit(token, fc->scsi_bitmap); + fc->scsi_free++; + SCpnt->scsi_done(SCpnt); +} + +void fcp_receive_solicited(fc_channel *fc, int proto, int token, int status, fc_hdr *fch) +{ + FCD(("Receive solicited %d %d %d\n", proto, token, status)) + switch (proto) { + case TYPE_SCSI_FCP: + fcp_scsi_receive(fc, token, status, fch); break; + case TYPE_EXTENDED_LS: + if (fc->ls && ((ls *)(fc->ls))->magic == LSMAGIC) { + ls *l = (ls *)fc->ls; + int i = (token >= l->count) ? token - l->count : token; + + /* Make us sure */ + if ((unsigned)i < l->count && l->fcmds[i].fc == fc) { + fcp_login_done(fc, token, status); + break; + } + } + break; + case PROTO_OFFLINE: + if (fc->ls && ((lso *)(fc->ls))->magic == LSOMAGIC) { + lso *l = (lso *)fc->ls; + + if ((unsigned)token < l->count && l->fcmds[token].fc == fc) { + /* Wow, OFFLINE response arrived :) */ + FCD(("OFFLINE Response arrived\n")) + fc->state = FC_STATE_OFFLINE; + if (atomic_dec_and_test (&l->todo)) + up(&l->sem); + } + } + break; + + default: + break; + } +} + +void fcp_state_change(fc_channel *fc, int state) +{ + FCD(("state_change %d %d\n", state, fc->state)) + if (state == FC_STATE_ONLINE && fc->state == FC_STATE_MAYBEOFFLINE) + fc->state = FC_STATE_UNINITED; + else if (state == FC_STATE_ONLINE) + printk (KERN_WARNING "%s: state change to ONLINE\n", fc->name); + else + printk (KERN_ERR "%s: state change to OFFLINE\n", fc->name); +} + +int fcp_initialize(fc_channel *fcchain, int count) +{ + fc_channel *fc; + fcp_cmnd *fcmd; + int i, retry, ret; + ls *l; + + FCND(("fcp_inititialize %08lx\n", (long)fcp_init)) + FCND(("fc_channels %08lx\n", (long)fc_channels)) + FCND((" SID %d DID %d\n", fcchain->sid, fcchain->did)) + l = kmalloc(sizeof (ls) + count * sizeof(int), GFP_KERNEL); + if (!l) { + printk ("FC: Cannot allocate memory for initialization\n"); + return -ENOMEM; + } + memset (l, 0, sizeof(ls) + count * sizeof(int)); + l->magic = LSMAGIC; + l->count = count; + FCND(("FCP Init for %d channels\n", count)) + l->sem = MUTEX_LOCKED; + l->timer.function = fcp_login_timeout; + l->timer.data = (unsigned long)l; + atomic_set (&l->todo, count); + l->logi = kmalloc (count * 3 * sizeof(logi), GFP_DMA); + l->fcmds = kmalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); + if (!l->logi || !l->fcmds) { + if (l->logi) kfree (l->logi); + if (l->fcmds) kfree (l->fcmds); + kfree (l); + printk ("FC: Cannot allocate DMA memory for initialization\n"); + return -ENOMEM; + } + memset (l->logi, 0, count * 3 * sizeof(logi)); + memset (l->fcmds, 0, count * sizeof(fcp_cmnd)); + FCND(("Initializing FLOGI packets\n")) + for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { + fc_hdr *fch; + + FCD(("SID %d DID %d\n", fc->sid, fc->did)) + fc->state = FC_STATE_UNINITED; + fcmd = l->fcmds + i; + fc->login = fcmd; + fc->ls = (void *)l; + fch = &fcmd->fch; + FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); + FILL_FCHDR_SID(fch, 0); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + fch->param = 0; + l->logi [3 * i].code = LS_FLOGI; + fcmd->cmd = fc_sync_dma_entry (l->logi + 3 * i, 3 * sizeof(logi), fc); + fcmd->rsp = fcmd->cmd + sizeof(logi); + fcmd->cmdlen = sizeof(logi); + fcmd->rsplen = sizeof(logi); + fcmd->data = (dma_handle)NULL; + fcmd->class = FC_CLASS_SIMPLE; + fcmd->proto = TYPE_EXTENDED_LS; + fcmd->token = i; + fcmd->fc = fc; + } + for (retry = 0; retry < 8; retry++) { + FCND(("Sending FLOGI/PLOGI packets\n")) + for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { + if (fc->state == FC_STATE_ONLINE || fc->state == FC_STATE_OFFLINE) + continue; + disable_irq(fc->irq); + if (fc->state == FC_STATE_MAYBEOFFLINE) { + if (!l->grace[i]) { + l->grace[i]++; + FCD(("Grace\n")) + } else { + fc->state = FC_STATE_OFFLINE; + enable_irq(fc->irq); + fc_sync_dma_exit (l->logi + 3 * i, 3 * sizeof(logi), fc); + if (atomic_dec_and_test (&l->todo)) + goto all_done; + } + } + ret = fc->hw_enque (fc, fc->login); + enable_irq(fc->irq); + if (ret) printk ("FC: Cannot enque FLOGI packet on %s\n", fc->name); + } + + l->timer.expires = jiffies + 5 * HZ; + add_timer(&l->timer); + + down(&l->sem); + if (!atomic_read(&l->todo)) { + FCND(("All channels answered in time\n")) + break; /* All fc channels have answered us */ + } + } +all_done: + for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i += 3) { + switch (fc->state) { + case FC_STATE_ONLINE: break; + case FC_STATE_OFFLINE: break; + default: fc_sync_dma_exit (l->logi + i, 3 * sizeof(logi), fc); + break; + } + fc->ls = NULL; + } + del_timer(&l->timer); + kfree (l->logi); + kfree (l->fcmds); + kfree (l); + return 0; +} + +int fcp_forceoffline(fc_channel *fcchain, int count) +{ + fc_channel *fc; + fcp_cmnd *fcmd; + int i, ret; + lso l; + + memset (&l, 0, sizeof(lso)); + l.count = count; + l.magic = LSOMAGIC; + FCND(("FCP Force Offline for %d channels\n", count)) + l.sem = MUTEX_LOCKED; + l.timer.function = fcp_login_timeout; + l.timer.data = (unsigned long)&l; + atomic_set (&l.todo, count); + l.fcmds = kmalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); + if (!l.fcmds) { + kfree (l.fcmds); + printk ("FC: Cannot allocate memory for forcing offline\n"); + return -ENOMEM; + } + memset (l.fcmds, 0, count * sizeof(fcp_cmnd)); + FCND(("Initializing OFFLINE packets\n")) + for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { + fc->state = FC_STATE_UNINITED; + fcmd = l.fcmds + i; + fc->login = fcmd; + fc->ls = (void *)&l; + fcmd->class = FC_CLASS_OFFLINE; + fcmd->proto = PROTO_OFFLINE; + fcmd->token = i; + fcmd->fc = fc; + disable_irq(fc->irq); + ret = fc->hw_enque (fc, fc->login); + enable_irq(fc->irq); + if (ret) printk ("FC: Cannot enque OFFLINE packet on %s\n", fc->name); + } + + l.timer.expires = jiffies + 5 * HZ; + add_timer(&l.timer); + down(&l.sem); + del_timer(&l.timer); + + kfree (l.fcmds); + return 0; +} + +int fcp_init(fc_channel *fcchain) +{ + fc_channel *fc; + int count=0; + + for (fc = fcchain; fc; fc = fc->next) { + fc->fcp_register = fcp_register; + fc->fcp_state_change = fcp_state_change; + count++; + } + + fcp_initialize (fcchain, count); + + if (!fc_channels) + fc_channels = fcchain; + else { + for (fc = fc_channels; fc->next; fc = fc->next); + fc->next = fcchain; + } + return 0; +} + +static void fcp_scsi_done (Scsi_Cmnd *SCpnt) +{ + if (FCP_CMND(SCpnt)->done) + FCP_CMND(SCpnt)->done(SCpnt); +} + +static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare) +{ + if (prepare) { + long i; + fcp_cmd *cmd; + u32 fcp_cntl; + + i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end); + set_bit (i, fc->scsi_bitmap); + fcmd->token = i; + cmd = fc->scsi_cmd_pool + i; + FCD(("Chose token %ld %08lx\n", i, (long)cmd)) + if (fc->encode_addr (SCpnt, cmd->fcp_addr)) { + /* Invalid channel/id/lun and couldn't map it into fcp_addr */ + clear_bit (i, fc->scsi_bitmap); + SCpnt->result = (DID_BAD_TARGET << 16); + SCpnt->scsi_done(SCpnt); + return 0; + } + fc->scsi_free--; + fc->token_tab[fcmd->token] = fcmd; + + if (SCpnt->device->tagged_supported) { + if (jiffies - fc->ages[SCpnt->channel * fc->targets + SCpnt->target] > (5 * 60 * HZ)) { + fc->ages[SCpnt->channel * fc->targets + SCpnt->target] = jiffies; + fcp_cntl = FCP_CNTL_QTYPE_ORDERED; + } else + fcp_cntl = FCP_CNTL_QTYPE_SIMPLE; + } else + fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED; + if (!SCpnt->request_bufflen && !SCpnt->use_sg) { + cmd->fcp_cntl = fcp_cntl; + fcmd->data = (dma_handle)NULL; + } else { + switch (SCpnt->cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + cmd->fcp_cntl = (FCP_CNTL_WRITE | fcp_cntl); break; + default: + cmd->fcp_cntl = (FCP_CNTL_READ | fcp_cntl); break; + } + if (!SCpnt->use_sg) { + cmd->fcp_data_len = SCpnt->request_bufflen; + fcmd->data = fc_sync_dma_entry ((char *)SCpnt->request_buffer, + SCpnt->request_bufflen, fc); + } else { + struct scatterlist *sg = (struct scatterlist *)SCpnt->buffer; + + FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length)) + if (SCpnt->use_sg > 1) printk ("%s: SG for use_sg > 1 not handled yet\n", fc->name); + fc_sync_dma_entry_sg (sg, SCpnt->use_sg, fc); + fcmd->data = sg->dvma_address; + cmd->fcp_data_len = sg->length; + } + } + memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len); + memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len); + FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8))) + } + FCD(("Trying to enque %08x\n", (int)fcmd)) + if (!fc->scsi_que[1]) { + if (!fc->hw_enque (fc, fcmd)) { + FCD(("hw_enque succeeded for %08x\n", (int)fcmd)) + return 0; + } + } + FCD(("Putting into que1 %08x\n", (int)fcmd)) + fcp_scsi_insert_queue (fc, 1, fcmd); + return 0; +} + +int fcp_scsi_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *)) +{ + fcp_cmnd *fcmd = FCP_CMND(SCpnt); + fc_channel *fc = FC_SCMND(SCpnt); + + FCD(("Entering SCSI queuecommand %08x\n", (int)fcmd)) + if (SCpnt->done != fcp_scsi_done) { + fcmd->done = SCpnt->done; + SCpnt->done = fcp_scsi_done; + SCpnt->scsi_done = done; + fcmd->proto = TYPE_SCSI_FCP; + if (!fc->scsi_free) { + FCD(("Putting into que0\n")) + fcp_scsi_insert_queue (fc, 0, fcmd); + return 1; + } + return fcp_scsi_queue_it(fc, SCpnt, fcmd, 1); + } + return fcp_scsi_queue_it(fc, SCpnt, fcmd, 0); +} + +void fcp_queue_empty(fc_channel *fc) +{ + fcp_cmnd *fcmd; + FCD(("Queue empty\n")) + while ((fcmd = fc->scsi_que[1])) { + /* The hw tell us we can try again queue some packet */ + if (fc->hw_enque (fc, fcmd)) + return; + fcp_scsi_remove_queue (fc, 1, fcmd); + } +} + +int fcp_scsi_abort(Scsi_Cmnd *SCpnt) +{ + printk ("FC: AIEEE, abort!\n"); + return 0; +} + +int fcp_scsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + printk ("FC: AIEEE, reset!\n"); + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/fc.h linux/drivers/fc4/fc.h --- v2.1.78/linux/drivers/fc4/fc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/fc.h Mon Jan 12 15:19:36 1998 @@ -0,0 +1,222 @@ +/* fc.h: Definitions for Fibre Channel Physical and Signaling Interface. + * + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Sources: + * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 + * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 + */ + +#ifndef __FC_H +#define __FC_H + +/* World Wide Name */ +#define NAAID_IEEE 1 +#define NAAID_IEEE_EXT 2 +#define NAAID_LOCAL 3 +#define NAAID_IP 4 +#define NAAID_CCITT 12 +#define NAAID_CCITT_GRP 14 + +typedef struct { + u32 naaid:4; + u32 nportid:12; + u32 hi:16; + u32 lo; +} fc_wwn; + +/* Frame header for FC-PH frames */ + +/* r_ctl field */ +#define R_CTL_DEVICE_DATA 0x00 /* FC4 Device_Data frame */ +#define R_CTL_EXTENDED_SVC 0x20 /* Extended Link_Data frame */ +#define R_CTL_FC4_SVC 0x30 /* FC4 Link_Data frame */ +#define R_CTL_VIDEO 0x40 /* Video_Data frame */ +#define R_CTL_BASIC_SVC 0x80 /* Basic Link_Data frame */ +#define R_CTL_LINK_CTL 0xc0 /* Link_Control frame */ +/* FC4 Device_Data frames */ +#define R_CTL_UNCATEGORIZED 0x00 +#define R_CTL_SOLICITED_DATA 0x01 +#define R_CTL_UNSOL_CONTROL 0x02 +#define R_CTL_SOLICITED_CONTROL 0x03 +#define R_CTL_UNSOL_DATA 0x04 +#define R_CTL_XFER_RDY 0x05 +#define R_CTL_COMMAND 0x06 +#define R_CTL_STATUS 0x07 +/* Basic Link_Data frames */ +#define R_CTL_LS_NOP 0x80 +#define R_CTL_LS_ABTS 0x81 +#define R_CTL_LS_RMC 0x82 +#define R_CTL_LS_BA_ACC 0x84 +#define R_CTL_LS_BA_RJT 0x85 +/* Extended Link_Data frames */ +#define R_CTL_ELS_REQ 0x22 +#define R_CTL_ELS_RSP 0x23 +/* Link_Control frames */ +#define R_CTL_ACK_1 0xc0 +#define R_CTL_ACK_N 0xc1 +#define R_CTL_P_RJT 0xc2 +#define R_CTL_F_RJT 0xc3 +#define R_CTL_P_BSY 0xc4 +#define R_CTL_F_BSY_DF 0xc5 +#define R_CTL_F_BSY_LC 0xc6 +#define R_CTL_LCR 0xc7 + +/* type field */ +#define TYPE_BASIC_LS 0x00 +#define TYPE_EXTENDED_LS 0x01 +#define TYPE_IS8802 0x04 +#define TYPE_IS8802_SNAP 0x05 +#define TYPE_SCSI_FCP 0x08 +#define TYPE_SCSI_GPP 0x09 +#define TYPE_HIPP_FP 0x0a +#define TYPE_IPI3_MASTER 0x11 +#define TYPE_IPI3_SLAVE 0x12 +#define TYPE_IPI3_PEER 0x13 + +/* f_ctl field */ +#define F_CTL_FILL_BYTES 0x000003 +#define F_CTL_XCHG_REASSEMBLE 0x000004 +#define F_CTL_RO_PRESENT 0x000008 +#define F_CTL_ABORT_SEQ 0x000030 +#define F_CTL_CONTINUE_SEQ 0x0000c0 +#define F_CTL_INVALIDATE_XID 0x004000 +#define F_CTL_XID_REASSIGNED 0x008000 +#define F_CTL_SEQ_INITIATIVE 0x010000 +#define F_CTL_CHAINED_SEQ 0x020000 +#define F_CTL_END_CONNECT 0x040000 +#define F_CTL_END_SEQ 0x080000 +#define F_CTL_LAST_SEQ 0x100000 +#define F_CTL_FIRST_SEQ 0x200000 +#define F_CTL_SEQ_CONTEXT 0x400000 +#define F_CTL_XCHG_CONTEXT 0x800000 + +typedef struct { + u32 r_ctl:8, did:24; + u32 xxx1:8, sid:24; + u32 type:8, f_ctl:24; + u32 seq_id:8, df_ctl:8, seq_cnt:16; + u16 ox_id, rx_id; + u32 param; +} fc_hdr; +/* The following are ugly macros to make setup of this structure faster */ +#define FILL_FCHDR_RCTL_DID(fch, r_ctl, did) *(u32 *)(fch) = ((r_ctl) << 24) | (did); +#define FILL_FCHDR_SID(fch, sid) *((u32 *)(fch)+1) = (sid); +#define FILL_FCHDR_TYPE_FCTL(fch, type, f_ctl) *((u32 *)(fch)+2) = ((type) << 24) | (f_ctl); +#define FILL_FCHDR_SEQ_DF_SEQ(fch, seq_id, df_ctl, seq_cnt) *((u32 *)(fch)+3) = ((seq_id) << 24) | ((df_ctl) << 16) | (seq_cnt); +#define FILL_FCHDR_OXRX(fch, ox_id, rx_id) *((u32 *)(fch)+4) = ((ox_id) << 16) | (rx_id); + +/* Well known addresses */ +#define FS_GENERAL_MULTICAST 0xfffff7 +#define FS_WELL_KNOWN_MULTICAST 0xfffff8 +#define FS_HUNT_GROUP 0xfffff9 +#define FS_MANAGEMENT_SERVER 0xfffffa +#define FS_TIME_SERVER 0xfffffb +#define FS_NAME_SERVER 0xfffffc +#define FS_FABRIC_CONTROLLER 0xfffffd +#define FS_FABRIC_F_PORT 0xfffffe +#define FS_BROADCAST 0xffffff + +/* Reject frames */ +/* The param field should be cast to this structure */ +typedef struct { + u8 action; + u8 reason; + u8 xxx; + u8 vendor_unique; +} rjt_param; + +/* Reject action codes */ +#define RJT_RETRY 0x01 +#define RJT_NONRETRY 0x02 + +/* Reject reason codes */ +#define RJT_INVALID_DID 0x01 +#define RJT_INVALID_SID 0x02 +#define RJT_NPORT_NOT_AVAIL_TEMP 0x03 +#define RJT_NPORT_NOT_AVAIL_PERM 0x04 +#define RJT_CLASS_NOT_SUPPORTED 0x05 +#define RJT_DELIMITER_ERROR 0x06 +#define RJT_TYPE_NOT_SUPPORTED 0x07 +#define RJT_INVALID_LINK_CONTROL 0x08 +#define RJT_INVALID_R_CTL 0x09 +#define RJT_INVALID_F_CTL 0x0a +#define RJT_INVALID_OX_ID 0x0b +#define RJT_INVALID_RX_ID 0x0c +#define RJT_INVALID_SEQ_ID 0x0d +#define RJT_INVALID_DF_CTL 0x0e +#define RJT_INVALID_SEQ_CNT 0x0f +#define RJT_INVALID_PARAMETER 0x10 +#define RJT_EXCHANGE_ERROR 0x11 +#define RJT_PROTOCOL_ERROR 0x12 +#define RJT_INCORRECT_LENGTH 0x13 +#define RJT_UNEXPECTED_ACK 0x14 +#define RJT_UNEXPECTED_LINK_RESP 0x15 +#define RJT_LOGIN_REQUIRED 0x16 +#define RJT_EXCESSIVE_SEQUENCES 0x17 +#define RJT_CANT_ESTABLISH_EXCHANGE 0x18 +#define RJT_SECURITY_NOT_SUPPORTED 0x19 +#define RJT_FABRIC_NA 0x1a +#define RJT_VENDOR_UNIQUE 0xff + + +#define SP_F_PORT_LOGIN 0x10 + +/* Extended SVC commands */ +#define LS_RJT 0x01000000 +#define LS_ACC 0x02000000 +#define LS_PLOGI 0x03000000 +#define LS_FLOGI 0x04000000 +#define LS_LOGO 0x05000000 +#define LS_ABTX 0x06000000 +#define LS_RCS 0x07000000 +#define LS_RES 0x08000000 +#define LS_RSS 0x09000000 +#define LS_RSI 0x0a000000 +#define LS_ESTS 0x0b000000 +#define LS_ESTC 0x0c000000 +#define LS_ADVC 0x0d000000 +#define LS_RTV 0x0e000000 +#define LS_RLS 0x0f000000 +#define LS_ECHO 0x10000000 +#define LS_TEST 0x11000000 +#define LS_RRQ 0x12000000 +#define LS_IDENT 0x20000000 +#define LS_DISPLAY 0x21000000 + +typedef struct { + u8 fcph_hi, fcph_lo; + u16 buf2buf_credit; + u8 common_features; + u8 xxx1; + u16 buf2buf_size; + u8 xxx2; + u8 total_concurrent; + u16 off_by_info; + u32 e_d_tov; +} common_svc_parm; + +typedef struct { + u16 serv_opts; + u16 initiator_ctl; + u16 rcpt_ctl; + u16 recv_size; + u8 xxx1; + u8 concurrent_seqs; + u16 end2end_credit; + u16 open_seqs_per_xchg; + u16 xxx2; +} svc_parm; + +/* Login */ +typedef struct { + u32 code; + common_svc_parm common; + fc_wwn nport_wwn; + fc_wwn node_wwn; + svc_parm class1; + svc_parm class2; + svc_parm class3; +} logi; + +#endif /* !(__FC_H) */ diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/fc_syms.c linux/drivers/fc4/fc_syms.c --- v2.1.78/linux/drivers/fc4/fc_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/fc_syms.c Mon Jan 12 15:19:36 1998 @@ -0,0 +1,28 @@ +/* + * We should not even be trying to compile this if we are not doing + * a module. + */ +#define __NO_VERSION__ +#include +#include + +#ifdef CONFIG_MODULES + +#include +#include +#include +#include + +#include "fcp_scsi.h" + +EXPORT_SYMBOL(fcp_init); +EXPORT_SYMBOL(fcp_queue_empty); +EXPORT_SYMBOL(fcp_receive_solicited); +EXPORT_SYMBOL(fc_channels); + +/* SCSI stuff */ +EXPORT_SYMBOL(fcp_scsi_queuecommand); +EXPORT_SYMBOL(fcp_scsi_abort); +EXPORT_SYMBOL(fcp_scsi_reset); + +#endif /* CONFIG_MODULES */ diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/fcp.h linux/drivers/fc4/fcp.h --- v2.1.78/linux/drivers/fc4/fcp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/fcp.h Mon Jan 12 15:19:36 1998 @@ -0,0 +1,94 @@ +/* fcp.h: Definitions for Fibre Channel Protocol. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + */ + +#ifndef __FCP_H +#define __FCP_H + +/* FCP addressing is hierarchical with up to 4 layers, MS first. + Exact meaning of the addresses is up to the vendor */ + +/* fcp_cntl field */ +#define FCP_CNTL_WRITE 0x00000001 /* Initiator write */ +#define FCP_CNTL_READ 0x00000002 /* Initiator read */ +#define FCP_CNTL_ABORT_TSK 0x00000200 /* Abort task set */ +#define FCP_CNTL_CLR_TASK 0x00000400 /* Clear task set */ +#define FCP_CNTL_RESET 0x00002000 /* Reset */ +#define FCP_CNTL_CLR_ACA 0x00004000 /* Clear ACA */ +#define FCP_CNTL_KILL_TASK 0x00008000 /* Terminate task */ +#define FCP_CNTL_QTYPE_MASK 0x00070000 /* Tagged queueing type */ +#define FCP_CNTL_QTYPE_SIMPLE 0x00000000 +#define FCP_CNTL_QTYPE_HEAD_OF_Q 0x00010000 +#define FCP_CNTL_QTYPE_ORDERED 0x00020000 +#define FCP_CNTL_QTYPE_ACA_Q_TAG 0x00040000 +#define FCP_CNTL_QTYPE_UNTAGGED 0x00050000 + +typedef struct { + u16 fcp_addr[4]; + u32 fcp_cntl; + u8 fcp_cdb[16]; + u32 fcp_data_len; +} fcp_cmd; + +/* fcp_status field */ +#define FCP_STATUS_MASK 0x000000ff /* scsi status of command */ +#define FCP_STATUS_RSP_LEN 0x00000100 /* response_len != 0 */ +#define FCP_STATUS_SENSE_LEN 0x00000200 /* sense_len != 0 */ +#define FCP_STATUS_RESID 0x00000400 /* resid != 0 */ + +typedef struct { + u32 xxx[2]; + u32 fcp_status; + u32 fcp_resid; + u32 fcp_sense_len; + u32 fcp_response_len; + /* u8 fcp_sense[fcp_sense_len]; */ + /* u8 fcp_response[fcp_response_len]; */ +} fcp_rsp; + +/* fcp errors */ + +/* rsp_info_type field */ +#define FCP_RSP_SCSI_BUS_ERR 0x01 +#define FCP_RSP_SCSI_PORT_ERR 0x02 +#define FCP_RSP_CARD_ERR 0x03 + +/* isp_status field */ +#define FCP_RSP_CMD_COMPLETE 0x0000 +#define FCP_RSP_CMD_INCOMPLETE 0x0001 +#define FCP_RSP_CMD_DMA_ERR 0x0002 +#define FCP_RSP_CMD_TRAN_ERR 0x0003 +#define FCP_RSP_CMD_RESET 0x0004 +#define FCP_RSP_CMD_ABORTED 0x0005 +#define FCP_RSP_CMD_TIMEOUT 0x0006 +#define FCP_RSP_CMD_OVERRUN 0x0007 + +/* isp_state_flags field */ +#define FCP_RSP_ST_GOT_BUS 0x0100 +#define FCP_RSP_ST_GOT_TARGET 0x0200 +#define FCP_RSP_ST_SENT_CMD 0x0400 +#define FCP_RSP_ST_XFRD_DATA 0x0800 +#define FCP_RSP_ST_GOT_STATUS 0x1000 +#define FCP_RSP_ST_GOT_SENSE 0x2000 + +/* isp_stat_flags field */ +#define FCP_RSP_STAT_DISC 0x0001 +#define FCP_RSP_STAT_SYNC 0x0002 +#define FCP_RSP_STAT_PERR 0x0004 +#define FCP_RSP_STAT_BUS_RESET 0x0008 +#define FCP_RSP_STAT_DEV_RESET 0x0010 +#define FCP_RSP_STAT_ABORTED 0x0020 +#define FCP_RSP_STAT_TIMEOUT 0x0040 +#define FCP_RSP_STAT_NEGOTIATE 0x0080 + +typedef struct { + u8 rsp_info_type; + u8 xxx; + u16 isp_status; + u16 isp_state_flags; + u16 isp_stat_flags; +} fcp_scsi_err; + +#endif /* !(__FCP_H) */ diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/fcp_scsi.h linux/drivers/fc4/fcp_scsi.h --- v2.1.78/linux/drivers/fc4/fcp_scsi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/fcp_scsi.h Mon Jan 12 15:19:36 1998 @@ -0,0 +1,140 @@ +/* fcp_scsi.h: Generic SCSI on top of FC4 - interface defines. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#ifndef _FCP_SCSI_H +#define _FCP_SCSI_H + +#include +#include +#include "../scsi/scsi.h" + +#include "fc.h" +#include "fcp.h" + +#ifdef __sparc__ + +#include +typedef u32 dma_handle; + +#else +#error Need to port FC layer to your architecture +#endif + +#define FC_CLASS_OUTBOUND 0x01 +#define FC_CLASS_INBOUND 0x02 +#define FC_CLASS_SIMPLE 0x03 +#define FC_CLASS_IO_WRITE 0x04 +#define FC_CLASS_IO_READ 0x05 +#define FC_CLASS_UNSOLICITED 0x06 +#define FC_CLASS_OFFLINE 0x08 + +#define PROTO_OFFLINE 0x02 + +struct _fc_channel; + +typedef struct fcp_cmnd { + struct fcp_cmnd *next; + struct fcp_cmnd *prev; + void (*done)(Scsi_Cmnd *); + int proto; + int token; + /* FCP SCSI stuff */ + dma_handle data; + /* From now on this cannot be touched for proto == TYPE_SCSI_FCP */ + fc_hdr fch; + dma_handle cmd; + dma_handle rsp; + int cmdlen; + int rsplen; + int class; + int datalen; + /* This is just used as a verification during login */ + struct _fc_channel *fc; +} fcp_cmnd; + +typedef struct _fc_channel { + struct _fc_channel *next; + int irq; + int state; + int sid; + int did; + char name[16]; + void (*fcp_register)(struct _fc_channel *, u8, int); + void (*fcp_state_change)(struct _fc_channel *, int); + void (*reset)(struct _fc_channel *); + int (*hw_enque)(struct _fc_channel *, fcp_cmnd *); + fc_wwn wwn_node; + fc_wwn wwn_nport; + fc_wwn wwn_dest; + common_svc_parm *common_svc; + svc_parm *class_svcs; +#ifdef __sparc__ + struct linux_sbus_device *dev; +#endif + /* FCP SCSI stuff */ + int can_queue; + int rsp_size; + fcp_cmd *scsi_cmd_pool; + char *scsi_rsp_pool; + dma_handle dma_scsi_cmd, dma_scsi_rsp; + long *scsi_bitmap; + long scsi_bitmap_end; + int scsi_free; + int (*encode_addr)(Scsi_Cmnd *cmnd, u16 *addr); + fcp_cmnd *scsi_que[2]; + char scsi_name[4]; + fcp_cmnd **token_tab; + int channels; + int targets; + long *ages; + /* LOGIN stuff */ + fcp_cmnd *login; + void *ls; +} fc_channel; + +extern fc_channel *fc_channels; + +#define FC_STATE_UNINITED 0 +#define FC_STATE_ONLINE 1 +#define FC_STATE_OFFLINE 2 +#define FC_STATE_RESETING 3 +#define FC_STATE_FPORT_OK 4 +#define FC_STATE_MAYBEOFFLINE 5 + +#define FC_STATUS_OK 0 +#define FC_STATUS_P_RJT 2 +#define FC_STATUS_F_RJT 3 +#define FC_STATUS_P_BSY 4 +#define FC_STATUS_F_BSY 5 +#define FC_STATUS_ERR_OFFLINE 0x11 +#define FC_STATUS_TIMEOUT 0x12 +#define FC_STATUS_ERR_OVERRUN 0x13 +#define FC_STATUS_UNKNOWN_CQ_TYPE 0x20 +#define FC_STATUS_BAD_SEG_CNT 0x21 +#define FC_STATUS_MAX_XCHG_EXCEEDED 0x22 +#define FC_STATUS_BAD_XID 0x23 +#define FC_STATUS_XCHG_BUSY 0x24 +#define FC_STATUS_BAD_POOL_ID 0x25 +#define FC_STATUS_INSUFFICIENT_CQES 0x26 +#define FC_STATUS_ALLOC_FAIL 0x27 +#define FC_STATUS_BAD_SID 0x28 +#define FC_STATUS_NO_SEQ_INIT 0x29 + +void fcp_queue_empty(fc_channel *); +int fcp_init(fc_channel *); +void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *); + +#define for_each_fc_channel(fc) \ + for (fc = fc_channels; fc; fc = fc->next) + +#define for_each_online_fc_channel(fc) \ + for_each_fc_channel(fc) \ + if (fc->state == FC_STATE_ONLINE) + +int fcp_scsi_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int fcp_scsi_abort(Scsi_Cmnd *); +int fcp_scsi_reset(Scsi_Cmnd *, unsigned int); + +#endif /* !(_FCP_SCSI_H) */ diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/soc.c linux/drivers/fc4/soc.c --- v2.1.78/linux/drivers/fc4/soc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/soc.c Mon Jan 12 15:19:36 1998 @@ -0,0 +1,710 @@ +/* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support. + * + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 Jiri Hanika (geo@ff.cuni.cz) + * + * Sources: + * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 + * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 + */ + +static char *version = + "soc.c:v1.0 24/Nov/97 Jakub Jelinek (jj@sunsite.mff.cuni.cz), Jiri Hanika (geo@ff.cuni.cz)\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* #define SOCDEBUG */ +/* #define HAVE_SOC_UCODE */ + +#include "fcp_scsi.h" +#include "soc.h" +#ifdef HAVE_SOC_UCODE +#include "soc_asm.c" +#endif + +#define soc_printk printk ("soc%d: ", s->soc_no); printk + +#ifdef SOCDEBUG +#define SOD(x) soc_printk x; +#else +#define SOD(x) +#endif + +#define for_each_soc(s) for (s = socs; s; s = s->next) +struct soc *socs = NULL; + +static inline void soc_disable(struct soc *s) +{ + s->regs->imask = 0; s->regs->cmd = SOC_CMD_SOFT_RESET; +} + +static inline void soc_enable(struct soc *s) +{ + SOD(("enable %08x\n", s->cfg)) + s->regs->sae = 0; s->regs->cfg = s->cfg; + s->regs->cmd = SOC_CMD_RSP_QALL; + SOC_SETIMASK(s, SOC_IMASK_RSP_QALL | SOC_IMASK_SAE); +} + +static void soc_reset(fc_channel *fc) +{ + soc_port *port = (soc_port *)fc; + struct soc *s = port->s; + + /* FIXME */ + soc_disable(s); + s->req[0].seqno = 1; + s->req[1].seqno = 1; + s->rsp[0].seqno = 1; + s->rsp[1].seqno = 1; + s->req[0].in = 0; + s->req[1].in = 0; + s->rsp[0].in = 0; + s->rsp[1].in = 0; + s->req[0].out = 0; + s->req[1].out = 0; + s->rsp[0].out = 0; + s->rsp[1].out = 0; + + /* FIXME */ + soc_enable(s); +} + +static void inline soc_solicited (struct soc *s) +{ + fc_hdr fchdr; + soc_rsp *hwrsp; + soc_cq *sw_cq; + int token; + int status; + fc_channel *fc; + + sw_cq = &s->rsp[SOC_SOLICITED_RSP_Q]; + + if (sw_cq->pool == NULL) + sw_cq->pool = + (soc_req *)(s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address) / sizeof(u16))); + sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); + SOD (("soc_solicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) + for (;;) { + hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out; + token = xram_get_32low ((xram_p)&hwrsp->shdr.token); + status = xram_get_32low ((xram_p)&hwrsp->status); + fc = (fc_channel *)(&s->port[(token >> 11) & 1]); + + if (status == SOC_OK) + fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), FC_STATUS_OK, NULL); + else { + xram_copy_from(&fchdr, (xram_p)&hwrsp->fchdr, sizeof(fchdr)); + /* We have intentionally defined FC_STATUS_* constants to match SOC_* constants, otherwise + we'd have to translate status */ + fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), status, &fchdr); + } + + if (++sw_cq->out > sw_cq->last) { + sw_cq->seqno++; + sw_cq->out = 0; + } + + if (sw_cq->out == sw_cq->in) { + sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); + if (sw_cq->out == sw_cq->in) { + /* Tell the hardware about it */ + s->regs->cmd = (sw_cq->out << 24) | (SOC_CMD_RSP_QALL & ~(SOC_CMD_RSP_Q0 << SOC_SOLICITED_RSP_Q)); + /* Read it, so that we're sure it has been updated */ + s->regs->cmd; + sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); + if (sw_cq->out == sw_cq->in) + break; + } + } + } +} + +static void inline soc_request (struct soc *s, u32 cmd) +{ + SOC_SETIMASK(s, s->imask & ~(cmd & SOC_CMD_REQ_QALL)); + + SOD(("Queues available %08x OUT %X %X\n", cmd, xram_get_8((xram_p)&s->req[0].hw_cq->out), xram_get_8((xram_p)&s->req[0].hw_cq->out))) + if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { + fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); + if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) + fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); + } else + fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); + if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) + s->curr_port ^= 1; +} + +static void inline soc_unsolicited (struct soc *s) +{ + soc_rsp *hwrsp, *hwrspc; + soc_cq *sw_cq; + int count; + int status; + int flags; + fc_channel *fc; + + sw_cq = &s->rsp[SOC_UNSOLICITED_RSP_Q]; + if (sw_cq->pool == NULL) + sw_cq->pool = + (soc_req *)(s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address) / sizeof(u16))); + + sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); + SOD (("soc_unsolicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) + while (sw_cq->in != sw_cq->out) { + /* ...real work per entry here... */ + hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out; + hwrspc = NULL; + flags = hwrsp->shdr.flags; + count = xram_get_8 ((xram_p)&hwrsp->count); + fc = (fc_channel *)&s->port[flags & SOC_PORT_B]; + SOD(("FC %08lx fcp_state_change %08lx\n", (long)fc, (long)fc->fcp_state_change)) + + if (count != 1) { + /* Ugh, continuation entries */ + u8 in; + + if (count != 2) { + printk("%s: Too many continuations entries %d\n", fc->name, count); + goto update_out; + } + + in = sw_cq->in; + if (in < sw_cq->out) in += sw_cq->last + 1; + if (in < sw_cq->out + 2) { + /* Ask the hardware about it if they haven't arrived yet */ + s->regs->cmd = (sw_cq->out << 24) | (SOC_CMD_RSP_QALL & ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)); + /* Read it, so that we're sure it has been updated */ + s->regs->cmd; + sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); + in = sw_cq->in; + if (in < sw_cq->out) in += sw_cq->last + 1; + if (in < sw_cq->out + 2) /* Nothing came, let us wait */ + return; + } + if (sw_cq->out == sw_cq->last) + hwrspc = (soc_rsp *)sw_cq->pool; + else + hwrspc = hwrsp + 1; + } + + switch (flags & ~SOC_PORT_B) { + case SOC_STATUS: + status = xram_get_32low ((xram_p)&hwrsp->status); + switch (status) { + case SOC_ONLINE: + fc->fcp_state_change(fc, FC_STATE_ONLINE); + break; + case SOC_OFFLINE: + fc->fcp_state_change(fc, FC_STATE_OFFLINE); + break; + default: + printk ("%s: Unknown STATUS no %d\n", fc->name, status); + break; + } + break; + case (SOC_UNSOLICITED|SOC_FC_HDR): + { + int r_ctl = xram_get_8 ((xram_p)&hwrsp->fchdr); + unsigned len; + char buf[64]; + + if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { + len = xram_get_32 ((xram_p)&hwrsp->shdr.bytecnt); + if (len < 4 || !hwrspc) + printk ("%s: Invalid R_CTL %02x continuation entries\n", fc->name, r_ctl); + else { + if (len > 60) len = 60; + xram_copy_from (buf, (xram_p)hwrspc, (len + 3) & ~3); + if (*(u32 *)buf == LS_DISPLAY) { + int i; + + for (i = 4; i < len; i++) + if (buf[i] == '\n') buf[i] = ' '; + buf[len] = 0; + printk ("%s message: %s\n", fc->name, buf + 4); + } else + printk ("%s: Unknown LS_CMD %02x\n", fc->name, buf[0]); + } + } else + printk ("%s: Unsolicited R_CTL %02x not handled\n", fc->name, r_ctl); + } + break; + default: + printk ("%s: Unexpected flags %08x\n", fc->name, flags); + break; + } +update_out: + if (++sw_cq->out > sw_cq->last) { + sw_cq->seqno++; + sw_cq->out = 0; + } + + if (hwrspc) { + if (++sw_cq->out > sw_cq->last) { + sw_cq->seqno++; + sw_cq->out = 0; + } + } + + if (sw_cq->out == sw_cq->in) { + sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); + if (sw_cq->out == sw_cq->in) { + /* Tell the hardware about it */ + s->regs->cmd = (sw_cq->out << 24) | (SOC_CMD_RSP_QALL & ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)); + /* Read it, so that we're sure it has been updated */ + s->regs->cmd; + sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); + } + } + } +} + +static void soc_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 cmd; + register struct soc *s = (struct soc *)dev_id; + + cmd = s->regs->cmd; + for (; (cmd = SOC_INTR (s, cmd)); cmd = s->regs->cmd) { + if (cmd & SOC_CMD_RSP_Q1) soc_unsolicited (s); + if (cmd & SOC_CMD_RSP_Q0) soc_solicited (s); + if (cmd & SOC_CMD_REQ_QALL) soc_request (s, cmd); + } +} + +#define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port)) + +static int soc_hw_enque (fc_channel *fc, fcp_cmnd *fcmd) +{ + soc_port *port = (soc_port *)fc; + struct soc *s = port->s; + int qno; + soc_cq *sw_cq; + int cq_next_in; + soc_req *request; + fc_hdr *fch; + int i; + + if (fcmd->proto == TYPE_SCSI_FCP) + qno = 1; + else + qno = 0; + SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno)) + if (s->imask & (SOC_IMASK_REQ_Q0 << qno)) + return -EIO; + sw_cq = s->req + qno; + cq_next_in = (sw_cq->in + 1) & sw_cq->last; + + if (cq_next_in == sw_cq->out + && cq_next_in == (sw_cq->out = xram_get_8((xram_p)&sw_cq->hw_cq->out))) { + SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last)) + SOC_SETIMASK(s, s->imask | (SOC_IMASK_REQ_Q0 << qno)); + return -EBUSY; // If queue full, just say NO + } + + request = sw_cq->pool + sw_cq->in; + fch = &request->fchdr; + + switch (fcmd->proto) { + case TYPE_SCSI_FCP: + request->shdr.token = TOKEN(TYPE_SCSI_FCP, port->mask, fcmd->token); + request->data[0].base = fc->dma_scsi_cmd + fcmd->token * sizeof(fcp_cmd); + request->data[0].count = sizeof(fcp_cmd); + request->data[1].base = fc->dma_scsi_rsp + fcmd->token * fc->rsp_size; + request->data[1].count = fc->rsp_size; + if (fcmd->data) { + request->shdr.segcnt = 3; + i = fc->scsi_cmd_pool[fcmd->token].fcp_data_len; + request->shdr.bytecnt = i; + request->data[2].base = fcmd->data; + request->data[2].count = i; + request->type = (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ? + SOC_CQTYPE_IO_WRITE : SOC_CQTYPE_IO_READ; + } else { + request->shdr.segcnt = 2; + request->shdr.bytecnt = 0; + request->data[2].base = 0; + request->data[2].count = 0; + request->type = SOC_CQTYPE_SIMPLE; + } + FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); + FILL_FCHDR_SID(fch, fc->sid); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + fch->param = 0; + request->shdr.flags = port->flags; + request->shdr.class = 2; + break; + + case PROTO_OFFLINE: + memset (request, 0, sizeof(*request)); + request->shdr.token = TOKEN(PROTO_OFFLINE, port->mask, fcmd->token); + request->type = SOC_CQTYPE_OFFLINE; + FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); + FILL_FCHDR_SID(fch, fc->sid); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + request->shdr.flags = port->flags; + break; + + default: + request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token); + request->shdr.class = 2; + request->shdr.flags = port->flags; + memcpy (fch, &fcmd->fch, sizeof(fc_hdr)); + request->data[0].count = fcmd->cmdlen; + request->data[1].count = fcmd->rsplen; + request->type = fcmd->class; + switch (fcmd->class) { + case FC_CLASS_OUTBOUND: + request->data[0].base = fcmd->cmd; + request->data[0].count = fcmd->cmdlen; + request->type = SOC_CQTYPE_OUTBOUND; + request->shdr.bytecnt = fcmd->cmdlen; + request->shdr.segcnt = 1; + break; + case FC_CLASS_INBOUND: + request->data[0].base = fcmd->rsp; + request->data[0].count = fcmd->rsplen; + request->type = SOC_CQTYPE_INBOUND; + request->shdr.bytecnt = 0; + request->shdr.segcnt = 1; + break; + case FC_CLASS_SIMPLE: + request->data[0].base = fcmd->cmd; + request->data[1].base = fcmd->rsp; + request->data[0].count = fcmd->cmdlen; + request->data[1].count = fcmd->rsplen; + request->type = SOC_CQTYPE_SIMPLE; + request->shdr.bytecnt = fcmd->cmdlen; + request->shdr.segcnt = 2; + break; + case FC_CLASS_IO_READ: + case FC_CLASS_IO_WRITE: + request->data[0].base = fcmd->cmd; + request->data[1].base = fcmd->rsp; + request->data[0].count = fcmd->cmdlen; + request->data[1].count = fcmd->rsplen; + request->type = (fcmd->class == FC_CLASS_IO_READ) ? SOC_CQTYPE_IO_READ : SOC_CQTYPE_IO_WRITE; + if (fcmd->data) { + request->data[2].base = fcmd->data; + request->data[2].count = fcmd->datalen; + request->shdr.bytecnt = fcmd->datalen; + request->shdr.segcnt = 3; + } else { + request->shdr.bytecnt = 0; + request->shdr.segcnt = 2; + } + break; + } + break; + } + + request->count = 1; + request->flags = 0; + request->seqno = sw_cq->seqno; + + /* And now tell the SOC about it */ + + if (++sw_cq->in > sw_cq->last) { + sw_cq->in = 0; + sw_cq->seqno++; + } + + SOD(("Putting %08x into cmd\n", SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno))) + + s->regs->cmd = SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno); + /* Read so that command is completed */ + s->regs->cmd; + + return 0; +} + +static inline void soc_download_fw(struct soc *s) +{ +#ifdef HAVE_SOC_UCODE + xram_copy_to (s->xram, soc_ucode, sizeof(soc_ucode)); + xram_bzero (s->xram + (sizeof(soc_ucode)/sizeof(u16)), 32768 - sizeof(soc_ucode)); +#endif +} + +/* Check for what the best SBUS burst we can use happens + * to be on this machine. + */ +static inline void soc_init_bursts(struct soc *s, struct linux_sbus_device *sdev) +{ + int bsizes, bsizes_more; + + bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff); + bsizes_more = (prom_getintdefault(sdev->my_bus->prom_node, "burst-sizes", 0xff) & 0xff); + bsizes &= bsizes_more; + if ((bsizes & 0x7f) == 0x7f) + s->cfg = SOC_CFG_BURST_64; + else if ((bsizes & 0x3f) == 0x3f) + s->cfg = SOC_CFG_BURST_32; + else if ((bsizes & 0x1f) == 0x1f) + s->cfg = SOC_CFG_BURST_16; + else + s->cfg = SOC_CFG_BURST_4; +} + +static inline void soc_init(struct linux_sbus_device *sdev, int no) +{ +#ifdef __sparc_v9__ + struct devid_cookie dcookie; +#endif + unsigned char tmp[60]; + int propl; + struct soc *s; + static unsigned version_printed = 0; + soc_hw_cq cq[8]; + int size, i; + int irq; + + s = kmalloc (sizeof (struct soc), GFP_KERNEL); + if (!s) return; + memset (s, 0, sizeof(struct soc)); + s->soc_no = no; + + SOD(("socs %08lx soc_intr %08lx soc_hw_enque %08x\n", (long)socs, (long)soc_intr, (long)soc_hw_enque)) + if (version_printed++ == 0) + printk (version); + + s->next = socs; + socs = s; + s->port[0].fc.dev = sdev; + s->port[1].fc.dev = sdev; + s->port[0].s = s; + s->port[1].s = s; + + s->port[0].fc.next = &s->port[1].fc; + + /* World Wide Name of SOC */ + propl = prom_getproperty (sdev->prom_node, "soc-wwn", tmp, sizeof(tmp)); + if (propl != sizeof (fc_wwn)) { + s->wwn.naaid = NAAID_IEEE; + s->wwn.lo = 0x12345678; + } else + memcpy (&s->wwn, tmp, sizeof (fc_wwn)); + + propl = prom_getproperty (sdev->prom_node, "port-wwns", tmp, sizeof(tmp)); + if (propl != 2 * sizeof (fc_wwn)) { + s->port[0].fc.wwn_nport.naaid = NAAID_IEEE_EXT; + s->port[0].fc.wwn_nport.hi = s->wwn.hi; + s->port[0].fc.wwn_nport.lo = s->wwn.lo; + s->port[1].fc.wwn_nport.naaid = NAAID_IEEE_EXT; + s->port[1].fc.wwn_nport.nportid = 1; + s->port[1].fc.wwn_nport.hi = s->wwn.hi; + s->port[1].fc.wwn_nport.lo = s->wwn.lo; + } else { + memcpy (&s->port[0].fc.wwn_nport, tmp, sizeof (fc_wwn)); + memcpy (&s->port[1].fc.wwn_nport, tmp + sizeof (fc_wwn), sizeof (fc_wwn)); + } + memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); + memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); + SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n", + *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, + *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, + *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) + + s->port[0].fc.sid = 1; + s->port[1].fc.sid = 17; + s->port[0].fc.did = 2; + s->port[1].fc.did = 18; + + s->port[0].fc.reset = soc_reset; + s->port[1].fc.reset = soc_reset; + + /* Setup the reg property for this device. */ + prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, sdev->num_registers, sdev); + + if (sdev->num_registers == 1) { + /* Probably SunFire onboard SOC */ + s->xram = (xram_p) + sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, + sdev->reg_addrs [0].reg_size, "soc_xram", + sdev->reg_addrs [0].which_io, 0); + s->regs = (struct soc_regs *)((char *)s->xram + 0x10000); + } else { + /* Probably SOC sbus card */ + s->xram = (xram_p) + sparc_alloc_io (sdev->reg_addrs [1].phys_addr, 0, + sdev->reg_addrs [1].reg_size, "soc_xram", + sdev->reg_addrs [1].which_io, 0); + s->regs = (struct soc_regs *) + sparc_alloc_io (sdev->reg_addrs [2].phys_addr, 0, + sdev->reg_addrs [2].reg_size, "soc_regs", + sdev->reg_addrs [2].which_io, 0); + } + + soc_init_bursts(s, sdev); + + SOD(("Disabling SOC\n")) + + soc_disable (s); + + irq = sdev->irqs[0].pri; + +#ifndef __sparc_v9__ + if (request_irq (irq, soc_intr, SA_SHIRQ, "SOC", (void *)s)) { + soc_printk ("Cannot order irq %d to go\n", irq); + return; + } +#else + dcookie.real_dev_id = s; + dcookie.imap = dcookie.iclr = 0; + dcookie.pil = -1; + dcookie.bus_cookie = sdev->my_bus; + if (request_irq (irq, soc_intr, (SA_SHIRQ | SA_SBUS | SA_DCOOKIE), "SOC", &dcookie)) { + soc_printk ("Cannot order irq %d to go\n", irq); + return; + } + irq = dcookie.ret_ino; +#endif + + SOD(("SOC uses IRQ%d\n", irq)) + + s->port[0].fc.irq = irq; + s->port[1].fc.irq = irq; + + sprintf (s->port[0].fc.name, "soc%d port A", no); + sprintf (s->port[1].fc.name, "soc%d port B", no); + s->port[0].flags = SOC_FC_HDR | SOC_PORT_A; + s->port[1].flags = SOC_FC_HDR | SOC_PORT_B; + s->port[1].mask = (1 << 11); + + s->port[0].fc.hw_enque = soc_hw_enque; + s->port[1].fc.hw_enque = soc_hw_enque; + + soc_download_fw (s); + + SOD(("Downloaded firmware\n")) + + /* Now setup xram circular queues */ + memset (cq, 0, sizeof(cq)); + + size = (SOC_CQ_REQ0_SIZE + SOC_CQ_REQ1_SIZE) * sizeof(soc_req); + s->req[0].pool = (soc_req *) sparc_dvma_malloc (size, "SOC request queues", &cq[0].address); + s->req[1].pool = s->req[0].pool + SOC_CQ_REQ0_SIZE; + + s->req[0].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET); + s->req[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq) / sizeof(u16)); + s->rsp[0].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET); + s->rsp[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq) / sizeof(u16)); + + cq[1].address = cq[0].address + (SOC_CQ_REQ0_SIZE * sizeof(soc_req)); + cq[4].address = 1; + cq[5].address = 1; + cq[0].last = SOC_CQ_REQ0_SIZE - 1; + cq[1].last = SOC_CQ_REQ1_SIZE - 1; + cq[4].last = SOC_CQ_RSP0_SIZE - 1; + cq[5].last = SOC_CQ_RSP1_SIZE - 1; + for (i = 0; i < 8; i++) + cq[i].seqno = 1; + + s->req[0].last = SOC_CQ_REQ0_SIZE - 1; + s->req[1].last = SOC_CQ_REQ1_SIZE - 1; + s->rsp[0].last = SOC_CQ_RSP0_SIZE - 1; + s->rsp[1].last = SOC_CQ_RSP1_SIZE - 1; + + s->req[0].seqno = 1; + s->req[1].seqno = 1; + s->rsp[0].seqno = 1; + s->rsp[1].seqno = 1; + + xram_copy_to (s->xram + SOC_CQ_REQ_OFFSET, cq, sizeof(cq)); + + /* Make our sw copy of SOC service parameters */ + xram_copy_from (s->serv_params, s->xram + 0x140, sizeof (s->serv_params)); + + s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params; + s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); + s->port[1].fc.common_svc = (common_svc_parm *)&s->serv_params; + s->port[1].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); + + soc_enable (s); + + SOD(("Enabled SOC\n")) +} + +#ifndef MODULE +__initfunc(int soc_probe(void)) +#else +int init_module(void) +#endif +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev = 0; + struct soc *s; + int cards = 0; + + for_each_sbus(bus) { + for_each_sbusdev(sdev, bus) { + if(!strcmp(sdev->prom_name, "SUNW,soc")) { + soc_init(sdev, cards); + cards++; + } + } + } + if (!cards) return -EIO; + + for_each_soc(s) + if (s->next) + s->port[1].fc.next = &s->next->port[0].fc; + fcp_init (&socs->port[0].fc); + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +void cleanup_module(void) +{ + struct soc *s; + int irq; + struct linux_sbus_device *sdev; + + for_each_soc(s) { + /* FIXME: Tell FC layer we say good bye */ + irq = s->port[0].fc.irq; + disable_irq (irq); + free_irq (irq, s); + sdev = s->port[0].fc.dev; + if (sdev->num_registers == 1) + sparc_free_io ((char *)s->xram, sdev->reg_addrs [0].reg_size); + else { + sparc_free_io ((char *)s->xram, sdev->reg_addrs [1].reg_size); + sparc_free_io ((char *)s->regs, sdev->reg_addrs [2].reg_size); + } + /* FIXME: sparc_dvma_free() ??? */ + } +} +#endif diff -u --recursive --new-file v2.1.78/linux/drivers/fc4/soc.h linux/drivers/fc4/soc.h --- v2.1.78/linux/drivers/fc4/soc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/fc4/soc.h Mon Jan 12 15:19:36 1998 @@ -0,0 +1,275 @@ +/* soc.h: Definitions for Sparc SUNW,soc Fibre Channel Sbus driver. + * + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#ifndef __SOC_H +#define __SOC_H + +#include "fc.h" +#include "fcp.h" +#include "fcp_scsi.h" + +/* Hardware structures and constants first {{{ */ + +struct soc_regs { + volatile u32 cfg; /* Config Register */ + volatile u32 sae; /* Slave Access Error Register */ + volatile u32 cmd; /* Command & Status Register */ + volatile u32 imask; /* Interrupt Mask Register */ +}; + +/* Config Register */ +#define SOC_CFG_EXT_RAM_BANK_MASK 0x07000000 +#define SOC_CFG_EEPROM_BANK_MASK 0x00030000 +#define SOC_CFG_BURST64_MASK 0x00000700 +#define SOC_CFG_SBUS_PARITY_TEST 0x00000020 +#define SOC_CFG_SBUS_PARITY_CHECK 0x00000010 +#define SOC_CFG_SBUS_ENHANCED 0x00000008 +#define SOC_CFG_BURST_MASK 0x00000007 +/* Bursts */ +#define SOC_CFG_BURST_4 0x00000000 +#define SOC_CFG_BURST_16 0x00000004 +#define SOC_CFG_BURST_32 0x00000005 +#define SOC_CFG_BURST_64 0x00000006 + +/* Slave Access Error Register */ +#define SOC_SAE_ALIGNMENT 0x00000004 +#define SOC_SAE_UNSUPPORTED 0x00000002 +#define SOC_SAE_PARITY 0x00000001 + +/* Command & Status Register */ +#define SOC_CMD_RSP_QALL 0x000f0000 +#define SOC_CMD_RSP_Q0 0x00010000 +#define SOC_CMD_RSP_Q1 0x00020000 +#define SOC_CMD_RSP_Q2 0x00040000 +#define SOC_CMD_RSP_Q3 0x00080000 +#define SOC_CMD_REQ_QALL 0x00000f00 +#define SOC_CMD_REQ_Q0 0x00000100 +#define SOC_CMD_REQ_Q1 0x00000200 +#define SOC_CMD_REQ_Q2 0x00000400 +#define SOC_CMD_REQ_Q3 0x00000800 +#define SOC_CMD_SAE 0x00000080 +#define SOC_CMD_INTR_PENDING 0x00000008 +#define SOC_CMD_NON_QUEUED 0x00000004 +#define SOC_CMD_IDLE 0x00000002 +#define SOC_CMD_SOFT_RESET 0x00000001 + +/* Interrupt Mask Register */ +#define SOC_IMASK_RSP_QALL 0x000f0000 +#define SOC_IMASK_RSP_Q0 0x00010000 +#define SOC_IMASK_RSP_Q1 0x00020000 +#define SOC_IMASK_RSP_Q2 0x00040000 +#define SOC_IMASK_RSP_Q3 0x00080000 +#define SOC_IMASK_REQ_QALL 0x00000f00 +#define SOC_IMASK_REQ_Q0 0x00000100 +#define SOC_IMASK_REQ_Q1 0x00000200 +#define SOC_IMASK_REQ_Q2 0x00000400 +#define SOC_IMASK_REQ_Q3 0x00000800 +#define SOC_IMASK_SAE 0x00000080 +#define SOC_IMASK_NON_QUEUED 0x00000004 + +#define SOC_INTR(s, cmd) \ + (((cmd & SOC_CMD_RSP_QALL) | ((~cmd) & SOC_CMD_REQ_QALL)) \ + & s->imask) + +#define SOC_SETIMASK(s, i) \ + (s)->imask = (i); (s)->regs->imask = (i) + +/* XRAM + * + * This is a 64KB register area. It accepts only halfword access. + * That's why here are the following inline functions... + */ + +typedef u16 *xram_p; + +/* Get 32bit number from XRAM */ +static inline u32 xram_get_32 (xram_p x) +{ + return (((u32)*x) << 16) | (x[1]); +} + +/* Like the above, but when we don't care about the high 16 bits */ +static inline u32 xram_get_32low (xram_p x) +{ + return (u32)x[1]; +} + +static inline u8 xram_get_8 (xram_p x) +{ + if (((long)x) & 1) { + x = (xram_p)((long)x - 1); + return (u8)*x; + } else + return (u8)(*x >> 8); +} + +static inline void xram_copy_from (void *p, xram_p x, int len) +{ + for (len >>= 2; len > 0; len--, x += 2) { + *((u32 *)p)++ = (((u32)(*x)) << 16) | (x[1]); + } +} + +static inline void xram_copy_to (xram_p x, void *p, int len) +{ + register u32 tmp; + for (len >>= 2; len > 0; len--, x += 2) { + tmp = *((u32 *)p)++; + *x = tmp >> 16; + x[1] = tmp; + } +} + +static inline void xram_bzero (xram_p x, int len) +{ + for (len >>= 1; len > 0; len--) *x++ = 0; +} + +/* Circular Queue */ + +/* These two are in sizeof(u16) units */ +#define SOC_CQ_REQ_OFFSET 0x100 +#define SOC_CQ_RSP_OFFSET 0x110 + +typedef struct { + u32 address; + u8 in; + u8 out; + u8 last; + u8 seqno; +} soc_hw_cq; + +#define SOC_PORT_A 0x0000 /* From/To Port A */ +#define SOC_PORT_B 0x0001 /* From/To Port A */ +#define SOC_FC_HDR 0x0002 /* Contains FC Header */ +#define SOC_NORSP 0x0004 /* Don't generate response nor interrupt */ +#define SOC_NOINT 0x0008 /* Generate response but not interrupt */ +#define SOC_XFERRDY 0x0010 /* Generate XFERRDY */ +#define SOC_IGNOREPARAM 0x0020 /* Ignore PARAM field in the FC header */ +#define SOC_COMPLETE 0x0040 /* Command completed */ +#define SOC_UNSOLICITED 0x0080 /* For request this is the packet to establish unsolicited pools, */ + /* for rsp this is unsolicited packet */ +#define SOC_STATUS 0x0100 /* State change (on/off line) */ + +typedef struct { + u32 token; + u16 flags; + u8 class; + u8 segcnt; + u32 bytecnt; +} soc_hdr; + +typedef struct { + u32 base; + u32 count; +} soc_data; + +#define SOC_CQTYPE_OUTBOUND 0x01 +#define SOC_CQTYPE_INBOUND 0x02 +#define SOC_CQTYPE_SIMPLE 0x03 +#define SOC_CQTYPE_IO_WRITE 0x04 +#define SOC_CQTYPE_IO_READ 0x05 +#define SOC_CQTYPE_UNSOLICITED 0x06 +#define SOC_CQTYPE_DIAG 0x07 +#define SOC_CQTYPE_OFFLINE 0x08 +#define SOC_CQTYPE_RESPONSE 0x10 +#define SOC_CQTYPE_INLINE 0x20 + +#define SOC_CQFLAGS_CONT 0x01 +#define SOC_CQFLAGS_FULL 0x02 +#define SOC_CQFLAGS_BADHDR 0x04 +#define SOC_CQFLAGS_BADPKT 0x08 + +typedef struct { + soc_hdr shdr; + soc_data data[3]; + fc_hdr fchdr; + u8 count; + u8 type; + u8 flags; + u8 seqno; +} soc_req; + +#define SOC_OK 0 +#define SOC_P_RJT 2 +#define SOC_F_RJT 3 +#define SOC_P_BSY 4 +#define SOC_F_BSY 5 +#define SOC_ONLINE 0x10 +#define SOC_OFFLINE 0x11 +#define SOC_TIMEOUT 0x12 +#define SOC_OVERRUN 0x13 +#define SOC_UNKOWN_CQ_TYPE 0x20 +#define SOC_BAD_SEG_CNT 0x21 +#define SOC_MAX_XCHG_EXCEEDED 0x22 +#define SOC_BAD_XID 0x23 +#define SOC_XCHG_BUSY 0x24 +#define SOC_BAD_POOL_ID 0x25 +#define SOC_INSUFFICIENT_CQES 0x26 +#define SOC_ALLOC_FAIL 0x27 +#define SOC_BAD_SID 0x28 +#define SOC_NO_SEG_INIT 0x29 + +typedef struct { + soc_hdr shdr; + u32 status; + soc_data data; + u8 xxx1[12]; + fc_hdr fchdr; + u8 count; + u8 type; + u8 flags; + u8 seqno; +} soc_rsp; + +/* }}} */ + +/* Now our software structures and constants we use to drive the beast {{{ */ + +#define SOC_CQ_REQ0_SIZE 4 +#define SOC_CQ_REQ1_SIZE 64 +#define SOC_CQ_RSP0_SIZE 8 +#define SOC_CQ_RSP1_SIZE 4 + +#define SOC_SOLICITED_RSP_Q 0 +#define SOC_UNSOLICITED_RSP_Q 1 + +struct soc; + +typedef struct { + /* This must come first */ + fc_channel fc; + struct soc *s; + u16 flags; + u16 mask; +} soc_port; + +typedef struct { + soc_hw_cq *hw_cq; /* Related XRAM cq */ + soc_req *pool; + u8 in; + u8 out; + u8 last; + u8 seqno; +} soc_cq; + +struct soc { + soc_port port[2]; /* Every SOC has one or two FC ports */ + soc_cq req[2]; /* Request CQs */ + soc_cq rsp[2]; /* Response CQs */ + int soc_no; + struct soc_regs *regs; + xram_p xram; + fc_wwn wwn; + u32 imask; /* Our copy of regs->imask */ + u32 cfg; /* Our copy of regs->cfg */ + char serv_params[80]; + struct soc *next; + int curr_port; /* Which port will have priority to fcp_queue_empty */ +}; + +/* }}} */ + +#endif /* !(__SOC_H) */ diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile --- v2.1.78/linux/drivers/macintosh/Makefile Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/Makefile Mon Jan 12 15:18:13 1998 @@ -14,12 +14,12 @@ L_TARGET := macintosh.a M_OBJS := -L_OBJS := via-cuda.o adb.o nvram.o +L_OBJS := via-cuda.o adb.o nvram.o macio-adb.o -ifeq ($(CONFIG_SERIAL),y) +ifeq ($(CONFIG_SERIAL)$(CONFIG_PMAC),yy) LX_OBJS += macserial.o else - ifeq ($(CONFIG_SERIAL),m) + ifeq ($(CONFIG_SERIAL)$(CONFIG_PMAC),my) MX_OBJS += macserial.o endif endif @@ -30,7 +30,19 @@ ifdef CONFIG_VT ifdef CONFIG_PMAC_CONSOLE - L_OBJS += pmac-cons.o control.o platinum.o valkyrie.o + L_OBJS += pmac-cons.o + ifdef CONFIG_CONTROL_VIDEO + L_OBJS += control.o + endif + ifdef CONFIG_PLATINUM_VIDEO + L_OBJS += platinum.o + endif + ifdef CONFIG_VALKYRIE_VIDEO + L_OBJS += valkyrie.o + endif + ifdef CONFIG_CHIPS_VIDEO + L_OBJS += chips.o + endif ifdef CONFIG_ATY_VIDEO L_OBJS += aty.o endif diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c --- v2.1.78/linux/drivers/macintosh/adb.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/macintosh/adb.c Mon Jan 12 15:18:13 1998 @@ -1,5 +1,6 @@ /* - * Device driver for the /dev/adb device on macintoshes. + * Device driver for the Apple Desktop Bus + * and the /dev/adb device on macintoshes. * * Copyright (C) 1996 Paul Mackerras. */ @@ -10,15 +11,99 @@ #include #include #include +#include #include #include +#include + +enum adb_hw adb_hardware; +int (*adb_send_request)(struct adb_request *req, int sync); +int (*adb_autopoll)(int on); + +static struct adb_handler { + void (*handler)(unsigned char *, int, struct pt_regs *, int); +} adb_handler[16]; + +static int adb_nodev(void) +{ + return -1; +} + +void adb_init(void) +{ + adb_hardware = ADB_NONE; + adb_send_request = (void *) adb_nodev; + adb_autopoll = (void *) adb_nodev; + via_cuda_init(); + macio_adb_init(); + if (adb_hardware == ADB_NONE) + printk(KERN_WARNING "Warning: no ADB interface detected\n"); + else + adb_autopoll(1); +} + +int +adb_request(struct adb_request *req, void (*done)(struct adb_request *), + int flags, int nbytes, ...) +{ + va_list list; + int i; + struct adb_request sreq; + + if (req == NULL) { + req = &sreq; + flags |= ADBREQ_SYNC; + } + req->nbytes = nbytes; + req->done = done; + req->reply_expected = flags & ADBREQ_REPLY; + va_start(list, nbytes); + for (i = 0; i < nbytes; ++i) + req->data[i] = va_arg(list, int); + va_end(list); + return adb_send_request(req, flags & ADBREQ_SYNC); +} + +/* Ultimately this should return the number of devices with + the given default id. */ +int +adb_register(int default_id, + void (*handler)(unsigned char *, int, struct pt_regs *, int)) +{ + if (adb_handler[default_id].handler != 0) + panic("Two handlers for ADB device %d\n", default_id); + adb_handler[default_id].handler = handler; + return 1; +} + +void +adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll) +{ + int i, id; + static int dump_adb_input = 0; + + id = buf[0] >> 4; + if (dump_adb_input) { + printk(KERN_INFO "adb packet: "); + for (i = 0; i < nb; ++i) + printk(" %x", buf[i]); + printk(", id = %d\n", id); + } + if (adb_handler[id].handler != 0) { + (*adb_handler[id].handler)(buf, nb, regs, autopoll); + } +} + +/* + * /dev/adb device driver. + */ #define ADB_MAJOR 56 /* major number for /dev/adb */ extern void adbdev_init(void); struct adbdev_state { - struct cuda_request req; + struct adb_request req; }; static struct wait_queue *adb_wait; @@ -31,7 +116,7 @@ add_wait_queue(&adb_wait, &wait); current->state = TASK_INTERRUPTIBLE; - while (!state->req.got_reply) { + while (!state->req.complete) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; @@ -49,11 +134,11 @@ return ret; } -static void adb_write_done(struct cuda_request *req) +static void adb_write_done(struct adb_request *req) { - if (!req->got_reply) { + if (!req->complete) { req->reply_len = 0; - req->got_reply = 1; + req->complete = 1; } wake_up_interruptible(&adb_wait); } @@ -62,7 +147,7 @@ { struct adbdev_state *state; - if (MINOR(inode->i_rdev) > 0) + if (MINOR(inode->i_rdev) > 0 || adb_hardware == ADB_NONE) return -ENXIO; state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); if (state == 0) @@ -78,7 +163,7 @@ if (state) { file->private_data = NULL; - if (state->req.reply_expected && !state->req.got_reply) + if (state->req.reply_expected && !state->req.complete) if (adb_wait_reply(state, file)) return 0; kfree(state); @@ -86,13 +171,13 @@ return 0; } -static long long adb_lseek(struct file *file, long long offset, int origin) +static long long adb_lseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } -static long adb_read(struct inode *inode, struct file *file, - char *buf, unsigned long count) +static ssize_t adb_read(struct file *file, char *buf, + size_t count, loff_t *ppos) { int ret; struct adbdev_state *state = file->private_data; @@ -112,17 +197,18 @@ if (ret) return ret; - ret = state->req.reply_len; - copy_to_user(buf, state->req.reply, ret); state->req.reply_expected = 0; + ret = state->req.reply_len; + if (copy_to_user(buf, state->req.reply, ret)) + return -EFAULT; return ret; } -static long adb_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count) +static ssize_t adb_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) { - int ret; + int ret, i; struct adbdev_state *state = file->private_data; if (count < 2 || count > sizeof(state->req.data)) @@ -131,7 +217,7 @@ if (ret) return ret; - if (state->req.reply_expected && !state->req.got_reply) { + if (state->req.reply_expected && !state->req.complete) { /* A previous request is still being processed. Wait for it to finish. */ ret = adb_wait_reply(state, file); @@ -141,10 +227,27 @@ state->req.nbytes = count; state->req.done = adb_write_done; - copy_from_user(state->req.data, buf, count); - state->req.reply_expected = 1; - state->req.got_reply = 0; - cuda_send_request(&state->req); + state->req.complete = 0; + if (copy_from_user(state->req.data, buf, count)) + return -EFAULT; + + switch (adb_hardware) { + case ADB_NONE: + return -ENXIO; + case ADB_VIACUDA: + state->req.reply_expected = 1; + cuda_send_request(&state->req); + break; + default: + if (state->req.data[0] != ADB_PACKET) + return -EINVAL; + for (i = 1; i < state->req.nbytes; ++i) + state->req.data[i] = state->req.data[i+1]; + state->req.reply_expected = + ((state->req.data[0] & 0xc) == 0xc); + adb_send_request(&state->req, 0); + break; + } return count; } diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/ati-gt.h linux/drivers/macintosh/ati-gt.h --- v2.1.78/linux/drivers/macintosh/ati-gt.h Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/ati-gt.h Mon Jan 12 15:18:13 1998 @@ -1,149 +1,203 @@ -#if 0 /* not filled inaty_gt_reg_init yet */ -/* Register values for 1280x1024, 75Hz mode (20) */ +/* the usage for the following structs vary from the gx and vt: +and sdram and sgram gt's + pll registers (sdram) 6,7,11; + crtc_h_sync_strt_wid[3]; + dsp1[3] (sdram,sgram,unused) + dsp2[3] (offset regbase+24, depends on colour mode); + crtc_h_tot_disp,crtc_v_tot_disp,crtc_v_sync_strt_wid,unused; + pll registers (sgram) 7,11; +*/ + +/* Register values for 1280x1024, 75Hz mode (20). no 16/32 */ static struct aty_regvals aty_gt_reg_init_20 = { - { 0x10, 0x28, 0x3c }, - { }, - { } /* pixel clock = 134.61MHz for V=74.81Hz */ + { 0x41, 0xf9, 0x04 }, + { 0xe02a7, 0x1401a6, 0 }, + { 0x260957, 0x2806d6, 0 }, + { 0x10006b6, 0x20006b6, 0x30006b6 }, + + 0x9f00d2, 0x03ff0429, 0x30400, 0, + { 0xb5, 0x04 } }; +#if 0 /* Register values for 1280x960, 75Hz mode (19) */ static struct aty_regvals aty_gt_reg_init_19 = { - { 0x10, 0x28, 0x3c }, - { }, - { } /* pixel clock = 126.01MHz for V=75.01 Hz */ }; +#endif /* Register values for 1152x870, 75Hz mode (18) */ static struct aty_regvals aty_gt_reg_init_18 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 100.33MHz for V=75.31Hz */ + { 0x41, 0xe6, 0x04 }, + { 0x300295, 0x300194, 0x300593 }, + { 0x260a1c, 0x380561, 0}, + { 0x1000744, 0x2000744, 0x3000744 }, + + 0x8f00b5, 0x3650392, 0x230368, 0, + { 0xe6, 0x04 } }; -/* Register values for 1024x768, 75Hz mode (17) */ +/* Register values for 1024x768, 75Hz mode (17), 32 bpp untested */ static struct aty_regvals aty_gt_reg_init_17 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 79.55MHz for V=74.50Hz */ + { 0x41, 0xb5, 0x04 }, + { 0xc0283, 0xc0182, 0xc0581 }, + { 0x36066d, 0x3806d6, 0}, + { 0xa0049e, 0x100049e, 0x200049e }, + + 0x7f00a3, 0x2ff031f, 0x30300, 0, + { 0xb8, 0x04 } }; -/* Register values for 1024x768, 72Hz mode (15) */ -static struct aty_regvals aty_gt_reg_init_15 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 78.12MHz for V=72.12Hz */ +#if 0 +/* Register values for x, Hz mode (16) */ +static struct aty_regvals aty_gt_reg_init_16 = { }; - #endif - -/* Register values for 1280x1024, 60Hz mode (20) */ -static struct aty_regvals aty_gt_reg_init_20 = { - { 0, 0, 0 }, - - { 0x310086, 0x310084, 0x310084 }, - { 0x3070200, 0x30e0300, 0x30e0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, - - 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000, - { 0x88, 0x7 } -}; - -/* Register values for 1024x768, 75Hz mode (17) */ -static struct aty_regvals aty_gt_reg_init_17 = { - { 0, 0, 0 }, - - { 0xc0085, 0xc0083, 0xc0083 }, - { 0x3070200, 0x30e0300, 0x30e0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, - - 0x7f00a3, 0x2ff031f, 0x30300, 0x20100000, - { 0x41, 0x3 } -}; - -/* Register values for 1024x768, 72Hz mode (15) */ +/* Register values for 1024x768, 70Hz mode (15) */ static struct aty_regvals aty_gt_reg_init_15 = { - { 0, 0, 0 }, - - { 0x310086, 0x310084, 0x310084 }, - { 0x3070200, 0x30e0300, 0x30e0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, - - 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000, - { 0x88, 0x7 } + { 0x41, 0xad, 0x04 }, + { 0x310284, 0x310183, 0x310582 }, + { 0x0, 0x380727 }, + { 0x0 }, + 0x7f00a5, 0x2ff0325, 0x260302, }; /* Register values for 1024x768, 60Hz mode (14) */ static struct aty_regvals aty_gt_reg_init_14 = { - { 0, 0, 0 }, + { 0x40, 0xe1, 0x14 }, + { 0x310284, 0x310183, 0x310582 }, + { 0x3607c0, 0x380840, 0x0 }, + { 0xa80592, 0x1000592, 0x0 }, - { 0x310086, 0x310084, 0x310084 }, - { 0x3060200, 0x30d0300, 0x30d0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, - - 0x7f00a7, 0x2ff0325, 0x260302, 0x20100000, - { 0x6c, 0x6 } + 0x7f00a7, 0x2ff0325, 0x260302, 0, + { 0xe1, 0x14 } }; /* Register values for 832x624, 75Hz mode (13) */ static struct aty_regvals aty_gt_reg_init_13 = { - { 0x200, 0x200, 0x200 }, - - { 0x28006f, 0x28006d, 0x28006c }, - { 0x3050200, 0x30b0300, 0x30e0600 }, - { 0x2002312, 0x3002312, 0x6002312 }, + { 0x40, 0xc6, 0x14 }, + { 0x28026d, 0x28016c, 0x28056b }, + { 0x3608cf, 0x380960, 0 }, + { 0xb00655, 0x1000655, 0x2000655 }, - 0x67008f, 0x26f029a, 0x230270, 0x1a100040, - { 0x4f, 0x05 } + 0x67008f, 0x26f029a, 0x230270, 0, + { 0xc6, 0x14 } }; -#if 0 /* not filled in yet */ /* Register values for 800x600, 75Hz mode (12) */ static struct aty_regvals aty_gt_reg_init_12 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 49.11MHz for V=74.40Hz */ + { 0x42, 0xe4, 0x04 }, + { 0xa0267, 0xa0166, 0x0a0565}, + { 0x360a33, 0x48056d, 0}, + { 0xc00755, 0x1000755, 0x02000755}, + + 0x630083, 0x2570270, 0x30258, 0, + { 0xe4, 0x4 } }; /* Register values for 800x600, 72Hz mode (11) */ static struct aty_regvals aty_gt_reg_init_11 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 49.63MHz for V=71.66Hz */ + { 0x42, 0xe6, 0x04 }, + { 0xf026c, 0xf016b, 0xf056a }, + { 0x360a1d, 0x480561, 0}, + { 0xc00745, 0x1000745, 0x2000745 }, + + 0x630081, 0x02570299, 0x6027c }; /* Register values for 800x600, 60Hz mode (10) */ static struct aty_regvals aty_gt_reg_init_10 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 41.41MHz for V=59.78Hz */ + { 0x42, 0xb8, 0x04 }, + { 0x10026a, 0x100169, 0x100568 }, + { 0x460652, 0x4806ba, 0}, + { 0x68048b, 0xa0048b, 0x100048b }, + + 0x630083, 0x02570273, 0x40258, 0, + { 0xb8, 0x4 } +}; + +/* Register values for 800x600, 56Hz mode (9) */ +static struct aty_regvals aty_gt_reg_init_9 = { + { 0x42, 0xf9, 0x14 }, + { 0x90268, 0x90167, 0x090566 }, + { 0x460701, 0x480774, 0}, + { 0x700509, 0xa80509, 0x1000509 }, + + 0x63007f, 0x2570270, 0x20258 +}; + +#if 0 +/* Register values for 768x576, 50Hz mode (8) */ +static struct aty_regvals aty_gt_reg_init_8 = { }; /* Register values for 640x870, 75Hz Full Page Display (7) */ static struct aty_regvals aty_gt_reg_init_7 = { - { 0x10, 0x30, 0x68 }, - { }, - { } /* pixel clock = 57.29MHz for V=75.01Hz */ }; #endif /* Register values for 640x480, 67Hz mode (6) */ static struct aty_regvals aty_gt_reg_init_6 = { - { 0x200, 0x200, 0x200 }, - - { 0x28005b, 0x280059, 0x280058 }, - { 0x3040200, 0x3060300, 0x30c0600 }, - { 0x2002312, 0x3002312, 0x6002312 }, + { 0x42, 0xd1, 0x14 }, + { 0x280259, 0x280158, 0x280557 }, + { 0x460858, 0x4808e2, 0}, + { 0x780600, 0xb00600, 0x1000600 }, - 0x4f006b, 0x1df020c, 0x2301e2, 0x14100040, - { 0x35, 0x07 } + 0x4f006b, 0x1df020c, 0x2301e2, 0, + { 0x8b, 0x4 } }; -#if 0 /* not filled in yet */ /* Register values for 640x480, 60Hz mode (5) */ static struct aty_regvals aty_gt_reg_init_5 = { - { 0x200, 0x200, 0x200 }, - { }, - { 0x35, 0x07 } + { 0x43, 0xe8, 0x04 }, + { 0x2c0253, 0x2c0152, 0x2c0551 }, + { 0x460a06, 0x580555, 0}, + { 0x880734, 0xc00734, 0x1000734 }, + + 0x4f0063, 0x1df020c, 0x2201e9, 0, + { 0xe8, 0x04 } +}; + +#if 0 +/* Register values for x, Hz mode (4) */ +static struct aty_regvals aty_gt_reg_init_4 = { +}; + +/* Register values for x, Hz mode (3) */ +static struct aty_regvals aty_gt_reg_init_3 = { +}; + +/* Register values for x, Hz mode (2) */ +static struct aty_regvals aty_gt_reg_init_2 = { +}; + +/* Register values for x, Hz mode (1) */ +static struct aty_regvals aty_gt_reg_init_1 = { }; #endif + +/* yikes, more data structures (dsp2) + * XXX kludge for sgram + */ +static int sgram_dsp[20][3] = { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0x5203d7,0x7803d9,0xb803dd}, //5 + {0x940666,0xe0066a,0x1700672}, //6 + {0,0,0}, + {0,0,0}, + {0x88055f,0xd80563,0x170056b}, //9 + {0x8404d9,0xb804dd,0x17004e5}, //10 + {0x7803e2,0xb803e6,0x17003ee}, //11 + {0x7803eb,0xb803ef,0x17003f7}, //12 + {0xe806c5,0x17006cd,0x2e006dd}, //13 + {0xe005f6,0x17005fe,0x2e0060e}, //14 + {0xd8052c,0x1700534,0x2e00544}, //15 + {0,0,0}, + {0xb804f2,0x17004e5,0x2e0050a}, //17 + {0xb803e6,0x17003ee,0x2e003fe}, //18 + {0,0,0}, + {0,0,0}, +}; diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/ati-gx.h linux/drivers/macintosh/ati-gx.h --- v2.1.78/linux/drivers/macintosh/ati-gx.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/ati-gx.h Mon Jan 12 15:18:13 1998 @@ -0,0 +1,149 @@ +#if 0 /* not filled inaty_gt_reg_init yet */ +/* Register values for 1280x1024, 75Hz mode (20) */ +static struct aty_regvals aty_gx_reg_init_20 = { + { 0x10, 0x28, 0x3c }, + { }, + { } /* pixel clock = 134.61MHz for V=74.81Hz */ +}; + +/* Register values for 1280x960, 75Hz mode (19) */ +static struct aty_regvals aty_gx_reg_init_19 = { + { 0x10, 0x28, 0x3c }, + { }, + { } /* pixel clock = 126.01MHz for V=75.01 Hz */ +}; + +/* Register values for 1152x870, 75Hz mode (18) */ +static struct aty_regvals aty_gx_reg_init_18 = { + { 0x10, 0x28, 0x50 }, + { }, + { } /* pixel clock = 100.33MHz for V=75.31Hz */ +}; + +/* Register values for 1024x768, 75Hz mode (17) */ +static struct aty_regvals aty_gx_reg_init_17 = { + { 0x10, 0x28, 0x50 }, + { }, + { } /* pixel clock = 79.55MHz for V=74.50Hz */ +}; + +/* Register values for 1024x768, 72Hz mode (15) */ +static struct aty_regvals aty_gx_reg_init_15 = { + { 0x10, 0x28, 0x50 }, + { }, + { } /* pixel clock = 78.12MHz for V=72.12Hz */ +}; + +#endif + + +/* Register values for 1280x1024, 60Hz mode (20) */ +static struct aty_regvals aty_gx_reg_init_20 = { + { 0, 0, 0 }, + + { 0x310086, 0x310084, 0x310084 }, + { 0x3070200, 0x30e0300, 0x30e0300 }, + { 0x2002312, 0x3002312, 0x3002312 }, + + 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000, + { 0x88, 0x7 } +}; + +/* Register values for 1024x768, 75Hz mode (17) */ +static struct aty_regvals aty_gx_reg_init_17 = { + { 0, 0, 0 }, + + { 0xc0085, 0xc0083, 0xc0083 }, + { 0x3070200, 0x30e0300, 0x30e0300 }, + { 0x2002312, 0x3002312, 0x3002312 }, + + 0x7f00a3, 0x2ff031f, 0x30300, 0x20100000, + { 0x41, 0x3 } +}; + +/* Register values for 1024x768, 72Hz mode (15) */ +static struct aty_regvals aty_gx_reg_init_15 = { + { 0, 0, 0 }, + + { 0x310086, 0x310084, 0x310084 }, + { 0x3070200, 0x30e0300, 0x30e0300 }, + { 0x2002312, 0x3002312, 0x3002312 }, + + 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000, + { 0x88, 0x7 } +}; + +/* Register values for 1024x768, 60Hz mode (14) */ +static struct aty_regvals aty_gx_reg_init_14 = { + { 0, 0, 0 }, + + { 0x310086, 0x310084, 0x310084 }, + { 0x3060200, 0x30d0300, 0x30d0300 }, + { 0x2002312, 0x3002312, 0x3002312 }, + + 0x7f00a7, 0x2ff0325, 0x260302, 0x20100000, + { 0x6c, 0x6 } +}; + +/* Register values for 832x624, 75Hz mode (13) */ +static struct aty_regvals aty_gx_reg_init_13 = { + { 0x200, 0x200, 0x200 }, + + { 0x28006f, 0x28006d, 0x28006c }, + { 0x3050200, 0x30b0300, 0x30e0600 }, + { 0x2002312, 0x3002312, 0x6002312 }, + + 0x67008f, 0x26f029a, 0x230270, 0x1a100040, + { 0x4f, 0x05 } +}; + +#if 0 /* not filled in yet */ +/* Register values for 800x600, 75Hz mode (12) */ +static struct aty_regvals aty_gx_reg_init_12 = { + { 0x10, 0x28, 0x50 }, + { }, + { } /* pixel clock = 49.11MHz for V=74.40Hz */ +}; + +/* Register values for 800x600, 72Hz mode (11) */ +static struct aty_regvals aty_gx_reg_init_11 = { + { 0x10, 0x28, 0x50 }, + { }, + { } /* pixel clock = 49.63MHz for V=71.66Hz */ +}; + +/* Register values for 800x600, 60Hz mode (10) */ +static struct aty_regvals aty_gx_reg_init_10 = { + { 0x10, 0x28, 0x50 }, + { }, + { } /* pixel clock = 41.41MHz for V=59.78Hz */ +}; + +/* Register values for 640x870, 75Hz Full Page Display (7) */ +static struct aty_regvals aty_gx_reg_init_7 = { + { 0x10, 0x30, 0x68 }, + { }, + { } /* pixel clock = 57.29MHz for V=75.01Hz */ +}; +#endif + +/* Register values for 640x480, 67Hz mode (6) */ +static struct aty_regvals aty_gx_reg_init_6 = { + { 0x200, 0x200, 0x200 }, + + { 0x28005b, 0x280059, 0x280058 }, + { 0x3040200, 0x3060300, 0x30c0600 }, + { 0x2002312, 0x3002312, 0x6002312 }, + + 0x4f006b, 0x1df020c, 0x2301e2, 0x14100040, + { 0x35, 0x07 } +}; + +#if 0 /* not filled in yet */ +/* Register values for 640x480, 60Hz mode (5) */ +static struct aty_regvals aty_gx_reg_init_5 = { + { 0x200, 0x200, 0x200 }, + { }, + { 0x35, 0x07 } +}; +#endif diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/ati-vt.h linux/drivers/macintosh/ati-vt.h --- v2.1.78/linux/drivers/macintosh/ati-vt.h Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/ati-vt.h Mon Jan 12 15:18:13 1998 @@ -1,147 +1,147 @@ -#if 0 /* not filled inaty_vt_reg_init yet */ -/* Register values for 640x870, 75Hz Full Page Display (7) */ -static struct aty_regvals aty_vt_reg_init_7 = { - { 0x10, 0x30, 0x68 }, - { }, - { } /* pixel clock = 57.29MHz for V=75.01Hz */ -}; - -/* Register values for 1024x768, 72Hz mode (15) */ -static struct aty_regvals aty_vt_reg_init_15 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 78.12MHz for V=72.12Hz */ -}; - -#endif - /* Register values for 1280x1024, 60Hz mode (20) */ static struct aty_regvals aty_vt_reg_init_20 = { - { 0, 0, 0 }, - { 0x2e02a7, 0x2e02a7, 0x2e02a7}, - { 0x3070200, 0x3070200, 0x3070200}, - { 0xa00cb22, 0xb00cb23, 0xe00cb24 }, - - 0x9f00d2, 0x3ff0429, 0x30400, 0x28000000, - { 0x00, 0xaa } + { 0, 0, 0 }, + + { 0x002e02a7, 0x002e02a7, 0 }, + { 0x03070200, 0x03070200, 0 }, + { 0x0a00cb22, 0x0b00cb23, 0 }, + + 0x009f00d2, 0x03ff0429, 0x00030400, 0x28000000, + { 0x00, 0xaa } +}; + +/* Register values for 1280x960, 75Hz mode (19) */ +static struct aty_regvals aty_vt_reg_init_19 = { + { 0, 0, 0 }, + { 0x003202a3, 0x003201a2, 0 }, + { 0x030b0200, 0x030b0300, 0 }, + { 0x0a00cb22, 0x0b00cb23, 0 }, + + 0x009f00d1, 0x03bf03e7, 0x000303c0, 0x28000000, + { 0x00, 0xc6 } }; /* Register values for 1152x870, 75Hz mode (18) */ static struct aty_regvals aty_vt_reg_init_18 = { - { 0, 0, 0 }, - { 0x300295, 0x300194, 0x300194 }, - { 0x3060200, 0x30e0300, 0x30e0300 }, - { 0xa00cb21, 0xb00cb22, 0xe00cb23 }, - - 0x8f00b5, 0x3650392, 0x230368, 0x24000000, - { 0x00, 0x9d } - /* pixel clock = 100.33MHz for V=75.31Hz */ + { 0, 0, 0 }, + + { 0x00300295, 0x00300194, 0 }, + { 0x03080200, 0x03080300, 0 }, + { 0x0a00cb21, 0x0b00cb22, 0 }, + + 0x008f00b5, 0x03650392, 0x00230368, 0x24000000, + { 0x00, 0x9d } }; /* Register values for 1024x768, 75Hz mode (17) */ static struct aty_regvals aty_vt_reg_init_17 = { - { 0, 0, 0 }, + { 0, 0, 0 }, - { 0x2c0283, 0x2c0182, 0x2c0182 }, - { 0x3060200, 0x30a0300, 0x30a0300 }, - { 0xa00cb21, 0xb00cb22, 0xe00cb23 }, - - 0x7f00a3, 0x2ff031f, 0x30300, 0x20000000, - { 0x01, 0xf7 } + { 0x002c0283, 0x002c0182, 0 }, + { 0x03080200, 0x03080300, 0 }, + { 0x0a00cb21, 0x0b00cb22, 0 }, + + 0x007f00a3, 0x02ff031f, 0x00030300, 0x20000000, + { 0x01, 0xf7 } }; -/* Register values for 1024x768, 72Hz mode (15) */ +/* Register values for 1024x768, 70Hz mode (15) */ static struct aty_regvals aty_vt_reg_init_15 = { - { 0, 0, 0 }, + { 0, 0, 0 }, + { 0x00310284, 0x00310183, 0 }, + { 0x03080200, 0x03080300, 0 }, + { 0x0a00cb21, 0x0b00cb22, 0 }, - { 0x310284, 0x310183, 0x310183 }, - { 0x3060200, 0x3090300, 0x3090600 }, - { 0xa00cb21, 0xb00cb22, 0xe00cb23 }, - - 0x7f00a5, 0x2ff0325, 0x260302, 0x20000000, - { 0x01, 0xeb } + 0x007f00a5, 0x02ff0325, 0x00260302, 0x20000000, + { 0x01, 0xeb } }; /* Register values for 1024x768, 60Hz mode (14) */ static struct aty_regvals aty_vt_reg_init_14 = { - { 0, 0, 0 }, - { 0x310284, 0x310183, 0x310183 }, - { 0x3060200, 0x3080300, 0x30f0600 }, - { 0xa00cb21, 0xb00cb22, 0xe00cb23 }, + { 0, 0, 0 }, + + { 0x00310284, 0x00310183, 0x00310582 }, /* 32 bit 0x00310582 */ + { 0x03080200, 0x03080300, 0x03070600 }, /* 32 bit 0x03070600 */ + { 0x0a00cb21, 0x0b00cb22, 0x0e00cb23 }, - 0x7f00a7, 0x2ff0325, 0x260302, 0x20000000, - { 0x01, 0xcc } + 0x007f00a7, 0x02ff0325, 0x00260302, 0x20000000, + { 0x01, 0xcc } }; /* Register values for 832x624, 75Hz mode (13) */ static struct aty_regvals aty_vt_reg_init_13 = { - { 0, 0, 0 }, + { 0, 0, 0 }, - { 0x28026d, 0x28016c, 0x28016c }, - { 0x3060200, 0x3080300, 0x30f0600 }, - { 0xa00cb21, 0xb00cb21, 0xe00cb22 }, - - 0x67008f, 0x26f029a, 0x230270, 0x1a000000, - { 0x01, 0xb4 } + { 0x0028026d, 0x0028016c, 0x0028056b }, + { 0x03080200, 0x03070300, 0x03090600 }, + { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, + + 0x0067008f, 0x026f029a, 0x00230270, 0x1a000000, + { 0x01, 0xb4 } }; /* Register values for 800x600, 75Hz mode (12) */ static struct aty_regvals aty_vt_reg_init_12 = { - { 0, 0, 0 }, - { 0x2a0267, 0x2a0166, 0x2a0565 }, - { 0x3040200, 0x3060300, 0x30d0600 }, - { 0xa00cb21, 0xb00cb21, 0xe00cb22 }, - - 0x630083, 0x2570270, 0x30258, 0x19000000, - { 0x01, 0x9c } - /* pixel clock = 49.11MHz for V=74.40Hz */ + { 0, 0, 0 }, + + { 0x002a0267, 0x002a0166, 0x002a0565 }, + { 0x03040200, 0x03060300, 0x03070600 }, + { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, + + 0x00630083, 0x02570270, 0x00030258, 0x19000000, + { 0x01, 0x9c } }; /* Register values for 800x600, 72Hz mode (11) */ static struct aty_regvals aty_vt_reg_init_11 = { - { 0, 0, 0 }, - - { 0x2f026c, 0x2f016b, 0x2f056a }, - { 0x3040200, 0x3060300, 0x30d0600 }, - { 0xa00cb21, 0xb00cb21, 0xe00cb22 }, - - 0x630081, 0x257029b, 0x6027c, 0x19000000, - { 0x01, 0x9d } - /* pixel clock = 49.63MHz for V=71.66Hz */ + { 0, 0, 0 }, + + { 0x002f026c, 0x002f016b, 0x002f056a }, + { 0x03050200, 0x03070300, 0x03090600 }, + { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, + + 0x00630081, 0x02570299, 0x0006027c, 0x19000000, + { 0x01, 0x9d } }; /* Register values for 800x600, 60Hz mode (10) */ static struct aty_regvals aty_vt_reg_init_10 = { - { 0, 0, 0 }, - { 0x30026a, 0x300169, 0x300568 }, - { 0x3030200, 0x3050300, 0x30b0600 }, - { 0xa00cb21, 0xb00cb21, 0xe00cb22 }, - - 0x630083, 0x2570273, 0x40258, 0x19000000, - { 0x02, 0xfb } -/* pixel clock = 41.41MHz for V=59.78Hz */ + { 0, 0, 0 }, + + { 0x0030026a, 0x00300169, 0x00300568 }, + { 0x03050200, 0x03070300, 0x03090600 }, + { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, + + 0x00630083, 0x02570273, 0x00040258, 0x19000000, + { 0x02, 0xfb } }; /* Register values for 640x480, 67Hz mode (6) */ static struct aty_regvals aty_vt_reg_init_6 = { - { 0, 0, 0 }, - - { 0x280259, 0x280158, 0x280557 }, - { 0x3030200, 0x3040300, 0x3080600 }, - { 0xa00cb21, 0xb00cb21, 0xe00cb22 }, - - 0x4f006b, 0x1df020c, 0x2301e2, 0x14000000, - { 0x02, 0xbe } + { 0, 0, 0 }, + + { 0x00280259, 0x00280158, 0x00280557 }, + { 0x03050200, 0x03070300, 0x030a0600 }, + { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, + + 0x004f006b, 0x01df020c, 0x002301e2, 0x14000000, + { 0x02, 0xbe } }; /* Register values for 640x480, 60Hz mode (5) */ static struct aty_regvals aty_vt_reg_init_5 = { - { 0, 0, 0 }, - - { 0x2c0253, 0x2c0152, 0x2c0551 }, - { 0x3030200, 0x3040300, 0x3060600 }, - { 0xa00cb21, 0xb00cb21, 0xe00cb22 }, - - 0x4f0063, 0x1df020c, 0x2201e9, 0x14000000, - { 0x02, 0x9e } -}; + { 0, 0, 0 }, + + { 0x002c0253, 0x002c0152, 0x002c0551 }, + { 0x03050200, 0x03070300, 0x03090600 }, + { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, + + 0x004f0063, 0x01df020c, 0x002201e9, 0x14000000, + { 0x02, 0x9e } +}; + /* 8 bit 15 bit 32 bit */ +static int vt_mem_cntl[3][3] = { { 0x0A00CB21, 0x0B00CB21, 0x0E00CB21 }, /* 1 MB VRAM */ + { 0x0A00CB22, 0x0B00CB22, 0x0E00CB22 }, /* 2 MB VRAM */ + { 0x0200053B, 0x0300053B, 0x0600053B } /* 4 M B VRAM */ + }; + diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/aty.c linux/drivers/macintosh/aty.c --- v2.1.78/linux/drivers/macintosh/aty.c Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/aty.c Mon Jan 12 15:18:13 1998 @@ -4,6 +4,7 @@ * Copyright (C) 1997 Michael AK Tesch * written with much help from Jon Howell * changes to support the vt chip set by harry ac eaton + * gt chipset support, scrollback console by anthony tong * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,11 +19,11 @@ #include #include #include +#include +#include #include #include #include -#include -#include #include "pmac-cons.h" #include "aty.h" @@ -34,82 +35,105 @@ unsigned char cntl; }; -struct aty_regvals { - int offset[3]; /* first pixel address */ +typedef struct aty_regvals { + int offset[3]; /* first pixel address */ - int crtc_h_sync_strt_wid[3]; /* depth dependant */ - int crtc_gen_cntl[3]; - int mem_cntl[3]; - - int crtc_h_tot_disp; /* mode dependant */ - int crtc_v_tot_disp; - int crtc_v_sync_strt_wid; - int crtc_off_pitch; - - unsigned char clock_val[2]; /* vals for 20 and 21 */ + int crtc_h_sync_strt_wid[3]; /* depth dependant */ + int crtc_gen_cntl[3]; + int mem_cntl[3]; + + int crtc_h_tot_disp; /* mode dependant */ + int crtc_v_tot_disp; + int crtc_v_sync_strt_wid; + int crtc_off_pitch; + + unsigned char clock_val[2]; /* vals for 20 and 21 */ +} aty_regvals; + +struct rage_regvals { + int h_total, h_sync_start, h_sync_width; + int v_total, v_sync_start, v_sync_width; + int h_sync_neg, v_sync_neg; }; -/*static void set_aty_clock(unsigned char *params);*/ static int aty_vram_reqd(int vmode, int cmode); +static aty_regvals *get_aty_struct(void); static unsigned char *frame_buffer; static int total_vram; /* total amount of video memory, bytes */ -static int is_vt_chip; /* whether a vt chip type was detected */ +static int chip_type; /* what chip type was detected */ -static unsigned long aty_regbase; +static unsigned long ati_regbase; static struct aty_cmap_regs *aty_cmap_regs; +#if 0 /* this array contains the number of bytes/line for each mode and color depth */ static int pitch[20][3] = { - {0,0,0}, /* mode 1?? */ - {0,0,0}, /* mode 2?? */ - {0,0,0}, /* mode 3??*/ - {0,0,0}, /* mode 4?? */ - {640, 1280, 2560}, /* mode 5 */ - {640, 1280, 2560}, /* mode 6 */ - {640, 1280, 2560}, /* mode 7 */ - {800, 1600, 3200}, /* mode 8 */ - {0,0,0}, /* mode 9 ??*/ - {800, 1600, 3200}, /* mode 10 */ - {800, 1600, 3200}, /* mode 11 */ - {800, 1600, 3200}, /* mode 12 */ - {832, 1664, 3328}, /* mode 13 */ - {1024, 2048, 4096}, /* mode 14 */ - {1024, 2048, 4096}, /* mode 15 */ - {1024, 2048, 4096}, /* mode 16 */ - {1024, 2048, 4096}, /* mode 17 */ - {1152, 2304, 4608}, /* mode 18 */ - {1280, 2560, 5120}, /* mode 19 */ - {1280, 2560, 5120} /* mode 20 */ + {512, 1024, 2048}, /* mode 1 */ + {512, 1024, 2048}, /* mode 2 */ + {640, 1024, 2048}, /* mode 3 */ + {640, 1024, 2048}, /* mode 4 */ + {640, 1280, 2560}, /* mode 5 */ + {640, 1280, 2560}, /* mode 6 */ + {640, 1280, 2560}, /* mode 7 */ + {800, 1600, 3200}, /* mode 8 */ + {768, 1536, 2072}, /* mode 9 */ + {800, 1600, 3200}, /* mode 10 */ + {800, 1600, 3200}, /* mode 11 */ + {800, 1600, 3200}, /* mode 12 */ + {832, 1664, 3328}, /* mode 13 */ + {1024, 2048, 4096}, /* mode 14 */ + {1024, 2048, 4096}, /* mode 15 */ + {1024, 2048, 4096}, /* mode 16 */ + {1024, 2048, 4096}, /* mode 17 */ + {1152, 2304, 4608}, /* mode 18 */ + {1280, 2560, 5120}, /* mode 19 */ + {1280, 2560, 5120} /* mode 20 */ }; +#endif +#include "ati-gx.h" #include "ati-gt.h" #include "ati-vt.h" static struct aty_regvals *aty_gt_reg_init[20] = { NULL, NULL, NULL, NULL, + &aty_gt_reg_init_5, &aty_gt_reg_init_6, - &aty_gt_reg_init_6, - NULL, NULL, NULL, - NULL, - NULL,NULL, + &aty_gt_reg_init_9, + &aty_gt_reg_init_10, + &aty_gt_reg_init_11, + &aty_gt_reg_init_12, &aty_gt_reg_init_13, &aty_gt_reg_init_14, &aty_gt_reg_init_15, NULL, &aty_gt_reg_init_17, - NULL, + &aty_gt_reg_init_18, NULL, &aty_gt_reg_init_20 }; -static struct aty_regvals *aty_vt_reg_init[20] = { +static struct aty_regvals *aty_gx_reg_init[20] = { NULL, NULL, NULL, NULL, - &aty_vt_reg_init_5, - &aty_vt_reg_init_6, + &aty_gx_reg_init_6, + &aty_gx_reg_init_6, + NULL, NULL, NULL, NULL, NULL, NULL, + &aty_gx_reg_init_13, + &aty_gx_reg_init_14, + &aty_gx_reg_init_15, NULL, + &aty_gx_reg_init_17, NULL, NULL, + &aty_gx_reg_init_20 +}; + +static struct aty_regvals *aty_vt_reg_init[21] = { + NULL, NULL, NULL, NULL, + &aty_vt_reg_init_5, + &aty_vt_reg_init_6, + NULL, NULL, NULL, &aty_vt_reg_init_10, &aty_vt_reg_init_11, &aty_vt_reg_init_12, @@ -119,330 +143,489 @@ NULL, &aty_vt_reg_init_17, &aty_vt_reg_init_18, - NULL, + &aty_vt_reg_init_19, &aty_vt_reg_init_20 }; -static inline int aty_vram_reqd(int vmode, int cmode) +static inline int +aty_vram_reqd(int vmode, int cmode) { - return vmode_attrs[vmode-1].vres - * pitch[vmode-1][cmode]; + return vmode_attrs[vmode - 1].vres * + (vmode_attrs[vmode - 1].hres << cmode); } -extern inline unsigned aty_ld_rev(volatile unsigned long addr) +extern inline unsigned aty_ld_le32(volatile unsigned long addr) { - unsigned val; + register unsigned long temp = ati_regbase,val; - (long)addr += (long)aty_regbase; - asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr)); - return val; + asm("lwbrx %0,%1,%2": "=r"(val):"r"(addr), "r"(temp)); + return val; } -extern inline void aty_st_rev(volatile unsigned long addr, unsigned val) +extern inline void aty_st_le32(volatile unsigned long addr, unsigned val) { - (long)addr += (long)aty_regbase; - asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory"); + register unsigned long temp = ati_regbase; + asm("stwbrx %0,%1,%2": : "r"(val), "r"(addr), "r"(temp):"memory"); } -extern inline unsigned char aty_ld_byte(volatile unsigned long addr) +extern inline unsigned char aty_ld_8(volatile unsigned long addr) { - unsigned char val; - - val = *(char*)((long)addr+(long)aty_regbase); - return val; + return *(char *) ((long) addr + (long) ati_regbase); } -extern inline void aty_st_byte(volatile unsigned long addr, unsigned char val) +extern inline void aty_st_8(volatile unsigned long addr, unsigned char val) { - *(unsigned char*)(addr+(unsigned long)aty_regbase) = val; + *(unsigned char *) (addr + (unsigned long) ati_regbase) = val; } -void -aty_st_514( int offset, char val ) +static void aty_st_514(int offset, char val) { - aty_WaitQueue(5); - aty_st_byte( DAC_CNTL, 1); - aty_st_byte( DAC_W_INDEX, offset & 0xff ); /* right addr byte */ - aty_st_byte( DAC_DATA, (offset>>8) & 0xff ); /* left addr byte */ - aty_st_byte( DAC_MASK, val ); - aty_st_byte( DAC_CNTL, 0 ); + aty_WaitQueue(5); + aty_st_8(DAC_CNTL, 1); + aty_st_8(DAC_W_INDEX, offset & 0xff); /* right addr byte */ + aty_st_8(DAC_DATA, (offset >> 8) & 0xff); /* left addr byte */ + eieio(); + aty_st_8(DAC_MASK, val); + eieio(); + aty_st_8(DAC_CNTL, 0); } -void -aty_st_pll( int offset, char val ) +static void +aty_st_pll(int offset, char val) { - aty_WaitQueue(3); - aty_st_byte( CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN ); /* write addr byte */ - aty_st_byte( CLOCK_CNTL + 2, val); /* write the register value */ - aty_st_byte( CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN); + aty_WaitQueue(3); + aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN); /* write addr byte */ + eieio(); + aty_st_8(CLOCK_CNTL + 2, val); /* write the register value */ + eieio(); + aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN); +} + +#if 0 // unused +static char +aty_ld_pll(int offset) +{ + aty_WaitQueue(2); + aty_st_8(CLOCK_CNTL + 1, offset << 2); + eieio(); + return aty_ld_8(CLOCK_CNTL + 2); } +#endif -#if 0 unsigned char -aty_ld_514( int offset ) +aty_ld_514(int offset) { -/* do the same thing as aty_st_514, just read the DAC_MASK instead of writing*/ +/* do the same thing as aty_st_514, just read the DAC_MASK instead of writing */ + char val; + + aty_WaitQueue(5); + aty_st_8(DAC_CNTL, 1); + aty_st_8(DAC_W_INDEX, offset & 0xff); /* right addr byte */ + aty_st_8(DAC_DATA, (offset >> 8) & 0xff); /* left addr byte */ + val = aty_ld_8(DAC_MASK); + eieio(); + aty_st_8(DAC_CNTL, 0); + return val; } -#endif void aty_set_palette(unsigned char red[], unsigned char green[], unsigned char blue[], int index, int ncolors) { - int i,scale; + int i, scale; + + aty_WaitQueue(2); + + i = aty_ld_8(DAC_CNTL) & 0xfc; + if (chip_type == MACH64_GT_ID) + i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ + aty_st_8(DAC_CNTL, i); + aty_st_8(DAC_REGS + DAC_MASK, 0xff); + eieio(); + scale = (chip_type != MACH64_GX_ID) + ? ((color_mode == CMODE_16) ? 3 : 0) : 0; + + for (i = 0; i < ncolors; ++i) { + aty_WaitQueue(4); + aty_cmap_regs->windex = (index + i) << scale; eieio(); + aty_cmap_regs->lut = red[i]; eieio(); + aty_cmap_regs->lut = green[i]; eieio(); + aty_cmap_regs->lut = blue[i]; eieio(); + } +} + +static aty_regvals +*get_aty_struct() +{ + int v = video_mode - 1; + + switch (chip_type) { + case MACH64_GT_ID: + return aty_gt_reg_init[v]; + break; + case MACH64_VT_ID: + return aty_vt_reg_init[v]; + break; + default: /* default to MACH64_GX_ID */ + return aty_gx_reg_init[v]; + break; + } +} + +static int +read_aty_sense(void) +{ + int sense, i; - aty_WaitQueue(2); - aty_st_byte(DAC_CNTL, aty_ld_byte(DAC_CNTL) & 0xfc); - aty_st_byte(DAC_REGS + DAC_MASK, 0xff); - eieio(); - scale = (is_vt_chip) ? ((color_mode == CMODE_16) ? 3 : 0) : 0; - for (i = 0; i < ncolors; ++i) { - aty_WaitQueue(4); - aty_cmap_regs->windex = (index + i) << scale; eieio(); - aty_cmap_regs->lut = red[i]; eieio(); - aty_cmap_regs->lut = green[i]; eieio(); - aty_cmap_regs->lut = blue[i]; eieio(); - } - + aty_st_le32(MON_SENSE, 0x31003100); /* drive outputs high */ + __delay(200); + aty_st_le32(MON_SENSE, 0); /* turn off outputs */ + __delay(2000); + i = aty_ld_le32(MON_SENSE); /* get primary sense value */ + sense = ((i & 0x3000) >> 3) | (i & 0x100); + + /* drive each sense line low in turn and collect the other 2 */ + aty_st_le32(MON_SENSE, 0x20000000); /* drive A low */ + __delay(2000); + i = aty_ld_le32(MON_SENSE); + sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); + aty_st_le32(MON_SENSE, 0x20002000); /* drive A high again */ + __delay(200); + + aty_st_le32(MON_SENSE, 0x10000000); /* drive B low */ + __delay(2000); + i = aty_ld_le32(MON_SENSE); + sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); + aty_st_le32(MON_SENSE, 0x10001000); /* drive B high again */ + __delay(200); + + aty_st_le32(MON_SENSE, 0x01000000); /* drive C low */ + __delay(2000); + sense |= (aty_ld_le32(MON_SENSE) & 0x3000) >> 12; + aty_st_le32(MON_SENSE, 0); /* turn off outputs */ + + return sense; } void map_aty_display(struct device_node *dp) { - int i, sense; - unsigned long addr; - unsigned char bus, devfn; - unsigned short cmd; - - if (dp->next != 0) - printk("Warning: only using first ATI card detected\n"); - if (dp->n_addrs != 1) - panic("expecting 1 addresses for ATY (got %d)", dp->n_addrs); - - aty_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000); - aty_cmap_regs = (struct aty_cmap_regs *)(aty_regbase+0xC0); - - /* enable memory-space accesses using config-space command register */ - if (pci_device_loc(dp, &bus, &devfn) == 0) { - pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); - if (cmd != 0xffff) { - cmd |= PCI_COMMAND_MEMORY; - pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); - } - } - - switch( aty_ld_rev(MEM_CNTL)&MEM_SIZE_ALIAS ) { - case MEM_SIZE_512K: - total_vram = 0x80000; - break; - case MEM_SIZE_1M: - total_vram = 0x100000; - break; - case MEM_SIZE_2M: - total_vram = 0x200000; - break; - case MEM_SIZE_4M: - total_vram = 0x400000; - break; - case MEM_SIZE_6M: - total_vram = 0x600000; - break; - case MEM_SIZE_8M: - total_vram = 0x800000; - break; - default: - total_vram = 0x80000; - } + struct aty_regvals *init; + int i, sense; + unsigned long addr; + unsigned char bus, devfn; + unsigned short cmd; + + if (dp->next != 0) + printk("Warning: only using first ATI card detected\n"); + if (dp->n_addrs != 1 && dp->n_addrs != 3) + printk("Warning: expecting 1 or 3 addresses for ATY (got %d)", + dp->n_addrs); + + ati_regbase = (int) ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000); + aty_cmap_regs = (struct aty_cmap_regs *) (ati_regbase + 0xC0); + + /* enable memory-space accesses using config-space command register */ + if (pci_device_loc(dp, &bus, &devfn) == 0) { + pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); + if (cmd != 0xffff) { + cmd |= PCI_COMMAND_MEMORY; + pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); + } + } + chip_type = (aty_ld_le32(CONFIG_CHIP_ID) & CFG_CHIP_TYPE); + + i = aty_ld_le32(MEM_CNTL); + if (chip_type != MACH64_GT_ID) + switch (i & MEM_SIZE_ALIAS) { + case MEM_SIZE_512K: + total_vram = 0x80000; + break; + case MEM_SIZE_1M: + total_vram = 0x100000; + break; + case MEM_SIZE_2M: + total_vram = 0x200000; + break; + case MEM_SIZE_4M: + total_vram = 0x400000; + break; + case MEM_SIZE_6M: + total_vram = 0x600000; + break; + case MEM_SIZE_8M: + total_vram = 0x800000; + break; + default: + total_vram = 0x80000; + } + else + switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ + case MEM_SIZE_512K: + total_vram = 0x80000; + break; + case MEM_SIZE_1M: + total_vram = 0x100000; + break; + case MEM_SIZE_2M_GTB: + total_vram = 0x200000; + break; + case MEM_SIZE_4M_GTB: + total_vram = 0x400000; + break; + case MEM_SIZE_6M_GTB: + total_vram = 0x600000; + break; + case MEM_SIZE_8M_GTB: + total_vram = 0x800000; + break; + default: + total_vram = 0x80000; + } + #if 1 - printk("aty_display_init: node = %p, addrs = ", dp->node); - printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size); - printk(", intrs ="); - for (i = 0; i < dp->n_intrs; ++i) - printk(" %x", dp->intrs[i]); - printk( "\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int)aty_regbase, - bus, devfn, total_vram, (int)aty_cmap_regs ); + printk("aty_display_init: node = %p, addrs = ", dp->node); + printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size); + printk(", intrs ="); + for (i = 0; i < dp->n_intrs; ++i) + printk(" %x", dp->intrs[i]); + printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int) ati_regbase, + bus, devfn, total_vram, (int) aty_cmap_regs); #endif - is_vt_chip = ((aty_ld_rev(CONFIG_CHIP_ID) & CFG_CHIP_TYPE) == MACH64_VT_ID); - /* Map in frame buffer */ - addr = dp->addrs[0].address; - - /* use the big-endian aperture (??) */ - addr += 0x800000; - frame_buffer = ioremap(addr, 0x800000); - - - /* sense = read_aty_sense(); XXX not yet, just give it mine */ - sense = 0x62b; - if (video_mode == VMODE_NVRAM) { - video_mode = nvram_read_byte(NV_VMODE); - if (video_mode <= 0 || video_mode > VMODE_MAX - || ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0) - video_mode = VMODE_CHOOSE; - } - if (video_mode == VMODE_CHOOSE) - video_mode = map_monitor_sense(sense); - if (((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0) - video_mode = VMODE_640_480_60; - - /* - * Reduce the pixel size if we don't have enough VRAM. - */ - - if (color_mode == CMODE_NVRAM) - color_mode = nvram_read_byte(NV_CMODE); - if (color_mode < CMODE_8 || color_mode > CMODE_32) - color_mode = CMODE_8; - while (aty_vram_reqd(video_mode, color_mode) > total_vram) { - while (color_mode > CMODE_8 - && aty_vram_reqd(video_mode, color_mode) > total_vram) - --color_mode; - /* - * adjust the video mode smaller if there still is not enough VRAM + /* Map in frame buffer */ + addr = dp->addrs[0].address; + + /* use the big-endian aperture (??) */ + addr += 0x800000; + frame_buffer = ioremap(addr, 0x800000); + + sense = read_aty_sense(); + printk("monitor sense = %x\n", sense); + if (video_mode == VMODE_NVRAM) { + video_mode = nvram_read_byte(NV_VMODE); + init = get_aty_struct(); + if (video_mode <= 0 || video_mode > VMODE_MAX || init == 0) + video_mode = VMODE_CHOOSE; + } + if (video_mode == VMODE_CHOOSE) + video_mode = map_monitor_sense(sense); + + init = get_aty_struct(); + if (!init) + video_mode = VMODE_640_480_60; + + /* + * Reduce the pixel size if we don't have enough VRAM. */ - if (aty_vram_reqd(video_mode, color_mode) > total_vram) - while ((((is_vt_chip) ? aty_vt_reg_init[--video_mode - 1] - : aty_gt_reg_init[--video_mode -1 ]) == 0) && (video_mode > VMODE_640_480_60)) ; - } -} -#if 0 -static void -set_aty_clock(unsigned char *params) -{ - /* done in aty_init...probably need to change for different modes */ - printk("tried to set ATY clock\n"); + if (color_mode == CMODE_NVRAM) + color_mode = nvram_read_byte(NV_CMODE); + if (color_mode < CMODE_8 || color_mode > CMODE_32) + color_mode = CMODE_8; + + while (aty_vram_reqd(video_mode, color_mode) > total_vram) { + while (color_mode > CMODE_8 + && aty_vram_reqd(video_mode, color_mode) > total_vram) + --color_mode; + /* + * adjust the video mode smaller if there still is not enough VRAM + */ + if (aty_vram_reqd(video_mode, color_mode) > total_vram) { + do { + video_mode--; + init = get_aty_struct(); + } while ((init == 0) && (video_mode > VMODE_640_480_60)); + } + } + + if (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5 + && init->crtc_gen_cntl[1] == 0) { + video_mode = 6; color_mode = 0; + } + return; } -#endif void RGB514_Program(int cmode) { - typedef struct { - char pixel_dly; - char misc2_cntl; - char pixel_rep; - char pixel_cntl_index; - char pixel_cntl_v1; - } RGB514_DAC_Table; - - static RGB514_DAC_Table RGB514DAC_Tab[8] = { - { 0, 0x41, 0x03, 0x71, 0x45 }, // 8bpp - { 0, 0x45, 0x04, 0x0c, 0x01 }, // 555 - { 0, 0x45, 0x06, 0x0e, 0x00 }, // XRGB - }; - RGB514_DAC_Table *pDacProgTab; - - pDacProgTab = &RGB514DAC_Tab[cmode]; - - aty_st_514(0x90, 0x00); - aty_st_514(0x04, pDacProgTab->pixel_dly); - aty_st_514(0x05, 0x00); - - aty_st_514(0x2, 0x1); - aty_st_514(0x71, pDacProgTab->misc2_cntl); - aty_st_514(0x0a, pDacProgTab->pixel_rep); + typedef struct { + char pixel_dly; + char misc2_cntl; + char pixel_rep; + char pixel_cntl_index; + char pixel_cntl_v1; + } RGB514_DAC_Table; + + static RGB514_DAC_Table RGB514DAC_Tab[8] = { + {0, 0x41, 0x03, 0x71, 0x45}, // 8bpp + {0, 0x45, 0x04, 0x0c, 0x01}, // 555 + {0, 0x45, 0x06, 0x0e, 0x00}, // XRGB + }; + RGB514_DAC_Table *pDacProgTab; + + pDacProgTab = &RGB514DAC_Tab[cmode]; + + aty_st_514(0x90, 0x00); + aty_st_514(0x04, pDacProgTab->pixel_dly); + aty_st_514(0x05, 0x00); + + aty_st_514(0x2, 0x1); + aty_st_514(0x71, pDacProgTab->misc2_cntl); + aty_st_514(0x0a, pDacProgTab->pixel_rep); - aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1); + aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1); } -/* The vt chipset seems to need a specialized color table for 15 bit mode */ void -VT_Program(int cmode) +aty_init() { -#if 0 - int i; - if (cmode != CMODE_8) { - aty_WaitQueue(2); - aty_cmap_regs->mask = 0xff; eieio(); - aty_cmap_regs->windex = 0; eieio(); - for (i = 0; i < 0x100; i++) { - aty_WaitQueue(3); - aty_cmap_regs->lut = i; - aty_cmap_regs->lut = i; - aty_cmap_regs->lut = i; eieio(); + int i, hres; + struct aty_regvals *init = get_aty_struct(); + int vram_type = aty_ld_le32(CONFIG_STAT0) & 7; + + if (init == 0) /* paranoia, shouldn't get here */ + panic("aty: display mode %d not supported", video_mode); + + n_scanlines = vmode_attrs[video_mode - 1].vres; + hres = vmode_attrs[video_mode - 1].hres; + pixel_size = 1 << color_mode; + line_pitch = vmode_attrs[video_mode - 1].hres << color_mode; + row_pitch = line_pitch * 16; + + /* clear FIFO errors */ + aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_HOST_ERR_ACK + | BUS_FIFO_ERR_ACK); + + /* Reset engine */ + i = aty_ld_le32(GEN_TEST_CNTL); + aty_st_le32(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE); + eieio(); + aty_WaitIdleEmpty(); + aty_st_le32(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE); + aty_WaitIdleEmpty(); + + if ( chip_type != MACH64_GT_ID ) { + i = aty_ld_le32(CRTC_GEN_CNTL); + aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN); + } + + if ( chip_type == MACH64_GX_ID ) { + i = aty_ld_le32(GEN_TEST_CNTL); + aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN ); + } + + switch (chip_type) { + case MACH64_VT_ID: + aty_st_pll(PLL_MACRO_CNTL, 0xb5); + aty_st_pll(PLL_REF_DIV, 0x2d); + aty_st_pll(PLL_GEN_CNTL, 0x14); + aty_st_pll(MCLK_FB_DIV, 0xbd); + aty_st_pll(PLL_VCLK_CNTL, 0x0b); + aty_st_pll(VCLK_POST_DIV, init->clock_val[0]); + aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]); + aty_st_pll(VCLK1_FB_DIV, 0xd6); + aty_st_pll(VCLK2_FB_DIV, 0xee); + aty_st_pll(VCLK3_FB_DIV, 0xf8); + aty_st_pll(PLL_XCLK_CNTL, 0x0); + aty_st_pll(PLL_TEST_CTRL, 0x0); + aty_st_pll(PLL_TEST_COUNT, 0x0); + break; + case MACH64_GT_ID: + if (vram_type == 5) { + aty_st_pll(0, 0xcd); + aty_st_pll(PLL_MACRO_CNTL, + video_mode >= VMODE_1024_768_60? 0xd3: 0xd5); + aty_st_pll(PLL_REF_DIV, 0x21); + aty_st_pll(PLL_GEN_CNTL, 0x44); + aty_st_pll(MCLK_FB_DIV, 0xe8); + aty_st_pll(PLL_VCLK_CNTL, 0x03); + aty_st_pll(VCLK_POST_DIV, init->offset[0]); + aty_st_pll(VCLK0_FB_DIV, init->offset[1]); + aty_st_pll(VCLK1_FB_DIV, 0x8e); + aty_st_pll(VCLK2_FB_DIV, 0x9e); + aty_st_pll(VCLK3_FB_DIV, 0xc6); + aty_st_pll(PLL_XCLK_CNTL, init->offset[2]); + aty_st_pll(12, 0xa6); + aty_st_pll(13, 0x1b); + } else { + aty_st_pll(PLL_MACRO_CNTL, 0xd5); + aty_st_pll(PLL_REF_DIV, 0x21); + aty_st_pll(PLL_GEN_CNTL, 0xc4); + aty_st_pll(MCLK_FB_DIV, 0xda); + aty_st_pll(PLL_VCLK_CNTL, 0x03); + /* offset actually holds clock values */ + aty_st_pll(VCLK_POST_DIV, init->offset[0]); + aty_st_pll(VCLK0_FB_DIV, init->offset[1]); + aty_st_pll(VCLK1_FB_DIV, 0x8e); + aty_st_pll(VCLK2_FB_DIV, 0x9e); + aty_st_pll(VCLK3_FB_DIV, 0xc6); + aty_st_pll(PLL_TEST_CTRL, 0x0); + aty_st_pll(PLL_XCLK_CNTL, init->offset[2]); + aty_st_pll(12, 0xa0); + aty_st_pll(13, 0x1b); } + break; + default: + RGB514_Program(color_mode); + aty_WaitIdleEmpty(); + aty_st_514(0x06, 0x02); + aty_st_514(0x10, 0x01); + aty_st_514(0x70, 0x01); + aty_st_514(0x8f, 0x1f); + aty_st_514(0x03, 0x00); + aty_st_514(0x05, 0x00); + aty_st_514(0x20, init->clock_val[0]); + aty_st_514(0x21, init->clock_val[1]); + break; } -#endif -} -void -aty_init() -{ - int i, yoff, hres; - unsigned *p; - struct aty_regvals *init; - - if (video_mode <= 0 || video_mode > VMODE_MAX - || (init = ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1])) == 0) - panic("aty: display mode %d not supported", video_mode); - n_scanlines = vmode_attrs[video_mode-1].vres; - hres = vmode_attrs[video_mode-1].hres; - pixel_size = 1 << color_mode; - line_pitch = pitch[video_mode-1][color_mode]; - row_pitch = line_pitch * 16; - - aty_st_rev(BUS_CNTL, aty_ld_rev(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK); - - /* Reset engine */ - i = aty_ld_rev(GEN_TEST_CNTL); - aty_st_rev(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE); - eieio(); - aty_WaitIdleEmpty(); - aty_st_rev(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE); - aty_WaitIdleEmpty(); - - i = aty_ld_byte(CRTC_GEN_CNTL+3); - aty_st_byte(CRTC_GEN_CNTL+3, i | (CRTC_EXT_DISP_EN >> 24)); - - i = aty_ld_byte(GEN_TEST_CNTL); - aty_st_byte(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN ); - - if (!is_vt_chip) { - RGB514_Program(color_mode); - - aty_WaitIdleEmpty(); - - aty_st_514(0x06, 0x02); - aty_st_514(0x10, 0x01); - aty_st_514(0x70, 0x01); - aty_st_514(0x8f, 0x1f); - aty_st_514(0x03, 0x00); - aty_st_514(0x05, 0x00); - - aty_st_514(0x20, init->clock_val[0]); - aty_st_514(0x21, init->clock_val[1]); - } else { - VT_Program(color_mode); - aty_st_pll(PLL_MACRO_CNTL, 0xb5); - aty_st_pll(PLL_REF_DIV, 0x2d); - aty_st_pll(PLL_GEN_CNTL, 0x14); - aty_st_pll(MCLK_FB_DIV, 0xbd); - aty_st_pll(PLL_VCLK_CNTL, 0x0b); - aty_st_pll(VCLK_POST_DIV, init->clock_val[0]); - aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]); - aty_st_pll(VCLK1_FB_DIV, 0xd6); - aty_st_pll(VCLK2_FB_DIV, 0xee); - aty_st_pll(VCLK3_FB_DIV, 0xf8); - aty_st_pll(PLL_XCLK_CNTL, 0x0); - aty_st_pll(PLL_TEST_CTRL, 0x0); - aty_st_pll(PLL_TEST_COUNT, 0x0); - } - - aty_ld_byte( DAC_REGS ); /* clear counter */ - - aty_WaitIdleEmpty(); - - aty_st_rev(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp); - aty_st_rev(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[color_mode]); - aty_st_rev(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp); - aty_st_rev(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid); - - aty_st_byte(CLOCK_CNTL, 0); - aty_st_byte(CLOCK_CNTL, CLOCK_STROBE); - - aty_st_rev(CRTC_OFF_PITCH, init->crtc_off_pitch); - - aty_st_rev(CRTC_VLINE_CRNT_VLINE, 0x14e01d0); + aty_ld_8(DAC_REGS); /* clear counter */ + aty_WaitIdleEmpty(); + + aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp); + aty_st_le32(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[color_mode]); + aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp); + aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid); + + aty_st_8(CLOCK_CNTL, 0); + aty_st_8(CLOCK_CNTL, CLOCK_STROBE); + + aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0); + + if (chip_type == MACH64_GT_ID) { + aty_st_le32(BUS_CNTL, 0x7b23a040); + + /* we calculate this so we can use a scrollback buffer. + * this should theoretically work with other ati's + * OFF_PITCH == (((hres + 7) & 0xfff8) >> 3) << 22 + */ + ati_set_origin(0); + + /* need to set DSP values !! assume sdram */ + i = init->crtc_gen_cntl[0] - (0x100000 * color_mode); + if ( vram_type == 5 ) + i = init->crtc_gen_cntl[1] - (0x100000 * color_mode); + aty_st_le32(DSP_CONFIG, i); + + i = aty_ld_le32(MEM_CNTL) & MEM_SIZE_ALIAS; + if ( vram_type == 5 ) { + i |= ((1 * color_mode) << 26) | 0x4215b0; + aty_st_le32(DSP_ON_OFF,sgram_dsp[video_mode-1][color_mode]); + + //aty_st_le32(CLOCK_CNTL,8192); + } else { + i |= ((1 * color_mode) << 26) | 0x300090; + aty_st_le32(DSP_ON_OFF, init->mem_cntl[color_mode]); + } + + aty_st_le32(MEM_CNTL, i); + aty_st_le32(EXT_MEM_CNTL, 0x5000001); + + /* if (total_vram > 0x400000) + i |= 0x538; this not been verified on > 4Megs!! */ + } else { + aty_st_le32(CRTC_OFF_PITCH, init->crtc_off_pitch); + /* The magic constant below translates into: * 5 = No RDY delay, 1 wait st for mem write, increment during burst transfer * 9 = DAC access delayed, 1 wait state for DAC @@ -455,75 +638,115 @@ * at some point it would be good to experiment with bench marks to see if * we can gain some speed by fooling with the wait states etc. */ - aty_st_rev(BUS_CNTL, 0x590e10ff); - i = aty_ld_rev(MEM_CNTL) & MEM_SIZE_ALIAS; - if (total_vram >= 0x400000) - aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] &0xffff0000) | 0x0538 | i); - else - aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] & ~MEM_SIZE_ALIAS) | i ); - aty_st_rev(CRTC_INT_CNTL, 0x2); - aty_WaitIdleEmpty(); + if (chip_type == MACH64_VT_ID) + aty_st_le32(BUS_CNTL, 0x680000f9); + else + aty_st_le32(BUS_CNTL, 0x590e10ff); + + switch (total_vram) { + case 0x00100000: + aty_st_le32(MEM_CNTL, vt_mem_cntl[0][color_mode]); + break; + case 0x00200000: + aty_st_le32(MEM_CNTL, vt_mem_cntl[1][color_mode]); + break; + case 0x00400000: + aty_st_le32(MEM_CNTL, vt_mem_cntl[2][color_mode]); + break; + default: + i = aty_ld_le32(MEM_CNTL) & 0x000F; + aty_st_le32(MEM_CNTL, (init->mem_cntl[color_mode] & 0xFFFFFFF0) | i); + } + } /* These magic constants are harder to figure out - * on the vt chipset bit 3 set makes the screen brighter + * on the vt chipset bit 2 set makes the screen brighter * and bit 15 makes the screen black! But nothing else * seems to matter for the vt DAC_CNTL */ - if (is_vt_chip) - aty_st_rev(DAC_CNTL, 0x47012104); - else - aty_st_rev(DAC_CNTL, 0x47012100); - - aty_st_byte(DAC_MASK, 0xff); - - aty_st_rev(CRTC_INT_CNTL, 0x00000002); - - aty_st_byte(CRTC_FIFO, ((char*)&init->crtc_gen_cntl[color_mode])[1] ); - aty_st_byte(CRTC_PIX_WIDTH, ((char*)&init->crtc_gen_cntl[color_mode])[2] ); - aty_st_byte(CRTC_EXT_DISP, ((char*)&init->crtc_gen_cntl[color_mode])[0] ); - - aty_st_rev(GEN_TEST_CNTL, 0x300); /* gui_en block_en*/ - - pmac_init_palette(); /* Initialize colormap */ - yoff = (n_scanlines % 16) / 2; - fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode]; - - /* Clear screen */ - p = (unsigned *) fb_start; - - for (i = n_scanlines * line_pitch * pixel_size / sizeof(unsigned); i != 0; --i) - *p++ = 0; - display_info.height = n_scanlines; - display_info.width = hres; - display_info.depth = pixel_size * 8; - display_info.pitch = line_pitch; - display_info.mode = video_mode; - strncpy(display_info.name, "ATY Mach64", sizeof(display_info.name)); - display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode]; - display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex; - display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut; - display_info.disp_reg_address = aty_regbase; + switch (chip_type) { + case MACH64_GT_ID: + i = 0x86010102; + break; + case MACH64_VT_ID: + i = 0x87010184; + break; + default: + i = 0x47012100; + break; + } + + aty_st_le32(DAC_CNTL, i); + aty_st_8(DAC_MASK, 0xff); + + switch (color_mode) { + case CMODE_16: + i = CRTC_PIX_WIDTH_15BPP; break; + /*case CMODE_24: */ + case CMODE_32: + i = CRTC_PIX_WIDTH_32BPP; break; + case CMODE_8: + default: + i = CRTC_PIX_WIDTH_8BPP; break; + } + + if (chip_type != MACH64_GT_ID) { + aty_st_le32(CRTC_INT_CNTL, 0x00000002); + aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE); /* gui_en block_en */ + i |= init->crtc_gen_cntl[color_mode]; + } + /* Gentlemen, start your crtc engine */ + aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_EXT_EN | i); + pmac_init_palette(); /* Initialize colormap */ + + /* clear screen */ + fb_start = frame_buffer + (((n_scanlines % 16) * line_pitch) >> 1); + memsetw((unsigned short *) fb_start, 0, total_vram); + + display_info.height = n_scanlines; + display_info.width = hres; + display_info.depth = pixel_size << 3; + display_info.pitch = line_pitch; + display_info.mode = video_mode; + strncpy(display_info.name, "ATY Mach64", sizeof(display_info.name)); + switch ( chip_type ) { + case MACH64_GX_ID: strcat(display_info.name,"GX"); + break; + case MACH64_VT_ID: strcat(display_info.name,"VT"); + break; + case MACH64_GT_ID: strcat(display_info.name,"GT"); + break; + default: strcat(display_info.name,"unknown"); + break; + } + display_info.fb_address = (chip_type != MACH64_GT_ID) ? + (unsigned long) frame_buffer + init->offset[color_mode] : + (unsigned long) frame_buffer; + display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex; + display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut; + display_info.disp_reg_address = ati_regbase; } int aty_setmode(struct vc_mode *mode, int doit) { - int cmode; -#if 0 + int cmode,old_vmode=video_mode; + struct aty_regvals *init; + +#if 1 if (mode->mode == 21) { - printk("hace: about to set 0x%x to 0x%x\n",mode->depth, mode->pitch & 0xff); - aty_st_byte(mode->depth, mode->pitch & 0xff); + printk("hace: about to set 0x%x to 0x%x\n", mode->depth, mode->pitch & 0xff); + aty_st_8(mode->depth, mode->pitch & 0xff); return 0; } - if (mode->mode == 0) { - printk("hace: 0x%x contains 0x%x\n",mode->depth, aty_ld_byte(mode->depth)); + printk("hace: 0x%x contains 0x%x\n", mode->depth, aty_ld_8(mode->depth)); return 0; } -#endif - - if (mode->mode <= 0 || mode->mode > VMODE_MAX - || ((is_vt_chip) ? aty_vt_reg_init[mode->mode-1] : aty_gt_reg_init[mode->mode-1]) == NULL) +#endif + + if (mode->mode <= 0 || mode->mode > VMODE_MAX ) return -EINVAL; + switch (mode->depth) { case 24: case 32: @@ -539,12 +762,25 @@ default: return -EINVAL; } - if (aty_vram_reqd(mode->mode, cmode) > total_vram) { + if (aty_vram_reqd(mode->mode, cmode) > total_vram) return -EINVAL; + + video_mode = mode->mode; + init = get_aty_struct(); + + /* Check if we know about the wanted video mode */ + if ( init == 0 || init->crtc_h_sync_strt_wid[cmode] == 0 + || (chip_type != MACH64_GT_ID && init->crtc_gen_cntl[cmode] == 0) + || (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5 + && init->crtc_gen_cntl[1] == 0)) { + video_mode = old_vmode; + return -EINVAL; } + if (doit) { video_mode = mode->mode; color_mode = cmode; + hide_cursor(); aty_init(); } return 0; @@ -555,7 +791,7 @@ { char gen_cntl; - gen_cntl = aty_ld_byte(CRTC_GEN_CNTL); + gen_cntl = aty_ld_8(CRTC_GEN_CNTL); if (blank_mode & VESA_VSYNC_SUSPEND) gen_cntl |= 0x8; if (blank_mode & VESA_HSYNC_SUSPEND) @@ -564,5 +800,33 @@ gen_cntl |= 0x40; if (blank_mode == VESA_NO_BLANKING) gen_cntl &= ~(0x4c); - aty_st_byte(CRTC_GEN_CNTL, gen_cntl); + aty_st_8(CRTC_GEN_CNTL, gen_cntl); } + +/* handle video scrollback; offset is in # of characters */ +void +ati_set_origin(unsigned short offset) +{ + register int x = (vmode_attrs[video_mode - 1].hres + 7) & 0xfff8, + lines = offset / video_num_columns, reg; + + reg = ((x >> 3) << 22) | /* calculate pitch */ + ((lines * video_font_height * x * (1<> 3); /*offset*/ + + aty_st_le32(CRTC_OFF_PITCH, reg); + aty_st_le32(DST_OFF_PITCH, reg); + aty_st_le32(SRC_OFF_PITCH, reg); + +#if 0 + fb_start = display_info.fb_address = + (unsigned long) frame_buffer + ((lines-2) * + vmode_attrs[video_mode-1].hres) << (4 + color_mode); +#endif +} + +int +ati_vram(void) +{ + return total_vram; +} + diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/aty.h linux/drivers/macintosh/aty.h --- v2.1.78/linux/drivers/macintosh/aty.h Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/aty.h Mon Jan 12 15:18:13 1998 @@ -14,9 +14,12 @@ extern void aty_init(void); extern int aty_setmode(struct vc_mode *mode, int doit); extern void aty_set_palette(unsigned char red[], unsigned char green[], - unsigned char blue[], int index, int ncolors); + unsigned char blue[], int index, int ncolors); extern void aty_set_blanking(int blank_mode); +extern void ati_set_origin(unsigned short offset); +extern int ati_vram(void); + /* * most of the rest of this file comes from ATI sample code */ @@ -49,6 +52,9 @@ #define CRTC_FIFO 0x001e #define CRTC_EXT_DISP 0x001f +#define DSP_CONFIG 0x0020 /* Dword offset 08 */ +#define DSP_ON_OFF 0x0024 /* Dword offset 09 */ + #define OVR_CLR 0x0040 /* Dword offset 10 */ #define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 11 */ #define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 12 */ @@ -59,6 +65,8 @@ #define CUR_HORZ_VERT_POSN 0x006C /* Dword offset 1B */ #define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 1C */ +#define MON_SENSE 0x0078 + #define SCRATCH_REG0 0x0080 /* Dword offset 20 */ #define SCRATCH_REG1 0x0084 /* Dword offset 21 */ @@ -67,6 +75,7 @@ #define BUS_CNTL 0x00A0 /* Dword offset 28 */ +#define EXT_MEM_CNTL 0x00AC /* Dword offset 2B */ #define MEM_CNTL 0x00B0 /* Dword offset 2C */ #define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 2D */ @@ -181,9 +190,9 @@ #define CRTC_PIX_BY_2_EN 0x00000020 #define CRTC_BLANK 0x00000040 -#define CRTC_PIX_WIDTH_MASK 0x00000700 -#define CRTC_PIX_WIDTH_4BPP 0x00000100 -#define CRTC_PIX_WIDTH_8BPP 0x00000200 +#define CRTC_PIX_WIDTH_MASK 0x00000700 +#define CRTC_PIX_WIDTH_4BPP 0x00000100 +#define CRTC_PIX_WIDTH_8BPP 0x00000200 #define CRTC_PIX_WIDTH_15BPP 0x00000300 #define CRTC_PIX_WIDTH_16BPP 0x00000400 #define CRTC_PIX_WIDTH_24BPP 0x00000500 @@ -252,6 +261,15 @@ #define GUI_ENGINE_ENABLE 0x100 #define BLOCK_WRITE_ENABLE 0x200 +/* DSP_CONFIG register constants */ +#define DSP_XCLKS_PER_QW 0x00003fff +#define DSP_LOOP_LATENCY 0x000f0000 +#define DSP_PRECISION 0x00700000 + +/* DSP_ON_OFF register constants */ +#define DSP_OFF 0x000007ff +#define DSP_ON 0x07ff0000 + /* CLOCK_CNTL register constants */ #define CLOCK_SEL 0x0f #define CLOCK_DIV 0x30 @@ -592,23 +610,23 @@ #define MACH64_NUM_FREQS 50 /* Wait until "v" queue entries are free */ -#define aty_WaitQueue(v) { while ((aty_ld_rev(FIFO_STAT) & 0xffff) > \ +#define aty_WaitQueue(v) { while ((aty_ld_le32(FIFO_STAT) & 0xffff) > \ ((unsigned short)(0x8000 >> (v)))); } /* Wait until GP is idle and queue is empty */ #define aty_WaitIdleEmpty() { aty_WaitQueue(16); \ - while ((aty_ld_rev(GUI_STAT) & 1) != 0); } + while ((aty_ld_le32(GUI_STAT) & 1) != 0); } #define SKIP_2(_v) ((((_v)<<1)&0xfff8)|((_v)&0x3)|(((_v)&0x80)>>5)) #define MACH64_BIT_BLT(_srcx, _srcy, _dstx, _dsty, _w, _h, _dir) \ { \ aty_WaitQueue(5); \ - aty_st_rev(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff))); \ - aty_st_rev(SRC_WIDTH1, (_w)); \ - aty_st_rev(DST_CNTL, (_dir)); \ - aty_st_rev(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff))); \ - aty_st_rev(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff))); \ + aty_st_le32(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff))); \ + aty_st_le32(SRC_WIDTH1, (_w)); \ + aty_st_le32(DST_CNTL, (_dir)); \ + aty_st_le32(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff))); \ + aty_st_le32(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff))); \ } #endif /* REGMACH64_H */ diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/chips.c linux/drivers/macintosh/chips.c --- v2.1.78/linux/drivers/macintosh/chips.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/chips.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,167 @@ +/* + * chips.c: Console support for PowerBook 3400/2400 chips65550 display adaptor. + * + * Copyright (C) 1997 Fabio Riccardi. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pmac-cons.h" +#include "chips.h" + + +static unsigned char *frame_buffer; +static unsigned char *blitter_regs; +static unsigned char *io_space; + +void +map_chips_display(struct device_node *dp) +{ + unsigned char bus, devfn; + unsigned short cmd; + unsigned long addr; + + addr = dp->addrs[0].address; + frame_buffer = ioremap(addr + 0x800000, 0x100000); + blitter_regs = ioremap(addr + 0xC00000, 4096); + + printk("Mapped chips65550 frame buffer at %p, blitter at %p\n", frame_buffer, blitter_regs); + + if (pci_device_loc(dp, &bus, &devfn) == 0) { + pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); + cmd |= 3; // enable memory and IO space + pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); + io_space = ioremap((unsigned long) pci_io_base(bus), 4096); + printk("Mapped chips65550 IO space at %p\n", io_space); + } + + video_mode = VMODE_800_600_60; + color_mode = CMODE_8; +} + +#define write_xr(num,val) { out_8(io_space + 0x3D6, num); out_8(io_space + 0x3D7, val); } +#define read_xr(num,var) { out_8(io_space + 0x3D6, num); var = in_8(io_space + 0x3D7); } +#define write_fr(num,val) { out_8(io_space + 0x3D0, num); out_8(io_space + 0x3D1, val); } +#define read_fr(num,var) { out_8(io_space + 0x3D0, num); var = in_8(io_space + 0x3D1); } +#define write_cr(num,val) { out_8(io_space + 0x3D4, num); out_8(io_space + 0x3D5, val); } +#define read_cr(num,var) { out_8(io_space + 0x3D4, num); var = in_8(io_space + 0x3D5); } + +void +chips_init() +{ + unsigned *p; + int i, hres; + + if (video_mode != VMODE_800_600_60) + panic("chips65550: display mode %d not supported", video_mode); + + if (color_mode != CMODE_8 && color_mode != CMODE_16) + panic("chips65550: color mode %d not supported", color_mode); + + n_scanlines = 600; + hres = 800; + pixel_size = 1 << color_mode; + line_pitch = hres * pixel_size; + row_pitch = line_pitch * 16; + + if (color_mode == CMODE_16) { + write_cr(0x13, 200); // 16 bit display width (decimal) + write_xr(0x81, 0x14); // 15 bit (TrueColor) color mode + write_xr(0x82, 0x00); // disable palettes + write_xr(0x20, 0x10); // 16 bit blitter mode + // write_xr(0x80, 0x00); // 6 bit DAC + // write_fr(0x11, 0X50); // No dither, 5 bits/color + } else if (color_mode == CMODE_8) { + write_cr(0x13, 100); // 8 bit display width (decimal) + write_xr(0x81, 0x12); // 8 bit color mode + write_xr(0x82, 0x08); // Graphics gamma enable + write_xr(0x20, 0x00); // 8 bit blitter mode + // write_xr(0x80, 0x82); // 8 bit DAC, CRT overscan + // write_fr(0x11, 0XE0); // Res Dither on, 6 bits/pixel + } + + pmac_init_palette(); /* Initialize colormap */ + + fb_start = frame_buffer; + + printk(KERN_INFO "hres = %d height = %d pitch = %d\n", + hres, n_scanlines, line_pitch); + + display_info.height = n_scanlines; + display_info.width = hres; + display_info.depth = pixel_size * 8; + display_info.pitch = line_pitch; + display_info.mode = video_mode; + strncpy(display_info.name, "chips65550", sizeof(display_info.name)); + display_info.fb_address = (unsigned long) frame_buffer; + display_info.cmap_adr_address = 0; + display_info.cmap_data_address = 0; + display_info.disp_reg_address = 0; + + /* Clear screen */ + p = (unsigned *) frame_buffer; + for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i) + *p++ = 0; +} + +int +chips_setmode(struct vc_mode *mode, int doit) +{ + int cmode; + + switch (mode->depth) { + case 16: + cmode = CMODE_16; + break; + case 8: + case 0: /* (default) */ + cmode = CMODE_8; + break; + default: + return -EINVAL; + } + + if (mode->mode != VMODE_800_600_60) + return -EINVAL; + + if (doit) { + video_mode = mode->mode; + color_mode = cmode; + chips_init(); + } + + return 0; +} + +void +chips_set_palette(unsigned char red[], unsigned char green[], + unsigned char blue[], int index, int ncolors) +{ + int i; + + for (i = 0; i < ncolors; ++i) { + out_8(&io_space[0x3C8], index + i); + udelay(1); + out_8(&io_space[0x3C9], red[i]); + out_8(&io_space[0x3C9], green[i]); + out_8(&io_space[0x3C9], blue[i]); + } +} + +void +chips_set_blanking(int blank_mode) +{ +} diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/chips.h linux/drivers/macintosh/chips.h --- v2.1.78/linux/drivers/macintosh/chips.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/chips.h Mon Jan 12 15:18:13 1998 @@ -0,0 +1,17 @@ +/* + * Exported procedures for the chips65550 display driver on PowerBook 3400/2400 + * + * Copyright (C) 1997 Fabio Riccardi. + * + * 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. + */ + +extern void map_chips_display(struct device_node *); +extern void chips_init(void); +extern int chips_setmode(struct vc_mode *mode, int doit); +extern void chips_set_palette(unsigned char red[], unsigned char green[], + unsigned char blue[], int index, int ncolors); +extern void chips_set_blanking(int blank_mode); diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/control.c linux/drivers/macintosh/control.c --- v2.1.78/linux/drivers/macintosh/control.c Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/control.c Mon Jan 12 15:18:13 1998 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include "pmac-cons.h" @@ -377,13 +378,13 @@ static void set_control_clock(unsigned char *params) { - struct cuda_request req; + struct adb_request req; int i; for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); - while (!req.got_reply) + while (!req.complete) cuda_poll(); } } diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.1.78/linux/drivers/macintosh/mac_keyb.c Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/mac_keyb.c Mon Jan 12 15:18:13 1998 @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -27,15 +28,19 @@ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ -unsigned char kbd_read_mask = 0; /* XXX */ - static void kbd_repeat(unsigned long); static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; static int last_keycode; -static void keyboard_input(unsigned char *, int, struct pt_regs *); +static void keyboard_input(unsigned char *, int, struct pt_regs *, int); static void input_keycode(int, int); -static void leds_done(struct cuda_request *); +static void leds_done(struct adb_request *); + +/* XXX: Hook for mouse driver */ +void (*adb_mouse_interrupt_hook) (char *, int); +int adb_emulate_button2; +int adb_emulate_button3; +extern int console_loglevel; extern struct kbd_struct kbd_table[]; @@ -75,14 +80,11 @@ if (!raw_mode) { /* * Convert R-shift/control/option to L version. - * Remap keycode 0 (A) to the unused keycode 0x5a. - * Other parts of the system assume 0 is not a valid keycode. */ switch (keycode) { case 0x7b: keycode = 0x38; break; /* R-shift */ case 0x7c: keycode = 0x3a; break; /* R-option */ case 0x7d: keycode = 0x36; break; /* R-control */ - case 0: keycode = 0x5a; break; /* A */ } } *keycodep = keycode; @@ -95,15 +97,15 @@ } static void -keyboard_input(unsigned char *data, int nb, struct pt_regs *regs) +keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll) { /* first check this is from register 0 */ - if (nb != 5 || (data[2] & 3) != KEYB_KEYREG) + if (nb != 3 || (data[0] & 3) != KEYB_KEYREG) return; /* ignore it */ kbd_pt_regs = regs; - input_keycode(data[3], 0); - if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f))) - input_keycode(data[4], 0); + input_keycode(data[1], 0); + if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f))) + input_keycode(data[2], 0); } static void @@ -114,10 +116,66 @@ kbd = kbd_table + fg_console; up_flag = (keycode & 0x80); - keycode &= 0x7f; + keycode &= 0x7f; + if (!repeat) del_timer(&repeat_timer); + /* + * XXX: Add mouse button 2+3 fake codes here if mouse open. + * Keep track of 'button' states here as we only send + * single up/down events! + * Really messy; might need to check if keyboard is in + * VC_RAW mode. + * Might also want to know how many buttons need to be emulated. + * -> hide this as function in arch/m68k/mac ? + */ + if (adb_mouse_interrupt_hook || console_loglevel == 10) { + unsigned char button, button2, button3, fake_event; + static unsigned char button2state=0, button3state=0; /* up */ + /* faked ADB packet */ + static char data[4] = { 0, 0x80, 0x80, 0x80 }; + + button = 0; + fake_event = 0; + switch (keycode) { /* which 'button' ? */ + case 0x7c: /* R-option */ + button2 = (!up_flag); /* new state */ + if (button2 != button2state) /* change ? */ + button = 2; + button2state = button2; /* save state */ + fake_event = 2; + break; + case 0x7d: /* R-control */ + button3 = (!up_flag); /* new state */ + if (button3 != button3state) /* change ? */ + button = 3; + button3state = button3; /* save state */ + fake_event = 3; + break; + } + if (fake_event && console_loglevel >= 8) + printk("fake event: button2 %d button3 %d button %d\n", + button2state, button3state, button); + if (button) { /* there's been a button state change */ + /* fake a mouse packet : send all bytes, change one! */ + data[button] = (up_flag ? 0x80 : 0); + if (adb_mouse_interrupt_hook) + adb_mouse_interrupt_hook(data, -1); + else + printk("mouse_fake: data %x %x %x buttons %x \n", + data[1], data[2], data[3], + ~( (data[1] & 0x80 ? 0 : 4) + | (data[2] & 0x80 ? 0 : 1) + | (data[3] & 0x80 ? 0 : 2) )&7 ); + } + /* + * XXX: testing mouse emulation ... don't process fake keys! + */ + if (fake_event) + return; + } + if (kbd->kbdmode != VC_RAW) { if (!up_flag && !dont_repeat[keycode]) { last_keycode = keycode; @@ -126,11 +184,23 @@ } /* - * XXX fix caps-lock behaviour by turning the key-up - * transition into a key-down transition. + * adb kludge!! Imitate pc caps lock behaviour by + * generating an up/down event for each time caps + * is pressed/released. Also, makes sure that the + * LED are handled. atong@uiuc.edu */ - if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK)) - up_flag = 0; + switch (keycode) { + /*case 0xb9:*/ + case 0x39: + handle_scancode(0x39); + handle_scancode(0xb9); + mark_bh(KEYBOARD_BH); + return; + case 0x47: + /*case 0xc7:*/ + mark_bh(KEYBOARD_BH); + break; + } } handle_scancode(keycode + up_flag); @@ -148,7 +218,7 @@ } static void -mouse_input(unsigned char *data, int nb, struct pt_regs *regs) +mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { /* [ACA:23-Mar-97] Three button mouse support. This is designed to function with MkLinux DR-2.1 style X servers. It only works with @@ -230,6 +300,18 @@ */ struct kbd_struct *kbd; + if (adb_mouse_interrupt_hook) + adb_mouse_interrupt_hook(data, nb); + else + if (console_loglevel == 10) + printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", + data[1], data[2], data[3], + ~((data[1] & 0x80 ? 0 : 4) + | (data[2] & 0x80 ? 0 : 1) + | (data[3] & 0x80 ? 0 : 2))&7, + ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ), + ((data[1]&0x7f) < 64 ? -(data[1]&0x7f) : 128-(data[1]&0x7f) ) ); + kbd = kbd_table + fg_console; /* Only send mouse codes when keyboard is in raw mode. */ @@ -239,13 +321,13 @@ /* Send first button, second button and movement. */ put_queue( 0x7e ); - put_queue( data[3] ); - put_queue( data[4] ); + put_queue( data[1] ); + put_queue( data[2] ); /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ /* Store the button state. */ - uchButtonSecond = (data[4] & 0x80); + uchButtonSecond = (data[2] & 0x80); /* Send second button. */ if (uchButtonSecond != uch_ButtonStateSecond) { @@ -254,12 +336,12 @@ } /* Macintosh 3-button mouse (handler 4). */ - if ((nb == 6) && (data[1] & 0x40)) { + if ((nb == 6) && autopoll /*?*/) { static unsigned char uch_ButtonStateThird = 0; unsigned char uchButtonThird; /* Store the button state for speed. */ - uchButtonThird = (data[5] & 0x80); + uchButtonThird = (data[3] & 0x80); /* Send third button. */ if (uchButtonThird != uch_ButtonStateThird) { @@ -282,20 +364,20 @@ 7, /* caps + num + scroll lock */ }; -static struct cuda_request led_request; +static struct adb_request led_request; static int leds_pending; void mackbd_leds(unsigned char leds) { - if (led_request.got_reply) { - cuda_request(&led_request, leds_done, 4, ADB_PACKET, + if (led_request.complete) { + adb_request(&led_request, leds_done, 0, 3, ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~mac_ledmap[leds]); } else leds_pending = leds | 0x100; } -static void leds_done(struct cuda_request *req) +static void leds_done(struct adb_request *req) { int leds; @@ -308,36 +390,32 @@ void mackbd_init_hw(void) { - struct cuda_request req; + struct adb_request req; + + /* initialize mouse interrupt hook */ + adb_mouse_interrupt_hook = NULL; + /* assume broken mouse :-) - should be adjusted based on + * result of the mouse setup !! (or passed as kernel option) */ + adb_emulate_button2 = 1; + adb_emulate_button3 = 1; adb_register(ADB_KEYBOARD, keyboard_input); adb_register(ADB_MOUSE, mouse_input); - /* turn on ADB auto-polling in the CUDA */ - cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); - while (!req.got_reply) - cuda_poll(); - /* turn off all leds */ - cuda_request(&req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff); - while (!req.got_reply) - cuda_poll(); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff); /* get the keyboard to send separate codes for left and right shift, control, option keys. */ - cuda_request(&req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); - while (!req.got_reply) - cuda_poll(); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); - led_request.got_reply = 1; + led_request.complete = 1; /* Try to switch the mouse (id 3) to handler 4, for three-button mode. (0x20 is Service Request Enable, 0x03 is Device ID). */ - cuda_request(&req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); - while (!req.got_reply) - cuda_poll(); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); } diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c --- v2.1.78/linux/drivers/macintosh/macio-adb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/macio-adb.c Mon Jan 12 15:18:13 1998 @@ -0,0 +1,211 @@ +/* + * Driver for the ADB controller in the Mac I/O (Hydra) chip. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct preg { + unsigned char r; + char pad[15]; +}; + +struct adb_regs { + struct preg intr; + struct preg data[9]; + struct preg intr_enb; + struct preg dcount; + struct preg error; + struct preg ctrl; + struct preg autopoll; + struct preg active_hi; + struct preg active_lo; + struct preg test; +}; + +/* Bits in intr and intr_enb registers */ +#define DFB 1 /* data from bus */ +#define TAG 2 /* transfer access grant */ + +/* Bits in dcount register */ +#define HMB 0x0f /* how many bytes */ +#define APD 0x10 /* auto-poll data */ + +/* Bits in error register */ +#define NRE 1 /* no response error */ +#define DLE 2 /* data lost error */ + +/* Bits in ctrl register */ +#define TAR 1 /* transfer access request */ +#define DTB 2 /* data to bus */ +#define CRE 4 /* command response expected */ +#define ADB_RST 8 /* ADB reset */ + +/* Bits in autopoll register */ +#define APE 1 /* autopoll enable */ + +static volatile struct adb_regs *adb; +static struct adb_request *current_req, *last_req; +static unsigned char adb_rbuf[16]; + +static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs); +static int macio_adb_send_request(struct adb_request *req, int sync); +static int macio_adb_autopoll(int on); +static void macio_adb_poll(void); +static void completed(void); + +void macio_adb_init(void) +{ + struct device_node *adbs; + + adbs = find_compatible_devices("adb", "chrp,adb0"); + if (adbs == 0) + return; + +#if 1 + { int i; + + printk("macio_adb_init: node = %p, addrs =", adbs->node); + for (i = 0; i < adbs->n_addrs; ++i) + printk(" %x(%x)", adbs->addrs[i].address, adbs->addrs[i].size); + printk(", intrs ="); + for (i = 0; i < adbs->n_intrs; ++i) + printk(" %x", adbs->intrs[i]); + printk("\n"); } +#endif + + adb = (volatile struct adb_regs *) adbs->addrs->address; + + if (request_irq(openpic_to_irq(adbs->intrs[0]), macio_adb_interrupt, + 0, "ADB", (void *)0)) { + printk(KERN_ERR "ADB: can't get irq %d\n", + openpic_to_irq(adbs->intrs[0])); + return; + } + + out_8(&adb->ctrl.r, 0); + out_8(&adb->intr.r, 0); + out_8(&adb->error.r, 0); + out_8(&adb->active_hi.r, 0xff); /* for now, set all devices active */ + out_8(&adb->active_lo.r, 0xff); + out_8(&adb->autopoll.r, APE); + out_8(&adb->intr_enb.r, DFB | TAG); + + adb_hardware = ADB_MACIO; + adb_send_request = macio_adb_send_request; + adb_autopoll = macio_adb_autopoll; +} + +static int macio_adb_autopoll(int on) +{ + out_8(&adb->autopoll.r, on? APE: 0); + return 0; +} + + +/* Send an ADB command */ +static int macio_adb_send_request(struct adb_request *req, int sync) +{ + unsigned long mflags; + + req->next = 0; + req->sent = 0; + req->complete = 0; + req->reply_len = 0; + + save_flags(mflags); + cli(); + if (current_req != 0) { + last_req->next = req; + last_req = req; + } else { + current_req = last_req = req; + out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR); + } + restore_flags(mflags); + + if (sync) { + while (!req->complete) + macio_adb_poll(); + } + + return 0; +} + +static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int i, n, err; + struct adb_request *req; + + if (in_8(&adb->intr.r) & TAG) { + if ((req = current_req) != 0) { + /* put the current request in */ + for (i = 0; i < req->nbytes; ++i) + out_8(&adb->data[i].r, req->data[i]); + out_8(&adb->dcount.r, req->nbytes & HMB); + req->sent = 1; + if (req->reply_expected) { + out_8(&adb->ctrl.r, DTB + CRE); + } else { + out_8(&adb->ctrl.r, DTB); + completed(); + } + } + out_8(&adb->intr.r, 0); + } + + if (in_8(&adb->intr.r) & DFB) { + err = in_8(&adb->error.r); + if (current_req && current_req->sent) { + /* this is the response to a command */ + req = current_req; + if (err == 0) { + req->reply_len = in_8(&adb->dcount.r) & HMB; + for (i = 0; i < req->reply_len; ++i) + req->reply[i] = in_8(&adb->data[i].r); + } + completed(); + } else if (err == 0) { + /* autopoll data */ + n = in_8(&adb->dcount.r) & HMB; + for (i = 0; i < n; ++i) + adb_rbuf[i] = in_8(&adb->data[i].r); + adb_input(adb_rbuf, n, regs, + in_8(&adb->dcount.r) & APD); + } + out_8(&adb->error.r, 0); + out_8(&adb->intr.r, 0); + } +} + +static void completed(void) +{ + struct adb_request *req = current_req; + + req->complete = 1; + current_req = req->next; + if (current_req) + out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR); + if (req->done) + (*req->done)(req); +} + +static void macio_adb_poll(void) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (in_8(&adb->intr.r) != 0) + macio_adb_interrupt(0, 0, 0); + restore_flags(flags); +} diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/mackeymap.c linux/drivers/macintosh/mackeymap.c --- v2.1.78/linux/drivers/macintosh/mackeymap.c Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/mackeymap.c Mon Jan 12 15:18:13 1998 @@ -6,7 +6,7 @@ #include u_short plain_map[NR_KEYS] = { - 0xf200, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, @@ -17,15 +17,15 @@ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, - 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, }; -u_short shift_map[NR_KEYS] = { - 0xf200, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, +static u_short shift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, @@ -36,15 +36,15 @@ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, - 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, }; -u_short altgr_map[NR_KEYS] = { - 0xf200, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, +static u_short altgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, @@ -55,15 +55,15 @@ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, - 0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, - 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, }; -u_short ctrl_map[NR_KEYS] = { - 0xf200, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, +static u_short ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, @@ -74,15 +74,15 @@ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, - 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, }; -u_short shift_ctrl_map[NR_KEYS] = { - 0xf200, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, +static u_short shift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, @@ -93,15 +93,15 @@ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, - 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, + 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c, }; -u_short alt_map[NR_KEYS] = { - 0xf200, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, +static u_short alt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, @@ -112,15 +112,15 @@ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, - 0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, - 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, }; -u_short ctrl_alt_map[NR_KEYS] = { - 0xf200, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, +static u_short ctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, @@ -131,11 +131,11 @@ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, - 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, }; ushort *key_maps[MAX_NR_KEYMAPS] = { diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/mackeymap.map linux/drivers/macintosh/mackeymap.map --- v2.1.78/linux/drivers/macintosh/mackeymap.map Mon Aug 18 18:19:45 1997 +++ linux/drivers/macintosh/mackeymap.map Mon Jan 12 15:18:14 1998 @@ -2,7 +2,8 @@ keymaps 0-2,4-5,8,12 # We use the Command (pretzel) key as Alt, and the Option key as AltGr. # -keycode 0x00 = +keycode 0x00 = a + altgr keycode 0x00 = Hex_A keycode 0x01 = s keycode 0x02 = d altgr keycode 0x02 = Hex_D @@ -162,9 +163,6 @@ keycode 0x59 = KP_7 alt keycode 0x59 = Ascii_7 altgr keycode 0x59 = Hex_7 -# keycode 0 (A) is remapped to here -keycode 0x5a = a - altgr keycode 0x00 = Hex_A keycode 0x5b = KP_8 alt keycode 0x5b = Ascii_8 altgr keycode 0x5b = Hex_8 diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.1.78/linux/drivers/macintosh/macserial.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/macintosh/macserial.c Mon Jan 12 15:18:14 1998 @@ -104,6 +104,7 @@ static void probe_sccs(void); static void change_speed(struct mac_serial *info); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static struct tty_struct *serial_table[NUM_CHANNELS]; static struct termios *serial_termios[NUM_CHANNELS]; @@ -325,7 +326,7 @@ if (!tty) continue; - queue_task(&tty->flip.tqueue, &tq_timer); + tty_flip_buffer_push(tty); if (tty->flip.count >= TTY_FLIPBUF_SIZE) { static int flip_buf_ovf; @@ -398,7 +399,8 @@ if (status & DCD) { wake_up_interruptible(&info->open_wait); } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) { - queue_task(&info->tqueue_hangup, &tq_scheduler); + if (info->tty) + tty_hangup(info->tty); } } @@ -548,27 +550,6 @@ } } -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void do_serial_hangup(void *private_) -{ - struct mac_serial *info = (struct mac_serial *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - tty_hangup(tty); -} - static void rs_timer(void) { } @@ -1196,21 +1177,25 @@ } /* - * This routine sends a break character out the serial port. + * rs_break - turn transmit break condition on/off */ -static void send_break( struct mac_serial * info, int duration) +static void rs_break(struct tty_struct *tty, int break_state) { + struct mac_serial *info = (struct mac_serial *) tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; if (!info->port) return; - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; - cli(); - info->curregs[5] |= SND_BRK; - write_zsreg(info->zs_channel, 5, info->curregs[5]); - schedule(); - info->curregs[5] &= ~SND_BRK; + + save_flags(flags); cli(); + if (break_state == -1) + info->curregs[5] |= SND_BRK; + else + info->curregs[5] &= ~SND_BRK; write_zsreg(info->zs_channel, 5, info->curregs[5]); - sti(); + restore_flags(flags); } static int rs_ioctl(struct tty_struct *tty, struct file * file, @@ -1218,7 +1203,6 @@ { int error; struct mac_serial * info = (struct mac_serial *)tty->driver_data; - int retval; if (serial_paranoia_check(info, tty->device, "rs_ioctl")) return -ENODEV; @@ -1231,31 +1215,6 @@ } switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - send_break(info, HZ/4); /* 1/4 second */ - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); - return 0; - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); - case TIOCSSOFTCAR: - error = get_user(arg, (int *) arg); - if (error) - return error; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; case TIOCMGET: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)); @@ -1326,7 +1285,6 @@ { struct mac_serial * info = (struct mac_serial *)tty->driver_data; unsigned long flags; - unsigned long timeout; if (!info || serial_paranoia_check(info, tty->device, "rs_close")) return; @@ -1395,14 +1353,7 @@ * Before we drop DTR, make sure the SCC transmitter * has completely drained. */ - timeout = jiffies+HZ; - while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->timeout; - schedule(); - if (jiffies > timeout) - break; - } + rs_wait_until_sent(tty, info->timeout); } shutdown(info); @@ -1413,14 +1364,6 @@ tty->closing = 0; info->event = 0; info->tty = 0; - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -1436,6 +1379,42 @@ } /* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct mac_serial *info = (struct mac_serial *) tty->driver_data; + unsigned long orig_jiffies, char_time; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); + while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + current->timeout = jiffies + char_time; + schedule(); + if (signal_pending(current)) + break; + if (timeout && ((orig_jiffies + timeout) < jiffies)) + break; + } + current->state = TASK_RUNNING; +} + +/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */ void rs_hangup(struct tty_struct *tty) @@ -1473,10 +1452,8 @@ if (info->flags & ZILOG_CLOSING) { interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - if (info->flags & ZILOG_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; + return ((info->flags & ZILOG_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; #endif @@ -1618,6 +1595,21 @@ info->tty = tty; /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ZILOG_CLOSING)) { + if (info->flags & ZILOG_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ZILOG_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* * Start up serial port */ retval = startup(info); @@ -1757,6 +1749,8 @@ serial_driver.stop = rs_stop; serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.wait_until_sent = rs_wait_until_sent; /* * The callout device is just like normal device except for @@ -1809,8 +1803,6 @@ info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; - info->tqueue_hangup.routine = do_serial_hangup; - info->tqueue_hangup.data = info; info->callout_termios =callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; info->open_wait = 0; diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c --- v2.1.78/linux/drivers/macintosh/nvram.c Tue Sep 23 16:48:47 1997 +++ linux/drivers/macintosh/nvram.c Mon Jan 12 15:18:14 1998 @@ -28,30 +28,40 @@ return file->f_pos; } -static long read_nvram(struct inode *inode, struct file *file, - char *buf, unsigned long count) +static ssize_t read_nvram(struct file *file, char *buf, + size_t count, loff_t *ppos) { - unsigned int i = file->f_pos; + unsigned int i; char *p = buf; - for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) - put_user(nvram_read_byte(i), p); - file->f_pos = i; + if (verify_area(VERIFY_WRITE, buf, count)) + return -EFAULT; + if (*ppos >= NVRAM_SIZE) + return 0; + for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) + if (__put_user(nvram_read_byte(i), p)) + return -EFAULT; + *ppos = i; return p - buf; } -static long write_nvram(struct inode *inode, struct file *file, - const char *buf, unsigned long count) +static ssize_t write_nvram(struct file *file, const char *buf, + size_t count, loff_t *ppos) { - unsigned int i = file->f_pos; + unsigned int i; const char *p = buf; char c; - for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) { - get_user(c, p); - nvram_write_byte(i, c); + if (verify_area(VERIFY_READ, buf, count)) + return -EFAULT; + if (*ppos >= NVRAM_SIZE) + return 0; + for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) { + if (__get_user(c, p)) + return -EFAULT; + nvram_write_byte(c, i); } - file->f_pos = i; + *ppos = i; return p - buf; } diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/pmac-cons.c linux/drivers/macintosh/pmac-cons.c --- v2.1.78/linux/drivers/macintosh/pmac-cons.c Mon Aug 18 18:19:46 1997 +++ linux/drivers/macintosh/pmac-cons.c Mon Jan 12 15:18:14 1998 @@ -19,7 +19,9 @@ #include #include #include +#include #include +#define INCLUDE_LINUX_LOGO_DATA #include #include #include @@ -28,6 +30,7 @@ #include "control.h" #include "platinum.h" #include "valkyrie.h" +#include "chips.h" #ifdef CONFIG_ATY_VIDEO #include "aty.h" #endif @@ -135,6 +138,8 @@ static void invert_cursor(int); static int map_unknown(struct device_node *); static void unknown_init(void); +static void unknown_set_palette(unsigned char red[], unsigned char green[], + unsigned char blue[], int index, int ncolors); struct display_interface { char *name; @@ -145,12 +150,22 @@ unsigned char blue[], int index, int ncolors); void (*set_blanking)(int blank_mode); } displays[] = { +#ifdef CONFIG_CONTROL_VIDEO { "control", map_control_display, control_init, control_setmode, control_set_palette, control_set_blanking }, +#endif +#ifdef CONFIG_PLATINUM_VIDEO { "platinum", map_platinum, platinum_init, platinum_setmode, platinum_set_palette, platinum_set_blanking }, +#endif +#ifdef CONFIG_VALKYRIE_VIDEO { "valkyrie", map_valkyrie_display, valkyrie_init, valkyrie_setmode, valkyrie_set_palette, valkyrie_set_blanking }, +#endif +#ifdef CONFIG_CHIPS_VIDEO + { "chips65550", map_chips_display, chips_init, + chips_setmode, chips_set_palette, chips_set_blanking }, +#endif #ifdef CONFIG_ATY_VIDEO { "ATY,mach64", map_aty_display, aty_init, aty_setmode, aty_set_palette, aty_set_blanking }, @@ -160,12 +175,16 @@ aty_setmode, aty_set_palette, aty_set_blanking }, { "ATY,mach64ii", map_aty_display, aty_init, aty_setmode, aty_set_palette, aty_set_blanking }, -#if 0 /* not right for 3D mach64 yet */ { "ATY,264GT-B", map_aty_display, aty_init, aty_setmode, aty_set_palette, aty_set_blanking }, { "ATY,mach64_3D_pcc", map_aty_display, aty_init, - aty_setmode, aty_set_palette }, -#endif + aty_setmode, aty_set_palette, aty_set_blanking }, + { "ATY,XCLAIM3D", map_aty_display, aty_init, + aty_setmode, aty_set_palette, aty_set_blanking }, + { "ATY,XCLAIMVR", map_aty_display, aty_init, + aty_setmode, aty_set_palette, aty_set_blanking }, + { "ATY,RAGEII_M", map_aty_display, aty_init, // untested!! + aty_setmode, aty_set_palette, aty_set_blanking }, #endif #ifdef CONFIG_IMSTT_VIDEO { "IMS,tt128mb", map_imstt_display, imstt_init, @@ -175,7 +194,7 @@ }; struct display_interface unknown_display = { - "unknown", NULL, unknown_init, NULL, NULL + "unknown", NULL, unknown_init, NULL, unknown_set_palette, NULL }; static struct display_interface *current_display; @@ -191,8 +210,6 @@ unsigned char *fb_start; /* addr of top left pixel of top left char */ struct vc_mode display_info; -extern int screen_initialized; /* in arch/ppc/pmac/prom.c */ - #define cmapsz (16*256) extern unsigned char vga_font[cmapsz]; @@ -500,8 +517,6 @@ struct vmode_attr *ap; current_display = NULL; - if (serial_console) - return; for (disp = displays; disp->name != NULL; ++disp) { dp = find_devices(disp->name); if (dp == 0) @@ -518,21 +533,23 @@ * we may be able to use it in a limited fashion. * If there is, it has already been opened in prom_init(). */ - if (prom_display_path[0] != 0) { - dp = find_path_device(prom_display_path); - if (dp != 0 && map_unknown(dp)) + int i; + for (i = 0; i < prom_num_displays; ++i) { + dp = find_path_device(prom_display_paths[i]); + if (dp != 0 && map_unknown(dp)) { current_display = &unknown_display; - else + break; + } else { printk(KERN_INFO "Can't use %s for display\n", - prom_display_path); + prom_display_paths[i]); + } } } if (current_display == NULL || video_mode <= 0 || video_mode > VMODE_MAX) { - printk(KERN_INFO "No usable display device found" - "- using serial console\n"); - serial_console = 1; /* no screen - fall back to serial */ + printk(KERN_INFO "No usable display device found\n"); + current_display = NULL; return; } ap = &vmode_attrs[video_mode - 1]; @@ -590,15 +607,6 @@ } void -pmac_cons_setup(char *str, int *ints) -{ - if (strcmp(str, "ttya") == 0 || strcmp(str, "modem") == 0) - serial_console = 1; - else if (strcmp(str, "ttyb") == 0 || strcmp(str, "printer") == 0) - serial_console = 2; -} - -void pmac_vmode_setup(char *str, int *ints) { if (ints[0] >= 1) @@ -611,9 +619,8 @@ con_type_init(unsigned long mem_start, const char **type_p) { if (current_display == NULL) - panic("no display available"); + return mem_start; current_display->init_interface(); - screen_initialized = 1; /* inhibits prom_print */ can_do_color = 1; video_type = VIDEO_TYPE_PMAC; *type_p = display_info.name; @@ -624,6 +631,12 @@ return mem_start; } +int +con_is_present(void) +{ + return current_display != NULL; +} + static __inline__ void draw_logo_8(void) { @@ -725,7 +738,14 @@ xy[1] = (LINUX_LOGO_HEIGHT + 16) / 16; putconsxy(0, xy); - p = "PowerMac/Linux " UTS_RELEASE; + switch (_machine) { + case _MACH_Pmac: + p = "PowerMac/Linux " UTS_RELEASE; + break; + default: + p = "Linux/PPC " UTS_RELEASE; + break; + } addr = (unsigned short *) video_mem_base + 2 * video_num_columns + LINUX_LOGO_WIDTH / 8 + 8; for (; *p; ++p) { @@ -868,6 +888,8 @@ }; static unsigned char *frame_buffer; +static unsigned char *unknown_cmap_adr; +static volatile unsigned char *unknown_cmap_data; static int map_unknown(struct device_node *dp) { @@ -914,9 +936,6 @@ return 0; } address = dp->addrs[i].address; - /* temporary kludge for valkyrie */ - if (strcmp(dp->name, "valkyrie") == 0) - address += 0x1000; } printk(KERN_INFO "%s: using address %x\n", dp->full_name, address); frame_buffer = ioremap(address, len); @@ -945,7 +964,15 @@ display_info.fb_address = (unsigned long) frame_buffer; display_info.cmap_adr_address = 0; display_info.cmap_data_address = 0; - display_info.disp_reg_address = 0; + unknown_cmap_adr = 0; + /* XXX kludge for ati */ + if (strncmp(dp->name, "ATY,", 4) == 0) { + display_info.disp_reg_address = address + 0x7ffc00; + display_info.cmap_adr_address = address + 0x7ffcc0; + display_info.cmap_data_address = address + 0x7ffcc1; + unknown_cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0; + unknown_cmap_data = unknown_cmap_adr + 1; + } return 1; } @@ -963,6 +990,25 @@ p = (unsigned *) frame_buffer; for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i) *p++ = 0; +} + +static void +unknown_set_palette(unsigned char red[], unsigned char green[], + unsigned char blue[], int index, int ncolors) +{ + volatile unsigned char *a, *d; + int i; + + if (unknown_cmap_adr == 0) + return; + a = unknown_cmap_adr; + d = unknown_cmap_data; + for (i = 0; i < ncolors; ++i) { + *a = index + i; eieio(); + *d = red[i]; eieio(); + *d = green[i]; eieio(); + *d = blue[i]; eieio(); + } } diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/pmac-cons.h linux/drivers/macintosh/pmac-cons.h --- v2.1.78/linux/drivers/macintosh/pmac-cons.h Mon Aug 18 18:19:46 1997 +++ linux/drivers/macintosh/pmac-cons.h Mon Jan 12 15:18:14 1998 @@ -9,8 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -extern int serial_console; /* set to use serial port as console */ - /* * Video mode values. * These are supposed to be the same as the values that diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/valkyrie.c linux/drivers/macintosh/valkyrie.c --- v2.1.78/linux/drivers/macintosh/valkyrie.c Mon Aug 18 18:19:46 1997 +++ linux/drivers/macintosh/valkyrie.c Mon Jan 12 15:18:14 1998 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include "pmac-cons.h" @@ -209,13 +210,13 @@ static void set_valkyrie_clock(unsigned char *params) { - struct cuda_request req; + struct adb_request req; int i; for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); - while (!req.got_reply) + while (!req.complete) cuda_poll(); } } diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c --- v2.1.78/linux/drivers/macintosh/via-cuda.c Mon Aug 18 18:19:46 1997 +++ linux/drivers/macintosh/via-cuda.c Mon Jan 12 15:18:14 1998 @@ -6,9 +6,6 @@ * Bus) which connects to the keyboard and mouse. The CUDA also * controls system power and the RTC (real time clock) chip. * - * This file also contains routines to support access to ADB - * devices via the /dev/adb interface. - * * Copyright (C) 1996 Paul Mackerras. */ #include @@ -18,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -58,10 +56,6 @@ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ -static struct adb_handler { - void (*handler)(unsigned char *, int, struct pt_regs *); -} adb_handler[16]; - static enum cuda_state { idle, sent_first_byte, @@ -71,8 +65,8 @@ awaiting_reply } cuda_state; -static struct cuda_request *current_req; -static struct cuda_request *last_req; +static struct adb_request *current_req; +static struct adb_request *last_req; static unsigned char cuda_rbuf[16]; static unsigned char *reply_ptr; static int reading_reply; @@ -82,6 +76,8 @@ static void cuda_start(void); static void via_interrupt(int irq, void *arg, struct pt_regs *regs); static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs); +static int cuda_adb_send_request(struct adb_request *req, int sync); +static int cuda_adb_autopoll(int on); void via_cuda_init() @@ -89,15 +85,10 @@ struct device_node *vias; vias = find_devices("via-cuda"); - if (vias == 0) { - printk(KERN_WARNING "Warning: no via-cuda\n"); - vias = find_devices("via-pmu"); - if (vias == 0) - return; - printk(KERN_WARNING "Found via-pmu, using it as via-cuda\n"); - } + if (vias == 0) + return; if (vias->next != 0) - printk("Warning: only using 1st via-cuda\n"); + printk(KERN_WARNING "Warning: only using 1st via-cuda\n"); #if 0 { int i; @@ -111,21 +102,34 @@ printk("\n"); } #endif - if (vias->n_addrs != 1 || vias->n_intrs != 1) - panic("via-cuda: expecting 1 address and 1 interrupt"); + if (vias->n_addrs != 1 || vias->n_intrs != 1) { + printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n", + vias->n_addrs, vias->n_intrs); + if (vias->n_addrs < 1 || vias->n_intrs < 1) + return; + } via = (volatile unsigned char *) vias->addrs->address; - if (!init_via()) - panic("init_via failed"); + if (!init_via()) { + printk(KERN_ERR "init_via failed\n"); + return; + } cuda_state = idle; - if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0)) - panic("VIA: can't get irq %d\n", vias->intrs[0]); + if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0)) { + printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0]); + return; + } /* Clear and enable interrupts */ via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */ + + /* Set function pointers */ + adb_hardware = ADB_VIACUDA; + adb_send_request = cuda_adb_send_request; + adb_autopoll = cuda_adb_autopoll; } #define WAIT_FOR(cond, what) \ @@ -178,9 +182,42 @@ return 1; } +/* Send an ADB command */ +static int +cuda_adb_send_request(struct adb_request *req, int sync) +{ + int i; + + for (i = req->nbytes; i > 0; --i) + req->data[i] = req->data[i-1]; + req->data[0] = ADB_PACKET; + ++req->nbytes; + req->reply_expected = 1; + i = cuda_send_request(req); + if (i) + return i; + if (sync) { + while (!req->complete) + cuda_poll(); + } + return 0; +} + +/* Enable/disable autopolling */ +static int +cuda_adb_autopoll(int on) +{ + struct adb_request req; + + cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, on); + while (!req.complete) + cuda_poll(); + return 0; +} + /* Construct and send a cuda request */ int -cuda_request(struct cuda_request *req, void (*done)(struct cuda_request *), +cuda_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...) { va_list list; @@ -197,13 +234,13 @@ } int -cuda_send_request(struct cuda_request *req) +cuda_send_request(struct adb_request *req) { unsigned long flags; req->next = 0; req->sent = 0; - req->got_reply = 0; + req->complete = 0; req->reply_len = 0; save_flags(flags); cli(); @@ -225,7 +262,7 @@ cuda_start() { unsigned long flags; - struct cuda_request *req; + struct adb_request *req; /* assert cuda_state == idle */ /* get the packet to send */ @@ -261,7 +298,7 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs) { int x, status; - struct cuda_request *req; + struct adb_request *req; if ((via[IFR] & SR_INT) == 0) return; @@ -351,7 +388,7 @@ if (reading_reply) { req = current_req; req->reply_len = reply_ptr - req->reply; - req->got_reply = 1; + req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); @@ -377,21 +414,11 @@ static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs) { - int i, id; - static int dump_cuda_input = 0; + int i; switch (buf[0]) { case ADB_PACKET: - id = buf[2] >> 4; - if (dump_cuda_input) { - printk(KERN_INFO "adb packet: "); - for (i = 0; i < nb; ++i) - printk(" %x", buf[i]); - printk(", id = %d\n", id); - } - if (adb_handler[id].handler != 0) { - (*adb_handler[id].handler)(buf, nb, regs); - } + adb_input(buf+2, nb-2, regs, buf[1] & 0x40); break; default: @@ -400,16 +427,4 @@ printk(" %.2x", buf[i]); printk("\n"); } -} - -/* Ultimately this should return the number of devices with - the given default id. */ -int -adb_register(int default_id, - void (*handler)(unsigned char *, int, struct pt_regs *)) -{ - if (adb_handler[default_id].handler != 0) - panic("Two handlers for ADB device %d\n", default_id); - adb_handler[default_id].handler = handler; - return 1; } diff -u --recursive --new-file v2.1.78/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.78/linux/drivers/net/3c59x.c Tue Jan 6 09:37:34 1998 +++ linux/drivers/net/3c59x.c Mon Jan 12 15:28:18 1998 @@ -15,7 +15,7 @@ */ static char *version = -"3c59x.c:v0.46B 9/25/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; +"3c59x.c:v0.47H 12/4/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -89,9 +89,10 @@ #endif #define virt_to_bus(addr) ((unsigned long)addr) #define bus_to_virt(addr) ((void*)addr) +#define NR_IRQS 16 #else /* 1.3.0 and later */ #define RUN_AT(x) (jiffies + (x)) -#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) +#define DEV_ALLOC_SKB(len) dev_alloc_skb(len) #endif #ifdef SA_SHIRQ @@ -111,8 +112,19 @@ #define udelay(microsec) do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) #endif -#if (LINUX_VERSION_CODE < 0x20123) +#if LINUX_VERSION_CODE < 0x20115 #define test_and_set_bit(val, addr) set_bit(val, addr) +#elif defined(MODULE) +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(compaq_ioaddr, "i"); +MODULE_PARM(compaq_irq, "i"); +MODULE_PARM(compaq_prod_id, "i"); #endif /* "Knobs" for adjusting internal parameters. */ @@ -147,7 +159,8 @@ /* Caution! These entries must be consistent, with the EISA ones last. */ static const int product_ids[] = { - 0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0, 0}; + 0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0x9055, + 0, 0}; static const char *product_names[] = { "3c590 Vortex 10Mbps", "3c595 Vortex 100baseTX", @@ -157,11 +170,12 @@ "3c900 Boomerang 10Mbps/Combo", "3c905 Boomerang 100baseTx", "3c905 Boomerang 100baseT4", + "3c905B Cyclone 100baseTx", "3c592 EISA 10mbps Demon/Vortex", "3c597 EISA Fast Demon/Vortex", }; -#define DEMON10_INDEX 8 -#define DEMON100_INDEX 9 +#define DEMON10_INDEX 9 +#define DEMON100_INDEX 10 /* Theory of Operation @@ -424,7 +438,7 @@ static int vortex_scan(struct device *dev); static struct device *vortex_found_device(struct device *dev, int ioaddr, - int irq, int product_index, + int irq, const char *product_name, int options, int card_idx); static int vortex_probe1(struct device *dev); static int vortex_open(struct device *dev); @@ -472,10 +486,10 @@ /* A list of all installed Vortex devices, for removing the driver module. */ static struct device *root_vortex_dev = NULL; +#ifdef MODULE /* Variables to work-around the Compaq PCI BIOS32 problem. */ -static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0; +static int compaq_ioaddr = 0, compaq_irq = 0; -#ifdef MODULE static int debug = -1; int @@ -510,6 +524,7 @@ static int vortex_scan(struct device *dev) { int cards_found = 0; + const char *product_name; #ifndef NO_PCI /* Allow an EISA-only driver. */ /* Ideally we would detect all cards in slot order. That would @@ -522,10 +537,10 @@ for (;pci_index < 0xff; pci_index++) { unsigned char pci_irq_line, pci_latency; - unsigned short pci_command, vendor, device; + unsigned short pci_command, new_command, vendor, device; unsigned int pci_ioaddr; - int board_index = 0; + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) @@ -538,6 +553,8 @@ PCI_INTERRUPT_LINE, &pci_irq_line); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_ioaddr); + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); /* Remove I/O space marker in bit 0. */ pci_ioaddr &= ~3; @@ -548,7 +565,13 @@ if (device == product_ids[board_index]) break; } - if (product_ids[board_index] == 0) { + if (product_ids[board_index]) + product_name = product_names[board_index]; + else if ((device & 0xfff0) == 0x9000) + product_name = "3c900"; + else if ((device & 0xfff0) == 0x9050) + product_name = "3c905"; + else { printk("Unknown 3Com PCI ethernet adapter type %4.4x detected:" " not configured.\n", device); continue; @@ -556,34 +579,34 @@ if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE)) continue; + new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled this" + " device! Updating PCI command %4.4x->%4.4x.\n", + pci_command, new_command); + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, new_command); + } + dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line, - board_index, dev && dev->mem_start + product_name, dev && dev->mem_start ? dev->mem_start : options[cards_found], cards_found); if (dev) { - /* Get and check the bus-master and latency values. - Some PCI BIOSes fail to set the master-enable bit, and + /* Get and check the latency values. On the 3c590 series the latency timer must be set to the maximum value to avoid data corruption that occurs when the timer expires during - a transfer -- a bug in the Vortex chip. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - if ( ! (pci_command & PCI_COMMAND_MASTER)) { - printk("%s: PCI Master Bit has not been set! " - " Setting...\n", dev->name); - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, pci_command); - } + a transfer -- a bug in the Vortex chip only. */ + unsigned char new_latency = (device&0xff00) == 0x5900 ? 248 : 32; pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency != 248) { + if (pci_latency < new_latency) { printk("%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is 248.\n", - dev->name, pci_latency); + " timer (CFLT) setting of %d, new value is %d.\n", + dev->name, pci_latency, new_latency); pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 248); + PCI_LATENCY_TIMER, new_latency); } dev = 0; cards_found++; @@ -596,7 +619,8 @@ if (EISA_bus) { static int ioaddr = 0x1000; for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - int product_id, product_index; + int product_id; + char *product_name; if (check_region(ioaddr, VORTEX_TOTAL_SIZE)) continue; /* Check the standard EISA ID register for an encoded '3Com'. */ @@ -605,13 +629,13 @@ /* Check for a product that we support, 3c59{2,7} any rev. */ product_id = inw(ioaddr + 0xC82) & 0xF0FF; if (product_id == 0x7059) /* 597 */ - product_index = DEMON100_INDEX; + product_name = "3c597 EISA Fast Demon/Vortex"; else if (product_id == 0x2059) /* 592 */ - product_index = DEMON10_INDEX; + product_name = "3c592 EISA 10mbps Demon/Vortex"; else continue; vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12, - product_index, dev && dev->mem_start + product_name, dev && dev->mem_start ? dev->mem_start : options[cards_found], cards_found); dev = 0; @@ -619,24 +643,25 @@ } } +#ifdef MODULE /* Special code to work-around the Compaq PCI BIOS32 problem. */ if (compaq_ioaddr) { - vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_prod_id, + vortex_found_device(dev, compaq_ioaddr, compaq_irq, "3Com Vortex", dev && dev->mem_start ? dev->mem_start : options[cards_found], cards_found); cards_found++; dev = 0; } +#endif - /* Finally check for a 3c515 on the ISA bus. */ - /* (3c515 support omitted on this version.) */ + /* 3c515 cards are now supported by the 3c515.c driver. */ return cards_found; } static struct device * vortex_found_device(struct device *dev, int ioaddr, int irq, - int product_index, int options, int card_idx) + const char *product_name, int options, int card_idx) { struct vortex_private *vp; @@ -654,7 +679,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->init = vortex_probe1; - vp->product_name = product_names[product_index]; + vp->product_name = product_name; vp->options = options; if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) @@ -687,7 +712,7 @@ dev->mtu = mtu; vp = (struct vortex_private *)dev->priv; - vp->product_name = product_names[product_index]; + vp->product_name = product_name; vp->options = options; if (options >= 0) { vp->media_override = ((options & 7) == 2) ? 0 : options & 7; @@ -717,7 +742,7 @@ /* Read the station address from the EEPROM. */ EL3WINDOW(0); for (i = 0; i < 0x18; i++) { - short *phys_addr = (short *)dev->dev_addr; + u16 *phys_addr = (u16 *)dev->dev_addr; int timer; outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ @@ -792,7 +817,7 @@ vp->info1 = eeprom[13]; vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; - if ((vp->capabilities & 0x20) && vp->bus_master) { + if (vp->capabilities & 0x20) { vp->full_bus_master_tx = 1; printk(" Enabling bus-master transmits and %s receives.\n", (vp->info2 & 1) ? "early" : "whole-frame" ); @@ -1045,13 +1070,17 @@ vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]); vp->rx_ring[i].status = 0; /* Clear complete bit. */ vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG; - skb = dev_alloc_skb(PKT_BUF_SZ); + skb = DEV_ALLOC_SKB(PKT_BUF_SZ); vp->rx_skbuff[i] = skb; if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ +#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = virt_to_bus(skb->tail); +#else + vp->rx_ring[i].addr = virt_to_bus(skb->data); +#endif } vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); @@ -1332,7 +1361,7 @@ /* Clear the Tx status stack. */ { short tx_status; - int i = 4; + int i = 32; while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ @@ -1431,9 +1460,10 @@ int latency; int i = max_interrupt_work; - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = 1; + if (test_and_set_bit(0, (void*)&dev->interrupt)) { + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); + return; + } ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); @@ -1560,7 +1590,16 @@ printk("%s: Host error, FIFO diagnostic register %4.4x.\n", dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ - if (fifo_diag & 0x0400) { + if (lp->full_bus_master_tx) { + int j; + outw(TotalReset | 0xff, ioaddr + EL3_CMD); + for (j = 200; j >= 0 ; j--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + /* Re-enable the receiver. */ + outw(RxEnable, ioaddr + EL3_CMD); + outw(TxEnable, ioaddr + EL3_CMD); + } else if (fifo_diag & 0x0400) { int j; outw(TxReset, ioaddr + EL3_CMD); for (j = 20; j >= 0 ; j--) @@ -1675,6 +1714,7 @@ int entry = vp->cur_rx % RX_RING_SIZE; int ioaddr = dev->base_addr; int rx_status; + int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; if (vortex_debug > 5) printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", @@ -1704,11 +1744,16 @@ if (pkt_len < rx_copybreak && (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) { skb->dev = dev; +#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), bus_to_virt(vp->rx_ring[entry].addr), pkt_len); +#else + memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr), pkt_len); + skb->len = pkt_len; +#endif rx_copy++; } else{ void *temp; @@ -1734,13 +1779,15 @@ vp->stats.rx_packets++; } entry = (++vp->cur_rx) % RX_RING_SIZE; + if (--rx_work_limit < 0) + break; } /* Refill the Rx ring buffers. */ for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) { struct sk_buff *skb; entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(PKT_BUF_SZ); + skb = DEV_ALLOC_SKB(PKT_BUF_SZ); if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ @@ -1914,7 +1961,7 @@ static void set_rx_mode(struct device *dev) { - short ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; short new_mode; if (dev->flags & IFF_PROMISC) { @@ -1964,4 +2011,3 @@ * tab-width: 4 * End: */ - diff -u --recursive --new-file v2.1.78/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.78/linux/drivers/net/de4x5.c Tue Dec 23 16:30:59 1997 +++ linux/drivers/net/de4x5.c Sat Jan 10 10:46:51 1998 @@ -364,11 +364,16 @@ Added generic MII PHY functionality to deal with newer PHY chips. Fix the mess in 2.1.67. + 0.532 5-Jan-98 Fix bug in mii_get_phy() reported by + . + Fix bug in pci_probe() for 64 bit systems reported + by . + 0.533 9-Jan-98 Fix more 64 bit bugs reported by . ========================================================================= */ -static const char *version = "de4x5.c:T0.531 1997/12/21 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.533 1998/1/9 davies@maniac.ultranet.com\n"; #include @@ -763,7 +768,7 @@ struct { void *priv; /* Original kmalloc'd mem addr */ void *buf; /* Original kmalloc'd mem addr */ - int lock; /* Lock the cache accesses */ + u_long lock; /* Lock the cache accesses */ s32 csr0; /* Saved Bus Mode Register */ s32 csr6; /* Saved Operating Mode Reg. */ s32 csr7; /* Saved IRQ Mask Register */ @@ -2076,8 +2081,8 @@ { u_char pb, pbus, dev_num, dnum, dev_fn, timer; u_short dev_id, vendor, index, status; - u_int irq = 0, device, class = DE4X5_CLASS_CODE; - u_long iobase; + u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_long iobase = 0; /* Clear upper 32 bits in Alphas */ struct bus_type *lp = &bus; if (lastPCI == NO_MORE_PCI) return; @@ -2137,8 +2142,8 @@ /* Get the board I/O address (64 bits on sparc64) */ #ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, - (int *)&iobase); + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); + iobase = tmp; #else iobase = pdev->base_address[0]; #endif @@ -2211,8 +2216,8 @@ { u_char pb, dev_fn; u_short dev_id, dev_num, vendor, status; - u_int irq = 0, device, class = DE4X5_CLASS_CODE; - u_long iobase; + u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j; struct bus_type *lp = &bus; @@ -2250,8 +2255,8 @@ /* Get the board I/O address (64 bits on sparc64) */ #ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, - (int *)&iobase); + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); + iobase = tmp; #else iobase = pdev->base_address[0]; #endif @@ -4985,7 +4990,9 @@ lp->phy[k].spd.reg = GENERIC_REG; /* ANLPA register */ lp->phy[k].spd.mask = GENERIC_MASK; /* 100Mb/s technologies */ lp->phy[k].spd.value = GENERIC_VALUE; /* TX & T4, H/F Duplex */ - printk("%s: Found MII device not currently supported. Please mail the following dump to\nthe author:\n", dev->name); + lp->mii_cnt++; + lp->active++; + printk("%s: Using generic MII device control. If the board doesn't operate, \nplease mail the following dump to the author:\n", dev->name); j = de4x5_debug; de4x5_debug |= DEBUG_MII; de4x5_dbg_mii(dev, k); diff -u --recursive --new-file v2.1.78/linux/drivers/net/dmascc.c linux/drivers/net/dmascc.c --- v2.1.78/linux/drivers/net/dmascc.c Wed Dec 10 11:12:43 1997 +++ linux/drivers/net/dmascc.c Wed Dec 31 16:00:00 1969 @@ -1,1260 +0,0 @@ -/* - * $Id: dmascc.c,v 1.2 1997/12/02 16:49:49 oe1kib Exp $ - * - * Driver for high-speed SCC boards (those with DMA support) - * Copyright (C) 1997 Klaus Kudielka - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "z8530.h" - - -/* Number of buffers per channel */ - -#define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (2 recommended) */ -#define NUM_RX_BUF 2 /* NUM_RX_BUF >= 1 (2 recommended) */ -#define BUF_SIZE 2016 - - -/* Cards supported */ - -#define HW_PI { "Ottawa PI", 0x300, 0x20, 0x10, 8, \ - 0, 8, 1843200, 3686400 } -#define HW_PI2 { "Ottawa PI2", 0x300, 0x20, 0x10, 8, \ - 0, 8, 3686400, 7372800 } -#define HW_TWIN { "Gracilis PackeTwin", 0x200, 0x10, 0x10, 32, \ - 0, 4, 6144000, 6144000 } - -#define HARDWARE { HW_PI, HW_PI2, HW_TWIN } - -#define TYPE_PI 0 -#define TYPE_PI2 1 -#define TYPE_TWIN 2 -#define NUM_TYPES 3 - -#define MAX_NUM_DEVS 32 - - -/* SCC chips supported */ - -#define Z8530 0 -#define Z85C30 1 -#define Z85230 2 - -#define CHIPNAMES { "Z8530", "Z85C30", "Z85230" } - - -/* I/O registers */ - -/* 8530 registers relative to card base */ -#define SCCB_CMD 0x00 -#define SCCB_DATA 0x01 -#define SCCA_CMD 0x02 -#define SCCA_DATA 0x03 - -/* 8254 registers relative to card base */ -#define TMR_CNT0 0x00 -#define TMR_CNT1 0x01 -#define TMR_CNT2 0x02 -#define TMR_CTRL 0x03 - -/* Additional PI/PI2 registers relative to card base */ -#define PI_DREQ_MASK 0x04 - -/* Additional PackeTwin registers relative to card base */ -#define TWIN_INT_REG 0x08 -#define TWIN_CLR_TMR1 0x09 -#define TWIN_CLR_TMR2 0x0a -#define TWIN_SPARE_1 0x0b -#define TWIN_DMA_CFG 0x08 -#define TWIN_SERIAL_CFG 0x09 -#define TWIN_DMA_CLR_FF 0x0a -#define TWIN_SPARE_2 0x0b - - -/* PackeTwin I/O register values */ - -/* INT_REG */ -#define TWIN_SCC_MSK 0x01 -#define TWIN_TMR1_MSK 0x02 -#define TWIN_TMR2_MSK 0x04 -#define TWIN_INT_MSK 0x07 - -/* SERIAL_CFG */ -#define TWIN_DTRA_ON 0x01 -#define TWIN_DTRB_ON 0x02 -#define TWIN_EXTCLKA 0x04 -#define TWIN_EXTCLKB 0x08 -#define TWIN_LOOPA_ON 0x10 -#define TWIN_LOOPB_ON 0x20 -#define TWIN_EI 0x80 - -/* DMA_CFG */ -#define TWIN_DMA_HDX_T1 0x08 -#define TWIN_DMA_HDX_R1 0x0a -#define TWIN_DMA_HDX_T3 0x14 -#define TWIN_DMA_HDX_R3 0x16 -#define TWIN_DMA_FDX_T3R1 0x1b -#define TWIN_DMA_FDX_T1R3 0x1d - - -/* Status values */ - -/* tx_state */ -#define TX_IDLE 0 -#define TX_OFF 1 -#define TX_TXDELAY 2 -#define TX_ACTIVE 3 -#define TX_SQDELAY 4 - - -/* Data types */ - -struct scc_hardware { - char *name; - int io_region; - int io_delta; - int io_size; - int num_devs; - int scc_offset; - int tmr_offset; - int tmr_hz; - int pclk_hz; -}; - -struct scc_priv { - char name[10]; - struct enet_statistics stats; - struct scc_info *info; - int channel; - int cmd, data, tmr; - struct scc_param param; - char rx_buf[NUM_RX_BUF][BUF_SIZE]; - int rx_len[NUM_RX_BUF]; - int rx_ptr; - struct tq_struct rx_task; - int rx_head, rx_tail, rx_count; - int rx_over; - char tx_buf[NUM_TX_BUF][BUF_SIZE]; - int tx_len[NUM_TX_BUF]; - int tx_ptr; - int tx_head, tx_tail, tx_count; - int tx_sem, tx_state; - unsigned long tx_start; - int status; -}; - -struct scc_info { - int type; - int chip; - int open; - int scc_base; - int tmr_base; - int twin_serial_cfg; - struct device dev[2]; - struct scc_priv priv[2]; - struct scc_info *next; -}; - - -/* Function declarations */ - -int dmascc_init(void) __init; -static int setup_adapter(int io, int h, int n) __init; - -static inline void write_scc(int ctl, int reg, int val); -static inline int read_scc(int ctl, int reg); -static int scc_open(struct device *dev); -static int scc_close(struct device *dev); -static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd); -static int scc_send_packet(struct sk_buff *skb, struct device *dev); -static struct enet_statistics *scc_get_stats(struct device *dev); -static int scc_set_mac_address(struct device *dev, void *sa); -static void scc_isr(int irq, void *dev_id, struct pt_regs * regs); -static inline void z8530_isr(struct scc_info *info); -static void rx_isr(struct device *dev); -static void special_condition(struct device *dev, int rc); -static void rx_bh(void *arg); -static void tx_isr(struct device *dev); -static void es_isr(struct device *dev); -static void tm_isr(struct device *dev); -static inline void delay(struct device *dev, int t); -static inline unsigned char random(void); - - -/* Initialization variables */ - -static int io[MAX_NUM_DEVS] __initdata = { 0, }; -/* Beware! hw[] is also used in cleanup_module(). If __initdata also applies - to modules, we may not declare hw[] as __initdata */ -static struct scc_hardware hw[NUM_TYPES] __initdata = HARDWARE; -static char ax25_broadcast[7] __initdata = - { 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1 }; -static char ax25_test[7] __initdata = - { 'L'<<1, 'I'<<1, 'N'<<1, 'U'<<1, 'X'<<1, ' '<<1, '1'<<1 }; - - -/* Global variables */ - -static struct scc_info *first = NULL; -static unsigned long rand; - - - -/* Module functions */ - -#ifdef MODULE - - -MODULE_AUTHOR("Klaus Kudielka "); -MODULE_DESCRIPTION("Driver for high-speed SCC boards"); -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); - - -int init_module(void) -{ - return dmascc_init(); -} - - -void cleanup_module(void) -{ - int i; - struct scc_info *info; - - while (first) { - info = first; - - /* Unregister devices */ - for (i = 0; i < 2; i++) { - if (info->dev[i].name) - unregister_netdev(&info->dev[i]); - } - - /* Reset board */ - if (info->type == TYPE_TWIN) - outb_p(0, info->dev[0].base_addr + TWIN_SERIAL_CFG); - write_scc(info->priv[0].cmd, R9, FHWRES); - release_region(info->dev[0].base_addr, - hw[info->type].io_size); - - /* Free memory */ - first = info->next; - kfree_s(info, sizeof(struct scc_info)); - } -} - - -#else - - -__initfunc(void dmascc_setup(char *str, int *ints)) -{ - int i; - - for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++) - io[i] = ints[i+1]; -} - - -#endif - - -/* Initialization functions */ - -__initfunc(int dmascc_init(void)) -{ - int h, i, j, n, base[MAX_NUM_DEVS], tcmd, t0, t1, status; - unsigned long time, start[MAX_NUM_DEVS], stop[MAX_NUM_DEVS]; - - /* Initialize random number generator */ - rand = jiffies; - - /* Cards found = 0 */ - n = 0; - - /* Run autodetection for each card type */ - for (h = 0; h < NUM_TYPES; h++) { - - if (io[0]) { - /* User-specified I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) base[i] = 0; - for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) { - j = (io[i] - hw[h].io_region) / hw[h].io_delta; - if (j >= 0 && - j < hw[h].num_devs && - hw[h].io_region + j * hw[h].io_delta == io[i]) - base[j] = io[i]; - } - } else { - /* Default I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) - base[i] = hw[h].io_region + i * hw[h].io_delta; - } - - /* Check valid I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i] && check_region(base[i], hw[h].io_size)) - base[i] = 0; - - /* Start timers */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - tcmd = base[i] + hw[h].tmr_offset + TMR_CTRL; - t0 = base[i] + hw[h].tmr_offset + TMR_CNT0; - t1 = base[i] + hw[h].tmr_offset + TMR_CNT1; - /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */ - outb_p(0x36, tcmd); - outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0); - outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0); - /* Timer 1: LSB+MSB, Mode 0, HZ/10 */ - outb_p(0x70, tcmd); - outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1); - outb_p((TMR_0_HZ/HZ*10) >> 8, t1); - /* Timer 2: LSB+MSB, Mode 0 */ - outb_p(0xb0, tcmd); - } - - /* Initialize start values in case we miss the null count bit */ - time = jiffies; - for (i = 0; i < hw[h].num_devs; i++) start[i] = time; - - /* Timing loop */ - while (jiffies - time < 12) { - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - /* Read back Timer 1: Status */ - outb_p(0xE4, base[i] + hw[h].tmr_offset + TMR_CTRL); - status = inb_p(base[i] + hw[h].tmr_offset + TMR_CNT1); - if ((status & 0x3F) != 0x30) base[i] = 0; - if (status & 0x40) start[i] = jiffies; - if (~status & 0x80) stop[i] = jiffies; - } - } - - /* Evaluate measurements */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - time = stop[i] - start[i]; - if (time < 9 || time > 11) - /* The time expired doesn't match */ - base[i] = 0; - else { - /* Ok, we have found an adapter */ - if (setup_adapter(base[i], h, n) == 0) - n++; - } - } - - } /* NUM_TYPES */ - - /* If any adapter was successfully initialized, return ok */ - if (n) return 0; - - /* If no adapter found, return error */ - printk("dmascc: no adapters found\n"); - return -EIO; -} - - -__initfunc(int setup_adapter(int io, int h, int n)) -{ - int i, irq, chip; - struct scc_info *info; - struct device *dev; - struct scc_priv *priv; - unsigned long time; - unsigned int irqs; - int tmr = io + hw[h].tmr_offset; - int scc = io + hw[h].scc_offset; - int cmd = scc + SCCA_CMD; - char *chipnames[] = CHIPNAMES; - - /* Reset 8530 */ - write_scc(cmd, R9, FHWRES | MIE | NV); - - /* Determine type of chip */ - write_scc(cmd, R15, 1); - if (!read_scc(cmd, R15)) { - /* WR7' not present. This is an ordinary Z8530 SCC. */ - chip = Z8530; - } else { - /* Put one character in TX FIFO */ - write_scc(cmd, R8, 0); - if (read_scc(cmd, R0) & Tx_BUF_EMP) { - /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ - chip = Z85230; - } else { - /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ - chip = Z85C30; - } - } - write_scc(cmd, R15, 0); - - /* Start IRQ auto-detection */ - sti(); - irqs = probe_irq_on(); - - /* Enable interrupts */ - switch (h) { - case TYPE_PI: - case TYPE_PI2: - outb_p(0, io + PI_DREQ_MASK); - write_scc(cmd, R15, CTSIE); - write_scc(cmd, R0, RES_EXT_INT); - write_scc(cmd, R1, EXT_INT_ENAB); - break; - case TYPE_TWIN: - outb_p(0, io + TWIN_DMA_CFG); - inb_p(io + TWIN_CLR_TMR1); - inb_p(io + TWIN_CLR_TMR2); - outb_p(TWIN_EI, io + TWIN_SERIAL_CFG); - break; - } - - /* Start timer */ - outb_p(1, tmr + TMR_CNT1); - outb_p(0, tmr + TMR_CNT1); - /* Wait and detect IRQ */ - time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); - irq = probe_irq_off(irqs); - - /* Clear pending interrupt, disable interrupts */ - switch (h) { - case TYPE_PI: - case TYPE_PI2: - write_scc(cmd, R1, 0); - write_scc(cmd, R15, 0); - write_scc(cmd, R0, RES_EXT_INT); - break; - case TYPE_TWIN: - inb_p(io + TWIN_CLR_TMR1); - outb_p(0, io + TWIN_SERIAL_CFG); - break; - } - - if (irq <= 0) { - printk("dmascc: could not find irq of %s at %#3x (irq=%d)\n", - hw[h].name, io, irq); - return -1; - } - - /* Allocate memory */ - info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); - if (!info) { - printk("dmascc: could not allocate memory for %s at %#3x\n", - hw[h].name, io); - return -1; - } - - /* Set up data structures */ - memset(info, 0, sizeof(struct scc_info)); - info->type = h; - info->chip = chip; - info->scc_base = io + hw[h].scc_offset; - info->tmr_base = io + hw[h].tmr_offset; - info->twin_serial_cfg = 0; - for (i = 0; i < 2; i++) { - dev = &info->dev[i]; - priv = &info->priv[i]; - sprintf(priv->name, "dmascc%i", 2*n+i); - priv->info = info; - priv->channel = i; - priv->cmd = info->scc_base + (i ? SCCB_CMD : SCCA_CMD); - priv->data = info->scc_base + (i ? SCCB_DATA : SCCA_DATA); - priv->tmr = info->tmr_base + (i ? TMR_CNT2 : TMR_CNT1); - priv->param.pclk_hz = hw[h].pclk_hz; - priv->param.brg_tc = -1; - priv->param.clocks = TCTRxCP | RCRTxCP; - priv->param.txdelay = TMR_0_HZ * 10 / 1000; - priv->param.txtime = HZ * 3; - priv->param.sqdelay = TMR_0_HZ * 1 / 1000; - priv->param.slottime = TMR_0_HZ * 10 / 1000; - priv->param.waittime = TMR_0_HZ * 100 / 1000; - priv->param.persist = 32; - priv->rx_task.routine = rx_bh; - priv->rx_task.data = dev; - dev->priv = priv; - dev->name = priv->name; - dev->base_addr = io; - dev->irq = irq; - dev->open = scc_open; - dev->stop = scc_close; - dev->do_ioctl = scc_ioctl; - dev->hard_start_xmit = scc_send_packet; - dev->get_stats = scc_get_stats; - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; - dev->set_mac_address = scc_set_mac_address; - dev->type = ARPHRD_AX25; - dev->hard_header_len = 73; - dev->mtu = 1500; - dev->addr_len = 7; - dev->tx_queue_len = 64; - memcpy(dev->broadcast, ax25_broadcast, 7); - memcpy(dev->dev_addr, ax25_test, 7); - dev->flags = 0; - dev_init_buffers(dev); - if (register_netdev(dev)) { - printk("dmascc: could not register %s\n", dev->name); - dev->name = NULL; - } - } - - request_region(io, hw[h].io_size, "dmascc"); - - info->next = first; - first = info; - printk("dmascc: found %s (%s) at %#3x, irq %d\n", hw[h].name, - chipnames[chip], io, irq); - return 0; -} - - -/* Driver functions */ - -static inline void write_scc(int ctl, int reg, int val) -{ - outb_p(reg, ctl); - outb_p(val, ctl); -} - - -static inline int read_scc(int ctl, int reg) -{ - outb_p(reg, ctl); - return inb_p(ctl); -} - - -static int scc_open(struct device *dev) -{ - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int io = dev->base_addr; - int cmd = priv->cmd; - - /* Request IRQ if not already used by other channel */ - if (!info->open) { - if (request_irq(dev->irq, scc_isr, SA_INTERRUPT, "dmascc", info)) - return -EAGAIN; - } - - /* Request DMA if required */ - if (dev->dma && request_dma(dev->dma, "dmascc")) { - if (!info->open) free_irq(dev->irq, info); - return -EAGAIN; - } - - /* Initialize local variables */ - dev->tbusy = 0; - priv->rx_ptr = 0; - priv->rx_over = 0; - priv->rx_head = priv->rx_tail = priv->rx_count = 0; - priv->tx_state = TX_IDLE; - priv->tx_head = priv->tx_tail = priv->tx_count = 0; - priv->tx_ptr = 0; - priv->tx_sem = 0; - - /* Reset channel */ - write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); - /* X1 clock, SDLC mode */ - write_scc(cmd, R4, SDLC | X1CLK); - /* DMA */ - write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN); - /* 8 bit RX char, RX disable */ - write_scc(cmd, R3, Rx8); - /* 8 bit TX char, TX disable */ - write_scc(cmd, R5, Tx8); - /* SDLC address field */ - write_scc(cmd, R6, 0); - /* SDLC flag */ - write_scc(cmd, R7, FLAG); - switch (info->chip) { - case Z85C30: - /* Select WR7' */ - write_scc(cmd, R15, 1); - /* Auto EOM reset */ - write_scc(cmd, R7, 0x02); - write_scc(cmd, R15, 0); - break; - case Z85230: - /* Select WR7' */ - write_scc(cmd, R15, 1); - /* RX FIFO half full (interrupt only), Auto EOM reset, - TX FIFO empty (DMA only) */ - write_scc(cmd, R7, dev->dma ? 0x22 : 0x0a); - write_scc(cmd, R15, 0); - break; - } - /* Preset CRC, NRZ(I) encoding */ - write_scc(cmd, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ)); - - /* Configure baud rate generator */ - if (priv->param.brg_tc >= 0) { - /* Program BR generator */ - write_scc(cmd, R12, priv->param.brg_tc & 0xFF); - write_scc(cmd, R13, (priv->param.brg_tc>>8) & 0xFF); - /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by - PackeTwin, not connected on the PI2); set DPLL source to BRG */ - write_scc(cmd, R14, SSBR | DTRREQ | BRSRC | BRENABL); - /* Enable DPLL */ - write_scc(cmd, R14, SEARCH | DTRREQ | BRSRC | BRENABL); - } else { - /* Disable BR generator */ - write_scc(cmd, R14, DTRREQ | BRSRC); - } - - /* Configure clocks */ - if (info->type == TYPE_TWIN) { - /* Disable external TX clock receiver */ - outb_p((info->twin_serial_cfg &= - ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), - io + TWIN_SERIAL_CFG); - } - write_scc(cmd, R11, priv->param.clocks); - if ((info->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) { - /* Enable external TX clock receiver */ - outb_p((info->twin_serial_cfg |= - (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), - io + TWIN_SERIAL_CFG); - } - - /* Configure PackeTwin */ - if (info->type == TYPE_TWIN) { - /* Assert DTR, enable interrupts */ - outb_p((info->twin_serial_cfg |= TWIN_EI | - (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)), - io + TWIN_SERIAL_CFG); - } - - /* Read current status */ - priv->status = read_scc(cmd, R0); - /* Enable SYNC, DCD, and CTS interrupts */ - write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE); - - /* Configure PI2 DMA */ - if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK); - - dev->start = 1; - info->open++; - MOD_INC_USE_COUNT; - - return 0; -} - - -static int scc_close(struct device *dev) -{ - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int io = dev->base_addr; - int cmd = priv->cmd; - - dev->start = 0; - info->open--; - MOD_DEC_USE_COUNT; - - if (info->type == TYPE_TWIN) - /* Drop DTR */ - outb_p((info->twin_serial_cfg &= - (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)), - io + TWIN_SERIAL_CFG); - - /* Reset channel, free DMA */ - write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); - if (dev->dma) { - if (info->type == TYPE_TWIN) outb_p(0, io + TWIN_DMA_CFG); - free_dma(dev->dma); - } - - if (!info->open) { - if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK); - free_irq(dev->irq, info); - } - return 0; -} - - -static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd) -{ - int rc; - struct scc_priv *priv = dev->priv; - - switch (cmd) { - case SIOCGSCCPARAM: - rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param)); - if (rc) return rc; - copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param)); - return 0; - case SIOCSSCCPARAM: - if (!suser()) return -EPERM; - rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param)); - if (rc) return rc; - if (dev->start) return -EAGAIN; - copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param)); - dev->dma = priv->param.dma; - return 0; - default: - return -EINVAL; - } -} - - -static int scc_send_packet(struct sk_buff *skb, struct device *dev) -{ - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int cmd = priv->cmd; - unsigned long flags; - int i; - - /* Block a timer-based transmit from overlapping */ - if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) { - atomic_inc((void *) &priv->stats.tx_dropped); - dev_kfree_skb(skb, FREE_WRITE); - return 0; - } - - /* Return with an error if we cannot accept more data */ - if (dev->tbusy) { - priv->tx_sem = 0; - return -1; - } - - /* Transfer data to DMA buffer */ - i = priv->tx_head; - memcpy(priv->tx_buf[i], skb->data+1, skb->len-1); - priv->tx_len[i] = skb->len-1; - - save_flags(flags); - cli(); - - /* Set the busy flag if we just filled up the last buffer */ - priv->tx_head = (i + 1) % NUM_TX_BUF; - priv->tx_count++; - if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1; - - /* Set new TX state */ - if (priv->tx_state == TX_IDLE) { - /* Assert RTS, start timer */ - priv->tx_state = TX_TXDELAY; - if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK); - write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); - if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK); - priv->tx_start = jiffies; - delay(dev, priv->param.txdelay); - } - - restore_flags(flags); - - dev_kfree_skb(skb, FREE_WRITE); - - priv->tx_sem = 0; - return 0; -} - - -static struct enet_statistics *scc_get_stats(struct device *dev) -{ - struct scc_priv *priv = dev->priv; - - return &priv->stats; -} - - -static int scc_set_mac_address(struct device *dev, void *sa) -{ - memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len); - return 0; -} - - -static void scc_isr(int irq, void *dev_id, struct pt_regs * regs) -{ - struct scc_info *info = dev_id; - int is, io = info->dev[0].base_addr; - - /* We're a fast IRQ handler and are called with interrupts disabled */ - - /* IRQ sharing doesn't make sense due to ISA's edge-triggered - interrupts, hence it is safe to return if we have found and - processed a single device. */ - - /* Interrupt processing: We loop until we know that the IRQ line is - low. If another positive edge occurs afterwards during the ISR, - another interrupt will be triggered by the interrupt controller - as soon as the IRQ level is enabled again (see asm/irq.h). */ - - switch (info->type) { - case TYPE_PI: - case TYPE_PI2: - outb_p(0, io + PI_DREQ_MASK); - z8530_isr(info); - outb_p(1, io + PI_DREQ_MASK); - return; - case TYPE_TWIN: - while ((is = ~inb_p(io + TWIN_INT_REG)) & - TWIN_INT_MSK) { - if (is & TWIN_SCC_MSK) { - z8530_isr(info); - } else if (is & TWIN_TMR1_MSK) { - inb_p(io + TWIN_CLR_TMR1); - tm_isr(&info->dev[0]); - } else { - inb_p(io + TWIN_CLR_TMR2); - tm_isr(&info->dev[1]); - } - } - /* No interrupts pending from the PackeTwin */ - return; - } -} - - -static inline void z8530_isr(struct scc_info *info) -{ - int is, a_cmd; - - a_cmd = info->scc_base + SCCA_CMD; - - while ((is = read_scc(a_cmd, R3))) { - if (is & CHARxIP) { - rx_isr(&info->dev[0]); - } else if (is & CHATxIP) { - tx_isr(&info->dev[0]); - } else if (is & CHAEXT) { - es_isr(&info->dev[0]); - } else if (is & CHBRxIP) { - rx_isr(&info->dev[1]); - } else if (is & CHBTxIP) { - tx_isr(&info->dev[1]); - } else { - es_isr(&info->dev[1]); - } - } - /* Ok, no interrupts pending from this 8530. The INT line should - be inactive now. */ -} - - -static void rx_isr(struct device *dev) -{ - struct scc_priv *priv = dev->priv; - int cmd = priv->cmd; - - if (dev->dma) { - /* Check special condition and perform error reset. See 2.4.7.5. */ - special_condition(dev, read_scc(cmd, R1)); - write_scc(cmd, R0, ERR_RES); - } else { - /* Check special condition for each character. Error reset not necessary. - Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */ - int rc; - while (read_scc(cmd, R0) & Rx_CH_AV) { - rc = read_scc(cmd, R1); - if (priv->rx_ptr < BUF_SIZE) - priv->rx_buf[priv->rx_head][priv->rx_ptr++] = read_scc(cmd, R8); - else { - priv->rx_over = 2; - read_scc(cmd, R8); - } - special_condition(dev, rc); - } - } -} - - -static void special_condition(struct device *dev, int rc) -{ - struct scc_priv *priv = dev->priv; - int cb, cmd = priv->cmd; - - /* See Figure 2-15. Only overrun and EOF need to be checked. */ - - if (rc & Rx_OVR) { - /* Receiver overrun */ - priv->rx_over = 1; - if (!dev->dma) write_scc(cmd, R0, ERR_RES); - } else if (rc & END_FR) { - /* End of frame. Get byte count */ - if (dev->dma) { - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - cb = BUF_SIZE - get_dma_residue(dev->dma) - 2; - } else { - cb = priv->rx_ptr - 2; - } - if (priv->rx_over) { - /* We had an overrun */ - priv->stats.rx_errors++; - if (priv->rx_over == 2) priv->stats.rx_length_errors++; - else priv->stats.rx_fifo_errors++; - priv->rx_over = 0; - } else if (rc & CRC_ERR) { - /* Count invalid CRC only if packet length >= minimum */ - if (cb >= 8) { - priv->stats.rx_errors++; - priv->stats.rx_crc_errors++; - } - } else { - if (cb >= 8) { - /* Put good frame in FIFO */ - priv->rx_len[priv->rx_head] = cb; - priv->rx_head = (priv->rx_head + 1) % NUM_RX_BUF; - priv->rx_count++; - if (priv->rx_count == NUM_RX_BUF) { - /* Disable receiver if FIFO full */ - write_scc(cmd, R3, Rx8); - priv->stats.rx_errors++; - priv->stats.rx_over_errors++; - } - /* Mark bottom half handler */ - queue_task(&priv->rx_task, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - } - /* Get ready for new frame */ - if (dev->dma) { - set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]); - set_dma_count(dev->dma, BUF_SIZE); - enable_dma(dev->dma); - } else { - priv->rx_ptr = 0; - } - } -} - - -static void rx_bh(void *arg) -{ - struct device *dev = arg; - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int cmd = priv->cmd; - int i = priv->rx_tail; - int cb; - unsigned long flags; - struct sk_buff *skb; - unsigned char *data; - - save_flags(flags); - cli(); - - while (priv->rx_count) { - restore_flags(flags); - cb = priv->rx_len[i]; - /* Allocate buffer */ - skb = dev_alloc_skb(cb+1); - if (skb == NULL) { - /* Drop packet */ - priv->stats.rx_dropped++; - } else { - /* Fill buffer */ - data = skb_put(skb, cb+1); - data[0] = 0; - memcpy(&data[1], priv->rx_buf[i], cb); - skb->dev = dev; - skb->protocol = ntohs(ETH_P_AX25); - skb->mac.raw = skb->data; - netif_rx(skb); - priv->stats.rx_packets++; - } - save_flags(flags); - cli(); - /* Enable receiver if RX buffers have been unavailable */ - if ((priv->rx_count == NUM_RX_BUF) && (priv->status & DCD)) { - if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK); - write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB); - if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK); - } - /* Move tail */ - priv->rx_tail = i = (i + 1) % NUM_RX_BUF; - priv->rx_count--; - } - - restore_flags(flags); -} - - -static void tx_isr(struct device *dev) -{ - struct scc_priv *priv = dev->priv; - int cmd = priv->cmd; - int i = priv->tx_tail, p = priv->tx_ptr; - - /* Suspend TX interrupts if we don't want to send anything. - See Figure 2-22. */ - if (p == priv->tx_len[i]) { - write_scc(cmd, R0, RES_Tx_P); - return; - } - - /* Write characters */ - while ((read_scc(cmd, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) { - write_scc(cmd, R8, priv->tx_buf[i][p++]); - } - priv->tx_ptr = p; - -} - - -static void es_isr(struct device *dev) -{ - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int i, cmd = priv->cmd; - int st, dst, res; - - /* Read status and reset interrupt bit */ - st = read_scc(cmd, R0); - write_scc(cmd, R0, RES_EXT_INT); - dst = priv->status ^ st; - priv->status = st; - - /* Since the EOM latch is reset automatically, we assume that - it has been zero if and only if we are in the TX_ACTIVE state. - Otherwise we follow 2.4.9.6. */ - - /* Transmit underrun */ - if ((priv->tx_state == TX_ACTIVE) && (st & TxEOM)) { - /* Get remaining bytes */ - i = priv->tx_tail; - if (dev->dma) { - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - res = get_dma_residue(dev->dma); - } else { - res = priv->tx_len[i] - priv->tx_ptr; - if (res) write_scc(cmd, R0, RES_Tx_P); - priv->tx_ptr = 0; - } - /* Remove frame from FIFO */ - priv->tx_tail = (i + 1) % NUM_TX_BUF; - priv->tx_count--; - dev->tbusy = 0; - /* Check if another frame is available and we are allowed to transmit */ - if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) { - if (dev->dma) { - set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]); - set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]); - enable_dma(dev->dma); - } else { - /* If we have an ESCC, we are allowed to write data bytes - immediately. Otherwise we have to wait for the next - TX interrupt. See Figure 2-22. */ - if (info->chip == Z85230) { - tx_isr(dev); - } - } - } else { - /* No frame available. Disable interrupts. */ - priv->tx_state = TX_SQDELAY; - delay(dev, priv->param.sqdelay); - write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE); - write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN); - } - /* Update packet statistics */ - if (res) { - priv->stats.tx_errors++; - priv->stats.tx_fifo_errors++; - } else { - priv->stats.tx_packets++; - } - /* Inform upper layers */ - mark_bh(NET_BH); - } - - /* DCD transition */ - if ((priv->tx_state < TX_TXDELAY) && (dst & DCD)) { - /* Transmitter state change */ - priv->tx_state = TX_OFF; - /* Enable or disable receiver */ - if (st & DCD) { - if (dev->dma) { - /* Program DMA controller */ - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_READ); - set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]); - set_dma_count(dev->dma, BUF_SIZE); - enable_dma(dev->dma); - /* Configure PackeTwin DMA */ - if (info->type == TYPE_TWIN) { - outb_p((dev->dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, - dev->base_addr + TWIN_DMA_CFG); - } - /* Sp. cond. intr. only, ext int enable */ - write_scc(cmd, R1, EXT_INT_ENAB | INT_ERR_Rx | - WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); - } else { - /* Intr. on all Rx characters and Sp. cond., ext int enable */ - write_scc(cmd, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | - WT_FN_RDYFN); - } - if (priv->rx_count < NUM_RX_BUF) { - /* Enable receiver */ - write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB); - } - } else { - /* Disable DMA */ - if (dev->dma) disable_dma(dev->dma); - /* Disable receiver */ - write_scc(cmd, R3, Rx8); - /* DMA disable, RX int disable, Ext int enable */ - write_scc(cmd, R1, EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN); - /* Transmitter state change */ - if (random() > priv->param.persist) - delay(dev, priv->param.slottime); - else { - if (priv->tx_count) { - priv->tx_state = TX_TXDELAY; - write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); - priv->tx_start = jiffies; - delay(dev, priv->param.txdelay); - } else { - priv->tx_state = TX_IDLE; - } - } - } - } - - /* CTS transition */ - if ((info->type <= TYPE_PI2) && (dst & CTS) && (~st & CTS)) { - /* Timer has expired */ - tm_isr(dev); - } - - /* /SYNC/HUNT transition */ - if ((dst & SYNC_HUNT) && (~st & SYNC_HUNT)) { - /* Reset current frame and clear RX FIFO */ - while (read_scc(cmd, R0) & Rx_CH_AV) read_scc(cmd, R8); - priv->rx_over = 0; - if (dev->dma) { - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]); - set_dma_count(dev->dma, BUF_SIZE); - enable_dma(dev->dma); - } else { - priv->rx_ptr = 0; - } - } -} - - -static void tm_isr(struct device *dev) -{ - struct scc_priv *priv = dev->priv; - struct scc_info *info = priv->info; - int cmd = priv->cmd; - - switch (priv->tx_state) { - case TX_OFF: - if (~priv->status & DCD) { - if (random() > priv->param.persist) delay(dev, priv->param.slottime); - else { - if (priv->tx_count) { - priv->tx_state = TX_TXDELAY; - write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); - priv->tx_start = jiffies; - delay(dev, priv->param.txdelay); - } else { - priv->tx_state = TX_IDLE; - } - } - } - break; - case TX_TXDELAY: - priv->tx_state = TX_ACTIVE; - if (dev->dma) { - /* Program DMA controller */ - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_WRITE); - set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]); - set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]); - enable_dma(dev->dma); - /* Configure PackeTwin DMA */ - if (info->type == TYPE_TWIN) { - outb_p((dev->dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, - dev->base_addr + TWIN_DMA_CFG); - } - /* Enable interrupts and DMA. On the PackeTwin, the DTR//REQ pin - is used for TX DMA requests, but we enable the WAIT/DMA request - pin, anyway */ - write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE); - write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); - } else { - write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE); - write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); - tx_isr(dev); - } - if (info->chip == Z8530) write_scc(cmd, R0, RES_EOM_L); - break; - case TX_SQDELAY: - /* Disable transmitter */ - write_scc(cmd, R5, TxCRC_ENAB | Tx8); - /* Transmitter state change: Switch to TX_OFF and wait at least - 1 slottime. */ - priv->tx_state = TX_OFF; - if (~priv->status & DCD) delay(dev, priv->param.waittime); - } -} - - -static inline void delay(struct device *dev, int t) -{ - struct scc_priv *priv = dev->priv; - int tmr = priv->tmr; - - outb_p(t & 0xFF, tmr); - outb_p((t >> 8) & 0xFF, tmr); -} - - -static inline unsigned char random(void) -{ - /* See "Numerical Recipes in C", second edition, p. 284 */ - rand = rand * 1664525L + 1013904223L; - return (unsigned char) (rand >> 24); -} - - diff -u --recursive --new-file v2.1.78/linux/drivers/net/dummy.c linux/drivers/net/dummy.c --- v2.1.78/linux/drivers/net/dummy.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/dummy.c Mon Jan 12 15:28:18 1998 @@ -30,9 +30,9 @@ /* To have statistics (just packets sent) define this */ -#include - +#include #include +#include #include #include #include @@ -73,6 +73,13 @@ { } +#ifdef CONFIG_NET_FASTROUTE +static int dummy_accept_fastpath(struct device *dev, struct dst_entry *dst) +{ + return -1; +} +#endif + __initfunc(int dummy_init(struct device *dev)) { /* Initialize the device structure. */ @@ -92,7 +99,10 @@ ether_setup(dev); dev->tx_queue_len = 0; dev->flags |= IFF_NOARP; - dev->flags &= ~IFF_BROADCAST; + dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST); +#ifdef CONFIG_NET_FASTROUTE + dev->accept_fastpath = dummy_accept_fastpath; +#endif return 0; } diff -u --recursive --new-file v2.1.78/linux/drivers/net/ipddp.c linux/drivers/net/ipddp.c --- v2.1.78/linux/drivers/net/ipddp.c Sun Dec 21 22:36:13 1997 +++ linux/drivers/net/ipddp.c Mon Jan 12 15:28:18 1998 @@ -195,6 +195,8 @@ struct ipddp_route *rt; struct at_addr *our_addr; + /* Wow! I'll eat my hat if this routine is really called. --ANK */ + /* * Find appropriate route to use, based only on IP number. */ diff -u --recursive --new-file v2.1.78/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.78/linux/drivers/net/myri_sbus.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/myri_sbus.c Mon Jan 12 15:28:18 1998 @@ -714,7 +714,6 @@ unsigned char *pad = (unsigned char *)skb->data; struct ethhdr *eth = (struct ethhdr *)(pad + MYRI_PAD_LEN); struct device *dev = skb->dev; - struct neighbour *neigh = NULL; #ifdef DEBUG_HEADER DHDR(("myri_rebuild_header: pad[%02x,%02x] ", pad[0], pad[1])); @@ -725,16 +724,6 @@ pad[0] = MYRI_PAD_LEN; pad[1] = 0xab; - /* - * Only ARP/IP and NDISC/IPv6 are currently supported - */ - - if (skb->dst) - neigh = skb->dst->neighbour; - - if (neigh) - return neigh->ops->resolve(eth->h_dest, skb); - switch (eth->h_proto) { #ifdef CONFIG_INET @@ -755,59 +744,31 @@ return 0; } -int myri_header_cache(struct dst_entry *dst, struct neighbour *neigh, - struct hh_cache *hh) +int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; unsigned char *pad = (unsigned char *)hh->hh_data; struct ethhdr *eth = (struct ethhdr *)(pad + MYRI_PAD_LEN); - struct device *dev = dst->dev; + struct device *dev = neigh->dev; - if (type == ETH_P_802_3) + if (type == __constant_htons(ETH_P_802_3)) return -1; /* Refill MyriNet padding identifiers, this is just being anal. */ pad[0] = MYRI_PAD_LEN; pad[1] = 0xab; - eth->h_proto = htons(type); - + eth->h_proto = type; memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - - if (dev->flags & IFF_LOOPBACK) { - memset(eth->h_dest, 0, dev->addr_len); - hh->hh_uptodate = 1; - return 0; - } - - if (type != ETH_P_IP) { - printk(KERN_DEBUG "%s: unable to resolve type %X addresses.\n", - dev->name, (int)eth->h_proto); - hh->hh_uptodate = 0; - return 0; - } - -#ifdef CONFIG_INET - hh->hh_uptodate = arp_find_1(eth->h_dest, dst, neigh); -#else - hh->hh_uptodate = 0; -#endif + memcpy(eth->h_dest, neigh->ha, dev->addr_len); return 0; } + /* Called by Address Resolution module to notify changes in address. */ -void myri_header_cache_update(struct hh_cache *hh, struct device *dev, - unsigned char * haddr) +void myri_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr) { - if (hh->hh_type != ETH_P_IP) { - printk(KERN_DEBUG "eth_header_cache_update: %04x cache is not " - "implemented\n", hh->hh_type); - return; - } - hh->hh_data[0] = MYRI_PAD_LEN; - hh->hh_data[1] = 0xab; - memcpy(hh->hh_data+2, haddr, ETH_ALEN); - hh->hh_uptodate = 1; + memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); } static int myri_change_mtu(struct device *dev, int new_mtu) diff -u --recursive --new-file v2.1.78/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.78/linux/drivers/net/sdla_fr.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/sdla_fr.c Mon Jan 12 14:46:16 1998 @@ -1,7 +1,8 @@ /***************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * -* Author: Gene Kozin +* Author(s): Gene Kozin +* Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -10,26 +11,52 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* -* Jun 29, 1997 Alan Cox o Hacked up vendor source 1.0.3 to remove -* C++ style comments, and a massive security -* hole (the UDP management junk). -* +* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards +* o Added Cli() to protect enabling of interrupts +* while polling is called. +* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts +* when they have been disabled by another +* interface or routine (eg. wpf_poll). +* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling +* routine disable interrupts during interrupt +* testing. +* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. +* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow +* control by avoiding RACE conditions. The +* cli() and restore_flags() are taken out. +* The fr_channel structure is appended for +* Driver Statistics. +* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX +* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() +* o Abstracted the UDP management stuff +* o Now use tbusy and critical more intelligently +* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 +* through router.conf. +* o Protected calls to sdla_peek() by adDing +* save_flags(), cli() and restore_flags(). +* o Added error message for Inactive DLCIs in +* fr_event() and update_chan_state(). +* o Fixed freeing up of buffers using kfree() +* when packets are received. +* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets +* o Added ability to discard multicast and +* broadcast source addressed packets +* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities +* New case (0x44) statement in if_send routine * Added a global variable rCount to keep track +* of FT1 status enabled on the board. * May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem * With multiple boards a problem was seen where * the second board always stopped transmitting * packet after running for a while. The code * got into a stage where the interrupts were * disabled and dev->tbusy was set to 1. -* This caused the If_send() routine to get into -* the if clause for set_bit(0,dev->tbusy) +* This caused the If_send() routine to get into* the if clause for it(0,dev->tbusy) * forever. * The code got into this stage due to an * interrupt occuring within the if clause for * set_bit(0,dev->tbusy). Since an interrupt * disables furhter transmit interrupt and -* makes dev->tbusy = 0, this effect was undone -* by making dev->tbusy = 1 in the if clause. +* makes dev->tbusy = 0, this effect was undone * by making dev->tbusy = 1 in the if clause. * The Fix checks to see if Transmit interrupts * are disabled then do not make dev->tbusy = 1 * Introduced a global variable: int_occur and @@ -51,7 +78,7 @@ * Jan 30, 1997 Gene Kozin Version 3.1.0 * o implemented exec() entry point * o fixed a bug causing driver configured as -* a FR switch to be stuck in WAN_DISCONNECTED +* a FR switch to be stuck in WAN_ * mode * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ @@ -60,115 +87,237 @@ #error This code MUST be compiled as a kernel module! #endif +#include /* OS configuration options */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ #include /* inline memset(), etc. */ #include /* kmalloc(), kfree() */ +#include /* __initfunc */ #include /* WAN router definitions */ #include /* WANPIPE common user API definitions */ #include /* ARPHRD_* defines */ -#include /* __initfunc et al. */ #include /* htons(), etc. */ #include /* for inb(), outb(), etc. */ #include +#include /* for do_gettimeofday */ #define _GNUC_ #include /* frame relay firmware API definitions */ - /****** Defines & Macros ****************************************************/ -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ /* Q.922 frame types */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* ??? */ +/* DLCI configured or not */ +#define DLCI_NOT_CONFIGURED 0x00 +#define DLCI_CONFIG_PENDING 0x01 +#define DLCI_CONFIGURED 0x02 + +/* CIR enabled or not */ +#define CIR_ENABLED 0x00 +#define CIR_DISABLED 0x01 + +/* Interrupt mode for DLCI = 0 */ +#define BUFFER_INTR_MODE 0x00 +#define DLCI_LIST_INTR_MODE 0x01 + +/* Transmit Interrupt Status */ +#define DISABLED 0x00 +#define WAITING_TO_BE_ENABLED 0x01 + +/* For handle_IPXWAN() */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + /****** Data Structures *****************************************************/ /* This is an extention of the 'struct device' we create for each network * interface to keep the rest of channel-specific data. */ -typedef struct fr_channel { - char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - char state; /* channel state */ +typedef struct fr_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + unsigned dlci_configured ; /* check whether configured or not */ + unsigned cir_status; /* check whether CIR enabled or not */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + unsigned mc; /* multicast support on or off */ + unsigned tx_int_status; /* Transmit Interrupt Status */ + unsigned short pkt_length; /* Packet Length */ + unsigned long router_start_time;/* Router start time in seconds */ + unsigned long tick_counter; /* counter for transmit time out */ + char dev_pending_devtint; /* interface pending dev_tint() */ + char state; /* channel state */ + void* dlci_int_interface; /* pointer to the DLCI Interface */ + unsigned long IB_addr; /* physical address of Interface Byte */ unsigned long state_tick; /* time of the last state change */ - sdla_t *card; /* -> owner */ - struct enet_statistics ifstats; /* interface statistics */ + sdla_t* card; /* -> owner */ + struct enet_statistics ifstats; /* interface statistics */ + + unsigned long if_send_entry; + unsigned long if_send_skb_null; + unsigned long if_send_broadcast; + unsigned long if_send_multicast; + unsigned long if_send_critical_ISR; + unsigned long if_send_critical_non_ISR; + unsigned long if_send_busy; + unsigned long if_send_busy_timeout; + unsigned long if_send_FPIPE_request; + unsigned long if_send_DRVSTATS_request; + unsigned long if_send_wan_disconnected; + unsigned long if_send_dlci_disconnected; + unsigned long if_send_no_bfrs; + unsigned long if_send_adptr_bfrs_full; + unsigned long if_send_bfrs_passed_to_adptr; + + unsigned long rx_intr_no_socket; + unsigned long rx_intr_dev_not_started; + unsigned long rx_intr_FPIPE_request; + unsigned long rx_intr_DRVSTATS_request; + unsigned long rx_intr_bfr_not_passed_to_stack; + unsigned long rx_intr_bfr_passed_to_stack; + + unsigned long UDP_FPIPE_mgmt_kmalloc_err; + unsigned long UDP_FPIPE_mgmt_direction_err; + unsigned long UDP_FPIPE_mgmt_adptr_type_err; + unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK; + unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout; + unsigned long UDP_FPIPE_mgmt_adptr_send_passed; + unsigned long UDP_FPIPE_mgmt_adptr_send_failed; + unsigned long UDP_FPIPE_mgmt_not_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_no_socket; + unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed; + unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed; + unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_no_socket; + unsigned long router_up_time; } fr_channel_t; -typedef struct dlci_status { - unsigned short dlci PACKED; - unsigned char state PACKED; +typedef struct dlci_status +{ + unsigned short dlci PACKED; + unsigned char state PACKED; } dlci_status_t; +typedef struct dlci_IB_mapping +{ + unsigned short dlci PACKED; + unsigned long addr_value PACKED; +} dlci_IB_mapping_t; + +/* This structure is used for DLCI list Tx interrupt mode. It is used to + enable interrupt bit and set the packet length for transmission + */ +typedef struct fr_dlci_interface +{ + unsigned char gen_interrupt PACKED; + unsigned short packet_length PACKED; + unsigned char reserved PACKED; +} fr_dlci_interface_t; + +static unsigned short num_frames; +static unsigned long curr_trace_addr; +static unsigned long start_trace_addr; +static unsigned short available_buffer_space; static char TracingEnabled; -/* variable for checking interrupts within the ISR routine */ -static int int_occur = 0; + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/* variable for keeping track of number of interrupts generated during + * interrupt test routine + */ +static int Intr_test_counter; + /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); /* WANPIPE-specific entry points */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data); /* Network device interface */ -static int if_init(struct device *dev); -static int if_open(struct device *dev); -static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int if_rebuild_hdr(struct sk_buff *skb); -static int if_send(struct sk_buff *skb, struct device *dev); -static struct enet_statistics *if_stats(struct device *dev); +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (struct sk_buff* skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); /* Interrupt handlers */ -static void fr502_isr(sdla_t * card); -static void fr508_isr(sdla_t * card); -static void fr502_rx_intr(sdla_t * card); -static void fr508_rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); -static void spur_intr(sdla_t * card); +static void fr502_isr (sdla_t* card); +static void fr508_isr (sdla_t* card); +static void fr502_rx_intr (sdla_t* card); +static void fr508_rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); +static void spur_intr (sdla_t* card); /* Background polling routines */ -static void wpf_poll(sdla_t * card); +static void wpf_poll (sdla_t* card); /* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t * card, char *str); -static int fr_configure(sdla_t * card, fr_conf_t * conf); -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu); -static int fr_comm_enable(sdla_t * card); -static int fr_comm_disable(sdla_t * card); -static int fr_get_err_stats(sdla_t * card); -static int fr_get_stats(sdla_t * card); -static int fr_add_dlci(sdla_t * card, int dlci, int num); -static int fr_activate_dlci(sdla_t * card, int dlci, int num); -static int fr_issue_isf(sdla_t * card, int isf); -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf); -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf); +static int fr_read_version (sdla_t* card, char* str); +static int fr_configure (sdla_t* card, fr_conf_t *conf); +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci); +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu); +static int fr_comm_enable (sdla_t* card); +static int fr_comm_disable (sdla_t* card); +static int fr_get_err_stats (sdla_t* card); +static int fr_get_stats (sdla_t* card); +static int fr_add_dlci (sdla_t* card, int dlci, int num); +static int fr_activate_dlci (sdla_t* card, int dlci, int num); +static int fr_issue_isf (sdla_t* card, int isf); +static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf); +static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf); /* Firmware asynchronous event handlers */ -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox); -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox); -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox); +static int fr_event (sdla_t* card, int event, fr_mbox_t* mbox); +static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox); +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox); /* Miscellaneous functions */ -static int update_chan_state(struct device *dev); -static void set_chan_state(struct device *dev, int state); -static struct device *find_channel(sdla_t * card, unsigned dlci); -static int is_tx_ready(sdla_t * card); -static unsigned int dec_to_uint(unsigned char *str, int len); +static int update_chan_state (struct device* dev); +static void set_chan_state (struct device* dev, int state); +static struct device* find_channel (sdla_t* card, unsigned dlci); +static int is_tx_ready (sdla_t* card, fr_channel_t* chan); +static unsigned int dec_to_uint (unsigned char* str, int len); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); + +static int intr_test( sdla_t* card ); +static void init_chan_statistics( fr_channel_t* chan ); +static void init_global_statistics( sdla_t* card ); +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); + +/* Udp management functions */ +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan); +static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan); +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ); + +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number); /****** Public Functions ****************************************************/ @@ -198,22 +347,23 @@ return -EINVAL; } /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) { - case SFID_FR502: - card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); - card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); - card->isr = &fr502_isr; - break; + switch (card->hw.fwid) + { + case SFID_FR502: + card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); + card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); + card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); + card->isr = &fr502_isr; + break; - case SFID_FR508: - card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); - card->isr = &fr508_isr; - break; + case SFID_FR508: + card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); + card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); + card->isr = &fr508_isr; + break; - default: - return -EINVAL; + default: + return -EINVAL; } /* Read firmware version. Note that when adapter initializes, it @@ -243,21 +393,28 @@ u.cfg.cir_fwd = 16; u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd; u.cfg.options = 0x0081; /* direct Rx, no CIR check */ - switch (conf->u.fr.signalling) { - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; + + switch (conf->u.fr.signalling) + { + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; + break; + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; + break; } - if (conf->station == WANOPT_CPE) { + + if (conf->station == WANOPT_CPE) + { u.cfg.options |= 0x8000; /* auto config DLCI */ - } else { + } + else + { u.cfg.station = 1; /* switch emulation mode */ card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16; card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); } + if (conf->clocking == WANOPT_INTERNAL) u.cfg.port |= 0x0001 ; @@ -279,7 +436,8 @@ return -EIO ; - if (card->hw.fwid == SFID_FR508) { + if (card->hw.fwid == SFID_FR508) + { fr_buf_info_t *buf_info = (void *) (card->hw.dpmbase + FR508_RXBC_OFFS); @@ -392,6 +550,32 @@ kfree(chan); return err; } + + /* place cir,be,bc and other channel specific information into the + * chan structure + */ + if (conf->cir) + { + chan->cir = max( 1, min( conf->cir, 512 ) ); + chan->cir_status = CIR_ENABLED; + + if (conf->bc) + chan->bc = max( 1, min( conf->bc, 512 ) ); + if (conf->be) + chan->be = max( 0, min( conf->be, 511) ); + + } + else + chan->cir_status = CIR_DISABLED; + + chan->mc = conf->mc; + + chan->dlci_configured = DLCI_NOT_CONFIGURED; + + chan->tx_int_status = DISABLED; + + init_chan_statistics( chan ); + /* prepare network device data space for registration */ dev->name = chan->name; dev->init = &if_init; @@ -503,34 +687,146 @@ * * Return 0 if O.k. or errno. */ + static int if_open(struct device *dev) { fr_channel_t *chan = dev->priv; sdla_t *card = chan->card; + struct device *dev2; int err = 0; - + fr508_flags_t *flags = card->flags; + struct timeval tv; + if (dev->start) - return -EBUSY /* only one open is allowed */ - ; + return -EBUSY; /* only one open is allowed */ + if (test_and_set_bit(0, (void *) &card->wandev.critical)) return -EAGAIN; - ; - if (!card->open_cnt) { - if ((fr_comm_enable(card)) || - (fr_set_intr_mode(card, 0x03, card->wandev.mtu))) { + + if (!card->open_cnt) + { + Intr_test_counter = 0; + card->intr_mode = INTR_TEST_MODE; + err = intr_test( card ); + + if ((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER +1))) { + printk(KERN_INFO + "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); err = -EIO; - goto done; + card->wandev.critical = 0; + return err; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n" + ,card->devname, Intr_test_counter); + + /* The following allocates and intializes a circular + * link list of interfaces per card. + */ + + card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL); + if (card->devs_struct == NULL) + return -ENOMEM; + card->dev_to_devtint_next = card->devs_struct; + + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + (card->devs_struct)->dev_ptr = dev2; + if(dev2->slave == NULL) + (card->devs_struct)->next = card->dev_to_devtint_next; + else { + (card->devs_struct)->next = kmalloc( + sizeof(load_sharing_t), GFP_KERNEL); + if ((card->devs_struct)->next == NULL) + return -ENOMEM; + card->devs_struct = (card->devs_struct)->next; + } + } + + card->devs_struct = card->dev_to_devtint_next; + + card->intr_mode = BUFFER_INTR_MODE; + + /* + check all the interfaces for the device to see if CIR has + been enabled for any DLCI(s). If so then use the DLCI list + Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode + */ + + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + + if( ((fr_channel_t *)dev2->priv)->cir_status + == CIR_ENABLED) { + card->intr_mode = DLCI_LIST_INTR_MODE; + break; + } + } + + /* + * If you enable comms and then set ints, you get a Tx int as you + * perform the SET_INT_TRIGGERS command. So, we only set int + * triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. + */ + if (card->intr_mode == BUFFER_INTR_MODE) + { + if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) + { + err = -EIO; + card->wandev.critical = 0; + return err; + } + + printk( KERN_INFO + "%s: Global Buffering Tx Interrupt Mode\n" + , card->devname); + + } + else if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) + { + err = -EIO; + card->wandev.critical = 0; + return err; + } + + printk( KERN_INFO "%s: DLCI list Tx Interrupt Mode\n", + card->devname); + } + + flags->imask &= ~0x02; + + if (fr_comm_enable(card)) + { + err = -EIO; + card->wandev.critical = 0; + return err; + } + wanpipe_set_state(card, WAN_CONNECTED); - if (card->wandev.station == WANOPT_CPE) { + if (card->wandev.station == WANOPT_CPE) + { /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); - } else { /* FR switch: activate DLCI(s) */ - fr_add_dlci(card, - card->u.f.node_dlci, card->u.f.dlci_num); - fr_activate_dlci(card, - card->u.f.node_dlci, card->u.f.dlci_num); + } + else + { /* FR switch: activate DLCI(s) */ + + /* For Switch emulation we have to ADD and ACTIVATE + * the DLCI(s) that were configured with the SET_DLCI_ + * CONFIGURATION command. Add and Activate will fail if + * DLCI specified is not included in the list. + * + * Also If_open is called once for each interface. But + * it does not get in here for all the interface. So + * we have to pass the entire list of DLCI(s) to add + * activate routines. + */ + + fr_add_dlci(card, card->u.f.node_dlci[0], card->u.f.dlci_num); + fr_activate_dlci(card, card->u.f.node_dlci, card->u.f.dlci_num); } } dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); @@ -540,7 +836,8 @@ wanpipe_open(card); update_chan_state(dev); - done: + do_gettimeofday( &tv ); + chan->router_start_time = tv.tv_sec; card->wandev.critical = 0; return err; } @@ -636,6 +933,33 @@ sdla_t *card = chan->card; int retry = 0, err; struct device *dev2; + fr508_flags_t* adptr_flags = card->flags; + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + unsigned long host_cpu_flags; + int send_data = 0; + ++chan->if_send_entry; + + if (dev->tbusy) + { + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + */ + + ++chan->if_send_busy; + ++chan->ifstats.collisions; + + if ((jiffies - chan->tick_counter) < (5*HZ)) + return 1; + + printk(KERN_INFO "%s: Transmit timed out\n", chan->name); + + ++chan->if_send_busy_timeout; + + /* unbusy all the interfaces on the card */ + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + dev2->tbusy = 0; + } if (test_and_set_bit(0, (void *) &card->wandev.critical)) { #ifdef _DEBUG_ @@ -645,60 +969,221 @@ dev_kfree_skb(skb, FREE_WRITE); return 0; } - if (test_and_set_bit(0, (void *) &dev->tbusy)) { -#ifdef _DEBUG_ - printk(KERN_INFO "%s: Tx collision on interface %s!\n", - card->devname, dev->name); -#endif - ++chan->ifstats.collisions; - ++card->wandev.stats.collisions; + disable_irq(card->hw.irq); + ++card->irq_dis_if_send_count; - retry = 1; - if (card->wandev.tx_int_enabled) { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - dev2->tbusy = 1; + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + if (card->wandev.critical == CRITICAL_IN_ISR) + { + ++chan->if_send_critical_ISR; + + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + /* The enable_tx_int flag is set here so that if + * the critical flag is set due to an interrupt + * then we want to enable transmit interrupts + * again. + */ + + card->wandev.enable_tx_int = 1; + + /* Setting this flag to WAITING_TO_BE_ENABLED + * specifies that interrupt bit has to be + * enabled for that particular interface. + * (delayed interrupt) + */ + + chan->tx_int_status = WAITING_TO_BE_ENABLED; + + /* This is used for enabling dynamic calculation + * of CIRs relative to the packet length. + */ + + chan->pkt_length = skb->len; + dev->tbusy = 1; + chan->tick_counter = jiffies; } + else + { + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + chan->tick_counter = jiffies; + } + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 1; } - } else if (card->wandev.state != WAN_CONNECTED) { + + ++chan->if_send_critical_non_ISR; + ++chan->ifstats.tx_dropped; + dev_kfree_skb(skb, FREE_WRITE); + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 0; + } + + card->wandev.critical = 0x21; + + if (card->wandev.state != WAN_CONNECTED) + { + ++chan->if_send_wan_disconnected; ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - } else if (chan->state != WAN_CONNECTED) { + } + else if (chan->state != WAN_CONNECTED) + { + ++chan->if_send_dlci_disconnected; update_chan_state(dev); ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - } else if (!is_tx_ready(card)) { + } + else if (!is_tx_ready(card, chan)) + { + if (card->intr_mode == DLCI_LIST_INTR_MODE ) + { + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = skb->len; + } + dev->tbusy = 1; + chan->tick_counter = jiffies; + + adptr_flags->imask |= 0x02; + + ++ chan->if_send_no_bfrs; retry = 1; - if (card->wandev.tx_int_enabled) { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - dev2->tbusy = 1; + } + else + { + send_data = 1; + /* If it's an IPX packet */ + if( sendpacket[1] == 0x00 && + sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && + sendpacket[7] == 0x37) + { + if( card->wandev.enable_IPX ) + { + switch_net_numbers(sendpacket, + card->wandev.network_number, 0); + } + else + { + /* increment some statistic here! */ + send_data = 0; } } - } else { - err = (card->hw.fwid == SFID_FR508) ? - fr508_send(card, chan->dlci, 0, skb->len, skb->data) : - fr502_send(card, chan->dlci, 0, skb->len, skb->data); - if (err) { - ++chan->ifstats.tx_errors; - ++card->wandev.stats.tx_errors; - } else { - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; + + if (send_data) + { + err = (card->hw.fwid == SFID_FR508) ? + fr508_send(card, chan->dlci, 0, skb->len, skb->data) : + fr502_send(card, chan->dlci, 0, skb->len, skb->data); + + if (err) + { + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = skb->len; + } + dev->tbusy = 1; + chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; + retry = 1; + ++ chan->if_send_adptr_bfrs_full; + ++ chan->ifstats.tx_errors; + ++ card->wandev.stats.tx_errors; + } + else + { + ++ chan->if_send_bfrs_passed_to_adptr; + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + } } } - if (!retry) { + + if (!retry) dev_kfree_skb(skb, FREE_WRITE); - dev->tbusy = 0; - } + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); return retry; } +/* + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + * + */ + +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[14] << 24) + + (sendpacket[15] << 16) + (sendpacket[16] << 8) + + sendpacket[17]); + + if (!incoming) { + if( pnetwork_number == network_number) { + sendpacket[14] = sendpacket[15] = sendpacket[16] = + sendpacket[17] = 0x00; + } + } else { + if( pnetwork_number == 0) { + sendpacket[14] = (unsigned char)(network_number >> 24); + sendpacket[15] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[16] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[17] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[26] << 24) + + (sendpacket[27] << 16) + (sendpacket[28] << 8) + + sendpacket[29]); + + if( !incoming ) { + if( pnetwork_number == network_number) { + sendpacket[26] = sendpacket[27] = sendpacket[28] = + sendpacket[29] = 0x00; + } + } else { + if( pnetwork_number == 0 ) { + sendpacket[26] = (unsigned char)(network_number >> 24); + sendpacket[27] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[28] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[29] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + /*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ -static struct enet_statistics *if_stats(struct device *dev) +static struct net_device_stats *if_stats(struct device *dev) { fr_channel_t *chan = dev->priv; @@ -714,18 +1199,19 @@ { fr502_flags_t *flags = card->flags; - switch (flags->iflag) { - case 0x01: /* receive interrupt */ - fr502_rx_intr(card); - break; + switch (flags->iflag) + { + case 0x01: /* receive interrupt */ + fr502_rx_intr(card); + break; - case 0x02: /* transmit interrupt */ - flags->imask &= ~0x02; - tx_intr(card); - break; + case 0x02: /* transmit interrupt */ + flags->imask &= ~0x02; + tx_intr(card); + break; - default: - spur_intr(card); + default: + spur_intr(card); } flags->iflag = 0; } @@ -737,36 +1223,186 @@ { fr508_flags_t *flags = card->flags; fr_buf_ctl_t *bctl; + char *ptr = &flags->iflag; + struct device* dev = card->wandev.dev; + struct device* dev2; + int i; + unsigned long host_cpu_flags; + unsigned disable_tx_intr =1; + fr_channel_t* chan; + fr_dlci_interface_t* dlci_interface; - if (int_occur) { -#ifdef _DEBUG_ - printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n", card->devname); -#endif + /* This flag prevents nesting of interrupts. See sdla_isr() routine + * in sdlamain.c. + */ + card->in_isr = 1; + + ++card->statistics.isr_entry; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); + ++card->statistics.isr_already_critical; + card->in_isr = 0; return; } int_occur = 1; + + /* For all interrupts set the critical flag to CRITICAL_RX_INTR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + + card->dlci_int_mode_unbusy = 0; + card->buff_int_mode_unbusy = 0; + switch (flags->iflag) { - case 0x01: /* receive interrupt */ - fr508_rx_intr(card); - break; + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + fr508_rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase); + bctl->flag = 0xA0; + + if (card->intr_mode == DLCI_LIST_INTR_MODE ) + { + /* Find the structure and make it unbusy */ + dev = find_channel( card, flags->dlci); + dev->tbusy = 0; + + /* This is used to perform devtint at the + * end of the isr + */ + card->dlci_int_mode_unbusy = 1; + + /* check to see if any other interfaces are + * busy. If so then do not disable the tx + * interrupts + */ + for (dev2 = card->wandev.dev; dev2; + dev2 = dev2->slave) + { + if ( dev2->tbusy == 1) + { + disable_tx_intr = 0; + break; + } + } + if (disable_tx_intr) + flags->imask &= ~0x02; + + } + else if (card->intr_mode == BUFFER_INTR_MODE) + { + for (dev2 = card->wandev.dev; dev2; + dev2 = dev2->slave) + { + if ( !dev2 || !dev2->start ) + { + ++card->statistics. + tx_intr_dev_not_started; + continue; + } + if(dev2->tbusy) + { + card->buff_int_mode_unbusy = 1; + ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 1; + dev2->tbusy = 0; + } else + ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 0; + } + flags->imask &= ~0x02; + } + break; - case 0x02: /* transmit interrupt */ - bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); - bctl->flag = 0x90; /* disable further Tx interrupts */ - tx_intr(card); - break; + case 0x08: + Intr_test_counter++; + ++card->statistics.isr_intr_test; + break; + + default: + ++card->statistics.isr_spurious; + spur_intr(card); + printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", + card->devname, flags->iflag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + + break; + } - default: - spur_intr(card); - } - int_occur = 0; + card->wandev.critical = CRITICAL_INTR_HANDLED; + if (card->wandev.enable_tx_int) + { + if( card->intr_mode == DLCI_LIST_INTR_MODE ) + { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + chan = dev2->priv; + if ( chan->tx_int_status == + WAITING_TO_BE_ENABLED ) + { + dlci_interface = + chan->dlci_int_interface; + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = + chan->pkt_length; + chan->tx_int_status = DISABLED; + } + } + } + card->wandev.enable_tx_int = 0; + flags->imask |= 0x02; + ++card->statistics.isr_enable_tx_int; + } + save_flags(host_cpu_flags); + cli(); + card->in_isr = 0; + card->wandev.critical = 0xD1; flags->iflag = 0; + card->wandev.critical = 0; + restore_flags(host_cpu_flags); + + /* + * Device is now ready to send. The instant this is executed the If_Send + * routine is called. That is why this is put at the bottom of the ISR + * to prevent a endless loop condition caused by repeated Interrupts and + * enable_tx_int flag. + */ + + if(card->dlci_int_mode_unbusy) + dev_tint(dev); + + if(card->buff_int_mode_unbusy) + { + for (;;) + { + if (((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1){ + + ((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint=0; + dev_tint((card->devs_struct)->dev_ptr); + } + if ((card->devs_struct)->next == card->dev_to_devtint_next) + break; + card->devs_struct = (card->devs_struct)->next; + } + card->devs_struct = (card->dev_to_devtint_next)->next; + card->dev_to_devtint_next = card->devs_struct; + } } /*============================================================================ * Receive interrupt handler. */ + static void fr502_rx_intr(sdla_t * card) { fr_mbox_t *mbox = card->rxmb; @@ -787,12 +1423,12 @@ /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", card->devname, dlci); - goto rx_done; + sdla_mapmem(&card->hw, FR_MB_VECTOR); } chan = dev->priv; if (!dev->start) { ++chan->ifstats.rx_dropped; - goto rx_done; + sdla_mapmem(&card->hw, FR_MB_VECTOR); } /* Allocate socket buffer */ skb = dev_alloc_skb(len); @@ -800,7 +1436,7 @@ printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); ++chan->ifstats.rx_dropped; - goto rx_done; + sdla_mapmem(&card->hw, FR_MB_VECTOR); } /* Copy data to the socket buffer */ buf = skb_put(skb, len); @@ -820,7 +1456,6 @@ ++chan->ifstats.rx_packets; ++card->wandev.stats.rx_packets; } - rx_done: sdla_mapmem(&card->hw, FR_MB_VECTOR); } @@ -835,68 +1470,133 @@ fr_channel_t *chan; unsigned dlci, len, offs; void *buf; + unsigned rx_count = 0; + fr508_flags_t* flags = card->flags; + char *ptr = &flags->iflag; + int i, err; if (frbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", card->devname, (unsigned) frbuf); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + + ++card->statistics.rx_intr_corrupt_rx_bfr; return; } - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (dev == NULL) { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci); - goto rx_done; - } - chan = dev->priv; - if (!dev->start) { - ++chan->ifstats.rx_dropped; - goto rx_done; - } - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb == NULL) { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++chan->ifstats.rx_dropped; - goto rx_done; - } - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs + 1; + do + { + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + chan = dev->priv; + + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" + , card->devname, dlci); + ++card->statistics.rx_intr_on_orphaned_DLCI; + } + else + { + skb = dev_alloc_skb(len); + if (!dev->start || (skb == NULL)) + { + ++chan->ifstats.rx_dropped; + if(dev->start) + { + printk(KERN_INFO + "%s: no socket buffers available!\n", + card->devname); + ++chan->rx_intr_no_socket; + + } + else + ++ chan->rx_intr_dev_not_started; + } + else + { + /* Copy data to the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) + { + unsigned tmp = card->u.f.rx_top - + offs + 1; + + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); +#ifdef CONFIG_SANGOMA_MANAGER + if (management_check(skb,card)) + { + ++chan->rx_intr_DRVSTATS_request; + } + else +#endif + if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number)) + { + if (card->wandev.enable_IPX) + { + fr508_send(card, dlci, 0, skb->len, skb->data); + } else { + /* increment some statistic! */ + } + } + else + { + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + if (!wan_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb, FREE_READ); + ++chan->rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + } + else + { + netif_rx(skb); + ++ chan->rx_intr_bfr_passed_to_stack; + ++ chan->ifstats.rx_packets; + ++ card->wandev.stats.rx_packets; + } + } + } + } + + /* Release buffer element and calculate a pointer to the next + one */ + frbuf->flag = 0; + card->rxmb = ++frbuf; + + if ((void*)frbuf > card->u.f.rxmb_last) + card->rxmb = card->u.f.rxmb_base; + + /* The loop put in is temporary, that is why the break is + * placed here. (?????) + */ + break; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - /* Decapsulate packet and pass it up the protocol stack */ - skb->dev = dev; - buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wan_type_trans(skb, dev)) { - /* can't decapsulate packet */ - dev_kfree_skb(skb, FREE_READ); - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - } else { - netif_rx(skb); - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - } - rx_done: - /* Release buffer element and calculate a pointer to the next one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void *) frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base - ; + frbuf = card->rxmb; + + } while (frbuf->flag && ((++ rx_count) < 4)); } /*============================================================================ @@ -908,20 +1608,26 @@ static void tx_intr(sdla_t * card) { struct device *dev = card->wandev.dev; - int v = 0; - for (; dev; dev = dev->slave) { - if (!dev || !dev->start) - continue; - v += dev->tbusy; + if (card->intr_mode == BUFFER_INTR_MODE) + { + for (; dev; dev = dev->slave) + { + if ( !dev || !dev->start ) + { + ++ card->statistics.tx_intr_dev_not_started; + continue; + } + + dev->tbusy = 0; + dev_tint(dev); + } + } + else + { dev->tbusy = 0; + dev_tint(dev); } - card->wandev.tx_int_enabled = 0; - if (v) - mark_bh(NET_BH); -/* - printk(KERN_INFO "%s: transmit interrupt!\n", card->devname); - */ } /*============================================================================ @@ -935,6 +1641,105 @@ printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } +/* + Return 0 for non-IPXWAN packet + 1 for IPXWAN packet or IPX is not enabled! + +*/ + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) +{ + int i; + + if( sendpacket[1] == 0x00 && + sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && + sendpacket[7] == 0x37) { + + if(!enable_IPX) { + return 1; + } + } else { + return 0; + } + + if( sendpacket[24] == 0x90 && + sendpacket[25] == 0x04) + { + if( sendpacket[10] == 0x02 && + sendpacket[42] == 0x00) + { + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + for(i = 49; sendpacket[i] == 0x00; i += 5) + { + if( sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + + if( sendpacket[i] == 0x04 ) + { + i += 8; + } + + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + sendpacket[42] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[42] == 0x02 ) + { + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + sendpacket[42] = 0x03; + + sendpacket[59] = 'F'; + sendpacket[60] = 'P'; + sendpacket[61] = 'I'; + sendpacket[62] = 'P'; + sendpacket[63] = 'E'; + sendpacket[64] = '-'; + sendpacket[65] = CVHexToAscii(network_number >> 28); + sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); + for(i = 73; i < 107; i+= 1) + { + sendpacket[i] = 0; + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + sendpacket[43] = (unsigned char)(network_number >> 24); + sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[46] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } + + switch_net_numbers(sendpacket, network_number ,1); + return 0; +} + + /****** Background Polling Routines ****************************************/ /*============================================================================ @@ -948,18 +1753,40 @@ * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */ + static void wpf_poll(sdla_t * card) { - static unsigned long last_poll; - fr502_flags_t *flags; + fr508_flags_t *flags; + unsigned long host_cpu_flags; - if ((jiffies - last_poll) < HZ) - return - ; + ++card->statistics.poll_entry; + + if (((jiffies - card->state_tick) < HZ) || + (card->intr_mode == INTR_TEST_MODE)) + return; + + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + + if (test_and_set_bit(0, (void *)&card->wandev.critical)) + { + ++ card->statistics.poll_already_critical; + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && + (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return; + } + + card->wandev.critical = 0x11; + + ++ card->statistics.poll_processed; - flags = card->flags; if (flags->event) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int err; memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); @@ -968,9 +1795,19 @@ if (err) fr_event(card, err, mbox); } - last_poll = jiffies; + + card->wandev.critical = 0; + + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + card->state_tick = jiffies; } + /****** Frame Relay Firmware-Specific Functions *****************************/ /*============================================================================ @@ -1005,17 +1842,17 @@ { fr_mbox_t *mbox = card->mbox; int retry = MAX_CMD_RETRY; - int dlci = card->u.f.node_dlci; int dlci_num = card->u.f.dlci_num; int err, i; do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_conf_t)); - if (dlci_num) - for (i = 0; i < dlci_num; ++i) - ((fr_conf_t *) mbox->data)->dlci[i] = dlci + i - ; + + if (dlci_num) for (i = 0; i < dlci_num; ++i) + ((fr_conf_t*)mbox->data)->dlci[i] = + card->u.f.node_dlci[i]; + mbox->cmd.command = FR_SET_CONFIG; mbox->cmd.length = sizeof(fr_conf_t) + dlci_num * sizeof(short); @@ -1026,6 +1863,30 @@ } /*============================================================================ + * Set DLCI configuration. + */ +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); + mbox->cmd.dlci = (unsigned short) dlci; + mbox->cmd.command = FR_SET_CONFIG; + mbox->cmd.length = 0x0E; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + } while (err && retry--); + + return err; +} + +/*============================================================================ * Set interrupt mode. */ static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) @@ -1112,12 +1973,12 @@ while (err && retry-- && fr_event(card, err, mbox)); if (!err) { - fr_comm_stat_t *stats = (void *) mbox->data; + fr_comm_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; card->wandev.stats.tx_aborted_errors = stats->tx_aborts; } return err; @@ -1153,6 +2014,7 @@ /*============================================================================ * Add DLCI(s) (Access Node only!). */ + static int fr_add_dlci(sdla_t * card, int dlci, int num) { fr_mbox_t *mbox = card->mbox; @@ -1164,8 +2026,8 @@ memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); for (i = 0; i < num; ++i) - dlci_list[i] = dlci + i - ; + dlci_list[i] = card->u.f.node_dlci[i]; + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ADD_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1188,8 +2050,8 @@ memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); for (i = 0; i < num; ++i) - dlci_list[i] = dlci + i - ; + dlci_list[i] = card->u.f.node_dlci[i]; + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ACTIVATE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1262,13 +2124,8 @@ if (!err) { fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - FR_MB_VECTOR + card->hw.dpmbase); - unsigned long flags; - - save_flags(flags); - cli(); sdla_poke(&card->hw, frbuf->offset, buf, len); frbuf->flag = 0x01; - restore_flags(flags); } return err; } @@ -1284,33 +2141,51 @@ */ static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) { - switch (event) { - case FRRES_MODEM_FAILURE: - return fr_modem_failure(card, mbox); + fr508_flags_t* flags = card->flags; + char *ptr = &flags->iflag; + int i; - case FRRES_CHANNEL_DOWN: - wanpipe_set_state(card, WAN_DISCONNECTED); - return 1; + switch (event) + { + case FRRES_MODEM_FAILURE: + return fr_modem_failure(card, mbox); - case FRRES_CHANNEL_UP: - wanpipe_set_state(card, WAN_CONNECTED); - return 1; + case FRRES_CHANNEL_DOWN: + wanpipe_set_state(card, WAN_DISCONNECTED); + return 1; - case FRRES_DLCI_CHANGE: - return fr_dlci_change(card, mbox); + case FRRES_CHANNEL_UP: + wanpipe_set_state(card, WAN_CONNECTED); + return 1; - case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname); - return 1; + case FRRES_DLCI_CHANGE: + return fr_dlci_change(card, mbox); - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - break; + case FRRES_DLCI_MISMATCH: + printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname); + return 1; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, mbox->cmd.command, event); + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, mbox->cmd.command); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + break; + + case FRRES_DLCI_INACTIVE: + printk(KERN_ERR "%s: DLCI %u is inactive!\n", + card->devname, mbox->cmd.dlci); + break; + + case FRRES_CIR_OVERFLOW: + break; + case FRRES_BUFFER_OVERFLOW: + break; + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, mbox->cmd.command, event); } return 0; } @@ -1324,10 +2199,11 @@ { printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", card->devname, mbox->data[0]); - switch (mbox->cmd.command) { - case FR_WRITE: - case FR_READ: - return 0; + switch (mbox->cmd.command) + { + case FR_WRITE: + case FR_READ: + return 0; } return 1; } @@ -1341,25 +2217,91 @@ { dlci_status_t *status = (void *) mbox->data; int cnt = mbox->cmd.length / sizeof(dlci_status_t); - + fr_dlc_conf_t cfg; + fr_channel_t *chan; + struct device* dev2; + for (; cnt; --cnt, ++status) { unsigned short dlci = status->dlci; struct device *dev = find_channel(card, dlci); - if (status->state & 0x01) { - printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); - if (dev && dev->start) - set_chan_state(dev, WAN_DISCONNECTED); - } else if (status->state & 0x02) { - printk(KERN_INFO - "%s: DLCI %u becomes active!\n", - card->devname, dlci); - if (dev && dev->start) - set_chan_state(dev, WAN_CONNECTED); + if (dev == NULL) + { + printk(KERN_INFO "%s: CPE contains unconfigured DLCI= %d\n", + card->devname, dlci); + } + else + { + if (status->state & 0x01) + { + printk(KERN_INFO + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); + if (dev && dev->start) + set_chan_state(dev, WAN_DISCONNECTED); + } + else if (status->state & 0x02) + { + printk(KERN_INFO + "%s: DLCI %u becomes active!\n", + card->devname, dlci); + chan = dev->priv; + /* This flag is used for configuring specific + DLCI(s) when they become active. + */ + chan->dlci_configured = DLCI_CONFIG_PENDING; + + if (dev && dev->start) + set_chan_state(dev, WAN_CONNECTED); + } } } + + for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave) + { + chan = dev2->priv; + + if (chan->dlci_configured == DLCI_CONFIG_PENDING) + { + memset(&cfg, 0, sizeof(cfg)); + + if ( chan->cir_status == CIR_DISABLED) + { + cfg.cir_fwd = cfg.cir_bwd = 16; + cfg.bc_fwd = cfg.bc_bwd = 16; + cfg.conf_flags = 0x0001; + printk(KERN_INFO "%s: CIR Disabled for %s\n", + card->devname, chan->name); + } + else if (chan->cir_status == CIR_ENABLED) + { + cfg.cir_fwd = cfg.cir_bwd = chan->cir; + cfg.bc_fwd = cfg.bc_bwd = chan->bc; + cfg.be_fwd = cfg.be_bwd = chan->be; + cfg.conf_flags = 0x0000; + printk(KERN_INFO "%s: CIR Enabled for %s\n", + card->devname, chan->name); + + } + + if (fr_dlci_configure( card, &cfg , chan->dlci)) + { + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); + return 1; + } + + chan->dlci_configured = DLCI_CONFIGURED; + + /* + * Read the interface byte mapping into the channel + * structure. + */ + if (card->intr_mode == DLCI_LIST_INTR_MODE) + read_DLCI_IB_mapping( card, chan ); + } + } return 1; } @@ -1375,6 +2317,7 @@ fr_mbox_t *mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + int dlci_found = 0; do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); @@ -1387,12 +2330,19 @@ unsigned short *list = (void *) mbox->data; int cnt = mbox->cmd.length / sizeof(short); - for (; cnt; --cnt, ++list) { - if (*list == chan->dlci) { + for (; cnt; --cnt, ++list) + { + if (*list == chan->dlci) + { + dlci_found = 1; set_chan_state(dev, WAN_CONNECTED); break; } } + + if(!dlci_found) + printk(KERN_INFO "%s: DLCI %u is inactive\n", + card->devname, chan->dlci); } return err; } @@ -1408,22 +2358,25 @@ save_flags(flags); cli(); - if (chan->state != state) { - switch (state) { - case WAN_CONNECTED: - printk(KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); - break; - - case WAN_CONNECTING: - printk(KERN_INFO "%s: interface %s connecting...\n", - card->devname, dev->name); - break; - case WAN_DISCONNECTED: - printk(KERN_INFO "%s: interface %s disconnected!\n", - card->devname, dev->name); - break; + if (chan->state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk(KERN_INFO "%s: interface %s connected!\n" + , card->devname, dev->name); + break; + case WAN_CONNECTING: + printk(KERN_INFO + "%s: interface %s connecting...\n", + card->devname, dev->name); + break; + case WAN_DISCONNECTED: + printk (KERN_INFO + "%s: interface %s disconnected!\n", + card->devname, dev->name); + break; } chan->state = state; } @@ -1452,20 +2405,19 @@ * Return: 1 - Tx buffer(s) available * 0 - no buffers available */ + static int is_tx_ready(sdla_t * card) { - if (card->hw.fwid == SFID_FR508) { - fr508_flags_t *flags = card->flags; + if (card->hw.fwid == SFID_FR508) + { unsigned char sb = inb(card->hw.port); if (sb & 0x02) return 1; - flags->imask |= 0x02; - card->wandev.tx_int_enabled = 1; } else { - fr502_flags_t *flags = card->flags; + fr502_flags_t* flags = card->flags; - if (flags->tx_ready) + if (flags->tx_ready) return 1; flags->imask |= 0x02; } @@ -1485,6 +2437,112 @@ for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned) '0'); return val; +} + +/*============================================================================== + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ + * TEST_COUNTER times. + */ +static int intr_test( sdla_t* card ) +{ + fr_mbox_t* mb = card->mbox; + int err,i; + + /* + * The critical flag is unset here because we want to get into the + * ISR without the flag already set. The If_open sets the flag. + */ + + card->wandev.critical = 0; + + err = fr_set_intr_mode( card, 0x08, card->wandev.mtu ); + + if (err == CMD_OK) + { + for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) + { + /* Run command READ_CODE_VERSION */ + memset(&mb->cmd, 0, sizeof(fr_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = 0x40; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + fr_event(card, err, mb); + } + } + else + return err; + + err = fr_set_intr_mode( card, 0, card->wandev.mtu ); + + if( err != CMD_OK ) + return err; + + card->wandev.critical = 1; + return 0; +} + +/*============================================================================== + * Initializes the Statistics values in the Sdla_t structure. + */ + +void init_global_statistics( sdla_t* card ) +{ + /* Intialize global statistics for a card */ + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; + card->statistics.rx_intr_corrupt_rx_bfr = 0; + card->statistics.rx_intr_on_orphaned_DLCI = 0; + card->statistics.tx_intr_dev_not_started = 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; +} + +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + dlci_IB_mapping_t* result; + int err, counter, found; + + do { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + } while (err && retry-- && fr_event(card, err, mbox)); + + if( mbox->cmd.result != 0) + printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", + chan->name); + + counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); + result = (void *)mbox->data; + + found = 0; + for (; counter; --counter, ++result) { + if ( result->dlci == chan->dlci ) { + printk( KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" + ,card->devname,result->dlci, result->addr_value + ,chan->name); + chan->IB_addr = result->addr_value; + chan->dlci_int_interface = (void*)(card->hw.dpmbase + + ( chan->IB_addr & 0x00001FFF)); + found = 1; + break; + } + } + if (!found) + printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); } /****** End *****************************************************************/ diff -u --recursive --new-file v2.1.78/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.78/linux/drivers/net/sdla_ppp.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/sdla_ppp.c Mon Jan 12 14:46:16 1998 @@ -1,7 +1,7 @@ /***************************************************************************** * sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. * -* Author: Gene Kozin +* Author: Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -10,8 +10,31 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Jun 29, 1997 Alan Cox o Dumped the idiot UDP management system. -* +* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs +* while they have been disabled. +* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by +* disabling and enabling of irqs. +* o Added new counters for stats on disable/enable* IRQs. +* Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' +* before every netif_rx(). +* o Free up the device structure in del_if(). +* Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing +* command. +* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. +* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow +* control by avoiding RACE conditions. The +* cli() and restore_flags() are taken out. +* A new structure, "ppp_private_area", is added +* to provide Driver Statistics. +* Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding +* save_flags(), cli() and restore_flags(). +* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets +* o Added ability to discard mulitcast and +* broacast source addressed packets. +* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities +* New case (0x25) statement in if_send routine. +* Added a global variable rCount to keep track +* of FT1 status enabled on the board. * May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for * 508 card to reflect changes in the new * ppp508.sfm for supporting:continous transmission @@ -59,65 +82,146 @@ #define STATIC static #endif -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ - -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ +#define PPP_DFLT_MTU 1500 /* default MTU */ +#define PPP_MAX_MTU 4000 /* maximum MTU */ #define PPP_HDR_LEN 1 -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +/* For handle_IPXWAN() */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with PPP specific data + */ + +typedef struct ppp_private_area +{ + sdla_t* card; + unsigned long router_start_time; /*router start time in sec */ + unsigned long tick_counter; /*used for 5 second counter*/ + unsigned mc; /*multicast support on or off*/ + /* PPP specific statistics */ + unsigned long if_send_entry; + unsigned long if_send_skb_null; + unsigned long if_send_broadcast; + unsigned long if_send_multicast; + unsigned long if_send_critical_ISR; + unsigned long if_send_critical_non_ISR; + unsigned long if_send_busy; + unsigned long if_send_busy_timeout; + unsigned long if_send_DRVSTATS_request; + unsigned long if_send_PTPIPE_request; + unsigned long if_send_wan_disconnected; + unsigned long if_send_adptr_bfrs_full; + unsigned long if_send_protocol_error; + unsigned long if_send_tx_int_enabled; + unsigned long if_send_bfr_passed_to_adptr; + + unsigned long rx_intr_no_socket; + unsigned long rx_intr_DRVSTATS_request; + unsigned long rx_intr_PTPIPE_request; + unsigned long rx_intr_bfr_not_passed_to_stack; + unsigned long rx_intr_bfr_passed_to_stack; + + unsigned long UDP_PTPIPE_mgmt_kmalloc_err; + unsigned long UDP_PTPIPE_mgmt_adptr_type_err; + unsigned long UDP_PTPIPE_mgmt_direction_err; + unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK; + unsigned long UDP_PTPIPE_mgmt_passed_to_adptr; + unsigned long UDP_PTPIPE_mgmt_passed_to_stack; + unsigned long UDP_PTPIPE_mgmt_no_socket; + + unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; + unsigned long UDP_DRVSTATS_mgmt_adptr_type_err; + unsigned long UDP_DRVSTATS_mgmt_direction_err; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr; + unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_no_socket; + + unsigned long router_up_time; + +}ppp_private_area_t; + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); /* WANPIPE-specific entry points */ -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data); +static int wpp_exec (struct sdla* card, void* u_cmd, void* u_data); /* Network device interface */ -static int if_init(struct device *dev); -static int if_open(struct device *dev); -static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int if_rebuild_hdr(struct sk_buff *skb); -static int if_send(struct sk_buff *skb, struct device *dev); -static struct enet_statistics *if_stats(struct device *dev); +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (struct sk_buff* skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); + /* PPP firmware interface functions */ -static int ppp_read_version(sdla_t * card, char *str); -static int ppp_configure(sdla_t * card, void *data); -static int ppp_set_intr_mode(sdla_t * card, unsigned mode); -static int ppp_comm_enable(sdla_t * card); -static int ppp_comm_disable(sdla_t * card); -static int ppp_get_err_stats(sdla_t * card); -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb); +static int ppp_read_version (sdla_t* card, char* str); +static int ppp_configure (sdla_t* card, void* data); +static int ppp_set_intr_mode (sdla_t* card, unsigned mode); +static int ppp_comm_enable (sdla_t* card); +static int ppp_comm_disable (sdla_t* card); +static int ppp_get_err_stats (sdla_t* card); +static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto); +static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb); /* Interrupt handlers */ -STATIC void wpp_isr(sdla_t * card); -static void rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); +STATIC void wpp_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); /* Background polling routines */ -static void wpp_poll(sdla_t * card); -static void poll_active(sdla_t * card); -static void poll_connecting(sdla_t * card); -static void poll_disconnected(sdla_t * card); +static void wpp_poll (sdla_t* card); +static void poll_active (sdla_t* card); +static void poll_connecting (sdla_t* card); +static void poll_disconnected (sdla_t* card); /* Miscellaneous functions */ -static int config502(sdla_t * card); -static int config508(sdla_t * card); -static void show_disc_cause(sdla_t * card, unsigned cause); -static unsigned char bps_to_speed_code(unsigned long bps); +static int config502 (sdla_t* card); +static int config508 (sdla_t* card); +static void show_disc_cause (sdla_t* card, unsigned cause); +static unsigned char bps_to_speed_code (unsigned long bps); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, ppp_private_area_t* ppp_priv_area); +static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, ppp_private_area_t* ppp_priv_area); +static void init_ppp_tx_rx_buff( sdla_t* card ); +static int intr_test( sdla_t* card ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static void init_ppp_priv_struct( ppp_private_area_t* ppp_priv_area); +static void init_global_statistics( sdla_t* card ); +static int Intr_test_counter; static char TracingEnabled; +static unsigned long curr_trace_addr; +static unsigned long start_trace_addr; +static unsigned short available_buffer_space; + +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); /****** Public Functions ****************************************************/ /*============================================================================ @@ -132,32 +236,38 @@ * Return: 0 o.k. * < 0 failure. */ -__initfunc(int wpp_init(sdla_t * card, wandev_conf_t * conf)) +int wpp_init (sdla_t* card, wandev_conf_t* conf) { - union { + union + { char str[80]; } u; /* Verify configuration ID */ if (conf->config_id != WANCONFIG_PPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + card->devname, conf->config_id); return -EINVAL; + } + /* Initialize protocol-specific fields */ switch (card->hw.fwid) { - case SFID_PPP502: - card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS); - break; - - case SFID_PPP508: - card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS); - break; - default: - return -EINVAL; + case SFID_PPP502: + card->mbox =(void*)(card->hw.dpmbase + PPP502_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP502_FLG_OFFS); + break; + + case SFID_PPP508: + card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); + break; + + default: + return -EINVAL; + } /* Read firmware version. Note that when adapter initializes, it @@ -166,28 +276,39 @@ * around this, we execute the first command twice. */ if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) - return -EIO - ; - printk(KERN_INFO "%s: running PPP firmware v%s\n", - card->devname, u.str); - + return -EIO; + + printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); /* Adjust configuration and set defaults */ card->wandev.mtu = (conf->mtu) ? - min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU - ; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = &wpp_poll; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.udp_port = conf->udp_port; - TracingEnabled = '0'; + min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; + + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpp_isr; + card->poll = &wpp_poll; + card->exec = &wpp_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.udp_port = conf->udp_port; + card->wandev.ttl = conf->ttl; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + TracingEnabled = 0; + + card->wandev.enable_IPX = conf->enable_IPX; + if (conf->network_number) + card->wandev.network_number = conf->network_number; + else + card->wandev.network_number = 0xDEADBEEF; + + /* initialize global statistics */ + init_global_statistics( card ); + return 0; } @@ -229,33 +350,59 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf) +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) { - sdla_t *card = wandev->private; + sdla_t* card = wandev->private; + ppp_private_area_t* ppp_priv_area; if (wandev->ndev) - return -EEXIST - ; + return -EEXIST; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + card->devname); return -EINVAL; + } + + /* allocate and initialize private data */ + ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); + + if( ppp_priv_area == NULL ) + return -ENOMEM; + + memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); + + ppp_priv_area->card = card; + /* initialize data */ strcpy(card->u.p.if_name, conf->name); + /* initialize data in ppp_private_area structure */ + + init_ppp_priv_struct( ppp_priv_area ); + + ppp_priv_area->mc = conf->mc; + /* prepare network device data space for registration */ dev->name = card->u.p.if_name; dev->init = &if_init; - dev->priv = card; + dev->priv = ppp_priv_area; return 0; } /*============================================================================ * Delete logical channel. */ -static int del_if(wan_device_t * wandev, struct device *dev) +static int del_if (wan_device_t* wandev, struct device* dev) { + if (dev->priv) { + + kfree(dev->priv); + dev->priv = NULL; + } + return 0; } @@ -298,39 +445,42 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init(struct device *dev) +static int if_init (struct device* dev) { - sdla_t *card = dev->priv; - wan_device_t *wandev = &card->wandev; + ppp_private_area_t* ppp_priv_area = dev->priv; + sdla_t* card = ppp_priv_area->card; + wan_device_t* wandev = &card->wandev; int i; /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + /* Initialize media-specific parameters */ - dev->family = AF_INET; /* address family */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + dev->family = AF_INET; /* address family */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->mtu = wandev->mtu; + dev->hard_header_len = PPP_HDR_LEN; /* media header length */ /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 30; - + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + /* Initialize socket buffers */ for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]); + return 0; } @@ -341,64 +491,73 @@ * * Return 0 if O.k. or errno. */ -static int if_open(struct device *dev) +static int if_open (struct device* dev) { - sdla_t *card = dev->priv; + ppp_private_area_t* ppp_priv_area = dev->priv; + sdla_t* card = ppp_priv_area->card; + ppp_flags_t* flags = card->flags; + struct timeval tv; int err = 0; if (dev->start) - return -EBUSY /* only one open is allowed */ - ; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - ; - if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) { + + if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)){ + + err = -EIO; + card->wandev.critical = 0; + return err; + + } + + Intr_test_counter = 0; + err = intr_test( card ); + + if( (err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { + + printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); err = -EIO; - goto split; + card->wandev.critical = 0; + return err; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + /* Initialize Rx/Tx buffer control fields */ - if (card->hw.fwid == SFID_PPP502) { - ppp502_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP502_BUF_OFFS); - - card->u.p.txbuf_base = (void *) (card->hw.dpmbase + - info->txb_offs); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = (void *) (card->hw.dpmbase + - info->rxb_offs); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); - } else { - ppp508_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP508_BUF_OFFS); + init_ppp_tx_rx_buff( card ); + + if (ppp_set_intr_mode(card, 0x03)) { + + err = -EIO; + card->wandev.critical = 0; + return err; - card->u.p.txbuf_base = (void *) (card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = (void *) (card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); - card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; } - card->u.p.txbuf = card->u.p.txbuf_base; - card->rxmb = card->u.p.rxbuf_base; - if (ppp_set_intr_mode(card, 0x03) || ppp_comm_enable(card)) { + flags->imask &= ~0x02; + + if (ppp_comm_enable(card)) { + err = -EIO; - goto split; + card->wandev.critical = 0; + return err; + } + wanpipe_set_state(card, WAN_CONNECTING); wanpipe_open(card); dev->mtu = min(dev->mtu, card->wandev.mtu); dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - - split: + do_gettimeofday( &tv ); + ppp_priv_area->router_start_time = tv.tv_sec; card->wandev.critical = 0; return err; } @@ -408,13 +567,14 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ -static int if_close(struct device *dev) +static int if_close (struct device* dev) { - sdla_t *card = dev->priv; + ppp_private_area_t* ppp_priv_area = dev->priv; + sdla_t* card = ppp_priv_area->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - ; + dev->start = 0; wanpipe_close(card); wanpipe_set_state(card, WAN_DISCONNECTED); @@ -433,18 +593,21 @@ * * Return: media header length. */ -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) { - switch (type) { - case ETH_P_IP: - case ETH_P_IPX: - skb->protocol = type; - break; + switch (type) + { + case ETH_P_IP: + + case ETH_P_IPX: + skb->protocol = type; + break; - default: - skb->protocol = 0; + default: + skb->protocol = 0; } + return PPP_HDR_LEN; } @@ -454,12 +617,13 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - sdla_t *card = skb->dev->priv; + ppp_private_area_t* ppp_priv_area = skb->dev->priv; + sdla_t* card = ppp_priv_area->card; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, skb->dev->name); + card->devname, dev->name); return 1; } @@ -480,55 +644,238 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ -static int if_send(struct sk_buff *skb, struct device *dev) +static int if_send (struct sk_buff* skb, struct device* dev) { - sdla_t *card = dev->priv; + ppp_private_area_t* ppp_priv_area = dev->priv; + sdla_t* card = ppp_priv_area->card; + unsigned char *sendpacket; + unsigned long check_braddr, check_mcaddr; + unsigned long host_cpu_flags; + ppp_flags_t* flags = card->flags; int retry = 0; + int err, udp_type; + + ++ppp_priv_area->if_send_entry; + + if (skb == NULL) { + + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + ++ppp_priv_area->if_send_skb_null; + + dev_tint(dev); + return 0; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { -#ifdef _DEBUG_ - printk(KERN_INFO "%s: if_send() hit critical section!\n", - card->devname); -#endif - return 1; } - if (test_and_set_bit(0, (void *) &dev->tbusy)) { -#ifdef _DEBUG_ - printk(KERN_INFO "%s: Tx collision on interface %s!\n", - card->devname, dev->name); + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++ppp_priv_area->if_send_busy; + ++card->wandev.stats.collisions; + + if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit times out\n",card->devname); + + ++ppp_priv_area->if_send_busy_timeout; + + /* unbusy the card (because only one interface per card)*/ + dev->tbusy = 0; + } + sendpacket = skb->data; +#ifdef CONFIG_SANGOMA_MANAGER + if(sangoma_ppp_manager(skb,card)) + { + dev_kfree_skb(skb, FREE_WRITE); + return 0; + } #endif - ++card->wandev.stats.collisions; - retry = 1; - } else if (card->wandev.state != WAN_CONNECTED) - ++card->wandev.stats.tx_dropped - ; - else if (!skb->protocol) - ++card->wandev.stats.tx_errors - ; - else if (ppp_send(card, skb->data, skb->len, skb->protocol)) { - ppp_flags_t *flags = card->flags; + disable_irq(card->hw.irq); + ++card->irq_dis_if_send_count; - flags->imask |= 0x02; /* unmask Tx interrupts */ - retry = 1; - } else - ++card->wandev.stats.tx_packets; + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + if (card->wandev.critical == CRITICAL_IN_ISR) + { + /* If the critical flag is set due to an Interrupt + * then set enable transmit interrupt flag to enable + * transmit interrupt. (delay interrupt) + */ + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + + /* set the counter to see if we get the interrupt in + * 5 seconds. + */ + ppp_priv_area->tick_counter = jiffies; + ++ppp_priv_area->if_send_critical_ISR; + + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return 1; + + } + + dev_kfree_skb(skb, FREE_WRITE); + ++ppp_priv_area->if_send_critical_non_ISR; + + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return 0; + } + + + if (card->wandev.state != WAN_CONNECTED) { + + ++ppp_priv_area->if_send_wan_disconnected; + ++card->wandev.stats.tx_dropped; + + } else if (!skb->protocol) { + ++ppp_priv_area->if_send_protocol_error; + ++card->wandev.stats.tx_errors; + + } else { + + /*If it's IPX change the network numbers to 0 if they're ours.*/ + if( skb->protocol == ETH_P_IPX ) { + if(card->wandev.enable_IPX) { + switch_net_numbers( skb->data, + card->wandev.network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + goto tx_done; + } + } - if (!retry) { + if (ppp_send(card, skb->data, skb->len, skb->protocol)) { + + retry = 1; + dev->tbusy = 1; + ++ppp_priv_area->if_send_adptr_bfrs_full; + ++ppp_priv_area->if_send_tx_int_enabled; + ppp_priv_area->tick_counter = jiffies; + ++card->wandev.stats.tx_errors; + flags->imask |= 0x02; /* unmask Tx interrupts */ + + } else { + ++ppp_priv_area->if_send_bfr_passed_to_adptr; + ++card->wandev.stats.tx_packets; + } + } + +tx_done: + if (!retry){ dev_kfree_skb(skb, FREE_WRITE); - dev->tbusy = 0; } + card->wandev.critical = 0; + + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return retry; } +/* + If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + if incoming is 1 - if the net number is 0 make it ours + +*/ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + + if (!incoming) + { + /* If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) + { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } + else + { + /* If the incoming network is 0, make it ours */ + if( pnetwork_number == 0) + { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) + { + /* If the source network is ours, make it 0 */ + if( pnetwork_number == network_number) + { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } + else + { + /* If the source network is 0, make it ours */ + if( pnetwork_number == 0 ) + { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + /*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ - -static struct enet_statistics *if_stats(struct device *dev) +static struct net_device_stats* if_stats (struct device* dev) { - sdla_t *card = dev->priv; + ppp_private_area_t* ppp_priv_area = dev->priv; + sdla_t* card = ppp_priv_area->card; return &card->wandev.stats; } @@ -539,125 +886,146 @@ * Read firmware code version. * Put code version as ASCII string in str. */ -static int ppp_read_version(sdla_t * card, char *str) +static int ppp_read_version (sdla_t* card, char* str) { - ppp_mbox_t *mb = card->mbox; + ppp_mbox_t* mb = card->mbox; int err; memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_CODE_VERSION; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + else if (str) { + int len = mb->cmd.length; memcpy(str, mb->data, len); str[len] = '\0'; + } + return err; } /*============================================================================ * Configure PPP firmware. */ -static int ppp_configure(sdla_t * card, void *data) +static int ppp_configure (sdla_t* card, void* data) { - ppp_mbox_t *mb = card->mbox; + ppp_mbox_t* mb = card->mbox; int data_len = (card->hw.fwid == SFID_PPP502) ? - sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); + sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); int err; memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; + mb->cmd.length = data_len; mb->cmd.command = PPP_SET_CONFIG; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Set interrupt mode. */ -static int ppp_set_intr_mode(sdla_t * card, unsigned mode) +static int ppp_set_intr_mode (sdla_t* card, unsigned mode) { - ppp_mbox_t *mb = card->mbox; + ppp_mbox_t* mb = card->mbox; int err; memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->data[0] = mode; - switch (card->hw.fwid) { - case SFID_PPP502: - mb->cmd.length = 1; - break; - - case SFID_PPP508: - default: - mb->data[1] = card->hw.irq; - mb->cmd.length = 2; + + switch (card->hw.fwid) + { + case SFID_PPP502: + mb->cmd.length = 1; + break; + + case SFID_PPP508: + + default: + mb->data[1] = card->hw.irq; + mb->cmd.length = 2; } + mb->cmd.command = PPP_SET_INTR_FLAGS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Enable communications. */ -static int ppp_comm_enable(sdla_t * card) +static int ppp_comm_enable (sdla_t* card) { - ppp_mbox_t *mb = card->mbox; + ppp_mbox_t* mb = card->mbox; int err; memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_ENABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Disable communications. */ -static int ppp_comm_disable(sdla_t * card) +static int ppp_comm_disable (sdla_t* card) { - ppp_mbox_t *mb = card->mbox; + ppp_mbox_t* mb = card->mbox; int err; memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_DISABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Get communications error statistics. */ -static int ppp_get_err_stats(sdla_t * card) +static int ppp_get_err_stats (sdla_t* card) { - ppp_mbox_t *mb = card->mbox; + ppp_mbox_t* mb = card->mbox; int err; memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_ERROR_STATS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err == CMD_OK) { - ppp_err_stats_t *stats = (void *) mb->data; - - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; + + if (err == CMD_OK) + { + ppp_err_stats_t* stats = (void*)mb->data; + card->wandev.stats.rx_over_errors = stats->rx_overrun; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_abort; + card->wandev.stats.rx_length_errors = stats->rx_lost; card->wandev.stats.tx_aborted_errors = stats->tx_abort; - } else + + } else ppp_error(card, err, mb); + return err; } @@ -666,34 +1034,36 @@ * Return: 0 - o.k. * 1 - no transmit buffers available */ -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) + +static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto) { - ppp_buf_ctl_t *txbuf = card->u.p.txbuf; - unsigned long addr, cpu_flags; + ppp_buf_ctl_t* txbuf = card->u.p.txbuf; + unsigned long addr; if (txbuf->flag) - return 1 - ; + return 1; + if (card->hw.fwid == SFID_PPP502) - addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; - else + addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; + else addr = txbuf->buf.ptr; - save_flags(cpu_flags); - cli(); + sdla_poke(&card->hw, addr, data, len); - restore_flags(cpu_flags); - txbuf->length = len; /* frame length */ + + txbuf->length = len; /* frame length */ + if (proto == ETH_P_IPX) - txbuf->proto = 0x01 /* protocol ID */ - ; - txbuf->flag = 1; /* start transmission */ + txbuf->proto = 0x01; /* protocol ID */ + + txbuf->flag = 1; /* start transmission */ /* Update transmit buffer control fields */ card->u.p.txbuf = ++txbuf; - if ((void *) txbuf > card->u.p.txbuf_last) - card->u.p.txbuf = card->u.p.txbuf_base - ; + + if ((void*)txbuf > card->u.p.txbuf_last) + card->u.p.txbuf = card->u.p.txbuf_base; + return 0; } @@ -706,20 +1076,23 @@ * * Return zero if previous command has to be cancelled. */ -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) + +static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb) { unsigned cmd = mb->cmd.command; - switch (err) { - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); + switch (err) + { + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, cmd, err); } + return 0; } @@ -728,112 +1101,361 @@ /*============================================================================ * PPP interrupt service routine. */ -STATIC void wpp_isr(sdla_t * card) +STATIC void wpp_isr (sdla_t* card) { - ppp_flags_t *flags = card->flags; + ppp_flags_t* flags = card->flags; + char *ptr = &flags->iflag; + unsigned long host_cpu_flags; + struct device* dev = card->wandev.dev; + int i; + + card->in_isr = 1; + + ++card->statistics.isr_entry; + + if (set_bit(0, (void*)&card->wandev.critical)) { + + ++card->statistics.isr_already_critical; + printk (KERN_INFO "%s: Critical while in ISR!\n",card->devname); + card->in_isr = 0; + return; + + } + + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + + card->buff_int_mode_unbusy = 0; switch (flags->iflag) { - case 0x01: /* receive interrupt */ - rx_intr(card); - break; - - case 0x02: /* transmit interrupt */ - flags->imask &= ~0x02; - tx_intr(card); - break; - - default: /* unexpected interrupt */ - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); + + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + flags->imask &= ~0x02; + dev->tbusy = 0; + card->buff_int_mode_unbusy = 1; + break; + + case 0x08: + ++Intr_test_counter; + ++card->statistics.isr_intr_test; + break; + + default: /* unexpected interrupt */ + ++card->statistics.isr_spurious; + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, flags->iflag); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + } + + /* The critical flag is set to CRITICAL_INTR_HANDLED to let the + * if_send call know that the interrupt is handled so that + * transmit interrupts are not enabled again. + */ + + card->wandev.critical = CRITICAL_INTR_HANDLED; + + /* If the enable transmit interrupt flag is set then enable transmit + * interrupt on the board. This only goes through if if_send is called + * and the critical flag is set due to an Interrupt. + */ + if(card->wandev.enable_tx_int) { + + flags->imask |= 0x02; + card->wandev.enable_tx_int = 0; + ++card->statistics.isr_enable_tx_int; + } + save_flags(host_cpu_flags); + cli(); + card->in_isr = 0; flags->iflag = 0; + card->wandev.critical = 0; + restore_flags(host_cpu_flags); + + if(card->buff_int_mode_unbusy) + mark_bh(NET_BH); + } /*============================================================================ * Receive interrupt handler. */ -static void rx_intr(sdla_t * card) +static void rx_intr (sdla_t* card) { - ppp_buf_ctl_t *rxbuf = card->rxmb; - struct device *dev = card->wandev.dev; - struct sk_buff *skb; + ppp_buf_ctl_t* rxbuf = card->rxmb; + struct device* dev = card->wandev.dev; + ppp_private_area_t* ppp_priv_area; + struct sk_buff* skb; unsigned len; - void *buf; + void* buf; + int i, err; + ppp_flags_t* flags = card->flags; + char *ptr = &flags->iflag; + int udp_type; + if (rxbuf->flag != 0x01) { - printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", - card->devname, (unsigned) rxbuf); - return; - } - if (!dev || !dev->start) - goto rx_done - ; - len = rxbuf->length; + - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb == NULL) { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++card->wandev.stats.rx_dropped; - goto rx_done; - } - /* Copy data to the socket buffer */ - if (card->hw.fwid == SFID_PPP502) { - unsigned addr = (rxbuf->buf.o_p[1] << 8) + rxbuf->buf.o_p[0]; + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->flag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + + ++card->statistics.rx_intr_corrupt_rx_bfr; + return; - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - } else { - unsigned addr = rxbuf->buf.ptr; + } + - if ((addr + len) > card->u.p.rx_top + 1) { - unsigned tmp = card->u.p.rx_top - addr + 1; + if (dev && dev->start) { + + len = rxbuf->length; + ppp_priv_area = dev->priv; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb != NULL) { + + /* Copy data to the socket buffer */ + if (card->hw.fwid == SFID_PPP502) { + + unsigned addr = (rxbuf->buf.o_p[1] << 8) + + rxbuf->buf.o_p[0]; + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + + } else { + + unsigned addr = rxbuf->buf.ptr; + + if ((addr + len) > card->u.p.rx_top + 1) { + + unsigned tmp = card->u.p.rx_top - addr + + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.p.rx_base; + len -= tmp; + + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + } + + /* Decapsulate packet */ + switch (rxbuf->proto) { + + case 0x00: + skb->protocol = htons(ETH_P_IP); + break; + + case 0x01: + skb->protocol = htons(ETH_P_IPX); + break; + } +#ifdef CONFIG_SANGOMA_MANAGER + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE){ + ++ppp_priv_area->rx_intr_DRVSTATS_request; + process_udp_driver_call( + UDP_PKT_FRM_NETWORK, card, skb, + dev, ppp_priv_area); + dev_kfree_skb(skb, FREE_READ); + + } else if (udp_type == UDP_PTPIPE_TYPE){ + ++ppp_priv_area->rx_intr_PTPIPE_request; + err = process_udp_mgmt_pkt( + UDP_PKT_FRM_NETWORK, card, + skb, dev, ppp_priv_area); + dev_kfree_skb(skb, FREE_READ); + } else +#endif + if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { + + if( card->wandev.enable_IPX) { + ppp_send(card, skb->data, skb->len, ETH_P_IPX); + dev_kfree_skb(skb, FREE_READ); + + } else { + ++card->wandev.stats.rx_dropped; + } + } else { + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++card->wandev.stats.rx_packets; + ++ppp_priv_area->rx_intr_bfr_passed_to_stack; + } + + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + ++ppp_priv_area->rx_intr_no_socket; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.p.rx_base; - len -= tmp; } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - } - /* Decapsulate packet */ - switch (rxbuf->proto) { - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; - } - - /* Pass it up the protocol stack */ - skb->dev = dev; - netif_rx(skb); - ++card->wandev.stats.rx_packets; - rx_done: + } else + ++card->statistics.rx_intr_dev_not_started; + /* Release buffer element and calculate a pointer to the next one */ rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; card->rxmb = ++rxbuf; - if ((void *) rxbuf > card->u.p.rxbuf_last) - card->rxmb = card->u.p.rxbuf_base - ; + + if ((void*)rxbuf > card->u.p.rxbuf_last) + card->rxmb = card->u.p.rxbuf_base; } /*============================================================================ * Transmit interrupt handler. */ -static void tx_intr(sdla_t * card) +static void tx_intr (sdla_t* card) { - struct device *dev = card->wandev.dev; + struct device* dev = card->wandev.dev; + + if (!dev || !dev->start) + { + ++card->statistics.tx_intr_dev_not_started; + return; + } - if (!dev || !dev->start) - return; dev->tbusy = 0; - mark_bh(NET_BH); + dev_tint(dev); +} + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) +{ + int i; + + if( proto == htons(ETH_P_IPX) ) + { + /* It's an IPX packet */ + if(!enable_IPX) + { + //Return 1 so we don't pass it up the stack. + return 1; + } + } + else + { + /* It's not IPX so pass it up the stack. */ + return 0; + } + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + /* It's IPXWAN */ + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every */ + /* option except Unnumbered RIP/SAP */ + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + /* 0x02 is the option for Unnumbered RIP/SAP */ + if( sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + + /* Skip over the extended Node ID option */ + if( sendpacket[i] == 0x04 ) + { + i += 8; + } + + /* We also want to turn off all header compression opt. */ + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + /* Set the packet type to timer response */ + sendpacket[34] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + /* This is an information request packet */ + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + /* Set the packet type to information response */ + sendpacket[34] = 0x03; + + /* Set the router name */ + sendpacket[51] = 'P'; + sendpacket[52] = 'T'; + sendpacket[53] = 'P'; + sendpacket[54] = 'I'; + sendpacket[55] = 'P'; + sendpacket[56] = 'E'; + sendpacket[57] = '-'; + sendpacket[58] = CVHexToAscii(network_number >> 28); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); + for(i = 66; i < 99; i+= 1) + { + sendpacket[i] = 0; + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + /* Set the WNodeID to our network address */ + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } else { + /* If we get here's its an IPX-data packet, so it'll get passed up the stack. */ + + /* switch the network numbers */ + switch_net_numbers(sendpacket, network_number, 1); + return 0; + } } /****** Background Polling Routines ****************************************/ @@ -847,33 +1469,100 @@ * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */ -static void wpp_poll(sdla_t * card) +static void wpp_poll (sdla_t* card) { - switch (card->wandev.state) { - case WAN_CONNECTED: - poll_active(card); - break; - - case WAN_CONNECTING: - poll_connecting(card); - break; - - case WAN_DISCONNECTED: - poll_disconnected(card); - break; + struct device* dev = card->wandev.dev; + ppp_flags_t* adptr_flags = card->flags; + unsigned long host_cpu_flags; + + ++card->statistics.poll_entry; + + /* The wpp_poll is called continously by the WANPIPE thread to allow + * for line state housekeeping. However if we are in a connected state + * then we do not need to go through all the checks everytime. When in + * connected state execute wpp_poll once every second. + */ + + if (card->wandev.state == WAN_CONNECTED) + { + if ((jiffies - card->state_tick) < HZ ) + return; + } + + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + + if (set_bit(0, (void *)&card->wandev.critical)) + { + ++card->statistics.poll_already_critical; + printk(KERN_INFO "%s: critical inside wpp_poll\n", + card->devname); + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && + (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return; } + + ++card->statistics.poll_processed; + + if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) + { + ++card->statistics.poll_tbusy_bad_status; + printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n" + , card->devname, adptr_flags->imask); + } + + switch(card->wandev.state) + { + case WAN_CONNECTED: + card->state_tick = jiffies; + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + break; + + default: + printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", + card->devname, card->wandev.state); + break; + } + + card->wandev.critical = 0; + + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + } /*============================================================================ * Monitor active link phase. */ -static void poll_active(sdla_t * card) +static void poll_active (sdla_t* card) { - ppp_flags_t *flags = card->flags; + ppp_flags_t* flags = card->flags; + + /* We check the lcp_state to see if we are in DISCONNECTED state. + * We are considered to be connected for lcp states 0x06, 0x07, 0x08 + * and 0x09. + */ + if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) { - if (flags->disc_cause & 0x03) { wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); + } } @@ -881,13 +1570,16 @@ * Monitor link establishment phase. * o if connection timed out, disconnect the link. */ -static void poll_connecting(sdla_t * card) +static void poll_connecting (sdla_t* card) { - ppp_flags_t *flags = card->flags; - - if (flags->lcp_state == 0x09) { + ppp_flags_t* flags = card->flags; + + if (flags->lcp_state == 0x09) + { wanpipe_set_state(card, WAN_CONNECTED); - } else if (flags->disc_cause & 0x03) { + } + else if (flags->disc_cause & 0x03) + { wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); } @@ -898,14 +1590,16 @@ * o if interface is up and the hold-down timeout has expired, then retry * connection. */ -static void poll_disconnected(sdla_t * card) +static void poll_disconnected (sdla_t* card) { - struct device *dev = card->wandev.dev; + struct device* dev = card->wandev.dev; if (dev && dev->start && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - wanpipe_set_state(card, WAN_CONNECTING); - ppp_comm_enable(card); + ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) + { + wanpipe_set_state(card, WAN_CONNECTING); + if(ppp_comm_enable(card) == CMD_OK) + init_ppp_tx_rx_buff( card ); } } @@ -914,7 +1608,7 @@ /*============================================================================ * Configure S502 adapter. */ -static int config502(sdla_t * card) +static int config502 (sdla_t* card) { ppp502_conf_t cfg; @@ -923,33 +1617,34 @@ if (card->wandev.clocking) cfg.line_speed = bps_to_speed_code(card->wandev.bps); - cfg.txbuf_num = 4; - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 5; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; - cfg.conf_flags |= 0x0E; + + cfg.txbuf_num = 4; + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 5; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 0; /* changed it from 900 */ + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + cfg.ip_options = 0x80; + cfg.ipx_options = 0xA0; + cfg.conf_flags |= 0x0E; /* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; +*/ return ppp_configure(card, &cfg); } /*============================================================================ * Configure S508 adapter. */ -static int config508(sdla_t * card) +static int config508 (sdla_t* card) { ppp508_conf_t cfg; @@ -957,111 +1652,275 @@ memset(&cfg, 0, sizeof(ppp508_conf_t)); if (card->wandev.clocking) - cfg.line_speed = card->wandev.bps - ; + cfg.line_speed = card->wandev.bps; + if (card->wandev.interface == WANOPT_RS232) cfg.conf_flags |= 0x0020; - ; - cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */ - cfg.txbuf_percent = 60; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 5; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; + + cfg.conf_flags |= 0x300; /*send Configure-Request packets forever*/ + cfg.txbuf_percent = 60; /* % of Tx bufs */ + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 100; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 0; /* changed it from 900 */ + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + cfg.ip_options = 0x80; + cfg.ipx_options = 0xA0; /* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; +*/ return ppp_configure(card, &cfg); } /*============================================================================ * Show disconnection cause. */ -static void show_disc_cause(sdla_t * card, unsigned cause) +static void show_disc_cause (sdla_t* card, unsigned cause) { - if (cause & 0x0002) - printk(KERN_INFO - "%s: link terminated by peer\n", card->devname); - else if (cause & 0x0004) - printk(KERN_INFO - "%s: link terminated by user\n", card->devname); - else if (cause & 0x0008) - printk(KERN_INFO - "%s: authentication failed\n", card->devname); + if (cause & 0x0002) + printk(KERN_INFO "%s: link terminated by peer\n", + card->devname); + + else if (cause & 0x0004) + printk(KERN_INFO "%s: link terminated by user\n", + card->devname); + + else if (cause & 0x0008) + printk(KERN_INFO "%s: authentication failed\n", card->devname); + else if (cause & 0x0010) + printk(KERN_INFO + "%s: authentication protocol negotiation failed\n", + card->devname); + + else if (cause & 0x0020) printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - else if (cause & 0x0020) - printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - else if (cause & 0x0040) - printk(KERN_INFO - "%s: MRU option rejected by peer\n", card->devname); - else if (cause & 0x0080) - printk(KERN_INFO - "%s: peer's MRU was too small\n", card->devname); - else if (cause & 0x0100) - printk(KERN_INFO - "%s: failed to negotiate peer's LCP options\n", - card->devname); - else if (cause & 0x0200) - printk(KERN_INFO - "%s: failed to negotiate peer's IPCP options\n", - card->devname); - else if (cause & 0x0400) - printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); + "%s: peer's request for authentication rejected\n", + card->devname); + + else if (cause & 0x0040) + printk(KERN_INFO "%s: MRU option rejected by peer\n", + card->devname); + + else if (cause & 0x0080) + printk(KERN_INFO "%s: peer's MRU was too small\n", + card->devname); + + else if (cause & 0x0100) + printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", + card->devname); + + else if (cause & 0x0200) + printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" + , card->devname); + + else if (cause & 0x0400) + printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname); } /*============================================================================ * Convert line speed in bps to a number used by S502 code. */ -static unsigned char bps_to_speed_code(unsigned long bps) +static unsigned char bps_to_speed_code (unsigned long bps) { - unsigned char number; + unsigned char number; - if (bps <= 1200) + if (bps <= 1200) number = 0x01; - else if (bps <= 2400) + else if (bps <= 2400) number = 0x02; - else if (bps <= 4800) + else if (bps <= 4800) number = 0x03; - else if (bps <= 9600) + else if (bps <= 9600) number = 0x04; - else if (bps <= 19200) + else if (bps <= 19200) number = 0x05; - else if (bps <= 38400) + else if (bps <= 38400) number = 0x06; - else if (bps <= 45000) + else if (bps <= 45000) number = 0x07; - else if (bps <= 56000) + else if (bps <= 56000) number = 0x08; - else if (bps <= 64000) + else if (bps <= 64000) number = 0x09; - else if (bps <= 74000) + else if (bps <= 74000) number = 0x0A; - else if (bps <= 112000) + else if (bps <= 112000) number = 0x0B; - else if (bps <= 128000) + else if (bps <= 128000) number = 0x0C; - else + else number = 0x0D; return number; +} + +/*============================================================================= + * Initial the ppp_private_area structure. + */ + +static void init_ppp_priv_struct( ppp_private_area_t* ppp_priv_area ) +{ + ppp_priv_area->if_send_entry = 0; + ppp_priv_area->if_send_skb_null = 0; + ppp_priv_area->if_send_broadcast = 0; + ppp_priv_area->if_send_multicast = 0; + ppp_priv_area->if_send_critical_ISR = 0; + ppp_priv_area->if_send_critical_non_ISR = 0; + ppp_priv_area->if_send_busy = 0; + ppp_priv_area->if_send_busy_timeout = 0; + ppp_priv_area->if_send_DRVSTATS_request = 0; + ppp_priv_area->if_send_PTPIPE_request = 0; + ppp_priv_area->if_send_wan_disconnected = 0; + ppp_priv_area->if_send_adptr_bfrs_full = 0; + ppp_priv_area->if_send_bfr_passed_to_adptr = 0; + + ppp_priv_area->rx_intr_no_socket = 0; + ppp_priv_area->rx_intr_DRVSTATS_request = 0; + ppp_priv_area->rx_intr_PTPIPE_request = 0; + ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0; + ppp_priv_area->rx_intr_bfr_passed_to_stack = 0; + + ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0; + + ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0; +} + +/*============================================================================ + * Initialize Global Statistics + */ +static void init_global_statistics( sdla_t* card ) +{ + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; + card->statistics.rx_intr_corrupt_rx_bfr = 0; + card->statistics.rx_intr_dev_not_started= 0; + card->statistics.tx_intr_dev_not_started= 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; + card->statistics.poll_tbusy_bad_status = 0; + +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ +static void init_ppp_tx_rx_buff( sdla_t* card ) +{ + + if (card->hw.fwid == SFID_PPP502) + { + ppp502_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP502_BUF_OFFS); + + card->u.p.txbuf_base = + (void*)(card->hw.dpmbase + info->txb_offs); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = + (void*)(card->hw.dpmbase + info->rxb_offs); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); + } + else + { + ppp508_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); + + card->u.p.txbuf_base = (void*)(card->hw.dpmbase + + (info->txb_ptr - PPP508_MB_VECT)); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + + (info->rxb_ptr - PPP508_MB_VECT)); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); + + card->u.p.rx_base = info->rxb_base; + card->u.p.rx_top = info->rxb_end; + } + + card->u.p.txbuf = card->u.p.txbuf_base; + card->rxmb = card->u.p.rxbuf_base; + +} + +/*============================================================================= + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card ) +{ + ppp_mbox_t* mb = card->mbox; + int err,i; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpp_isr is + * called it does not exit due to critical flag set. + */ + + card->wandev.critical = 0; + + err = ppp_set_intr_mode( card, 0x08 ); + + if ( err == CMD_OK ) + { + for (i=0; icmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = 0x10; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + } + } + else return err; + + err = ppp_set_intr_mode( card, 0 ); + if (err != CMD_OK) + return err; + + card->wandev.critical = 1; + return 0; } /****** End *****************************************************************/ diff -u --recursive --new-file v2.1.78/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.1.78/linux/drivers/net/sdla_x25.c Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/sdla_x25.c Mon Jan 12 14:46:16 1998 @@ -10,6 +10,19 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs +* when they are disabled. +* Nov 17, 1997 Farhan Thawar o Added IPX support +* o Changed if_send() to now buffer packets when +* the board is busy +* o Removed queueing of packets via the polling +* routing +* o Changed if_send() critical flags to properly +* handle race conditions +* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts +* o Changed PVC encapsulation to ETH_P_IP +* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree() +* when packets are received. * Mar 11, 1997 Farhan Thawar Version 3.1.1 * o added support for V35 * o changed if_send() to return 0 if @@ -49,12 +62,15 @@ #define MAX_CMD_RETRY 10 /* max number of firmware retries */ #define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ -#define X25_HRDHDR_SZ 6 /* max encapsulation header size */ +#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ #define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ #define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ +/* For IPXWAN */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + /****** Data Structures *****************************************************/ /* This is an extention of the 'struct device' we create for each network @@ -72,7 +88,10 @@ char drop_sequence; /* mark sequence for dropping */ unsigned long state_tick; /* time of the last state change */ unsigned idle_timeout; /* sec, before disconnecting */ + unsigned long i_timeout_sofar; /* # of sec's we've been idle */ unsigned hold_timeout; /* sec, before re-connecting */ + unsigned long tick_counter; /* counter for transmit time out */ + char devtint; /* Weather we should dev_tint() */ struct sk_buff* rx_skb; /* receive socket buffer */ struct sk_buff* tx_skb; /* transmit socket buffer */ sdla_t* card; /* -> owner */ @@ -167,6 +186,13 @@ static unsigned int hex_to_uint (unsigned char* str, int len); static void parse_call_info (unsigned char* str, x25_call_info_t* info); +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + /****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! */ @@ -232,7 +258,7 @@ u.cfg.hdlcWindow = 7; u.cfg.pktWindow = 2; u.cfg.station = 1; /* DTE */ - u.cfg.options = 0x0010; /* disable D-bit pragmatics */ + u.cfg.options = 0x00B0; /* disable D-bit pragmatics */ u.cfg.ccittCompat = 1988; u.cfg.t10t20 = 30; u.cfg.t11t21 = 30; @@ -243,6 +269,7 @@ u.cfg.r10r20 = 5; u.cfg.r12r22 = 5; u.cfg.r13r23 = 5; + u.cfg.responseOpt = 1; /* RR's after every packet */ if (conf->clocking != WANOPT_EXTERNAL) u.cfg.baudRate = bps_to_speed_code(conf->bps) @@ -267,7 +294,7 @@ else if (conf->mtu >= 128) card->wandev.mtu = 128 ; - else conf->mtu = 64; + else card->wandev.mtu = 64; u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; if (conf->u.x25.hi_pvc) @@ -322,6 +349,15 @@ card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; card->wandev.state = WAN_DISCONNECTED; + card->wandev.enable_tx_int = 0; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + card->wandev.enable_IPX = conf->enable_IPX; + + if (conf->network_number) + card->wandev.network_number = conf->network_number; + else + card->wandev.network_number = 0xDEADBEEF; return 0; } @@ -386,13 +422,18 @@ memset(chan, 0, sizeof(x25_channel_t)); strcpy(chan->name, conf->name); chan->card = card; + chan->protocol = ETH_P_IP; + chan->tx_skb = chan->rx_skb = NULL; /* verify media address */ if (conf->addr[0] == '@') /* SVC */ { chan->svc = 1; - chan->protocol = ETH_P_IP; strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); + + /* Set channel timeouts (default if not specified) */ + chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 90; + chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; } else if (is_digit(conf->addr[0])) /* PVC */ { @@ -435,6 +476,7 @@ /*============================================================================ * Delete logical channel. */ + static int del_if (wan_device_t* wandev, struct device* dev) { if (dev->priv) @@ -450,6 +492,7 @@ /*============================================================================ * Execute adapter interface command. */ + static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) { TX25Mbox* mbox = card->mbox; @@ -525,6 +568,9 @@ dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; + /* Initialize socket buffers */ for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]) @@ -659,33 +705,86 @@ { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - int queued = 0; + struct device *dev2; + TX25Status* status = card->flags; + unsigned long host_cpu_flags; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) + if (skb == NULL) { + /* If we get here, some higher layer thinks we've missed a + * tx-done interrupt. + */ #ifdef _DEBUG_ - printk(KERN_INFO "%s: if_send() hit critical section!\n", - card->devname) + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name) ; #endif - dev_kfree_skb(skb, FREE_WRITE); + dev_tint(dev); return 0; } - if (test_and_set_bit(0, (void*)&dev->tbusy)) + if (dev->tbusy) { -#ifdef _DEBUG_ - printk(KERN_INFO "%s: Tx collision on interface %s!\n", + ++chan->ifstats.rx_dropped; + if ((jiffies - chan->tick_counter) < (5*HZ)) + { + return dev->tbusy; + } + printk(KERN_INFO "%s: Transmit time out %s!\n", card->devname, dev->name) ; -#endif - ++chan->ifstats.collisions; - ++card->wandev.stats.collisions; - dev_kfree_skb(skb, FREE_WRITE); - card->wandev.critical = 0; - return 0; + for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + dev2->tbusy = 0; + } } - else if (chan->protocol && (chan->protocol != skb->protocol)) + chan->tick_counter = jiffies; + + disable_irq(card->hw.irq); + ++card->irq_dis_if_send_count; + + if (set_bit(0, (void*)&card->wandev.critical)) + { + printk(KERN_INFO "Hit critical in if_send()!\n"); + if (card->wandev.critical == CRITICAL_IN_ISR) + { + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return dev->tbusy; + } + dev_kfree_skb(skb, FREE_WRITE); + + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return dev->tbusy; + } + + /* Below is only until we have per-channel IPX going.... */ + if(!(chan->svc)) + { + chan->protocol = skb->protocol; + } + + if (card->wandev.state != WAN_CONNECTED) + { + ++chan->ifstats.tx_dropped + ; + } + /* Below is only until we have per-channel IPX going.... */ + else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) { printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", @@ -693,41 +792,57 @@ ; ++chan->ifstats.tx_errors; } - else if (card->wandev.state != WAN_CONNECTED) - ++chan->ifstats.tx_dropped - ; else switch (chan->state) { - case WAN_CONNECTED: - dev->trans_start = jiffies; - queued = chan_send(dev, skb); - if (queued) chan->tx_skb = skb; - break; - case WAN_DISCONNECTED: /* Try to establish connection. If succeded, then start * transmission, else drop a packet. */ - if (chan_connect(dev) == 0) + if (chan_connect(dev) != 0) { - dev->trans_start = jiffies; - queued = chan_send(dev, skb); - if (queued) chan->tx_skb = skb; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; break; } - /* else fall through */ + /* fall through */ + + case WAN_CONNECTED: + if( skb->protocol == ETH_P_IPX ) { + if(card->wandev.enable_IPX) { + switch_net_numbers( skb->data, + card->wandev.network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + goto tx_done; + } + } + dev->trans_start = jiffies; + if(chan_send(dev, skb)) + { + dev->tbusy = 1; + status->imask |= 0x2; + } + break; default: - ++chan->ifstats.tx_dropped; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; } - if (!queued) +tx_done: + if (!dev->tbusy) { dev_kfree_skb(skb, FREE_WRITE); - dev->tbusy = 0; } card->wandev.critical = 0; - return 0; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return dev->tbusy; } /*============================================================================ @@ -749,6 +864,24 @@ static void wpx_isr (sdla_t* card) { TX25Status* status = card->flags; + struct device *dev; + unsigned long host_cpu_flags; + + card->in_isr = 1; + card->buff_int_mode_unbusy = 0; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); + card->in_isr = 0; + return; + } + + /* For all interrupts set the critical flag to CRITICAL_RX_INTR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; switch (status->iflags) { @@ -758,6 +891,8 @@ case 0x02: /* transmit interrupt */ tx_intr(card); + card->buff_int_mode_unbusy = 1; + status->imask &= ~0x2; break; case 0x04: /* modem status interrupt */ @@ -768,10 +903,33 @@ event_intr(card); break; - default: /* unwanter interrupt */ + default: /* unwanted interrupt */ spur_intr(card); } + + card->wandev.critical = CRITICAL_INTR_HANDLED; + if( card->wandev.enable_tx_int) + { + card->wandev.enable_tx_int = 0; + status->imask |= 0x2; + } + save_flags(host_cpu_flags); + cli(); + card->in_isr = 0; status->iflags = 0; /* clear interrupt condition */ + card->wandev.critical = 0; + restore_flags(host_cpu_flags); + + if(card->buff_int_mode_unbusy) + { + for(dev = card->wandev.dev; dev; dev = dev->slave) + { + if(((x25_channel_t*)dev->priv)->devtint) + { + dev_tint(dev); + } + } + } } /*============================================================================ @@ -812,6 +970,7 @@ } chan = dev->priv; + chan->i_timeout_sofar = jiffies; if (chan->drop_sequence) { if (!(qdm & 0x01)) chan->drop_sequence = 0; @@ -870,8 +1029,29 @@ } else { - netif_rx(skb); - ++chan->ifstats.rx_packets; + if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) + { + if( card->wandev.enable_IPX ) + { + if(chan_send(dev, skb)) + { + chan->tx_skb = skb; + } + else + { + dev_kfree_skb(skb, FREE_WRITE); + } + } + else + { + /* increment IPX packet dropped statistic */ + } + } + else + { + netif_rx(skb); + ++chan->ifstats.rx_packets; + } } } @@ -882,6 +1062,16 @@ */ static void tx_intr (sdla_t* card) { + struct device *dev; + + + /* unbusy all devices and then dev_tint(); */ + for(dev = card->wandev.dev; dev; dev = dev->slave) + { + ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; + dev->tbusy = 0; + } + } /*============================================================================ @@ -922,6 +1112,25 @@ */ static void wpx_poll (sdla_t* card) { + unsigned long host_cpu_flags; + + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + + if (set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: critical in polling!\n",card->devname); + + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && + (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return; + } + switch(card->wandev.state) { case WAN_CONNECTED: @@ -935,6 +1144,15 @@ case WAN_DISCONNECTED: poll_disconnected(card); } + + card->wandev.critical = 0; + + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + } /*============================================================================ @@ -948,7 +1166,8 @@ if (status->gflags & X25_HDLC_ABM) { wanpipe_set_state(card, WAN_CONNECTED); - x25_set_intr_mode(card, 0x81); /* enable Rx interrupts */ + x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ + status->imask &= ~0x2; /* mask Tx interupts */ } else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) disconnect(card) @@ -998,14 +1217,16 @@ /* If SVC has been idle long enough, close virtual circuit */ -/* - unsigned long flags; - - save_flags(flags); - cli(); - - restore_flags(flags); -*/ + if(( chan->svc )&&( chan->state == WAN_CONNECTED )) + { + if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ) + { + //Close svc + printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); + chan->i_timeout_sofar = jiffies; + chan_disc(dev); + } + } } } @@ -1644,7 +1865,10 @@ accept = 1; break; - case NLPID_SNAP: + case NLPID_SNAP: /* IPX datagrams */ + chan->protocol = ETH_P_IPX; + accept = 1; + break; default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X in incomming call " @@ -1853,8 +2077,8 @@ { x25_channel_t* chan = dev->priv; - set_chan_state(dev, WAN_DISCONNECTED); if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -1878,6 +2102,7 @@ card->devname, dev->name) ; *(unsigned short*)dev->dev_addr = htons(chan->lcn); + chan->i_timeout_sofar = jiffies; break; case WAN_CONNECTING: @@ -1941,6 +2166,7 @@ switch(x25_send(card, chan->lcn, qdm, len, skb->data)) { case 0x00: /* success */ + chan->i_timeout_sofar = jiffies; if (qdm) { skb_pull(skb, len); @@ -1954,6 +2180,7 @@ default: /* failure */ ++chan->ifstats.tx_errors; +/* return 1; */ } return 0; } @@ -2080,5 +2307,172 @@ } return val; } + + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) +{ + int i; + + if( proto == htons(ETH_P_IPX) ) { + /* It's an IPX packet */ + if(!enable_IPX) { + /* Return 1 so we don't pass it up the stack. */ + return 1; + } + } else { + /* It's not IPX so pass it up the stack. */ + return 0; + } + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + /* It's IPXWAN */ + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every */ + /* option except Unnumbered RIP/SAP */ + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + /* 0x02 is the option for Unnumbered RIP/SAP */ + if( sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + + /* Skip over the extended Node ID option */ + if( sendpacket[i] == 0x04 ) + { + i += 8; + } + + /* We also want to turn off all header compression opt. */ + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + /* Set the packet type to timer response */ + sendpacket[34] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + /* This is an information request packet */ + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + /* Set the packet type to information response */ + sendpacket[34] = 0x03; + + /* Set the router name */ + sendpacket[51] = 'X'; + sendpacket[52] = 'T'; + sendpacket[53] = 'P'; + sendpacket[54] = 'I'; + sendpacket[55] = 'P'; + sendpacket[56] = 'E'; + sendpacket[57] = '-'; + sendpacket[58] = CVHexToAscii(network_number >> 28); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); + for(i = 66; i < 99; i+= 1) + { + sendpacket[i] = 0; + } + + /* printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); */ + } + else + { + printk(KERN_WARNING "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + /* Set the WNodeID to our network address */ + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } else { + /* If we get here its an IPX-data packet, so it'll get passed up the stack. */ + + /* switch the network numbers */ + switch_net_numbers(sendpacket, network_number, 1); + return 0; + } +} + +/* + If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + if incoming is 1 - if the net number is 0 make it ours + +*/ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + + if (!incoming) { + /* If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } else { + /* If the incoming network is 0, make it ours */ + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) { + /* If the source network is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } else { + /* If the source network is 0, make it ours */ + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + /****** End *****************************************************************/ diff -u --recursive --new-file v2.1.78/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c --- v2.1.78/linux/drivers/net/sdlamain.c Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/sdlamain.c Mon Jan 12 14:46:16 1998 @@ -2,6 +2,7 @@ * sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. * * Author: Gene Kozin +* Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -10,6 +11,21 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 +* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); +* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 +* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr +* assignments are taken out and placed in the +* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr +* routines. Took out 'wandev->tx_int_enabled' and +* replaced it with 'wandev->enable_tx_int'. +* May 29, 1997 Jaspreet Singh Flow Control Problem +* added "wandev->tx_int_enabled=1" line in the +* init module. This line intializes the flag for +* preventing Interrupt disabled with device set to +* busy +* Jan 15, 1997 Gene Kozin Version 3.1.0 +* o added UDP management stuff * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ @@ -39,8 +55,8 @@ #define STATIC static #endif -#define DRV_VERSION 3 /* version number */ -#define DRV_RELEASE 0 /* release (minor version) number */ +#define DRV_VERSION 4 /* version number */ +#define DRV_RELEASE 1 /* release (minor version) number */ #define MAX_CARDS 8 /* max number of adapters */ #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ @@ -132,6 +148,7 @@ wandev->magic = ROUTER_MAGIC; wandev->name = card->devname; wandev->private = card; + wandev->enable_tx_int = 0; wandev->setup = &setup; wandev->shutdown = &shutdown; wandev->ioctl = &ioctl; @@ -388,7 +405,7 @@ /****** Driver IOCTL Hanlers ************************************************/ /*============================================================================ - * Dump adpater memory to user buffer. + * Dump adapter memory to user buffer. * o verify request structure * o copy request structure to kernel data space * o verify length/offset @@ -403,6 +420,7 @@ sdla_dump_t dump; unsigned winsize; unsigned long oldvec; /* DPM window vector */ + unsigned long flags; int err = 0; if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) @@ -413,6 +431,7 @@ return -EINVAL; winsize = card->hw.dpmsize; + save_flags(flags); cli(); /* >>> critical section start <<< */ oldvec = card->hw.vector; while (dump.length) @@ -438,7 +457,7 @@ (char*)dump.ptr += len; } sdla_mapmem(&card->hw, oldvec); /* restore DPM window position */ - sti(); /* >>> critical section end <<< */ + restore_flags(flags); /* >>> critical section end <<< */ return err; } @@ -483,10 +502,10 @@ ; return; } - card->in_isr = 1; + sdla_intack(&card->hw); - if (card->isr) card->isr(card); - card->in_isr = 0; + if (card->isr) + card->isr(card); #undef card } @@ -507,13 +526,13 @@ sdla_t* card = &card_array[i]; if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && - !test_and_set_bit(0, (void*)&card->wandev.critical)) + !card->wandev.critical) { card->poll(card); - card->wandev.critical = 0; } } - if (active) queue_task(&sdla_tq, &tq_scheduler); + if (active) + queue_task(&sdla_tq, &tq_scheduler); } /*============================================================================ diff -u --recursive --new-file v2.1.78/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.1.78/linux/drivers/net/sunlance.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/net/sunlance.c Mon Jan 12 15:28:18 1998 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.68 1997/08/15 06:44:36 davem Exp $ +/* $Id: sunlance.c,v 1.69 1998/01/09 16:42:52 jj Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -53,12 +53,15 @@ * * 1.10: * 1/26/97: Modularize driver. (ecd@skynet.be) + * + * 1.11: + * 12/27/97: Added sun4d support. (jj@sunsite.mff.cuni.cz) */ #undef DEBUG_DRIVER static char *version = - "sunlance.c:v1.10 26/Jan/97 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; + "sunlance.c:v1.11 27/Dec/97 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; static char *lancestr = "LANCE"; static char *lancedma = "LANCE DMA"; @@ -679,14 +682,25 @@ printk ("Lance: Can't get irq %d\n", dev->irq); return -EAGAIN; } + } +#else + if (sparc_cpu_model == sun4d) { + struct devid_cookie dcookie; - } else -#endif - if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ, + dcookie.real_dev_id = dev; + dcookie.bus_cookie = (void *)dev->base_addr; + if(request_irq(dev->irq, &lance_interrupt, + (SA_SHIRQ | SA_DCOOKIE), + lancestr, &dcookie)) { + printk ("Lance: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + } else if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ, lancestr, (void *) dev)) { printk ("Lance: Can't get irq %d\n", dev->irq); return -EAGAIN; } +#endif /* Stop the Lance */ ll->rap = LE_CSR0; diff -u --recursive --new-file v2.1.78/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.1.78/linux/drivers/net/tulip.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/tulip.c Mon Jan 12 15:28:18 1998 @@ -1,7 +1,7 @@ -/* tulip.c: A DEC 21040 ethernet driver for linux. */ +/* tulip.c: A DEC 21040-family ethernet driver for linux. */ /* - NOTICE: this version works with kernels 1.1.82 and later only! - Written 1994,1995 by Donald Becker. + NOTICE: THIS IS THE ALPHA TEST VERSION! + Written 1994-1997 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -13,47 +13,69 @@ Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - Subscribe to linux-tulip@cesdis.gsfc.nasa.gov and linux-tulip-bugs@cesdis.gsfc.nasa.gov - for late breaking news and exciting develovements. - - This has Baldur Norddahl's one liner fix for the AC/AE boards. If it - stops working please change TINTR_ENABLE to 0xFFFFFFFF + Support and updates available at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html */ -static char *version = -"tulip.c:v0.10 8/11/95 becker@cesdis.gsfc.nasa.gov\n" -" +0.72 4/17/96 " -"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n" -" +0.02 12/15/96 mjacob@feral.com (2.0.27)\n"; +static const char *version = "tulip.c:v0.83 10/19/97 becker@cesdis.gsfc.nasa.gov\n"; /* A few user-configurable values. */ -/* Default to using 10baseT (i.e. AUI/10base2/100baseT port) port. */ -#define TULIP_10TP_PORT 0 -#define TULIP_100TP_PORT 1 -#define TULIP_AUI_PORT 1 -#define TULIP_BNC_PORT 2 -#define TULIP_MAX_PORT 3 -#define TULIP_AUTO_PORT -1 +/* Used to pass the full-duplex flag, etc. */ +static int full_duplex[8] = {0, }; +static int options[8] = {0, }; +static int mtu[8] = {0, }; /* Jumbo MTU for interfaces. */ + +/* Set if the PCI BIOS detects the chips on a multiport board backwards. */ +#ifdef REVERSE_PROBE_ORDER +static int reverse_probe = 1; +#else +static int reverse_probe = 0; +#endif + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 16 + +/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ +#ifdef __alpha__ +static const rx_copybreak = 1518; +#else +static const rx_copybreak = 100; +#endif -#ifndef TULIP_PORT -#define TULIP_PORT TULIP_10TP_PORT +/* The following example shows how to always use the 10base2 port. */ +#ifdef notdef +#define TULIP_DEFAULT_MEDIA 1 /* 1 == 10base2 */ +#define TULIP_NO_MEDIA_SWITCH /* Don't switch from this port */ #endif /* Define to force full-duplex operation on all Tulip interfaces. */ /* #define TULIP_FULL_DUPLEX 1 */ -/* Define to fix port. */ -/* #define TULIP_FIX_PORT 1 */ - -/* Define to probe only first detected device */ -/*#define TULIP_MAX_CARDS 1*/ +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT ((2000*HZ)/1000) +#include +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif #include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif #include #include #include +#include #include #include #include @@ -61,9 +83,7 @@ #include #include #include -#include -#include -#include +#include /* Processor type for cache alignment. */ #include #include #include @@ -72,35 +92,116 @@ #include #include +/* Kernel compatibility defines, common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ +#include /* Evil, but neccessary */ + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300 +#define RUN_AT(x) (x) /* What to put in timer->expires. */ +#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC) +#define virt_to_bus(addr) ((unsigned long)addr) +#define bus_to_virt(addr) ((void*)addr) + +#else /* 1.3.0 and later */ +#define RUN_AT(x) (jiffies + (x)) +#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) +#endif + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338 +#ifdef MODULE +#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__) +char kernel_version[] = UTS_RELEASE; +#endif +#else +#undef MOD_INC_USE_COUNT +#define MOD_INC_USE_COUNT +#undef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif +#endif /* 1.3.38 */ + +#if (LINUX_VERSION_CODE >= 0x10344) +#define NEW_MULTICAST +#include +#endif +#if (LINUX_VERSION_CODE >= 0x20100) +char kernel_version[] = UTS_RELEASE; +#endif +#ifdef SA_SHIRQ +#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) +#else +#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs) +#endif + +#if (LINUX_VERSION_CODE < 0x20123) +#define test_and_set_bit(val, addr) set_bit(val, addr) +#endif + +/* This my implementation of shared IRQs, now only used for 1.2.13. */ +#ifdef HAVE_SHARED_IRQ +#define USE_SHARED_IRQ +#include +#endif + /* The total size is unusually large: The 21040 aligns each of its 16 longword-wide registers on a quadword boundary. */ #define TULIP_TOTAL_SIZE 0x80 +#ifdef HAVE_DEVLIST +struct netdev_entry tulip_drv = +{"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL}; +#endif + +#ifdef TULIP_DEBUG +int tulip_debug = TULIP_DEBUG; +#else +int tulip_debug = 1; +#endif + /* Theory of Operation I. Board Compatibility -This device driver is designed for the DECchip 21040 "Tulip", Digital's -single-chip ethernet controller for PCI, as used on the SMC EtherPower -ethernet adapter. It also works with boards based the 21041 (new/experimental) -and 21140 (10/100mbps). +This device driver is designed for the DECchip "Tulip", Digital's +single-chip ethernet controllers for PCI. Supported members of the family +are the 21040, 21041, 21140, 21140A and 21142. These chips are used on +many PCI boards including the SMC EtherPower series. II. Board-specific settings PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS should be set to assign the -PCI INTA signal to an otherwise unused system IRQ line. While it's -physically possible to shared PCI interrupt lines, the kernel doesn't -support it. +need to be set on the board. The system BIOS preferably should assign the +PCI INTA signal to an otherwise unused system IRQ line. +Note: Kernel versions earlier than 1.3.73 do not support shared PCI +interrupt lines. III. Driver operation IIIa. Ring buffers + The Tulip can use either ring buffers or lists of Tx and Rx descriptors. -The current driver uses a statically allocated Rx ring of descriptors and -buffers, and a list of the Tx buffers. +This driver uses statically allocated rings of Rx and Tx descriptors, set at +compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs +for the Rx ring buffers at open() time and passes the skb->data field to the +Tulip as receive data buffers. When an incoming frame is less than +RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is +copied to the new skbuff. When the incoming frame is larger, the skbuff is +passed directly up the protocol stack and replaced by a newly allocated +skbuff. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. For small frames the copying cost is negligible (esp. considering +that we are pre-loading the cache with immediately useful header +information). For large frames the copying cost is non-trivial, and the +larger copy might flush the cache of useful data. A subtle aspect of this +choice is that the Tulip only receives into longword aligned buffers, thus +the IP header at offset 14 isn't longword aligned for further processing. +Copied frames are put into the new skbuff at an offset of "+2", thus copying +has the beneficial effect of aligning the IP header and preloading the +cache. IIIC. Synchronization The driver runs as two independent, single-threaded flows of control. One @@ -124,659 +225,1468 @@ Thanks to Duke Kamstra of SMC for providing an EtherPower board. +IVb. References + +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") +http://www.national.com/pf/DP/DP83840.html + +IVc. Errata + The DEC databook doesn't document which Rx filter settings accept broadcast packets. Nor does it document how to configure the part to configure the serial subsystem for normal (vs. loopback) operation or how to have it autoswitch between internal 10baseT, SIA and AUI transceivers. -The databook claims that CSR13, CSR14, and CSR15 should each be the last -register of the set CSR12-15 written. Hmmm, now how is that possible? -*/ +The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last +register of the set CSR12-15 written. Hmmm, now how is that possible? */ + /* A few values that may be tweaked. */ -/* Keep the ring sizes a power of two for efficiency. */ -#define TX_RING_SIZE 4 -#define RX_RING_SIZE 4 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* This is a mysterious value that can be written to CSR11 in the 21040 - to detect a full-duplex frame. No one knows what it should be, but if - left at its default value some 10base2(!) packets trigger a - full-duplex-request interrupt. */ +/* This is a mysterious value that can be written to CSR11 in the 21040 (only) + to support a pre-NWay full-duplex signaling mechanism using short frames. + No one knows what it should be, but if left at its default value some + 10base2(!) packets trigger a full-duplex-request interrupt. */ #define FULL_DUPLEX_MAGIC 0x6969 +#ifndef PCI_VENDOR_ID_DEC /* Now defined in linux/pci.h */ +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_TULIP 0x0002 /* 21040. */ +#define PCI_DEVICE_ID_TULIP_FAST 0x0009 /* 21140. */ +#endif + +#ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS +#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 /* 21041. */ +#endif +#ifndef PCI_DEVICE_ID_DEC_TULIP_21142 +#define PCI_DEVICE_ID_DEC_TULIP_21142 0x0019 +#endif + +#ifndef PCI_VENDOR_ID_LITEON +#define PCI_VENDOR_ID_LITEON 0x11AD +#define PCI_DEVICE_ID_PNIC 0x0002 +#define PCI_DEVICE_ID_PNIC_X 0x0168 +#else +/* Now PCI_VENDOR_ID_LITEON is defined, but device IDs have different names */ +#define PCI_DEVICE_ID_PNIC PCI_DEVICE_ID_LITEON_LNE100TX +#define PCI_DEVICE_ID_PNIC_X 0x0168 +#endif + /* The rest of these values should never change. */ -#define PCI_DEVICE_ID_NONE 0xFFFF -#define ETHNAMSIZ 8 -#define ROUND_UP(size, n) ((size + n - 1) & ~(n - 1)) +static void tulip_timer(unsigned long data); + +/* A table describing the chip types. */ +static struct tulip_chip_table { + int device_id; + char *chip_name; + int flags; + void (*media_timer)(unsigned long data); +} tulip_tbl[] = { + { PCI_DEVICE_ID_DEC_TULIP, "Digital DS21040 Tulip", 0, tulip_timer }, + { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DS21041 Tulip", 0, tulip_timer }, + { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 0, tulip_timer }, + { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 0, tulip_timer }, + { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 0, tulip_timer }, + {0, 0, 0, 0}, +}; +/* This matches the table above. */ +enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, LC82C168}; + +static const char * const medianame[] = { + "10baseT", "10base2", "AUI", "100baseTx", + "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", + "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", +}; +/* A full-duplex map for above. */ +static const char media_fd[] = +{0,0,0,0, 0xff,0xff,0,0, 0xff,0,0xff,0x01, 0,0,0xff,0 }; +/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ +static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; +static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + +static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; +static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; /* Offsets to the Command and Status Registers, "CSRs". All accesses must be longword instructions and quadword aligned. */ enum tulip_offsets { - /* 21040 21041 21140 */ - CSR0=0, /* BUS mode */ - CSR1=0x08, /* TX poll demand */ - CSR2=0x10, /* RX poll demand */ - CSR3=0x18, /* RX ring base addr */ - CSR4=0x20, /* TX ring base addr */ - CSR5=0x28, /* Status */ - CSR6=0x30, /* Command mode */ - CSR7=0x38, /* Interrupt Mask */ - CSR8=0x40, /* Missed frame counter */ - CSR9=0x48, /* Eth.addrROM SROM mii SROM mii */ - CSR10=0x50, /* Diagn. boot ROM - */ - CSR11=0x58, /* Full duplex G.P. timer G.P. timer */ - CSR12=0x60, /* SIA status G.P. */ - CSR13=0x68, /* SIA connectivity - */ - CSR14=0x70, /* SIA TX/RX - */ - CSR15=0x78 /* SIA general watchdog */ + CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, + CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, + CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10, + RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, + TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, + TxIntr=0x01, }; -/* description of CSR0 bus mode register */ -#define TBMOD_RESERVED 0xfff80000 /* I don't know */ -#define TBMOD_RESET 0x00000001 -#define TBMOD_BIGENDIAN 0x00000080 -/* - Cache alignment bits 15:14 Burst length 13:8 - 0000 No alignment 0x00000000 unlimited 0800 8 longwords - 4000 8 longwords 0100 1 longword 1000 16 longwords - 8000 16 longwords 0200 2 longwords 2000 32 longwords - C000 32 longwords 0400 4 longwords -*/ -#define TBMOD_ALIGN0 0x00000000 /* no cache alignment */ -#define TBMOD_ALIGN8 0x00004000 /* 8 longwords */ -#define TBMOD_ALIGN16 0x00008000 -#define TBMOD_ALIGN32 (TBMOD_ALIGN8|TBMOD_ALIGN16) -#define TBMOD_BURST0 0x00000000 /* unlimited=rx buffer size */ -#define TBMOD_BURST1 0x00000100 /* 1 longwords */ -#define TBMOD_BURST2 0x00000200 -#define TBMOD_BURST4 0x00000400 -#define TBMOD_BURST8 0x00000800 -#define TBMOD_BURST16 0x00001000 -#define TBMOD_BURST32 0x00002000 - -/* description of CSR1 Tx poll demand register */ -/* description of CSR2 Rx poll demand register */ -#define TPOLL_START 0x00000001 /* ? */ -#define TPOLL_TRIGGER 0x00000000 /* ? */ - -/* description of CSR5 status register from de4x5.h */ -#define TSTAT_BUSERROR 0x03800000 -#define TSTAT_SYSERROR 0x00002000 -#define TSTAT_TxSTAT 0x00700000 -#define TSTAT_RxSTAT 0x000e0000 -#define TSTAT_LKFAIL 0x00001000 -#define TSTAT_NORINTR 0x00010000 /* Normal interrupt */ -#define TSTAT_ABNINTR 0x00008000 /* Abnormal interrupt */ -#define TSTAT_RxMISSED 0x00000100 /* Rx frame missed */ -#define TSTAT_RxUNABL 0x00000080 -#define TSTAT_RxINTR 0x00000040 -#define TSTAT_LKPASS 0x00000010 -#define TSTAT_TEXPIRED 0x00000800 /* Timer Expired */ -#define TSTAT_TxTOUT 0x00000008 -#define TSTAT_TxUNABL 0x00000004 -#define TSTAT_TxINTR 0x00000001 -#define TSTAT_CLEARINTR 0x0001ffff /* clear all interrupt sources */ - -/* description of CSR6 command mode register */ -#define TCMOD_SCRM 0x01000000 /* scrambler mode */ -#define TCMOD_PCS 0x00800000 /* PCS function */ -#define TCMOD_TxTHMODE 0x00400000 /* Tx threshold mode */ -#define TCMOD_SW100TP 0x00040000 /* 21140: 100MB */ -#define TCMOD_CAPTURE 0x00020000 /* capture effect */ -#define TCMOD_FULLDUPLEX 0x00000200 -#define TCMOD_TH128 0x00008000 /* 10 - 128 bytes threshold */ -#define TCMOD_TxSTART 0x00002000 -#define TCMOD_RxSTART 0x00000002 -#define TCMOD_ALLMCAST 0x00000080 /* pass all multicast */ -#define TCMOD_PROMISC 0x00000040 /* promisc */ -#define TCMOD_BOFFCOUNTER 0x00000020 /* backoff counter */ -#define TCMOD_INVFILTER 0x00000010 /* invert filtering */ -#define TCMOD_HONLYFILTER 0x00000004 /* hash only filtering */ -#define TCMOD_HPFILTER 0x00000001 /* hash/perfect Rx filtering */ -#define TCMOD_MODEMASK (TCMOD_ALLMCAST|TCMOD_PROMISC) -#define TCMOD_FILTERMASK (TCMOD_HONLYFILTER|TCMOD_HPFILTER|TCMOD_INVFILTER) -#define TCMOD_TRxSTART (TCMOD_TxSTART|TCMOD_RxSTART) -#define TCMOD_BASE (TCMOD_CAPTURE|TCMOD_BOFFCOUNTER) -#define TCMOD_10TP (TCMOD_TxTHMODE|TCMOD_BASE) -#define TCMOD_100TP (TCMOD_SCRM|TCMOD_PCS|TCMOD_SW100TP|TCMOD_BASE) -#define TCMOD_AUTO (TCMOD_SW100TP|TCMOD_TH128|TCMOD_10TP) - -/* description of CSR7 interrupt mask register */ -#define TINTR_ENABLE 0xFFFFBBFF -#define TINTR_DISABLE 0x00000000 - -/* description of CSR11 G.P. timer (21041/21140) register */ -#define TGEPT_COUNT 0x0001FFFF - -/* description of CSR12 SIA status(2104x)/GP(21140) register */ -#define TSIAS_CONERROR 0x00000002 /* connection error */ -#define TSIAS_LNKERROR 0x00000004 /* link error */ -#define TSIAS_ACTERROR 0x00000200 /* port Rx activity */ -#define TSIAS_RxACTIVE 0x00000100 /* port Rx activity */ - -#define TGEPR_LK10NG 0x00000080 /* 10Mbps N.G. (R) */ -#define TGEPR_LK100NG 0x00000040 /* 100Mbps N.G. (R) */ -#define TGEPR_DETECT 0x00000020 /* detect signal (R) */ -#define TGEPR_HALFDUPLEX 0x00000008 /* half duplex (W) */ -#define TGEPR_PHYLOOPBACK 0x00000004 /* PHY loopback (W) */ -#define TGEPR_FORCEALED 0x00000002 /* force activity LED on (W) */ -#define TGEPR_FORCE100 0x00000001 /* force 100Mbps mode */ - -/* description of CSR13 SIA connectivity register */ -#define TSIAC_OUTEN 0x0000e000 /* 21041: Output enable */ -#define TSIAC_SELED 0x00000f00 /* 21041: AUI or TP with LEDs */ -#define TSIAC_INEN 0x00001000 /* 21041: Input enable */ -#define TSIAC_NO10TP 0x00000008 /* 10baseT(0) or not(1) */ -#define TSIAC_CONFIG 0x00000004 /* Configuration */ -#define TSIAC_SWRESET 0x00000001 /* 21041: software reset */ -#define TSIAC_RESET 0x00000000 /* reset */ -#define TSIAC_C21041 (TSIAC_OUTEN|TSIAC_SELED|TSIAC_SWRESET) -#define TSIAC_C21040 TSIAC_CONFIG - -/* description of CSR14 SIA TX/RX register */ -#define TSIAX_NO10TP 0x0000f73d -#define TSIAX_10TP 0x0000ff3f - -/* description of CSR15 SIA general register */ -#define TSIAG_SWBNCAUI 0x00000008 /* BNC(0) or AUI(1) */ -#define TSIAG_BNC 0x00000006 -#define TSIAG_AUI (TSIAG_BNC|TSIAG_SWBNCAUI) -#define TSIAG_10TP 0x00000000 - -/* description of rx_ring.status */ -#define TRING_OWN 0x80000000 /* Owned by chip */ -#define TRING_CLEAR 0x00000000 /* clear */ -#define TRING_ERROR 0x00008000 /* error summary */ -#define TRING_ETxTO 0x00004000 /* Tx time out */ -#define TRING_ELCOLL 0x00000200 /* late collision */ -#define TRING_EFCOLL 0x00000100 /* fatal collision */ -#define TRING_ELCARR 0x00000800 /* carrier lost */ -#define TRING_ENCARR 0x00000400 /* no carrier */ -#define TRING_ENOHB 0x00000080 /* heartbeat fail */ -#define TRING_ELINK 0x00000004 /* link fail */ -#define TRING_EUFLOW 0x00000002 /* underflow */ - -#define TRING_ELEN 0x00004000 /* length error */ -#define TRING_FDESC 0x00000200 /* first descriptor */ -#define TRING_LDESC 0x00000100 /* last descriptor */ -#define TRING_ERUNT 0x00000800 /* runt frame */ -#define TRING_ELONG 0x00000080 /* frame too long */ -#define TRING_EWATCHDOG 0x00000010 /* receive watchdog */ -#define TRING_EDRBIT 0x00000004 /* dribble bit */ -#define TRING_ECRC 0x00000002 /* CRC error */ -#define TRING_EOVERFLOW 0x00000001 /* overflow */ - -#define TRING_RxDESCMASK (TRING_FDESC|TRING_LDESC) -#define TRING_RxLENGTH (TRING_ERUNT|TRING_ELONG|TRING_EWATCHDOG) -#define TRING_RxFRAME (TRING_EDRBIT) -#define TRING_RxCRC (TRING_ECRC) -#define TRING_RxFIFO (TRING_EOVERFLOW) -#define TRING_TxABORT (TRING_ETxTO|TRING_EFCOLL|TRING_ELINK) -#define TRING_TxCARR (TRING_ELCARR|TRING_ENCARR) -#define TRING_TxWINDOW (TRING_ELCOLL) -#define TRING_TxFIFO (TRING_EUFLOW) -#define TRING_TxHEARTBEAT (TRING_ENOHB) /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { s32 status; s32 length; - u32 buffer1, buffer2; /* We use only buffer 1. */ + u32 buffer1, buffer2; }; struct tulip_tx_desc { s32 status; s32 length; - u32 buffer1, buffer2; /* We use only buffer 1. */ + u32 buffer1, buffer2; /* We use only buffer 1. */ +}; + +struct medialeaf { + u8 type; + u8 media; + unsigned char *leafdata; +}; + +struct mediatable { + u16 defaultmedia; + u8 leafcount, csr12dir; /* General purpose pin directions. */ + unsigned has_mii:1; + struct medialeaf mleaf[0]; +}; + +struct mediainfo { + struct mediainfo *next; + int info_type; + int index; + struct non_mii { char media; unsigned char csr12val; char bitnum, flags;} non_mii; + unsigned char *info; }; struct tulip_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct device *next_module; struct tulip_rx_desc rx_ring[RX_RING_SIZE]; struct tulip_tx_desc tx_ring[TX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; - char rx_buffs[RX_RING_SIZE][PKT_BUF_SZ]; - /* temporary Rx buffers. */ + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + char *rx_buffs; /* Address of temporary Rx buffers. */ + u32 setup_frame[48]; /* Pseudo-Tx frame to init address table. */ + int chip_id; + int revision; +#if LINUX_VERSION_CODE > 0x20139 struct net_device_stats stats; - int setup_frame[48]; /* Pseudo-Tx frame to init address table. */ - void (*port_select)(struct device *dev); - int (*port_fail)(struct device *dev); - struct device *next_module; - char *signature; +#else + struct enet_statistics stats; +#endif + struct timer_list timer; /* Media selection timer. */ +#ifdef CONFIG_NET_HW_FLOWCONTROL + int fc_bit; +#endif unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int port_fix:1; /* Fix if_port to specified port. */ + unsigned int full_duplex_lock:1; + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + unsigned int csr6; /* Current CSR6 control settings. */ + unsigned char eeprom[128]; /* Serial EEPROM contents. */ + signed char phys[4]; /* MII device addresses. */ + struct mediatable *mtable; + int cur_index; /* Current media index. */ + unsigned char pci_bus, pci_device_fn; + int pad0, pad1; /* Used for 8-byte alignment */ }; -struct eeprom { - union { - struct { /* broken EEPROM structure */ - u_char addr[ETH_ALEN]; - } ng; - struct { /* DEC EtherWorks - and other cards which have correct eeprom structure */ - u_char dum1[20]; - u_char addr[ETH_ALEN]; - } ok; - } hw; -#define ng_addr hw.ng.addr -#define ok_addr hw.ok.addr -#define EE_SIGNLEN 14 /* should be 102 ? */ - u_char sign[EE_SIGNLEN]; -}; - -static int read_eeprom(unsigned long ioaddr, struct eeprom *eepp); +static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq, + int chip_id, int options); +static void parse_eeprom(struct device *dev); +static int read_eeprom(int ioaddr, int location); +static int mdio_read(int ioaddr, int phy_id, int location); +static void select_media(struct device *dev, int startup); static int tulip_open(struct device *dev); +static void tulip_timer(unsigned long data); +static void tulip_tx_timeout(struct device *dev); static void tulip_init_ring(struct device *dev); static int tulip_start_xmit(struct sk_buff *skb, struct device *dev); static int tulip_rx(struct device *dev); -static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs); static int tulip_close(struct device *dev); -static struct net_device_stats *tulip_get_stats(struct device *dev); +static struct enet_statistics *tulip_get_stats(struct device *dev); +#ifdef NEW_MULTICAST static void set_multicast_list(struct device *dev); +#else +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +#endif +#ifdef CONFIG_NET_FASTROUTE +#include +#include + +static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst); +#endif -#define generic21140_fail NULL -static void generic21040_select(struct device *dev); -static void generic21140_select(struct device *dev); -static void generic21041_select(struct device *dev); -static void auto21140_select(struct device *dev); -static void cogent21140_select(struct device *dev); -static int generic21040_fail(struct device *dev); -static int generic21041_fail(struct device *dev); + #ifdef MODULE /* A list of all installed Tulip devices, for removing the driver module. */ static struct device *root_tulip_dev = NULL; #endif -static struct { - void (*port_select)(struct device *dev); - int (*port_fail)(struct device *dev); - unsigned int vendor_id, device_id; - char *signature; - unsigned int array:1; -} cardVendor[] = { - {generic21140_select, generic21140_fail, - 0x0000c000, PCI_DEVICE_ID_DEC_TULIP_FAST, "smc9332", 0}, - {generic21041_select, generic21041_fail, - 0x0000c000, PCI_DEVICE_ID_DEC_TULIP_PLUS, "smc8432", 0}, - {generic21040_select, generic21040_fail, - 0x0000c000, PCI_DEVICE_ID_DEC_TULIP, "old smc8432", 0}, - {auto21140_select, generic21140_fail, - 0x0000f400, PCI_DEVICE_ID_DEC_TULIP_FAST, "LA100PCI", 0}, - {cogent21140_select, generic21140_fail, - 0x00009200, PCI_DEVICE_ID_DEC_TULIP_FAST, "cogent_em110", 0}, - {generic21040_select, generic21040_fail, - 0x00009200, PCI_DEVICE_ID_DEC_TULIP, "cogent_em96x", 1}, - {generic21140_select, generic21140_fail, - 0x0000f800, PCI_DEVICE_ID_DEC_TULIP_FAST, "DE500", 0}, - {generic21041_select, generic21041_fail, - 0x0000f800, PCI_DEVICE_ID_DEC_TULIP_PLUS, "DE450", 0}, - {generic21040_select, generic21040_fail, - 0x0000f800, PCI_DEVICE_ID_DEC_TULIP, "DE43x", 0}, - {generic21040_select, generic21040_fail, - 0x0040c700, PCI_DEVICE_ID_DEC_TULIP, "EN9400", 0}, - {generic21040_select, generic21040_fail, - 0x00c09500, PCI_DEVICE_ID_DEC_TULIP, "ZNYX312", 1}, - {generic21040_select, generic21040_fail, - 0x08002b00, PCI_DEVICE_ID_DEC_TULIP, "QSILVER's", 0}, - {generic21040_select, generic21040_fail, - 0, PCI_DEVICE_ID_DEC_TULIP, "21040", 0}, - {generic21140_select, generic21140_fail, - 0, PCI_DEVICE_ID_DEC_TULIP_FAST, "21140", 0}, - {generic21041_select, generic21041_fail, - 0, PCI_DEVICE_ID_DEC_TULIP_PLUS, "21041", 0}, - {NULL, NULL, 0, 0, "Unknown", 0} -}; +/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region, + but now receives directly into full-sized skbuffs that are allocated + at open() time. + This allows the probe routine to use the old driver initialization + interface. */ + +int tulip_probe(struct device *dev) +{ + int cards_found = 0; + static int pci_index = 0; /* Static, for multiple probe calls. */ + + /* Ideally we would detect all network cards in slot order. That would + be best done a central PCI probe dispatch, which wouldn't work + well with the current structure. So instead we detect just the + Tulip cards in slot order. */ + + if (pcibios_present()) { + unsigned char pci_bus, pci_device_fn; + + for (;pci_index < 0xff; pci_index++) { + unsigned char pci_irq_line, pci_latency; + unsigned short pci_command, vendor, device; + unsigned int pci_ioaddr, chip_idx = 0; + + if (pcibios_find_class + (PCI_CLASS_NETWORK_ETHERNET << 8, + reverse_probe ? 0xfe - pci_index : pci_index, + &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) + if (reverse_probe) + continue; + else + break; + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_DEVICE_ID, &device); + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + /* Remove I/O space marker in bit 0. */ + pci_ioaddr &= ~3; - -/* Serial EEPROM section. - A "bit" grungy, but we work our way through bit-by-bit :->. */ -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ -#define EE_CS 0x01 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 -#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ -#define EE_ENB (0x4800 | EE_CS) + if (vendor != PCI_VENDOR_ID_DEC + && vendor != PCI_VENDOR_ID_LITEON) + continue; + if (vendor == PCI_VENDOR_ID_LITEON) + device = PCI_DEVICE_ID_PNIC_X; -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) + for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++) + if (device == tulip_tbl[chip_idx].device_id) + break; + if (tulip_tbl[chip_idx].chip_name == 0) { + printk(KERN_INFO "Unknown Digital PCI ethernet chip type" + " %4.4x"" detected: not configured.\n", device); + continue; + } + if (tulip_debug > 2) + printk(KERN_DEBUG "Found DEC PCI Tulip at I/O %#x, IRQ %d.\n", + pci_ioaddr, pci_irq_line); + + if (check_region(pci_ioaddr, TULIP_TOTAL_SIZE)) + continue; #ifdef MODULE -static int if_port=TULIP_AUTO_PORT; -#ifdef TULIP_FULL_DUPLEX -static int full_duplex=1; + dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, + cards_found); #else -static int full_duplex=0; -#endif + dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, -1); #endif -#define tio_write(val, port) outl(val, ioaddr + port) -#define tio_read(port) inl(ioaddr + port) + if (dev) { + /* Get and check the bus-master and latency values. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + if ( ! (pci_command & PCI_COMMAND_MASTER)) { + printk(KERN_INFO " PCI Master Bit has not been set! Setting...\n"); + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, pci_command); + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 10) { + printk(KERN_INFO " PCI latency timer (CFLT) is unreasonably" + " low at %d. Setting to 64 clocks.\n", pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 64); + } else if (tulip_debug > 1) + printk(KERN_INFO " PCI latency timer (CFLT) is %#x.\n", + pci_latency); + /* Bring the 21143 out power-down mode. */ + if (device == PCI_DEVICE_ID_DEC_TULIP_21142) + pcibios_write_config_dword(pci_bus, pci_device_fn, + 0x40, 0x40000000); + dev = 0; + cards_found++; + } + } + } -static void inline -tio_sia_write(unsigned long ioaddr, u32 val13, u32 val14, u32 val15) -{ - tio_write(0,CSR13); - tio_write(val15,CSR15); - tio_write(val14,CSR14); - tio_write(val13,CSR13); + return cards_found ? 0 : -ENODEV; } -/* - card_type returns 1 if the card is 'etherarray' -*/ - -__initfunc(static int -card_type(struct tulip_private *tp, int device_id, int vendor_id)) +static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq, + int chip_id, int board_idx) { - int n; + static int did_version = 0; /* Already printed version info. */ + struct tulip_private *tp; + /* See note below on the multiport cards. */ + static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; + static int last_irq = 0; + int i; + unsigned short sum; - for (n = 0; cardVendor[n].device_id; n ++) - if (cardVendor[n].device_id == device_id - && (cardVendor[n].vendor_id == vendor_id - || cardVendor[n].vendor_id == 0)) break; - tp->port_select = cardVendor[n].port_select; - tp->port_fail = cardVendor[n].port_fail; - tp->signature = cardVendor[n].signature; - return(cardVendor[n].array ? 1: 0); -} - -__initfunc(static int -read_eeprom(unsigned long ioaddr, struct eeprom *eepp)) -{ - int i, n; - unsigned short val = 0; - int read_cmd = EE_READ_CMD; - u_char *p=(u_char *)eepp; - - for (n = 0; n < sizeof(struct eeprom) / 2; n ++, read_cmd ++) { - tio_write(EE_ENB & ~EE_CS, CSR9); - tio_write(EE_ENB, CSR9); - - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - tio_write(EE_ENB | dataval, CSR9); - udelay(100); - tio_write(EE_ENB | dataval | EE_SHIFT_CLK, CSR9); - udelay(150); - tio_write(EE_ENB | dataval, CSR9); - udelay(250); - } - tio_write(EE_ENB, CSR9); - - for (i = 16; i > 0; i--) { - tio_write(EE_ENB | EE_SHIFT_CLK, CSR9); - udelay(100); - val = (val << 1) - | ((tio_read(CSR9) & EE_DATA_READ) ? 1 : 0); - tio_write(EE_ENB, CSR9); - udelay(100); - } - - /* Terminate the EEPROM access. */ - tio_write(EE_ENB & ~EE_CS, CSR9); - *p ++ = le16_to_cpu(val); - *p ++ = le16_to_cpu(val) >> 8; - } - /* broken eeprom ? */ - p = (u_char *)eepp; - for (i = 0; i < 8; i ++) - if (p[i] != p[15 - i] || p[i] != p[16 + i]) return(0); - return(-1); /* broken */ -} + if (tulip_debug > 0 && did_version++ == 0) + printk(KERN_INFO "%s", version); -/* Is this required ? */ -static int -generic21040_fail(struct device *dev) -{ - unsigned long ioaddr = dev->base_addr; + dev = init_etherdev(dev, 0); - return(tio_read(CSR12) & TSIAS_CONERROR); -} + printk(KERN_INFO "%s: %s at %#3x,", + dev->name, tulip_tbl[chip_id].chip_name, ioaddr); -static int -generic21041_fail(struct device *dev) -{ - unsigned long ioaddr = dev->base_addr; - u32 csr12 = tio_read(CSR12); + /* Stop the chip's Tx and Rx processes. */ + outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); + /* Clear the missed-packet counter. */ + (volatile)inl(ioaddr + CSR8); - return((!(csr12 & TSIAS_CONERROR) - || !(csr12 & TSIAS_LNKERROR)) ? 0: 1); -} + if (chip_id == DC21041) { + if (inl(ioaddr + CSR9) & 0x8000) { + printk(" 21040 compatible mode,"); + chip_id = DC21040; + } else { + printk(" 21041 mode,"); + } + } -static void -generic21040_select(struct device *dev) -{ - unsigned long ioaddr = dev->base_addr; - const char *media; + /* The station address ROM is read byte serially. The register must + be polled, waiting for the value to be read bit serially from the + EEPROM. + */ + sum = 0; + if (chip_id == DC21040) { + outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ + for (i = 0; i < 6; i++) { + int value, boguscnt = 100000; + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + dev->dev_addr[i] = value; + sum += value & 0xff; + } + } else if (chip_id == LC82C168) { + for (i = 0; i < 3; i++) { + int value, boguscnt = 100000; + outl(0x600 | i, ioaddr + 0x98); + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + ((u16*)dev->dev_addr)[i] = value; + sum += value & 0xffff; + } + } else { /* Must be a new chip, with a serial EEPROM interface. */ + /* We read the whole EEPROM, and sort it out later. DEC has a + specification _Digital Semiconductor 21X4 Serial ROM Format_ + but early vendor boards just put the address in the first six + EEPROM locations. */ + unsigned char ee_data[128]; + int sa_offset = 0; + + for (i = 0; i < sizeof(ee_data)/2; i++) + ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i); + + /* Detect the simple EEPROM format by the duplicated station addr. */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + sa_offset = 20; + for (i = 0; i < 6; i ++) { + dev->dev_addr[i] = ee_data[i + sa_offset]; + sum += ee_data[i + sa_offset]; + } + } + /* Lite-On boards have the address byte-swapped. */ + if (dev->dev_addr[0] == 0xA0 && dev->dev_addr[1] == 0x00) + for (i = 0; i < 6; i+=2) { + char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[i+1]; + dev->dev_addr[i+1] = tmp; + } + /* On the Zynx 315 Etherarray and other multiport boards only the + first Tulip has an EEPROM. + The addresses of the subsequent ports are derived from the first. + Many PCI BIOSes also incorrectly report the IRQ line, so we correct + that here as well. */ + if (sum == 0 || sum == 6*0xff) { + printk(" EEPROM not present,"); + for (i = 0; i < 5; i++) + dev->dev_addr[i] = last_phys_addr[i]; + dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__i386) /* This BIOS bug doesn't exist on Alphas. */ + irq = last_irq; +#endif + } + for (i = 0; i < 6; i++) + printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]); + printk(", IRQ %d.\n", irq); + last_irq = irq; - dev->if_port &= 3; - switch (dev->if_port) - { - case TULIP_10TP_PORT: - media = "10baseT"; + /* We do a request_region() only to register /proc/ioports info. */ + request_region(ioaddr, TULIP_TOTAL_SIZE, tulip_tbl[chip_id].chip_name); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Make certain the data structures are quadword aligned. */ + tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7); + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + +#ifdef MODULE + tp->next_module = root_tulip_dev; + root_tulip_dev = dev; +#endif + + tp->chip_id = chip_id; + +#ifdef TULIP_FULL_DUPLEX + tp->full_duplex = 1; + tp->full_duplex_lock = 1; +#endif +#ifdef TULIP_DEFAULT_MEDIA + tp->default_port = TULIP_DEFAULT_MEDIA; +#endif +#ifdef TULIP_NO_MEDIA_SWITCH + tp->medialock = 1; +#endif + + /* The lower four bits are the media type. */ + if (board_idx >= 0) { + tp->full_duplex = (options[board_idx]&16) || full_duplex[board_idx]>0; + if (tp->full_duplex) + tp->full_duplex_lock = 1; + tp->default_port = options[board_idx] & 15; + if (tp->default_port) + tp->medialock = 1; + if (mtu[board_idx] > 0) + dev->mtu = mtu[board_idx]; + } + + /* This is logically part of probe1(), but too complex to write inline. */ + if (chip_id != DC21040 && chip_id != LC82C168) + parse_eeprom(dev); + + if (tp->mtable && tp->mtable->has_mii) { + int phy, phy_idx; + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = mdio_read(ioaddr, phy, 0); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + printk(KERN_INFO "%s: MII transceiver found at MDIO address %d.\n", + dev->name, phy); + } + } + if (phy_idx == 0) { + printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + tp->phys[0] = 1; + } + } + + /* The Tulip-specific entries in the device structure. */ + dev->open = &tulip_open; + dev->hard_start_xmit = &tulip_start_xmit; + dev->stop = &tulip_close; + dev->get_stats = &tulip_get_stats; +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &set_multicast_list; +#endif +#ifdef CONFIG_NET_FASTROUTE + dev->accept_fastpath = tulip_accept_fastpath; +#endif + + /* Reset the xcvr interface and turn on heartbeat. */ + switch (chip_id) { + case DC21041: + outl(0x00000000, ioaddr + CSR13); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ + outl(inl(ioaddr + CSR6) | 0x200, ioaddr + CSR6); + outl(0x0000EF05, ioaddr + CSR13); break; - case TULIP_AUI_PORT: - media = "AUI"; + case DC21140: case DC21142: + if (tp->mtable) + outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); break; - case TULIP_BNC_PORT: - media = "BNC"; + case DC21040: + outl(0x00000000, ioaddr + CSR13); + outl(0x00000004, ioaddr + CSR13); break; - default: - media = "unknown type"; + case LC82C168: + outl(0x33, ioaddr + CSR12); + outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ break; } - printk("%s: enabling %s port.\n", dev->name, media); - /* Set the full duplex match frame. */ - tio_write(FULL_DUPLEX_MAGIC, CSR11); - tio_write(TSIAC_RESET, CSR13); - /* Reset the serial interface */ - tio_write((dev->if_port ? TSIAC_NO10TP: 0) | TSIAC_C21040, CSR13); + + return dev; } + +/* Serial EEPROM section. */ +/* The main routine to parse the very complicated SROM structure. + Search www.digital.com for "21X4 SROM" to get details. + This code is very complex, and will require changes to support + additional cards, so I'll be verbose about what is going on. + */ + +/* Known cards that have old-style EEPROMs. */ +static struct fixups { + char *name; + unsigned char addr0, addr1, addr2; + u16 newtable[32]; /* Max length below. */ +} eeprom_fixups[] = { + {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f, + 0x0000, 0x009E, /* 10baseT */ + 0x0903, 0x006D, /* 100baseTx */ }}, + {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x013f, + 0x0103, 0x006D, /* 100baseTx */ }}, + {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }}, + {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F, + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + }}, + {0, 0, 0, 0, {}}}; + +static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", + "21142 non-MII PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; + +#define EEPROM_SIZE 128 +static void parse_eeprom(struct device *dev) +{ + /* The last media info list parsed, for multiport boards. */ + static struct mediatable *last_mediatable = NULL; + static unsigned char *last_ee_data = NULL; + static controller_index = 0; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned char *ee_data = tp->eeprom; + int i; -#if 0 -static void -generic_timer(struct device *dev, u32 count) -{ - unsigned long ioaddr = dev->base_addr; + tp->mtable = 0; + for (i = 0; i < EEPROM_SIZE/2; i++) + ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i); - tio_write(count, CSR11); - while (tio_read(CSR11) & TGEPT_COUNT); + /* Detect an old-style (SA only) EEPROM layout: + memcmp(eedata, eedata+16, 8). */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + break; + if (i >= 8) { + if (ee_data[0] == 0xff) { + if (last_mediatable) { + controller_index++; + printk(KERN_INFO "%s: Controller %d of multiport board.\n", + dev->name, controller_index); + tp->mtable = last_mediatable; + ee_data = last_ee_data; + goto subsequent_board; + } else + printk(KERN_INFO "%s: Missing EEPROM, this interface may " + "not work correctly!\n", + dev->name); + return; + } + /* Do a fix-up based on the vendor half of the station address prefix. */ + for (i = 0; eeprom_fixups[i].name; i++) { + if (dev->dev_addr[0] == eeprom_fixups[i].addr0 + && dev->dev_addr[1] == eeprom_fixups[i].addr1 + && dev->dev_addr[2] == eeprom_fixups[i].addr2) { + if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + i++; /* An Accton EN1207, not an outlaw Maxtech. */ + memcpy(ee_data + 26, eeprom_fixups[i].newtable, + sizeof(eeprom_fixups[i].newtable)); + printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" + " substitute media control info.\n", + dev->name, eeprom_fixups[i].name); + break; + } + } + if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ + printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n", + dev->name); + return; + } + } + if (tulip_debug > 1) { + printk(KERN_DEBUG "read_eeprom:"); + for (i = 0; i < 64; i++) { + printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ", + read_eeprom(ioaddr, i)); + } + printk("\n"); + } + + controller_index = 0; + if (ee_data[19] > 1) { /* Multiport board. */ + last_ee_data = ee_data; + } +subsequent_board: + + if (tp->chip_id == DC21041) { + unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; + short media = *(u16 *)p; + int count = p[2]; + + printk(KERN_INFO "%s:21041 Media information at %d, default media " + "%4.4x (%s).\n", dev->name, ee_data[27], media, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + unsigned char media_code = p[3 + i*7]; + u16 *csrvals = (u16 *)&p[3 + i*7 + 1]; + printk(KERN_INFO "%s: 21041 media %2.2x (%s)," + " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n", + dev->name, media_code & 15, medianame[media_code & 15], + csrvals[0], csrvals[1], csrvals[2]); + } + } else { + unsigned char *p = (void *)ee_data + ee_data[27]; + unsigned char csr12dir = 0; + int count; + struct mediatable *mtable; + u16 media = *((u16 *)p)++; + + if (tp->chip_id == DC21140) + csr12dir = *p++; + count = *p++; + mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), + GFP_KERNEL); + if (mtable == NULL) + return; /* Horrible, impossible failure. */ + last_mediatable = tp->mtable = mtable; + mtable->defaultmedia = media; + mtable->leafcount = count; + mtable->csr12dir = csr12dir; + mtable->has_mii = 0; + + printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + struct medialeaf *leaf = &mtable->mleaf[i]; + + if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ + leaf->type = 0; + leaf->media = p[0] & 0x3f; + leaf->leafdata = p; + p += 4; + } else { + leaf->type = p[1]; + if (p[1] & 1) { + mtable->has_mii = 1; + leaf->media = 11; + } else + leaf->media = p[2] & 0x0f; + leaf->leafdata = p + 2; + p += (p[0] & 0x3f) + 1; + } + if (tulip_debug > 1 && leaf->media == 11) { + unsigned char *bp = leaf->leafdata; + printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " + "sequences %d/%d long, capabilities %2.2x %2.2x.\n", + dev->name, bp[0], bp[1], bp[1 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + } + printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", + dev->name, i, medianame[leaf->media], leaf->media, + block_name[leaf->type], leaf->type); + } + } } +/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + The 1.2 code is a "nasty" timing loop, but PC compatible machines are + *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */ +#ifdef _LINUX_DELAY_H +#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000) +#else +#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) #endif -static void -generic21041_select(struct device *dev) +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +static int read_eeprom(int ioaddr, int location) { - unsigned long ioaddr = dev->base_addr; - u32 tsiac = TSIAC_C21041; - u32 tsiax = TSIAX_10TP; - u32 tsiag = TSIAG_10TP; - - switch(dev->if_port) { - case TULIP_AUI_PORT: - tsiac |= TSIAC_NO10TP; - tsiax = TSIAX_NO10TP; - tsiag = TSIAG_AUI; - break; - case TULIP_BNC_PORT: - tsiac |= TSIAC_NO10TP; - tsiax = TSIAX_NO10TP; - tsiag = TSIAG_BNC; - break; - default: - dev->if_port = TULIP_10TP_PORT; - break; + int i; + unsigned short retval = 0; + int ee_addr = ioaddr + CSR9; + int read_cmd = location | EE_READ_CMD; + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(100); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(150); + outl(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ + eeprom_delay(250); } - tio_sia_write(ioaddr, tsiac, tsiax, tsiag); - if (dev->start) - printk("%s: enabling %s port.\n", dev->name, - (dev->if_port == TULIP_AUI_PORT) ? "AUI": - (dev->if_port == TULIP_BNC_PORT) ? "BNC": "10TP"); -} + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(100); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(100); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 +#ifdef _LINUX_DELAY_H +#define mdio_delay() udelay(1) +#else +#define mdio_delay() __SLOW_DOWN_IO +#endif -static void -auto21140_select(struct device *dev) +static int mdio_read(int ioaddr, int phy_id, int location) { int i; - unsigned long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - - /* kick port */ - tio_write(TPOLL_TRIGGER, CSR1); - tio_write(TINTR_ENABLE, CSR7); - tio_write(TCMOD_AUTO|TCMOD_TRxSTART, CSR6); - dev->if_port = !(tio_read(CSR12) & TGEPR_FORCEALED); - printk("%s: probed %s port.\n", - dev->name, dev->if_port ? "100TX" : "10TP"); - tio_write((dev->if_port ? TGEPR_FORCE100: 0) - | (tp->full_duplex ? 0:TGEPR_HALFDUPLEX), CSR12); - tio_write(TINTR_DISABLE, CSR7); - i = tio_read(CSR8) & 0xffff; - tio_write(TCMOD_AUTO, CSR6); + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + unsigned short retval = 0; + int mdio_addr = ioaddr + CSR9; + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the read command bits out. */ + for (i = 17; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + + outl(dataval, mdio_addr); + mdio_delay(); + outl(dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + outl(dataval, mdio_addr); + mdio_delay(); + } + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN, mdio_addr); + + for (i = 16; i > 0; i--) { + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 16; i > 0; i--) { + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + } + return retval; } -static void -cogent21140_select(struct device *dev) -{ - unsigned long ioaddr = dev->base_addr, csr6; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - dev->if_port &= 1; - csr6 = tio_read(CSR6) & - ~(TCMOD_10TP|TCMOD_100TP|TCMOD_TRxSTART|TCMOD_SCRM); - /* Stop the transmit process. */ - tio_write(csr6 | TCMOD_RxSTART, CSR6); - printk("%s: enabling %s port.\n", - dev->name, dev->if_port ? "100baseTx" : "10baseT"); - /* Turn on the output drivers */ - tio_write(0x0000013F, CSR12); - tio_write((dev->if_port ? TGEPR_FORCE100: 0) - | (tp->full_duplex ? 0:TGEPR_HALFDUPLEX), CSR12); - tio_write((dev->if_port ? TCMOD_100TP: TCMOD_10TP) - | TCMOD_TRxSTART | TCMOD_TH128 | csr6, CSR6); -} +#ifdef CONFIG_NET_HW_FLOWCONTROL +/* Enable receiver */ -static void -generic21140_select(struct device *dev) +void tulip_xon(struct device *dev) { - unsigned long ioaddr = dev->base_addr, csr6; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - - dev->if_port &= 1; - csr6 = tio_read(CSR6) & - ~(TCMOD_10TP|TCMOD_100TP|TCMOD_TRxSTART|TCMOD_SCRM); + struct tulip_private *lp = (struct tulip_private *)dev->priv; - /* Stop the transmit process. */ - tio_write(csr6 | TCMOD_RxSTART, CSR6); + clear_bit(lp->fc_bit, &netdev_fc_xoff); if (dev->start) - printk("%s: enabling %s port.\n", - dev->name, dev->if_port ? "100TX" : "10TP"); - tio_write((dev->if_port ? TCMOD_100TP: TCMOD_10TP) - | TCMOD_TRxSTART | TCMOD_TH128 | csr6, CSR6); - tio_write((dev->if_port ? TGEPR_FORCE100: 0) - | (tp->full_duplex ? 0:TGEPR_HALFDUPLEX), CSR12); + outl(lp->csr6 | 0x2002, dev->base_addr + CSR6); } +#endif + static int tulip_open(struct device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; - unsigned long ioaddr = dev->base_addr; - int i; + int ioaddr = dev->base_addr; + int i = 0; - /* Reset the chip, holding bit 0 set at least 10 PCI cycles. */ - tio_write(tio_read(CSR0)|TBMOD_RESET, CSR0); - udelay(1000); - /* Deassert reset. Set 8 longword cache alignment, 8 longword burst. - -> Set 32 longword cache alignment, unlimited longword burst ? + /* On some chip revs we must set the MII/SYM port before the reset!? */ + if (tp->mtable && tp->mtable->has_mii) + outl(0x00040000, ioaddr + CSR6); + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + outl(0x00000001, ioaddr + CSR0); +#ifdef _LINUX_DELAY_H + udelay(2); +#else + SLOW_DOWN_IO; +#endif + /* Deassert reset. + 486: Set 8 longword cache alignment, 8 longword burst. + 586: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 No alignment 0x00000000 unlimited 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. */ - tio_write(tio_read(CSR0)|TBMOD_ALIGN32|TBMOD_BURST0, CSR0); +#if defined(__alpha__) + /* ToDo: Alpha setting could be better. */ + outl(0x00200000 | 0xE000, ioaddr + CSR0); +#elif defined(__powerpc__) + outl(0x00200080 | 0x8000, ioaddr + CSR0); +#elif defined(__i386) +#if defined(MODULE) + /* When a module we don't have 'x86' to check. */ + outl(0x00200000 | 0x4800, ioaddr + CSR0); +#else +#ifndef ORIGINAL_TEXT +#ifndef __SMP__ +#define x86 ((struct cpuinfo_x86*)cpu_data)->x86 +#else +#error What should we make here? +#endif +#endif + outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0); + if (x86 <= 4) + printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " + "alignment to %x.\n", dev->name, + 0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000)); +#endif +#else + outl(0x00200000 | 0x4800, ioaddr + CSR0); +#warning Processor architecture undefined! +#endif - if (request_irq(dev->irq, (void *)&tulip_interrupt, SA_SHIRQ, - tp->signature, dev)) +#ifdef SA_SHIRQ + if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, + tulip_tbl[tp->chip_id].chip_name, dev)) { return -EAGAIN; + } +#else + if (irq2dev_map[dev->irq] != NULL + || (irq2dev_map[dev->irq] = dev) == NULL + || dev->irq == 0 + || request_irq(dev->irq, &tulip_interrupt, 0, + tulip_tbl[tp->chip_id].chip_name)) { + return -EAGAIN; + } +#endif + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); + + MOD_INC_USE_COUNT; tulip_init_ring(dev); + /* This is set_rx_mode(), but without starting the transmitter. */ /* Fill the whole address filter table with our physical address. */ - { - unsigned short *eaddrs = (unsigned short *)dev->dev_addr; - int *setup_frm = tp->setup_frame, i; + { + u16 *eaddrs = (u16 *)dev->dev_addr; + u32 *setup_frm = tp->setup_frame, i; /* You must add the broadcast address when doing perfect filtering! */ - *setup_frm++ = cpu_to_le32(0xffff); - *setup_frm++ = cpu_to_le32(0xffff); - *setup_frm++ = cpu_to_le32(0xffff); + *setup_frm++ = 0xffff; + *setup_frm++ = 0xffff; + *setup_frm++ = 0xffff; /* Fill the rest of the accept table with our physical address. */ for (i = 1; i < 16; i++) { - *setup_frm++ = cpu_to_le32(eaddrs[0]); - *setup_frm++ = cpu_to_le32(eaddrs[1]); - *setup_frm++ = cpu_to_le32(eaddrs[2]); + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; + } + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].length = 0x08000000 | 192; + tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[0].status = 0x80000000; + + tp->cur_tx++; + } + + outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); + outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); + + if (dev->if_port == 0) + dev->if_port = tp->default_port; + if (tp->chip_id == DC21041 && dev->if_port > 4) + /* Invalid: Select initial TP, autosense, autonegotiate. */ + dev->if_port = 4; + + /* Allow selecting a default media. */ + if (tp->mtable == NULL) + goto media_picked; + if (dev->if_port) + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == + (dev->if_port == 12 ? 0 : dev->if_port)) { + printk(KERN_INFO "%s: Using user-specified media %s.\n", + dev->name, medianame[dev->if_port]); + goto media_picked; + } + if ((tp->mtable->defaultmedia & 0x0800) == 0) + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) { + printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", + dev->name, medianame[tp->mtable->mleaf[i].media]); + goto media_picked; + } + for (i = tp->mtable->leafcount - 1; + (media_fd[tp->mtable->mleaf[i].media] & 2) && i > 0; i--) + ; +media_picked: + + tp->cur_index = i; + tp->csr6 = 0; + select_media(dev, 1); + + /* Start the chip's Tx to process setup frame. */ + outl(tp->csr6, ioaddr + CSR6); + outl(tp->csr6 | 0x2000, ioaddr + CSR6); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + + /* Enable interrupts by setting the interrupt mask. */ + outl(0x0001ebef, ioaddr + CSR7); + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl(0, ioaddr + CSR2); /* Rx poll demand */ + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR13 %8.8x.\n", + dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), + inl(ioaddr + CSR13)); + } + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + tp->timer.data = (unsigned long)dev; + tp->timer.function = &tulip_timer; /* timer handler */ + add_timer(&tp->timer); + +#ifdef CONFIG_NET_HW_FLOWCONTROL + tp->fc_bit = netdev_register_fc(dev, tulip_xon); +#endif +#ifdef CONFIG_NET_FASTROUTE + dev->tx_semaphore = 1; +#endif + return 0; +} + +/* Set up the transceiver control registers for the selected media type. */ +static void select_media(struct device *dev, int startup) +{ + int ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct mediatable *mtable = tp->mtable; + u32 new_csr6; + int check_mii =0, i; + + if (mtable) { + struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; + unsigned char *p = mleaf->leafdata; + switch (mleaf->type) { + case 0: /* 21140 non-MII xcvr. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control" + " setting %2.2x.\n", + dev->name, p[1]); + dev->if_port = p[0]; + if (startup) + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + outl(p[1], ioaddr + CSR12); + new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); + break; + case 1: + if (startup) { + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + dev->if_port = 11; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Doing a reset sequence of length %d.\n", + dev->name, p[2 + p[1]]); + for (i = 0; i < p[2 + p[1]]; i++) + outl(p[3 + p[1] + i], ioaddr + CSR12); + if (tulip_debug > 2) + printk(KERN_DEBUG "%s Doing a transceiver setup sequence of length %d.\n", + dev->name, p[1]); + for (i = 0; i < p[1]; i++) + outl(p[2 + i], ioaddr + CSR12); + } + check_mii = 1; + new_csr6 = 0x020C0000; + break; + case 2: case 4: { + u16 *setup = (u16*)&p[1]; + dev->if_port = p[0] & 15; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n", + dev->name, medianame[dev->if_port], setup[0], setup[1]); + if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ + outl(0, ioaddr + CSR13); + outl(setup[1], ioaddr + CSR14); + outl(setup[2], ioaddr + CSR15); + outl(setup[0], ioaddr + CSR13); + setup += 3; + } else { + outl(0, ioaddr + CSR13); + outl(t21142_csr14[dev->if_port], ioaddr + CSR14); + outl(t21142_csr15[dev->if_port], ioaddr + CSR15); + outl(t21142_csr13[dev->if_port], ioaddr + CSR13); + } + outl(setup[0]<<16, ioaddr + CSR15); /* Direction */ + outl(setup[1]<<16, ioaddr + CSR15); /* Data */ + if (mleaf->type == 4) + new_csr6 = 0x02000000 | ((setup[2] & 0x71) << 18); + else + new_csr6 = 0x82420000; + break; + } + case 3: { + int init_length = p[1]; + u16 * init_sequence = (u16*)(p + 2); + int reset_length = p[2 + init_length*2]; + u16 * reset_sequence = (u16*)&p[3 + init_length*2]; + + dev->if_port = 11; + if (startup) { + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Doing a 21142 reset sequence of length %d.\n", + dev->name, reset_length); + for (i = 0; i < reset_length; i++) + outl(reset_sequence[i] << 16, ioaddr + CSR15); + } + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Doing a 21142 xcvr setup sequence of length %d.\n", + dev->name, init_length); + for (i = 0; i < init_length; i++) + outl(init_sequence[i] << 16, ioaddr + CSR15); + check_mii = 1; + new_csr6 = 0x020C0000; + break; + } + default: + new_csr6 = 0x020C0000; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12) & 0xff); + } else if (tp->chip_id == DC21140) { + /* Set media type to MII @ 100mbps: 0x020C0000 */ + new_csr6 = 0x020C0000; + dev->if_port = 11; + if (tulip_debug > 1) { + printk(KERN_DEBUG "%s: Unknown media control, assuming MII, CSR12 %2.2x.\n", + dev->name, inl(ioaddr + CSR12) & 0xff); } - /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); - tp->tx_ring[0].buffer1 = cpu_to_le32(virt_to_bus(tp->setup_frame)); - tp->tx_ring[0].buffer2 = cpu_to_le32(0); - tp->tx_ring[0].status = cpu_to_le32(TRING_OWN); - barrier(); - tp->cur_tx++, tp->dirty_tx++; + } else if (tp->chip_id == DC21041) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", + dev->name, medianame[dev->if_port & 15], + inl(ioaddr + CSR12) & 0xffff); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + new_csr6 = 0x80020000; + } else if (tp->chip_id == LC82C168) { + if (startup) + dev->if_port = 3; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: LiteOn PHY status is %3.3x, CSR12 %4.4x," + " media %s.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12), + medianame[dev->if_port]); + if (dev->if_port == 3 || dev->if_port == 5) { + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + if (startup) + outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */ + else + outl(0x1F868, ioaddr + 0xB8); + } else { + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + } else { /* 21040 */ + /* Turn on the xcvr interface. */ + int csr12 = inl(ioaddr + CSR12); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", + dev->name, dev->if_port ? "AUI" : "10baseT", csr12); + new_csr6 = (dev->if_port ? 0x01860000 : 0x00420000); + /* Set the full duplux match frame. */ + outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13); } - tio_write(virt_to_bus(tp->rx_ring), CSR3); - tio_write(virt_to_bus(tp->tx_ring), CSR4); + tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); + return; +} - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - /* - * process setup frame completely prior to fiddling with media. - */ - tio_write((tio_read(CSR6) & ~TCMOD_PROMISC) | TCMOD_TxSTART, CSR6); - tio_write(TPOLL_TRIGGER, CSR1); - sti(); - for (i = 0; i < 1000; i++) { - if (((s32)le32_to_cpu(tp->tx_ring[0].status)) >= 0) { +static void tulip_timer(unsigned long data) +{ + struct device *dev = (struct device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int ioaddr = dev->base_addr; + u32 csr12 = inl(ioaddr + CSR12); + int next_tick = 0; + + if (tulip_debug > 3) { + printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x " + "SIA %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6), + csr12, inl(ioaddr + CSR13), + inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + } + switch (tp->chip_id) { + case DC21040: + if (csr12 & 0x0002) { /* Network error */ + printk(KERN_INFO "%s: No 10baseT link beat found, switching to %s media.\n", + dev->name, dev->if_port ? "10baseT" : "AUI"); + dev->if_port ^= 1; + outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13); + dev->trans_start = jiffies; + } + break; + case DC21041: + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", + dev->name, csr12); + switch (dev->if_port) { + case 0: case 3: case 4: + if (csr12 & 0x0004) { /*LnkFail */ + /* 10baseT is dead. Check for activity on alternate port. */ + tp->mediasense = 1; + if (csr12 & 0x0200) + dev->if_port = 2; + else + dev->if_port = 1; + printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", + dev->name, medianame[dev->if_port]); + outl(0, ioaddr + CSR13); /* Reset */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + next_tick = 10*HZ; /* 2.4 sec. */ + } else + next_tick = 30*HZ; + break; + case 1: /* 10base2 */ + case 2: /* AUI */ + if (csr12 & 0x0100) { + next_tick = (30*HZ); /* 30 sec. */ + tp->mediasense = 0; + } else if ((csr12 & 0x0004) == 0) { + printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", dev->name); + dev->if_port = 0; + select_media(dev, 0); + next_tick = (24*HZ)/10; /* 2.4 sec. */ + } else if (tp->mediasense || (csr12 & 0x0002)) { + dev->if_port = 3 - dev->if_port; /* Swap ports. */ + select_media(dev, 0); + next_tick = 20*HZ; + } else { + next_tick = 20*HZ; + } + break; + } + break; + case LC82C168: { + int phy_reg = inl(ioaddr + 0xB8); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n", + dev->name, phy_reg, inl(ioaddr + CSR5)); + if (phy_reg & 0x04000000) { /* Remote link fault */ + outl(0x0201F078, ioaddr + 0xB8); + next_tick = (24*HZ)/10; + } else + next_tick = 10*HZ; + if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " + "CSR5 %8.8x, PHY %3.3x.\n", + dev->name, medianame[dev->if_port], csr12, + inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); + if (dev->if_port == 0) { + dev->if_port = 3; + } else + dev->if_port = 0; + next_tick = (24*HZ)/10; + select_media(dev, 0); + outl(tp->csr6 | 0x0002, ioaddr + CSR6); + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + dev->trans_start = jiffies; + } + break; + } + case DC21140: case DC21142: { + struct medialeaf *mleaf; + unsigned char *p; + if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ + /* Assume this is like a SMC card, and check its link beat bit. */ + if ((dev->if_port == 0 && (csr12 & 0x0080)) || + (dev->if_port == 1 && (csr12 & 0x0040) == 0)) { + dev->if_port ^= 1; + /* Stop the transmit process. */ + tp->csr6 = (dev->if_port ? 0x03860000 : 0x02420000); + outl(tp->csr6 | 0x0002, ioaddr + CSR6); + printk(KERN_INFO "%s: link beat timed out, CSR12 is 0x%2.2x, switching to" + " %s media.\n", dev->name, + csr12 & 0xff, + dev->if_port ? "100baseTx" : "10baseT"); + outl(tp->csr6 | 0xA002, ioaddr + CSR6); + dev->trans_start = jiffies; + next_tick = (24*HZ)/10; + } else { + next_tick = 10*HZ; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: network media monitor 0x%2.2x, link" + " beat detected as %s.\n", dev->name, + csr12 & 0xff, + dev->if_port ? "100baseTx" : "10baseT"); + } break; } - udelay(1000); + mleaf = &tp->mtable->mleaf[tp->cur_index]; + p = mleaf->leafdata; + switch (mleaf->type) { + case 0: case 4: { + /* Type 0 non-MII or #4 SYM transceiver. Check the link beat bit. */ + s8 bitnum = p[mleaf->type == 4 ? 5 : 2]; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is" + " %d, expecting %d.\n", + dev->name, csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); + /* Check that the specified bit has the proper value. */ + if ((bitnum < 0) != + ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, + medianame[mleaf->media]); + break; + } + if (tp->medialock) + break; + select_next_media: + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + dev->if_port = tp->mtable->mleaf[tp->cur_index].media; + if (media_fd[dev->if_port]) + goto select_next_media; /* Skip FD entries. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No link beat on media %s," + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & 15], + medianame[tp->mtable->mleaf[tp->cur_index].media]); + select_media(dev, 0); + /* Restart the transmit process. */ + outl(tp->csr6 | 0x0002, ioaddr + CSR6); + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + next_tick = (24*HZ)/10; + break; + } + case 1: case 3: /* 21140, 21142 MII */ + { + int mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1); + int mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5); + printk(KERN_INFO "%s: MII monitoring tick: CSR12 %2.2x, " + "MII status %4.4x, Link partner report %4.4x.\n", + dev->name, csr12, mii_reg1, mii_reg5); +#ifdef notdef + if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0) + goto select_next_media; +#else + if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0) + printk(KERN_INFO "%s: No link beat on the MII interface, " + "status then %4.4x now %4.4x.\n", + dev->name, mii_reg1, + mdio_read(ioaddr, tp->phys[0], 1)); +#endif + if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) + ; /* No MII device or no link partner report */ + else if (tp->full_duplex_lock) + ; + else if ((mii_reg5 & 0x0100) != 0 + || (mii_reg5 & 0x00C0) == 0x0040) { + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + if (tp->full_duplex == 0) { + tp->full_duplex = 1; + tp->csr6 |= 0x0200; + outl(tp->csr6 | 0x0002, ioaddr + CSR6); + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + } + if (tulip_debug > 0) /* Gurppp, should be >1 */ + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + " Xcvr #%d parter capability of %4.4x.\n", + dev->name, full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + } + } + break; + case 2: /* 21142 serial block has no link beat. */ + default: + break; + } + } + break; + default: /* Invalid chip type. */ + break; + } + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); } - if (i == 500) { - printk("%s: initial setup frame didn't complete.\n", dev->name); - dev->start = 0; - dev->tbusy = 1; - tio_write(TINTR_DISABLE, CSR7); - tio_write(tio_read(CSR6) & ~(TCMOD_TRxSTART), CSR6); - tio_write(TSIAC_CONFIG, CSR13); - tio_write(0, CSR13); - free_irq(dev->irq, dev); - return (-EIO); - } - /* - * Whack the chip to stop it and *then* do initial media setup. - */ - tio_write((tio_read(CSR6) & ~(TCMOD_PROMISC|TCMOD_TxSTART)), CSR6); - if (tp->port_select) - tp->port_select(dev); - /* Start the chip's Tx and Rx processes. */ - tio_write(tio_read(CSR6) | TCMOD_TRxSTART - | (tp->full_duplex ? TCMOD_FULLDUPLEX:0), CSR6); - /* Enable interrupts by setting the interrupt mask. */ - tio_write(TINTR_ENABLE, CSR7); +} - MOD_INC_USE_COUNT; - return 0; +static void tulip_tx_timeout(struct device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int ioaddr = dev->base_addr; + + if (tp->mtable && tp->mtable->has_mii) { + /* Do nothing -- the media monitor should handle this. */ + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", + dev->name); + } else if (tp->chip_id == DC21040) { + if (inl(ioaddr + CSR12) & 0x0002) { + printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n", + dev->name, dev->if_port ? "10baseT" : "AUI"); + dev->if_port ^= 1; + outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13); + } + dev->trans_start = jiffies; + return; + } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142) { + /* Stop the transmit process. */ + outl(tp->csr6 | 0x0002, ioaddr + CSR6); + dev->if_port ^= 1; + printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " + "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), + inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n", + dev->name, dev->if_port ? "100baseTx" : "10baseT"); + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + tp->stats.tx_errors++; + dev->trans_start = jiffies; + return; + } else if (tp->chip_id == DC21041) { + u32 csr12 = inl(ioaddr + CSR12); + + printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x," + " CSR13 %8.8x, CSR14 %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), csr12, + inl(ioaddr + CSR13), inl(ioaddr + CSR14)); + tp->mediasense = 1; + if (dev->if_port == 1 || dev->if_port == 2) + if (csr12 & 0x0004) { + dev->if_port = 2 - dev->if_port; + } else + dev->if_port = 0; + else + dev->if_port = 1; + select_media(dev, 0); + tp->stats.tx_errors++; + dev->trans_start = jiffies; + return; + } else + printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x," + " resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); +#ifdef way_too_many_messages + printk(" Rx ring %8.8x: ", (int)tp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); + printk("\n Tx ring %8.8x: ", (int)tp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); + printk("\n"); +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + outl(tp->csr6 | 0x0002, ioaddr + CSR6); + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + dev->trans_start = jiffies; + tp->stats.tx_errors++; + return; } + /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void tulip_init_ring(struct device *dev) @@ -789,76 +1699,73 @@ tp->dirty_rx = tp->dirty_tx = 0; for (i = 0; i < RX_RING_SIZE; i++) { - tp->rx_ring[i].status = cpu_to_le32(TRING_OWN); - tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); - tp->rx_ring[i].buffer1 = cpu_to_le32(virt_to_bus(tp->rx_buffs[i])); - tp->rx_ring[i].buffer2 = cpu_to_le32(virt_to_bus(&tp->rx_ring[i+1])); - } - /* Mark the last entry as wrapping the ring. */ - tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | 0x02000000); - tp->rx_ring[i-1].buffer2 = cpu_to_le32(virt_to_bus(&tp->rx_ring[0])); + tp->rx_ring[i].status = 0x80000000; /* Owned by Tulip chip */ + tp->rx_ring[i].length = PKT_BUF_SZ; + { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb; + skb = DEV_ALLOC_SKB(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ +#if LINUX_VERSION_CODE > 0x10300 + tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail); +#else + tp->rx_ring[i].buffer1 = virt_to_bus(skb->data); +#endif + } + tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]); + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000; + tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]); /* The Tx buffer descriptor is filled in as needed, but we do need to clear the ownership bit. */ for (i = 0; i < TX_RING_SIZE; i++) { - tp->tx_ring[i].status = cpu_to_le32(0x00000000); + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]); } + tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]); } static int tulip_start_xmit(struct sk_buff *skb, struct device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; - unsigned long ioaddr = dev->base_addr; - int entry, len; - unsigned long daddr; - - /* Transmitter timeout, serious problems. */ - if (dev->tbusy || (tp->port_fail && tp->port_fail(dev))) { - int tickssofar = jiffies - dev->trans_start; - int i; - if (tickssofar < 40) return(1); - if (tp->port_select) { - if (!tp->port_fix) dev->if_port ++; - tp->port_select(dev); - dev->trans_start = jiffies; - return(0); - } - printk("%s: transmit timed out, status %8.8x," - "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", - dev->name, tio_read(CSR5), tio_read(CSR12), - tio_read(CSR13), tio_read(CSR14), tio_read(CSR15)); -#if !defined(__alpha__) && !defined(__sparc_v9__) - printk(" Rx ring %8.8x: ", (int)tp->rx_ring); -#endif - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)le32_to_cpu(tp->rx_ring[i].status)); -#if !defined(__alpha__) && !defined(__sparc_v9__) - printk("\n Tx ring %8.8x: ", (int)tp->tx_ring); -#endif - for (i = 0; i < TX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)le32_to_cpu(tp->tx_ring[i].status)); - printk("\n"); - - tp->stats.tx_errors++; - /* Perhaps we should reinitialize the hardware here. */ - dev->if_port = 0; - tio_write(TSIAC_CONFIG, CSR13); - /* Start the chip's Tx and Rx processes . */ - tio_write(TCMOD_10TP | TCMOD_TRxSTART, CSR6); - /* Trigger an immediate transmit demand. */ - tio_write(TPOLL_TRIGGER, CSR1); - - dev->tbusy=0; - dev->trans_start = jiffies; - return(0); + int entry; + u32 flag; + +#ifdef ORIGINAL_TEXT +#ifndef final_version + if (skb == NULL || skb->len <= 0) { + printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n", + dev->name); + dev_tint(dev); + return 0; } +#endif +#endif +#ifdef CONFIG_NET_FASTROUTE + cli(); + dev->tx_semaphore = 0; +#endif /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - If this ever occurs the queue layer is doing something evil! */ + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); +#ifdef CONFIG_NET_FASTROUTE + sti(); +#endif + if (jiffies - dev->trans_start >= TX_TIMEOUT) + tulip_tx_timeout(dev); +#ifdef CONFIG_NET_FASTROUTE + dev->tx_semaphore = 0; +#endif return 1; } @@ -868,90 +1775,108 @@ /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; - tp->tx_full = 1; - /* - * If skb is == -1, then this is a funky setup_frame redo. - */ - if (skb == (struct sk_buff *) -1) { - daddr = virt_to_bus((char *)tp->setup_frame); -#ifdef NO_ANK_FIX - len = 192; -#else - len = 192 | 0x08000000; -#endif - skb = NULL; + tp->tx_skbuff[entry] = skb; + tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data); + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x60000000; /* No interrupt */ + dev->tbusy = 0; + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0xe0000000; /* Tx-done intr. */ + dev->tbusy = 0; + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x60000000; /* No Tx-done intr. */ + dev->tbusy = 0; } else { - daddr = virt_to_bus(skb->data); - len = skb->len; - tp->stats.tx_bytes+=len; + /* Leave room for set_rx_mode() to fill entries. */ + flag = 0xe0000000; /* Tx-done intr. */ + tp->tx_full = 1; } - tp->tx_skbuff[entry] = skb; - tp->tx_ring[entry].length = cpu_to_le32(len | - (entry == TX_RING_SIZE-1 ? 0xe2000000 : 0xe0000000)); - tp->tx_ring[entry].buffer1 = cpu_to_le32(daddr); - tp->tx_ring[entry].buffer2 = cpu_to_le32(0); - tp->tx_ring[entry].status = cpu_to_le32(TRING_OWN); /* Pass ownership to the chip. */ - barrier(); + if (entry == TX_RING_SIZE-1) + flag |= 0xe2000000; + tp->tx_ring[entry].length = skb->len | flag; + tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */ tp->cur_tx++; - /* Trigger an immediate transmit demand. */ - tio_write(TPOLL_TRIGGER, CSR1); + outl(0, dev->base_addr + CSR1); dev->trans_start = jiffies; +#ifdef CONFIG_NET_FASTROUTE + dev->tx_semaphore = 0; + sti(); +#endif - return(0); + return 0; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs) { - struct device *dev = (struct device *)dev_id; +#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */ + struct device *dev = (struct device *)dev_instance; +#else + struct device *dev = (struct device *)(irq2dev_map[irq]); +#endif + struct tulip_private *lp; - int csr5, boguscnt=10; - unsigned long ioaddr; + int csr5, ioaddr, boguscnt = 12; if (dev == NULL) { - printk ("tulip_interrupt(): irq %d for unknown device.\n", irq); + printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n", + irq); return; } ioaddr = dev->base_addr; lp = (struct tulip_private *)dev->priv; if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; do { - csr5 = tio_read(CSR5); + csr5 = inl(ioaddr + CSR5); /* Acknowledge all of the current interrupt sources ASAP. */ - tio_write(csr5 & TSTAT_CLEARINTR, CSR5); - /* check interrupt ? */ - if ((csr5 & (TSTAT_NORINTR|TSTAT_ABNINTR)) == 0) break; + outl(csr5 & 0x0001ffff, ioaddr + CSR5); + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if ((csr5 & 0x00018000) == 0) + break; - if (csr5 & TSTAT_RxINTR) /* Rx interrupt */ + if (csr5 & RxIntr) tulip_rx(dev); - if (csr5 & TSTAT_TxINTR) { /* Tx-done interrupt */ - int dirty_tx = lp->dirty_tx; + if (csr5 & (TxNoBuf | TxDied | TxIntr)) { + int dirty_tx; - while (dirty_tx < lp->cur_tx) { + for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) { int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(lp->tx_ring[entry].status); + int status = lp->tx_ring[entry].status; if (status < 0) break; /* It still hasn't been Txed */ + /* Check for Rx filter setup frames. */ + if (lp->tx_skbuff[entry] == NULL) + continue; - if (status & TRING_ERROR) { + if (status & 0x8000) { /* There was an major error, log it. */ +#ifndef final_version + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif lp->stats.tx_errors++; - if (status & TRING_TxABORT) lp->stats.tx_aborted_errors++; - if (status & TRING_TxCARR) lp->stats.tx_carrier_errors++; - if (status & TRING_TxWINDOW) lp->stats.tx_window_errors++; - if (status & TRING_TxFIFO) lp->stats.tx_fifo_errors++; - if ((status & TRING_TxHEARTBEAT) && !lp->full_duplex) + if (status & 0x4104) lp->stats.tx_aborted_errors++; + if (status & 0x0C00) lp->stats.tx_carrier_errors++; + if (status & 0x0200) lp->stats.tx_window_errors++; + if (status & 0x0002) lp->stats.tx_fifo_errors++; + if ((status & 0x0080) && lp->full_duplex == 0) lp->stats.tx_heartbeat_errors++; #ifdef ETHER_STATS if (status & 0x0100) lp->stats.collisions16++; @@ -965,15 +1890,14 @@ } /* Free the original skb. */ - if (lp->tx_skbuff[entry] != NULL) - dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE); - dirty_tx++; + dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE); + lp->tx_skbuff[entry] = 0; } #ifndef final_version - if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { - printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dirty_tx, lp->cur_tx, lp->tx_full); + if (lp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, lp->cur_tx, lp->tx_full); dirty_tx += TX_RING_SIZE; } #endif @@ -990,34 +1914,52 @@ } /* Log errors. */ - if (csr5 & TSTAT_ABNINTR) { /* Abnormal error summary bit. */ - if (csr5 & TSTAT_TxTOUT) lp->stats.tx_errors++; /* Tx babble. */ - if (csr5 & TSTAT_RxMISSED) { /* Missed a Rx frame. */ + if (csr5 & 0x8000) { /* Abnormal error summary bit. */ + if (csr5 & TxJabber) lp->stats.tx_errors++; + if (csr5 & TxFIFOUnderflow) { + lp->csr6 |= 0x00200000; /* Reconfigure to store-n-forward. */ + /* Restart the transmit process. */ + outl(lp->csr6 | 0x0002, ioaddr + CSR6); + outl(lp->csr6 | 0x2002, ioaddr + CSR6); + } + if (csr5 & RxDied) { /* Missed a Rx frame. */ lp->stats.rx_errors++; - lp->stats.rx_missed_errors += tio_read(CSR8) & 0xffff; + lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; } - if (csr5 & TSTAT_TEXPIRED) { - printk("%s: Something Wicked happened! %8.8x.\n", + if (csr5 & TimerInt) { + printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n", dev->name, csr5); /* Hmmmmm, it's not clear what to do here. */ } + /* Clear all error sources, included undocumented ones! */ + outl(0x000f7ba, ioaddr + CSR5); } if (--boguscnt < 0) { - printk("%s: Too much work at interrupt, csr5=0x%8.8x.\n", + printk(KERN_WARNING "%s: Too much work at interrupt, csr5=0x%8.8x.\n", dev->name, csr5); /* Clear all interrupt sources. */ - tio_write(TSTAT_CLEARINTR, CSR5); + outl(0x0001ffff, ioaddr + CSR5); break; } } while (1); - /* Special code for testing *only*. */ + if (tulip_debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", + dev->name, inl(ioaddr + CSR5)); + + /* Code that should never be run! Perhaps remove after testing.. */ { static int stopit = 10; if (dev->start == 0 && --stopit < 0) { - printk("%s: Emergency stop, looping startup interrupt.\n", - dev->name); + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n" + KERN_ERR "%s: Disabling interrupt handler %d to avoid " + "locking up the machine.\n", + dev->name, dev->name, dev->irq); +#ifdef SA_SHIRQ free_irq(irq, dev); +#else + free_irq(irq); +#endif } } @@ -1025,433 +1967,522 @@ return; } +#ifdef CONFIG_NET_FASTROUTE +/* DMAing cards are the most easy in this respect, + they are able to make fast route to any device. + + Now we allow to make it only to another ethernet card. + */ +static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst) +{ + struct device *odev = dst->dev; + + if (dst->ops->protocol != __constant_htons(ETH_P_IP)) + return -1; + if (odev->type != ARPHRD_ETHER || odev->accept_fastpath == NULL) + return -1; + + return 0; +} + +/* + Return values: + + 0 - packet has gone by fast path. + 1 - fast path is OK, but device deferred xmit. (semifast path) + + 2 - fast path is hit, but packet is a bit strange. (NI) + 3 - oom + + 4 - fast path miss. + */ + +static int tulip_fast_forward(struct device *dev, int entry, int len) +{ + struct tulip_private *lp = (struct tulip_private *)dev->priv; + struct sk_buff *skb = lp->rx_skbuff[entry]; + struct ethhdr *eth = (void*)skb->data; + + if (eth->h_proto == __constant_htons(ETH_P_IP)) { + struct rtable *rt; + struct iphdr *iph; + unsigned h; + + iph = (struct iphdr*)(skb->data + ETH_HLEN); + h = (*(u8*)&iph->daddr^*(u8*)&iph->saddr)&NETDEV_FASTROUTE_HMASK; + rt = (struct rtable*)(dev->fastpath[h]); + if (rt && + ((u16*)&iph->daddr)[0] == ((u16*)&rt->key.dst)[0] && + ((u16*)&iph->daddr)[1] == ((u16*)&rt->key.dst)[1] && + ((u16*)&iph->saddr)[0] == ((u16*)&rt->key.src)[0] && + ((u16*)&iph->saddr)[1] == ((u16*)&rt->key.src)[1] && + rt->u.dst.obsolete == 0) { + struct device *odev = rt->u.dst.dev; + + dev_fastroute_stat.hits++; + + if (*(u8*)iph != 0x45 || + (eth->h_dest[0]&1) || + !neigh_is_valid(rt->u.dst.neighbour) || + iph->ttl <= 1) + goto alas2; + + ip_decrease_ttl(iph); + + if (1) { + struct sk_buff *skb2 = DEV_ALLOC_SKB(PKT_BUF_SZ); + if (skb2 == NULL) + goto oom; + lp->rx_ring[entry].buffer1 = virt_to_bus(skb2->tail); + skb2->dev = dev; + lp->rx_skbuff[entry] = skb2; + } + + skb_put(skb, len); + + ip_statistics.IpInReceives++; + ip_statistics.IpForwDatagrams++; + + /* Could use hh cache */ + memcpy(eth->h_source, odev->dev_addr, 6); + memcpy(eth->h_dest, rt->u.dst.neighbour->ha, 6); + skb->dev = odev; + +#ifdef FAST_SKB_RECYCLE /* DO NOT DEFINE IT! READ COMMENT */ + /* We could use fast buffer recycling here if odev + is not DMAing. + + The only problem is that we must allocate skb2 + BEFORE we lose skb, otherwise we would make hole in + tulip rx array. Hence, to implement FAST_SKB_RECYCLE + we need always keep at least one skb in a safe place. + */ + atomic_inc(&skb->users); +#endif + + if (odev->tx_semaphore && + odev->tbusy == 0 && + odev->interrupt == 0 && + odev->hard_start_xmit(skb, odev) == 0) { +#ifdef FAST_SKB_RECYCLE + if (atomic_read(&skb->users) == 1) { + skb->tail = skb->data; + skb->len = 0; + } +#endif + dev_fastroute_stat.succeed++; + return 0; + } +#ifdef FAST_SKB_RECYCLE + atomic_dec(&skb->users); +#endif + + /* Otherwise... */ + skb->pkt_type = PACKET_FASTROUTE; + skb->nh.raw = skb->data + ETH_HLEN; + skb->protocol = __constant_htons(ETH_P_IP); + dev_fastroute_stat.deferred++; + return 1; + } + } + return 4; + +oom: + return 3; + +alas2: +#ifdef not_yet + skb->dst = dst_clone(&rt->u.dst); + return 2; +#else + return 4; +#endif +} +#endif + static int tulip_rx(struct device *dev) { struct tulip_private *lp = (struct tulip_private *)dev->priv; int entry = lp->cur_rx % RX_RING_SIZE; - int i; + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + lp->rx_ring[entry].status); /* If we own the next entry, it's a new packet. Send it up. */ - while (((s32)le32_to_cpu(lp->rx_ring[entry].status)) >= 0) { - int status = le32_to_cpu(lp->rx_ring[entry].status); + while (lp->rx_ring[entry].status >= 0) { + int status = lp->rx_ring[entry].status; - if ((status & TRING_RxDESCMASK) != TRING_RxDESCMASK) { - printk("%s: Ethernet frame spanned multiple buffers," - "status %8.8x!\n", dev->name, status); - } else if (status & TRING_ERROR) { + if ((status & 0x0300) != 0x0300) { + if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */ + printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " + "multiple buffers, status %8.8x!\n", dev->name, status); + lp->stats.rx_length_errors++; + } + } else if (status & 0x8000) { /* There was a fatal error. */ lp->stats.rx_errors++; /* end of a packet.*/ - if (status & TRING_RxLENGTH) lp->stats.rx_length_errors++; - if (status & TRING_RxFRAME) lp->stats.rx_frame_errors++; - if (status & TRING_RxCRC) lp->stats.rx_crc_errors++; - if (status & TRING_RxFIFO) lp->stats.rx_fifo_errors++; + if (status & 0x0890) lp->stats.rx_length_errors++; + if (status & 0x0004) lp->stats.rx_frame_errors++; + if (status & 0x0002) lp->stats.rx_crc_errors++; + if (status & 0x0001) lp->stats.rx_fifo_errors++; } else { /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - short pkt_len = (le32_to_cpu(lp->rx_ring[entry].status) >> 16) - 4; + short pkt_len = (lp->rx_ring[entry].status >> 16) - 4; struct sk_buff *skb; + int rx_in_place = 0; + +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (netdev_dropping) + goto throttle; +#endif - skb = dev_alloc_skb(pkt_len + 2); + skb = lp->rx_skbuff[entry]; + +#ifdef CONFIG_NET_FASTROUTE + switch (tulip_fast_forward(dev, entry, pkt_len)) { + case 0: + goto gone; + case 1: + goto semi_gone; + case 2: + break; + case 3: + skb = NULL; + goto memory_squeeze; + } +#endif + /* Check if the packet is long enough to just accept without + copying to a properly sized skbuff. */ + if (pkt_len > rx_copybreak) { + struct sk_buff *newskb; + char *temp; + + /* Get a fresh skbuff to replace the filled one. */ + newskb = DEV_ALLOC_SKB(PKT_BUF_SZ); + if (newskb == NULL) { + skb = NULL; /* No memory, drop the packet. */ + goto memory_squeeze; + } + /* Pass up the skb already on the Rx ring. */ + temp = skb_put(skb, pkt_len); + if (bus_to_virt(lp->rx_ring[entry].buffer1) != temp) + printk(KERN_ERR "%s: Internal consistency error -- the " + "skbuff addresses do not match" + " in tulip_rx: %p vs. %p / %p.\n", dev->name, + bus_to_virt(lp->rx_ring[entry].buffer1), + skb->head, temp); + rx_in_place = 1; + lp->rx_skbuff[entry] = newskb; + newskb->dev = dev; + /* Longword alignment required: do not skb_reserve(2)! */ + lp->rx_ring[entry].buffer1 = virt_to_bus(newskb->tail); + } else + skb = DEV_ALLOC_SKB(pkt_len + 2); +memory_squeeze: if (skb == NULL) { - printk("%s: Memory squeeze, deferring packet.\n", + int i; + printk(KERN_WARNING "%s: Memory squeeze, deferring packet.\n", dev->name); /* Check that at least two ring entries are free. If not, free one and mark stats->rx_dropped++. */ - for (i=0; i < RX_RING_SIZE; i++) - if (((s32)le32_to_cpu(lp->rx_ring[(entry+i) % RX_RING_SIZE].status)) < 0) + for (i = 0; i < RX_RING_SIZE; i++) + if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0) break; if (i > RX_RING_SIZE -2) { lp->stats.rx_dropped++; - lp->rx_ring[entry].status = cpu_to_le32(TRING_OWN); + lp->rx_ring[entry].status = 0x80000000; lp->cur_rx++; } break; } skb->dev = dev; - skb_reserve(skb, 2); - memcpy(skb_put(skb, pkt_len), - bus_to_virt(lp->rx_ring[entry].buffer1), pkt_len); - /* Needed for 1.3.x */ - skb->protocol = eth_type_trans(skb,dev); + if (! rx_in_place) { + skb_reserve(skb, 2); /* 16 byte align the data fields */ +#if LINUX_VERSION_CODE < 0x20200 || defined(__alpha__) + memcpy(skb_put(skb, pkt_len), + bus_to_virt(lp->rx_ring[entry].buffer1), pkt_len); +#else +#ifdef ORIGINAL_TEXT +#warning Code untested +#else +#error Code is wrong, and it has nothing to do with 2.2 :-) +#endif + eth_copy_and_sum(skb, bus_to_virt(lp->rx_ring[entry].buffer1), + pkt_len, 0); + skb_put(skb, pkt_len); +#endif + } +#if LINUX_VERSION_CODE > 0x10300 + skb->protocol = eth_type_trans(skb, dev); +#else + skb->len = pkt_len; +#endif +#ifdef CONFIG_NET_FASTROUTE +semi_gone: +#endif netif_rx(skb); +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (netdev_dropping) { +throttle: + if (lp->fc_bit) { + outl(lp->csr6 | 0x2000, dev->base_addr + CSR6); + set_bit(lp->fc_bit, &netdev_fc_xoff); + } + } +#endif +#ifdef CONFIG_NET_FASTROUTE +gone: +#endif lp->stats.rx_packets++; - lp->stats.rx_bytes+=skb->len; +#ifndef ORIGINAL_TEXT + lp->stats.rx_bytes += pkt_len; +#endif } - lp->rx_ring[entry].status = cpu_to_le32(TRING_OWN); + lp->rx_ring[entry].status = 0x80000000; entry = (++lp->cur_rx) % RX_RING_SIZE; } - return(0); + + return 0; } static int tulip_close(struct device *dev) { - unsigned long ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; +#ifdef CONFIG_NET_FASTROUTE + dev->tx_semaphore = 0; +#endif dev->start = 0; dev->tbusy = 1; +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (tp->fc_bit) { + int bit = tp->fc_bit; + tp->fc_bit = 0; + netdev_unregister_fc(bit); + } +#endif + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl(ioaddr + CSR5)); + /* Disable interrupts by clearing the interrupt mask. */ - tio_write(TINTR_DISABLE, CSR7); + outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ - tio_write(tio_read(CSR6) & ~(TCMOD_TRxSTART), CSR6); - /* Leave the card in 10baseT state. */ - tio_write(TSIAC_CONFIG, CSR13); + outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); + /* 21040 -- Leave the card in 10baseT state. */ + if (tp->chip_id == DC21040) + outl(0x00000004, ioaddr + CSR13); - tp->stats.rx_missed_errors += tio_read(CSR8) & 0xffff; + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - tio_write(0, CSR13); -/* tio_write(0, CSR8); wake up chip ? */ + del_timer(&tp->timer); +#ifdef SA_SHIRQ free_irq(dev->irq, dev); +#else + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; +#endif - MOD_DEC_USE_COUNT; - return(0); -} + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].length = 0; + tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ + if (skb) { +#if LINUX_VERSION_CODE < 0x20100 + skb->free = 1; +#endif + dev_kfree_skb(skb, FREE_WRITE); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE); + tp->tx_skbuff[i] = 0; + } -static int -tulip_config(struct device *dev, struct ifmap *map) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - if (map->port == 0xff) return(-EINVAL); - dev->if_port = map->port; - tp->port_fix = 1; - if (tp->port_select) tp->port_select(dev); - return(0); + MOD_DEC_USE_COUNT; + + return 0; } -static struct net_device_stats *tulip_get_stats(struct device *dev) +static struct enet_statistics * +tulip_get_stats(struct device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; - /* unsigned long ioaddr = dev->base_addr;*/ + int ioaddr = dev->base_addr; + + if (dev->start) + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - return(&tp->stats); + return &tp->stats; } -/* - * Set or clear the multicast filter for this adaptor. - */ +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN32 ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} +#ifdef NEW_MULTICAST static void set_multicast_list(struct device *dev) +#else +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) +#endif { - unsigned long ioaddr = dev->base_addr; - int csr6 = tio_read(CSR6) & ~(TCMOD_MODEMASK|TCMOD_FILTERMASK); + int ioaddr = dev->base_addr; + int csr6 = inl(ioaddr + CSR6) & ~0x00D5; + struct tulip_private *tp = (struct tulip_private *)dev->priv; - if (dev->flags&IFF_PROMISC) - { /* Set promiscuous. why ALLMULTI ? */ - tio_write(csr6 | TCMOD_PROMISC | TCMOD_ALLMCAST, CSR6); - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - } - else if (dev->mc_count > 14 || (dev->flags&IFF_ALLMULTI)) - { + tp->csr6 &= ~0x00D5; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + outl(csr6 | 0x00C0, ioaddr + CSR6); + /* Unconditionally log net taps. */ + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + tp->csr6 |= 0xC0; + } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ - tio_write(csr6 | TCMOD_ALLMCAST, CSR6); - } - else - { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - struct dev_mc_list *dmi=dev->mc_list; - int *setup_frm = tp->setup_frame; - unsigned short *eaddrs; + outl(csr6 | 0x0080, ioaddr + CSR6); + tp->csr6 |= 0x80; + } else { + u32 *setup_frm = tp->setup_frame; + struct dev_mc_list *mclist; + u16 *eaddrs; + u32 tx_flags; int i; - /* We have < 15 addresses that we can use the wonderful - 16 address perfect filtering of the Tulip. Note that only - the low shortword of setup_frame[] is valid. */ - tio_write(csr6 | 0x0000, CSR6); - for (i = 0; i < dev->mc_count; i ++) { - eaddrs=(unsigned short *)dmi->dmi_addr; - dmi=dmi->next; - *setup_frm++ = cpu_to_le32(*eaddrs++); - *setup_frm++ = cpu_to_le32(*eaddrs++); - *setup_frm++ = cpu_to_le32(*eaddrs++); - } - /* Fill the rest of the table with our physical address. */ - eaddrs = (unsigned short *)dev->dev_addr; - /* Always accept broadcast packets */ - *setup_frm++ = cpu_to_le32(0xffff); - *setup_frm++ = cpu_to_le32(0xffff); - *setup_frm++ = cpu_to_le32(0xffff); + if (dev->mc_count > 14) { /* Must use a multicast hash table. */ + u16 hash_table[32]; + memset(hash_table, 0, sizeof(hash_table)); + /* This should work on big-endian machines as well. */ + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + hash_table); + /* Copy the hash table to the setup frame. + NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */ + for (i = 0; i < 32; i++) + *setup_frm++ = hash_table[i]; + setup_frm += 7; + tx_flags = 0x08400000 | 192; + /* Too clever: i > 15 for fall-though. */ + } else { + /* We have <= 15 addresses so we can use the wonderful + 16 address perfect filtering of the Tulip. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + /* Note that only the low shortword of setup_frame[] is valid! + This code may require tweaking for non-x86 architectures! */ + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = *eaddrs++; + *setup_frm++ = *eaddrs++; + *setup_frm++ = *eaddrs++; + } + /* Fill the rest of the table with our physical address. + Once again, only the low shortword or setup_frame[] is valid! */ + *setup_frm++ = 0xffff; + *setup_frm++ = 0xffff; + *setup_frm++ = 0xffff; + tx_flags = 0x08000000 | 192; + } + eaddrs = (u16 *)dev->dev_addr; do { - *setup_frm++ = cpu_to_le32(eaddrs[0]); - *setup_frm++ = cpu_to_le32(eaddrs[1]); - *setup_frm++ = cpu_to_le32(eaddrs[2]); + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; } while (++i < 15); - /* Now add this frame to the Tx list. */ - tulip_start_xmit((struct sk_buff *) -1, dev); - } -} - -__initfunc(int -tulip_hwinit(struct device *dev, unsigned long ioaddr, - int irq, int device_id)) -{ - /* See note below on the Znyx 315 etherarray. */ - static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; - static int last_irq; - char detect_mesg[80], *mesgp=detect_mesg; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - unsigned short sum, bitsum; - - if (check_region(ioaddr, TULIP_TOTAL_SIZE) != 0) { - printk("tulip_hwinit: region already allocated at %#3lx.\n", - ioaddr); - return(-1); - } - - mesgp += sprintf(mesgp, "(DEC 21%d4%d Tulip", - device_id == PCI_DEVICE_ID_DEC_TULIP_FAST, - device_id == PCI_DEVICE_ID_DEC_TULIP_PLUS); - - /* Stop the chip's Tx and Rx processes. */ - tio_write(tio_read(CSR6) & ~TCMOD_TRxSTART, CSR6); - /* Clear the missed-packet counter. */ - i = tio_read(CSR8) & 0xffff; - - if (device_id == PCI_DEVICE_ID_DEC_TULIP_PLUS - && (tio_read(CSR9) & 0x8000)) { - mesgp += sprintf(mesgp, " treat as 21040"); - device_id = PCI_DEVICE_ID_DEC_TULIP; - } - - /* The station address ROM is read byte serially. The register must - be polled, waiting for the value to be read bit serially from the - EEPROM. - */ - sum = 0; - if (device_id == PCI_DEVICE_ID_DEC_TULIP) { - tio_write(0, CSR9); - /* Reset the pointer with a dummy write. */ - bitsum = 0xff; - for (i = 0; i < 6; i++) { - int value, boguscnt = 100000; - do - value = tio_read(CSR9); - while (value < 0 && --boguscnt > 0); - dev->dev_addr[i] = value; - sum += value & 0xFF; - bitsum &= value; - } - } else { - /* Must be a 21140/21041, with a serial EEPROM interface. */ - struct eeprom eep; - u_char *addr; - - if (read_eeprom(ioaddr, &eep) < 0) { - addr = eep.ng_addr;/* broken EEPROM structure */ - } else { - addr = eep.ok_addr;/* DEC EtherWorks */ - } - for (i = 0; i < ETH_ALEN; i++) { - sum += addr[i]; - dev->dev_addr[i] = addr[i]; - } - } - /* Make certain the data structures are quadword aligned. */ - - mesgp += sprintf(mesgp, ") at %016lx, ", ioaddr); - - /* On the Zynx 315 etherarray boards only the first Tulip has an EEPROM. - The addresses of the subsequent ports are derived from the first. */ - if (sum == 0) { - for (i = 0; i < ETH_ALEN - 1; i++) - dev->dev_addr[i] = last_phys_addr[i]; - dev->dev_addr[i] = last_phys_addr[i] + 1; - irq = last_irq; - } - for (i = 0; i < ETH_ALEN - 1; i++) - mesgp += sprintf(mesgp, "%2.2x:", dev->dev_addr[i]); - mesgp += sprintf(mesgp, "%2.2x, IRQ %d\n", - last_phys_addr[i] = dev->dev_addr[i], irq); - last_irq = irq; - - /* copy ethernet address */ - if (card_type(tp, device_id, - htonl((*(int*)dev->dev_addr) & 0xFFFFFF))) - for (i = 0; i < ETH_ALEN - 1; i++) - last_phys_addr[i] = dev->dev_addr[i]; - /* We do a request_region() only to register /proc/ioports info. */ - request_region(ioaddr, TULIP_TOTAL_SIZE, tp->signature); - - dev->base_addr = ioaddr; - dev->irq = irq; - - /* The Tulip-specific entries in the device structure. */ - dev->open = &tulip_open; - dev->hard_start_xmit = &tulip_start_xmit; - dev->stop = &tulip_close; - dev->get_stats = &tulip_get_stats; - dev->set_config = &tulip_config; - dev->set_multicast_list = &set_multicast_list; - -#ifdef MODULE - if (if_port == TULIP_AUTO_PORT) - if_port = TULIP_PORT; - else - tp->port_fix = 1; - dev->if_port = if_port; - tp->full_duplex = full_duplex; - tp->next_module = root_tulip_dev; - root_tulip_dev = dev; -#else -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; -#endif - dev->if_port = TULIP_PORT; -#endif -#ifdef TULIP_FIX_PORT - tp->port_fix = 1; -#endif - - printk("%s: %s %s", dev->name, tp->signature, detect_mesg); - - /* Reset the xcvr interface and turn on heartbeat. */ - tio_write(TSIAC_RESET, CSR13); - tio_write(TSIAC_CONFIG, CSR13); - - return(0); -} - -__initfunc(int tulip_probe(struct device *dev)) -{ - static struct device *tulip_head=NULL; -#ifdef __sparc_v9__ - struct pci_dev *pdev; -#else - u_char btmp; - u_int itmp; -#endif - u_char pci_bus, pci_device_fn, pci_latency; - u_int pci_irq; - unsigned long pci_ioaddr; - u_short pci_command, vendor_id, device_id; - u_int pci_chips[] = { - PCI_DEVICE_ID_DEC_TULIP, - PCI_DEVICE_ID_DEC_TULIP_FAST, - PCI_DEVICE_ID_DEC_TULIP_PLUS, - PCI_DEVICE_ID_NONE - }; - int num=0, cno; - static int pci_index = 0; - - if (!pcibios_present()) - return(-ENODEV); - - for (; pci_index < 0xff; pci_index++) { - if (pcibios_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) - break; - -#ifdef __sparc_v9__ - for(pdev = pci_devices; pdev; pdev = pdev->next) - if(pdev->bus->number == pci_bus && - pdev->devfn == pci_device_fn) - break; - if(!pdev) - panic("tulip: Cannot find pci_dev for [%x:%x]\n", - pci_bus, pci_device_fn); -#endif - - /* get vendor id */ - pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, - &vendor_id); - /* get device id */ - pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, - &device_id); - -#ifndef __sparc_v9__ - /* get IO address */ - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, - &itmp); - pci_ioaddr = itmp; - - /* get IRQ */ - pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, - &btmp); - pci_irq = btmp; -#else - /* get IO address */ - pci_ioaddr = pdev->base_address[0]; - - /* get IRQ */ - pci_irq = pdev->irq; -#endif - - /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; - if (vendor_id != PCI_VENDOR_ID_DEC) - continue; - - for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno++) - if (device_id == pci_chips[cno]) - break; - if (pci_chips[cno] == PCI_DEVICE_ID_NONE) { - printk("Unknown Digital PCI ethernet chip type %4.4x detected:" - " not configured.\n", device_id); - continue; - } - dev = init_etherdev(NULL, ROUND_UP(sizeof(struct device) + - sizeof (struct tulip_private) + - ETHNAMSIZ, 8)); - if (dev == NULL) - break; + if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { + /* Same setup recently queued, we need not add it. */ + } else { + unsigned long flags; + unsigned int entry; + + save_flags(flags); cli(); + entry = tp->cur_tx++ % TX_RING_SIZE; + + if (entry != 0) { + /* Avoid a chip errata by prefixing a dummy entry. */ + tp->tx_skbuff[entry] = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? 0x02000000 : 0; + tp->tx_ring[entry].buffer1 = 0; + tp->tx_ring[entry].status = 0x80000000; + entry = tp->cur_tx++ % TX_RING_SIZE; + } - if (!tulip_head) { - printk(version); - tulip_head = dev; - } - - /* Get and check the bus-master and latency values. */ - pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, - &pci_command); - if ((pci_command & PCI_COMMAND_MASTER) == 0) { - printk(" PCI Master Bit has not been set!" - " Setting...\n"); - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, - pci_command); - } - - pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, - &pci_latency); - - if (pci_latency < 10) { - printk(" PCI latency timer (CFLT) is" - " unreasonably low at %d." - " Setting to 100 clocks.\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 100); - } - - if (tulip_hwinit(dev, pci_ioaddr, pci_irq, pci_chips[cno]) < 0) { - continue; - } - num++; -#ifdef TULIP_MAX_CARDS - if (num >= TULIP_MAX_CARDS) return(0); -#endif + tp->tx_skbuff[entry] = 0; + /* Put the setup frame on the Tx list. */ + if (entry == TX_RING_SIZE-1) + tx_flags |= 0x02000000; /* Wrap ring. */ + tp->tx_ring[entry].length = tx_flags; + tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[entry].status = 0x80000000; + if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { + dev->tbusy = 1; + tp->tx_full = 1; + } + restore_flags(flags); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + } + outl(csr6 | 0x0000, ioaddr + CSR6); } - return(num > 0 ? 0: -ENODEV); } - + #ifdef MODULE +#if LINUX_VERSION_CODE > 0x20118 +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(reverse_probe, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +#endif -/* The parameters that may be passed in... */ -/* This driver does nothing with options yet. It will later be used to - pass the full-duplex flag, etc. */ -int debug = -1; +/* An additional parameter that may be passed in... */ +static int debug = -1; int init_module(void) { + if (debug >= 0) + tulip_debug = debug; + root_tulip_dev = NULL; return tulip_probe(NULL); } @@ -1463,21 +2494,21 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_tulip_dev) { - next_dev = - ((struct tulip_private *) root_tulip_dev->priv)->next_module; + next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module; unregister_netdev(root_tulip_dev); release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE); kfree(root_tulip_dev); root_tulip_dev = next_dev; } } -#endif /* MODULE */ +#endif /* MODULE */ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c tulip.c" + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c" * c-indent-level: 4 + * c-basic-offset: 4 * tab-width: 4 * End: */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/Makefile linux/drivers/sbus/audio/Makefile --- v2.1.78/linux/drivers/sbus/audio/Makefile Mon Mar 17 14:54:27 1997 +++ linux/drivers/sbus/audio/Makefile Mon Jan 12 15:15:45 1998 @@ -25,11 +25,11 @@ ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y) M=y -O_OBJS += amd7930.o +OX_OBJS += amd7930.o else ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m) MM=y - M_OBJS += amd7930.o + MX_OBJS += amd7930.o endif endif diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c --- v2.1.78/linux/drivers/sbus/audio/amd7930.c Tue May 13 22:41:12 1997 +++ linux/drivers/sbus/audio/amd7930.c Mon Jan 12 15:15:45 1998 @@ -1,12 +1,18 @@ /* * drivers/sbus/audio/amd7930.c * - * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu) * * This is the lowlevel driver for the AMD7930 audio chip found on all * sun4c machines and some sun4m machines. * - * XXX Add note about the fun of getting the docs. + * The amd7930 is actually an ISDN chip which has a very simple + * integrated audio encoder/decoder. When Sun decided on what chip to + * use for audio, they had the brilliant idea of using the amd7930 and + * only connecting the audio encoder/decoder pins. + * + * Thanks to the AMD engineer who was able to get us the AMD79C30 + * databook which has all the programming information and gain tables. */ #include @@ -29,26 +35,78 @@ #define MAX_DRIVERS 1 -/* Private information we store for each amd7930 chip. */ -struct amd7930_info { - /* Current buffer that the driver is playing. */ +static struct sparcaudio_driver drivers[MAX_DRIVERS]; +static int num_drivers; + +/* Each amd7930 chip has two bi-directional B channels and a D + * channel available to the uproc. This structure handles all + * the buffering needed to transmit and receive via a single channel. + */ + +#define CHANNEL_AVAILABLE 0x00 +#define CHANNEL_INUSE_AUDIO_IN 0x01 +#define CHANNEL_INUSE_AUDIO_OUT 0x02 +#define CHANNEL_INUSE_ISDN_B1 0x04 +#define CHANNEL_INUSE_ISDN_B2 0x08 +#define CHANNEL_INUSE 0xff + +struct amd7930_channel { + /* Channel status */ + unsigned char channel_status; + + /* Current buffer that the driver is playing on channel */ volatile __u8 * output_ptr; volatile unsigned long output_count; + unsigned char xmit_idle_char; - /* Current record buffer. */ + /* Callback routine (and argument) when output is done on */ + void (*output_callback)(); + void * output_callback_arg; + + /* Current buffer that the driver is recording on channel */ volatile __u8 * input_ptr; volatile unsigned long input_count; + volatile unsigned long input_limit; + + /* Callback routine (and argument) when input is done on */ + void (*input_callback)(); + void * input_callback_arg; +}; + +/* Private information we store for each amd7930 chip. */ +struct amd7930_info { + struct amd7930_channel D; + struct amd7930_channel Bb; + struct amd7930_channel Bc; + + /* Pointers to which B channels are being used for what + * These three fields (Baudio, Bisdn[0], and Bisdn[1]) will either + * be NULL or point to one of the Bb/Bc structures above. + */ + struct amd7930_channel *Baudio; + struct amd7930_channel *Bisdn[2]; /* Device registers information. */ struct amd7930 *regs; unsigned long regs_size; struct amd7930_map map; + /* Volume information. */ + int pgain, rgain, mgain; + /* Device interrupt information. */ int irq; volatile int ints_on; + + + /* Someone to signal when the ISDN LIU state changes */ + int liu_state; + void (*liu_callback)(void *); + void *liu_callback_arg; }; + + /* Output a 16-bit quantity in the order that the amd7930 expects. */ #define amd7930_out16(regs,v) ({ regs->dr = v & 0xFF; regs->dr = (v >> 8) & 0xFF; }) @@ -120,9 +178,8 @@ #define NR_GER_COEFFS (sizeof(ger_coeff) / sizeof(ger_coeff[0])) /* Enable amd7930 interrupts atomically. */ -static __inline__ void amd7930_enable_ints(struct sparcaudio_driver *drv) +static __inline__ void amd7930_enable_ints(struct amd7930_info *info) { - struct amd7930_info *info = (struct amd7930_info *)drv->private; register unsigned long flags; if (info->ints_on) @@ -137,9 +194,8 @@ } /* Disable amd7930 interrupts atomically. */ -static __inline__ void amd7930_disable_ints(struct sparcaudio_driver *drv) +static __inline__ void amd7930_disable_ints(struct amd7930_info *info) { - struct amd7930_info *info = (struct amd7930_info *)drv->private; register unsigned long flags; if (!info->ints_on) @@ -153,8 +209,24 @@ info->ints_on = 0; } +/* Idle amd7930 (no interrupts, no audio, no data) */ +static __inline__ void amd7930_idle(struct amd7930_info *info) +{ + register unsigned long flags; + + if (!info->ints_on) + return; + + save_and_cli(flags); + info->regs->cr = AMR_INIT; + info->regs->dr = 0; + restore_flags(flags); + + info->ints_on = 0; +} + /* Commit the local copy of the MAP registers to the amd7930. */ -static void amd7930_commit_map(struct sparcaudio_driver *drv) +static void amd7930_write_map(struct sparcaudio_driver *drv) { struct amd7930_info *info = (struct amd7930_info *)drv->private; struct amd7930 *regs = info->regs; @@ -184,71 +256,257 @@ restore_flags(flags); } -/* Interrupt handler (The chip takes only one byte per interrupt. Grrr!) */ -static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *intr_regs) +/* Update the MAP registers with new settings. */ +static void amd7930_update_map(struct sparcaudio_driver *drv) { - struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; struct amd7930_info *info = (struct amd7930_info *)drv->private; - struct amd7930 *regs = info->regs; + struct amd7930_map *map = &info->map; + int level; + + map->gx = gx_coeff[info->rgain]; + map->stgr = gx_coeff[info->mgain]; + + level = (info->pgain * (256 + NR_GER_COEFFS)) >> 8; + if (level >= 256) { + map->ger = ger_coeff[level - 256]; + map->gr = gx_coeff[255]; + } else { + map->ger = ger_coeff[0]; + map->gr = gx_coeff[level]; + } + + /* force output to speaker for now */ + map->mmr2 |= AM_MAP_MMR2_LS; + + /* input from external microphone */ + map->mmr2 |= AM_MAP_MMR2_AINB; + + amd7930_write_map(drv); +} + +/* Bit of a hack here - if the HISAX ISDN driver has got INTSTAT debugging + * turned on, we send debugging characters to the ISDN driver: + * + * i# - Interrupt received - number from 0 to 7 is low three bits of IR + * > - Loaded a single char into the Dchan xmit FIFO + * + - Finished loading an xmit packet into the Dchan xmit FIFO + * < - Read a single char from the Dchan recv FIFO + * ! - Finished reading a packet from the Dchan recv FIFO + * + * This code needs to be removed if anything other than HISAX uses the ISDN + * driver, since D.output_callback_arg is assumed to be a certain struct ptr + */ + +#include "../../isdn/hisax/hisax.h" +#include "../../isdn/hisax/isdnl1.h" + +#ifdef L2FRAME_DEBUG + +inline void debug_info(struct amd7930_info *info, char c) { + struct IsdnCardState *cs; + + if (!info || !info->D.output_callback_arg) return; + + cs = (struct IsdnCardState *)info->D.output_callback_arg; + + if (!cs || !cs->status_write) return; + + if (cs->debug & L1_DEB_INTSTAT) { + *(cs->status_write++) = c; + if (cs->status_write > cs->status_end) + cs->status_write = cs->status_buf; + } +} + +#else + +#define debug_info(info,c) + +#endif + + +static void fill_D_xmit_fifo(struct amd7930_info *info) +{ + /* Send next byte(s) of outgoing data. */ + while (info->D.output_ptr && info->D.output_count > 0 && + (info->regs->dsr2 & AMR_DSR2_TBE)) { + + /* Send the next byte and advance buffer pointer. */ + info->regs->dctb = *(info->D.output_ptr); + info->D.output_ptr++; + info->D.output_count--; + + debug_info(info, '>'); + } +} + +static void transceive_Dchannel(struct amd7930_info *info) +{ __u8 dummy; + int lbrp=0; /* Last Byte of Received Packet (LBRP) */ - /* Clear the interrupt. */ - dummy = regs->ir; +#define D_XMIT_ERRORS (AMR_DER_COLLISION | AMR_DER_UNRN) +#define D_RECV_ERRORS (AMR_DER_RABRT | AMR_DER_RFRAME | AMR_DER_FCS | \ + AMR_DER_OVFL | AMR_DER_UNFL | AMR_DER_OVRN) + + /* Transmit if we can */ + fill_D_xmit_fifo(info); + + /* Done with the xmit buffer? Notify the midlevel driver. */ + if (info->D.output_ptr != NULL && info->D.output_count == 0) { + info->D.output_ptr = NULL; + info->D.output_count = 0; + debug_info(info, '+'); + if (info->D.output_callback) + (*info->D.output_callback) + (info->D.output_callback_arg, + info->regs->der); + /* info->regs->der & D_XMIT_ERRORS); */ + } + + /* Read the next byte(s) of incoming data. */ + + while (info->regs->dsr2 & AMR_DSR2_RBA) { + + if (info->D.input_ptr && + (info->D.input_count < info->D.input_limit)) { + + /* Get the next byte and advance buffer pointer. */ + *(info->D.input_ptr) = info->regs->dcrb; + info->D.input_ptr++; + info->D.input_count++; + + } else { + + /* Overflow - should be detected by chip via RBLR + * so we'll just consume data until we see LBRP + */ + + dummy = info->regs->dcrb; + + } + + debug_info(info, '<'); + + if (info->regs->dsr2 & AMR_DSR2_LBRP) { + + /* End of recv packet? Notify the midlevel driver. */ + + __u8 der; + + debug_info(info, '!'); + + info->D.input_ptr = NULL; + + der = info->regs->der & D_RECV_ERRORS; + + /* Read receive byte count - advances FIFOs */ + info->regs->cr = AMR_DLC_DRCR; + dummy = info->regs->dr; + dummy = info->regs->dr; + + if (info->D.input_callback) + (*info->D.input_callback) + (info->D.input_callback_arg, der, + info->D.input_count); + } + + } +} + +long amd7930_xmit_idles=0; + +static void transceive_Bchannel(struct amd7930_channel *channel, + __volatile__ __u8 *io_reg) +{ /* Send the next byte of outgoing data. */ - if (info->output_ptr && info->output_count > 0) { + if (channel->output_ptr && channel->output_count > 0) { + /* Send the next byte and advance buffer pointer. */ - regs->bbtb = *(info->output_ptr); - info->output_ptr++; - info->output_count--; + *io_reg = *(channel->output_ptr); + channel->output_ptr++; + channel->output_count--; /* Done with the buffer? Notify the midlevel driver. */ - if (info->output_count == 0) { - info->output_ptr = NULL; - info->output_count = 0; - sparcaudio_output_done(drv); + if (channel->output_count == 0) { + channel->output_ptr = NULL; + channel->output_count = 0; + if (channel->output_callback) + (*channel->output_callback) + (channel->output_callback_arg); } - } + } else { + *io_reg = channel->xmit_idle_char; + amd7930_xmit_idles++; + } /* Read the next byte of incoming data. */ - if (info->input_ptr && info->input_count > 0) { + if (channel->input_ptr && channel->input_count > 0) { + /* Get the next byte and advance buffer pointer. */ - *(info->input_ptr) = regs->bbrb; - info->input_ptr++; - info->input_count--; + *(channel->input_ptr) = *io_reg; + channel->input_ptr++; + channel->input_count--; /* Done with the buffer? Notify the midlevel driver. */ - if (info->input_count == 0) { - info->input_ptr = NULL; - info->input_count = 0; - sparcaudio_input_done(drv); + if (channel->input_count == 0) { + channel->input_ptr = NULL; + channel->input_count = 0; + if (channel->input_callback) + (*channel->input_callback) + (channel->input_callback_arg); } } } - -static int amd7930_open(struct inode * inode, struct file * file, - struct sparcaudio_driver *drv) +/* Interrupt handler (The chip takes only one byte per interrupt. Grrr!) */ +static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *intr_regs) { + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; struct amd7930_info *info = (struct amd7930_info *)drv->private; - int level; + struct amd7930 *regs = info->regs; + __u8 ir; + __u8 lsr; - /* Set the default audio parameters. */ - info->map.gx = gx_coeff[128]; - info->map.stgr = gx_coeff[0]; + /* Clear the interrupt. */ + ir = regs->ir; - level = (128 * (256 + NR_GER_COEFFS)) >> 8; - if (level >= 256) { - info->map.ger = ger_coeff[level-256]; - info->map.gr = gx_coeff[255]; - } else { - info->map.ger = ger_coeff[0]; - info->map.gr = gx_coeff[level]; + if (ir & AMR_IR_BBUF) { + if (info->Bb.channel_status == CHANNEL_INUSE) + transceive_Bchannel(&info->Bb, &info->regs->bbtb); + if (info->Bc.channel_status == CHANNEL_INUSE) + transceive_Bchannel(&info->Bc, &info->regs->bctb); + } + + if (ir & (AMR_IR_DRTHRSH | AMR_IR_DTTHRSH | AMR_IR_DSRI)) { + debug_info(info, 'i'); + debug_info(info, '0' + (ir&7)); + transceive_Dchannel(info); } - info->map.mmr2 |= AM_MAP_MMR2_LS; + if (ir & AMR_IR_LSRI) { + regs->cr = AMR_LIU_LSR; + lsr = regs->dr; + + info->liu_state = (lsr&0x7) + 2; + + if (info->liu_callback) + (*info->liu_callback)(info->liu_callback_arg); + } +} + + +static int amd7930_open(struct inode * inode, struct file * file, + struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; - amd7930_commit_map(drv); + /* Set the default audio parameters. */ + info->rgain = 128; + info->pgain = 200; + info->mgain = 0; + amd7930_update_map(drv); MOD_INC_USE_COUNT; @@ -258,29 +516,87 @@ static void amd7930_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) { - amd7930_disable_ints(drv); + /* amd7930_disable_ints(drv->private); */ MOD_DEC_USE_COUNT; } +static void request_Baudio(struct amd7930_info *info) +{ + if (info->Bb.channel_status == CHANNEL_AVAILABLE) { + + info->Bb.channel_status = CHANNEL_INUSE; + info->Baudio = &info->Bb; + + /* Multiplexor map - audio (Ba) to Bb */ + info->regs->cr = AMR_MUX_MCR1; + info->regs->dr = AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4); + + /* Enable B channel interrupts */ + info->regs->cr = AMR_MUX_MCR4; + info->regs->dr = AM_MUX_MCR4_ENABLE_INTS; + + } else if (info->Bc.channel_status == CHANNEL_AVAILABLE) { + + info->Bc.channel_status = CHANNEL_INUSE; + info->Baudio = &info->Bc; + + /* Multiplexor map - audio (Ba) to Bc */ + info->regs->cr = AMR_MUX_MCR1; + info->regs->dr = AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bc << 4); + + /* Enable B channel interrupts */ + info->regs->cr = AMR_MUX_MCR4; + info->regs->dr = AM_MUX_MCR4_ENABLE_INTS; + + } +} + +static void release_Baudio(struct amd7930_info *info) +{ + if (info->Baudio) { + info->Baudio->channel_status = CHANNEL_AVAILABLE; + info->regs->cr = AMR_MUX_MCR1; + info->regs->dr = 0; + info->Baudio = NULL; + + if (info->Bb.channel_status == CHANNEL_AVAILABLE && + info->Bc.channel_status == CHANNEL_AVAILABLE) { + + /* Disable B channel interrupts */ + info->regs->cr = AMR_MUX_MCR4; + info->regs->dr = 0; + } + } +} + static void amd7930_start_output(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long count) { struct amd7930_info *info = (struct amd7930_info *)drv->private; - info->output_ptr = buffer; - info->output_count = count; - amd7930_enable_ints(drv); + if (! info->Baudio) { + request_Baudio(info); + } + + if (info->Baudio) { + info->Baudio->output_ptr = buffer; + info->Baudio->output_count = count; + info->Baudio->output_callback = (void *) &sparcaudio_output_done; + info->Baudio->output_callback_arg = (void *) drv; + info->Baudio->xmit_idle_char = 0; + } } static void amd7930_stop_output(struct sparcaudio_driver *drv) { struct amd7930_info *info = (struct amd7930_info *)drv->private; - info->output_ptr = NULL; - info->output_count = 0; - - if (!info->input_ptr) - amd7930_disable_ints(drv); + if (info->Baudio) { + info->Baudio->output_ptr = NULL; + info->Baudio->output_count = 0; + if (! info->Baudio->input_ptr) + release_Baudio(info); + } } static void amd7930_start_input(struct sparcaudio_driver *drv, @@ -288,20 +604,29 @@ { struct amd7930_info *info = (struct amd7930_info *)drv->private; - info->input_ptr = buffer; - info->input_count = count; - amd7930_enable_ints(drv); + if (! info->Baudio) { + request_Baudio(info); + } + + if (info->Baudio) { + info->Baudio->input_ptr = buffer; + info->Baudio->input_count = count; + info->Baudio->input_callback = (void *) &sparcaudio_input_done; + info->Baudio->input_callback_arg = (void *) drv; + } } static void amd7930_stop_input(struct sparcaudio_driver *drv) { struct amd7930_info *info = (struct amd7930_info *)drv->private; - info->input_ptr = NULL; - info->input_count = 0; + if (info->Baudio) { + info->Baudio->input_ptr = NULL; + info->Baudio->input_count = 0; + if (! info->Baudio->output_ptr) + release_Baudio(info); + } - if (!info->output_ptr) - amd7930_disable_ints(drv); } static void amd7930_sunaudio_getdev(struct sparcaudio_driver *drv, @@ -312,23 +637,686 @@ strncpy(audinfo->config, "audio", sizeof(audinfo->config) - 1); } +static int amd7930_sunaudio_getdev_sunos(struct sparcaudio_driver *drv) +{ + return AUDIO_DEV_AMD; +} + +static int amd7930_set_output_volume(struct sparcaudio_driver *drv, int vol) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + info->pgain = vol; + amd7930_update_map(drv); + return 0; +} + +static int amd7930_get_output_volume(struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + return info->pgain; +} + +static int amd7930_set_input_volume(struct sparcaudio_driver *drv, int vol) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + info->rgain = vol; + amd7930_update_map(drv); + return 0; +} + +static int amd7930_get_input_volume(struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + return info->rgain; +} + +static int amd7930_set_monitor_volume(struct sparcaudio_driver *drv, int vol) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + info->mgain = vol; + amd7930_update_map(drv); + return 0; +} + +/* Cheats. The amd has the minimum capabilities we support */ +static int amd7930_get_output_balance(struct sparcaudio_driver *drv) +{ + return AUDIO_MID_BALANCE; +} + +static int amd7930_get_input_balance(struct sparcaudio_driver *drv) +{ + return AUDIO_MID_BALANCE; +} + +static int amd7930_get_output_channels(struct sparcaudio_driver *drv) +{ + return AUDIO_MIN_PLAY_CHANNELS; +} + +static int amd7930_get_input_channels(struct sparcaudio_driver *drv) +{ + return AUDIO_MIN_REC_CHANNELS; +} + +static int amd7930_get_output_precision(struct sparcaudio_driver *drv) +{ + return AUDIO_MIN_PLAY_PRECISION; +} + +static int amd7930_get_input_precision(struct sparcaudio_driver *drv) +{ + return AUDIO_MIN_REC_PRECISION; +} + +/* This should eventually be made to DTRT, whatever that ends up */ +static int amd7930_get_output_port(struct sparcaudio_driver *drv) +{ + return AUDIO_SPEAKER; /* some of these have only HEADPHONE */ +} + +/* Only a microphone here, so no troubles */ +static int amd7930_get_input_port(struct sparcaudio_driver *drv) +{ + return AUDIO_MICROPHONE; +} + +/* This chip also supports AUDIO_ENCODING_ALAW, add support later */ +static int amd7930_get_output_encoding(struct sparcaudio_driver *drv) +{ + return AUDIO_ENCODING_ULAW; +} + +static int amd7930_get_input_encoding(struct sparcaudio_driver *drv) +{ + return AUDIO_ENCODING_ULAW; +} + +/* This is what you get. Take it or leave it */ +static int amd7930_get_output_rate(struct sparcaudio_driver *drv) +{ + return AMD7930_RATE; +} + +static int amd7930_get_input_rate(struct sparcaudio_driver *drv) +{ + return AMD7930_RATE; +} + +static int amd7930_get_output_muted(struct sparcaudio_driver *drv) +{ + return 0; +} + +static int amd7930_get_output_ports(struct sparcaudio_driver *drv) +{ + return AUDIO_SPEAKER | AUDIO_HEADPHONE; +} + +static int amd7930_get_input_ports(struct sparcaudio_driver *drv) +{ + return AUDIO_MICROPHONE; +} + +static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + return info->mgain; +} + /* - * Device detection and initialization. + * ISDN operations + * + * Many of these routines take an "int dev" argument, which is simply + * an index into the drivers[] array. Currently, we only support a + * single AMD 7930 chip, so the value should always be 0. B channel + * operations require an "int chan", which should be 0 for channel B1 + * and 1 for channel B2 + * + * int amd7930_get_irqnum(int dev) + * + * returns the interrupt number being used by the chip. ISDN4linux + * uses this number to watch the interrupt during initialization and + * make sure something is happening. + * + * int amd7930_get_liu_state(int dev) + * + * returns the current state of the ISDN Line Interface Unit (LIU) + * as a number between 2 (state F2) and 7 (state F7). 0 may also be + * returned if the chip doesn't exist or the LIU hasn't been + * activated. The meanings of the states are defined in I.430, ISDN + * BRI Physical Layer Interface. The most important two states are + * F3 (shutdown) and F7 (syncronized). + * + * void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg) + * + * initializes the LIU and optionally registers a callback to be + * signaled upon a change of LIU state. The callback will be called + * with a single opaque callback_arg Once the callback has been + * triggered, amd7930_get_liu_state can be used to determine the LIU + * current state. + * + * void amd7930_liu_activate(int dev, int priority) + * + * requests LIU activation at a given D-channel priority. + * Successful activatation is achieved upon entering state F7, which + * will trigger any callback previously registered with + * amd7930_liu_init. + * + * void amd7930_liu_deactivate(int dev) + * + * deactivates LIU. Outstanding D and B channel transactions are + * terminated rudely and without callback notification. LIU change + * of state callback will be triggered, however. + * + * void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count, + * void (*callback)(void *, int), void *callback_arg) + * + * transmits a packet - specified with buffer, count - over the D-channel + * interface. Buffer should begin with the LAPD address field and + * end with the information field. FCS and flag sequences should not + * be included, nor is bit-stuffing required - all these functions are + * performed by the chip. The callback function will be called + * DURING THE TOP HALF OF AN INTERRUPT HANDLER and will be passed + * both the arbitrary callback_arg and an integer error indication: + * + * 0 - successful transmission; ready for next packet + * non-0 - error value from chip's DER (D-Channel Error Register): + * 4 - collision detect + * 128 - underrun; irq routine didn't service chip fast enough + * + * The callback routine should defer any time-consuming operations + * to a bottom-half handler; however, amd7930_dxmit may be called + * from within the callback to request back-to-back transmission of + * a second packet (without repeating the priority/collision mechanism) + * + * A comment about the "collision detect" error, which is signalled + * whenever the echoed D-channel data didn't match the transmitted + * data. This is part of ISDN's normal multi-drop T-interface + * operation, indicating that another device has attempted simultaneous + * transmission, but can also result from line noise. An immediate + * requeue via amd7930_dxmit is suggested, but repeated collision + * errors may indicate a more serious problem. + * + * void amd7930_drecv(int dev, __u8 *buffer, unsigned int size, + * void (*callback)(void *, int, unsigned int), + * void *callback_arg) + * + * register a buffer - buffer, size - into which a D-channel packet + * can be received. The callback function will be called DURING + * THE TOP HALF OF AN INTERRUPT HANDLER and will be passed an + * arbitrary callback_arg, an integer error indication and the length + * of the received packet, which will start with the address field, + * end with the information field, and not contain flag or FCS + * bytes. Bit-stuffing will already have been corrected for. + * Possible values of second callback argument "error": + * + * 0 - successful reception + * non-0 - error value from chip's DER (D-Channel Error Register): + * 1 - recieved packet abort + * 2 - framing error; non-integer number of bytes received + * 8 - FCS error; CRC sequence indicated corrupted data + * 16 - overflow error; packet exceeded size of buffer + * 32 - underflow error; packet smaller than required five bytes + * 64 - overrun error; irq routine didn't service chip fast enough + * + * int amd7930_bopen(int dev, int chan, u_char xmit_idle_char) + * + * This function should be called before any other operations on a B + * channel. In addition to arranging for interrupt handling and + * channel multiplexing, it sets the xmit_idle_char which is + * transmitted on the interface when no data buffer is available. + * Suggested values are: 0 for ISDN audio; FF for HDLC mark idle; 7E + * for HDLC flag idle. Returns 0 on a successful open; -1 on error, + * which is quite possible if audio and the other ISDN channel are + * already in use, since the Am7930 can only send two of the three + * channels to the processor + * + * void amd7930_bclose(int dev, int chan) + * + * Shuts down a B channel when no longer in use. + * + * void amd7930_bxmit(int dev, int chan, __u8 *buffer, unsigned int count, + * void (*callback)(void *), void *callback_arg) + * + * transmits a raw data block - specified with buffer, count - over + * the B channel interface specified by dev/chan. The callback + * function will be called DURING THE TOP HALF OF AN INTERRUPT + * HANDLER and will be passed the arbitrary callback_arg + * + * The callback routine should defer any time-consuming operations + * to a bottom-half handler; however, amd7930_bxmit may be called + * from within the callback to request back-to-back transmission of + * another data block + * + * void amd7930_brecv(int dev, int chan, __u8 *buffer, unsigned int size, + * void (*callback)(void *), void *callback_arg) + * + * receive a raw data block - specified with buffer, size - over the + * B channel interface specified by dev/chan. The callback function + * will be called DURING THE TOP HALF OF AN INTERRUPT HANDLER and + * will be passed the arbitrary callback_arg + * + * The callback routine should defer any time-consuming operations + * to a bottom-half handler; however, amd7930_brecv may be called + * from within the callback to register another buffer and ensure + * continuous B channel reception without loss of data + * */ -static struct sparcaudio_driver drivers[MAX_DRIVERS]; -static int num_drivers; + +int amd7930_get_irqnum(int dev) +{ + struct amd7930_info *info; + + if (dev > num_drivers) { + return(0); + } + + info = (struct amd7930_info *) drivers[dev].private; + + return info->irq; +} + +int amd7930_get_liu_state(int dev) +{ + struct amd7930_info *info; + + if (dev > num_drivers) { + return(0); + } + + info = (struct amd7930_info *) drivers[dev].private; + + return info->liu_state; +} + +void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg) +{ + struct amd7930_info *info; + register unsigned long flags; + + if (dev > num_drivers) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + + save_and_cli(flags); + + /* Set callback for LIU state change */ + info->liu_callback = callback; + info->liu_callback_arg = callback_arg; + + /* De-activate the ISDN Line Interface Unit (LIU) */ + info->regs->cr = AMR_LIU_LMR1; + info->regs->dr = 0; + + /* Request interrupt when LIU changes state from/to F3/F7/F8 */ + info->regs->cr = AMR_LIU_LMR2; + info->regs->dr = AM_LIU_LMR2_EN_F3_INT | + AM_LIU_LMR2_EN_F7_INT | AM_LIU_LMR2_EN_F8_INT; + + /* amd7930_enable_ints(info); */ + + /* Activate the ISDN Line Interface Unit (LIU) */ + info->regs->cr = AMR_LIU_LMR1; + info->regs->dr = AM_LIU_LMR1_LIU_ENABL; + + restore_flags(flags); +} + +void amd7930_liu_activate(int dev, int priority) +{ + struct amd7930_info *info; + register unsigned long flags; + + if (dev > num_drivers) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + + save_and_cli(flags); + + /* Set D-channel access priority + * + * I.430 defines a priority mechanism based on counting 1s + * in the echo channel before transmitting + * + * Priority 0 is eight 1s; priority 1 is ten 1s; etc + */ + + info->regs->cr = AMR_LIU_LPR; + info->regs->dr = priority & 0x0f; + + /* request LIU activation */ + + info->regs->cr = AMR_LIU_LMR1; + info->regs->dr = AM_LIU_LMR1_LIU_ENABL | AM_LIU_LMR1_REQ_ACTIV; + + restore_flags(flags); +} + +void amd7930_liu_deactivate(int dev) +{ + struct amd7930_info *info; + register unsigned long flags; + + if (dev > num_drivers) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + + save_and_cli(flags); + + /* deactivate LIU */ + + info->regs->cr = AMR_LIU_LMR1; + info->regs->dr = 0; + + restore_flags(flags); +} + +void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count, + void (*callback)(void *, int), void *callback_arg) +{ + struct amd7930_info *info; + register unsigned long flags; + __u8 dmr1; + + if (dev > num_drivers) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + + save_and_cli(flags); + + if (info->D.output_ptr) { + restore_flags(flags); + printk("amd7930_dxmit: transmitter in use\n"); + return; + } + + info->D.output_ptr = buffer; + info->D.output_count = count; + info->D.output_callback = callback; + info->D.output_callback_arg = callback_arg; + + /* Enable D-channel Transmit Threshold interrupt; disable addressing */ + info->regs->cr = AMR_DLC_DMR1; + dmr1 = info->regs->dr; + dmr1 |= AMR_DLC_DMR1_DTTHRSH_INT; + dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS; + info->regs->dr = dmr1; + + /* Begin xmit by setting D-channel Transmit Byte Count Reg (DTCR) */ + info->regs->cr = AMR_DLC_DTCR; + info->regs->dr = count & 0xff; + info->regs->dr = (count >> 8) & 0xff; + + /* Prime xmit FIFO */ + /* fill_D_xmit_fifo(info); */ + transceive_Dchannel(info); + + restore_flags(flags); +} + +void amd7930_drecv(int dev, __u8 *buffer, unsigned int size, + void (*callback)(void *, int, unsigned int), + void *callback_arg) +{ + struct amd7930_info *info; + register unsigned long flags; + __u8 dmr1; + + if (dev > num_drivers) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + + save_and_cli(flags); + + if (info->D.input_ptr) { + restore_flags(flags); + printk("amd7930_drecv: receiver already has buffer!\n"); + return; + } + + info->D.input_ptr = buffer; + info->D.input_count = 0; + info->D.input_limit = size; + info->D.input_callback = callback; + info->D.input_callback_arg = callback_arg; + + /* Enable D-channel Receive Threshold interrupt; + * Enable D-channel End of Receive Packet interrupt; + * Disable address recognition + */ + info->regs->cr = AMR_DLC_DMR1; + dmr1 = info->regs->dr; + dmr1 |= AMR_DLC_DMR1_DRTHRSH_INT | AMR_DLC_DMR1_EORP_INT; + dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS; + info->regs->dr = dmr1; + + /* Set D-channel Receive Byte Count Limit Register */ + info->regs->cr = AMR_DLC_DRCR; + info->regs->dr = size & 0xff; + info->regs->dr = (size >> 8) & 0xff; + + restore_flags(flags); +} + +int amd7930_bopen(int dev, int chan, u_char xmit_idle_char) +{ + struct amd7930_info *info; + register unsigned long flags; + + if (dev > num_drivers || chan<0 || chan>1) { + return -1; + } + + info = (struct amd7930_info *) drivers[dev].private; + + save_and_cli(flags); + + if (info->Bb.channel_status == CHANNEL_AVAILABLE) { + + info->Bb.channel_status = CHANNEL_INUSE; + info->Bb.xmit_idle_char = xmit_idle_char; + info->Bisdn[chan] = &info->Bb; + + /* Multiplexor map - isdn (B1/2) to Bb */ + info->regs->cr = AMR_MUX_MCR2 + chan; + info->regs->dr = (AM_MUX_CHANNEL_B1 + chan) | + (AM_MUX_CHANNEL_Bb << 4); + + } else if (info->Bc.channel_status == CHANNEL_AVAILABLE) { + + info->Bc.channel_status = CHANNEL_INUSE; + info->Bc.xmit_idle_char = xmit_idle_char; + info->Bisdn[chan] = &info->Bc; + + /* Multiplexor map - isdn (B1/2) to Bc */ + info->regs->cr = AMR_MUX_MCR2 + chan; + info->regs->dr = (AM_MUX_CHANNEL_B1 + chan) | + (AM_MUX_CHANNEL_Bc << 4); + + } else { + restore_flags(flags); + return (-1); + } + + /* Enable B channel transmit */ + info->regs->cr = AMR_LIU_LMR1; + info->regs->dr |= AM_LIU_LMR1_B1_ENABL + chan; + + /* Enable B channel interrupts */ + info->regs->cr = AMR_MUX_MCR4; + info->regs->dr = AM_MUX_MCR4_ENABLE_INTS | AM_MUX_MCR4_REVERSE_Bb | AM_MUX_MCR4_REVERSE_Bc; + + restore_flags(flags); + return 0; +} + +void amd7930_bclose(int dev, int chan) +{ + struct amd7930_info *info; + register unsigned long flags; + + if (dev > num_drivers || chan<0 || chan>1) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + + save_and_cli(flags); + + if (info->Bisdn[chan]) { + info->Bisdn[chan]->channel_status = CHANNEL_AVAILABLE; + info->regs->cr = AMR_MUX_MCR2 + chan; + info->regs->dr = 0; + info->Bisdn[chan] = NULL; + + /* Disable B channel transmit */ + info->regs->cr = AMR_LIU_LMR1; + info->regs->dr &= ~(AM_LIU_LMR1_B1_ENABL + chan); + + if (info->Bb.channel_status == CHANNEL_AVAILABLE && + info->Bc.channel_status == CHANNEL_AVAILABLE) { + + /* Disable B channel interrupts */ + info->regs->cr = AMR_MUX_MCR4; + info->regs->dr = 0; + } + } + + restore_flags(flags); +} + +void amd7930_bxmit(int dev, int chan, __u8 * buffer, unsigned long count, + void (*callback)(void *), void *callback_arg) +{ + struct amd7930_info *info; + struct amd7930_channel *Bchan; + register unsigned long flags; + + if (dev > num_drivers) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + Bchan = info->Bisdn[chan]; + + if (Bchan) { + save_and_cli(flags); + + Bchan->output_ptr = buffer; + Bchan->output_count = count; + Bchan->output_callback = (void *) callback; + Bchan->output_callback_arg = callback_arg; + + restore_flags(flags); + } +} + +void amd7930_brecv(int dev, int chan, __u8 * buffer, unsigned long size, + void (*callback)(void *), void *callback_arg) +{ + struct amd7930_info *info; + struct amd7930_channel *Bchan; + register unsigned long flags; + + if (dev > num_drivers) { + return; + } + + info = (struct amd7930_info *) drivers[dev].private; + Bchan = info->Bisdn[chan]; + + if (Bchan) { + save_and_cli(flags); + + Bchan->input_ptr = buffer; + Bchan->input_count = size; + Bchan->input_callback = (void *) callback; + Bchan->input_callback_arg = callback_arg; + + restore_flags(flags); + } +} + +EXPORT_SYMBOL(amd7930_get_irqnum); +EXPORT_SYMBOL(amd7930_get_liu_state); +EXPORT_SYMBOL(amd7930_liu_init); +EXPORT_SYMBOL(amd7930_liu_activate); +EXPORT_SYMBOL(amd7930_liu_deactivate); +EXPORT_SYMBOL(amd7930_dxmit); +EXPORT_SYMBOL(amd7930_drecv); +EXPORT_SYMBOL(amd7930_bopen); +EXPORT_SYMBOL(amd7930_bclose); +EXPORT_SYMBOL(amd7930_bxmit); +EXPORT_SYMBOL(amd7930_brecv); + + +/* + * Device detection and initialization. + */ static struct sparcaudio_operations amd7930_ops = { amd7930_open, amd7930_release, - NULL, /* amd7930_ioctl */ + NULL, /* amd7930_ioctl */ amd7930_start_output, amd7930_stop_output, amd7930_start_input, amd7930_stop_input, amd7930_sunaudio_getdev, + amd7930_set_output_volume, + amd7930_get_output_volume, + amd7930_set_input_volume, + amd7930_get_input_volume, + amd7930_set_monitor_volume, + amd7930_get_monitor_volume, + NULL, /* amd7930_set_output_balance */ + amd7930_get_output_balance, + NULL, /* amd7930_set_input_balance */ + amd7930_get_input_balance, + NULL, /* amd7930_set_output_channels */ + amd7930_get_output_channels, + NULL, /* amd7930_set_input_channels */ + amd7930_get_input_channels, + NULL, /* amd7930_set_output_precision */ + amd7930_get_output_precision, + NULL, /* amd7930_set_input_precision */ + amd7930_get_input_precision, + NULL, /* amd7930_set_output_port */ + amd7930_get_output_port, + NULL, /* amd7930_set_input_port */ + amd7930_get_input_port, + NULL, /* amd7930_set_output_encoding */ + amd7930_get_output_encoding, + NULL, /* amd7930_set_input_encoding */ + amd7930_get_input_encoding, + NULL, /* amd7930_set_output_rate */ + amd7930_get_output_rate, + NULL, /* amd7930_set_input_rate */ + amd7930_get_input_rate, + amd7930_sunaudio_getdev_sunos, + amd7930_get_output_ports, + amd7930_get_input_ports, + NULL, /* amd7930_set_output_muted */ + amd7930_get_output_muted, }; /* Attach to an amd7930 chip given its PROM node. */ @@ -348,8 +1336,10 @@ /* Point at the information structure and initialize it. */ drv->ops = &amd7930_ops; info = (struct amd7930_info *)drv->private; - info->output_ptr = info->input_ptr = NULL; - info->output_count = info->input_count = 0; + info->Bb.output_ptr = info->Bb.input_ptr = NULL; + info->Bb.output_count = info->Bb.input_count = 0; + info->Bc.output_ptr = info->Bc.input_ptr = NULL; + info->Bc.output_count = info->Bc.input_count = 0; info->ints_on = 1; /* force disable below */ /* Map the registers into memory. */ @@ -365,15 +1355,14 @@ return -EIO; } - /* Disable amd7930 interrupt generation. */ - amd7930_disable_ints(drv); + /* Put amd7930 in idle mode (interrupts disabled) */ + amd7930_idle(info); - /* Initialize the MUX unit to connect the MAP to the CPU. */ - info->regs->cr = AMR_MUX_1_4; - info->regs->dr = (AM_MUX_CHANNEL_Bb << 4) | AM_MUX_CHANNEL_Ba; - info->regs->dr = 0; - info->regs->dr = 0; - info->regs->dr = AM_MUX_MCR4_ENABLE_INTS; + /* Enable extended FIFO operation on D-channel */ + info->regs->cr = AMR_DLC_EFCR; + info->regs->dr = AMR_DLC_EFCR_EXTEND_FIFO; + info->regs->cr = AMR_DLC_DMR4; + info->regs->dr = /* AMR_DLC_DMR4_RCV_30 | */ AMR_DLC_DMR4_XMT_14; /* Attach the interrupt handler to the audio interrupt. */ prom_getproperty(node, "intr", (char *)&irq, sizeof(irq)); @@ -381,6 +1370,7 @@ request_irq(info->irq, amd7930_interrupt, SA_INTERRUPT, "amd7930", drv); enable_irq(info->irq); + amd7930_enable_ints(info); /* Initalize the local copy of the MAP registers. */ memset(&info->map, 0, sizeof(info->map)); @@ -413,7 +1403,7 @@ struct amd7930_info *info = (struct amd7930_info *)drv->private; unregister_sparcaudio_driver(drv); - amd7930_disable_ints(drv); + amd7930_idle(info); disable_irq(info->irq); free_irq(info->irq, drv); sparc_free_io(info->regs, info->regs_size); @@ -421,7 +1411,6 @@ } #endif - /* Probe for the amd7930 chip and then attach the driver. */ #ifdef MODULE int init_module(void) @@ -432,12 +1421,6 @@ struct linux_sbus *bus; struct linux_sbus_device *sdev; int node; - -#if 0 -#ifdef MODULE - register_symtab(0); -#endif -#endif /* Try to find the sun4c "audio" node first. */ node = prom_getchild(prom_root_node); diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/amd7930.h linux/drivers/sbus/audio/amd7930.h --- v2.1.78/linux/drivers/sbus/audio/amd7930.h Mon Mar 17 14:54:27 1997 +++ linux/drivers/sbus/audio/amd7930.h Mon Jan 12 15:15:45 1998 @@ -15,6 +15,26 @@ #include +/* Exported ISDN functions */ + +int amd7930_get_irqnum(int dev); +int amd7930_get_liu_state(int dev); +void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg); +void amd7930_liu_activate(int dev, int priority); +void amd7930_liu_deactivate(int dev); +void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count, + void (*callback)(void *, int), void *callback_arg); +void amd7930_drecv(int dev, __u8 *buffer, unsigned int size, + void (*callback)(void *, int, unsigned int), + void *callback_arg); +int amd7930_bopen(int dev, int chan, u_char xmit_idle_char); +void amd7930_bclose(int dev, int chan); +void amd7930_bxmit(int dev, int chan, __u8 * buffer, unsigned long count, + void (*callback)(void *), void *callback_arg); +void amd7930_brecv(int dev, int chan, __u8 * buffer, unsigned long size, + void (*callback)(void *), void *callback_arg); + + /* Register interface presented to the CPU by the amd7930. */ struct amd7930 { @@ -48,6 +68,20 @@ }; +/* After an amd7930 interrupt, reading the Interrupt Register (ir) + * clears the interrupt and returns a bitmask indicated which + * interrupt source(s) require service + */ + +#define AMR_IR_DTTHRSH 0x01 /* D-channel xmit threshold */ +#define AMR_IR_DRTHRSH 0x02 /* D-channel recv threshold */ +#define AMR_IR_DSRI 0x04 /* D-channel packet status */ +#define AMR_IR_DERI 0x08 /* D-channel error */ +#define AMR_IR_BBUF 0x10 /* B-channel data xfer */ +#define AMR_IR_LSRI 0x20 /* LIU status */ +#define AMR_IR_DSR2I 0x40 /* D-channel buffer status */ +#define AMR_IR_MLTFRMI 0x80 /* multiframe or PP */ + /* The amd7930 has "indirect registers" which are accessed by writing * the register number into the Command Register and then reading or * writing values from the Data Register as appropriate. We define the @@ -67,9 +101,29 @@ /* Line Interface Unit */ #define AMR_LIU_LSR 0xA1 +#define AM_LIU_LSR_STATE 0x07 +#define AM_LIU_LSR_F3 0x08 +#define AM_LIU_LSR_F7 0x10 +#define AM_LIU_LSR_F8 0x20 +#define AM_LIU_LSR_HSW 0x40 +#define AM_LIU_LSR_HSW_CHG 0x80 #define AMR_LIU_LPR 0xA2 #define AMR_LIU_LMR1 0xA3 +#define AM_LIU_LMR1_B1_ENABL 0x01 +#define AM_LIU_LMR1_B2_ENABL 0x02 +#define AM_LIU_LMR1_F_DISABL 0x04 +#define AM_LIU_LMR1_FA_DISABL 0x08 +#define AM_LIU_LMR1_REQ_ACTIV 0x10 +#define AM_LIU_LMR1_F8_F3 0x20 +#define AM_LIU_LMR1_LIU_ENABL 0x40 #define AMR_LIU_LMR2 0xA4 +#define AM_LIU_LMR2_DECHO 0x01 +#define AM_LIU_LMR2_DLOOP 0x02 +#define AM_LIU_LMR2_DBACKOFF 0x04 +#define AM_LIU_LMR2_EN_F3_INT 0x08 +#define AM_LIU_LMR2_EN_F8_INT 0x10 +#define AM_LIU_LMR2_EN_HSW_INT 0x20 +#define AM_LIU_LMR2_EN_F7_INT 0x40 #define AMR_LIU_2_4 0xA5 #define AMR_LIU_MF 0xA6 #define AMR_LIU_MFSB 0xA7 @@ -134,7 +188,24 @@ #define AMR_DLC_DRLR 0x84 #define AMR_DLC_DTCR 0x85 #define AMR_DLC_DMR1 0x86 +#define AMR_DLC_DMR1_DTTHRSH_INT 0x01 +#define AMR_DLC_DMR1_DRTHRSH_INT 0x02 +#define AMR_DLC_DMR1_TAR_ENABL 0x04 +#define AMR_DLC_DMR1_EORP_INT 0x08 +#define AMR_DLC_DMR1_EN_ADDR1 0x10 +#define AMR_DLC_DMR1_EN_ADDR2 0x20 +#define AMR_DLC_DMR1_EN_ADDR3 0x40 +#define AMR_DLC_DMR1_EN_ADDR4 0x80 +#define AMR_DLC_DMR1_EN_ADDRS 0xf0 #define AMR_DLC_DMR2 0x87 +#define AMR_DLC_DMR2_RABRT_INT 0x01 +#define AMR_DLC_DMR2_RESID_INT 0x02 +#define AMR_DLC_DMR2_COLL_INT 0x04 +#define AMR_DLC_DMR2_FCS_INT 0x08 +#define AMR_DLC_DMR2_OVFL_INT 0x10 +#define AMR_DLC_DMR2_UNFL_INT 0x20 +#define AMR_DLC_DMR2_OVRN_INT 0x40 +#define AMR_DLC_DMR2_UNRN_INT 0x80 #define AMR_DLC_1_7 0x88 #define AMR_DLC_DRCR 0x89 #define AMR_DLC_RNGR1 0x8A @@ -142,10 +213,66 @@ #define AMR_DLC_FRAR4 0x8C #define AMR_DLC_SRAR4 0x8D #define AMR_DLC_DMR3 0x8E +#define AMR_DLC_DMR3_VA_INT 0x01 +#define AMR_DLC_DMR3_EOTP_INT 0x02 +#define AMR_DLC_DMR3_LBRP_INT 0x04 +#define AMR_DLC_DMR3_RBA_INT 0x08 +#define AMR_DLC_DMR3_LBT_INT 0x10 +#define AMR_DLC_DMR3_TBE_INT 0x20 +#define AMR_DLC_DMR3_RPLOST_INT 0x40 +#define AMR_DLC_DMR3_KEEP_FCS 0x80 #define AMR_DLC_DMR4 0x8F +#define AMR_DLC_DMR4_RCV_1 0x00 +#define AMR_DLC_DMR4_RCV_2 0x01 +#define AMR_DLC_DMR4_RCV_4 0x02 +#define AMR_DLC_DMR4_RCV_8 0x03 +#define AMR_DLC_DMR4_RCV_16 0x01 +#define AMR_DLC_DMR4_RCV_24 0x02 +#define AMR_DLC_DMR4_RCV_30 0x03 +#define AMR_DLC_DMR4_XMT_1 0x00 +#define AMR_DLC_DMR4_XMT_2 0x04 +#define AMR_DLC_DMR4_XMT_4 0x08 +#define AMR_DLC_DMR4_XMT_8 0x0c +#define AMR_DLC_DMR4_XMT_10 0x08 +#define AMR_DLC_DMR4_XMT_14 0x0c +#define AMR_DLC_DMR4_IDLE_MARK 0x00 +#define AMR_DLC_DMR4_IDLE_FLAG 0x10 +#define AMR_DLC_DMR4_ADDR_BOTH 0x00 +#define AMR_DLC_DMR4_ADDR_1ST 0x20 +#define AMR_DLC_DMR4_ADDR_2ND 0xa0 +#define AMR_DLC_DMR4_CR_ENABLE 0x40 #define AMR_DLC_12_15 0x90 #define AMR_DLC_ASR 0x91 #define AMR_DLC_EFCR 0x92 +#define AMR_DLC_EFCR_EXTEND_FIFO 0x01 +#define AMR_DLC_EFCR_SEC_PKT_INT 0x02 + +#define AMR_DSR1_VADDR 0x01 +#define AMR_DSR1_EORP 0x02 +#define AMR_DSR1_PKT_IP 0x04 +#define AMR_DSR1_DECHO_ON 0x08 +#define AMR_DSR1_DLOOP_ON 0x10 +#define AMR_DSR1_DBACK_OFF 0x20 +#define AMR_DSR1_EOTP 0x40 +#define AMR_DSR1_CXMT_ABRT 0x80 + +#define AMR_DSR2_LBRP 0x01 +#define AMR_DSR2_RBA 0x02 +#define AMR_DSR2_RPLOST 0x04 +#define AMR_DSR2_LAST_BYTE 0x08 +#define AMR_DSR2_TBE 0x10 +#define AMR_DSR2_MARK_IDLE 0x20 +#define AMR_DSR2_FLAG_IDLE 0x40 +#define AMR_DSR2_SECOND_PKT 0x80 + +#define AMR_DER_RABRT 0x01 +#define AMR_DER_RFRAME 0x02 +#define AMR_DER_COLLISION 0x04 +#define AMR_DER_FCS 0x08 +#define AMR_DER_OVFL 0x10 +#define AMR_DER_UNFL 0x20 +#define AMR_DER_OVRN 0x40 +#define AMR_DER_UNRN 0x80 /* Peripheral Port */ #define AMR_PP_PPCR1 0xC0 @@ -160,4 +287,6 @@ #define AMR_PP_PPCR2 0xC8 #define AMR_PP_PPCR3 0xC9 +/* Give this chip a "default" sample rate */ +#define AMD7930_RATE (8000) #endif diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.1.78/linux/drivers/sbus/audio/audio.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/sbus/audio/audio.c Mon Jan 12 15:15:45 1998 @@ -1,7 +1,7 @@ /* * drivers/sbus/audio/audio.c * - * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu) * * This is the audio midlayer that sits between the VFS character * devices and the low-level audio hardware device drivers. @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include "audio.h" @@ -42,33 +44,47 @@ if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output) return -EINVAL; - /* Setup the circular queue of output buffers. */ + /* Setup the circular queues of output and input buffers + * + * Each buffer is a single page, but output buffers might + * be partially filled (by a write with count < PAGE_SIZE), + * so each output buffer also has a paired output size. + * + * Input buffers, on the other hand, always fill completely, + * so we don't need input counts - each contains PAGE_SIZE + * bytes of audio data. + * + * TODO: Make number of input/output buffers tunable parameters + */ + drv->num_output_buffers = 32; drv->output_front = 0; drv->output_rear = 0; drv->output_count = 0; drv->output_active = 0; - drv->output_buffers = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL); - drv->output_sizes = kmalloc(32 * sizeof(size_t), GFP_KERNEL); - if (!drv->output_buffers || !drv->output_sizes) { - if (drv->output_buffers) - kfree(drv->output_buffers); - if (drv->output_sizes) - kfree(drv->output_sizes); - return -ENOMEM; - } + drv->output_buffers = kmalloc(drv->num_output_buffers * sizeof(__u8 *), GFP_KERNEL); + drv->output_sizes = kmalloc(drv->num_output_buffers * sizeof(size_t), GFP_KERNEL); + if (!drv->output_buffers || !drv->output_sizes) goto kmalloc_failed1; /* Allocate the pages for each output buffer. */ for (i = 0; i < drv->num_output_buffers; i++) { drv->output_buffers[i] = (void *) __get_free_page(GFP_KERNEL); - if (!drv->output_buffers[i]) { - int j; - for (j = 0; j < i; j++) - free_page((unsigned long) drv->output_buffers[j]); - kfree(drv->output_buffers); - kfree(drv->output_sizes); - return -ENOMEM; - } + if (!drv->output_buffers[i]) goto kmalloc_failed2; + } + + /* Setup the circular queue of input buffers. */ + drv->num_input_buffers = 32; + drv->input_front = 0; + drv->input_rear = 0; + drv->input_count = 0; + drv->input_active = 0; + drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *), GFP_KERNEL); + if (!drv->input_buffers) goto kmalloc_failed3; + + /* Allocate the pages for each input buffer. */ + for (i = 0; i < drv->num_input_buffers; i++) { + drv->input_buffers[i] = (void *) __get_free_page(GFP_KERNEL); + if (!drv->input_buffers[i]) goto kmalloc_failed4; } /* Ensure that the driver is marked as not being open. */ @@ -78,6 +94,28 @@ driver = drv; return 0; + + +kmalloc_failed4: + for (i--; i >= 0; i--) + free_page((unsigned long) drv->input_buffers[i]); + +kmalloc_failed3: + if (drv->input_buffers) + kfree(drv->input_buffers); + i = drv->num_output_buffers; + +kmalloc_failed2: + for (i--; i >= 0; i--) + free_page((unsigned long) drv->output_buffers[i]); + +kmalloc_failed1: + if (drv->output_buffers) + kfree(drv->output_buffers); + if (drv->output_sizes) + kfree(drv->output_sizes); + + return -ENOMEM; } int unregister_sparcaudio_driver(struct sparcaudio_driver *drv) @@ -94,6 +132,11 @@ kfree(driver->output_buffers); kfree(driver->output_sizes); + /* Deallocate the queue of input buffers. */ + for (i = 0; i < driver->num_input_buffers; i++) + free_page((unsigned long) driver->input_buffers[i]); + kfree(driver->input_buffers); + MOD_DEC_USE_COUNT; driver = NULL; @@ -116,6 +159,7 @@ void sparcaudio_output_done(struct sparcaudio_driver * drv) { /* Point the queue after the "done" buffer. */ + drv->output_size -= drv->output_sizes[drv->output_front]; drv->output_front = (drv->output_front + 1) % drv->num_output_buffers; drv->output_count--; @@ -146,7 +190,23 @@ void sparcaudio_input_done(struct sparcaudio_driver * drv) { - /* XXX Implement! */ + /* Point the queue after the "done" buffer. */ + drv->input_front = (drv->input_front + 1) % drv->num_input_buffers; + drv->input_count++; + + /* If the input queue is full, shutdown the driver. */ + if (drv->input_count == drv->num_input_buffers) { + /* Stop the lowlevel driver from inputing. */ + drv->ops->stop_input(drv); + drv->input_active = 0; + } else { + /* Otherwise, give the driver the next buffer. */ + drv->ops->start_input(drv, drv->input_buffers[drv->input_front], + PAGE_SIZE); + } + + /* Wake up any tasks that are waiting. */ + wake_up_interruptible(&drv->input_read_wait); } @@ -155,34 +215,85 @@ * VFS layer interface */ -static int sparcaudio_lseek(struct inode * inode, struct file * file, - off_t offset, int origin) +static loff_t sparcaudio_llseek(struct file * file, loff_t offset, int origin) { return -ESPIPE; } -static int sparcaudio_read(struct inode * inode, struct file * file, - char *buf, int count) +static ssize_t sparcaudio_read(struct file * file, + char *buf, size_t count, loff_t *ppos) +{ + int bytes_to_copy; + + if (! file->f_mode & FMODE_READ) + return -EINVAL; + + if (driver->input_count == 0) { + interruptible_sleep_on(&driver->input_read_wait); + if (signal_pending(current)) + return -EINTR; + } + + bytes_to_copy = PAGE_SIZE - driver->input_offset; + if (bytes_to_copy > count) + bytes_to_copy = count; + + copy_to_user_ret(buf, driver->input_buffers[driver->input_rear]+driver->input_offset, + bytes_to_copy, -EFAULT); + driver->input_offset += bytes_to_copy; + + if (driver->input_offset >= PAGE_SIZE) { + driver->input_rear = (driver->input_rear + 1) % driver->num_input_buffers; + driver->input_count--; + driver->input_offset = 0; + } + + return bytes_to_copy; +} + +static void sparcaudio_reorganize_buffers(struct sparcaudio_driver * driver) { - /* XXX Implement me! */ - return -EINVAL; + /* It may never matter but if it does this routine will pack */ + /* buffers to free space for more data */ } -static int sparcaudio_write(struct inode * inode, struct file * file, - const char *buf, int count) +static void sparcaudio_sync_output(struct sparcaudio_driver * driver) { unsigned long flags; - int bytes_written = 0, bytes_to_copy, err; + + /* If the low-level driver is not active, activate it. */ + save_and_cli(flags); + if (! driver->output_active) { + driver->ops->start_output(driver, + driver->output_buffers[driver->output_front], + driver->output_sizes[driver->output_front]); + driver->output_active = 1; + } + restore_flags(flags); +} + +static ssize_t sparcaudio_write(struct file * file, const char *buf, + size_t count, loff_t *ppos) +{ + int bytes_written = 0, bytes_to_copy; /* Ensure that we have something to write. */ - if (count < 1) + if (count < 1) { + sparcaudio_sync_output(driver); return 0; + } /* Loop until all output is written to device. */ while (count > 0) { /* Check to make sure that an output buffer is available. */ + /* If not, make valiant attempt */ + if (driver->output_count == driver->num_output_buffers) + sparcaudio_reorganize_buffers(driver); + if (driver->output_count == driver->num_output_buffers) { - interruptible_sleep_on(&driver->output_write_wait); + /* We need buffers, so... */ + sparcaudio_sync_output(driver); + interruptible_sleep_on(&driver->output_write_wait); if (signal_pending(current)) return bytes_written > 0 ? bytes_written : -EINTR; } @@ -202,15 +313,11 @@ driver->output_sizes[driver->output_rear] = bytes_to_copy; driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers; driver->output_count++; + driver->output_size += bytes_to_copy; - /* If the low-level driver is not active, activate it. */ - save_and_cli(flags); - if (! driver->output_active) { - driver->ops->start_output(driver, driver->output_buffers[driver->output_front], - driver->output_sizes[driver->output_front]); - driver->output_active = 1; - } - restore_flags(flags); + /* Activate the driver if more than page of data is waiting. */ + if (driver->output_size > 4096) + sparcaudio_sync_output(driver); } /* Return the number of bytes written to the caller. */ @@ -221,8 +328,10 @@ unsigned int cmd, unsigned long arg) { int retval = 0; + struct audio_info ainfo; switch (cmd) { + case SNDCTL_DSP_SYNC: case AUDIO_DRAIN: if (driver->output_count > 0) { interruptible_sleep_on(&driver->output_drain_wait); @@ -239,18 +348,381 @@ copy_to_user_ret((audio_device_t *)arg, &tmp, sizeof(tmp), -EFAULT); } else retval = -EINVAL; + + printk(KERN_INFO "sparcaudio_ioctl: AUDIO_GETDEV\n"); + break; + + case AUDIO_GETDEV_SUNOS: + if (driver->ops->sunaudio_getdev_sunos) { + int tmp=driver->ops->sunaudio_getdev_sunos(driver); + + copy_to_user_ret((int *)arg, &tmp, sizeof(tmp), -EFAULT); + } else + retval = -EINVAL; + + printk(KERN_INFO "sparcaudio_ioctl: AUDIO_GETDEV_SUNOS\n"); + break; + + case AUDIO_GETINFO: + + AUDIO_INITINFO(&ainfo); + + if (driver->ops->get_input_rate) + ainfo.record.sample_rate = + driver->ops->get_input_rate(driver); + if (driver->ops->get_input_channels) + ainfo.record.channels = + driver->ops->get_input_channels(driver); + if (driver->ops->get_input_precision) + ainfo.record.precision = + driver->ops->get_input_precision(driver); + if (driver->ops->get_input_encoding) + ainfo.record.encoding = + driver->ops->get_input_encoding(driver); + if (driver->ops->get_input_volume) + ainfo.record.gain = + driver->ops->get_input_volume(driver); + if (driver->ops->get_input_port) + ainfo.record.port = + driver->ops->get_input_port(driver); + if (driver->ops->get_input_ports) + ainfo.record.avail_ports = + driver->ops->get_input_ports(driver); + ainfo.record.buffer_size = PAGE_SIZE; + ainfo.record.samples = 0; + ainfo.record.eof = 0; + ainfo.record.pause = 0; + ainfo.record.error = 0; + ainfo.record.waiting = 0; + if (driver->ops->get_input_balance) + ainfo.record.balance = + driver->ops->get_input_balance(driver); + ainfo.record.minordev = 4; + ainfo.record.open = 1; + ainfo.record.active = 0; + + if (driver->ops->get_output_rate) + ainfo.play.sample_rate = + driver->ops->get_output_rate(driver); + if (driver->ops->get_output_channels) + ainfo.play.channels = + driver->ops->get_output_channels(driver); + if (driver->ops->get_output_precision) + ainfo.play.precision = + driver->ops->get_output_precision(driver); + if (driver->ops->get_output_encoding) + ainfo.play.encoding = + driver->ops->get_output_encoding(driver); + if (driver->ops->get_output_volume) + ainfo.play.gain = + driver->ops->get_output_volume(driver); + if (driver->ops->get_output_port) + ainfo.play.port = + driver->ops->get_output_port(driver); + if (driver->ops->get_output_ports) + ainfo.play.avail_ports = + driver->ops->get_output_ports(driver); + ainfo.play.buffer_size = PAGE_SIZE; + ainfo.play.samples = 0; + ainfo.play.eof = 0; + ainfo.play.pause = 0; + ainfo.play.error = 0; + ainfo.play.waiting = waitqueue_active(&driver->open_wait); + if (driver->ops->get_output_balance) + ainfo.play.balance = + driver->ops->get_output_balance(driver); + ainfo.play.minordev = 4; + ainfo.play.open = 1; + ainfo.play.active = driver->output_active; + + if (driver->ops->get_monitor_volume) + ainfo.monitor_gain = + driver->ops->get_monitor_volume(driver); + + if (driver->ops->get_output_muted) + ainfo.output_muted = + driver->ops->get_output_muted(driver); + + printk("sparcaudio_ioctl: AUDIO_GETINFO\n"); + + copy_to_user_ret((struct audio_info *)arg, &ainfo, + sizeof(ainfo), -EFAULT); + break; + case AUDIO_SETINFO: + { + audio_info_t curinfo; + + copy_from_user_ret(&ainfo, (audio_info_t *) arg, sizeof(audio_info_t), -EFAULT); + + /* Without these there's no point in trying */ + if (!driver->ops->get_input_precision || + !driver->ops->get_input_channels || + !driver->ops->get_input_rate || + !driver->ops->get_input_encoding || + !driver->ops->get_output_precision || + !driver->ops->get_output_channels || + !driver->ops->get_output_rate || + !driver->ops->get_output_encoding) + { + retval = -EINVAL; + break; + } + + /* Do bounds checking for things which always apply. + * Follow with enforcement of basic tenets of certain + * encodings. Everything over and above generic is + * enforced by the driver, which can assume that + * Martian cases are taken care of here. */ + if (Modify(ainfo.play.gain) && + ((ainfo.play.gain > AUDIO_MAX_GAIN) || + (ainfo.play.gain < AUDIO_MIN_GAIN))) { + /* Need to differentiate this from e.g. the above error */ + retval = -EINVAL; + break; + } + if (Modify(ainfo.record.gain) && + ((ainfo.record.gain > AUDIO_MAX_GAIN) || + (ainfo.record.gain < AUDIO_MIN_GAIN))) { + retval = -EINVAL; + break; + } + if (Modify(ainfo.monitor_gain) && + ((ainfo.monitor_gain > AUDIO_MAX_GAIN) || + (ainfo.monitor_gain < AUDIO_MIN_GAIN))) { + retval = -EINVAL; + break; + } + /* Don't need to check less than zero on these */ + if (Modifyc(ainfo.play.balance) && + (ainfo.play.balance > AUDIO_RIGHT_BALANCE)) { + retval = -EINVAL; + break; + } + if (Modifyc(ainfo.record.balance) && + (ainfo.record.balance > AUDIO_RIGHT_BALANCE)) { + retval = -EINVAL; + break; + } + + /* If any of these changed, record them all, then make + * changes atomically. If something fails, back it all out. */ + if (Modify(ainfo.record.precision) || + Modify(ainfo.record.sample_rate) || + Modify(ainfo.record.channels) || + Modify(ainfo.record.encoding) || + Modify(ainfo.play.precision) || + Modify(ainfo.play.sample_rate) || + Modify(ainfo.play.channels) || + Modify(ainfo.play.encoding)) + { + /* If they're trying to change something we + * have no routine for, they lose */ + if ((!driver->ops->set_input_encoding && + Modify(ainfo.record.encoding)) || + (!driver->ops->set_input_rate && + Modify(ainfo.record.sample_rate)) || + (!driver->ops->set_input_precision && + Modify(ainfo.record.precision)) || + (!driver->ops->set_input_channels && + Modify(ainfo.record.channels))) { + retval = -EINVAL; + break; + } + + curinfo.record.encoding = (Modify(ainfo.record.encoding) ? + ainfo.record.encoding : + driver->ops->get_input_encoding(driver)); + curinfo.record.sample_rate = (Modify(ainfo.record.sample_rate) ? + ainfo.record.sample_rate : + driver->ops->get_input_rate(driver)); + curinfo.record.precision = (Modify(ainfo.record.precision) ? + ainfo.record.precision : + driver->ops->get_input_precision(driver)); + curinfo.record.channels = (Modify(ainfo.record.channels) ? + ainfo.record.channels : + driver->ops->get_input_channels(driver)); + switch (curinfo.record.encoding) { + case AUDIO_ENCODING_ALAW: + case AUDIO_ENCODING_ULAW: + if (Modify(ainfo.record.precision) && + ainfo.record.precision != 8) { + retval = -EINVAL; + break; + } + if (Modify(ainfo.record.channels) && + ainfo.record.channels != 1) { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR: + case AUDIO_ENCODING_LINEARLE: + if (Modify(ainfo.record.precision) && + ainfo.record.precision != 16) { + retval = -EINVAL; + break; + } + if (Modify(ainfo.record.channels) && + (ainfo.record.channels != 1 && + ainfo.record.channels != 2)) + { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR8: + if (Modify(ainfo.record.precision) && + ainfo.record.precision != 8) { + retval = -EINVAL; + break; + } + if (Modify(ainfo.record.channels) && + (ainfo.record.channels != 1 && + ainfo.record.channels != 2)) + { + retval = -EINVAL; + break; + } + } + + if (retval < 0) + break; + + /* If they're trying to change something we + * have no routine for, they lose */ + if ((!driver->ops->set_output_encoding && + Modify(ainfo.play.encoding)) || + (!driver->ops->set_output_rate && + Modify(ainfo.play.sample_rate)) || + (!driver->ops->set_output_precision && + Modify(ainfo.play.precision)) || + (!driver->ops->set_output_channels && + Modify(ainfo.play.channels))) { + retval = -EINVAL; + break; + } + + curinfo.play.encoding = (Modify(ainfo.play.encoding) ? + ainfo.play.encoding : + driver->ops->get_output_encoding(driver)); + curinfo.play.sample_rate = (Modify(ainfo.play.sample_rate) ? + ainfo.play.sample_rate : + driver->ops->get_output_rate(driver)); + curinfo.play.precision = (Modify(ainfo.play.precision) ? + ainfo.play.precision : + driver->ops->get_output_precision(driver)); + curinfo.play.channels = (Modify(ainfo.play.channels) ? + ainfo.play.channels : + driver->ops->get_output_channels(driver)); + switch (curinfo.play.encoding) { + case AUDIO_ENCODING_ALAW: + case AUDIO_ENCODING_ULAW: + if (Modify(ainfo.play.precision) && + ainfo.play.precision != 8) { + retval = -EINVAL; + break; + } + if (Modify(ainfo.play.channels) && + ainfo.play.channels != 1) { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR: + case AUDIO_ENCODING_LINEARLE: + if (Modify(ainfo.play.precision) && + ainfo.play.precision != 16) { + retval = -EINVAL; + break; + } + if (Modify(ainfo.play.channels) && + (ainfo.play.channels != 1 && + ainfo.play.channels != 2)) + { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR8: + if (Modify(ainfo.play.precision) && + ainfo.play.precision != 8) { + retval = -EINVAL; + break; + } + if (Modify(ainfo.play.channels) && + (ainfo.play.channels != 1 && + ainfo.play.channels != 2)) + { + retval = -EINVAL; + break; + } + } + + if (retval < 0) + break; + + /* If we got this far, we're at least sane with + * respect to generics. Try the changes. */ + if ((driver->ops->set_input_precision(driver, ainfo.record.precision) < 0) || + (driver->ops->set_output_precision(driver, ainfo.play.precision) < 0) || + (driver->ops->set_input_channels(driver, ainfo.record.channels) < 0) || + (driver->ops->set_output_channels(driver, ainfo.play.channels) < 0) || + (driver->ops->set_input_rate(driver, ainfo.record.sample_rate) < 0) || + (driver->ops->set_output_rate(driver, ainfo.play.sample_rate) < 0) || + (driver->ops->set_input_encoding(driver, ainfo.record.encoding) < 0) || + (driver->ops->set_output_encoding(driver, ainfo.play.encoding) < 0)) + { + /* Pray we can set it all back. If not, uh... */ + driver->ops->set_input_precision(driver, curinfo.record.precision); + driver->ops->set_output_precision(driver, curinfo.play.precision); + driver->ops->set_input_channels(driver, curinfo.record.channels); + driver->ops->set_output_channels(driver, curinfo.play.channels); + driver->ops->set_input_rate(driver, curinfo.record.sample_rate); + driver->ops->set_output_rate(driver, curinfo.play.sample_rate); + driver->ops->set_input_encoding(driver, curinfo.record.encoding); + driver->ops->set_output_encoding(driver, curinfo.play.encoding); + } + + } + + printk("sparcaudio_ioctl: AUDIO_SETINFO\n"); + break; + } + default: if (driver->ops->ioctl) retval = driver->ops->ioctl(inode,file,cmd,arg,driver); - else + else { retval = -EINVAL; + + printk("sparcaudio_ioctl: 0x%x\n", cmd); + } } return retval; } +static int sparcaudioctl_release(struct inode * inode, struct file * file) +{ + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct file_operations sparcaudioctl_fops = { + NULL, + NULL, + NULL, + NULL, /* sparcaudio_readdir */ + NULL, /* sparcaudio_select */ + sparcaudio_ioctl, + NULL, /* sparcaudio_mmap */ + NULL, + sparcaudioctl_release +}; + static int sparcaudio_open(struct inode * inode, struct file * file) { int err; @@ -259,6 +731,15 @@ if (!driver) return -ENODEV; + if (MINOR(inode->i_rdev) == 5) { + + file->f_op = &sparcaudioctl_fops; + + MOD_INC_USE_COUNT; + + return 0; + } + /* We only support minor #4 (/dev/audio) right now. */ if (MINOR(inode->i_rdev) != 4) return -ENXIO; @@ -285,9 +766,18 @@ } /* Mark the driver as locked for read and/or write. */ - if (file->f_mode & FMODE_READ) + if (file->f_mode & FMODE_READ) { + driver->input_offset = 0; + driver->input_front = 0; + driver->input_rear = 0; + driver->input_count = 0; + driver->ops->start_input(driver, driver->input_buffers[driver->input_front], + PAGE_SIZE); + driver->input_active = 1; driver->flags |= SDF_OPEN_READ; + } if (file->f_mode & FMODE_WRITE) { + driver->output_size = 0; driver->output_front = 0; driver->output_rear = 0; driver->output_count = 0; @@ -308,8 +798,15 @@ return 0; } -static void sparcaudio_release(struct inode * inode, struct file * file) +static int sparcaudio_release(struct inode * inode, struct file * file) { + /* Anything in the queue? */ + sparcaudio_sync_output(driver); + + /* Stop input */ + driver->ops->stop_input(driver); + driver->input_active = 0; + /* Wait for any output still in the queue to be played. */ if (driver->output_count > 0) interruptible_sleep_on(&driver->output_drain_wait); @@ -331,10 +828,12 @@ MOD_DEC_USE_COUNT; wake_up_interruptible(&driver->open_wait); + + return 0; } static struct file_operations sparcaudio_fops = { - sparcaudio_lseek, + sparcaudio_llseek, sparcaudio_read, sparcaudio_write, NULL, /* sparcaudio_readdir */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/audio.h linux/drivers/sbus/audio/audio.h --- v2.1.78/linux/drivers/sbus/audio/audio.h Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/audio/audio.h Mon Jan 12 15:15:45 1998 @@ -82,12 +82,13 @@ /* * Audio encoding types */ -#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ -#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ -#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ -#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */ -#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ -#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ +#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ +#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ +#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ +#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */ +#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ +#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ +#define AUDIO_ENCODING_LINEARLE (106) /* Linear PCM LE encoding */ /* * These ranges apply to record, play, and monitor gain values @@ -136,6 +137,8 @@ #define AUDIO_LINE_IN 0x02 /* input from line in */ #define AUDIO_CD 0x04 /* input from on-board CD inputs */ #define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */ +/* Supposedly an undocumented feature of the 4231 */ +#define AUDIO_ANALOG_LOOPBACK 0x40 /* @@ -152,6 +155,14 @@ /* + * These allow testing for what the user wants to set + */ +#define AUD_INITVALUE (~0) +#define Modify(X) ((unsigned int)(X) != AUD_INITVALUE) +#define Modifys(X) ((X) != (unsigned short)AUD_INITVALUE) +#define Modifyc(X) ((X) != (unsigned char)AUD_INITVALUE) + +/* * Parameter for the AUDIO_GETDEV ioctl to determine current * audio devices. */ @@ -192,6 +203,16 @@ #define AUDIO_SETINFO _IOWR('A', 2, audio_info_t) #define AUDIO_DRAIN _IO('A', 3) #define AUDIO_GETDEV _IOR('A', 4, audio_device_t) +#define AUDIO_GETDEV_SUNOS _IOR('A', 4, int) + +/* Define possible audio hardware configurations for + * old SunOS-style AUDIO_GETDEV ioctl */ + +#define AUDIO_DEV_UNKNOWN (0) /* not defined */ +#define AUDIO_DEV_AMD (1) /* audioamd device */ +#define AUDIO_DEV_SPEAKERBOX (2) /* dbri device with speakerbox */ +#define AUDIO_DEV_CODEC (3) /* dbri device (internal speaker) */ +#define AUDIO_DEV_CS4231 (5) /* cs4231 device */ /* * The following ioctl sets the audio device into an internal loopback mode, @@ -214,8 +235,6 @@ }; #endif - - /* * Linux kernel internal implementation. */ @@ -245,10 +264,17 @@ /* Support for a circular queue of output buffers. */ __u8 **output_buffers; - size_t *output_sizes; + size_t *output_sizes, output_size; int num_output_buffers, output_front, output_rear; int output_count, output_active; struct wait_queue *output_write_wait, *output_drain_wait; + + /* Support for a circular queue of input buffers. */ + __u8 **input_buffers; + int input_offset; + int num_input_buffers, input_front, input_rear; + int input_count, input_active; + struct wait_queue *input_read_wait; }; struct sparcaudio_operations @@ -272,6 +298,77 @@ /* Return driver name/version to caller. (/dev/audio specific) */ void (*sunaudio_getdev)(struct sparcaudio_driver *, audio_device_t *); + + /* Get and set the output volume. (0-255) */ + int (*set_output_volume)(struct sparcaudio_driver *, int); + int (*get_output_volume)(struct sparcaudio_driver *); + + /* Get and set the input volume. (0-255) */ + int (*set_input_volume)(struct sparcaudio_driver *, int); + int (*get_input_volume)(struct sparcaudio_driver *); + + /* Get and set the monitor volume. (0-255) */ + int (*set_monitor_volume)(struct sparcaudio_driver *, int); + int (*get_monitor_volume)(struct sparcaudio_driver *); + + /* Get and set the output balance. (0-64) */ + int (*set_output_balance)(struct sparcaudio_driver *, int); + int (*get_output_balance)(struct sparcaudio_driver *); + + /* Get and set the input balance. (0-64) */ + int (*set_input_balance)(struct sparcaudio_driver *, int); + int (*get_input_balance)(struct sparcaudio_driver *); + + /* Get and set the output channels. (1-4) */ + int (*set_output_channels)(struct sparcaudio_driver *, int); + int (*get_output_channels)(struct sparcaudio_driver *); + + /* Get and set the input channels. (1-4) */ + int (*set_input_channels)(struct sparcaudio_driver *, int); + int (*get_input_channels)(struct sparcaudio_driver *); + + /* Get and set the output precision. (8-32) */ + int (*set_output_precision)(struct sparcaudio_driver *, int); + int (*get_output_precision)(struct sparcaudio_driver *); + + /* Get and set the input precision. (8-32) */ + int (*set_input_precision)(struct sparcaudio_driver *, int); + int (*get_input_precision)(struct sparcaudio_driver *); + + /* Get and set the output port. () */ + int (*set_output_port)(struct sparcaudio_driver *, int); + int (*get_output_port)(struct sparcaudio_driver *); + + /* Get and set the input port. () */ + int (*set_input_port)(struct sparcaudio_driver *, int); + int (*get_input_port)(struct sparcaudio_driver *); + + /* Get and set the output encoding. () */ + int (*set_output_encoding)(struct sparcaudio_driver *, int); + int (*get_output_encoding)(struct sparcaudio_driver *); + + /* Get and set the input encoding. () */ + int (*set_input_encoding)(struct sparcaudio_driver *, int); + int (*get_input_encoding)(struct sparcaudio_driver *); + + /* Get and set the output rate. () */ + int (*set_output_rate)(struct sparcaudio_driver *, int); + int (*get_output_rate)(struct sparcaudio_driver *); + + /* Get and set the input rate. () */ + int (*set_input_rate)(struct sparcaudio_driver *, int); + int (*get_input_rate)(struct sparcaudio_driver *); + + /* Return driver number to caller. (SunOS /dev/audio specific) */ + int (*sunaudio_getdev_sunos)(struct sparcaudio_driver *); + + /* Get available ports */ + int (*get_output_ports)(struct sparcaudio_driver *); + int (*get_input_ports)(struct sparcaudio_driver *); + + /* Get and set output mute */ + int (*set_output_muted)(struct sparcaudio_driver *, int); + int (*get_output_muted)(struct sparcaudio_driver *); }; extern int register_sparcaudio_driver(struct sparcaudio_driver *); @@ -282,6 +379,6 @@ extern int amd7930_init(void); extern int cs4231_init(void); -#endif +#endif /* __KERNEL__ */ -#endif +#endif /* _AUDIO_H */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/cs4215.h linux/drivers/sbus/audio/cs4215.h --- v2.1.78/linux/drivers/sbus/audio/cs4215.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/audio/cs4215.h Mon Jan 12 15:15:45 1998 @@ -0,0 +1,120 @@ +/* + * drivers/sbus/audio/cs4215.h + * + * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) + * Used with dbri.h + */ + +#ifndef _CS4215_H_ +#define _CS4215_H_ + +struct cs4215 { + __u8 data[4]; /* Data mode: Time slots 5-8 */ + __u8 ctrl[4]; /* Ctrl mode: Time slots 1-4 */ + __volatile__ struct dbri_mem td; + __volatile__ struct dbri_mem rd; + __u8 version; + __u8 onboard; +}; + + +/* + * Control mode first + */ + +/* Time Slot 1, Status register */ +#define CS4215_CLB (1<<2) /* Control Latch Bit */ +#define CS4215_OLB (1<<3) /* 1: line: 2.0V, speaker 4V */ + /* 0: line: 2.8V, speaker 8V */ +#define CS4215_MLB (1<<4) /* 1: Microphone: 20dB gain disabled */ +#define CS4215_RSRVD_1 (1<<5) + + +/* Time Slot 2, Data Format Register */ +#define CS4215_DFR_LINEAR16 0 +#define CS4215_DFR_ULAW 1 +#define CS4215_DFR_ALAW 2 +#define CS4215_DFR_LINEAR8 3 +#define CS4215_DFR_STEREO (1<<2) +static struct { + unsigned short freq; + unsigned char xtal; + unsigned char csval; +} CS4215_FREQ[] = { + { 8000, 1, (0<<3) }, + { 16000, 1, (1<<3) }, + { 27429, 1, (2<<3) }, /* Actually 24428.57 */ + { 32000, 1, (3<<3) }, + /* { NA, 1, (4<<3) }, */ + /* { NA, 1, (5<<3) }, */ + { 48000, 1, (6<<3) }, + { 9600, 1, (7<<3) }, + { 5513, 2, (0<<3) }, /* Actually 5512.5 */ + { 11025, 2, (1<<3) }, + { 18900, 2, (2<<3) }, + { 22050, 2, (3<<3) }, + { 37800, 2, (4<<3) }, + { 44100, 2, (5<<3) }, + { 33075, 2, (6<<3) }, + { 6615, 2, (7<<3) }, + { 0, 0, 0 } +}; +#define CS4215_HPF (1<<7) /* High Pass Filter, 1: Enabled */ + +#define CS4215_12_MASK 0xfcbf /* Mask off reseved bits in slot 1 & 2 */ + +/* Time Slot 3, Serial Port Control register */ +#define CS4215_XEN (1<<0) /* 0: Enable serial output */ +#define CS4215_XCLK (1<<1) /* 1: Master mode: Generate SCLK */ +#define CS4215_BSEL_64 (0<<2) /* Bitrate: 64 bits per frame */ +#define CS4215_BSEL_128 (1<<2) +#define CS4215_BSEL_256 (2<<2) +#define CS4215_MCK_MAST (0<<4) /* Master clock */ +#define CS4215_MCK_XTL1 (1<<4) /* 24.576 MHz clock source */ +#define CS4215_MCK_XTL2 (2<<4) /* 16.9344 MHz clock source */ +#define CS4215_MCK_CLK1 (3<<4) /* Clockin, 256 x Fs */ +#define CS4215_MCK_CLK2 (4<<4) /* Clockin, see DFR */ + +/* Time Slot 4, Test Register */ +#define CS4215_DAD (1<<0) /* 0:Digital-Dig loop, 1:Dig-Analog-Dig loop */ +#define CS4215_ENL (1<<1) /* Enable Loopback Testing */ + +/* Time Slot 5, Parallel Port Register */ +/* Read only here and the same as the in data mode */ + +/* Time Slot 6, Reserved */ + +/* Time Slot 7, Version Register */ +#define CS4215_VERSION_MASK 0xf /* Known versions 0/C, 1/D, 2/E */ + +/* Time Slot 8, Reserved */ + + + +/* + * Data mode + */ +/* Time Slot 1-2: Left Channel Data, 2-3: Right Channel Data */ + +/* Time Slot 5, Output Setting */ +#define CS4215_LO(v) v /* Left Output Attenuation 0x3f: -94.5 dB */ +#define CS4215_LE (1<<6) /* Line Out Enable */ +#define CS4215_HE (1<<7) /* Headphone Enable */ + +/* Time Slot 6, Output Setting */ +#define CS4215_RO(v) v /* Right Output Attenuation 0x3f: -94.5 dB */ +#define CS4215_SE (1<<6) /* Line Out Enable */ +#define CS4215_ADI (1<<7) /* A/D Data Invalid: Busy in calibration */ + +/* Time Slot 7, Input Setting */ +#define CS4215_LG(v) v /* Left Gain Setting 0xf: 22.5 dB */ +#define CS4215_IS (1<<4) /* Input Select: 1=Microphone, 0=Line */ +#define CS4215_OVR (1<<5) /* 1: Overrange condition occured */ +#define CS4215_PIO0 (1<<6) /* Parallel I/O 0 */ +#define CS4215_PIO1 (1<<7) + +/* Time Slot 8, Input Setting */ +#define CS4215_RG(v) v /* Right Gain Setting 0xf: 22.5 dB */ +#define CS4215_MA(v) (v<<4) /* Monitor Path Attenuation 0xf: mute */ + +#endif diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.1.78/linux/drivers/sbus/audio/cs4231.c Tue May 13 22:41:12 1997 +++ linux/drivers/sbus/audio/cs4231.c Mon Jan 12 15:15:45 1998 @@ -44,8 +44,6 @@ static void cs4231_output_muted(struct sparcaudio_driver *drv, unsigned int value); static void cs4231_mute(struct sparcaudio_driver *drv); static void cs4231_pollinput(struct sparcaudio_driver *drv); -static int cs4231_attach(struct sparcaudio_driver *drv, int node, - struct linux_sbus *sbus); #define CHIP_BUG udelay(100); cs4231_ready(drv); udelay(1000); @@ -623,56 +621,16 @@ cs4231_audio_getdev, }; -/* Probe for the cs4231 chip and then attach the driver. */ -#ifdef MODULE -int init_module(void) -#else -__initfunc(int cs4231_init(void)) -#endif -{ - struct linux_sbus *bus; - struct linux_sbus_device *sdev; - int cs4231_node; - - /* Find the PROM CS4231 node. */ - /* There's an easier way, and I should FIXME */ - cs4231_node = prom_getchild(prom_root_node); - cs4231_node = prom_searchsiblings(cs4231_node,"iommu"); - cs4231_node = prom_getchild(cs4231_node); - cs4231_node = prom_searchsiblings(cs4231_node,"sbus"); - cs4231_node = prom_getchild(cs4231_node); - cs4231_node = prom_searchsiblings(cs4231_node,"SUNW,CS4231"); - - if (cs4231_node && cs4231_attach(&drivers[0], cs4231_node, NULL) == 0) - num_drivers = 1; - else - num_drivers = 0; - - /* Probe each SBUS for cs4231 chips. */ - for_all_sbusdev(sdev,bus) { - if (!strcmp(sdev->prom_name, "SUNW,CS4231")) { - /* Don't go over the max number of drivers. */ - if (num_drivers >= MAX_DRIVERS) - continue; - - if (cs4231_attach(&drivers[num_drivers], - sdev->prom_node, sdev->my_bus) == 0) - num_drivers++; - } - } - - /* Only return success if we found some cs4231 chips. */ - return (num_drivers > 0) ? 0 : -EIO; -} - /* Attach to an cs4231 chip given its PROM node. */ -static int cs4231_attach(struct sparcaudio_driver *drv, int node, - struct linux_sbus *sbus) +static inline int +cs4231_attach(struct sparcaudio_driver *drv, struct linux_sbus_device *sdev) { - struct linux_prom_registers regs; - struct linux_prom_irqs irq; struct cs4231_chip *cs4231_chip; int err; + struct linux_sbus *sbus = sdev->my_bus; +#ifdef __sparc_v9__ + struct devid_cookie dcookie; +#endif /* Allocate our private information structure. */ drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL); @@ -690,12 +648,11 @@ #endif /* Map the registers into memory. */ - prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); - if (sbus) - prom_apply_sbus_ranges(sbus, ®s, 1); - cs4231_chip->regs_size = regs.reg_size; - cs4231_chip->pioregs = sparc_alloc_io(regs.phys_addr, 0, regs.reg_size, - "cs4231", regs.which_io, 0); + prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev); + cs4231_chip->regs_size = sdev->reg_addrs[0].reg_size; + cs4231_chip->pioregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, + "cs4231", sdev->reg_addrs[0].which_io, 0); if (!cs4231_chip->pioregs) { printk(KERN_ERR "cs4231: could not allocate registers\n"); kfree(drv->private); @@ -706,9 +663,18 @@ cs4231_reset(drv); /* Attach the interrupt handler to the audio interrupt. */ - prom_getproperty(node, "intr", (char *)&irq, sizeof(irq)); - cs4231_chip->irq = irq.pri; - request_irq(cs4231_chip->irq, cs4231_interrupt, SA_INTERRUPT, "cs4231", NULL); + cs4231_chip->irq = sdev->irqs[0].pri; + +#ifndef __sparc_v9__ + request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv); +#else + dcookie.real_dev_id = s; + dcookie.imap = dcookie.iclr = 0; + dcookie.pil = -1; + dcookie.bus_cookie = sdev->my_bus; + request_irq (cs4231_chip->irq, cs4231_interrupt, (SA_SHIRQ | SA_SBUS | SA_DCOOKIE), "cs4231", drv); + cs4231_chip->irq = dcookie.ret_ino; +#endif enable_irq(cs4231_chip->irq); /* Register ourselves with the midlevel audio driver. */ @@ -728,6 +694,32 @@ /* Success! */ return 0; +} + +/* Probe for the cs4231 chip and then attach the driver. */ +#ifdef MODULE +int init_module(void) +#else +__initfunc(int cs4231_init(void)) +#endif +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev; + + /* Probe each SBUS for cs4231 chips. */ + for_all_sbusdev(sdev,bus) { + if (!strcmp(sdev->prom_name, "SUNW,CS4231")) { + /* Don't go over the max number of drivers. */ + if (num_drivers >= MAX_DRIVERS) + continue; + + if (cs4231_attach(&drivers[num_drivers], sdev) == 0) + num_drivers++; + } + } + + /* Only return success if we found some cs4231 chips. */ + return (num_drivers > 0) ? 0 : -EIO; } #ifdef MODULE diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c --- v2.1.78/linux/drivers/sbus/audio/dbri.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/audio/dbri.c Mon Jan 12 15:15:45 1998 @@ -0,0 +1,715 @@ +/* + * drivers/sbus/audio/dbri.c + * + * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) + * The SparcLinux interface was adopted from the CS4231 driver. + * + * This is the lowlevel driver for the DBRI & MMCODEC duo used for ISDN & AUDIO + * on Sun SPARCstation 10, 20, LX and Voyager models. + * NOTE: This driver only supports audio for now, there is NO SUPPORT for ISDN. + * + * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel + * data time multiplexer with ISDN support (aka T7259) + * Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel. + * CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?). + * Documentation: + * - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Tranceiver" from + * Sparc Technology Business (courtesy of Sun Support) + * - Data sheet of the T7903, a newer but very similar ISA bus equivalent + * available from the Lucent (formarly AT&T microelectronics) home + * page. + * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec + * Interfaces: CHI, Audio In & Out, 2 bits parallel + * Documentation: from the Crystal Semiconductor home page. + * + * The DBRI is a 32 pipe machine, each pipe can transfer some bits between + * memory and a serial device (long pipes, nr 0-15) or between two serial + * devices (short pipes, nr 16-31), or simply send a fixed data to a serial + * device (short pipes). + * A timeslot defines the bit-offset and nr of bits read from a serial device. + * The timeslots are linked to 6 circular lists, one for each direction for + * each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes + * (the second one is a monitor/tee pipe, valid only for serial input). + * + * The mmcodec is connected via the CHI bus and needs the data & some + * parameters (volume, balance, output selection) timemultiplexed in 8 byte + * chunks. It also has a control mode, which serves for audio format setting. + * + * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on + * the same CHI bus, so I thought perhaps it is possible to use the onboard + * & the speakerbox codec simultanously, giving 2 (not very independent :-) + * audio devices. But the SUN HW group decided against it, at least on my + * LX the speakerbox connector has at least 1 pin missing and 1 wrongly + * connected. + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audio.h" +#include "dbri.h" + + + +#define DBRI_DEBUG + +#ifdef DBRI_DEBUG + +#define dprintk(a, x) if(dbri_debug & a) printk x +#define D_GEN (1<<0) +#define D_INT (1<<1) +#define D_CMD (1<<2) +#define D_MM (1<<3) +#define D_USR (1<<4) + +static int dbri_debug = D_GEN|D_INT|D_CMD|D_MM|D_USR; +static char *cmds[] = { + "WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS", + "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV" +}; + +/* Bit hunting */ +#define dumpcmd {int i; for(i=0; icmd[i]); } + +#else + +#define dprintk(a, x) +#define dumpcmd + +#endif /* DBRI_DEBUG */ + + + +#define MAX_DRIVERS 2 /* Increase this if need more than 2 DBRI's */ + +#define WAIT_INTR1 0xbe +#define WAIT_INTR2 0xbf + +static struct sparcaudio_driver drivers[MAX_DRIVERS]; +static char drv_name[] = "DBRI/audio"; +static int num_drivers; +static int dbri_cmdlocked = 0; + + +/* + * Make sure, that we can send a command to the dbri + */ +static int dbri_cmdlock(struct dbri *dbri) +{ + unsigned long flags; + int was_sleeping = 0; + + save_flags(flags); + cli(); + + if(dbri_cmdlocked) { + interruptible_sleep_on(&dbri->wait); + was_sleeping = 1; + } + if(dbri_cmdlocked) + return -EINTR; + dbri_cmdlocked = 1; + + restore_flags(flags); + + if(was_sleeping) + dprintk(D_INT, ("DBRI: Just woke up\n")); + return 0; +} + +static void dummy() +{ +} + +static struct sparcaudio_operations dbri_ops = { + dummy, /* dbri_open, */ + dummy, /* dbri_release, */ + dummy, /* dbri_ioctl, */ + dummy, /* dbri_start_output, */ + dummy, /* dbri_stop_output, */ + dummy, /* dbri_start_input, */ + dummy, /* dbri_stop_input, */ + dummy, /* dbri_audio_getdev, */ +}; + +static void dbri_reset(struct sparcaudio_driver *drv) +{ + struct dbri *dbri = (struct dbri *)drv->private; + int i; + + dprintk(D_GEN, ("DBRI: reset 0:%x 2:%x 8:%x 9:%x\n", + dbri->regs->reg0, dbri->regs->reg2, + dbri->regs->reg8, dbri->regs->reg9)); + + dbri->regs->reg0 = D_R; /* Soft Reset */ + for(i = 0; (dbri->regs->reg0 & D_R) && i < 10; i++) + udelay(10); +} + +static void dbri_detach(struct sparcaudio_driver *drv) +{ + struct dbri *info = (struct dbri *)drv->private; + + dbri_reset(drv); + unregister_sparcaudio_driver(drv); + free_irq(info->irq, drv); + sparc_free_io(info->regs, info->regs_size); + kfree(drv->private); +} + + +static void dbri_init(struct sparcaudio_driver *drv) +{ + struct dbri *dbri = (struct dbri *)drv->private; + int n; + + dbri_reset(drv); + dbri->wait = NULL; + + dprintk(D_GEN, ("DBRI: init: cmd: %x, int: %x\n", + (int)dbri->cmd, (int)dbri->intr)); + + /* + * Initialize the interrupt ringbuffer. + */ + for(n = 0; n < DBRI_NO_INTS-1; n++) + dbri->intr[n * DBRI_INT_BLK] = + (int)(&dbri->intr[(n+1)*DBRI_INT_BLK]); + dbri->intr[n * DBRI_INT_BLK] = (int)(dbri->intr); + dbri->dbri_irqp = 1; + + dbri->regs->reg0 |= (D_G|D_S|D_E); + + /* + * Set up the interrupt queue + */ + (void)dbri_cmdlock(dbri); + + n = 0; + dbri->cmd[n++] = DBRI_CMD(D_IIQ, 0, 0); + dbri->cmd[n++] = (int)(dbri->intr); + dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1); + dbri->regs->reg8 = (int)dbri->cmd; +} + + + +/* + * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr. + * So we have to reverse the bits. Note: only 1, 2 or 4 bytes are supported. + */ +static __u32 reverse_bytes(__u32 b, int len) +{ + switch(len) { + case 4: b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16); + case 2: b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8); + case 1: b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4); + b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2); + b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1); + } + return b; +} + + + +static void mmcodec_default(struct cs4215 *mm) +{ + /* + * No action, memory resetting only. + * + * Data Time Slot 5-8 + * Speaker,Line and Headphone enable. Gain set to the half. + * Input is mike. + */ + mm->data[0] = CS4215_LO(0x20) | CS4215_HE|CS4215_LE; + mm->data[1] = CS4215_RO(0x20) | CS4215_SE; + mm->data[2] = CS4215_LG( 0x8) | CS4215_IS; + mm->data[3] = CS4215_RG( 0x8) | CS4215_MA(0xf); + + /* + * Control Time Slot 1-4 + * 0: Default I/O voltage scale + * 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled + * 2: Serial enable, CHI master, 1 CHI device (64bit), clock 1 + * 3: Tests disabled + */ + mm->ctrl[0] = CS4215_RSRVD_1; + mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval; + mm->ctrl[2] = CS4215_XEN | CS4215_XCLK | + CS4215_BSEL_128 | CS4215_FREQ[0].xtal; + mm->ctrl[3] = 0; +} + +static void mmcodec_init_data(struct dbri *dbri) +{ + int val, n = 0; + + dbri_cmdlock(dbri); + + /* + * Data mode: + * Pipe 4: Send timeslots 1-4 (audio data) + * Pipe 17: Send timeslots 5-8 (part of ctrl data) + * Pipe 6: Receive timeslots 1-4 (audio data) + * Pipe 19: Receive timeslots 6-7. We can only receive 20 bits via + * interrupt, and the rest of the data (slot 5 and 8) is + * not relevant for us (only for doublechecking). + */ + + /* Transmit & Receive Memory setup */ + dbri->mm.td.flags = DBRI_TD_F|DBRI_TD_D|DBRI_TD_CNT(0); + dbri->mm.td.ba = 0; + dbri->mm.td.nda = (__u32)&dbri->mm.td; + dbri->mm.td.status = 0; + + dbri->mm.td.flags = DBRI_RD_BCNT(0); + dbri->mm.td.ba = 0; + dbri->mm.td.nda = (__u32)&dbri->mm.rd; + dbri->mm.td.status = 0; + + /* Pipe 4: SDP + DTS */ + val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_C|D_SDP_MSB|D_PIPE(D_P_4); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = (__u32)&dbri->mm.td; + + val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_4); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = 0; + dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_16); + + + /* Pipe 17: SDP + DTS + SSP */ + val = D_SDP_FIXED|D_SDP_TO_SER|D_SDP_C|D_PIPE(D_P_17); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; /* Fixed data */ + + val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_4) | D_PIPE(D_P_17); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = 0; + dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(32) | D_TS_NONCONTIG | + D_TS_MON(D_P_4) | D_TS_NEXT(D_P_16); + + dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17)); + dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.data, 4); + + + /* Pipe 6: SDP + DTS */ + val=D_SDP_MEM|D_SDP_FROM_SER|D_SDP_C|D_SDP_MSB|D_PIPE(D_P_6); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = (__u32)&dbri->mm.rd; + + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_6); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_16); + dbri->cmd[n++] = 0; + + + /* Pipe 19: SDP + DTS */ + val = D_SDP_FIXED|D_SDP_FROM_SER|D_SDP_P|D_SDP_C|D_PIPE(D_P_19); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; /* Fixed data */ + + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_6) | D_PIPE(D_P_19); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(40) | D_TS_NONCONTIG | + D_TS_MON(D_P_6) | D_TS_NEXT(D_P_16); + dbri->cmd[n++] = 0; + + dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1); + + dbri->regs->reg8 = (int)dbri->cmd; +} + + +/* + * Send the control information (i.e. audio format) + */ +static void mmcodec_setctrl(struct dbri *dbri) +{ + int n = 0, val; + + /* + * Enable Command mode: Set PIO3 to 0, then wait + * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec + */ + val = D_ENPIO | D_PIO1 | (dbri->mm.onboard ? D_PIO0 : D_PIO2); + dbri->regs->reg2 = val; + udelay(34); + + dbri_cmdlock(dbri); + + /* + * Control mode: + * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly) + * Pipe 18: Receive timeslot 1 (clb). + * Pipe 19: Receive timeslot 7 (version). + */ + + /* Set CHI Anchor: Pipe 16. This should take care of the rest. */ + val = D_DTS_VI | D_DTS_VO | D_DTS_INS | + D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); + dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); + + + /* Setup the pipes first */ + val = D_SDP_FIXED|D_SDP_TO_SER|D_SDP_P|D_SDP_C|D_PIPE(D_P_17); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_P|D_SDP_C|D_PIPE(D_P_18); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_P|D_SDP_C|D_PIPE(D_P_19); + dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); + dbri->cmd[n++] = 0; + + /* Fill in the data to send */ + dbri->mm.ctrl[0] &= ~CS4215_CLB; + dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17)); + dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4); + + dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); + + + + /* Link the timeslots */ + val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_17); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = 0; + dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(256) | D_TS_NEXT(D_P_16); + + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_18); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(0) | D_TS_NEXT(D_P_16); + dbri->cmd[n++] = 0; + + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_18) | D_PIPE(D_P_19); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(48) | D_TS_NEXT(D_P_16); + /* + * According to the manual we should also specify + * D_TS_NONCONTIG | D_TS_MON(D_P_18), but the machine freezes + * if we do that. Can somebody explain me why? + */ + dbri->cmd[n++] = 0; + + + /* Setup DBRI for CHI Master */ + dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_REN); + dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(6) | D_CHI_FD | + D_CHI_IR | D_CHI_EN); + dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); + dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN); + + dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, 0); + dbri->regs->reg8 = (int)dbri->cmd; + + /* Wait for the data from the CS4215 */ + interruptible_sleep_on(&dbri->int_wait); +printk("Woke up (1) reg2: %x\n", dbri->regs->reg2); + + + /* Now switch back to data mode */ + n = 0; + /* CHI Anchor: Stop Send/Receive */ + val = D_DTS_VI | D_DTS_VO | D_DTS_INS | + D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16); + dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); + dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); + dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); + + dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, 0x17); + dbri->regs->reg8 = (int)dbri->cmd; + +#if 0 + dbri->mm.ctrl[0] |= CS4215_CLB; + dbri->cmd[n++] = DBRI_CMD(D_SSP, 1, D_PIPE(D_P_17)); + dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4); + + /* Setup DBRI for CHI Slave */ + dbri->cmd[n++] = DBRI_CMD(D_CDM, 1, D_CDM_XCE|D_CDM_REN); + dbri->cmd[n++] = DBRI_CMD(D_CHI, 1, D_CHI_CHICM(1) | D_CHI_FD | + D_CHI_IR | D_CHI_EN); + dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 1, 0x16); + dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN); + + dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, 0x17); + dbri->regs->reg8 = (int)dbri->cmd; + + dbri->regs->reg2 = D_ENPIO | D_PIO3 | + (dbri->mm.onboard ? D_PIO0 : D_PIO2); +#endif + + /* We are ready */ + dbri_cmdlocked = 0; + wake_up(&dbri->wait); +} + +static int mmcodec_init(struct sparcaudio_driver *drv) +{ + struct dbri *dbri = (struct dbri *)drv->private; + int reg2 = dbri->regs->reg2; + + + /* Look for the cs4215 chips */ + if(reg2 & D_PIO2) { + dprintk(D_MM, ("DBRI: Onboard CS4215 detected\n")); + dbri->mm.onboard = 1; + } + if(reg2 & D_PIO0) { + dprintk(D_MM, ("DBRI: Speakerbox detected\n")); + dbri->mm.onboard = 0; + } + + + /* Using the Speakerbox, if both are attached. */ + if((reg2 & D_PIO2) && (reg2 & D_PIO0)) { + printk("DBRI: Using speakerbox / ignoring onboard mmcodec.\n"); + dbri->regs->reg2 = D_ENPIO2; + dbri->mm.onboard = 0; + } + if( !(reg2 & (D_PIO0|D_PIO2)) ) { + printk("DBRI: no mmcodec found.\n"); + return -EIO; + } + + + /* Now talk to our baby */ + dbri->regs->reg0 |= D_C; /* Enable CHI */ + + mmcodec_default(&dbri->mm); + + dbri->mm.version = 0xff; + mmcodec_setctrl(dbri); + if(dbri->mm.version == 0xff) + return -EIO; + + /* + mmcodec_init_data(dbri, &n); + */ + + return 0; +} + +void dbri_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; + struct dbri *dbri = (struct dbri *)drv->private; + int x, val; + static int numint = 0; + + /* + * Read it, so the interrupt goes away. + */ + x = dbri->regs->reg1; + if(numint++ > 20) { + dbri->regs->reg0 = D_R; /* Soft Reset */ + numint = 0; + printk("Soft reset\n"); + } + + if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) { + /* + * What should I do here ? + */ + if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n"); + if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n"); + if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n"); + if(x & D_MBE) printk("DBRI: Burst Error on SBus\n"); + } + + if (!(x & D_IR)) /* Not for us */ + return; + + x = dbri->intr[dbri->dbri_irqp]; + while (x != 0) { + dbri->intr[dbri->dbri_irqp] = 0; + + if(D_INTR_GETCHAN(x) == D_INTR_CMD) { + dprintk(D_INT,("DBRI: INTR: Command: %-5s Value:%d\n", + cmds[D_INTR_GETCMD(x)], D_INTR_GETVAL(x))); + } else { + dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n", + D_INTR_GETCHAN(x), D_INTR_GETCODE(x), + D_INTR_GETRVAL(x))); + } + + val = D_INTR_GETVAL(x); + + switch(D_INTR_GETCHAN(x)) { + case D_INTR_CMD: + if(D_INTR_GETCMD(x) == D_WAIT) + if(val == WAIT_INTR1) { + dbri_cmdlocked = 0; + wake_up(&dbri->wait); + } + if(val == WAIT_INTR2) + wake_up(&dbri->int_wait); + break; + case D_P_18: + if(val != 0) { + x = reverse_bytes(val,2)&CS4215_12_MASK; +printk("Comparing int: %x with hi(%x)\n", x, *(int *)dbri->mm.ctrl); + if(x == (*(int *)dbri->mm.ctrl >> 16)) +{ +printk("Comp ok\n"); + wake_up(&dbri->int_wait); +} + } + break; + case D_P_19: + if(val != 0) { + dbri->mm.version = + reverse_bytes(val, 1) & 0xf; + } + break; + } + + dbri->dbri_irqp++; + if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK)) + dbri->dbri_irqp = 1; + else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0) + dbri->dbri_irqp++; + x = dbri->intr[dbri->dbri_irqp]; + } +} + + + + + +static int dbri_attach(struct sparcaudio_driver *drv, + struct linux_sbus_device *sdev) +{ + struct dbri *dbri; + struct linux_prom_irqs irq; + int err; + + if (sdev->prom_name[9] < 'e') { + printk(KERN_ERR "DBRI: unsupported chip version %c found.\n", + sdev->prom_name[9]); + return -EIO; + } + + drv->ops = &dbri_ops; + drv->private = kmalloc(sizeof(struct dbri), GFP_KERNEL); + if (!drv->private) + return -ENOMEM; + dbri = (struct dbri *)drv->private; + + memset(dbri, 0, sizeof(*dbri)); + + dbri->dbri_version = sdev->prom_name[9]; + + /* Map the registers into memory. */ + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); + dbri->regs_size = sdev->reg_addrs[0].reg_size; + dbri->regs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, + drv_name, sdev->reg_addrs[0].which_io, 0); + if (!dbri->regs) { + printk(KERN_ERR "DBRI: could not allocate registers\n"); + kfree(drv->private); + return -EIO; + } + + prom_getproperty(sdev->prom_node, "intr", (char *)&irq, sizeof(irq)); + dbri->irq = irq.pri; + + err = request_irq(dbri->irq, dbri_intr, SA_SHIRQ, "DBRI/audio", drv); + if (err) { + printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq); + sparc_free_io(dbri->regs, dbri->regs_size); + kfree(drv->private); + return err; + } + + /* Register ourselves with the midlevel audio driver. */ + err = register_sparcaudio_driver(drv); + if (err) { + printk(KERN_ERR "DBRI: unable to register audio\n"); + free_irq(dbri->irq, drv); + sparc_free_io(dbri->regs, dbri->regs_size); + kfree(drv->private); + return err; + } + + dbri_init(drv); + err = mmcodec_init(drv); + if(err) { + dbri_detach(drv); + return err; + } + + + dbri->perchip_info.play.active = dbri->perchip_info.play.pause = 0; + dbri->perchip_info.record.active = dbri->perchip_info.record.pause = 0; + + printk(KERN_INFO "audio%d at 0x%lx (irq %d) is DBRI(%c)+CS4215(%d)\n", + num_drivers, (unsigned long)dbri->regs, + dbri->irq, dbri->dbri_version, dbri->mm.version); + + return 0; +} + +/* Probe for the dbri chip and then attach the driver. */ +#ifdef MODULE +int init_module(void) +#else +__initfunc(int dbri_init(void)) +#endif +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev; + + num_drivers = 0; + + /* Probe each SBUS for the DBRI chip(s). */ + for_all_sbusdev(sdev,bus) { + /* + * The version is coded in the last character + */ + if (!strncmp(sdev->prom_name, "SUNW,DBRI", 9)) { + dprintk(D_GEN, ("DBRI: Found %s in SBUS slot %d\n", + sdev->prom_name, sdev->slot)); + if (num_drivers >= MAX_DRIVERS) { + printk("DBRI: Ignoring slot %d\n", sdev->slot); + continue; + } + + if (dbri_attach(&drivers[num_drivers], sdev) == 0) + num_drivers++; + } + } + + return (num_drivers > 0) ? 0 : -EIO; +} + +#ifdef MODULE +void cleanup_module(void) +{ + register int i; + + for (i = 0; i < num_drivers; i++) { + dbri_detach(&drivers[i]); + num_drivers--; + } +} +#endif diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/audio/dbri.h linux/drivers/sbus/audio/dbri.h --- v2.1.78/linux/drivers/sbus/audio/dbri.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/audio/dbri.h Mon Jan 12 15:15:45 1998 @@ -0,0 +1,293 @@ +/* + * drivers/sbus/audio/cs4231.h + * + * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) + */ + +#ifndef _DBRI_H_ +#define _DBRI_H_ + +#include + +struct dbri_regs { + __volatile__ __u32 reg0; /* Status & Control */ + __volatile__ __u32 reg1; /* Mode & Interrupt */ + __volatile__ __u32 reg2; /* Parallel IO */ + __volatile__ __u32 reg3; /* Test */ + __volatile__ __u32 unused[4]; + __volatile__ __u32 reg8; /* Command Queue Pointer */ + __volatile__ __u32 reg9; /* Interrupt Queue Pointer */ +}; + +#define DBRI_NO_CMDS 64 +#define DBRI_NO_INTS 2 +#define DBRI_INT_BLK 64 + +#define DBRI_MM_ONB 1 +#define DBRI_MM_SB 2 + +struct dbri_mem { + __u32 flags; + __u32 ba; /* Transmit/Receive Buffer Address */ + __u32 nda; /* Next Descriptor Address */ + __u32 status; +}; + +#include "cs4215.h" + +/* This structure holds the information for both chips (DBRI & CS4215) */ +struct dbri { + int regs_size, irq; /* Needed for unload */ + + struct dbri_regs *regs; /* dbri HW regs */ + int dbri_version; /* 'e' and up is OK */ + int dbri_irqp; /* intr queue pointer */ + __volatile__ int cmd[DBRI_NO_CMDS]; /* Place for commands */ + __volatile__ int intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field */ + + struct cs4215 mm; /* mmcodec special info */ + + struct wait_queue *wait, *int_wait; /* Where to sleep if busy */ + struct audio_info perchip_info; +}; + + +/* DBRI Reg0 - Status Control Register - defines. (Page 17) */ +#define D_P (1<<15) /* Program command & queue pointer valid */ +#define D_G (1<<14) /* Allow 4-Word SBus Burst */ +#define D_S (1<<13) /* Allow 16-Word SBus Burst */ +#define D_E (1<<12) /* Allow 8-Word SBus Burst */ +#define D_X (1<<7) /* Sanity Timer Disable */ +#define D_T (1<<6) /* Permit activation of the TE interface */ +#define D_N (1<<5) /* Permit activation of the NT interface */ +#define D_C (1<<4) /* Permit activation of the CHI interface */ +#define D_F (1<<3) /* Force Sanity Timer Time-Out */ +#define D_D (1<<2) /* Disable Master Mode */ +#define D_H (1<<1) /* Halt for Analysis */ +#define D_R (1<<0) /* Soft Reset */ + + +/* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */ +#define D_LITTLE_END (1<<8) /* Byte Order */ +#define D_BIG_END (0<<8) /* Byte Order */ +#define D_MRR (1<<4) /* Multiple Error Ack on SBus (readonly) */ +#define D_MLE (1<<3) /* Multiple Late Error on SBus (readonly) */ +#define D_LBG (1<<2) /* Lost Bus Grant on SBus (readonly) */ +#define D_MBE (1<<1) /* Burst Error on SBus (readonly) */ +#define D_IR (1<<0) /* Interrupt Indicator (readonly) */ + + +/* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */ +#define D_ENPIO3 (1<<7) /* Enable Pin 3 */ +#define D_ENPIO2 (1<<6) /* Enable Pin 2 */ +#define D_ENPIO1 (1<<5) /* Enable Pin 1 */ +#define D_ENPIO0 (1<<4) /* Enable Pin 0 */ +#define D_ENPIO (0xf0) /* Enable all the pins */ +#define D_PIO3 (1<<3) /* Pin 3: 1: Data mode, 0: Ctrl mode */ +#define D_PIO2 (1<<2) /* Pin 2: 1: Onboard PDN */ +#define D_PIO1 (1<<1) /* Pin 1: 0: Reset */ +#define D_PIO0 (1<<0) /* Pin 0: 1: Speakerbox PDN */ + + +/* DBRI Commands (Page 20) */ +#define D_WAIT 0x0 /* Stop execution */ +#define D_PAUSE 0x1 /* Flush long pipes */ +#define D_JUMP 0x2 /* New command queue */ +#define D_IIQ 0x3 /* Initialize Interrupt Queue */ +#define D_REX 0x4 /* Report command execution via interrupt */ +#define D_SDP 0x5 /* Setup Data Pipe */ +#define D_CDP 0x6 /* Continue Data Pipe (reread NULL Pointer) */ +#define D_DTS 0x7 /* Define Time Slot */ +#define D_SSP 0x8 /* Set short Data Pipe */ +#define D_CHI 0x9 /* Set CHI Global Mode */ +#define D_NT 0xa /* NT Command */ +#define D_TE 0xb /* TE Command */ +#define D_CDEC 0xc /* Codec setup */ +#define D_TEST 0xd /* No comment */ +#define D_CDM 0xe /* CHI Data mode command */ + +#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (intr << 27) | value) + + +/* Special bits for some commands */ +#define D_PIPE(v) (v<<0) /* Pipe Nr: 0-15 long, 16-21 short */ + +/* Setup Data Pipe */ +/* IRM */ +#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value rcvd*/ +#define D_SDP_CHANGE (2<<18) /* Report any changes */ +#define D_SDP_EVERY (3<<18) /* Report any changes */ +#define D_SDP_EOL (1<<17) /* EOL interrupt enable */ +#define D_SDP_IDLE (1<<16) /* HDLC idle interrupt enable */ + +/* Pipe data MODE */ +#define D_SDP_MEM (0<<13) /* To/from memory */ +#define D_SDP_HDLC (2<<13) +#define D_SDP_HDLC_D (3<<13) /* D Channel (prio control)*/ +#define D_SDP_SER (4<<13) /* Serial to serial */ +#define D_SDP_FIXED (6<<13) /* Short only */ + +#define D_SDP_TO_SER (1<<12) /* Direction */ +#define D_SDP_FROM_SER (0<<12) /* Direction */ +#define D_SDP_MSB (1<<11) /* Bit order within Byte */ +#define D_SDP_LSB (0<<11) /* Bit order within Byte */ +#define D_SDP_P (1<<10) /* Pointer Valid */ +#define D_SDP_A (1<<8) /* Abort */ +#define D_SDP_C (1<<7) /* Clear */ + +/* Define Time Slot */ +#define D_DTS_VI (1<<17) /* Valid Input Time-Slot Descriptor */ +#define D_DTS_VO (1<<16) /* Valid Output Time-Slot Descriptor */ +#define D_DTS_INS (1<<15) /* Insert Time Slot */ +#define D_DTS_DEL (0<<15) /* Delete Time Slot */ +#define D_DTS_PRVIN(v) (v<<10) /* Previous In Pipe */ +#define D_DTS_PRVOUT(v) (v<<5) /* Previous Out Pipe */ + +/* Time Slot defines */ +#define D_TS_LEN(v) (v<<24) /* Number of bits in this time slot */ +#define D_TS_CYCLE(v) (v<<14) /* Bit Count at start of TS */ +#define D_TS_DI(v) (1<<13) /* Data Invert */ +#define D_TS_1CHANNEL (0<<10) /* Single Channel / Normal mode */ +#define D_TS_MONITOR (2<<10) /* Monitor pipe */ +#define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */ +#define D_TS_ANCHOR (7<<10) /* Starting short pipes */ +#define D_TS_MON(v) (v<<5) /* Monitor Pipe */ +#define D_TS_NEXT(v) (v<<0) /* Pipe Nr: 0-15 long, 16-21 short */ + +/* Concentration Highway Interface Modes */ +#define D_CHI_CHICM(v) (v<<16) /* Clock mode */ +#define D_CHI_IR (1<<15) /* Immediate Interrupt Report */ +#define D_CHI_EN (1<<14) /* CHIL Interrupt enabled */ +#define D_CHI_OD (1<<13) /* Open Drain Enable */ +#define D_CHI_FE (1<<12) /* Sample CHIFS on Rising Frame Edge */ +#define D_CHI_FD (1<<11) /* Frame Drive */ +#define D_CHI_BPF(v) (v<<0) /* Bits per Frame */ + +/* NT: These are here for completeness */ +#define D_NT_FBIT (1<<17) /* Frame Bit */ +#define D_NT_NBF (1<<16) /* Number of bad frames to loose framing */ +#define D_NT_IRM_IMM (1<<15) /* Interrupt Report & Mask: Immediate */ +#define D_NT_IRM_EN (1<<14) /* Interrupt Report & Mask: Enable */ +#define D_NT_ISNT (1<<13) /* Configfure interface as NT */ +#define D_NT_FT (1<<12) /* Fixed Timing */ +#define D_NT_EZ (1<<11) /* Echo Channel is Zeros */ +#define D_NT_IFA (1<<10) /* Inhibit Final Activation */ +#define D_NT_ACT (1<<9) /* Activate Interface */ +#define D_NT_MFE (1<<8) /* Multiframe Enable */ +#define D_NT_RLB(v) (1<<5) /* Remote Loopback */ +#define D_NT_LLB(v) (1<<2) /* Local Loopback */ +#define D_NT_FACT (1<<1) /* Force Activation */ +#define D_NT_ABV (1<<0) /* Activate Bipolar Violation */ + +/* Codec Setup */ +#define D_CDEC_CK(v) (v<<24) /* Clock Select */ +#define D_CDEC_FED(v) (v<<12) /* FSCOD Falling Edge Delay */ +#define D_CDEC_RED(v) (v<<0) /* FSCOD Rising Edge Delay */ + +/* Test */ +#define D_TEST_RAM(v) (v<<16) /* RAM Pointer */ +#define D_TEST_SIZE(v) (v<<11) /* */ +#define D_TEST_ROMONOFF 0x5 /* Toggle ROM opcode monitor on/off */ +#define D_TEST_PROC 0x6 /* MicroProcessor test */ +#define D_TEST_SER 0x7 /* Serial-Controller test */ +#define D_TEST_RAMREAD 0x8 /* Copy from Ram to system memory */ +#define D_TEST_RAMWRITE 0x9 /* Copy into Ram from system memory */ +#define D_TEST_RAMBIST 0xa /* RAM Built-In Self Test */ +#define D_TEST_MCBIST 0xb /* Microcontroller Built-In Self Test */ +#define D_TEST_DUMP 0xe /* ROM Dump */ + +/* CHI Data Mode */ +#define D_CDM_THI (1<<8) /* Transmit Data on CHIDR Pin */ +#define D_CDM_RHI (1<<7) /* Receive Data on CHIDX Pin */ +#define D_CDM_RCE (1<<6) /* Receive on Rising Edge of CHICK */ +#define D_CDM_XCE (1<<2) /* Transmit Data on Rising Edge of CHICK */ +#define D_CDM_XEN (1<<1) /* Transmit Highway Enable */ +#define D_CDM_REN (1<<0) /* Receive Highway Enable */ + +/* The Interrupts */ +#define D_INTR_BRDY 1 /* Buffer Ready for processing */ +#define D_INTR_MINT 2 /* Marked Interrupt in RD/TD */ +#define D_INTR_IBEG 3 /* Flag to idle transition detected (HDLC) */ +#define D_INTR_IEND 4 /* Idle to flag transition detected (HDLC) */ +#define D_INTR_EOL 5 /* End of List */ +#define D_INTR_CMDI 6 /* Command has bean read */ +#define D_INTR_XCMP 8 /* Transmission of frame complete */ +#define D_INTR_SBRI 9 /* BRI status change info */ +#define D_INTR_FXDT 10 /* Fixed data change */ +#define D_INTR_CHIL 11 /* CHI lost frame sync (channel 36 only) */ +#define D_INTR_COLL 11 /* Unrecoverable D-Channel collision */ +#define D_INTR_DBYT 12 /* Dropped by frame slip */ +#define D_INTR_RBYT 13 /* Repeated by frame slip */ +#define D_INTR_LINT 14 /* Lost Interrupt */ +#define D_INTR_UNDR 15 /* DMA underrun */ + +#define D_INTR_TE 32 +#define D_INTR_NT 34 +#define D_INTR_CHI 36 +#define D_INTR_CMD 38 + +#define D_INTR_GETCHAN(v) ((v>>24) & 0x3f) +#define D_INTR_GETCODE(v) ((v>>20) & 0xf) +#define D_INTR_GETCMD(v) ((v>>16) & 0xf) +#define D_INTR_GETVAL(v) (v & 0xffff) +#define D_INTR_GETRVAL(v) (v & 0xfffff) + +#define D_P_0 0 /* TE receive anchor */ +#define D_P_1 1 /* TE transmit anchor */ +#define D_P_2 2 /* NT transmit anchor */ +#define D_P_3 3 /* NT receive anchor */ +#define D_P_4 4 /* CHI send data */ +#define D_P_5 5 /* CHI receive data */ +#define D_P_6 6 /* */ +#define D_P_7 7 /* */ +#define D_P_8 8 /* */ +#define D_P_9 9 /* */ +#define D_P_10 10 /* */ +#define D_P_11 11 /* */ +#define D_P_12 12 /* */ +#define D_P_13 13 /* */ +#define D_P_14 14 /* */ +#define D_P_15 15 /* */ +#define D_P_16 16 /* CHI anchor pipe */ +#define D_P_17 17 /* CHI send */ +#define D_P_18 18 /* CHI receive */ +#define D_P_19 19 /* CHI receive */ +#define D_P_20 20 /* CHI receive */ +#define D_P_21 21 /* */ +#define D_P_22 22 /* */ +#define D_P_23 23 /* */ +#define D_P_24 24 /* */ +#define D_P_25 25 /* */ +#define D_P_26 26 /* */ +#define D_P_27 27 /* */ +#define D_P_28 28 /* */ +#define D_P_29 29 /* */ +#define D_P_30 30 /* */ +#define D_P_31 31 /* */ + + +/* Transmit descriptor defines */ +#define DBRI_TD_F (1<<31) /* End of Frame */ +#define DBRI_TD_D (1<<31) /* Do not append CRC */ +#define DBRI_TD_CNT(v) (v<<16) /* Number of valid bytes in the buffer */ +#define DBRI_TD_B (1<<15) /* Final interrupt */ +#define DBRI_TD_M (1<<14) /* Marker interrupt */ +#define DBRI_TD_I (1<<13) /* Transmit Idle Characters */ +#define DBRI_TD_FCNT(v) v /* Flag Count */ +#define DBRI_TD_UNR (1<<3) /* Underrun: transmitter is out of data */ +#define DBRI_TD_ABT (1<<2) /* Abort: frame aborted */ +#define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ + +/* Receive descriptor defines */ +#define DBRI_RD_F (1<<31) /* End of Frame */ +#define DBRI_RD_C (1<<30) /* Completed buffer */ +#define DBRI_RD_B (1<<15) /* Final interrupt */ +#define DBRI_RD_M (1<<14) /* Marker interrupt */ +#define DBRI_RD_CNT(v) (v<<16) /* Number of valid bytes in the buffer */ +#define DBRI_RD_BCNT(v) v /* Buffer size */ +#define DBRI_RD_CRC (1<<7) /* 0: CRC is correct */ +#define DBRI_RD_BBC (1<<6) /* 1: Bad Byte recieved */ +#define DBRI_RD_ABT (1<<5) /* Abort: frame aborted */ +#define DBRI_RD_OVRN (1<<3) /* Overrun: data lost */ + +#endif /* _DBRI_H_ */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in --- v2.1.78/linux/drivers/sbus/char/Config.in Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/Config.in Mon Jan 12 15:15:45 1998 @@ -19,6 +19,7 @@ fbs=$fbs$SUN_FB_CGFOURTEEN fbs=$fbs$SUN_FB_LEO fbs=$fbs$TADPOLE_FB_WEITEK + fbs=$fbs$SUN_FB_CREATOR if [ "$fbs" = "nnnnnnnn" ]; then echo "Warning: You have excluded ALL FB Support" echo "Notice: Enabling Generic AutoResolution" @@ -41,7 +42,10 @@ comment 'Misc Linux/SPARC drivers' tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC -tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532 +if [ "$ARCH" = "sparc64" ]; then + tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532 + tristate 'OBP Flash Device support' CONFIG_OBP_FLASH +fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile --- v2.1.78/linux/drivers/sbus/char/Makefile Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/Makefile Mon Jan 12 15:15:45 1998 @@ -51,13 +51,35 @@ O_TARGET := sunchar.o O_OBJ := ${FB_OBJS} suncons.o sbuscons.o pcicons.o sunfb.o -O_OBJS := ${O_OBJ} sunkbd.o sunkeymap.o sunmouse.o sunserial.o zs.o +O_OBJS := ${O_OBJ} sunkbd.o sunkbdmap.o sunmouse.o sunserial.o zs.o M_OBJS := ifeq ($(ARCH),sparc64) + +ifeq ($(CONFIG_PCI),y) + O_OBJS += su.o pcikbd.o + +ifeq ($(CONFIG_SAB82532),y) +O_OBJS += sab82532.o +else + ifeq ($(CONFIG_SAB82532),m) + M_OBJS += sab82532.o + endif endif +endif # eq($(CONFIG_PCI,y) + +ifeq ($(CONFIG_OBP_FLASH),y) +O_OBJS += flash.o +else + ifeq ($(CONFIG_OBP_FLASH),m) + M_OBJS += flash.o + endif +endif + +endif # eq($(ARCH),sparc64) + ifeq ($(CONFIG_SUN_OPENPROMIO),y) O_OBJS += openprom.o else @@ -90,14 +112,6 @@ endif endif -ifeq ($(CONFIG_SAB82532),y) -O_OBJS += sab82532.o -else - ifeq ($(CONFIG_SAB82532),m) - M_OBJS += sab82532.o - endif -endif - # Add PCI console/fb drivers here. # ifeq ($(CONFIG_PCI),y) @@ -105,6 +119,8 @@ endif include $(TOPDIR)/Rules.make + +sunkbdmap.o: sunkeymap.c vfc.o: vfc_dev.o vfc_i2c.o $(LD) -r -o vfc.o vfc_dev.o vfc_i2c.o diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c --- v2.1.78/linux/drivers/sbus/char/creator.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/creator.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: creator.c,v 1.12 1997/08/25 07:50:27 jj Exp $ +/* $Id: creator.c,v 1.13 1997/10/17 04:14:40 davem Exp $ * creator.c: Creator/Creator3D frame buffer driver * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -194,7 +194,7 @@ unsigned long map_offset = 0; int i; int alignment; - struct vm_area_struct *vmm; + struct vm_area_struct *vmm = NULL; size = vma->vm_end - vma->vm_start; if (vma->vm_offset & ~PAGE_MASK) diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c --- v2.1.78/linux/drivers/sbus/char/flash.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/flash.c Mon Jan 12 15:15:45 1998 @@ -0,0 +1,232 @@ +/* $Id: flash.c,v 1.5 1997/11/01 10:22:13 ecd Exp $ + * flash.c: Allow mmap access to the OBP Flash, for OBP updates. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static struct { + unsigned long read_base; + unsigned long write_base; + unsigned long read_size; + unsigned long write_size; + unsigned long busy; +} flash; + +#define FLASH_MINOR 152 + +static int +flash_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long addr; + unsigned long size; + + if (vma->vm_offset & ~(PAGE_MASK)) + return -ENXIO; + + if (flash.read_base == flash.write_base) { + addr = __pa(flash.read_base); + size = flash.read_size; + } else { + if ((vma->vm_flags & VM_READ) && + (vma->vm_flags & VM_WRITE)) + return -EINVAL; + + if (vma->vm_flags & VM_READ) { + addr = __pa(flash.read_base); + size = flash.read_size; + } else if (vma->vm_flags & VM_WRITE) { + addr = __pa(flash.write_base); + size = flash.write_size; + } else + return -ENXIO; + } + + if (vma->vm_offset > size) + return -ENXIO; + addr += vma->vm_offset; + + if (vma->vm_end - (vma->vm_start + vma->vm_offset) > size) + size = vma->vm_end - (vma->vm_start + vma->vm_offset); + + pgprot_val(vma->vm_page_prot) &= ~(_PAGE_CACHE); + pgprot_val(vma->vm_page_prot) |= _PAGE_E; + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot)) + return -EAGAIN; + vma->vm_dentry = dget(file->f_dentry); + return 0; +} + +static long long +flash_llseek(struct file *file, long long offset, int origin) +{ + switch (origin) { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + if (file->f_pos > flash.read_size) + file->f_pos = flash.read_size; + break; + case 2: + file->f_pos = flash.read_size; + break; + default: + return -EINVAL; + } + return file->f_pos; +} + +static ssize_t +flash_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + unsigned long p = file->f_pos; + + if (count > flash.read_size - p) + count = flash.read_size - p; + + if (copy_to_user(buf, flash.read_base + p, count) < 0) + return -EFAULT; + + file->f_pos += count; + return count; +} + +static int +flash_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, (void *)&flash.busy) != 0) + return -EBUSY; + + MOD_INC_USE_COUNT; + return 0; +} + +static int +flash_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + flash.busy = 0; + return 0; +} + +static struct file_operations flash_fops = { + flash_llseek, + flash_read, + NULL, /* no write to the Flash, use mmap + * and play flash dependant tricks. + */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + flash_mmap, + flash_open, + flash_release +}; + +static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +__initfunc(int flash_init(void)) +#endif +{ + struct linux_sbus *sbus; + struct linux_sbus_device *sdev = 0; + struct linux_ebus *ebus; + struct linux_ebus_device *edev = 0; + struct linux_prom_registers regs[2]; + int len, err; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "flashprom")) { + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); + if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) { + flash.read_base = (unsigned long)sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, "flashprom", + sdev->reg_addrs[0].which_io, 0); + flash.read_size = sdev->reg_addrs[0].reg_size; + flash.write_base = flash.read_base; + flash.write_size = flash.read_size; + } else { + flash.read_base = (unsigned long)sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, "flashprom", + sdev->reg_addrs[0].which_io, 0); + flash.read_size = sdev->reg_addrs[0].reg_size; + flash.write_base = (unsigned long)sparc_alloc_io(sdev->reg_addrs[1].phys_addr, 0, + sdev->reg_addrs[1].reg_size, "flashprom", + sdev->reg_addrs[1].which_io, 0); + flash.write_size = sdev->reg_addrs[1].reg_size; + } + flash.busy = 0; + break; + } + } + if (!sdev) { +#ifdef CONFIG_PCI + for_all_ebusdev(edev, ebus) + if (!strcmp(edev->prom_name, "flashprom")) + break; + if (!edev) + return -ENODEV; + + len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs)); + if (len != sizeof(regs)) { + printk("flash: Strange reg property size %d\n", len); + return -ENODEV; + } + + flash.read_base = edev->base_address[0]; + flash.read_size = regs[0].reg_size; + flash.write_base = edev->base_address[1]; + flash.write_size = regs[1].reg_size; + flash.busy = 0; + +#else + return -ENODEV; +#endif + } + + printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n", + __pa(flash.read_base), flash.read_size, + __pa(flash.write_base), flash.write_size); + + err = misc_register(&flash_dev); + if (err) { + printk(KERN_ERR "flash: unable to get misc minor\n"); + return err; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + misc_deregister(&flash_dev); +} +#endif diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/mach64.c linux/drivers/sbus/char/mach64.c --- v2.1.78/linux/drivers/sbus/char/mach64.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/mach64.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: mach64.c,v 1.8 1997/08/25 07:50:34 jj Exp $ +/* $Id: mach64.c,v 1.11 1997/10/17 04:13:35 davem Exp $ * mach64.c: Ultra/PCI Mach64 console driver. * * Just about all of this is from the PPC/mac driver, see that for @@ -22,13 +22,18 @@ #include #include #include +#include #include "pcicons.h" #include "mach64.h" #include "fb.h" +static unsigned int mach64_pci_membase; +static unsigned int mach64_pci_iobase; + +#define MACH64_LE_FBOFF 0x000000 #define MACH64_REGOFF 0x7ffc00 -#define MACH64_FBOFF 0x800000 +#define MACH64_BE_FBOFF 0x800000 static inline void mach64_waitq(int entries) { @@ -69,7 +74,35 @@ mach64_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, fbinfo_t *fb) { - return -ENOSYS; + unsigned long addr, size; + + size = vma->vm_end - vma->vm_start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + + if (vma->vm_offset == mach64_pci_iobase) { + addr = __pa(pcivga_iobase); + size = PAGE_SIZE; + } else if (vma->vm_offset >= (mach64_pci_membase + 0x800000)) { + addr = __pa(pcivga_membase) - mach64_pci_membase + + vma->vm_offset; + pgprot_val(vma->vm_page_prot) |= _PAGE_IE; + } else if (vma->vm_offset >= mach64_pci_membase) { + addr = __pa(pcivga_membase) - mach64_pci_membase + + vma->vm_offset; + } else { + return -EINVAL; + } + + pgprot_val(vma->vm_page_prot) &= ~(_PAGE_CACHE); + pgprot_val(vma->vm_page_prot) |= _PAGE_E; + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot)) + return -EAGAIN; + + vma->vm_dentry = dget(file->f_dentry); + return 0; } static void @@ -113,11 +146,29 @@ static struct mach64_info mach64; +void mach64_test(fbinfo_t *fb) +{ + unsigned int x; + int i; + + for (i = 0; i < mach64.total_vram; i += 4) + writel(i, pcivga_membase + i); + + for (i = 0; i < mach64.total_vram; i += 4) + if ((x = readl(pcivga_membase + i)) != i) { + printk("vga mem read error @ %08x: exp %x, rd %x\n", + i, i, x); + i = (i & ~(0xffff)) + 0x10000; + } +} + int mach64_init(fbinfo_t *fb) { struct pci_dev *pdev; struct pcidev_cookie *cookie; + struct linux_pbm_info *pbm; unsigned long addr; + unsigned int tmp; memset(&mach64, 0, sizeof(mach64)); for(pdev = pci_devices; pdev; pdev = pdev->next) { @@ -148,48 +199,85 @@ prom_halt(); } + pcibios_read_config_dword(pdev->bus->number, pdev->devfn, + PCI_BASE_ADDRESS_0, &mach64_pci_membase); + mach64_pci_membase &= PCI_BASE_ADDRESS_MEM_MASK; + + pcibios_read_config_dword(pdev->bus->number, pdev->devfn, + PCI_BASE_ADDRESS_1, &mach64_pci_iobase); + mach64_pci_iobase &= PCI_BASE_ADDRESS_IO_MASK; + printk("mach64_init: IOBASE[%016lx] MEMBASE[%016lx]\n", pcivga_iobase, pcivga_membase); - cookie = (struct pcidev_cookie *)pdev->sysdata; + cookie = pdev->sysdata; + pbm = cookie->pbm; + fb->prom_node = cookie->prom_node; - fb->proc_entry.node = cookie->pbm->prom_node; + fb->proc_entry.node = pbm->prom_node; fb->type.fb_type = FBTYPE_PCI_MACH64; fb->type.fb_cmsize = 256; fb->info.private = (void *)&mach64; - fb->base = pcivga_membase + MACH64_FBOFF; - - switch(pcivga_readl(MACH64_REGOFF + MEM_CNTL) & MEM_SIZE_ALIAS) { - case MEM_SIZE_512K: - mach64.total_vram = 0x80000; - break; - case MEM_SIZE_1M: - mach64.total_vram = 0x100000; - break; - case MEM_SIZE_2M: - mach64.total_vram = 0x200000; - break; - case MEM_SIZE_4M: - mach64.total_vram = 0x400000; - break; - case MEM_SIZE_6M: - mach64.total_vram = 0x600000; - break; - case MEM_SIZE_8M: - mach64.total_vram = 0x800000; - break; - default: - mach64.total_vram = 0x80000; - break; - } + fb->base = pcivga_membase + MACH64_BE_FBOFF; if ((pcivga_readl(MACH64_REGOFF + CONFIG_CHIP_ID) & CFG_CHIP_TYPE) == MACH64_VT_ID) mach64.flags |= MACH64_MASK_VT; + /* + * Fix the PROM's idea of MEM_CNTL settings... + */ + tmp = pcivga_readl(MACH64_REGOFF + MEM_CNTL); + switch (tmp & 0xf) { + case 3: + tmp = (tmp & ~(0xf)) | 2; + break; + case 7: + tmp = (tmp & ~(0xf)) | 3; + break; + case 9: + tmp = (tmp & ~(0xf)) | 4; + break; + case 11: + tmp = (tmp & ~(0xf)) | 5; + break; + default: + break; + } + tmp &= ~(0x00f00000); + pcivga_writel(tmp, MACH64_REGOFF + MEM_CNTL); + + switch(tmp & MEM_SIZE_ALIAS) { + case MEM_SIZE_512K: + mach64.total_vram = 0x80000; + break; + case MEM_SIZE_1M: + mach64.total_vram = 0x100000; + break; + case MEM_SIZE_2M: + mach64.total_vram = 0x200000; + break; + case MEM_SIZE_4M: + mach64.total_vram = 0x400000; + break; + case MEM_SIZE_6M: + mach64.total_vram = 0x600000; + break; + case MEM_SIZE_8M: + mach64.total_vram = 0x800000; + break; + default: + mach64.total_vram = 0x80000; + break; + } + printk("mach64_init: total_vram[%08x] is_vt_chip[%d]\n", mach64.total_vram, mach64.flags & MACH64_MASK_VT ? 1 : 0); + +#if 0 + mach64_test(fb); +#endif fb->mmap = mach64_mmap; fb->loadcmap = mach64_loadcmap; diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/mach64.h linux/drivers/sbus/char/mach64.h --- v2.1.78/linux/drivers/sbus/char/mach64.h Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/mach64.h Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: mach64.h,v 1.3 1997/08/24 12:13:07 ecd Exp $ +/* $Id: mach64.h,v 1.4 1997/10/04 08:51:30 ecd Exp $ * mach64.h: Ultra/PCI mach64 driver constants etc. * * Copyright 1997 David S. Miller (davem@caip.rutgers.edu) @@ -42,6 +42,9 @@ #define CRTC_FIFO 0x001e #define CRTC_EXT_DISP 0x001f +#define SHARED_CNTL 0x0030 /* Dword offset 0C */ +#define SHARED_MEM_CONFIG 0x0034 /* Dword offset 0D */ + #define OVR_CLR 0x0040 /* Dword offset 10 */ #define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 11 */ #define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 12 */ @@ -60,6 +63,7 @@ #define BUS_CNTL 0x00A0 /* Dword offset 28 */ +#define EXT_MEM_CNTL 0x00AC /* Dword offset 2B */ #define MEM_CNTL 0x00B0 /* Dword offset 2C */ #define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 2D */ @@ -359,6 +363,8 @@ #define MEM_SIZE_6M 0x00000004 #define MEM_SIZE_8M 0x00000005 #define MEM_SIZE_ALIAS_GTB 0x0000000F +#define MEM_SIZE_512K_GTB 0x00000000 +#define MEM_SIZE_1M_GTB 0x00000001 #define MEM_SIZE_2M_GTB 0x00000003 #define MEM_SIZE_4M_GTB 0x00000007 #define MEM_SIZE_6M_GTB 0x00000009 diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c --- v2.1.78/linux/drivers/sbus/char/openprom.c Mon Jul 7 08:18:55 1997 +++ linux/drivers/sbus/char/openprom.c Mon Jan 12 15:15:45 1998 @@ -526,8 +526,7 @@ } } -static long long openprom_lseek(struct inode * inode, struct file * file, - long long offset, int origin) +static long long openprom_lseek(struct file * file, long long offset, int origin) { return -ESPIPE; } diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/pcicons.c linux/drivers/sbus/char/pcicons.c --- v2.1.78/linux/drivers/sbus/char/pcicons.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/pcicons.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: pcicons.c,v 1.9 1997/08/28 02:23:24 ecd Exp $ +/* $Id: pcicons.c,v 1.10 1997/10/04 08:52:57 ecd Exp $ * pcicons.c: PCI specific probing and console operations layer. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -37,14 +37,9 @@ static int y_margin = 0; static int skip_bytes; -static void pci_cursor_blink(unsigned long); -static __u32 *cursor_screen_pos; -static __u32 cursor_bits; +static __u64 *cursor_screen_pos; +static __u64 cursor_bits[2]; static int cursor_pos = -1; -static int cursor_off = 1; -static struct timer_list pci_cursor_timer = { - NULL, NULL, 0, 0, pci_cursor_blink -}; extern int serial_console; @@ -219,52 +214,24 @@ static void pci_invert_cursor(int cpos) { fbinfo_t *fb = &fbinfo[0]; - unsigned char color; - __u32 *screen, mask; - int i; - - del_timer(&pci_cursor_timer); + __u64 *screen; if (cpos == -1) { - if (cursor_off) - return; screen = cursor_screen_pos; - mask = cursor_bits; - } else { - screen = (__u32 *)(fb->base + fbuf_offset(cpos) - + 14 * fb->linebytes); - - color = CHARATTR_TO_SUNCOLOR( - vc_cons[fg_console].d->vc_color << 8); - - mask = (color ^ (color >> 4)) & 0x0f; - mask |= mask << 8; - mask |= mask << 16; - - cursor_screen_pos = screen; - cursor_bits = mask; - - pci_cursor_timer.expires = jiffies + (HZ >> 2); - add_timer(&pci_cursor_timer); + *screen = cursor_bits[0]; + screen = (__u64 *)((unsigned long)screen + fb->linebytes); + *screen = cursor_bits[1]; + return; } - for (i = 0; i < 2; i++) { - screen[0] ^= mask; - screen[1] ^= mask; - screen = (__u32 *)((unsigned long)screen + fb->linebytes); - } -} + screen = (__u64 *)(fb->base + fbuf_offset(cpos) + 14 * fb->linebytes); + cursor_screen_pos = screen; -static void pci_cursor_blink(unsigned long ignored) -{ - unsigned long flags; - - save_flags(flags); cli(); - if (cursor_pos != -1) { - pci_invert_cursor(cursor_pos); - cursor_off = 1 - cursor_off; - } - restore_flags(flags); + cursor_bits[0] = *screen; + *screen = 0x0000000000000000; + screen = (__u64 *)((unsigned long)screen + fb->linebytes); + cursor_bits[1] = *screen; + *screen = 0x0000000000000000; } static void pci_hide_cursor(void) @@ -275,11 +242,8 @@ return; save_flags(flags); cli(); - if (cursor_pos != -1) { + if (cursor_pos != -1) pci_invert_cursor(-1); - cursor_pos = -1; - } - cursor_off = 1; restore_flags(flags); } @@ -300,7 +264,6 @@ if (old_cursor != -1) pci_invert_cursor(-1); pci_invert_cursor(cursor_pos); - cursor_off = 0; } restore_flags(flags); } diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.1.78/linux/drivers/sbus/char/pcikbd.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/sbus/char/pcikbd.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.4 1997/09/05 22:59:53 ecd Exp $ +/* $Id: pcikbd.c,v 1.12 1997/12/27 16:28:27 jj Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -8,6 +8,7 @@ * to the original authors. */ +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -26,7 +28,6 @@ #include #include #include -#include #include "pcikbd.h" #include "sunserial.h" @@ -35,6 +36,7 @@ static int beep_node; static unsigned long pcikbd_iobase = 0; +static unsigned long pcibeep_iobase = 0; static unsigned int pcikbd_irq; /* used only by send_data - set by keyboard_interrupt */ @@ -42,12 +44,31 @@ static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; +unsigned char pckbd_read_mask = KBD_STAT_OBF; + +extern int pcikbd_init(void); +extern void pci_compute_shiftstate(void); +extern int pci_setkeycode(unsigned int, unsigned int); +extern int pci_getkeycode(unsigned int); +extern void pci_setledstate(struct kbd_struct *, unsigned int); +extern unsigned char pci_getledstate(void); + +static __inline__ unsigned char pcikbd_inb(unsigned long port) +{ + return inb(port); +} + +static __inline__ void pcikbd_outb(unsigned char val, unsigned long port) +{ + outb(val, port); +} + static inline void kb_wait(void) { unsigned long start = jiffies; do { - if(!(inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF)) + if(!(pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF)) return; } while (jiffies - start < KBC_TIMEOUT); } @@ -167,6 +188,19 @@ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ }; +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char pcikbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + static unsigned int prev_scancode = 0; int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode) @@ -268,25 +302,17 @@ { unsigned char status; - /* - * This IRQ might be shared with the 16550A serial chip, - * so we check dev_id to see if it was for us. - * (See also drivers/sbus/char/su.c). - */ - if (dev_id) - return; - - /* kbd_pt_regs = regs; */ - status = inb(pcikbd_iobase + KBD_STATUS_REG); + kbd_pt_regs = regs; + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); do { unsigned char scancode; - if(status & kbd_read_mask & KBD_STAT_MOUSE_OBF) + if(status & pckbd_read_mask & KBD_STAT_MOUSE_OBF) break; - scancode = inb(pcikbd_iobase + KBD_DATA_REG); + scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); if((status & KBD_STAT_OBF) && do_acknowledge(scancode)) - /* handle_scancode(scancode) */; - status = inb(pcikbd_iobase + KBD_STATUS_REG); + handle_scancode(scancode); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while(status & KBD_STAT_OBF); mark_bh(KEYBOARD_BH); } @@ -300,7 +326,7 @@ kb_wait(); acknowledge = resend = 0; reply_expected = 1; - outb(data, pcikbd_iobase + KBD_DATA_REG); + pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG); start = jiffies; do { if(acknowledge) @@ -325,10 +351,10 @@ unsigned long start = jiffies; do { - status = inb(pcikbd_iobase + KBD_STATUS_REG); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); if(!(status & KBD_STAT_OBF)) continue; - data = inb(pcikbd_iobase + KBD_DATA_REG); + data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); if(status & (KBD_STAT_GTO | KBD_STAT_PERR)) continue; return (data & 0xff); @@ -341,18 +367,55 @@ int status; do { - status = inb(pcikbd_iobase + KBD_STATUS_REG); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while (status & KBD_STAT_IBF); - outb(data, pcikbd_iobase + address); + pcikbd_outb(data, pcikbd_iobase + address); +} + +/* Timer routine to turn off the beep after the interval expires. */ +static void pcikbd_kd_nosound(unsigned long __unused) +{ + outl(0, pcibeep_iobase); +} + +/* + * Initiate a keyboard beep. If the frequency is zero, then we stop + * the beep. Any other frequency will start a monotone beep. The beep + * will be stopped by a timer after "ticks" jiffies. If ticks is 0, + * then we do not start a timer. + */ +static void pcikbd_kd_mksound(unsigned int hz, unsigned int ticks) +{ + unsigned long flags; + static struct timer_list sound_timer = { NULL, NULL, 0, 0, + pcikbd_kd_nosound }; + + save_flags(flags); cli(); + del_timer(&sound_timer); + if (hz) { + outl(1, pcibeep_iobase); + if (ticks) { + sound_timer.expires = jiffies + ticks; + add_timer(&sound_timer); + } + } else + outl(0, pcibeep_iobase); + restore_flags(flags); } -__initfunc(static char *do_pcikbd_hwinit(void)) +static void nop_kd_mksound(unsigned int hz, unsigned int ticks) +{ +} + +extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); + +__initfunc(static char *do_pcikbd_init_hw(void)) { while(pcikbd_wait_for_input() != -1) ; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); - if(pcikbd_wait_for_input() != 0xff) + if(pcikbd_wait_for_input() != 0x55) return "Keyboard failed self test"; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); @@ -388,23 +451,12 @@ return NULL; /* success */ } -__initfunc(void pcikbd_hwinit(void)) -{ - char *msg; - - disable_irq(pcikbd_irq); - msg = do_pcikbd_hwinit(); - enable_irq(pcikbd_irq); - - if(msg) - printk("8042: keyboard init failure [%s]\n", msg); -} - -__initfunc(int pcikbd_probe(void)) +__initfunc(void pcikbd_init_hw(void)) { struct linux_ebus *ebus; struct linux_ebus_device *edev; struct linux_ebus_child *child; + char *msg; for_all_ebusdev(edev, ebus) { if(!strcmp(edev->prom_name, "8042")) { @@ -415,29 +467,57 @@ } } printk("pcikbd_probe: no 8042 found\n"); - return -ENODEV; + return; found: pcikbd_iobase = child->base_address[0]; if (check_region(pcikbd_iobase, sizeof(unsigned long))) { printk("8042: can't get region %lx, %d\n", pcikbd_iobase, (int)sizeof(unsigned long)); - return -ENODEV; + return; } request_region(pcikbd_iobase, sizeof(unsigned long), "8042 controller"); pcikbd_irq = child->irqs[0]; if (request_irq(pcikbd_irq, &pcikbd_interrupt, - SA_SHIRQ, "keyboard", NULL)) { + SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) { printk("8042: cannot register IRQ %x\n", pcikbd_irq); - return -ENODEV; + return; } printk("8042(kbd): iobase[%016lx] irq[%x]\n", pcikbd_iobase, pcikbd_irq); - /* pcikbd_init(); */ - kbd_read_mask = KBD_STAT_OBF; - return 0; + kd_mksound = nop_kd_mksound; + for_all_ebusdev(edev, ebus) { + if(!strcmp(edev->prom_name, "beeper")) + break; + } + + /* + * XXX: my 3.1.3 PROM does not give me the beeper node for the audio + * auxio register, though I know it is there... (ecd) + */ + if (!edev) + pcibeep_iobase = (pcikbd_iobase & ~(0xffffff)) | 0x722000; + else + pcibeep_iobase = edev->base_address[0]; + + if (check_region(pcibeep_iobase, sizeof(unsigned int))) { + printk("8042: can't get region %lx, %d\n", + pcibeep_iobase, (int)sizeof(unsigned int)); + } else { + request_region(pcibeep_iobase, sizeof(unsigned int), "speaker"); + kd_mksound = pcikbd_kd_mksound; + printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase, + edev ? "" : " (forced)"); + } + + disable_irq(pcikbd_irq); + msg = do_pcikbd_init_hw(); + enable_irq(pcikbd_irq); + + if(msg) + printk("8042: keyboard init failure [%s]\n", msg); } @@ -451,8 +531,6 @@ static unsigned long pcimouse_iobase = 0; static unsigned int pcimouse_irq; -#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */ - #define AUX_BUF_SIZE 2048 struct aux_queue { @@ -468,6 +546,16 @@ static int aux_count = 0; static int aux_present = 0; +static __inline__ unsigned char pcimouse_inb(unsigned long port) +{ + return inb(port); +} + +static __inline__ void pcimouse_outb(unsigned char val, unsigned long port) +{ + outb(val, port); +} + /* * Shared subroutines */ @@ -491,11 +579,11 @@ return queue->head == queue->tail; } -static int fasync_aux(struct inode *inode, struct file *filp, int on) +static int aux_fasync(struct file *filp, int on) { int retval; - retval = fasync_helper(inode, filp, on, &queue->fasync); + retval = fasync_helper(filp, on, &queue->fasync); if (retval < 0) return retval; return 0; @@ -521,11 +609,11 @@ { int retries=0; - while ((inb(pcimouse_iobase + KBD_STATUS_REG) & + while ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) { - if ((inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) - inb(pcimouse_iobase + KBD_DATA_REG); + pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + (5*HZ + 99) / 100; schedule(); @@ -541,9 +629,10 @@ static void aux_write_dev(int val) { poll_aux_status(); - outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG);/* Write magic cookie */ + pcimouse_outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG);/* Write magic cookie */ poll_aux_status(); - outb_p(val, pcimouse_iobase + KBD_DATA_REG); /* Write data */ + pcimouse_outb(val, pcimouse_iobase + KBD_DATA_REG); /* Write data */ + udelay(1); } /* @@ -555,8 +644,8 @@ aux_write_dev(val); poll_aux_status(); - if ((inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) - return (inb(pcimouse_iobase + KBD_DATA_REG)); + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) + return (pcimouse_inb(pcimouse_iobase + KBD_DATA_REG)); return 0; } @@ -567,9 +656,9 @@ static void aux_write_cmd(int val) { poll_aux_status(); - outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - outb(val, pcimouse_iobase + KBD_DATA_REG); + pcimouse_outb(val, pcimouse_iobase + KBD_DATA_REG); } /* @@ -607,18 +696,10 @@ int head = queue->head; int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); - /* - * This IRQ might be shared with the 16550A serial chip, - * so we check dev_id to see if it was for us. - * (See also drivers/sbus/char/su.c). - */ - if (dev_id) - return; - - if ((inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) return; - add_mouse_randomness(queue->buf[head] = inb(pcimouse_iobase + KBD_DATA_REG)); + add_mouse_randomness(queue->buf[head] = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG)); if (head != maxhead) { head++; head &= AUX_BUF_SIZE-1; @@ -630,9 +711,9 @@ wake_up_interruptible(&queue->proc_list); } -static int release_aux(struct inode * inode, struct file * file) +static int aux_release(struct inode * inode, struct file * file) { - fasync_aux(inode, file, 0); + aux_fasync(file, 0); if (--aux_count) return 0; aux_start_atomic(); @@ -642,7 +723,7 @@ poll_aux_status(); /* Disable Aux device */ - outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); aux_end_atomic(); @@ -655,10 +736,11 @@ * Enable auxiliary device. */ -static int open_aux(struct inode * inode, struct file * file) +static int aux_open(struct inode * inode, struct file * file) { if (!aux_present) return -ENODEV; + aux_start_atomic(); if (aux_count++) { aux_end_atomic(); @@ -674,7 +756,7 @@ MOD_INC_USE_COUNT; poll_aux_status(); - outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase+KBD_CNTL_REG); /* Enable Aux */ + pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase+KBD_CNTL_REG); /* Enable Aux */ aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */ poll_aux_status(); @@ -688,31 +770,31 @@ * Write to the aux device. */ -static long write_aux(struct inode * inode, struct file * file, - const char * buffer, unsigned long count) +static ssize_t aux_write(struct file * file, const char * buffer, + size_t count, loff_t *ppos) { - int retval = 0; + ssize_t retval = 0; if (count) { - int written = 0; + ssize_t written = 0; aux_start_atomic(); do { char c; if (!poll_aux_status()) break; - outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG); if (!poll_aux_status()) break; get_user(c, buffer++); - outb(c, pcimouse_iobase + KBD_DATA_REG); + pcimouse_outb(c, pcimouse_iobase + KBD_DATA_REG); written++; } while (--count); aux_end_atomic(); retval = -EIO; if (written) { retval = written; - inode->i_mtime = CURRENT_TIME; + file->f_dentry->d_inode->i_mtime = CURRENT_TIME; } } @@ -727,11 +809,11 @@ * Put bytes from input queue to buffer. */ -static long read_aux(struct inode * inode, struct file * file, - char * buffer, unsigned long count) +static ssize_t aux_read(struct file * file, char * buffer, + size_t count, loff_t *ppos) { struct wait_queue wait = { current, NULL }; - int i = count; + ssize_t i = count; unsigned char c; if (queue_empty()) { @@ -754,7 +836,7 @@ } aux_ready = !queue_empty(); if (count-i) { - inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-i; } if (signal_pending(current)) @@ -772,16 +854,16 @@ struct file_operations psaux_fops = { NULL, /* seek */ - read_aux, - write_aux, + aux_read, + aux_write, NULL, /* readdir */ aux_poll, NULL, /* ioctl */ NULL, /* mmap */ - open_aux, - release_aux, + aux_open, + aux_release, NULL, - fasync_aux, + aux_fasync, }; static struct miscdevice psaux_mouse = { @@ -816,7 +898,7 @@ pcimouse_irq = child->irqs[0]; if (request_irq(pcimouse_irq, &pcimouse_interrupt, - SA_SHIRQ, "mouse", NULL)) { + SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) { printk("8042: Cannot register IRQ %x\n", pcimouse_irq); return -ENODEV; } @@ -826,7 +908,7 @@ printk("8042: PS/2 auxiliary pointing device detected.\n"); aux_present = 1; - kbd_read_mask = AUX_STAT_OBF; + pckbd_read_mask = AUX_STAT_OBF; misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); @@ -834,18 +916,19 @@ queue->head = queue->tail = 0; queue->proc_list = NULL; aux_start_atomic(); - outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG); + aux_write_ack(AUX_RESET); aux_write_ack(AUX_SET_SAMPLE); aux_write_ack(100); aux_write_ack(AUX_SET_RES); aux_write_ack(3); aux_write_ack(AUX_SET_SCALE21); poll_aux_status(); - outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG); + pcimouse_outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG); poll_aux_status(); aux_end_atomic(); @@ -853,21 +936,6 @@ } -__initfunc(static int ps2_init(void)) -{ - int err; - - err = pcikbd_probe(); - if (err) - return err; - - err = pcimouse_init(); - if (err) - return err; - - return 0; -} - __initfunc(int ps2kbd_probe(unsigned long *memory_start)) { int pnode, enode, node, dnode; @@ -959,6 +1027,12 @@ return -ENODEV; found: - sunserial_setinitfunc(memory_start, ps2_init); + sunkbd_setinitfunc(memory_start, pcimouse_init); + sunkbd_setinitfunc(memory_start, pcikbd_init); + kbd_ops.compute_shiftstate = pci_compute_shiftstate; + kbd_ops.setledstate = pci_setledstate; + kbd_ops.getledstate = pci_getledstate; + kbd_ops.setkeycode = pci_setkeycode; + kbd_ops.getkeycode = pci_getkeycode; return 0; } diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/pcikbd.h linux/drivers/sbus/char/pcikbd.h --- v2.1.78/linux/drivers/sbus/char/pcikbd.h Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/pcikbd.h Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.h,v 1.1 1997/08/24 02:53:25 davem Exp $ +/* $Id: pcikbd.h,v 1.2 1997/12/25 21:13:14 geert Exp $ * pcikbd.h: PCI/PC 8042 keyboard/mouse driver stuff. Mostly snarfed * from the existing driver by Martin Mares. * @@ -28,7 +28,7 @@ * Internal variables of the driver */ -extern unsigned char kbd_read_mask; +extern unsigned char pckbd_read_mask; extern unsigned char aux_device_present; extern unsigned long pcikbd_iobase; diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.1.78/linux/drivers/sbus/char/rtc.c Mon Apr 14 16:28:13 1997 +++ linux/drivers/sbus/char/rtc.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.10 1997/04/03 08:47:55 davem Exp $ +/* $Id: rtc.c,v 1.11 1997/09/20 20:47:26 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -70,8 +70,7 @@ restore_flags(flags); } -static long long rtc_lseek(struct inode *inode, struct file *file, - long long offset, int origin) +static long long rtc_lseek(struct file *file, long long offset, int origin) { return -ESPIPE; } diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.1.78/linux/drivers/sbus/char/sab82532.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/sbus/char/sab82532.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.4 1997/09/03 17:04:21 ecd Exp $ +/* $Id: sab82532.c,v 1.13 1997/12/30 09:37:49 ecd Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,9 @@ /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 +#define SERIAL_PARANOIA_CHECK +#define SERIAL_DO_RESTART + /* Set of debugging defines */ #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_INTR @@ -59,10 +63,23 @@ static struct termios *sab82532_termios[NR_PORTS]; static struct termios *sab82532_termios_locked[NR_PORTS]; +#ifdef CONFIG_SERIAL_CONSOLE +extern int serial_console; +static struct console sab82532_console; +static int sab82532_console_init(void); +#endif + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +static char *sab82532_version[16] = { + "V1.0", "V2.0", "V3.2", "V(0x03)", + "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)", + "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)", + "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)" +}; + /* * tmp_buf is used as a temporary buffer by sab82532_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -178,8 +195,10 @@ restore_flags(flags); } -static void batten_down_hatches(void) +static void batten_down_hatches(struct sab82532 *info) { + unsigned char saved_rfc; + /* If we are doing kadb, we call the debugger * else we just drop into the boot monitor. * Note that we must flush the user windows @@ -187,6 +206,16 @@ */ printk("\n"); flush_user_windows(); + + /* + * Set FIFO to single character mode. + */ + saved_rfc = info->regs->r.rfc; + info->regs->rw.rfc &= ~(SAB82532_RFC_RFDF); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + info->regs->w.cmdr = SAB82532_CMDR_RRES; + #ifndef __sparc_v9__ if ((((unsigned long)linux_dbvec) >= DEBUG_FIRSTVADDR) && (((unsigned long)linux_dbvec) <= DEBUG_LASTVADDR)) @@ -194,6 +223,14 @@ else #endif prom_cmdline(); + + /* + * Reset FIFO to character + status mode. + */ + info->regs->w.rfc = saved_rfc; + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + info->regs->w.cmdr = SAB82532_CMDR_RRES; } /* @@ -242,16 +279,11 @@ count = info->recv_fifo_size; free_fifo++; } + if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { count = info->regs->r.rbcl & (info->recv_fifo_size - 1); free_fifo++; } - if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { -#if 1 - printk("sab82532: receive_chars: RFO"); -#endif - free_fifo++; - } /* Issue a FIFO read command in case we where idle. */ if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { @@ -260,8 +292,15 @@ info->regs->w.cmdr = SAB82532_CMDR_RFRD; } + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { +#if 1 + printk("sab82532: receive_chars: RFO"); +#endif + free_fifo++; + } + /* Read the FIFO. */ - for (i = 0; i < (count << 1); i++) + for (i = 0; i < count; i++) buf[i] = info->regs->r.rfifo[i]; /* Issue Receive Message Complete command. */ @@ -271,6 +310,11 @@ info->regs->w.cmdr = SAB82532_CMDR_RMC; } + if (info->is_console) + wake_up(&keypress_wait); + if (!tty) + return; + for (i = 0; i < count; ) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { #if 1 @@ -312,6 +356,12 @@ { int i; + if (!info->tty) { + info->interrupt_mask1 |= SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) @@ -356,7 +406,7 @@ if (stat->sreg.isr1 & SAB82532_ISR1_BRK) { if (info->is_console) { - batten_down_hatches(); + batten_down_hatches(info); return; } if (tty->flip.count >= TTY_FLIPBUF_SIZE) { @@ -369,6 +419,9 @@ info->icount.brk++; } + if (!tty) + return; + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { info->icount.buf_overrun++; @@ -380,9 +433,6 @@ info->icount.overrun++; } - if (info->is_console) - return; - check_modem: if (stat->sreg.isr0 & SAB82532_ISR0_CDSC) { info->dcd = (info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : 1; @@ -581,38 +631,18 @@ tty_hangup(tty); } - -static int startup(struct sab82532 *info) +static void +sab82532_init_line(struct sab82532 *info) { - unsigned long flags; - unsigned long page; unsigned char stat; - page = get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - free_page(page); - goto errout; - } - - if (!info->regs) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - free_page(page); - goto errout; - } - if (info->xmit_buf) - free_page(page); - else - info->xmit_buf = (unsigned char *)page; - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up serial port %d...", info->line); -#endif + /* + * Wait for any commands or immediate characters + */ + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); /* * Clear the FIFO buffers. @@ -662,7 +692,46 @@ break; } info->regs->rw.ccr0 |= SAB82532_CCR0_PU; /* power-up */ - +} + +static int startup(struct sab82532 *info) +{ + unsigned long flags; + unsigned long page; + int retval = 0; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!info->regs) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + retval = -ENODEV; + goto errout; + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *)page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up serial port %d...", info->line); +#endif + + /* + * Initialize the Hardware + */ + sab82532_init_line(info); + /* * Finally, enable interrupts */ @@ -689,7 +758,7 @@ errout: restore_flags(flags); - return -ENODEV; + return retval; } /* @@ -720,6 +789,22 @@ info->xmit_buf = 0; } + if (info->is_console) { + info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + info->regs->w.imr0 = info->interrupt_mask0; + info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); + return; + } + /* Disable Interrupts */ info->interrupt_mask0 = 0xff; info->regs->w.imr0 = info->interrupt_mask0; @@ -758,7 +843,7 @@ unsigned int ebrg; tcflag_t cflag; unsigned char dafo; - int i; + int i, bits; if (!info->tty || !info->tty->termios) return; @@ -766,19 +851,23 @@ /* Byte size and parity */ switch (cflag & CSIZE) { - case CS5: dafo = SAB82532_DAFO_CHL5; break; - case CS6: dafo = SAB82532_DAFO_CHL6; break; - case CS7: dafo = SAB82532_DAFO_CHL7; break; - case CS8: dafo = SAB82532_DAFO_CHL8; break; + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; /* Never happens, but GCC is too dumb to figure it out */ - default: dafo = SAB82532_DAFO_CHL5; break; + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; } - if (cflag & CSTOPB) + if (cflag & CSTOPB) { dafo |= SAB82532_DAFO_STOP; + bits++; + } - if (cflag & PARENB) + if (cflag & PARENB) { dafo |= SAB82532_DAFO_PARE; + bits++; + } if (cflag & PARODD) { #ifdef CMSPAR @@ -808,6 +897,12 @@ ebrg = ebrg_table[i].n; ebrg |= (ebrg_table[i].m << 6); + if (ebrg_table[i].baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + else + info->timeout = 0; + info->timeout += HZ / 50; /* Add .02 seconds of slop */ + /* CTS flow control flags */ if (cflag & CRTSCTS) info->flags |= ASYNC_CTS_FLOW; @@ -842,6 +937,10 @@ SAB82532_ISR0_TIME; save_flags(flags); cli(); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); info->regs->w.dafo = dafo; info->regs->w.bgr = ebrg & 0xff; info->regs->rw.ccr2 &= ~(0xc0); @@ -980,7 +1079,7 @@ static void sab82532_flush_buffer(struct tty_struct *tty) { struct sab82532 *info = (struct sab82532 *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "sab82532_flush_buffer")) return; cli(); @@ -1003,7 +1102,7 @@ if (serial_paranoia_check(info, tty->device, "sab82532_send_xchar")) return; - if (info->regs->r.star & SAB82532_STAR_TEC) + while (info->regs->r.star & SAB82532_STAR_TEC) udelay(1); info->regs->w.tic = ch; } @@ -1114,7 +1213,7 @@ { unsigned int result; - result = info->all_sent ? TIOCSER_TEMT : 0; + result = (!info->xmit_buf && info->all_sent) ? TIOCSER_TEMT : 0; return put_user(result, value); } @@ -1496,7 +1595,9 @@ */ info->interrupt_mask0 |= SAB82532_IMR0_TCD; info->regs->w.imr0 = info->interrupt_mask0; +#if 0 info->regs->rw.mode &= ~(SAB82532_MODE_RAC); +#endif if (info->flags & ASYNC_INITIALIZED) { /* * Before we drop DTR, make sure the UART transmitter @@ -1554,16 +1655,23 @@ char_time = 1; if (timeout) char_time = MIN(char_time, timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT printk("In sab82532_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies); #endif - - /* XXX: Implement this... */ - + while (info->xmit_cnt || !info->all_sent) { + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; + current->timeout = jiffies + char_time; + schedule(); + if (signal_pending(current)) + break; + if (timeout && (orig_jiffies + timeout) < jiffies) + break; + } current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT + printk("xmit_cnt = %d, alls = %d (jiff=%lu)...done\n", info->xmit_cnt, info->all_sent, jiffies); #endif } @@ -1573,10 +1681,13 @@ static void sab82532_hangup(struct tty_struct *tty) { struct sab82532 * info = (struct sab82532 *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "sab82532_hangup")) return; + if (info->is_console) + return; + sab82532_flush_buffer(tty); shutdown(info); info->event = 0; @@ -1754,7 +1865,6 @@ return -ENODEV; } - info->count++; if (serial_paranoia_check(info, tty->device, "sab82532_open")) return -ENODEV; @@ -1762,6 +1872,8 @@ printk("sab82532_open %s%d, count = %d\n", tty->driver.name, info->line, info->count); #endif + + info->count++; tty->driver_data = info; info->tty = tty; @@ -1774,7 +1886,22 @@ else tmp_buf = (unsigned char *) page; } - + + /* + * If the port is in the middle of closing, bail out now. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + /* * Start up serial port */ @@ -1801,6 +1928,14 @@ change_speed(info); } +#ifdef CONFIG_SERIAL_CONSOLE + if (sab82532_console.cflag && sab82532_console.index == line) { + tty->termios->c_cflag = sab82532_console.cflag; + sab82532_console.cflag = 0; + change_speed(info); + } +#endif + info->session = current->session; info->pgrp = current->pgrp; @@ -1856,7 +1991,7 @@ int i, len = 0; off_t begin = 0; - len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.4 $"); + len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.13 $"); for (i = 0; i < NR_PORTS && len < 4000; i++) { len += line_info(page + len, sab82532_table[i]); if (len+begin > off+count) @@ -1881,7 +2016,7 @@ * sab82532_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- */ -__initfunc(static int get_sab82532(void)) +__initfunc(static int get_sab82532(unsigned long *memory_start)) { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -1895,23 +2030,29 @@ if (!edev) return -ENODEV; - printk("%s: SAB82532 at 0x%lx IRQ %x\n", __FUNCTION__, - edev->base_address[0], edev->irqs[0]); - regs = edev->base_address[0]; offset = sizeof(union sab82532_async_regs); for (i = 0; i < 2; i++) { - sab = (struct sab82532 *)kmalloc(sizeof(struct sab82532), - GFP_KERNEL); - if (!sab) { - printk("sab82532: can't alloc sab struct\n"); - break; + if (memory_start) { + *memory_start = (*memory_start + 7) & ~(7); + sab = (struct sab82532 *)*memory_start; + *memory_start += sizeof(struct sab82532); + } else { + sab = (struct sab82532 *)kmalloc(sizeof(struct sab82532), + GFP_KERNEL); + if (!sab) { + printk("sab82532: can't alloc sab struct\n"); + break; + } } memset(sab, 0, sizeof(struct sab82532)); sab->regs = (union sab82532_async_regs *)(regs + offset); sab->irq = edev->irqs[0]; + sab->line = 1 - i; + sab->xmit_fifo_size = 32; + sab->recv_fifo_size = 32; if (check_region((unsigned long)sab->regs, sizeof(union sab82532_async_regs))) { @@ -1932,20 +2073,8 @@ return 0; } -/* Hooks for running a serial console. con_init() calls this if the - * console is run over one of the ttya/ttyb serial ports. - * 'chip' should be zero, as for now we only have one chip on board. - * 'line' is decoded as 0=ttya, 1=ttyb. - */ -void -sab82532_cons_hook(int chip, int out, int line) -{ - prom_printf("sab82532: serial console is not implemented, yet\n"); - prom_halt(); -} - -void -sab82532_kgdb_hook(int line) +__initfunc(static void +sab82532_kgdb_hook(int line)) { prom_printf("sab82532: kgdb support is not implemented, yet\n"); prom_halt(); @@ -1953,7 +2082,7 @@ __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.4 $"; + char *revision = "$Revision: 1.13 $"; char *version, *p; version = strchr(revision, ' '); @@ -1971,7 +2100,7 @@ int i; if (!sab82532_chain) - get_sab82532(); + get_sab82532(0); if (!sab82532_chain) return -ENODEV; @@ -2035,9 +2164,6 @@ for (info = sab82532_chain, i = 0; info; info = info->next, i++) { info->magic = SERIAL_MAGIC; - info->line = i; - info->tty = 0; - info->count = 0; info->type = info->regs->r.vstr & 0x0f; info->regs->w.pcr = ~((1 << 1) | (1 << 2) | (1 << 4)); @@ -2053,14 +2179,11 @@ info->regs->rw.mode |= SAB82532_MODE_FRTS; info->regs->rw.mode |= SAB82532_MODE_RTS; - info->xmit_fifo_size = 32; - info->recv_fifo_size = 32; info->custom_divisor = 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; info->x_char = 0; info->event = 0; - info->count = 0; info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; @@ -2086,9 +2209,9 @@ } } - printk(KERN_INFO "ttyS%02d at 0x%lx (irq = %x) is a %s\n", + printk(KERN_INFO "ttyS%02d at 0x%lx (irq = %x) is a SAB82532 %s\n", info->line, (unsigned long)info->regs, info->irq, - "SAB82532"); + sab82532_version[info->type]); } return 0; } @@ -2125,8 +2248,10 @@ return -ENODEV; found: +#ifdef CONFIG_SERIAL_CONSOLE + sunserial_setinitfunc(memory_start, sab82532_console_init); +#endif sunserial_setinitfunc(memory_start, sab82532_init); - rs_ops.rs_cons_hook = sab82532_cons_hook; rs_ops.rs_kgdb_hook = sab82532_kgdb_hook; return 0; } @@ -2134,7 +2259,7 @@ #ifdef MODULE int init_module(void) { - if (get_sab82532()) + if (get_sab82532(0)) return -ENODEV; return sab82532_init(); @@ -2171,3 +2296,200 @@ } } #endif /* MODULE */ + +#ifdef CONFIG_SERIAL_CONSOLE + +static void +sab82532_console_putchar(struct sab82532 *info, char c) +{ + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); + info->regs->w.tic = c; +} + +static void +sab82532_console_write(struct console *con, const char *s, unsigned n) +{ + struct sab82532 *info; + int i; + + info = sab82532_chain + con->index; + + for (i = 0; i < n; i++) { + if (*s == '\n') + sab82532_console_putchar(info, '\r'); + sab82532_console_putchar(info, *s++); + } + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); +} + +static int +sab82532_console_wait_key(struct console *con) +{ + sleep_on(&keypress_wait); + return 0; +} + +static kdev_t +sab82532_console_device(struct console *con) +{ + return MKDEV(TTY_MAJOR, 64 + con->index); +} + +static int +sab82532_console_setup(struct console *con, char *options) +{ + struct sab82532 *info; + unsigned int ebrg; + tcflag_t cflag; + unsigned char dafo; + int i, bits; + unsigned long flags; + + info = sab82532_chain + con->index; + info->is_console = 1; + + /* + * Initialize the hardware + */ + sab82532_init_line(info); + + /* + * Finally, enable interrupts + */ + info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + info->regs->w.imr0 = info->interrupt_mask0; + info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + + printk("Console: ttyS%d (SAB82532)\n", info->line); + + sunserial_console_termios(con); + cflag = con->cflag; + + /* Byte size and parity */ + switch (cflag & CSIZE) { + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + } + + if (cflag & CSTOPB) { + dafo |= SAB82532_DAFO_STOP; + bits++; + } + + if (cflag & PARENB) { + dafo |= SAB82532_DAFO_PARE; + bits++; + } + + if (cflag & PARODD) { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_MARK; + else +#endif + dafo |= SAB82532_DAFO_PAR_ODD; + } else { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_SPACE; + else +#endif + dafo |= SAB82532_DAFO_PAR_EVEN; + } + + /* Determine EBRG values based on baud rate */ + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~(CBAUDEX); + if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES)) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + ebrg = ebrg_table[i].n; + ebrg |= (ebrg_table[i].m << 6); + + if (ebrg_table[i].baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + else + info->timeout = 0; + info->timeout += HZ / 50; /* Add .02 seconds of slop */ + + /* CTS flow control flags */ + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~(ASYNC_CTS_FLOW); + + if (cflag & CLOCAL) + info->flags &= ~(ASYNC_CHECK_CD); + else + info->flags |= ASYNC_CHECK_CD; + + save_flags(flags); cli(); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); + info->regs->w.dafo = dafo; + info->regs->w.bgr = ebrg & 0xff; + info->regs->rw.ccr2 &= ~(0xc0); + info->regs->rw.ccr2 |= (ebrg >> 2) & 0xc0; + if (info->flags & ASYNC_CTS_FLOW) { + info->regs->rw.mode &= ~(SAB82532_MODE_RTS); + info->regs->rw.mode |= SAB82532_MODE_FRTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FCTS); + } else { + info->regs->rw.mode |= SAB82532_MODE_RTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); + info->regs->rw.mode |= SAB82532_MODE_FCTS; + } + info->regs->rw.mode |= SAB82532_MODE_RAC; + restore_flags(flags); + + return 0; +} + +static struct console sab82532_console = { + "ttyS", + sab82532_console_write, + NULL, + sab82532_console_device, + sab82532_console_wait_key, + NULL, + sab82532_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +__initfunc(int sab82532_console_init(void)) +{ + extern int con_is_present(void); + + if (con_is_present()) + return 0; + + if (!sab82532_chain) { + prom_printf("sab82532_console_setup: can't get SAB82532 chain"); + prom_halt(); + } + + sab82532_console.index = serial_console - 1; + register_console(&sab82532_console); + return 0; +} + +#endif /* CONFIG_SERIAL_CONSOLE */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sbuscons.c linux/drivers/sbus/char/sbuscons.c --- v2.1.78/linux/drivers/sbus/char/sbuscons.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/sbuscons.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: sbuscons.c,v 1.7 1997/08/28 09:30:07 davem Exp $ +/* $Id: sbuscons.c,v 1.10 1998/01/07 06:37:22 baccala Exp $ * sbuscons.c: Routines specific to SBUS frame buffer consoles. * * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su) @@ -1168,7 +1168,7 @@ const int cpl = chars_per_line; /* The register assignment is important here, do not modify without touching the assembly code as well */ register unsigned int x1 __asm__("g4"), x2 __asm__("g5"), x3 __asm__("g2"), x4 __asm__("g3"), flags __asm__("g7"); - register unsigned int *dst __asm__("g1"); + register unsigned int *dst; #else const int ipl = ints_per_line; unsigned int data2, data3, data4; @@ -1182,9 +1182,9 @@ if (j == ' ') /* space is quite common, so we optimize a bit */ { #ifdef ASM_BLITC #define BLITC_SPACE \ - "\n\t std %%g4, [%%g1]" \ - "\n\t std %%g4, [%%g1 + %0]" \ - "\n\t add %%g1, %1, %%g1" + "\n\t std %3, [%0]" \ + "\n\t std %3, [%0 + %1]" \ + "\n\t add %0, %2, %0" #define BLITC_SPC \ "\n\t std %0, [%1]" \ "\n\t std %0, [%1 + %2]" @@ -1195,7 +1195,7 @@ x3 = cpl << 1; __asm__ __volatile__ ( - "\n\t mov %2, %3" + "\n\t mov %3, %4" BLITC_SPACE BLITC_SPACE BLITC_SPACE @@ -1203,12 +1203,19 @@ BLITC_SPACE BLITC_SPACE BLITC_SPACE - : : "r" (cpl), "r" (x3), "r" (x1), "r" (x2)); + : "=r" (dst) + : "r" (cpl), "r" (x3), "r" (x1), "r" (x2)); __save_and_cli (flags); if (idx != cursor_pos) - __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (dst), "r" (cpl)); + __asm__ __volatile__ ( + BLITC_SPC + : /* no outputs */ + : "r" (x1), "r" (dst), "r" (cpl)); else - __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (under_cursor), "i" (8)); + __asm__ __volatile__ (BLITC_SPC + : /* no outputs */ + : "r" (x1), "r" (under_cursor), + "i" (8)); __restore_flags (flags); #else bgmask = attrib >> 4; diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.1.78/linux/drivers/sbus/char/su.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/su.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.3 1997/09/03 11:54:56 ecd Exp $ +/* $Id: su.c,v 1.4 1997/09/07 15:40:19 ecd Exp $ * su.c: Small serial driver for keyboard/mouse interface on Ultra/AX * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -150,16 +150,6 @@ struct su_struct *info = (struct su_struct *)dev_id; unsigned char status; - /* - * We might share interrupts with ps2kbd/ms driver, - * in case we want to use the 16550A as general serial - * driver in the presence of ps2 devices, so do a - * sanity check here, needs to be done in ps2kbd/ms - * driver, too. - */ - if (!info || info->magic != SERIAL_MAGIC) - return; - #ifdef SERIAL_DEBUG_INTR printk("su_interrupt(%d)...", irq); #endif @@ -644,12 +634,12 @@ * Does it match? */ if (sunode == kbnode) { - info->kbd_node = kbnode; + info->kbd_node = sunode; ++info; ++devices; } if (sunode == msnode) { - info->ms_node = msnode; + info->ms_node = sunode; ++info; ++devices; } @@ -674,5 +664,15 @@ found: sunserial_setinitfunc(memory_start, su_init); rs_ops.rs_change_mouse_baud = su_change_mouse_baud; + sunkbd_setinitfunc(memory_start, sun_kbd_init); + kbd_ops.compute_shiftstate = sun_compute_shiftstate; + kbd_ops.setledstate = sun_setledstate; + kbd_ops.getledstate = sun_getledstate; + kbd_ops.setkeycode = sun_setkeycode; + kbd_ops.getkeycode = sun_getkeycode; + sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, + sun_func_buf, sun_func_table, + sun_funcbufsize, sun_funcbufleft, + sun_accent_table, sun_accent_table_size); return 0; } diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c --- v2.1.78/linux/drivers/sbus/char/suncons.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/suncons.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: suncons.c,v 1.73 1997/08/25 07:50:33 jj Exp $ +/* $Id: suncons.c,v 1.77 1997/12/19 07:32:59 ecd Exp $ * suncons.c: Sparc platform console generic layer. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -100,13 +100,11 @@ static unsigned long nop_con_type_init(unsigned long mem_start, const char **display_desc) { - prom_printf("YIEEE: nop_con_type_init called!\n"); return mem_start; } static void nop_con_type_init_finish(void) { - prom_printf("YIEEE: nop_con_type_init_finish called!\n"); } static void nop_vesa_blank(void) @@ -323,12 +321,17 @@ extern void pci_console_inithook(void); #endif +__initfunc(int con_is_present(void)) +{ + return serial_console ? 0 : 1; +} + __initfunc(unsigned long sun_console_init(unsigned long memory_start)) { int i; /* Nothing to do in this case. */ - if(serial_console) + if (!con_is_present()) return memory_start; fbinfo = (fbinfo_t *)memory_start; @@ -358,7 +361,7 @@ __initfunc(unsigned long pci_console_init(unsigned long memory_start)) { /* Nothing to do in this case. */ - if(serial_console) + if (!con_is_present()) return memory_start; if(pci_console_probe()) { @@ -369,8 +372,6 @@ memory_start = finish_console_init(memory_start); con_type_init_finish(); - register_console(&vt_console_driver); - return memory_start; } #endif diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c --- v2.1.78/linux/drivers/sbus/char/sunfb.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/sunfb.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: sunfb.c,v 1.28 1997/08/22 15:55:23 jj Exp $ +/* $Id: sunfb.c,v 1.29 1997/09/20 20:47:26 davem Exp $ * sunfb.c: Sun generic frame buffer support. * * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -45,7 +45,7 @@ extern void set_cursor (int); #define FB_SETUP(err) \ - int minor = FB_DEV (inode->i_rdev); \ + int minor = FB_DEV (file->f_dentry->d_inode->i_rdev); \ \ if (minor >= fbinfos || \ fbinfo [minor].type.fb_type == FBTYPE_NOTYPE) \ @@ -229,7 +229,7 @@ } static int -fb_close (struct inode * inode, struct file *filp) +fb_close (struct inode * inode, struct file *file) { fbinfo_t *fb; struct fbcursor cursor; @@ -255,7 +255,7 @@ if (fb->open) fb->open = 0; - fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor); + fb_ioctl (inode, file, FBIOSCURPOS, (unsigned long) &cursor); set_other_palette (minor); if (!minor) { render_screen (); @@ -266,7 +266,7 @@ } static int -fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) +fb_mmap (struct file *file, struct vm_area_struct *vma) { fbinfo_t *fb; FB_SETUP(ENXIO) @@ -276,7 +276,7 @@ if (fb->mmap){ int v; - v = (*fb->mmap)(inode, file, vma, fb->base, fb); + v = (*fb->mmap)(file->f_dentry->d_inode, file, vma, fb->base, fb); if (v) return v; vma->vm_flags |= VM_IO; diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.1.78/linux/drivers/sbus/char/sunkbd.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/sbus/char/sunkbd.c Mon Jan 12 15:15:45 1998 @@ -6,6 +6,7 @@ * compatibility - Miguel (miguel@nuclecu.unam.mx) * * Added PCI 8042 controller support -DaveM + * Added Magic SysRq support -MJ */ #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -77,10 +79,10 @@ extern void scrollfront(int); struct l1a_kbd_state l1a_state = { 0, 0 }; -unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ -unsigned char aux_device_present = 0x00; /* To make kernel/ksyms.c happy */ +#ifndef CONFIG_PCI struct wait_queue * keypress_wait = NULL; +#endif void keyboard_wait_for_keypress(void) { @@ -96,7 +98,6 @@ /* shift state counters.. */ static unsigned char k_down[NR_SHIFT] = {0, }; /* keyboard key bitmap */ -#define BITS_PER_LONG (8*sizeof(unsigned long)) static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; void push_kbd (int scan); @@ -108,7 +109,9 @@ * the variable must be global, or a new procedure must be created to * return the value. I chose the former way. */ +#ifndef CONFIG_PCI /*static*/ int shift_state = 0; +#endif static int npadch = -1; /* -1 or number assembled on pad */ static unsigned char diacr = 0; static char rep = 0; /* flag telling character repeat */ @@ -120,7 +123,7 @@ static int kbd_delay_ticks = HZ / 5; static int kbd_rate_ticks = HZ / 20; -extern void compute_shiftstate(void); +void sun_compute_shiftstate(void); typedef void (*k_hand)(unsigned char value, char up_flag); typedef void (k_handfn)(unsigned char value, char up_flag); @@ -151,13 +154,16 @@ }; /* maximum values each key_handler can handle */ +#ifndef CONFIG_PCI const int max_vals[] = { 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, NR_DEAD - 1, 255, 3, NR_SHIFT - 1, - 255, NR_ASCII - 1, NR_LOCK - 1, 255 + 255, NR_ASCII - 1, NR_LOCK - 1, 255, + NR_LOCK - 1 }; const int NR_TYPES = SIZE(max_vals); +#endif static void put_queue(int); static unsigned char handle_diacr(unsigned char); @@ -165,6 +171,18 @@ /* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ static struct pt_regs * pt_regs; +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char sun_sysrq_xlate[128] = + "\0\0\0\0\0\201\202\212\203\213\204\214\205\0\206\0" /* 0x00 - 0x0f */ + "\207\210\211\0\0\0\0\0\0\0\0\0\0\03312" /* 0x10 - 0x1f */ + "34567890-=`\177\0=/*" /* 0x20 - 0x2f */ + "\0\0.\0\0\011qwertyuiop" /* 0x30 - 0x3f */ + "[]\177\000789-\0\0\0\0\0asd" /* 0x40 - 0x4f */ + "fghjkl;'\\\015\0154560\0" /* 0x50 - 0x5f */ + "\0\0\0\0zxcvbnm,./\0\012" /* 0x60 - 0x6f */ + "123\0\0\0\0\0\0 \0\0\0\0\0\0"; /* 0x70 - 0x7f */ +#endif + volatile unsigned char sunkbd_layout; volatile unsigned char sunkbd_type; #define SUNKBD_TYPE2 0x02 @@ -222,7 +240,7 @@ #define KEY_ALT 0x86 #define KEY_L1 0x87 -/* Do to kbd_init() being called before rs_init(), and kbd_init() doing: +/* Do to sun_kbd_init() being called before rs_init(), and sun_kbd_init() doing: * * init_bh(KEYBOARD_BH, kbd_bh); * mark_bh(KEYBOARD_BH); @@ -394,7 +412,7 @@ }; -int setkeycode(unsigned int scancode, unsigned int keycode) +int sun_setkeycode(unsigned int scancode, unsigned int keycode) { if (scancode < SC_LIM || scancode > 255 || keycode > 127) return -EINVAL; @@ -405,7 +423,7 @@ return 0; } -int getkeycode(unsigned int scancode) +int sun_getkeycode(unsigned int scancode) { return (scancode < SC_LIM || scancode > 255) ? -EINVAL : @@ -468,7 +486,7 @@ } else if(ch == SKBD_ALLUP) { del_timer (&auto_repeat_timer); memset(key_down, 0, sizeof(key_down)); - compute_shiftstate(); + sun_compute_shiftstate(); goto out; } #ifdef SKBD_DEBUG @@ -520,6 +538,14 @@ rep = test_and_set_bit(keycode, key_down); } +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq hack */ + if (l1a_state.l1_down) { + if (!up_flag) + handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, kbd, tty); + goto out; + } +#endif + if(raw_mode) goto out; @@ -548,7 +574,7 @@ u_char type; /* the XOR below used to be an OR */ - int shift_final = shift_state ^ kbd->lockstate; + int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; ushort *key_map = key_maps[shift_final]; if (key_map != NULL) { @@ -572,7 +598,7 @@ } else { /* maybe beep? */ /* we have at least to update shift_state */ - compute_shiftstate(); + sun_compute_shiftstate(); } } out: @@ -774,7 +800,7 @@ static void do_null() { - compute_shiftstate(); + sun_compute_shiftstate(); } static void do_spec(unsigned char value, char up_flag) @@ -981,7 +1007,7 @@ /* called after returning from RAW mode or when changing consoles - recompute k_down[] and shift_state from key_down[] */ /* maybe called when keymap is undefined, so that shiftkey release is seen */ -void compute_shiftstate(void) +void sun_compute_shiftstate(void) { int i, j, k, sym, val; @@ -1055,11 +1081,11 @@ static unsigned char sunkbd_ledstate = 0xff; /* undefined */ static unsigned char ledioctl; -unsigned char getledstate(void) { +unsigned char sun_getledstate(void) { return ledstate; } -void setledstate(struct kbd_struct *kbd, unsigned int led) { +void sun_setledstate(struct kbd_struct *kbd, unsigned int led) { if (!(led & ~7)) { ledioctl = led; kbd->ledmode = LED_SHOW_IOCTL; @@ -1181,7 +1207,7 @@ extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -__initfunc(int kbd_init(void)) +__initfunc(int sun_kbd_init(void)) { int i, opt_node; struct kbd_struct kbd0; @@ -1190,6 +1216,7 @@ kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; kbd0.ledmode = LED_SHOW_FLAGS; kbd0.lockstate = KBD_DEFLOCK; + kbd0.slockstate = 0; kbd0.modeflags = KBD_DEFMODE; kbd0.kbdmode = VC_XLATE; @@ -1245,8 +1272,8 @@ wake_up_interruptible (&kbd_wait); } -static long -kbd_read (struct inode *inode, struct file *f, char *buffer, unsigned long count) +static ssize_t +kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos) { struct wait_queue wait = { current, NULL }; char *end, *p; @@ -1278,12 +1305,11 @@ } /* Needed by X */ -static int -kbd_fasync (struct inode *inode, struct file *filp, int on) +static int kbd_fasync (struct file *filp, int on) { int retval; - retval = fasync_helper (inode, filp, on, &kb_fasync); + retval = fasync_helper (filp, on, &kb_fasync); if (retval < 0) return retval; return 0; @@ -1353,7 +1379,7 @@ if (c & LED_NLOCK) leds |= (1 << VC_NUMLOCK); if (c & LED_CLOCK) leds |= (1 << VC_CAPSLOCK); compose_led_on = !!(c & LED_CMPOSE); - setledstate(kbd_table + fg_console, leds); + sun_setledstate(kbd_table + fg_console, leds); break; case KIOCGLED: put_user_ret(vcleds_to_sunkbd(getleds()), (unsigned char *) arg, -EFAULT); @@ -1433,7 +1459,7 @@ kbd_redirected = 0; kbd_opened = 0; - kbd_fasync (i, f, 0); + kbd_fasync (f, 0); return 0; } diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sunkbd.h linux/drivers/sbus/char/sunkbd.h --- v2.1.78/linux/drivers/sbus/char/sunkbd.h Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/sunkbd.h Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: sunkbd.h,v 1.1 1997/08/28 02:23:34 ecd Exp $ +/* $Id: sunkbd.h,v 1.3 1997/09/08 03:05:10 tdyas Exp $ * sunkbd.h: Defines needed by SUN Keyboard drivers * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -7,6 +7,8 @@ #ifndef _SPARC_SUNKBD_H #define _SPARC_SUNKBD_H 1 +#include + /* Keyboard defines for L1-A processing... */ #define SUNKBD_RESET 0xff #define SUNKBD_L1 0x01 @@ -23,5 +25,27 @@ extern void keyboard_zsinit(void (*kbd_put_char)(unsigned char)); extern void sunkbd_inchar(unsigned char, struct pt_regs *); extern void batten_down_hatches(void); + +extern int sun_kbd_init(void); +extern void sun_compute_shiftstate(void); +extern void sun_setledstate(struct kbd_struct *, unsigned int); +extern unsigned char sun_getledstate(void); +extern int sun_setkeycode(unsigned int, unsigned int); +extern int sun_getkeycode(unsigned int); + +#ifdef CONFIG_PCI + +extern ushort *sun_key_maps[MAX_NR_KEYMAPS]; +extern unsigned int sun_keymap_count; + +extern char sun_func_buf[]; +extern char *sun_func_table[MAX_NR_FUNC]; +extern int sun_funcbufsize; +extern int sun_funcbufleft; + +extern struct kbdiacr sun_accent_table[MAX_DIACR]; +extern unsigned int sun_accent_table_size; + +#endif /* CONFIG_PCI */ #endif /* !(_SPARC_SUNKBD_H) */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sunkbdmap.c linux/drivers/sbus/char/sunkbdmap.c --- v2.1.78/linux/drivers/sbus/char/sunkbdmap.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/sunkbdmap.c Mon Jan 12 15:15:45 1998 @@ -0,0 +1,33 @@ + +/* $Id: sunkbdmap.c,v 1.1 1997/09/07 15:40:27 ecd Exp $ + * sunkbdmap.c: Wrapper around sunkeymap.c to change table names. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + */ + +#include + +#ifdef CONFIG_PCI + +#define func_buf sun_func_buf +#define func_table sun_func_table +#define funcbufsize sun_funcbufsize +#define funcbufleft sun_funcbufleft +#define funcbufptr sun_funcbufptr +#define accent_table sun_accent_table +#define accent_table_size sun_accent_table_size + +#define key_maps sun_key_maps +#define keymap_count sun_keymap_count + +#define plain_map sun_plain_map +#define shift_map sun_shift_map +#define ctrl_map sun_ctrl_map +#define alt_map sun_alt_map +#define altgr_map sun_altgr_map +#define shift_ctrl_map sun_shift_ctrl_map +#define ctrl_alt_map sun_ctrl_alt_map + +#endif /* CONFIG_PCI */ + +#include "sunkeymap.c" diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.1.78/linux/drivers/sbus/char/sunmouse.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/sbus/char/sunmouse.c Mon Jan 12 15:15:45 1998 @@ -329,12 +329,11 @@ return 0; } -static int -sun_mouse_fasync (struct inode *inode, struct file *filp, int on) +static int sun_mouse_fasync (struct file *filp, int on) { int retval; - retval = fasync_helper (inode, filp, on, &sunmouse.fasync); + retval = fasync_helper (filp, on, &sunmouse.fasync); if (retval < 0) return retval; return 0; @@ -343,23 +342,23 @@ static int sun_mouse_close(struct inode *inode, struct file *file) { - sun_mouse_fasync (inode, file, 0); + sun_mouse_fasync (file, 0); if (--sunmouse.active) return 0; sunmouse.ready = 0; return 0; } -static long -sun_mouse_write(struct inode *inode, struct file *file, const char *buffer, - unsigned long count) +static ssize_t +sun_mouse_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) { return -EINVAL; /* foo on you */ } -static long -sun_mouse_read(struct inode *inode, struct file *file, char *buffer, - unsigned long count) +static ssize_t +sun_mouse_read(struct file *file, char *buffer, + size_t count, loff_t *ppos) { struct wait_queue wait = { current, NULL }; @@ -399,7 +398,7 @@ } } sunmouse.ready = !queue_empty (); - inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = CURRENT_TIME; return p-buffer; } else { int c; @@ -410,7 +409,7 @@ sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; } sunmouse.ready = !queue_empty(); - inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-c; } /* Only called if nothing was sent */ @@ -484,8 +483,11 @@ __initfunc(int sun_mouse_init(void)) { + if (!sunmouse.present) + return -ENODEV; + printk("Sun Mouse-Systems mouse driver version 1.00\n"); - sunmouse.present = 1; + sunmouse.ready = sunmouse.active = 0; misc_register (&sun_mouse_mouse); sunmouse.delta_x = sunmouse.delta_y = 0; @@ -498,5 +500,5 @@ void sun_mouse_zsinit(void) { - sunmouse.ready = 1; + sunmouse.present = 1; } diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.1.78/linux/drivers/sbus/char/sunserial.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/sunserial.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.50 1997/09/03 11:54:59 ecd Exp $ +/* $Id: sunserial.c,v 1.56 1997/12/19 07:33:07 ecd Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -9,17 +9,19 @@ #include #include #include +#include +#include +#include +#include #include #include "sunserial.h" -static void nop_rs_cons_hook(int chip, int out, int line) -{ - printk("Oops: %s called\n", __FUNCTION__); -} +int serial_console; -static void nop_rs_kgdb_hook(int channel) +__initfunc(static void +nop_rs_kgdb_hook(int channel)) { printk("Oops: %s called\n", __FUNCTION__); } @@ -36,10 +38,8 @@ return 0; } - struct sunserial_operations rs_ops = { 0, - nop_rs_cons_hook, nop_rs_kgdb_hook, nop_rs_change_mouse_baud, nop_rs_read_proc @@ -47,25 +47,41 @@ int rs_init(void) { - struct rs_initfunc *init; + struct initfunc *init; int err = -ENODEV; init = rs_ops.rs_init; while (init) { - err = init->rs_init(); + err = init->init(); init = init->next; } return err; } -void rs_cons_hook(int chip, int out, int line) +__initfunc(void +rs_kgdb_hook(int channel)) { - rs_ops.rs_cons_hook(chip, out, line); + rs_ops.rs_kgdb_hook(channel); } -void rs_kgdb_hook(int channel) +__initfunc(static void sun_serial_finish_init(void)) { - rs_ops.rs_kgdb_hook(channel); + extern unsigned char *linux_serial_image; + extern int con_is_present(void); + char buffer[2048]; + + if (con_is_present()) + return; + + sprintf (buffer, linux_serial_image, UTS_RELEASE); + printk(buffer); +} + +__initfunc(long +serial_console_init(long kmem_start, long kmem_end)) +{ + sun_serial_finish_init(); + return kmem_start; } void rs_change_mouse_baud(int baud) @@ -88,45 +104,299 @@ { } + +static void nop_compute_shiftstate (void) +{ + printk("Oops: %s called\n", __FUNCTION__); +} + +static void nop_setledstate (struct kbd_struct *kbd, unsigned int ledstate) +{ + printk("Oops: %s called\n", __FUNCTION__); +} + +static unsigned char nop_getledstate (void) +{ + printk("Oops: %s called\n", __FUNCTION__); + return 0; +} + +static int nop_setkeycode (unsigned int scancode, unsigned int keycode) +{ + printk("Oops: %s called\n", __FUNCTION__); + return -EINVAL; +} + +static int nop_getkeycode (unsigned int scancode) +{ + printk("Oops: %s called\n", __FUNCTION__); + return -EINVAL; +} + +struct sunkbd_operations kbd_ops = { + 0, + nop_compute_shiftstate, + nop_setledstate, + nop_getledstate, + nop_setkeycode, + nop_getkeycode +}; + +int kbd_init(void) +{ + struct initfunc *init; + int err = -ENODEV; + + init = kbd_ops.kbd_init; + while (init) { + err = init->init(); + init = init->next; + } + return err; +} + +void compute_shiftstate (void) +{ + kbd_ops.compute_shiftstate(); +} + +void setledstate (struct kbd_struct *kbd, unsigned int ledstate) +{ + kbd_ops.setledstate(kbd, ledstate); +} + +unsigned char getledstate (void) +{ + return kbd_ops.getledstate(); +} + +int setkeycode (unsigned int scancode, unsigned int keycode) +{ + return kbd_ops.setkeycode(scancode, keycode); +} + +int getkeycode (unsigned int scancode) +{ + return kbd_ops.getkeycode(scancode); +} + + void sunserial_setinitfunc(unsigned long *memory_start, int (*init) (void)) { - struct rs_initfunc *rs_init; + struct initfunc *rs_init; *memory_start = (*memory_start + 7) & ~(7); - rs_init = (struct rs_initfunc *) *memory_start; - *memory_start += sizeof(struct rs_initfunc); + rs_init = (struct initfunc *) *memory_start; + *memory_start += sizeof(struct initfunc); - rs_init->rs_init = init; + rs_init->init = init; rs_init->next = rs_ops.rs_init; rs_ops.rs_init = rs_init; } +void +sunserial_console_termios(struct console *con) +{ + char mode[16], buf[16], *s; + char *mode_prop = "ttyX-mode"; + char *cd_prop = "ttyX-ignore-cd"; + char *dtr_prop = "ttyX-rts-dtr-off"; + int baud, bits, stop, cflag; + char parity; + int carrier = 0; + int rtsdtr = 1; + int topnd, nd; + + if (!serial_console) + return; + + if (serial_console == 1) { + mode_prop[3] = 'a'; + cd_prop[3] = 'a'; + dtr_prop[3] = 'a'; + } else { + mode_prop[3] = 'b'; + cd_prop[3] = 'b'; + dtr_prop[3] = 'b'; + } + + topnd = prom_getchild(prom_root_node); + nd = prom_searchsiblings(topnd, "options"); + if (!nd) { + strcpy(mode, "9600,8,n,1,-"); + goto no_options; + } + + if (!prom_node_has_property(nd, mode_prop)) { + strcpy(mode, "9600,8,n,1,-"); + goto no_options; + } + + memset(mode, 0, sizeof(mode)); + prom_getstring(nd, mode_prop, mode, sizeof(mode)); + + if (prom_node_has_property(nd, cd_prop)) { + memset(buf, 0, sizeof(buf)); + prom_getstring(nd, cd_prop, buf, sizeof(buf)); + if (!strcmp(buf, "false")) + carrier = 1; + + /* XXX: this is unused below. */ + } + + if (prom_node_has_property(nd, cd_prop)) { + memset(buf, 0, sizeof(buf)); + prom_getstring(nd, cd_prop, buf, sizeof(buf)); + if (!strcmp(buf, "false")) + rtsdtr = 0; + + /* XXX: this is unused below. */ + } + +no_options: + cflag = CREAD | HUPCL | CLOCAL; + + s = mode; + baud = simple_strtoul(s, 0, 0); + s = strchr(s, ','); + bits = simple_strtoul(++s, 0, 0); + s = strchr(s, ','); + parity = *(++s); + s = strchr(s, ','); + stop = simple_strtoul(++s, 0, 0); + s = strchr(s, ','); + /* XXX handshake is not handled here. */ + + switch (baud) { + case 150: cflag |= B150; break; + case 300: cflag |= B300; break; + case 600: cflag |= B600; break; + case 1200: cflag |= B1200; break; + case 2400: cflag |= B2400; break; + case 4800: cflag |= B4800; break; + case 9600: cflag |= B9600; break; + case 19200: cflag |= B19200; break; + case 38400: cflag |= B38400; break; + default: cflag |= B9600; break; + } + + switch (bits) { + case 5: cflag |= CS5; break; + case 6: cflag |= CS6; break; + case 7: cflag |= CS7; break; + case 8: cflag |= CS8; break; + default: cflag |= CS8; break; + } + + switch (parity) { + case 'o': cflag |= (PARENB | PARODD); break; + case 'e': cflag |= PARENB; break; + case 'n': default: break; + } + + switch (stop) { + case 2: cflag |= CSTOPB; break; + case 1: default: break; + } + + con->cflag = cflag; +} + +void +sunkbd_setinitfunc(unsigned long *memory_start, int (*init) (void)) +{ + struct initfunc *kbd_init; + + *memory_start = (*memory_start + 7) & ~(7); + kbd_init = (struct initfunc *) *memory_start; + *memory_start += sizeof(struct initfunc); + + kbd_init->init = init; + kbd_init->next = kbd_ops.kbd_init; + kbd_ops.kbd_init = kbd_init; +} + +#ifdef CONFIG_PCI +void +sunkbd_install_keymaps(unsigned long *memory_start, + ushort **src_key_maps, unsigned int src_keymap_count, + char *src_func_buf, char **src_func_table, + int src_funcbufsize, int src_funcbufleft, + struct kbdiacr *src_accent_table, + unsigned int src_accent_table_size) +{ + extern unsigned int keymap_count; + int i, j; + + for (i = 0; i < MAX_NR_KEYMAPS; i++) { + if (src_key_maps[i]) { + if (!key_maps[i]) { + key_maps[i] = (ushort *)*memory_start; + *memory_start += NR_KEYS * sizeof(ushort); + } + for (j = 0; j < NR_KEYS; j++) + key_maps[i][j] = src_key_maps[i][j]; + } + key_maps[i] = src_key_maps[i]; + } + keymap_count = src_keymap_count; + + for (i = 0; i < MAX_NR_FUNC; i++) + func_table[i] = src_func_table[i]; + funcbufptr = src_func_buf; + funcbufsize = src_funcbufsize; + funcbufleft = src_funcbufleft; + + for (i = 0; i < MAX_DIACR; i++) + accent_table[i] = src_accent_table[i]; + accent_table_size = src_accent_table_size; +} +#endif + extern int zs_probe(unsigned long *); #ifdef CONFIG_SAB82532 extern int sab82532_probe(unsigned long *); #endif -#ifdef __sparc_v9__ +#ifdef CONFIG_PCI extern int ps2kbd_probe(unsigned long *); extern int su_probe(unsigned long *); #endif -unsigned long -sun_serial_setup(unsigned long memory_start) +__initfunc(unsigned long +sun_serial_setup(unsigned long memory_start)) { + int ret = -ENODEV; + /* Probe for controllers. */ - if (zs_probe(&memory_start) == 0) + ret = zs_probe(&memory_start); + if (!ret) return memory_start; #ifdef CONFIG_SAB82532 - sab82532_probe(&memory_start); + ret = sab82532_probe(&memory_start); #endif -#ifdef __sparc_v9__ - if (ps2kbd_probe(&memory_start) == 0) - return memory_start; - if (su_probe(&memory_start) == 0) - return memory_start; +#ifdef CONFIG_PCI + /* + * Keyboard serial devices. + * + * Well done, Sun, prom_devopen("/pci@1f,4000/ebus@1/su@14,3083f8") + * hangs the machine if no keyboard is connected to the device... + * All PCI PROMs seem to do this, I have seen this on the Ultra 450 + * with version 3.5 PROM, and on the Ultra/AX with 3.1.5 PROM. + * + * So be very careful not to probe for keyboards if we are on a + * serial console. + */ + if (!serial_console) { + if (ps2kbd_probe(&memory_start) == 0) + return memory_start; + if (su_probe(&memory_start) == 0) + return memory_start; + } #endif + if (!ret) + return memory_start; prom_printf("No serial devices found, bailing out.\n"); prom_halt(); diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/sunserial.h linux/drivers/sbus/char/sunserial.h --- v2.1.78/linux/drivers/sbus/char/sunserial.h Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/char/sunserial.h Mon Jan 12 15:15:45 1998 @@ -1,5 +1,5 @@ -/* $Id: sunserial.h,v 1.13 1997/09/03 11:55:00 ecd Exp $ - * sunserial.h: SUN serial driver infrastructure. +/* $Id: sunserial.h,v 1.17 1997/12/19 07:33:12 ecd Exp $ + * sunserial.h: SUN serial driver infrastructure (including keyboards). * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) */ @@ -7,42 +7,45 @@ #ifndef _SPARC_SUNSERIAL_H #define _SPARC_SUNSERIAL_H 1 +#include #include - -struct rs_initfunc { - int (*rs_init) (void); - struct rs_initfunc *next; +#include +#include +#include + +struct initfunc { + int (*init) (void); + struct initfunc *next; }; struct sunserial_operations { - struct rs_initfunc *rs_init; - void (*rs_cons_hook) (int, int, int); - void (*rs_kgdb_hook) (int); - void (*rs_change_mouse_baud) (int); - int (*rs_read_proc) (char *, char **, off_t, int, int *, void *); + struct initfunc *rs_init; + void (*rs_kgdb_hook) (int); + void (*rs_change_mouse_baud) (int); + int (*rs_read_proc) (char *, char **, off_t, int, int *, void *); }; -/* - * XXX: Work in progress, don't worry this will go away in a few days. (ecd) - * - * To support multiple keyboards in one binary we have to take care - * about (at least) the following: - * - * int shift_state; - * - * char *func_buf; - * char *func_bufptr; - * int funcbufsize; - * int funcbufleft; - * char **func_table; - * - * XXX: keymaps need to be handled... - * - * struct kbd_struct *kbd_table; - * int (*kbd_init)(void); - */ +struct sunkbd_operations { + struct initfunc *kbd_init; + void (*compute_shiftstate) (void); + void (*setledstate) (struct kbd_struct *, unsigned int); + unsigned char (*getledstate) (void); + int (*setkeycode) (unsigned int, unsigned int); + int (*getkeycode) (unsigned int); +}; extern struct sunserial_operations rs_ops; +extern struct sunkbd_operations kbd_ops; + extern void sunserial_setinitfunc(unsigned long *, int (*) (void)); +extern void sunkbd_setinitfunc(unsigned long *, int (*) (void)); + +extern int serial_console; +extern void sunserial_console_termios(struct console *); + +#ifdef CONFIG_PCI +extern void sunkbd_install_keymaps(unsigned long *, ushort **, unsigned int, char *, + char **, int, int, struct kbdiacr *, unsigned int); +#endif #endif /* !(_SPARC_SUNSERIAL_H) */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.1.78/linux/drivers/sbus/char/zs.c Wed Sep 24 20:05:47 1997 +++ linux/drivers/sbus/char/zs.c Mon Jan 12 15:15:45 1998 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.3 1997/09/04 14:57:34 jj Exp $ +/* $Id: zs.c,v 1.15 1997/12/22 16:09:34 jj Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -22,8 +22,8 @@ #include #include #include -#include #include +#include #include #include @@ -36,6 +36,9 @@ #include #ifdef __sparc_v9__ #include +#ifdef CONFIG_PCI +#include +#endif #endif #include "sunserial.h" @@ -52,7 +55,6 @@ struct sun_zslayout **zs_chips; struct sun_zschannel **zs_channels; -struct sun_zschannel *zs_conschan; struct sun_zschannel *zs_mousechan; struct sun_zschannel *zs_kbdchan; struct sun_zschannel *zs_kgdbchan; @@ -63,12 +65,12 @@ int zilog_irq; struct tty_struct *zs_ttys; -/** struct tty_struct *zs_constty; **/ /* Console hooks... */ -static int zs_cons_chanout = 0; -static int zs_cons_chanin = 0; -struct sun_serial *zs_consinfo = 0; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console zs_console; +static int zs_console_init(void); +#endif static unsigned char kgdb_regs[16] = { 0, 0, 0, /* write 0, 1, 2 */ @@ -114,6 +116,8 @@ /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 +#define SERIAL_DO_RESTART + /* Debugging... DEBUG_INTR is bad to use when one of the zs * lines is your console ;( */ @@ -127,8 +131,7 @@ #define _INLINE_ inline int zs_init(void); -void zs_cons_hook(int, int, int); -void zs_kgdb_hook(int); +static void zs_kgdb_hook(int); static void change_speed(struct sun_serial *info); @@ -443,20 +446,29 @@ return; } if(info->is_cons) { +#ifdef CONFIG_MAGIC_SYSRQ + static int serial_sysrq; + + if (!ch) { + serial_sysrq = 1; + return; + } else if (serial_sysrq) { + if (ch == 'a' || ch == 'A') + /* whee, break-A received */ + batten_down_hatches(); + else + handle_sysrq(ch, regs, NULL, NULL); + serial_sysrq = 0; + return; + } +#else if(ch==0) { /* whee, break received */ batten_down_hatches(); /* Continue execution... */ return; -#if 0 - } else if (ch == 1) { - show_state(); - return; - } else if (ch == 2) { - show_buffers(); - return; -#endif } +#endif /* It is a 'keyboard interrupt' ;-) */ wake_up(&keypress_wait); } @@ -996,21 +1008,6 @@ restore_flags(flags); } - -/* This is for console output over ttya/ttyb */ -static void zs_cons_put_char(char ch) -{ - struct sun_zschannel *chan = zs_conschan; - unsigned long flags; - - if(!chan) - return; - - save_flags(flags); cli(); - zs_put_char(chan, ch); - restore_flags(flags); -} - /* These are for receiving and sending characters under the kgdb * source level kernel debugger. */ @@ -1032,70 +1029,6 @@ return chan->data; } -/* - * Fair output driver allows a process to speak. - */ -static void zs_fair_output(void) -{ - int left; /* Output no more than that */ - unsigned long flags; - struct sun_serial *info = zs_consinfo; - char c; - - if (info == 0) return; - if (info->xmit_buf == 0) return; - - save_flags(flags); cli(); - left = info->xmit_cnt; - while (left != 0) { - c = info->xmit_buf[info->xmit_tail]; - info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - restore_flags(flags); - - zs_cons_put_char(c); - - cli(); - left = MIN(info->xmit_cnt, left-1); - } - - /* Last character is being transmitted now (hopefully). */ - zs_conschan->control = RES_Tx_P; - udelay(5); - - restore_flags(flags); - return; -} - -/* - * zs_console_print is registered for printk. - */ -static void zs_console_print(const char *s, unsigned count) -{ - int i; - - for (i = 0; i < count; i++, s++) { - if(*s == '\n') - zs_cons_put_char('\r'); - zs_cons_put_char(*s); - } - - /* Comment this if you want to have a strict interrupt-driven output */ - zs_fair_output(); -} - -static void zs_console_wait_key(void) -{ - sleep_on(&keypress_wait); -} - -static int zs_console_device(void) -{ - extern int serial_console; - - return MKDEV(TTYAUX_MAJOR, 64 + serial_console - 1); -} - static void zs_flush_chars(struct tty_struct *tty) { struct sun_serial *info = (struct sun_serial *)tty->driver_data; @@ -1190,7 +1123,7 @@ { struct sun_serial *info = (struct sun_serial *)tty->driver_data; int ret; - + if (serial_paranoia_check(info, tty->device, "zs_write_room")) return 0; ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; @@ -1202,7 +1135,7 @@ static int zs_chars_in_buffer(struct tty_struct *tty) { struct sun_serial *info = (struct sun_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "zs_chars_in_buffer")) return 0; return info->xmit_cnt; @@ -1211,7 +1144,7 @@ static void zs_flush_buffer(struct tty_struct *tty) { struct sun_serial *info = (struct sun_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "zs_flush_buffer")) return; cli(); @@ -1641,10 +1574,13 @@ void zs_hangup(struct tty_struct *tty) { struct sun_serial * info = (struct sun_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "zs_hangup")) return; - + + if (info->is_cons) + return; + #ifdef SERIAL_DEBUG_OPEN printk("zs_hangup<%p: tty-%d, count = %d bye\n", __builtin_return_address(0), info->line, info->count); @@ -1862,6 +1798,14 @@ change_speed(info); } +#ifdef CONFIG_SERIAL_CONSOLE + if (zs_console.cflag && zs_console.index == line) { + tty->termios->c_cflag = zs_console.cflag; + zs_console.cflag = 0; + change_speed(info); + } +#endif + info->session = current->session; info->pgrp = current->pgrp; @@ -1875,7 +1819,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.3 $"; + char *revision = "$Revision: 1.15 $"; char *version, *p; version = strchr(revision, ' '); @@ -1895,7 +1839,8 @@ #ifdef __sparc_v9__ static struct devid_cookie zs_dcookie; static unsigned long zs_irq_flags; -static struct sun_zslayout *get_zs(int chip) +__initfunc(static struct sun_zslayout * +get_zs(int chip)) { unsigned int vaddr[2] = { 0, 0 }; int busnode, seen, zsnode, sun4u_ino; @@ -1968,13 +1913,16 @@ return (struct sun_zslayout *)(unsigned long) vaddr[0]; } #else /* !(__sparc_v9__) */ -static struct sun_zslayout *get_zs(int chip) +__initfunc(static struct sun_zslayout * +get_zs(int chip)) { struct linux_prom_irqs tmp_irq[2]; unsigned int paddr = 0; unsigned int vaddr[2] = { 0, 0 }; - int zsnode, tmpnode, iospace, slave, len, seen, sun4u_irq; + int zsnode, tmpnode, iospace, slave, len; + int cpunode = 0, bbnode = 0; static int irq = 0; + int chipid = chip; #if CONFIG_AP1000 printk("No zs chip\n"); @@ -2014,7 +1962,10 @@ if (board == (chip >> 1)) { node = prom_getchild(tmpnode); if (node && (node = prom_searchsiblings(node, "bootbus"))) { - zsnode = node; + cpunode = tmpnode; + bbnode = node; + zsnode = prom_getchild(node); + chipid = (chip & 1); break; } } @@ -2022,10 +1973,6 @@ } if (!tmpnode) panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1); - } else if (sparc_cpu_model == sun4u) { - tmpnode = prom_searchsiblings(zsnode, "sbus"); - if(tmpnode) - zsnode = prom_getchild(tmpnode); } else { tmpnode = prom_searchsiblings(zsnode, "obio"); if(tmpnode) @@ -2033,41 +1980,46 @@ } if(!zsnode) panic("get_zs no zs serial prom node"); - seen = 0; while(zsnode) { zsnode = prom_searchsiblings(zsnode, "zs"); slave = prom_getintdefault(zsnode, "slave", -1); - if((slave == chip) || - (sparc_cpu_model == sun4u && seen == chip)) { + if(slave == chipid) { /* The one we want */ - len = prom_getproperty(zsnode, "address", - (void *) vaddr, - sizeof(vaddr)); - if (len % sizeof(unsigned int)) { - prom_printf("WHOOPS: proplen for %s " - "was %d, need multiple of " - "%d\n", "address", len, - sizeof(unsigned int)); - panic("zilog: address property"); - } - zs_nodes[chip] = zsnode; - if(sparc_cpu_model == sun4u) { - len = prom_getproperty(zsnode, "interrupts", - (char *) &sun4u_irq, - sizeof(tmp_irq)); - tmp_irq[0].pri = sun4u_irq; - } else { - len = prom_getproperty(zsnode, "intr", - (char *) tmp_irq, - sizeof(tmp_irq)); - if (len % sizeof(struct linux_prom_irqs)) { - prom_printf( - "WHOOPS: proplen for %s " - "was %d, need multiple of " - "%d\n", "address", len, - sizeof(struct linux_prom_irqs)); + if (sparc_cpu_model != sun4d) { + len = prom_getproperty(zsnode, "address", + (void *) vaddr, + sizeof(vaddr)); + if (len % sizeof(unsigned int)) { + prom_printf("WHOOPS: proplen for %s " + "was %d, need multiple of " + "%d\n", "address", len, + sizeof(unsigned int)); panic("zilog: address property"); } + } else { + /* On sun4d don't have address property :( */ + struct linux_prom_registers zsreg[4]; + + if (prom_getproperty(zsnode, "reg", (char *)zsreg, sizeof(zsreg)) == -1) { + prom_printf ("Cannot map zs regs\n"); + prom_halt(); + } + prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1); + vaddr[0] = (unsigned long) + sparc_alloc_io(zsreg[0].phys_addr, 0, 8, + "Zilog Serial", zsreg[0].which_io, 0); + } + zs_nodes[chip] = zsnode; + len = prom_getproperty(zsnode, "intr", + (char *) tmp_irq, + sizeof(tmp_irq)); + if (len % sizeof(struct linux_prom_irqs)) { + prom_printf( + "WHOOPS: proplen for %s " + "was %d, need multiple of " + "%d\n", "address", len, + sizeof(struct linux_prom_irqs)); + panic("zilog: address property"); } if(!irq) { irq = zilog_irq = tmp_irq[0].pri; @@ -2078,7 +2030,6 @@ break; } zsnode = prom_getsibling(zsnode); - seen++; } if(!zsnode) panic("get_zs whee chip not found"); @@ -2089,242 +2040,6 @@ return (struct sun_zslayout *)(unsigned long) vaddr[0]; } #endif - -static inline void -init_zscons_termios(struct termios *termios) -{ - char mode[16], buf[16]; - char *mode_prop = "ttyX-mode"; - char *cd_prop = "ttyX-ignore-cd"; - char *dtr_prop = "ttyX-rts-dtr-off"; - char *s; - int baud, bits, cflag; - char parity; - int topnd, nd; - int channel, stop; - int carrier = 0; - int rtsdtr = 1; - extern int serial_console; - - if (!serial_console) - return; - - if (serial_console == 1) { - mode_prop[3] = 'a'; - cd_prop[3] = 'a'; - dtr_prop[3] = 'a'; - } else { - mode_prop[3] = 'b'; - cd_prop[3] = 'b'; - dtr_prop[3] = 'b'; - } - - topnd = prom_getchild(prom_root_node); - nd = prom_searchsiblings(topnd, "options"); - if (!nd) { - strcpy(mode, "9600,8,n,1,-"); - goto no_options; - } - - if (!prom_node_has_property(nd, mode_prop)) { - strcpy(mode, "9600,8,n,1,-"); - goto no_options; - } - - memset(mode, 0, sizeof(mode)); - prom_getstring(nd, mode_prop, mode, sizeof(mode)); - - if (prom_node_has_property(nd, cd_prop)) { - memset(buf, 0, sizeof(buf)); - prom_getstring(nd, cd_prop, buf, sizeof(buf)); - if (!strcmp(buf, "false")) - carrier = 1; - - /* XXX this is unused below. */ - } - - if (prom_node_has_property(nd, cd_prop)) { - memset(buf, 0, sizeof(buf)); - prom_getstring(nd, cd_prop, buf, sizeof(buf)); - if (!strcmp(buf, "false")) - rtsdtr = 0; - - /* XXX this is unused below. */ - } - -no_options: - cflag = CREAD | HUPCL | CLOCAL; - - s = mode; - baud = simple_strtoul(s, 0, 0); - s = strchr(s, ','); - bits = simple_strtoul(++s, 0, 0); - s = strchr(s, ','); - parity = *(++s); - s = strchr(s, ','); - stop = simple_strtoul(++s, 0, 0); - s = strchr(s, ','); - /* XXX handshake is not handled here. */ - - for (channel = 0; channel < NUM_CHANNELS; channel++) - if (zs_soft[channel].is_cons) - break; - - switch (baud) { - case 150: - cflag |= B150; - break; - case 300: - cflag |= B300; - break; - case 600: - cflag |= B600; - break; - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - default: - baud = 9600; - case 9600: - cflag |= B9600; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - } - zs_soft[channel].zs_baud = baud; - - switch (bits) { - case 5: - zscons_regs[3] = Rx5 | RxENAB; - zscons_regs[5] = Tx5 | TxENAB; - zs_soft[channel].parity_mask = 0x1f; - cflag |= CS5; - break; - case 6: - zscons_regs[3] = Rx6 | RxENAB; - zscons_regs[5] = Tx6 | TxENAB; - zs_soft[channel].parity_mask = 0x3f; - cflag |= CS6; - break; - case 7: - zscons_regs[3] = Rx7 | RxENAB; - zscons_regs[5] = Tx7 | TxENAB; - zs_soft[channel].parity_mask = 0x7f; - cflag |= CS7; - break; - default: - case 8: - zscons_regs[3] = Rx8 | RxENAB; - zscons_regs[5] = Tx8 | TxENAB; - zs_soft[channel].parity_mask = 0xff; - cflag |= CS8; - break; - } - zscons_regs[5] |= DTR; - - switch (parity) { - case 'o': - zscons_regs[4] |= PAR_ENAB; - cflag |= (PARENB | PARODD); - break; - case 'e': - zscons_regs[4] |= (PAR_ENAB | PAR_EVEN); - cflag |= PARENB; - break; - default: - case 'n': - break; - } - - switch (stop) { - default: - case 1: - zscons_regs[4] |= SB1; - break; - case 2: - cflag |= CSTOPB; - zscons_regs[4] |= SB2; - break; - } - - termios->c_cflag = cflag; -} - -__initfunc(static void serial_finish_init(void (*printfunc)(const char *, unsigned))) -{ - extern unsigned char *linux_serial_image; - char buffer[2048]; - - sprintf (buffer, linux_serial_image, UTS_RELEASE); - (*printfunc)(buffer, strlen(buffer)); -} - -static inline void -zs_cons_check(struct sun_serial *ss, int channel) -{ - int i, o, io; - static int consout_registered = 0; - static int msg_printed = 0; - static struct console console = { - zs_console_print, 0, - zs_console_wait_key, zs_console_device }; - - i = o = io = 0; - - /* Is this one of the serial console lines? */ - if((zs_cons_chanout != channel) && - (zs_cons_chanin != channel)) - return; - zs_conschan = ss->zs_channel; - zs_consinfo = ss; - - /* Register the console output putchar, if necessary */ - if((zs_cons_chanout == channel)) { - o = 1; - /* double whee.. */ - if(!consout_registered) { - serial_finish_init (zs_console_print); - register_console(&console); - consout_registered = 1; - } - } - - /* If this is console input, we handle the break received - * status interrupt on this line to mean prom_halt(). - */ - if(zs_cons_chanin == channel) { - ss->break_abort = 1; - i = 1; - } - if(o && i) - io = 1; - - /* Set flag variable for this port so that it cannot be - * opened for other uses by accident. - */ - ss->is_cons = 1; - - if(io) { - if(!msg_printed) { - printk("zs%d: console I/O\n", ((channel>>1)&1)); - msg_printed = 1; - } - } else { - printk("zs%d: console %s\n", ((channel>>1)&1), - (i==1 ? "input" : (o==1 ? "output" : "WEIRD"))); - } -} - /* This is for the auto baud rate detection in the mouse driver. */ void zs_change_mouse_baud(int newbaud) { @@ -2347,10 +2062,11 @@ if(sparc_cpu_model == sun4) goto no_probe; + NUM_SERIAL = 0; + node = prom_getchild(prom_root_node); if (sparc_cpu_model == sun4d) { node = prom_searchsiblings(node, "boards"); - NUM_SERIAL = 0; if (!node) panic ("Cannot find out count of boards"); else @@ -2360,22 +2076,38 @@ node = prom_getsibling(node); } goto no_probe; - } else if (sparc_cpu_model == sun4u) { - node = prom_searchsiblings(node, "sbus"); - if(node) + } +#ifdef __sparc_v9__ + else if (sparc_cpu_model == sun4u) { + int central_node; + + /* Central bus zilogs must be checked for first, + * since Enterprise boxes have SBUS as well. + */ + central_node = prom_finddevice("/central"); + if(central_node != 0 && central_node != -1) + node = prom_searchsiblings(prom_getchild(central_node), "fhc"); + else + node = prom_searchsiblings(node, "sbus"); + if(node != 0 && node != -1) node = prom_getchild(node); - if(!node) + if(node == 0 || node == -1) return -ENODEV; - } else { + } +#endif /* __sparc_v9__ */ + else { node = prom_searchsiblings(node, "obio"); if(node) node = prom_getchild(node); + NUM_SERIAL = 2; goto no_probe; } node = prom_searchsiblings(node, "zs"); if (!node) return -ENODEV; + + NUM_SERIAL = 2; no_probe: p = (char *)((*memory_start + 7) & ~7); @@ -2399,17 +2131,85 @@ *memory_start = (((unsigned long)p) + i + 7) & ~7; /* Fill in rs_ops struct... */ +#ifdef CONFIG_SERIAL_CONSOLE + sunserial_setinitfunc(memory_start, zs_console_init); +#endif sunserial_setinitfunc(memory_start, zs_init); - rs_ops.rs_cons_hook = zs_cons_hook; rs_ops.rs_kgdb_hook = zs_kgdb_hook; rs_ops.rs_change_mouse_baud = zs_change_mouse_baud; + sunkbd_setinitfunc(memory_start, sun_kbd_init); + kbd_ops.compute_shiftstate = sun_compute_shiftstate; + kbd_ops.setledstate = sun_setledstate; + kbd_ops.getledstate = sun_getledstate; + kbd_ops.setkeycode = sun_setkeycode; + kbd_ops.getkeycode = sun_getkeycode; +#ifdef CONFIG_PCI + sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, + sun_func_buf, sun_func_table, + sun_funcbufsize, sun_funcbufleft, + sun_accent_table, sun_accent_table_size); +#endif return 0; } +static inline void zs_prepare(void) +{ + int channel, chip; + unsigned long flags; + + if (!NUM_SERIAL) return; + + save_and_cli(flags); + + /* Set up our interrupt linked list */ + zs_chain = &zs_soft[0]; + for(channel = 0; channel < NUM_CHANNELS - 1; channel++) { + zs_soft[channel].zs_next = &zs_soft[channel + 1]; + zs_soft[channel].line = channel; + } + zs_soft[channel].zs_next = 0; + + /* Initialize Softinfo */ + for(chip = 0; chip < NUM_SERIAL; chip++) { + /* If we are doing kgdb over one of the channels on + * chip zero, kgdb_channel will be set to 1 by the + * zs_kgdb_hook() routine below. + */ + if(!zs_chips[chip]) { + zs_chips[chip] = get_zs(chip); + /* Two channels per chip */ + zs_channels[(chip*2)] = &zs_chips[chip]->channelA; + zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; + zs_soft[(chip*2)].kgdb_channel = 0; + zs_soft[(chip*2)+1].kgdb_channel = 0; + } + + /* First, set up channel A on this chip. */ + channel = chip * 2; + zs_soft[channel].zs_channel = zs_channels[channel]; + zs_soft[channel].change_needed = 0; + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].cons_keyb = 0; + zs_soft[channel].cons_mouse = 0; + zs_soft[channel].channelA = 1; + + /* Now, channel B */ + channel++; + zs_soft[channel].zs_channel = zs_channels[channel]; + zs_soft[channel].change_needed = 0; + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].cons_keyb = 0; + zs_soft[channel].cons_mouse = 0; + zs_soft[channel].channelA = 0; + } + + restore_flags(flags); +} + __initfunc(int zs_init(void)) { - int chip, channel, brg, i; + int channel, brg, i; unsigned long flags; struct sun_serial *info; char dummy; @@ -2420,7 +2220,7 @@ #endif #ifdef CONFIG_PCI - if (prom_searchsiblings(prom_getchild(prom_root_node), "pci")) + if (pcibios_present()) return 0; #endif @@ -2444,7 +2244,6 @@ serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver.flags = TTY_DRIVER_REAL_RAW; @@ -2472,8 +2271,6 @@ serial_driver.read_proc = 0; serial_driver.proc_entry = 0; - init_zscons_termios(&serial_driver.init_termios); - /* * The callout device is just like normal device except for * major number and the subtype code. @@ -2487,48 +2284,11 @@ panic("Couldn't register serial driver\n"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver\n"); - - save_flags(flags); cli(); - /* Set up our interrupt linked list */ - zs_chain = &zs_soft[0]; - for(channel = 0; channel < NUM_CHANNELS - 1; channel++) - zs_soft[channel].zs_next = &zs_soft[channel + 1]; - zs_soft[channel + 1].zs_next = 0; + save_flags(flags); cli(); /* Initialize Softinfo */ - for(chip = 0; chip < NUM_SERIAL; chip++) { - /* If we are doing kgdb over one of the channels on - * chip zero, kgdb_channel will be set to 1 by the - * zs_kgdb_hook() routine below. - */ - if(!zs_chips[chip]) { - zs_chips[chip] = get_zs(chip); - /* Two channels per chip */ - zs_channels[(chip*2)] = &zs_chips[chip]->channelA; - zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; - zs_soft[(chip*2)].kgdb_channel = 0; - zs_soft[(chip*2)+1].kgdb_channel = 0; - } - - /* First, set up channel A on this chip. */ - channel = chip * 2; - zs_soft[channel].zs_channel = zs_channels[channel]; - zs_soft[channel].change_needed = 0; - zs_soft[channel].clk_divisor = 16; - zs_soft[channel].cons_keyb = 0; - zs_soft[channel].cons_mouse = 0; - zs_soft[channel].channelA = 1; - - /* Now, channel B */ - channel++; - zs_soft[channel].zs_channel = zs_channels[channel]; - zs_soft[channel].change_needed = 0; - zs_soft[channel].clk_divisor = 16; - zs_soft[channel].cons_keyb = 0; - zs_soft[channel].cons_mouse = 0; - zs_soft[channel].channelA = 0; - } + zs_prepare(); /* Initialize Hardware */ for(channel = 0; channel < NUM_CHANNELS; channel++) { @@ -2719,50 +2479,13 @@ return 0; } -/* Hooks for running a serial console. con_init() calls this if the - * console is being run over one of the ttya/ttyb serial ports. - * 'chip' should be zero, as chip 1 drives the mouse/keyboard. - * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels - * are addressed backwards, channel B is first, then channel A. - */ -void -zs_cons_hook(int chip, int out, int line) -{ - int channel; - -#ifdef CONFIG_PCI - if (prom_searchsiblings(prom_getchild(prom_root_node), "pci")) - return; -#endif - - if(chip) - panic("zs_cons_hook called with chip not zero"); - if(line != 1 && line != 2) - panic("zs_cons_hook called with line not ttya or ttyb"); - channel = line - 1; - if(!zs_chips[chip]) { - zs_chips[chip] = get_zs(chip); - /* Two channels per chip */ - zs_channels[(chip*2)] = &zs_chips[chip]->channelA; - zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; - } - zs_soft[channel].zs_channel = zs_channels[channel]; - zs_soft[channel].change_needed = 0; - zs_soft[channel].clk_divisor = 16; - if(out) - zs_cons_chanout = ((chip * 2) + channel); - else - zs_cons_chanin = ((chip * 2) + channel); - zs_cons_check(&zs_soft[channel], channel); -} - /* This is called at boot time to prime the kgdb serial debugging * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */ -void -zs_kgdb_hook(int tty_num) +__initfunc(static void +zs_kgdb_hook(int tty_num)) { int chip = 0; @@ -2784,3 +2507,183 @@ ZS_CLEARERR(zs_kgdbchan); ZS_CLEARFIFO(zs_kgdbchan); } + +#ifdef CONFIG_SERIAL_CONSOLE + +/* This is for console output over ttya/ttyb */ +static void +zs_console_putchar(struct sun_serial *info, char ch) +{ + unsigned long flags; + + if(!info->zs_channel) + return; + + save_flags(flags); cli(); + zs_put_char(info->zs_channel, ch); + restore_flags(flags); +} + +/* + * Fair output driver allows a process to speak. + */ +static void zs_fair_output(struct sun_serial *info) +{ + int left; /* Output no more than that */ + unsigned long flags; + char c; + + if (info == 0) return; + if (info->xmit_buf == 0) return; + + save_flags(flags); cli(); + left = info->xmit_cnt; + while (left != 0) { + c = info->xmit_buf[info->xmit_tail]; + info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + restore_flags(flags); + + zs_console_putchar(info, c); + + cli(); + left = MIN(info->xmit_cnt, left-1); + } + + /* Last character is being transmitted now (hopefully). */ + info->zs_channel->control = RES_Tx_P; + udelay(5); + + restore_flags(flags); + return; +} + +/* + * zs_console_write is registered for printk. + */ +static void +zs_console_write(struct console *con, const char *s, unsigned count) +{ + struct sun_serial *info; + int i; + + info = zs_soft + con->index; + + for (i = 0; i < count; i++, s++) { + if(*s == '\n') + zs_console_putchar(info, '\r'); + zs_console_putchar(info, *s); + } + + /* Comment this if you want to have a strict interrupt-driven output */ + zs_fair_output(info); +} + +static int +zs_console_wait_key(struct console *con) +{ + sleep_on(&keypress_wait); + return 0; +} + +static kdev_t zs_console_device(struct console *con) +{ + return MKDEV(TTY_MAJOR, 64 + con->index); +} + +__initfunc(static int +zs_console_setup(struct console *con, char *options)) +{ + struct sun_serial *info; + int i, brg, baud; + + info = zs_soft + con->index; + info->is_cons = 1; + + printk("Console: ttyS%d (Zilog8530)\n", info->line); + + sunserial_console_termios(con); + + i = con->cflag & CBAUD; + if (con->cflag & CBAUDEX) { + i &= ~CBAUDEX; + con->cflag &= ~CBAUDEX; + } + baud = baud_table[i]; + info->zs_baud = baud; + + switch (con->cflag & CSIZE) { + case CS5: + zscons_regs[3] = Rx5 | RxENAB; + zscons_regs[5] = Tx5 | TxENAB; + info->parity_mask = 0x1f; + break; + case CS6: + zscons_regs[3] = Rx6 | RxENAB; + zscons_regs[5] = Tx6 | TxENAB; + info->parity_mask = 0x3f; + break; + case CS7: + zscons_regs[3] = Rx7 | RxENAB; + zscons_regs[5] = Tx7 | TxENAB; + info->parity_mask = 0x7f; + break; + default: + case CS8: + zscons_regs[3] = Rx8 | RxENAB; + zscons_regs[5] = Tx8 | TxENAB; + info->parity_mask = 0xff; + break; + } + zscons_regs[5] |= DTR; + + if (con->cflag & PARENB) + zscons_regs[4] |= PAR_ENAB; + if (!(con->cflag & PARODD)) + zscons_regs[4] |= PAR_EVEN; + + if (con->cflag & CSTOPB) + zscons_regs[4] |= SB2; + else + zscons_regs[4] |= SB1; + + brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor); + zscons_regs[12] = brg & 0xff; + zscons_regs[13] = (brg >> 8) & 0xff; + + memcpy(info->curregs, zscons_regs, sizeof(zscons_regs)); + load_zsregs(info, zscons_regs); + + ZS_CLEARERR(info->zs_channel); + ZS_CLEARFIFO(info->zs_channel); + return 0; +} + +static struct console zs_console = { + "ttyS", + zs_console_write, + NULL, + zs_console_device, + zs_console_wait_key, + NULL, + zs_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +__initfunc(static int +zs_console_init(void)) +{ + extern int con_is_present(void); + + if (con_is_present()) + return 0; + + zs_console.index = serial_console - 1; + register_console(&zs_console); + return 0; +} + +#endif /* CONFIG_SERIAL_CONSOLE */ diff -u --recursive --new-file v2.1.78/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c --- v2.1.78/linux/drivers/sbus/sbus.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/sbus/sbus.c Mon Jan 12 15:15:45 1998 @@ -65,13 +65,16 @@ base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; if(base>=SUN_SBUS_BVADDR || - sparc_cpu_model == sun4m || - sparc_cpu_model == sun4u) { + (sparc_cpu_model != sun4c && + sparc_cpu_model != sun4)) { /* Ahh, we can determine the slot and offset */ if(sparc_cpu_model == sun4u) { /* A bit tricky on the SYSIO. */ sbus_dev->slot = sbus_dev->reg_addrs[0].which_io; sbus_dev->offset = sbus_dev_offset(base); + } else if (sparc_cpu_model == sun4d) { + sbus_dev->slot = sbus_dev->reg_addrs[0].which_io; + sbus_dev->offset = base; } else { sbus_dev->slot = sbus_dev_slot(base); sbus_dev->offset = sbus_dev_offset(base); @@ -181,19 +184,20 @@ extern unsigned long sun_console_init(unsigned long); extern unsigned long iommu_init(int iommu_node, unsigned long memstart, unsigned long memend, struct linux_sbus *sbus); -extern void iommu_sun4d_init(int sbi_node, struct linux_sbus *sbus); +extern unsigned long iounit_init(int sbi_node, int iounit_node, unsigned long memstart, + unsigned long memend, struct linux_sbus *sbus); #ifdef CONFIG_SUN_OPENPROMIO extern int openprom_init(void); #endif #ifdef CONFIG_SUN_MOSTEK_RTC extern int rtc_init(void); #endif -#ifdef CONFIG_SPARCAUDIO -extern int sparcaudio_init(void); -#endif #ifdef CONFIG_SUN_AUXIO extern void auxio_probe(void); #endif +#ifdef CONFIG_OBP_FLASH +extern int flash_init(void); +#endif __initfunc(static unsigned long sbus_do_child_siblings(unsigned long memory_start, int start_node, @@ -247,7 +251,7 @@ memory_start = ((memory_start + 7) & (~7)); topnd = prom_getchild(prom_root_node); - + /* Finding the first sbus is a special case... */ iommund = 0; if(sparc_cpu_model == sun4u) { @@ -287,19 +291,10 @@ sbus->next = 0; this_sbus=nd; - if(sparc_cpu_model != sun4u) - /* Have IOMMU will travel. - * - * XXX This should be per sbus on sun4d... - */ - if(iommund) { - if (sparc_cpu_model == sun4d) - iommu_sun4d_init(this_sbus, sbus); - else - memory_start = iommu_init(iommund, - memory_start, memory_end, - sbus); - } + if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d) + memory_start = iommu_init(iommund, + memory_start, memory_end, + sbus); /* Loop until we find no more SBUS's */ while(this_sbus) { @@ -311,7 +306,12 @@ memory_start = iommu_init(this_sbus, memory_start, memory_end, sbus); - +#ifndef __sparc_v9__ + else if (sparc_cpu_model == sun4d) + memory_start = iounit_init(this_sbus, iommund, + memory_start, memory_end, + sbus); +#endif #ifdef E3000_DEBUG prom_printf("1"); #endif @@ -323,9 +323,16 @@ (((sbus_clock/1000)%1000) + 1000) : 0)); prom_getstring(this_sbus, "name", lbuf, sizeof(lbuf)); + lbuf[sizeof(sbus->prom_name) - 1] = 0; sbus->prom_node = this_sbus; strcpy(sbus->prom_name, lbuf); sbus->clock_freq = sbus_clock; +#ifndef __sparc_v9__ + if (sparc_cpu_model == sun4d) { + sbus->devid = prom_getint(iommund, "device-id"); + sbus->board = prom_getint(iommund, "board#"); + } +#endif #ifdef E3000_DEBUG prom_printf("psri()"); @@ -458,6 +465,12 @@ break; } } /* while(this_sbus) */ + if (sparc_cpu_model == sun4d) { + extern unsigned long sun4d_init_sbi_irq(unsigned long); + + memory_start = sun4d_init_sbi_irq(memory_start); + } + #ifdef E3000_DEBUG prom_printf("sbus_init: No more sbus's, calling sun_console_init()\n"); #endif @@ -471,15 +484,15 @@ #ifdef CONFIG_SUN_MOSTEK_RTC rtc_init(); #endif -#ifdef CONFIG_SPARCAUDIO - sparcaudio_init(); -#endif #ifdef CONFIG_SUN_BPP bpp_init(); #endif #ifdef CONFIG_SUN_AUXIO if (sparc_cpu_model == sun4u) auxio_probe (); +#endif +#ifdef CONFIG_OBP_FLASH + flash_init(); #endif #ifdef __sparc_v9__ if (sparc_cpu_model == sun4u) { diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.1.78/linux/drivers/scsi/ChangeLog.ncr53c8xx Wed Sep 24 20:05:47 1997 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Jan 12 15:05:27 1998 @@ -1,3 +1,30 @@ +Fri Jan 2 18:00 1998 Gerard Roudier (groudier@club-internet.fr) + * Revision 2.5f + - Use FAST-5 instead of SLOW for slow scsi devices according to + new SPI-2 draft. + - Make some changes in order to accomodate with 875 rev <= 3 + device errata listing 397. Minor consequences are: + . Leave use of PCI Write and Invalidate under user control. + Now, by default the driver does not enable PCI MWI and option + 'specf:y' is required in order to enable this feature. + . Memory Read Line is not enabled for 875 and 875-like chips. + . Programmed burst length set to 64 DWORDS (instead of 128). + (Note: SYMBIOS uses 32 DWORDS for the SDMS BIOS) + +Sun Oct 26 12:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.5e + - Add 'buschk' boot option. + This option enables checking of SCSI BUS data lines after SCSI + RESET (set by default). (Submitted by Richard Waltham). + - Update the README file. + +Sat Oct 4 18:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.5d + - Dispatch CONDITION MET and RESERVATION CONFLICT scsi status + as OK driver status. + - Update the README file and the Symbios NVRAM format definition + with removable media flags values (available with SDMS 4.09). + Sat Sep 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr) * revision 2.5c - Several PCI configuration registers fix-ups for powerpc. diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.1.78/linux/drivers/scsi/README.ncr53c8xx Wed Sep 3 20:52:43 1997 +++ linux/drivers/scsi/README.ncr53c8xx Mon Jan 12 15:05:27 1998 @@ -4,7 +4,7 @@ 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -23 August 1997 +2 January 1998 =============================================================================== 1. Introduction @@ -30,6 +30,7 @@ 10.3 Advised boot setup commands 10.4 PCI configuration fix-up boot option 10.5 Serial NVRAM support boot option + 10.6 SCSI BUS checking boot option 11. Some constants and flags of the ncr53c8xx.h header file 12. Installation 12.1 Provided files @@ -38,6 +39,8 @@ 14. Known problems 14.1 Tagged commands with Iomega Jaz device 14.2 Device names change when another controller is added + 14.3 Using only 8 bit devices with a WIDE SCSI controller. + 14.4 Possible data corruption during a Memory Write and Invalidate 15. SCSI problem troubleshooting 16. Synchonous transfer negotiation tables 16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers @@ -490,7 +493,9 @@ 10.1 Syntax -Setup commands can be passed to the driver at boot time. +Setup commands can be passed to the driver either at boot time or as a +string variable using 'insmod'. + A boot setup command for the ncr53c8xx driver begins with the driver name "ncr53c8xx=". The kernel syntax parser then expects an optionnal list of integers separated with comma followed by an optionnal list of comma- @@ -502,7 +507,14 @@ - set synchronous negotiation speed to 10 Mega-transfers / second. - set DEBUG_NEGO flag. -For the moment, the integer list of arguments is disgarded by the driver. +Since comma seems not to be allowed when defining a string variable using +'insmod', the driver also accepts as option separator. +The following command will install driver module with the same options as +above. + +insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200" + +For the moment, the integer list of arguments is discarded by the driver. It will be used in the future in order to allow a per controller setup. Each string argument must be specified as "keyword:value". Only lower-case @@ -525,8 +537,12 @@ Special features Only apply to 810A, 825A, 860 and 875 controllers. Have no effect with normal 810 and 825. - specf:y enabled - specf:n disabled + specf:y (or 1) enabled + specf:n (or 0) disabled + specf:3 enabled except Memory Write And Invalidate + The default driver setup is 'specf:3'. As a consequence, option 'specf:y' + must be specified in the boot setup command to enable Memory Write And + Invalidate. Ultra SCSI support Only apply to 860 and 875 controllers. @@ -628,6 +644,7 @@ pcifix: