diff -u --recursive --new-file v2.3.15/linux/CREDITS linux/CREDITS --- v2.3.15/linux/CREDITS Thu Aug 26 13:05:34 1999 +++ linux/CREDITS Tue Aug 31 11:27:38 1999 @@ -810,7 +810,7 @@ D: Selection mechanism N: Andre Hedrick -E: hedrick@astro.dyer.vanderbilt.edu +E: andre@suse.com D: Random SMP kernel hacker... D: Uniform Multi-Platform E-IDE driver D: Aladdin 1533/1543(C) chipset @@ -1031,6 +1031,16 @@ S: 80-283 Gdansk S: Poland +N: Dave Jones +E: dave@powertweak.com +W: http://linux.powertweak.com +D: Centaur/IDT Winchip/Winchip 2 tweaks +D: Misc clean ups and other random hacking. +S: 40, Heol Edward Lewis, +S: Gelligaer, Hengoed, +S: Mid Glamorgan, CF82 8EJ, +S: Wales, United Kingdom + N: Bernhard Kaindl E: bkaindl@netway.at E: edv@bartelt.via.at @@ -2362,6 +2372,7 @@ E: lnz@dandelion.com W: http://www.dandelion.com/Linux/ D: BusLogic SCSI driver +D: Mylex DAC960 PCI RAID driver D: Miscellaneous kernel fixes S: 3078 Sulphur Spring Court S: San Jose, California 95148 diff -u --recursive --new-file v2.3.15/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.15/linux/Documentation/Changes Thu Aug 26 13:05:34 1999 +++ linux/Documentation/Changes Tue Aug 31 11:02:26 1999 @@ -243,7 +243,7 @@ modules) are currently distributed separately: see http://antarctica.penguincomputing.com/~netfilter/ http://www.samba.org/netfilter/ - http://netfilter.kernenotes.org + http://netfilter.kernelnotes.org DHCP clients for 2.0 do not work with the new networking code in the 2.2 kernel. You will need to upgrade your dhcpcd / dhcpclient. @@ -419,9 +419,16 @@ ========= Linux PCI utils are available; these include lspci, which displays -the detailed information about your system's PCI devices which used to -be in /proc/pci, and setpci, which allws you to read and write -configuration registers on your PCI devices. +detailed information about your system's PCI devices (much more than +the basic things in /proc/pci), and setpci, which allows you to read +and write PCI configuration registers of your devices. + +Powertweak +========== + + The PCI Bridge Optimization has been removed from the kernel. If you +think your BIOS does a poor job when setting up your chipset, there +is a utility called PowerTweak whose job is to tune chipset parameters. Xosview ======= @@ -734,9 +741,16 @@ PCI utils ========= -The 1.09 release: -ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-1.09.tar.gz -ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-1.09.tar.gz +The 2.0 release: +ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.0.tar.gz +ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.0.tar.gz + +Powertweak +========== + +The 0.1.2 release: +http://linux.powertweak.com/files/powertweak-0.1.2.tgz +ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/powertweak/powertweak-0.1.2.tgz Tunelp ====== diff -u --recursive --new-file v2.3.15/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.15/linux/Documentation/Configure.help Thu Aug 26 13:05:34 1999 +++ linux/Documentation/Configure.help Mon Aug 30 18:05:57 1999 @@ -168,6 +168,11 @@ on the Alpha. The only time you would ever not say Y is to say M in order to debug the code. Say Y unless you know what you are doing. +Big memory support +CONFIG_BIGMEM + This option is required if you want to utilize physical memory which + is not covered by the kernel virtual address space (> 1GB). + Normal PC floppy disk support CONFIG_BLK_DEV_FD If you want to use the floppy disk drive(s) of your PC under Linux, @@ -931,6 +936,17 @@ It's pretty unlikely that you have one of these: say N. +Mylex DAC960/DAC1100 PCI RAID Controller support +CONFIG_BLK_DEV_DAC960 + This driver adds support for the Mylex DAC960, AcceleRAID, and + eXtremeRAID PCI RAID controllers. See README.DAC960 for further + information about this driver. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called DAC960.o. + Parallel port IDE device support CONFIG_PARIDE There are many external CD-ROM and disk devices that connect through @@ -4047,6 +4063,15 @@ kernel. The default value has been reduced to 5 seconds. If this doesn't work with your hardware, try increasing this value. +IBM ServeRAID Support +CONFIG_SCSI_IPS + This is support for the IBM ServeRAID hardware RAID controllers. + Consult the SCSI-HOWTO, available via anonymous FTP from + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, and the file + README.ips in drivers/scsi for more information. If this driver + does not work correctly without modification please contact the + author by email at ipslinux@us.ibm.com. + BusLogic SCSI support CONFIG_SCSI_BUSLOGIC This is support for BusLogic MultiMaster and FlashPoint SCSI Host @@ -9081,6 +9106,35 @@ module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called dtlk.o. + +Siemens R3964 serial protocol support +CONFIG_R3964 + This driver allows syncronous communication with devices using the + Siemens R3964 packet protocol. Unless you are dealing with special + hardware like PLCs, you are unlikely to need this. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. The module will be called + n_r3964.o. + + If unsure, say N. + +Applicom intelligent fieldbus card support +CONFIG_APPLICOM + This driver provides the kernel-side support for the intelligent + fieldbus cards made by Applicom International. More information + about these cards can be found on the WWW at the address + http://www.applicom-int.com/ (to browse the WWW, you need to have + access to a machine on the Internet that has a program like lynx + or netscape), or by email from David Woodhouse . + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. The module will be called + applicom.o. + + If unsure, say N. Advanced Power Management CONFIG_APM diff -u --recursive --new-file v2.3.15/linux/Documentation/README.DAC960 linux/Documentation/README.DAC960 --- v2.3.15/linux/Documentation/README.DAC960 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/README.DAC960 Mon Aug 30 10:24:14 1999 @@ -0,0 +1,717 @@ + Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux + + Version 2.2.4 for Linux 2.2.11 + Version 2.0.4 for Linux 2.0.37 + + PRODUCTION RELEASE + + 23 August 1999 + + Leonard N. Zubkoff + Dandelion Digital + lnz@dandelion.com + + Copyright 1998-1999 by Leonard N. Zubkoff + + + INTRODUCTION + +Mylex, Inc. designs and manufactures a variety of high performance PCI RAID +controllers. Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont, +California 94555, USA and can be reached at 510/796-6100 or on the World Wide +Web at http://www.mylex.com. Mylex RAID Technical Support can be reached by +electronic mail at support@mylex.com (for eXtremeRAID 1100 and older DAC960 +models) or techsup@mylex.com (for AcceleRAID models), by voice at 510/608-2400, +or by FAX at 510/745-7715. Contact information for offices in Europe and Japan +is available on the Web site. + +The latest information on Linux support for DAC960 PCI RAID Controllers, as +well as the most recent release of this driver, will always be available from +my Linux Home Page at URL "http://www.dandelion.com/Linux/". The Linux DAC960 +driver supports all current DAC960 PCI family controllers including the +AcceleRAID models, as well as the eXtremeRAID 1100; see below for a complete +list. For simplicity, in most places this documentation refers to DAC960 +generically rather than explicitly listing all the models. + +Bug reports should be sent via electronic mail to "lnz@dandelion.com". Please +include with the bug report the complete configuration messages reported by the +driver at startup, along with any subsequent system messages relevant to the +controller's operation, and a detailed description of your system's hardware +configuration. + +Please consult the DAC960 RAID controller documentation for detailed +information regarding installation and configuration of the controllers. This +document primarily provides information specific to the Linux DAC960 support. + + + DRIVER FEATURES + +The DAC960 RAID controllers are supported solely as high performance RAID +controllers, not as interfaces to arbitrary SCSI devices. The Linux DAC960 +driver operates at the block device level, the same level as the SCSI and IDE +drivers. Unlike other RAID controllers currently supported on Linux, the +DAC960 driver is not dependent on the SCSI subsystem, and hence avoids all the +complexity and unnecessary code that would be associated with an implementation +as a SCSI driver. The DAC960 driver is designed for as high a performance as +possible with no compromises or extra code for compatibility with lower +performance devices. The DAC960 driver includes extensive error logging and +online configuration management capabilities. Except for initial configuration +of the controller and adding new disk drives, most everything can be handled +from Linux while the system is operational. + +The DAC960 driver is architected to support up to 8 controllers per system. +Each DAC960 controller can support up to 15 disk drives per channel, for a +maximum of 45 drives on a three channel controller. The drives installed on a +controller are divided into one or more "Drive Groups", and then each Drive +Group is subdivided further into 1 to 32 "Logical Drives". Each Logical Drive +has a specific RAID Level and caching policy associated with it, and it appears +to Linux as a single block device. Logical Drives are further subdivided into +up to 7 partitions through the normal Linux and PC disk partitioning schemes. +Logical Drives are also known as "System Drives", and Drive Groups are also +called "Packs". Both terms are in use in the Mylex documentation; I have +chosen to standardize on the more generic "Logical Drive" and "Drive Group". + +DAC960 RAID disk devices are named in the style of the Device File System +(DEVFS). The device corresponding to Logical Drive D on Controller C is +referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1 +through /dev/rd/cCdDp7. For example, partition 3 of Logical Drive 5 on +Controller 2 is referred to as /dev/rd/c2d5p3. Note that unlike with SCSI +disks the device names will not change in the event of a disk drive failure. +The DAC960 driver is assigned major numbers 48 - 55 with one major number per +controller. The 8 bits of minor number are divided into 5 bits for the Logical +Drive and 3 bits for the partition. + + + SUPPORTED DAC960/DAC1100 PCI RAID CONTROLLERS + +The following list comprises the supported DAC960 and DAC1100 PCI RAID +Controllers as of the date of this document. It is recommended that anyone +purchasing a Mylex PCI RAID Controller not in the following table contact the +author beforehand to verify that it is or will be supported. + +eXtremeRAID 1100 (DAC1164P) + 3 Wide Ultra-2/LVD SCSI channels + 233MHz StrongARM SA 110 Processor + 64 Bit PCI (backward compatible with 32 Bit PCI slots) + 16MB/32MB/64MB Parity SDRAM Memory with Battery Backup + +AcceleRAID 250 (DAC960PTL1) + Uses onboard Symbios SCSI chips on certain motherboards + Also includes one onboard Wide Ultra-2/LVD SCSI Channel + 66MHz Intel i960RD RISC Processor + 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory + +AcceleRAID 200 (DAC960PTL0) + Uses onboard Symbios SCSI chips on certain motherboards + Includes no onboard SCSI Channels + 66MHz Intel i960RD RISC Processor + 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory + +AcceleRAID 150 (DAC960PRL) + Uses onboard Symbios SCSI chips on certain motherboards + Also includes one onboard Wide Ultra-2/LVD SCSI Channel + 33MHz Intel i960RP RISC Processor + 4MB Parity EDO Memory + +DAC960PJ 1/2/3 Wide Ultra SCSI-3 Channels + 66MHz Intel i960RD RISC Processor + 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory + +DAC960PG 1/2/3 Wide Ultra SCSI-3 Channels + 33MHz Intel i960RP RISC Processor + 4MB/8MB ECC EDO Memory + +DAC960PU 1/2/3 Wide Ultra SCSI-3 Channels + Intel i960CF RISC Processor + 4MB/8MB EDRAM or 2MB/4MB/8MB/16MB/32MB DRAM Memory + +DAC960PD 1/2/3 Wide Fast SCSI-2 Channels + Intel i960CF RISC Processor + 4MB/8MB EDRAM or 2MB/4MB/8MB/16MB/32MB DRAM Memory + +DAC960PL 1/2/3 Wide Fast SCSI-2 Channels + Intel i960 RISC Processor + 2MB/4MB/8MB/16MB/32MB DRAM Memory + +For the eXtremeRAID 1100, firmware version 5.06-0-52 or above is required. + +For the AcceleRAID 250, 200, and 150, firmware version 4.06-0-57 or above is +required. + +For the DAC960PJ and DAC960PG, firmware version 4.06-0-00 or above is required. + +For the DAC960PU, DAC960PD, and DAC960PL, firmware version 3.51-0-04 or above +is required. + +Note that earlier revisions of the DAC960PU, DAC960PD, and DAC960PL controllers +were delivered with version 2.xx firmware. Version 2.xx firmware is not +supported by this driver and no support is envisioned. Contact Mylex RAID +Technical Support to inquire about upgrading controllers with version 2.xx +firmware to version 3.51-0-04. Upgrading to version 3.xx firmware requires +installation of higher capacity Flash ROM chips, and not all DAC960PD and +DAC960PL controllers can be upgraded. + +Please note that not all SCSI disk drives are suitable for use with DAC960 +controllers, and only particular firmware versions of any given model may +actually function correctly. Similarly, not all motherboards have a BIOS that +properly initializes the AcceleRAID 250, AcceleRAID 200, AcceleRAID 150, +DAC960PJ, and DAC960PG because the Intel i960RD/RP is a multi-function device. +If in doubt, contact Mylex RAID Technical Support (support@mylex.com) to verify +compatibility. Mylex makes available a hard disk compatibility list by FTP at +ftp://ftp.mylex.com/pub/dac960/diskcomp.html. + + + DRIVER INSTALLATION + +This distribution was prepared for Linux kernel version 2.2.11 or 2.0.37. + +To install the DAC960 RAID driver, you may use the following commands, +replacing "/usr/src" with wherever you keep your Linux kernel source tree: + + cd /usr/src + tar -xvzf DAC960-2.2.4.tar.gz (or DAC960-2.0.4.tar.gz) + mv README.DAC960 linux/Documentation + mv DAC960.[ch] linux/drivers/block + patch -p0 < DAC960.patch + cd linux + make config + make depend + make bzImage (or zImage) + +Then install "arch/i386/boot/bzImage" or "arch/i386/boot/zImage" as your +standard kernel, run lilo if appropriate, and reboot. + +To create the necessary devices in /dev, the "make_rd" script included in +"DAC960-Utilities.tar.gz" from http://www.dandelion.com/Linux/ may be used. +LILO 21 and FDISK v2.9 include DAC960 support; also included in this archive +are patches to LILO 20 and FDISK v2.8 that add DAC960 support, along with +statically linked executables of LILO and FDISK. This modified version of LILO +will allow booting from a DAC960 controller and/or mounting the root file +system from a DAC960. + +Red Hat Linux 6.0 and SuSE Linux 6.1 include support for Mylex PCI RAID +controllers. Installing directly onto a DAC960 may be problematic from other +Linux distributions until their installation utilities are updated. + + + INSTALLATION NOTES + +Before installing Linux or adding DAC960 logical drives to an existing Linux +system, the controller must first be configured to provide one or more logical +drives using the BIOS Configuration Utility or DACCF. Please note that since +there are only at most 6 usable partitions on each logical drive, systems +requiring more partitions should subdivide a drive group into multiple logical +drives, each of which can have up to 6 partitions. Also, note that with large +disk arrays it is advisable to enable the 8GB BIOS Geometry (255/63) rather +than accepting the default 2GB BIOS Geometry (128/32); failing to so do will +cause the logical drive geometry to have more than 65535 cylinders which will +make it impossible for FDISK to be used properly. The 8GB BIOS Geometry can be +enabled by configuring the DAC960 BIOS, which is accessible via Alt-M during +the BIOS initialization sequence. + +For maximum performance and the most efficient E2FSCK performance, it is +recommended that EXT2 file systems be built with a 4KB block size and 16 block +stride to match the DAC960 controller's 64KB default stripe size. The command +"mke2fs -b 4096 -R stride=16 " is appropriate. Unless there will be a +large number of small files on the file systems, it is also beneficial to add +the "-i 16384" option to increase the bytes per inode parameter thereby +reducing the file system metadata. Finally, on systems that will only be run +with Linux 2.2 or later kernels it is beneficial to enable sparse superblocks +with the "-s 1" option. + + + DAC960 ANNOUNCEMENTS MAILING LIST + +The DAC960 Announcements Mailing List provides a forum for informing Linux +users of new driver releases and other announcements regarding Linux support +for DAC960 PCI RAID Controllers. To join the mailing list, send a message to +"dac960-announce-request@dandelion.com" with the line "subscribe" in the +message body. + + + CONTROLLER CONFIGURATION AND STATUS MONITORING + +The DAC960 RAID controllers running firmware 4.06 or above include a Background +Initialization facility so that system downtime is minimized both for initial +installation and subsequent configuration of additional storage. The BIOS +Configuration Utility (accessible via Alt-R during the BIOS initialization +sequence) is used to quickly configure the controller, and then the logical +drives that have been created are available for immediate use even while they +are still being initialized by the controller. The primary need for online +configuration and status monitoring is then to avoid system downtime when disk +drives fail and must be replaced. Mylex's online monitoring and configuration +utilities are being ported to Linux and will become available at some point in +the future. Note that with a SAF-TE (SCSI Accessed Fault-Tolerant Enclosure) +enclosure, the controller is able to rebuild failed drives automatically as +soon as a drive replacement is made available. + +The primary interfaces for controller configuration and status monitoring are +special files created in the /proc/rd/... hierarchy along with the normal +system console logging mechanism. Whenever the system is operating, the DAC960 +driver queries each controller for status information every 10 seconds, and +checks for additional conditions every 60 seconds. The initial status of each +controller is always available for controller N in /proc/rd/cN/initial_status, +and the current status as of the last status monitoring query is available in +/proc/rd/cN/current_status. In addition, status changes are also logged by the +driver to the system console and will appear in the log files maintained by +syslog. The progress of asynchronous rebuild or consistency check operations +is also available in /proc/rd/cN/current_status, and progress messages are +logged to the system console at most every 60 seconds. + +Starting with the 2.2.3/2.0.3 versions of the driver, the status information +available in /proc/rd/cN/initial_status and /proc/rd/cN/current_status has been +augmented to include the vendor, model, revision, and serial number (if +available) for each physical device found connected to the controller: + +***** DAC960 RAID Driver Version 2.2.3 of 19 August 1999 ***** +Copyright 1998-1999 by Leonard N. Zubkoff +Configuring Mylex DAC960PRL PCI RAID Controller + Firmware Version: 4.07-0-07, Channels: 1, Memory Size: 16MB + PCI Bus: 1, Device: 4, Function: 1, I/O Address: Unassigned + PCI Address: 0xFE300000 mapped at 0xA0800000, IRQ Channel: 21 + Controller Queue Depth: 128, Maximum Blocks per Command: 128 + Driver Queue Depth: 127, Maximum Scatter/Gather Segments: 33 + Stripe Size: 64KB, Segment Size: 8KB, BIOS Geometry: 255/63 + SAF-TE Enclosure Management Enabled + Physical Devices: + 0:0 Vendor: IBM Model: DRVS09D Revision: 0270 + Serial Number: 68016775HA + Disk Status: Online, 17928192 blocks + 0:1 Vendor: IBM Model: DRVS09D Revision: 0270 + Serial Number: 68004E53HA + Disk Status: Online, 17928192 blocks + 0:2 Vendor: IBM Model: DRVS09D Revision: 0270 + Serial Number: 13013935HA + Disk Status: Online, 17928192 blocks + 0:3 Vendor: IBM Model: DRVS09D Revision: 0270 + Serial Number: 13016897HA + Disk Status: Online, 17928192 blocks + 0:4 Vendor: IBM Model: DRVS09D Revision: 0270 + Serial Number: 68019905HA + Disk Status: Online, 17928192 blocks + 0:5 Vendor: IBM Model: DRVS09D Revision: 0270 + Serial Number: 68012753HA + Disk Status: Online, 17928192 blocks + 0:6 Vendor: ESG-SHV Model: SCA HSBP M6 Revision: 0.61 + Logical Drives: + /dev/rd/c0d0: RAID-5, Online, 89640960 blocks, Write Thru + No Rebuild or Consistency Check in Progress + +To simplify the monitoring process for custom software, the special file +/proc/rd/status returns "OK" when all DAC960 controllers in the system are +operating normally and no failures have occurred, or "ALERT" if any logical +drives are offline or critical or any non-standby physical drives are dead. + +Configuration commands for controller N are available via the special file +/proc/rd/cN/user_command. A human readable command can be written to this +special file to initiate a configuration operation, and the results of the +operation can then be read back from the special file in addition to being +logged to the system console. The shell command sequence + + echo "" > /proc/rd/c0/user_command + cat /proc/rd/c0/user_command + +is typically used to execute configuration commands. The configuration +commands are: + + flush-cache + + The "flush-cache" command flushes the controller's cache. The system + automatically flushes the cache at shutdown or if the driver module is + unloaded, so this command is only needed to be certain a write back cache + is flushed to disk before the system is powered off by a command to a UPS. + Note that the flush-cache command also stops an asynchronous rebuild or + consistency check, so it should not be used except when the system is being + halted. + + kill : + + The "kill" command marks the physical drive : as DEAD. + This command is provided primarily for testing, and should not be used + during normal system operation. + + make-online : + + The "make-online" command changes the physical drive : + from status DEAD to status ONLINE. In cases where multiple physical drives + have been killed simultaneously, this command may be used to bring them + back online, after which a consistency check is advisable. + + Warning: make-online should only be used on a dead physical drive that is + an active part of a drive group, never on a standby drive. + + make-standby : + + The "make-standby" command changes physical drive : + from status DEAD to status STANDBY. It should only be used in cases where + a dead drive was replaced after an automatic rebuild was performed onto a + standby drive. It cannot be used to add a standby drive to the controller + configuration if one was not created initially; the BIOS Configuration + Utility must be used for that currently. + + rebuild : + + The "rebuild" command initiates an asynchronous rebuild onto physical drive + :. It should only be used when a dead drive has been + replaced. + + check-consistency + + The "check-consistency" command initiates an asynchronous consistency check + of with automatic restoration. It can be used + whenever it is desired to verify the consistency of the redundancy + information. + + cancel-rebuild + cancel-consistency-check + + The "cancel-rebuild" and "cancel-consistency-check" commands cancel any + rebuild or consistency check operations previously initiated. + + + EXAMPLE I - DRIVE FAILURE WITHOUT A STANDBY DRIVE + +The following annotated logs demonstrate the controller configuration and and +online status monitoring capabilities of the Linux DAC960 Driver. The test +configuration comprises 6 1GB Quantum Atlas I disk drives on two channels of a +DAC960PJ controller. The physical drives are configured into a single drive +group without a standby drive, and the drive group has been configured into two +logical drives, one RAID-5 and one RAID-6. Note that these logs are from an +earlier version of the driver and the messages have changed somewhat with newer +releases, but the functionality remains similar. First, here is the current +status of the RAID configuration: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status +***** DAC960 RAID Driver Version 2.0.0 of 23 March 1999 ***** +Copyright 1998-1999 by Leonard N. Zubkoff +Configuring Mylex DAC960PJ PCI RAID Controller + Firmware Version: 4.06-0-08, Channels: 3, Memory Size: 8MB + PCI Bus: 0, Device: 19, Function: 1, I/O Address: Unassigned + PCI Address: 0xFD4FC000 mapped at 0x8807000, IRQ Channel: 9 + Controller Queue Depth: 128, Maximum Blocks per Command: 128 + Driver Queue Depth: 127, Maximum Scatter/Gather Segments: 33 + Stripe Size: 64KB, Segment Size: 8KB, BIOS Geometry: 255/63 + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Online, 2201600 blocks + 1:2 - Disk: Online, 2201600 blocks + 1:3 - Disk: Online, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Online, 5498880 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Online, 3305472 blocks, Write Thru + No Rebuild or Consistency Check in Progress + +gwynedd:/u/lnz# cat /proc/rd/status +OK + +The above messages indicate that everything is healthy, and /proc/rd/status +returns "OK" indicating that there are no problems with any DAC960 controller +in the system. For demonstration purposes, while I/O is active Physical Drive +1:1 is now disconnected, simulating a drive failure. The failure is noted by +the driver within 10 seconds of the controller's having detected it, and the +driver logs the following console status messages indicating that Logical +Drives 0 and 1 are now CRITICAL as a result of Physical Drive 1:1 being DEAD: + +DAC960#0: Physical Drive 1:2 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02 +DAC960#0: Physical Drive 1:3 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02 +DAC960#0: Physical Drive 1:1 killed because of timeout on SCSI command +DAC960#0: Physical Drive 1:1 is now DEAD +DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now CRITICAL +DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now CRITICAL + +The Sense Keys logged here are just Check Condition / Unit Attention conditions +arising from a SCSI bus reset that is forced by the controller during its error +recovery procedures. Concurrently with the above, the driver status available +from /proc/rd also reflects the drive failure. The status message in +/proc/rd/status has changed from "OK" to "ALERT": + +gwynedd:/u/lnz# cat /proc/rd/status +ALERT + +and /proc/rd/c0/current_status has been updated: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status + ... + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Dead, 2201600 blocks + 1:2 - Disk: Online, 2201600 blocks + 1:3 - Disk: Online, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Critical, 5498880 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Critical, 3305472 blocks, Write Thru + No Rebuild or Consistency Check in Progress + +Since there are no standby drives configured, the system can continue to access +the logical drives in a performance degraded mode until the failed drive is +replaced and a rebuild operation completed to restore the redundancy of the +logical drives. Once Physical Drive 1:1 is replaced with a properly +functioning drive, or if the physical drive was killed without having failed +(e.g., due to electrical problems on the SCSI bus), the user can instruct the +controller to initiate a rebuild operation onto the newly replaced drive: + +gwynedd:/u/lnz# echo "rebuild 1:1" > /proc/rd/c0/user_command +gwynedd:/u/lnz# cat /proc/rd/c0/user_command +Rebuild of Physical Drive 1:1 Initiated + +The echo command instructs the controller to initiate an asynchronous rebuild +operation onto Physical Drive 1:1, and the status message that results from the +operation is then available for reading from /proc/rd/c0/user_command, as well +as being logged to the console by the driver. + +Within 10 seconds of this command the driver logs the initiation of the +asynchronous rebuild operation: + +DAC960#0: Rebuild of Physical Drive 1:1 Initiated +DAC960#0: Physical Drive 1:1 Error Log: Sense Key = 6, ASC = 29, ASCQ = 01 +DAC960#0: Physical Drive 1:1 is now WRITE-ONLY +DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 1% completed + +and /proc/rd/c0/current_status is updated: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status + ... + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Write-Only, 2201600 blocks + 1:2 - Disk: Online, 2201600 blocks + 1:3 - Disk: Online, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Critical, 5498880 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Critical, 3305472 blocks, Write Thru + Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 6% completed + +As the rebuild progresses, the current status in /proc/rd/c0/current_status is +updated every 10 seconds: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status + ... + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Write-Only, 2201600 blocks + 1:2 - Disk: Online, 2201600 blocks + 1:3 - Disk: Online, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Critical, 5498880 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Critical, 3305472 blocks, Write Thru + Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 15% completed + +and every minute a progress message is logged to the console by the driver: + +DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 32% completed +DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 63% completed +DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 94% completed +DAC960#0: Rebuild in Progress: Logical Drive 1 (/dev/rd/c0d1) 94% completed + +Finally, the rebuild completes successfully. The driver logs the status of the +logical and physical drives and the rebuild completion: + +DAC960#0: Rebuild Completed Successfully +DAC960#0: Physical Drive 1:1 is now ONLINE +DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now ONLINE +DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now ONLINE + +/proc/rd/c0/current_status is updated: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status + ... + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Online, 2201600 blocks + 1:2 - Disk: Online, 2201600 blocks + 1:3 - Disk: Online, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Online, 5498880 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Online, 3305472 blocks, Write Thru + Rebuild Completed Successfully + +and /proc/rd/status indicates that everything is healthy once again: + +gwynedd:/u/lnz# cat /proc/rd/status +OK + + + EXAMPLE II - DRIVE FAILURE WITH A STANDBY DRIVE + +The following annotated logs demonstrate the controller configuration and and +online status monitoring capabilities of the Linux DAC960 Driver. The test +configuration comprises 6 1GB Quantum Atlas I disk drives on two channels of a +DAC960PJ controller. The physical drives are configured into a single drive +group with a standby drive, and the drive group has been configured into two +logical drives, one RAID-5 and one RAID-6. Note that these logs are from an +earlier version of the driver and the messages have changed somewhat with newer +releases, but the functionality remains similar. First, here is the current +status of the RAID configuration: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status +***** DAC960 RAID Driver Version 2.0.0 of 23 March 1999 ***** +Copyright 1998-1999 by Leonard N. Zubkoff +Configuring Mylex DAC960PJ PCI RAID Controller + Firmware Version: 4.06-0-08, Channels: 3, Memory Size: 8MB + PCI Bus: 0, Device: 19, Function: 1, I/O Address: Unassigned + PCI Address: 0xFD4FC000 mapped at 0x8807000, IRQ Channel: 9 + Controller Queue Depth: 128, Maximum Blocks per Command: 128 + Driver Queue Depth: 127, Maximum Scatter/Gather Segments: 33 + Stripe Size: 64KB, Segment Size: 8KB, BIOS Geometry: 255/63 + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Online, 2201600 blocks + 1:2 - Disk: Online, 2201600 blocks + 1:3 - Disk: Standby, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Online, 4399104 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Online, 2754560 blocks, Write Thru + No Rebuild or Consistency Check in Progress + +gwynedd:/u/lnz# cat /proc/rd/status +OK + +The above messages indicate that everything is healthy, and /proc/rd/status +returns "OK" indicating that there are no problems with any DAC960 controller +in the system. For demonstration purposes, while I/O is active Physical Drive +1:2 is now disconnected, simulating a drive failure. The failure is noted by +the driver within 10 seconds of the controller's having detected it, and the +driver logs the following console status messages: + +DAC960#0: Physical Drive 1:1 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02 +DAC960#0: Physical Drive 1:3 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02 +DAC960#0: Physical Drive 1:2 killed because of timeout on SCSI command +DAC960#0: Physical Drive 1:2 is now DEAD +DAC960#0: Physical Drive 1:2 killed because it was removed +DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now CRITICAL +DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now CRITICAL + +Since a standby drive is configured, the controller automatically begins +rebuilding onto the standby drive: + +DAC960#0: Physical Drive 1:3 is now WRITE-ONLY +DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 4% completed + +Concurrently with the above, the driver status available from /proc/rd also +reflects the drive failure and automatic rebuild. The status message in +/proc/rd/status has changed from "OK" to "ALERT": + +gwynedd:/u/lnz# cat /proc/rd/status +ALERT + +and /proc/rd/c0/current_status has been updated: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status + ... + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Online, 2201600 blocks + 1:2 - Disk: Dead, 2201600 blocks + 1:3 - Disk: Write-Only, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Critical, 4399104 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Critical, 2754560 blocks, Write Thru + Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 4% completed + +As the rebuild progresses, the current status in /proc/rd/c0/current_status is +updated every 10 seconds: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status + ... + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Online, 2201600 blocks + 1:2 - Disk: Dead, 2201600 blocks + 1:3 - Disk: Write-Only, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Critical, 4399104 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Critical, 2754560 blocks, Write Thru + Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 40% completed + +and every minute a progress message is logged on the console by the driver: + +DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 40% completed +DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 76% completed +DAC960#0: Rebuild in Progress: Logical Drive 1 (/dev/rd/c0d1) 66% completed +DAC960#0: Rebuild in Progress: Logical Drive 1 (/dev/rd/c0d1) 84% completed + +Finally, the rebuild completes successfully. The driver logs the status of the +logical and physical drives and the rebuild completion: + +DAC960#0: Rebuild Completed Successfully +DAC960#0: Physical Drive 1:3 is now ONLINE +DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now ONLINE +DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now ONLINE + +/proc/rd/c0/current_status is updated: + +***** DAC960 RAID Driver Version 2.0.0 of 23 March 1999 ***** +Copyright 1998-1999 by Leonard N. Zubkoff +Configuring Mylex DAC960PJ PCI RAID Controller + Firmware Version: 4.06-0-08, Channels: 3, Memory Size: 8MB + PCI Bus: 0, Device: 19, Function: 1, I/O Address: Unassigned + PCI Address: 0xFD4FC000 mapped at 0x8807000, IRQ Channel: 9 + Controller Queue Depth: 128, Maximum Blocks per Command: 128 + Driver Queue Depth: 127, Maximum Scatter/Gather Segments: 33 + Stripe Size: 64KB, Segment Size: 8KB, BIOS Geometry: 255/63 + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Online, 2201600 blocks + 1:2 - Disk: Dead, 2201600 blocks + 1:3 - Disk: Online, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Online, 4399104 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Online, 2754560 blocks, Write Thru + Rebuild Completed Successfully + +and /proc/rd/status indicates that everything is healthy once again: + +gwynedd:/u/lnz# cat /proc/rd/status +OK + +Note that the absence of a viable standby drive does not create an "ALERT" +status. Once dead Physical Drive 1:2 has been replaced, the controller must be +told that this has occurred and that the newly replaced drive should become the +new standby drive: + +gwynedd:/u/lnz# echo "make-standby 1:2" > /proc/rd/c0/user_command +gwynedd:/u/lnz# cat /proc/rd/c0/user_command +Make Standby of Physical Drive 1:2 Succeeded + +The echo command instructs the controller to make Physical Drive 1:2 into a +standby drive, and the status message that results from the operation is then +available for reading from /proc/rd/c0/user_command, as well as being logged to +the console by the driver. Within 60 seconds of this command the driver logs: + +DAC960#0: Physical Drive 1:2 Error Log: Sense Key = 6, ASC = 29, ASCQ = 01 +DAC960#0: Physical Drive 1:2 is now STANDBY +DAC960#0: Make Standby of Physical Drive 1:2 Succeeded + +and /proc/rd/c0/current_status is updated: + +gwynedd:/u/lnz# cat /proc/rd/c0/current_status + ... + Physical Devices: + 0:1 - Disk: Online, 2201600 blocks + 0:2 - Disk: Online, 2201600 blocks + 0:3 - Disk: Online, 2201600 blocks + 1:1 - Disk: Online, 2201600 blocks + 1:2 - Disk: Standby, 2201600 blocks + 1:3 - Disk: Online, 2201600 blocks + Logical Drives: + /dev/rd/c0d0: RAID-5, Online, 4399104 blocks, Write Thru + /dev/rd/c0d1: RAID-6, Online, 2754560 blocks, Write Thru + Rebuild Completed Successfully diff -u --recursive --new-file v2.3.15/linux/Documentation/i386/zero-page.txt linux/Documentation/i386/zero-page.txt --- v2.3.15/linux/Documentation/i386/zero-page.txt Mon Oct 5 12:59:25 1998 +++ linux/Documentation/i386/zero-page.txt Mon Aug 30 10:47:02 1999 @@ -30,6 +30,7 @@ 0xb0 - 0x1df Free. Add more parameters here if you really need them. 0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb +0x1e8 char number of entries in E820MAP (below) 0x1f1 char size of setup.S, number of sectors 0x1f2 unsigned short MOUNT_ROOT_RDONLY (if !=0) 0x1f4 unsigned short size of compressed kernel-part in the @@ -64,7 +65,7 @@ 0x21c unsigned long INITRD_SIZE, size in bytes of ramdisk image 0x220 4 bytes (setup.S) 0x224 unsigned short setup.S heap end pointer -0x226 - 0x7ff setup.S code. +0x2d0 - 0x600 E820MAP 0x800 string, 2K max COMMAND_LINE, the kernel commandline as copied using CL_OFFSET. diff -u --recursive --new-file v2.3.15/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.3.15/linux/Documentation/ioctl-number.txt Thu Aug 26 13:05:34 1999 +++ linux/Documentation/ioctl-number.txt Fri Aug 27 11:46:35 1999 @@ -79,6 +79,7 @@ 'S' 82-FF scsi/scsi.h 'T' all linux/soundcard.h conflict! 'T' all asm-i386/ioctls.h conflict! +'U' all linux/drivers/usb/usb.h 'V' all linux/vt.h 'W' 00-1F linux/router.h conflict [Please reallocate] 'W' 00-1F linux/watchdog.h diff -u --recursive --new-file v2.3.15/linux/Documentation/networking/soundmodem.txt linux/Documentation/networking/soundmodem.txt --- v2.3.15/linux/Documentation/networking/soundmodem.txt Wed May 20 18:54:34 1998 +++ linux/Documentation/networking/soundmodem.txt Mon Aug 30 10:18:40 1999 @@ -42,8 +42,8 @@ /etc/conf.modules). Examples: - insmod soundmodem hw=0 mode=0 iobase=0x220 irq=5 dma=1 - sethdlc -i sm0 -p hw sbc type afsk1200 io 0x220 irq 5 dma 1 + insmod soundmodem mode="sbc:afsk1200" iobase=0x220 irq=5 dma=1 + sethdlc -i sm0 -p mode "sbc:afsk1200" io 0x220 irq 5 dma 1 Both lines configure the first port to drive a soundblaster card in 1200 baud AFSK mode. diff -u --recursive --new-file v2.3.15/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt --- v2.3.15/linux/Documentation/watchdog.txt Wed Jun 24 14:30:07 1998 +++ linux/Documentation/watchdog.txt Mon Aug 30 10:18:40 1999 @@ -77,17 +77,17 @@ Contact Information People keep asking about the WDT watchdog timer hardware: The phone contacts -for Industrial Computer Source are: +for ICS Advent are: US: 619 677 0877 (sales) 0895 (fax) UK: 01243 533900 France (1) 69.18.74.30 -Industrial Computer Source +ICS Advent 9950 Barnes Canyon Road San Diego, CA -http://www.industry.net/indcompsrc +http://www.icsadvent.com and please mention Linux when enquiring. diff -u --recursive --new-file v2.3.15/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.15/linux/MAINTAINERS Thu Aug 26 13:05:34 1999 +++ linux/MAINTAINERS Tue Aug 31 16:03:17 1999 @@ -401,16 +401,24 @@ W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained +IBM ServeRAID RAID DRIVER +P: Keith Mitchell +M: ipslinux@us.ibm.com +W: http://www.developer.ibm.com/welcome/netfinity/serveraid_beta.html +S: Supported + IDE DRIVER [GENERAL] P: Andre Hedrick -M: hedrick@astro.dyer.vanderbilt.edu +M: andre@suse.com L: linux-kernel@vger.rutgers.edu -S: Maintained +W: http://linux.kernel.org/pub/linux/kernel/people/hedrick/ +S: Supported IDE/ATAPI CDROM DRIVER P: Jens Axboe M: axboe@image.dk L: linux-kernel@vger.rutgers.edu +W: http://www.kernel.dk S: Maintained IDE/ATAPI TAPE/FLOPPY DRIVERS @@ -716,6 +724,13 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +SCSI CDROM DRIVER +P: Jens Axboe +M: axboe@image.dk +L: linux-kernel@vger.rutgers.edu +W: http://www.kernel.dk +S: Maintained + SCSI SG DRIVER P: Doug Gilbert M: dgilbert@interlog.com @@ -843,6 +858,7 @@ P: Jens Axboe M: axboe@image.dk L: linux-kernel@vger.rutgers.edu +W: http://www.kernel.dk S: Maintained USB HUB AND UHCI DRIVERS diff -u --recursive --new-file v2.3.15/linux/Makefile linux/Makefile --- v2.3.15/linux/Makefile Thu Aug 26 13:05:34 1999 +++ linux/Makefile Thu Aug 26 13:05:56 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 15 +SUBLEVEL = 16 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.3.15/linux/Rules.make linux/Rules.make --- v2.3.15/linux/Rules.make Mon Aug 2 17:09:47 1999 +++ linux/Rules.make Thu Aug 26 09:41:36 1999 @@ -73,11 +73,11 @@ ALL_O = $(OX_OBJS) $(O_OBJS) $(O_TARGET): $(ALL_O) rm -f $@ -ifneq "$(strip $(ALL_O))" "" - $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(ALL_O) -else - $(AR) rcs $@ -endif + ifneq "$(strip $(ALL_O))" "" + $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(ALL_O), $^) + else + $(AR) rcs $@ $(filter $(ALL_O), $^) + endif @ ( \ echo 'ifeq ($(strip $(subst $(comma),:,$(EXTRA_LDFLAGS) $(ALL_O))),$$(strip $$(subst $$(comma),:,$$(EXTRA_LDFLAGS) $$(ALL_O))))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v2.3.15/linux/arch/alpha/Makefile Sun Jan 24 21:29:52 1999 +++ linux/arch/alpha/Makefile Tue Aug 31 10:50:39 1999 @@ -59,10 +59,10 @@ endif # For TSUNAMI, we must have the assembler not emulate our instructions. -# The same is true for POLARIS. +# The same is true for POLARIS, and now PYXIS. # BWX is most important, but we don't really want any emulation ever. ifeq ($(old_gas),y) - ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI)$(CONFIG_ALPHA_POLARIS),) + ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI)$(CONFIG_ALPHA_POLARIS)$(CONFIG_ALPHA_PYXIS),) # How do we do #error in make? CFLAGS := --error-please-upgrade-your-assembler endif @@ -71,7 +71,7 @@ CFLAGS := $(CFLAGS) -Wa,-mev6 endif ifeq ($(CONFIG_ALPHA_PYXIS),y) - CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWIO_ENABLED + CFLAGS := $(CFLAGS) -Wa,-m21164a endif ifeq ($(CONFIG_ALPHA_POLARIS),y) CFLAGS := $(CFLAGS) -Wa,-m21164pc diff -u --recursive --new-file v2.3.15/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.3.15/linux/arch/alpha/config.in Thu Aug 26 13:05:34 1999 +++ linux/arch/alpha/config.in Tue Aug 31 10:50:39 1999 @@ -150,11 +150,6 @@ -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" ] then bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_ALPHA_SRM" = "y" ]; then - bool ' Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP - fi - fi fi if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.3.15/linux/arch/alpha/defconfig Thu Feb 25 10:46:46 1999 +++ linux/arch/alpha/defconfig Tue Aug 31 10:50:39 1999 @@ -17,7 +17,6 @@ # # General setup # -CONFIG_NATIVE=y CONFIG_ALPHA_GENERIC=y # CONFIG_ALPHA_ALCOR is not set # CONFIG_ALPHA_XL is not set @@ -39,14 +38,12 @@ # CONFIG_ALPHA_P2K is not set # CONFIG_ALPHA_RAWHIDE is not set # CONFIG_ALPHA_RUFFIAN is not set +# CONFIG_ALPHA_RX164 is not set # CONFIG_ALPHA_SX164 is not set # CONFIG_ALPHA_SABLE is not set # CONFIG_ALPHA_TAKARA is not set -# CONFIG_SMP is not set CONFIG_PCI=y -CONFIG_ALPHA_NEED_ROUNDING_EMULATION=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y +# CONFIG_SMP is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -58,9 +55,10 @@ # CONFIG_PARPORT is not set # -# Plug and Play support +# Plug and Play configuration # # CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices @@ -72,6 +70,7 @@ # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -83,6 +82,7 @@ # CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set # @@ -90,7 +90,7 @@ # # CONFIG_PACKET is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -106,8 +106,6 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # @@ -141,6 +139,7 @@ # SCSI low-level drivers # # CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set @@ -148,23 +147,29 @@ # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_DMA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set CONFIG_SCSI_QLOGIC_ISP=y +# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -175,9 +180,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set CONFIG_DUMMY=m # CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -194,14 +208,26 @@ # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_NE2K_PCI is not set # CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set -# CONFIG_DLCI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # CONFIG_WAN_DRIVERS is not set # CONFIG_LAPBETHER is not set # CONFIG_X25_ASY is not set @@ -217,7 +243,7 @@ # CONFIG_ISDN is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# Old CD-ROM drivers (not SCSI, not IDE) # # CONFIG_CD_NO_IDESCSI is not set @@ -232,20 +258,30 @@ # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_MOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set + +# +# Mice +# # CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set -# CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set # CONFIG_RTC is not set + +# +# Video For Linux +# # CONFIG_VIDEO_DEV is not set -# CONFIG_NVRAM is not set + +# +# Joystick support +# # CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set # # Ftape, the floppy tape device driver @@ -256,31 +292,43 @@ # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS 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_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set CONFIG_NFS_FS=y -# CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set # CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_UFS_FS is not set -CONFIG_DEVPTS_FS=y -# CONFIG_MAC_PARTITION is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_OSF_PARTITION=y +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SGI_DISKLABEL is not set # CONFIG_NLS is not set # diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.3.15/linux/arch/alpha/kernel/Makefile Thu Aug 26 13:05:34 1999 +++ linux/arch/alpha/kernel/Makefile Tue Aug 31 10:50:39 1999 @@ -16,7 +16,7 @@ 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 fpreg.o semaphore.o + ptrace.o time.o fpreg.o semaphore.o pci_syscall.o OX_OBJS := alpha_ksyms.o @@ -28,9 +28,14 @@ sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \ sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \ sys_sx164.o sys_takara.o sys_rx164.o \ - es1888.o smc37c669.o smc37c93x.o + es1888.o smc37c669.o smc37c93x.o ns87312.o \ + pci.o pci_setup.o else +ifdef CONFIG_PCI +O_OBJS += pci.o pci_setup.o +endif + # Core logic support ifdef CONFIG_ALPHA_APECS O_OBJS += core_apecs.o @@ -62,10 +67,10 @@ O_OBJS += sys_alcor.o endif ifneq ($(CONFIG_ALPHA_CABRIOLET)$(CONFIG_ALPHA_EB164)$(CONFIG_ALPHA_EB66P)$(CONFIG_ALPHA_LX164)$(CONFIG_ALPHA_PC164),) -O_OBJS += sys_cabriolet.o +O_OBJS += sys_cabriolet.o ns87312.o endif ifdef CONFIG_ALPHA_DP264 -O_OBJS += sys_dp264.o +O_OBJS += sys_dp264.o es1888.o smc37c669.o endif ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),) O_OBJS += sys_eb64p.o @@ -74,7 +79,7 @@ O_OBJS += sys_jensen.o endif ifdef CONFIG_ALPHA_MIATA -O_OBJS += sys_miata.o +O_OBJS += sys_miata.o es1888.o smc37c669.o endif ifdef CONFIG_ALPHA_MIKASA O_OBJS += sys_mikasa.o @@ -95,22 +100,16 @@ O_OBJS += sys_sable.o endif ifneq ($(CONFIG_ALPHA_BOOK1)$(CONFIG_ALPHA_AVANTI)$(CONFIG_ALPHA_NONAME)$(CONFIG_ALPHA_P2K)$(CONFIG_ALPHA_XL),) -O_OBJS += sys_sio.o +O_OBJS += sys_sio.o ns87312.o endif ifdef CONFIG_ALPHA_SX164 -O_OBJS += sys_sx164.o +O_OBJS += sys_sx164.o smc37c669.o endif ifdef CONFIG_ALPHA_TAKARA -O_OBJS += sys_takara.o +O_OBJS += sys_takara.o ns87312.o endif # Device support -ifneq ($(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),) -O_OBJS += es1888.o -endif -ifneq ($(CONFIG_ALPHA_SX164)$(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),) -O_OBJS += smc37c669.o -endif ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),) O_OBJS += smc37c93x.o endif diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.3.15/linux/arch/alpha/kernel/alpha_ksyms.c Wed Aug 4 15:48:00 1999 +++ linux/arch/alpha/kernel/alpha_ksyms.c Tue Aug 31 10:50:39 1999 @@ -36,6 +36,7 @@ extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); +extern void ___delay(void); /* these are C runtime functions with special calling conventions: */ extern void __divl (void); @@ -146,6 +147,11 @@ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__up_wakeup); + +/* + * This is called specially from __delay. + */ +EXPORT_SYMBOL_NOVERS(___delay); /* * SMP-specific symbols. diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.3.15/linux/arch/alpha/kernel/bios32.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/bios32.c Wed Dec 31 16:00:00 1969 @@ -1,1374 +0,0 @@ -/* - * bios32.c - PCI BIOS functions for Alpha systems not using BIOS - * emulation code. - * - * Written by Dave Rusling (david.rusling@reo.mts.dec.com) - * - * Adapted to 64-bit kernel and then rewritten by David Mosberger - * (davidm@cs.arizona.edu) - * - * For more information, please consult - * - * PCI BIOS Specification Revision - * PCI Local Bus Specification - * PCI System Design Guide - * - * PCI Special Interest Group - * M/S HF3-15A - * 5200 N.E. Elam Young Parkway - * Hillsboro, Oregon 97124-6497 - * +1 (503) 696-2000 - * +1 (800) 433-5177 - * - * Manuals are $25 each or $50 for all three, plus $7 shipping - * within the United States, $35 abroad. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "proto.h" -#include "bios32.h" - -#define DEBUG_DEVS 0 -#define DEBUG_HOSE 0 - -#if DEBUG_DEVS -# define DBG_DEVS(args) printk args -#else -# define DBG_DEVS(args) -#endif - -#if DEBUG_HOSE -# define DBG_HOSE(args) printk args -#else -# define DBG_HOSE(args) -#endif - -#ifndef CONFIG_PCI - -asmlinkage int sys_pciconfig_read() { return -ENOSYS; } -asmlinkage int sys_pciconfig_write() { return -ENOSYS; } -void reset_for_srm(void) { } - -#else /* CONFIG_PCI */ - -#include -#include - -#include -#include -#include -#include - -/* - * PCI public interfaces. - */ - -#define MAJOR_REV 0 -#define MINOR_REV 4 /* minor revision 4, add multi-PCI handling */ - -struct linux_hose_info *bus2hose[256]; -struct linux_hose_info *hose_head, **hose_tail = &hose_head; -int hose_count; -int pci_probe_enabled; - -static void layout_hoses(void); - -int -pcibios_present(void) -{ - return alpha_mv.hose_read_config_byte != NULL; -} - -void __init -pcibios_init(void) -{ - if (!pcibios_present()) - return; - - printk("Alpha PCI BIOS32 revision %d.%02d\n", MAJOR_REV, MINOR_REV); - if (alpha_use_srm_setup) - printk(" NOT modifying existing (SRM) PCI configuration\n"); -} - -char * __init -pcibios_setup(char *str) -{ - return str; -} - -void __init -pcibios_fixup(void) -{ - alpha_mv.pci_fixup(); -} - -void __init -pcibios_fixup_bus(struct pci_bus *bus) -{ -} - -int -pcibios_read_config_byte (u8 bus, u8 dev, u8 where, u8 *value) -{ - int r = PCIBIOS_FUNC_NOT_SUPPORTED; - *value = 0xff; - if (alpha_mv.hose_read_config_byte) { - r = (alpha_mv.hose_read_config_byte - (bus, dev, where, value, bus2hose[bus])); - } - return r; -} - -int -pcibios_read_config_word (u8 bus, u8 dev, u8 where, u16 *value) -{ - int r = PCIBIOS_FUNC_NOT_SUPPORTED; - *value = 0xffff; - if (alpha_mv.hose_read_config_word) { - r = PCIBIOS_BAD_REGISTER_NUMBER; - if (!(where & 1)) - r = (alpha_mv.hose_read_config_word - (bus, dev, where, value, bus2hose[bus])); - } - return r; -} - -int -pcibios_read_config_dword (u8 bus, u8 dev, u8 where, u32 *value) -{ - int r = PCIBIOS_FUNC_NOT_SUPPORTED; - *value = 0xffffffff; - if (alpha_mv.hose_read_config_dword) { - r = PCIBIOS_BAD_REGISTER_NUMBER; - if (!(where & 3)) - r = (alpha_mv.hose_read_config_dword - (bus, dev, where, value, bus2hose[bus])); - } - return r; -} - -int -pcibios_write_config_byte (u8 bus, u8 dev, u8 where, u8 value) -{ - int r = PCIBIOS_FUNC_NOT_SUPPORTED; - if (alpha_mv.hose_write_config_byte) { - r = (alpha_mv.hose_write_config_byte - (bus, dev, where, value, bus2hose[bus])); - } - return r; -} - -int -pcibios_write_config_word (u8 bus, u8 dev, u8 where, u16 value) -{ - int r = PCIBIOS_FUNC_NOT_SUPPORTED; - if (alpha_mv.hose_write_config_word) { - r = PCIBIOS_BAD_REGISTER_NUMBER; - if (!(where & 1)) - r = (alpha_mv.hose_write_config_word - (bus, dev, where, value, bus2hose[bus])); - } - return r; -} - -int -pcibios_write_config_dword (u8 bus, u8 dev, u8 where, u32 value) -{ - int r = PCIBIOS_FUNC_NOT_SUPPORTED; - if (alpha_mv.hose_write_config_dword) { - r = PCIBIOS_BAD_REGISTER_NUMBER; - if (!(where & 3)) - r = (alpha_mv.hose_write_config_dword - (bus, dev, where, value, bus2hose[bus])); - } - return r; -} - -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 (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, buf); - break; - case 2: - err = pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, (unsigned short *)buf); - break; - case 4: - err = pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, (unsigned int *)buf); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -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 (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = get_user(ubyte, buf); - if (err) - break; - err = pcibios_write_config_byte(bus, dfn, off, ubyte); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 2: - err = get_user(ushort, (unsigned short *)buf); - if (err) - break; - err = pcibios_write_config_word(bus, dfn, off, ushort); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 4: - err = get_user(uint, (unsigned int *)buf); - if (err) - break; - err = pcibios_write_config_dword(bus, dfn, off, uint); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - default: - err = -EINVAL; - break; - } - return err; -} - - -/* - * Gory details start here... - */ - -/* - * Align VAL to ALIGN, which must be a power of two. - */ -#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) - - -/* - * The following structure records initial configuration of devices - * so that we can reset them on shutdown and so enable clean reboots - * on SRM. It is more trouble than it iw worth to conditionalize this. - */ - -struct srm_irq_reset { - struct srm_irq_reset *next; - struct pci_dev *dev; - u8 irq; -} *srm_irq_resets; - -struct srm_io_reset { - struct srm_io_reset *next; - struct pci_dev *dev; - u32 io; - u8 reg; -} *srm_io_resets; - -/* Apply the collected reset modifications. */ - -void -reset_for_srm(void) -{ - struct srm_irq_reset *qreset; - struct srm_io_reset *ireset; - - /* Reset any IRQs that we changed. */ - for (qreset = srm_irq_resets; qreset ; qreset = qreset->next) { - pcibios_write_config_byte(qreset->dev->bus->number, - qreset->dev->devfn, - PCI_INTERRUPT_LINE, - qreset->irq); -#if 1 - printk("reset_for_srm: bus %d slot 0x%x " - "SRM IRQ 0x%x changed back from 0x%x\n", - qreset->dev->bus->number, - PCI_SLOT(qreset->dev->devfn), - qreset->irq, qreset->dev->irq); -#endif - } - - /* Reset any IO addresses that we changed. */ - for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { - pcibios_write_config_dword(ireset->dev->bus->number, - ireset->dev->devfn, - ireset->reg, ireset->io); -#if 1 - printk("reset_for_srm: bus %d slot 0x%x " - "SRM MEM/IO restored to 0x%x\n", - ireset->dev->bus->number, - PCI_SLOT(ireset->dev->devfn), - ireset->io); -#endif - } -} - -static void -new_irq_reset(struct pci_dev *dev, u8 irq) -{ - struct srm_irq_reset *n; - n = kmalloc(sizeof(*n), GFP_KERNEL); - - n->next = srm_irq_resets; - n->dev = dev; - n->irq = irq; - srm_irq_resets = n; -} - -static void -new_io_reset(struct pci_dev *dev, u8 reg, u32 io) -{ - struct srm_io_reset *n; - n = kmalloc(sizeof(*n), GFP_KERNEL); - - n->next = srm_io_resets; - n->dev = dev; - n->reg = reg; - n->io = io; - srm_io_resets = n; -} - - -/* - * Disable PCI device DEV so that it does not respond to I/O or memory - * accesses. - */ -static void __init -disable_dev(struct pci_dev *dev) -{ - struct pci_bus *bus; - unsigned short cmd; - - /* - * HACK: the PCI-to-EISA bridge does not seem to identify - * itself as a bridge... :-( - */ - if (dev->vendor == PCI_VENDOR_ID_INTEL && - dev->device == PCI_DEVICE_ID_INTEL_82375) { - dev->class = PCI_CLASS_BRIDGE_EISA; - DBG_DEVS(("disable_dev: ignoring PCEB...\n")); - return; - } - - if (dev->vendor == PCI_VENDOR_ID_INTEL && - dev->device == PCI_DEVICE_ID_INTEL_82378) { - dev->class = PCI_CLASS_BRIDGE_ISA; - DBG_DEVS(("disable_dev: ignoring SIO...\n")); - return; - } - - /* - * We don't have code that will init the CYPRESS bridge correctly - * so we do the next best thing, and depend on the previous - * console code to do the right thing, and ignore it here... :-\ - */ - if (dev->vendor == PCI_VENDOR_ID_CONTAQ && - dev->device == PCI_DEVICE_ID_CONTAQ_82C693) { - DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n")); - return; - } - -#if DEBUG_DEVS && 0 - /* Worse HACK: Don't disable the video card, so I can see where - it is *really* falling over. */ - if (dev->class >> 16 == PCI_BASE_CLASS_DISPLAY) { - DBG_DEVS(("disable_dev: ignoring video card %04x:%04x\n", - dev->vendor, dev->device)); - return; - } -#endif - - DBG_DEVS(("disable_dev: disabling %04x:%04x\n", - dev->vendor, dev->device)); - - bus = dev->bus; - pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); - - /* hack, turn it off first... */ - cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); - pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd); -} - - -/* - * Layout memory and I/O for a device: - */ -#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2)) - -static unsigned int io_base; -static unsigned int mem_base; - -static void __init -layout_dev(struct pci_dev *dev) -{ - struct pci_bus *bus; - unsigned short cmd; - unsigned int base, mask, size, off, idx; - unsigned int orig_base; - unsigned int alignto; - unsigned long handle; - - /* - * HACK: the PCI-to-EISA bridge does not seem to identify - * itself as a bridge... :-( - */ - if (dev->vendor == PCI_VENDOR_ID_INTEL - && dev->device == PCI_DEVICE_ID_INTEL_82375) { - dev->class = PCI_CLASS_BRIDGE_EISA; - DBG_DEVS(("layout_dev: ignoring PCEB...\n")); - return; - } - - if (dev->vendor == PCI_VENDOR_ID_INTEL - && dev->device == PCI_DEVICE_ID_INTEL_82378) { - dev->class = PCI_CLASS_BRIDGE_ISA; - DBG_DEVS(("layout_dev: ignoring SIO...\n")); - return; - } - - if (dev->vendor == PCI_VENDOR_ID_CONTAQ - && dev->device == PCI_DEVICE_ID_CONTAQ_82C693 - && dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) { - DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n")); - return; - } - - bus = dev->bus; - pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); - - for (idx = 0; idx <= 5; idx++) { - off = PCI_BASE_ADDRESS_0 + 4*idx; - /* - * Figure out how much space and of what type this - * device wants. - */ - pcibios_read_config_dword(bus->number, dev->devfn, off, - &orig_base); - pcibios_write_config_dword(bus->number, dev->devfn, off, - 0xffffffff); - pcibios_read_config_dword(bus->number, dev->devfn, off, &base); - if (!base) { - /* This base-address register is unused. */ - dev->resource[idx].start = 0; - dev->resource[idx].end = 0; - dev->resource[idx].flags = 0; - continue; - } - - DBG_DEVS(("layout_dev: slot %d fn %d off 0x%x base 0x%x\n", - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - off, base)); - - /* - * We've read the base address register back after - * writing all ones and so now we must decode it. - */ - if (base & PCI_BASE_ADDRESS_SPACE_IO) { - /* - * I/O space base address register. - */ - cmd |= PCI_COMMAND_IO; - - base &= PCI_BASE_ADDRESS_IO_MASK; - mask = (~base << 1) | 0x1; - size = (mask & base) & 0xffffffff; - - /* We don't want to disturb normal IDE functions, so - we don't touch the first two I/O ports on the - Cypress. */ - if (dev->vendor == PCI_VENDOR_ID_CONTAQ - && dev->device == PCI_DEVICE_ID_CONTAQ_82C693 - && idx < 2) { - continue; - } - - /* - * 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, - off, base | 0x1); - new_io_reset(dev, off, orig_base); - - handle = PCI_HANDLE(bus->number) | base | 1; - dev->resource[idx].start - = handle & PCI_BASE_ADDRESS_IO_MASK; - dev->resource[idx].end - = dev->resource[idx].start + size - 1; - dev->resource[idx].flags - = handle & ~PCI_BASE_ADDRESS_IO_MASK; - - DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%lx (0x%x)\n", - dev->device, handle, size)); - } else { - unsigned int type; - /* - * Memory space base address register. - */ - cmd |= PCI_COMMAND_MEMORY; - type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; - base &= PCI_BASE_ADDRESS_MEM_MASK; - mask = (~base << 1) | 0x1; - size = (mask & base) & 0xffffffff; - switch (type) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - case PCI_BASE_ADDRESS_MEM_TYPE_64: - break; - - case PCI_BASE_ADDRESS_MEM_TYPE_1M: - /* - * Allocating memory below 1MB is *very* - * tricky, as there may be all kinds of - * ISA devices lurking that we don't know - * about. For now, we just cross fingers - * and hope nobody tries to do this on an - * 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", - PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - continue; - } - /* - * The following holds at least for the Low Cost - * Alpha implementation of the PCI interface: - * - * In sparse memory address space, the first - * octant (16MB) of every 128MB segment is - * aliased to the very first 16 MB of the - * address space (i.e., it aliases the ISA - * memory address space). Thus, we try to - * avoid allocating PCI devices in that range. - * Can be allocated in 2nd-7th octant only. - * Devices that need more than 112MB of - * address space must be accessed through - * dense memory space only! - */ - /* align to multiple of size of minimum base */ - alignto = MAX(0x1000, size); - base = ALIGN(mem_base, alignto); - if (size > 7 * 16*MB) { - 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 { - if (((base / (16*MB)) & 0x7) == 0) { - base &= ~(128*MB - 1); - base += 16*MB; - base = ALIGN(base, alignto); - } - if (base/(128*MB) != (base + size)/(128*MB)) { - base &= ~(128*MB - 1); - base += (128 + 16)*MB; - base = ALIGN(base, alignto); - } - } - mem_base = base + size; - - pcibios_write_config_dword(bus->number, dev->devfn, - off, base); - new_io_reset(dev, off, orig_base); - - handle = PCI_HANDLE(bus->number) | base; - dev->resource[idx].start - = handle & PCI_BASE_ADDRESS_MEM_MASK; - dev->resource[idx].end - = dev->resource[idx].start + size - 1; - dev->resource[idx].flags - = handle & ~PCI_BASE_ADDRESS_MEM_MASK; - - /* - * Currently for 64-bit cards, we simply do the usual - * for setup of the first register (low) of the pair, - * and then clear out the second (high) register, as - * we are not yet able to do 64-bit addresses, and - * setting the high register to 0 allows 32-bit SAC - * addresses to be used. - */ - if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) { - unsigned int orig_base2; - pcibios_read_config_dword(bus->number, - dev->devfn, - off+4, &orig_base2); - if (0 != orig_base2) { - pcibios_write_config_dword(bus->number, - dev->devfn, - off+4, 0); - new_io_reset (dev, off+4, orig_base2); - } - /* Bypass hi reg in the loop. */ - dev->resource[++idx].start = 0; - dev->resource[idx].end = 0; - dev->resource[idx].flags = 0; - - printk("bios32 WARNING: " - "handling 64-bit device in " - "slot %d, function %d: \n", - PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - } - - DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n", - dev->device, handle, size)); - } - } - - /* Enable device: */ - if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED || - dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || - dev->class >> 8 == PCI_CLASS_STORAGE_IDE || - dev->class >> 16 == PCI_BASE_CLASS_DISPLAY) { - /* - * All of these (may) have I/O scattered all around - * and may not use i/o-base address registers at all. - * So we just have to always enable I/O to these - * devices. - */ - cmd |= PCI_COMMAND_IO; - } - - pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, - cmd | PCI_COMMAND_MASTER); - - 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)); -} - -static int __init -layout_bus(struct pci_bus *bus) -{ - unsigned int l, tio, bio, tmem, bmem; - struct pci_bus *child; - struct pci_dev *dev; - int found_vga = 0; - - DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); - - if (!bus->devices && !bus->children) - return 0; - - /* - * Align the current bases on appropriate boundaries (4K for - * IO and 1MB for memory). - */ - bio = io_base = ALIGN(io_base, 4*KB); - bmem = mem_base = ALIGN(mem_base, 1*MB); - - /* - * There are times when the PCI devices have already been - * setup (e.g., by MILO or SRM). In these cases there is a - * window during which two devices may have an overlapping - * address range. To avoid this causing trouble, we first - * turn off the I/O and memory address decoders for all PCI - * devices. They'll be re-enabled only once all address - * decoders are programmed consistently. - */ - DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number)); - - for (dev = bus->devices; dev; dev = dev->sibling) { - if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || - (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) { - disable_dev(dev); - } - } - - /* - * Allocate space to each device: - */ - 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) || - (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) { - layout_dev(dev); - } - if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) - found_vga = 1; - } - /* - * Recursively allocate space for all of the sub-buses: - */ - DBG_DEVS(("layout_bus: starting bus %d children\n", bus->number)); - - for (child = bus->children; child; child = child->next) { - found_vga += layout_bus(child); - } - /* - * Align the current bases on 4K and 1MB boundaries: - */ - tio = io_base = ALIGN(io_base, 4*KB); - tmem = mem_base = ALIGN(mem_base, 1*MB); - - if (bus->self) { - struct pci_dev *bridge = bus->self; - - DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number)); - - /* - * Set up the top and bottom of the PCI I/O segment - * for this bus. - */ - pcibios_read_config_dword(bridge->bus->number, bridge->devfn, - PCI_IO_BASE, &l); - l &= 0xffff0000; - l |= ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000); - pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - PCI_IO_BASE, l); - - /* - * Clear out the upper 16 bits of IO base/limit. - * Clear out the upper 32 bits of PREF base/limit. - */ - pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - PCI_IO_BASE_UPPER16, 0); - pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - PCI_PREF_BASE_UPPER32, 0); - pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - PCI_PREF_LIMIT_UPPER32, 0); - - /* - * Set up the top and bottom of the PCI Memory segment - * for this bus. - */ - l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000); - pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - PCI_MEMORY_BASE, l); - - /* - * Turn off downstream PF memory address range, unless - * there is a VGA behind this bridge, in which case, we - * enable the PREFETCH range to include BIOS ROM at C0000. - * - * NOTE: this is a bit of a hack, done with PREFETCH for - * simplicity, rather than having to add it into the above - * non-PREFETCH range, which could then be bigger than we want. - * We might assume that we could relocate the BIOS ROM, but - * that would depend on having it found by those who need it - * (the DEC BIOS emulator would find it, but I do not know - * about the Xservers). So, we do it this way for now... ;-} - */ - l = (found_vga) ? 0 : 0x0000ffff; - pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - PCI_PREF_MEMORY_BASE, l); - - /* - * Tell bridge that there is an ISA bus in the system, - * and (possibly) a VGA as well. - */ - l = (found_vga) ? 0x0c : 0x04; - pcibios_write_config_byte(bridge->bus->number, bridge->devfn, - PCI_BRIDGE_CONTROL, l); - - /* - * Clear status bits, - * turn on I/O enable (for downstream I/O), - * turn on memory enable (for downstream memory), - * turn on master enable (for upstream memory and I/O). - */ - pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - PCI_COMMAND, 0xffff0007); - } - DBG_DEVS(("layout_bus: bus %d finished\n", bus->number)); - return found_vga; -} - -void __init -layout_all_busses(unsigned long default_io_base, - unsigned long default_mem_base) -{ - struct pci_bus *cur; - - layout_hoses(); - - /* - * Scan the tree, allocating PCI memory and I/O space. - */ - /* - * Sigh; check_region() will need changing to accept a PCI_HANDLE, - * if we allocate I/O space addresses on a per-bus basis. - * For now, make the I/O bases unique across all busses, so - * that check_region() will not get confused... ;-} - */ - io_base = default_io_base; - for (cur = &pci_root; cur; cur = cur->next) { - mem_base = default_mem_base; - DBG_DEVS(("layout_all_busses: calling layout_bus()\n")); - layout_bus(cur); - } - DBG_DEVS(("layout_all_busses: done.\n")); -} - - -/* - * The SRM console *disables* the IDE interface, this code ensures it's - * enabled. - * - * This code bangs on a control register of the 87312 Super I/O chip - * that implements parallel port/serial ports/IDE/FDI. Depending on - * the motherboard, the Super I/O chip can be configured through a - * pair of registers that are located either at I/O ports 0x26e/0x26f - * or 0x398/0x399. Unfortunately, autodetecting which base address is - * in use works only once (right after a reset). The Super I/O chip - * has the additional quirk that configuration register data must be - * written twice (I believe this is a safety feature to prevent - * accidental modification---fun, isn't it?). - */ - -void __init -enable_ide(long ide_base) -{ - int data; - unsigned long flags; - - __save_and_cli(flags); - outb(0, ide_base); /* set the index register for reg #0 */ - data = inb(ide_base+1); /* read the current contents */ - outb(0, ide_base); /* set the index register for reg #0 */ - outb(data | 0x40, ide_base+1); /* turn on IDE */ - outb(data | 0x40, ide_base+1); /* turn on IDE, really! */ - __restore_flags(flags); -} - -/* Look for mis-configured devices' I/O space addresses behind bridges. */ -static void -check_behind_io(struct pci_dev *dev) -{ - struct pci_bus *bus = dev->bus; - unsigned int reg, orig_base, new_base, found_one = 0; - - for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { - /* Read the current setting, check for I/O space and >= 64K */ - pcibios_read_config_dword(bus->number, dev->devfn, - reg, &orig_base); - - if (!orig_base || !(orig_base & PCI_BASE_ADDRESS_SPACE_IO)) - continue; /* unused or non-IO */ - - if (orig_base < 64*1024) { -#if 1 -printk("check_behind_io: ALREADY OK! bus %d slot %d base 0x%x\n", - bus->number, PCI_SLOT(dev->devfn), orig_base); -#endif - if (orig_base & ~1) - continue; /* OK! */ - orig_base = 0x12001; /* HACK! FIXME!! */ - } - - /* HACK ALERT! for now, just subtract 32K from the - original address, which should give us addresses - in the range 0x8000 and up */ - new_base = orig_base - 0x8000; -#if 1 -printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n", - bus->number, PCI_SLOT(dev->devfn), orig_base, new_base); -#endif - pcibios_write_config_dword(bus->number, dev->devfn, - reg, new_base); - - new_io_reset(dev, reg, orig_base); - found_one++; - } - - /* If any were modified, gotta hack the bridge IO limits too. */ - if (found_one) { - if (bus->self) { - struct pci_dev *bridge = bus->self; - unsigned int l; - /* - * Set up the top and bottom of the PCI I/O segment - * for this bus. - */ - pcibios_read_config_dword(bridge->bus->number, - bridge->devfn, 0x1c, &l); -#if 1 -printk("check_behind_io: ALERT! bus %d slot %d oldLIM 0x%x\n", - bus->number, PCI_SLOT(bridge->devfn), l); -#endif - l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */ - pcibios_write_config_dword(bridge->bus->number, - bridge->devfn, 0x1c, l); - pcibios_write_config_dword(bridge->bus->number, - bridge->devfn, - 0x3c, 0x00040000); - pcibios_write_config_dword(bridge->bus->number, - bridge->devfn, - 0x4, 0xffff0007); - } else - printk("check_behind_io: WARNING! bus->self NULL\n"); - } -} - - -/* - * Most boards share most of the fixup code, which is isolated here. - */ - -void __init -common_pci_fixup(int (*map_irq)(struct pci_dev *dev, int slot, int pin), - int (*swizzle)(struct pci_dev *dev, int *pin)) -{ - struct pci_dev *dev; - u8 pin, slot, irq_orig; - int irq; - - /* - * 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) && - (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) - continue; - - /* - * We don't have code that will init the CYPRESS bridge - * correctly so we do the next best thing, and depend on - * the previous console code to do the right thing, and - * ignore it here... :-\ - */ - if (dev->vendor == PCI_VENDOR_ID_CONTAQ && - dev->device == PCI_DEVICE_ID_CONTAQ_82C693) { - DBG_DEVS(("common_pci_fixup: ignoring CYPRESS bridge...\n")); - continue; - } - - /* - * 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; - - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_PIN, &pin); - /* Cope with 0 and illegal. */ - if (pin == 0 || pin > 4) - pin = 1; - - if (!DEV_IS_ON_PRIMARY(dev)) { - /* Follow the chain of bridges, swizzling as we go. */ - - int spill = pin; - slot = (*swizzle)(dev, &spill); - pin = spill; - - /* Must make sure that SRM didn't screw up - and allocate an address > 64K for I/O - space behind a PCI-PCI bridge. */ - if (alpha_use_srm_setup) - check_behind_io(dev); - } else { - /* Just a device on a primary bus. */ - slot = PCI_SLOT(dev->devfn); - } - - irq = (*map_irq)(dev, slot, pin); - - DBG_DEVS(("common_pci_fixup: bus %d slot %d " - "pin %d irq %d\n", - dev->bus->number, slot, pin, irq)); - - if (irq != -1) - dev->irq = irq; - - if (alpha_using_srm) { - /* Read the original SRM-set IRQ and tell. */ - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_LINE, - &irq_orig); - - if (irq_orig != dev->irq) { - DBG_DEVS(("common_pci_fixup: bus %d " - "slot 0x%x SRM IRQ 0x%x " - "changed to 0x%x\n", - dev->bus->number, - PCI_SLOT(dev->devfn), - irq_orig, dev->irq)); - - new_irq_reset(dev, irq_orig); - } - } - - /* Always tell the device, so the driver knows what is - the real IRQ to use; the device does not use it. */ - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); - - DBG_DEVS(("common_pci_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) { - /* But if its a Cirrus 543x/544x DISABLE it, - since enabling ROM disables the memory... */ - if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) && - (dev->device >= 0x00a0) && - (dev->device <= 0x00ac)) { - pcibios_write_config_dword( - dev->bus->number, - dev->devfn, - PCI_ROM_ADDRESS, - 0x00000000); - } else { - 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); - } - } -} - -/* Most Alphas have straight-forward swizzling needs. */ - -int __init -common_swizzle(struct pci_dev *dev, int *pinp) -{ - int pin = *pinp; - do { - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - /* Move up the chain of bridges. */ - dev = dev->bus->self; - } while (dev->bus->self); - *pinp = pin; - - /* The slot is the slot of the last bridge. */ - return PCI_SLOT(dev->devfn); -} - -/* - * On multiple bus machines, in order to cope with a somewhat deficient - * API, we must map the 8-bit bus identifier so that it is unique across - * multiple interfaces (hoses). At the same time we do this, chain the - * other hoses off of pci_root so that they will be found during normal - * PCI probing and layout. - */ - -#define PRIMARY(b) ((b)&0xff) -#define SECONDARY(b) (((b)>>8)&0xff) -#define SUBORDINATE(b) (((b)>>16)&0xff) - -static int __init -hose_scan_bridges(struct linux_hose_info *hose, unsigned char bus) -{ - unsigned int devfn, l, class; - unsigned char hdr_type = 0; - unsigned int found = 0; - - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) == 0) { - alpha_mv.hose_read_config_byte(bus, devfn, - PCI_HEADER_TYPE, - &hdr_type, hose); - } else if (!(hdr_type & 0x80)) { - /* not a multi-function device */ - continue; - } - - /* Check if there is anything here. */ - alpha_mv.hose_read_config_dword(bus, devfn, PCI_VENDOR_ID, - &l, hose); - if (l == 0xffffffff || l == 0x00000000) { - hdr_type = 0; - continue; - } - - /* See if this is a bridge device. */ - alpha_mv.hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION, - &class, hose); - - if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { - unsigned int busses; - - found++; - - alpha_mv.hose_read_config_dword(bus, devfn, - PCI_PRIMARY_BUS, - &busses, hose); - - DBG_HOSE(("hose_scan_bridges: hose %d bus %d " - "slot %d busses 0x%x\n", - hose->pci_hose_index, bus, PCI_SLOT(devfn), - busses)); - - /* - * Do something with first_busno and last_busno - */ - if (hose->pci_first_busno > PRIMARY(busses)) { - hose->pci_first_busno = PRIMARY(busses); - DBG_HOSE(("hose_scan_bridges: hose %d bus %d " - "slot %d change first to %d\n", - hose->pci_hose_index, bus, - PCI_SLOT(devfn), PRIMARY(busses))); - } - if (hose->pci_last_busno < SUBORDINATE(busses)) { - hose->pci_last_busno = SUBORDINATE(busses); - DBG_HOSE(("hose_scan_bridges: hose %d bus %d " - "slot %d change last to %d\n", - hose->pci_hose_index, bus, - PCI_SLOT(devfn), - SUBORDINATE(busses))); - } - /* - * Now scan everything underneath the bridge. - */ - hose_scan_bridges(hose, SECONDARY(busses)); - } - } - return found; -} - -static void __init -hose_reconfigure_bridges(struct linux_hose_info *hose, unsigned char bus) -{ - unsigned int devfn, l, class; - unsigned char hdr_type = 0; - - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) == 0) { - alpha_mv.hose_read_config_byte(bus, devfn, - PCI_HEADER_TYPE, - &hdr_type, hose); - } else if (!(hdr_type & 0x80)) { - /* not a multi-function device */ - continue; - } - - /* Check if there is anything here. */ - alpha_mv.hose_read_config_dword(bus, devfn, PCI_VENDOR_ID, - &l, hose); - if (l == 0xffffffff || l == 0x00000000) { - hdr_type = 0; - continue; - } - - /* See if this is a bridge device. */ - alpha_mv.hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION, - &class, hose); - - if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { - unsigned int busses; - - alpha_mv.hose_read_config_dword(bus, devfn, - PCI_PRIMARY_BUS, - &busses, hose); - - /* - * First reconfigure everything underneath the bridge. - */ - hose_reconfigure_bridges(hose, (busses >> 8) & 0xff); - - /* - * Unconfigure this bridges bus numbers, - * pci_scan_bus() will fix this up properly. - */ - busses &= 0xff000000; - alpha_mv.hose_write_config_dword(bus, devfn, - PCI_PRIMARY_BUS, - busses, hose); - } - } -} - -static void __init -hose_fixup_busno(struct linux_hose_info *hose, unsigned char bus) -{ - int nbus; - - /* - * First, scan for all bridge devices underneath this hose, - * to determine the first and last busnos. - */ - DBG_HOSE(("hose_fixup_busno: before hose_scan_bridges()\n")); - - if (!hose_scan_bridges(hose, 0)) { - /* none found, exit */ - hose->pci_first_busno = bus; - hose->pci_last_busno = bus; - } else { - /* - * Reconfigure all bridge devices underneath this hose. - */ - DBG_HOSE(("hose_fixup_busno: before hose_reconfigure_bridges\n")); - hose_reconfigure_bridges(hose, hose->pci_first_busno); - } - - /* - * Now reconfigure the hose to it's new bus number and set up - * our bus2hose mapping for this hose. - */ - nbus = hose->pci_last_busno - hose->pci_first_busno; - - hose->pci_first_busno = bus; - - DBG_HOSE(("hose_fixup_busno: hose %d startbus %d nbus %d\n", - hose->pci_hose_index, bus, nbus)); - - do { - bus2hose[bus++] = hose; - } while (nbus-- > 0); - DBG_HOSE(("hose_fixup_busno: returning...\n")); -} - -static void __init -layout_one_hose(struct linux_hose_info *hose) -{ - static struct pci_bus *pchain = NULL; - struct pci_bus *pbus = &hose->pci_bus; - static unsigned char busno = 0; - - DBG_HOSE(("layout_one_hose: entry\n")); - - /* - * Hoses 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 - * hose's root PCI device hierarchy. - */ - - pbus->number = pbus->secondary = busno; - pbus->sysdata = hose; - - DBG_HOSE(("layout_one_hose: before hose_fixup_busno()\n")); - - hose_fixup_busno(hose, busno); - - DBG_HOSE(("layout_one_hose: before pci_scan_bus()\n")); - - pbus->subordinate = pci_scan_bus(pbus); /* the original! */ - - /* - * Set the maximum subordinate bus of this hose. - */ - hose->pci_last_busno = pbus->subordinate; -#if 0 - alpha_mv.hose_write_config_byte(busno, 0, 0x41, hose->pci_last_busno, - hose); -#endif - busno = pbus->subordinate + 1; - - /* - * Fixup the chain of primary PCI busses. - */ - if (pchain) { - pchain->next = &hose->pci_bus; - pchain = pchain->next; - } else { - pchain = &pci_root; - memcpy(pchain, &hose->pci_bus, sizeof(pci_root)); - } - DBG_HOSE(("layout_one_hose: returning...\n")); -} - -static void __init -layout_hoses(void) -{ - struct linux_hose_info * hose; - int i; - - /* On multiple bus machines, we play games with pci_root in order - that all of the busses are probed as part of the normal PCI - setup. The existance of the busses was determined in init_arch. */ - - if (hose_head) { - /* Multi-bus machines did not yet wish to allow bus - accesses. We now do our own thing after the normal - pci_scan_bus is over. This mechanism is relatively - broken but will be fixed later. */ - pci_probe_enabled = 1; - - for (hose = hose_head; hose; hose = hose->next) - layout_one_hose(hose); - } else { - /* For the benefit of single-bus machines, emulate a - multi-bus machine to the (limited) extent necessary. - Init all bus2hose entries to point to a dummy. */ - hose = kmalloc(sizeof(*hose), GFP_KERNEL); - memset(hose, 0, sizeof(*hose)); - for (i = 0; i < 256; ++i) - bus2hose[i] = hose; - } -} - -#endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/bios32.h linux/arch/alpha/kernel/bios32.h --- v2.3.15/linux/arch/alpha/kernel/bios32.h Sun Jan 10 09:59:54 1999 +++ linux/arch/alpha/kernel/bios32.h Wed Dec 31 16:00:00 1969 @@ -1,166 +0,0 @@ -/* - * linux/arch/alpha/kernel/bios32.h - * - * This file contains declarations and inline functions for interfacing - * with the PCI initialization routines in bios32.c. - */ - - -#define KB 1024 -#define MB (1024*KB) -#define GB (1024*MB) - -/* - * 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. - * - * Note that we may need this stuff for SRM_SETUP also, since certain - * SRM consoles screw up and allocate I/O space addresses > 64K behind - * PCI-to_PCI bridges, which can't pass I/O addresses larger than 64K, - * AFAIK. - */ - -#define EISA_DEFAULT_IO_BASE 0x9000 /* start above 8th slot */ -#define DEFAULT_IO_BASE 0x8000 /* start at 8th slot */ - -/* - * We try to make the DEFAULT_MEM_BASE addresses *always* have more than - * a single 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. - */ - -/* - * 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. - */ -#define XL_DEFAULT_MEM_BASE (16*MB + 2*MB) /* 16M to 64M-1 is avail */ - -/* - * APECS and LCA have only 34 bits for physical addresses, thus limiting PCI - * bus memory addresses for SPARSE access to be less than 128Mb. - */ -#define APECS_AND_LCA_DEFAULT_MEM_BASE (64*MB + 2*MB) - -/* - * Because the MCPCIA core logic supports more bits for physical addresses, - * it should allow an expanded range of SPARSE memory addresses. - * However, we do not use them all, in order to avoid the HAE manipulation - * that would be needed. - */ -#define RAWHIDE_DEFAULT_MEM_BASE (64*MB + 2*MB) - -/* - * Because CIA and PYXIS and T2 have more bits for physical addresses, - * they support an expanded range of SPARSE memory addresses. - */ -#define DEFAULT_MEM_BASE (128*MB + 16*MB) - - -/* - * PCI_MODIFY - * - * If this 0, then do not write to any of the PCI registers, merely - * read them (i.e., use configuration as determined by SRM). The SRM - * seem do be doing a less than perfect job in configuring PCI - * devices, so for now we do it ourselves. Reconfiguring PCI devices - * breaks console (RPB) callbacks, but those don't work properly with - * 64 bit addresses anyways. - * - * The accepted convention seems to be that the console (POST - * software) should fully configure boot devices and configure the - * interrupt routing of *all* devices. In particular, the base - * addresses of non-boot devices need not be initialized. For - * example, on the AXPpci33 board, the base address a #9 GXE PCI - * graphics card reads as zero (this may, however, be due to a bug in - * the graphics card---there have been some rumor that the #9 BIOS - * incorrectly resets that address to 0...). - */ - -#define PCI_MODIFY (!alpha_use_srm_setup) - - -/* - * 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 - * Device Connector - * - * 4 A A - * B B - * C C - * D D - * - * 5 A B - * B C - * C D - * D A - * - * 6 A C - * B D - * C A - * D B - * - * 7 A D - * B A - * C B - * D C - * - * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. - * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 - * - * The following code swizzles for exactly one bridge. The routine - * common_swizzle below handles multiple bridges. But there are a - * couple boards that do strange things, so we define this here. - */ - -static inline unsigned char -bridge_swizzle(unsigned char pin, unsigned int slot) -{ - return (((pin-1) + slot) % 4) + 1; -} - -extern void layout_all_busses(unsigned long io_base, unsigned long mem_base); -extern void enable_ide(long ide_base); - -struct pci_dev; - -extern void -common_pci_fixup(int (*map_irq)(struct pci_dev *dev, int slot, int pin), - int (*swizzle)(struct pci_dev *dev, int *pin)); - -extern int common_swizzle(struct pci_dev *dev, int *pinp); - -/* The following macro is used to implement the table-based irq mapping - function for all single-bus Alphas. */ - -#define COMMON_TABLE_LOOKUP \ -({ long _ctl_ = -1; \ - if (slot >= min_idsel && slot <= max_idsel && pin < irqs_per_slot) \ - _ctl_ = irq_tab[slot - min_idsel][pin]; \ - _ctl_; }) - - -/* The hose list. */ -extern struct linux_hose_info *hose_head, **hose_tail; -extern int hose_count; -extern int pci_probe_enabled; diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c --- v2.3.15/linux/arch/alpha/kernel/core_apecs.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_apecs.c Tue Aug 31 10:50:39 1999 @@ -1,14 +1,15 @@ /* * linux/arch/alpha/kernel/core_apecs.c * - * Code common to all APECS core logic chips. - * * Rewritten for Apecs from the lca.c from: * * Written by David Mosberger (davidm@cs.arizona.edu) with some code * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit * bios code. + * + * Code common to all APECS core logic chips. */ + #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #define __EXTERN_INLINE inline #include @@ -25,6 +27,7 @@ #undef __EXTERN_INLINE #include "proto.h" +#include "pci_impl.h" /* * NOTE: Herein lie back-to-back mb instructions. They are magic. @@ -89,10 +92,12 @@ */ static int -mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," " pci_addr=0x%p, type1=0x%p)\n", @@ -212,7 +217,6 @@ __save_and_cli(flags); /* avoid getting hit by machine check */ - /* Reset status register to avoid losing errors. */ stat0 = *(vuip)APECS_IOC_DCSR; *(vuip)APECS_IOC_DCSR = stat0; @@ -270,162 +274,106 @@ __restore_flags(flags); } -int -apecs_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +apecs_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr = APECS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; - + addr = (pci_addr << 5) + 0x00 + APECS_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; } -int -apecs_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +apecs_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = APECS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x08; - + addr = (pci_addr << 5) + 0x08 + APECS_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -apecs_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +apecs_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = APECS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x18; + addr = (pci_addr << 5) + 0x18 + APECS_CONF; *value = conf_read(addr, type1); return PCIBIOS_SUCCESSFUL; } -int -apecs_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +apecs_write_config(struct pci_dev *dev, int where, u32 value, long mask) { - unsigned long addr = APECS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + mask + APECS_CONF; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } -int -apecs_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +apecs_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = APECS_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr |= (pci_addr << 5) + 0x08; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; + return apecs_write_config(dev, where, value, 0x00); } -int -apecs_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +apecs_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = APECS_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; + return apecs_write_config(dev, where, value, 0x08); +} - addr |= (pci_addr << 5) + 0x18; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; +static int +apecs_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + return apecs_write_config(dev, where, value, 0x18); } +struct pci_ops apecs_pci_ops = +{ + read_byte: apecs_read_config_byte, + read_word: apecs_read_config_word, + read_dword: apecs_read_config_dword, + write_byte: apecs_write_config_byte, + write_word: apecs_write_config_word, + write_dword: apecs_write_config_dword +}; + void __init apecs_init_arch(unsigned long *mem_start, unsigned long *mem_end) { - switch (alpha_use_srm_setup) - { - default: -#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) - /* Check window 1 for enabled and mapped to 0. */ - if ((*(vuip)APECS_IOC_PB1R & (1U<<19)) - && (*(vuip)APECS_IOC_TB1R == 0)) { - APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB1R & 0xfff00000U; - APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM1R & 0xfff00000U; - APECS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("apecs_init: using Window 1 settings\n"); - printk("apecs_init: PB1R 0x%x PM1R 0x%x TB1R 0x%x\n", - *(vuip)APECS_IOC_PB1R, - *(vuip)APECS_IOC_PM1R, - *(vuip)APECS_IOC_TB1R); -#endif - break; - } + struct pci_controler *hose; - /* Check window 2 for enabled and mapped to 0. */ - if ((*(vuip)APECS_IOC_PB2R & (1U<<19)) - && (*(vuip)APECS_IOC_TB2R == 0)) { - APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB2R & 0xfff00000U; - APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM2R & 0xfff00000U; - APECS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("apecs_init: using Window 2 settings\n"); - printk("apecs_init: PB2R 0x%x PM2R 0x%x TB2R 0x%x\n", - *(vuip)APECS_IOC_PB2R, - *(vuip)APECS_IOC_PM2R, - *(vuip)APECS_IOC_TB2R); -#endif - break; - } - - /* Otherwise, we must use our defaults. */ - APECS_DMA_WIN_BASE = APECS_DMA_WIN_BASE_DEFAULT; - APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT; -#endif - case 0: - /* - * 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. - */ - *(vuip)APECS_IOC_PB2R = 0U; /* disable window 2 */ - - *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_DMA_WIN_BASE_DEFAULT & 0xfff00000U); - *(vuip)APECS_IOC_PM1R = (APECS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; - *(vuip)APECS_IOC_TB1R = 0; - break; - } + /* + * 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. + */ + *(vuip)APECS_IOC_PB1R = 1UL << 19 | (APECS_DMA_WIN_BASE & 0xfff00000U); + *(vuip)APECS_IOC_PM1R = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U; + *(vuip)APECS_IOC_TB1R = 0; + + *(vuip)APECS_IOC_PB2R = 0U; /* disable window 2 */ /* * Finally, clear the HAXR2 register, which gets used @@ -433,7 +381,18 @@ * we want to use it, and we do not want to depend on * what ARC or SRM might have left behind... */ - *(vuip)APECS_IOC_HAXR2 = 0; mb(); + *(vuip)APECS_IOC_HAXR2 = 0; + mb(); + + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(mem_start); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = APECS_CONF; + hose->index = 0; } void diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.3.15/linux/arch/alpha/kernel/core_cia.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_cia.c Tue Aug 31 10:50:39 1999 @@ -1,12 +1,16 @@ /* * linux/arch/alpha/kernel/core_cia.c * - * Code common to all CIA core logic chips. - * * Written by David A Rusling (david.rusling@reo.mts.dec.com). * December 1995. * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1997, 1998 Jay Estabrook + * Copyright (C) 1998, 1999 Richard Henderson + * + * Code common to all CIA core logic chips. */ + #include #include #include @@ -16,6 +20,7 @@ #include #include +#include #define __EXTERN_INLINE inline #include @@ -23,6 +28,8 @@ #undef __EXTERN_INLINE #include "proto.h" +#include "pci_impl.h" + /* * NOTE: Herein lie back-to-back mb instructions. They are magic. @@ -88,10 +95,12 @@ */ static int -mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; DBGC(("mk_conf_addr(bus=%d, device_fn=0x%x, where=0x%x, " "pci_addr=0x%p, type1=0x%p)\n", @@ -166,30 +175,6 @@ mcheck_expected(0) = 0; mb(); -#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 = *(vuip)CIA_IOC_CIA_ERR; - DBGC(("conf_read: CIA ERR after read 0x%x\n", stat0)); - - /* Is any error bit set? */ - if (stat0 & 0x8FEF0FFFU) { - /* If not MAS_ABT, print status. */ - if (!(stat0 & 0x0080)) { - printk("CIA.c:conf_read: got stat0=%x\n", stat0); - } - - /* reset error status: */ - *(vuip)CIA_IOC_CIA_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)CIA_IOC_CFG = cia_cfg & ~1; @@ -237,30 +222,6 @@ mcheck_expected(0) = 0; mb(); -#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 = *(vuip)CIA_IOC_CIA_ERR; - DBGC(("conf_write: CIA ERR after write 0x%x\n", stat0)); - - /* Is any error bit set? */ - if (stat0 & 0x8FEF0FFFU) { - /* If not MAS_ABT, print status */ - if (!(stat0 & 0x0080)) { - printk("CIA.c:conf_read: got stat0=%x\n", stat0); - } - - /* Reset error status. */ - *(vuip)CIA_IOC_CIA_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)CIA_IOC_CFG = cia_cfg & ~1; @@ -271,267 +232,179 @@ __restore_flags(flags); } -int -cia_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +cia_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr = CIA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + 0x00 + CIA_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -cia_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +cia_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = CIA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x08; + addr = (pci_addr << 5) + 0x08 + CIA_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -cia_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +cia_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = CIA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x18; + addr = (pci_addr << 5) + 0x18 + CIA_CONF; *value = conf_read(addr, type1); return PCIBIOS_SUCCESSFUL; } -int -cia_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +cia_write_config(struct pci_dev *dev, int where, u32 value, long mask) { - unsigned long addr = CIA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + mask + CIA_CONF; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } -int -cia_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +cia_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = CIA_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr |= (pci_addr << 5) + 0x08; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; + return cia_write_config(dev, where, value, 0x00); } -int -cia_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +cia_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = CIA_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; + return cia_write_config(dev, where, value, 0x08); +} - addr |= (pci_addr << 5) + 0x18; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; +static int +cia_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + return cia_write_config(dev, where, value, 0x18); } +struct pci_ops cia_pci_ops = +{ + read_byte: cia_read_config_byte, + read_word: cia_read_config_word, + read_dword: cia_read_config_dword, + write_byte: cia_write_config_byte, + write_word: cia_write_config_word, + write_dword: cia_write_config_dword +}; + void __init cia_init_arch(unsigned long *mem_start, unsigned long *mem_end) { - unsigned int cia_tmp; + struct pci_controler *hose; + struct resource *hae_mem; + unsigned int temp; #if 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); - 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); - temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb(); - printk("cia_init: W0_BASE was 0x%x\n", temp); - temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb(); - printk("cia_init: W1_BASE was 0x%x\n", temp); - temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb(); - printk("cia_init: W2_BASE was 0x%x\n", temp); - temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb(); - printk("cia_init: W3_BASE was 0x%x\n", 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); + 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); + temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb(); + printk("cia_init: W0_BASE was 0x%x\n", temp); + temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb(); + printk("cia_init: W1_BASE was 0x%x\n", temp); + temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb(); + printk("cia_init: W2_BASE was 0x%x\n", temp); + temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb(); + printk("cia_init: W3_BASE was 0x%x\n", temp); #endif /* DEBUG_DUMP_REGS */ /* * Set up error reporting. */ - 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(); - - switch (alpha_use_srm_setup) - { - default: -#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) - /* Check window 0 for enabled and mapped to 0 */ - if (((*(vuip)CIA_IOC_PCI_W0_BASE & 3) == 1) - && (*(vuip)CIA_IOC_PCI_T0_BASE == 0)) { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W0_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W0_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("cia_init: using Window 0 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W0_BASE, - *(vuip)CIA_IOC_PCI_W0_MASK, - *(vuip)CIA_IOC_PCI_T0_BASE); -#endif - break; - } - - /* Check window 1 for enabled and mapped to 0. */ - if (((*(vuip)CIA_IOC_PCI_W1_BASE & 3) == 1) - && (*(vuip)CIA_IOC_PCI_T1_BASE == 0)) { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W1_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W1_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("cia_init: using Window 1 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W1_BASE, - *(vuip)CIA_IOC_PCI_W1_MASK, - *(vuip)CIA_IOC_PCI_T1_BASE); -#endif - break; - } + temp = *(vuip)CIA_IOC_CIA_ERR; + temp |= 0x180; /* master, target abort */ + *(vuip)CIA_IOC_CIA_ERR = temp; + mb(); - /* Check window 2 for enabled and mapped to 0. */ - if (((*(vuip)CIA_IOC_PCI_W2_BASE & 3) == 1) - && (*(vuip)CIA_IOC_PCI_T2_BASE == 0)) { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W2_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W2_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("cia_init: using Window 2 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W2_BASE, - *(vuip)CIA_IOC_PCI_W2_MASK, - *(vuip)CIA_IOC_PCI_T2_BASE); -#endif - break; - } + temp = *(vuip)CIA_IOC_CIA_CTRL; + temp |= 0x400; /* turn on FILL_ERR to get mchecks */ + *(vuip)CIA_IOC_CIA_CTRL = temp; + mb(); - /* Check window 3 for enabled and mapped to 0. */ - if (((*(vuip)CIA_IOC_PCI_W3_BASE & 3) == 1) - && (*(vuip)CIA_IOC_PCI_T3_BASE == 0)) { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W3_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W3_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("cia_init: using Window 3 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W3_BASE, - *(vuip)CIA_IOC_PCI_W3_MASK, - *(vuip)CIA_IOC_PCI_T3_BASE); -#endif - break; - } + /* + * Set up the PCI->physical memory translation windows. + * For now, windows 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. + * Window 1 goes at 2 GB and is 1 GB large. + */ - /* Otherwise, we must use our defaults. */ - CIA_DMA_WIN_BASE = CIA_DMA_WIN_BASE_DEFAULT; - CIA_DMA_WIN_SIZE = CIA_DMA_WIN_SIZE_DEFAULT; -#endif - case 0: - /* - * Set up the PCI->physical memory translation windows. - * For now, windows 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. - * Window 1 goes at 2 GB and is 1 GB large. - */ - - *(vuip)CIA_IOC_PCI_W0_BASE = CIA_DMA_WIN0_BASE_DEFAULT | 1U; - *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN0_SIZE_DEFAULT - 1) & - 0xfff00000U; - *(vuip)CIA_IOC_PCI_T0_BASE = CIA_DMA_WIN0_TRAN_DEFAULT >> 2; + *(vuip)CIA_IOC_PCI_W0_BASE = CIA_DMA_WIN0_BASE_DEFAULT | 1U; + *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN0_SIZE_DEFAULT - 1) & + 0xfff00000U; + *(vuip)CIA_IOC_PCI_T0_BASE = CIA_DMA_WIN0_TRAN_DEFAULT >> 2; - *(vuip)CIA_IOC_PCI_W1_BASE = CIA_DMA_WIN1_BASE_DEFAULT | 1U; - *(vuip)CIA_IOC_PCI_W1_MASK = (CIA_DMA_WIN1_SIZE_DEFAULT - 1) & - 0xfff00000U; - *(vuip)CIA_IOC_PCI_T1_BASE = CIA_DMA_WIN1_TRAN_DEFAULT >> 2; + *(vuip)CIA_IOC_PCI_W1_BASE = CIA_DMA_WIN1_BASE_DEFAULT | 1U; + *(vuip)CIA_IOC_PCI_W1_MASK = (CIA_DMA_WIN1_SIZE_DEFAULT - 1) & + 0xfff00000U; + *(vuip)CIA_IOC_PCI_T1_BASE = CIA_DMA_WIN1_TRAN_DEFAULT >> 2; - *(vuip)CIA_IOC_PCI_W2_BASE = 0x0; - *(vuip)CIA_IOC_PCI_W3_BASE = 0x0; - mb(); - break; - } + *(vuip)CIA_IOC_PCI_W2_BASE = 0x0; + *(vuip)CIA_IOC_PCI_W3_BASE = 0x0; + mb(); /* * Next, clear the CIA_CFG register, which gets used @@ -541,40 +414,31 @@ */ *((vuip)CIA_IOC_CFG) = 0; mb(); + /* + * Zero the HAEs. + */ + *((vuip)CIA_IOC_HAE_MEM) = 0; mb(); + *((vuip)CIA_IOC_HAE_MEM); /* read it back. */ + *((vuip)CIA_IOC_HAE_IO) = 0; mb(); + *((vuip)CIA_IOC_HAE_IO); /* read it back. */ /* - * Sigh... For the SRM setup, unless we know apriori what the HAE - * contents will be, we need to setup the arbitrary region bases - * so we can test against the range of addresses and tailor the - * region chosen for the SPARSE memory access. - * - * See include/asm-alpha/cia.h for the SPARSE mem read/write. + * Create our single hose. */ - if (alpha_use_srm_setup) { - unsigned int cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM); - alpha_mv.sm_base_r1 = (cia_hae_mem ) & 0xe0000000UL; - alpha_mv.sm_base_r2 = (cia_hae_mem << 16) & 0xf8000000UL; - alpha_mv.sm_base_r3 = (cia_hae_mem << 24) & 0xfc000000UL; - - /* - * Set the HAE cache, so that setup_arch() code - * will use the SRM setting always. Our readb/writeb - * code in cia.h expects never to have to change - * the contents of the HAE. - */ - alpha_mv.hae_cache = cia_hae_mem; - - alpha_mv.mv_readb = cia_srm_readb; - alpha_mv.mv_readw = cia_srm_readw; - alpha_mv.mv_writeb = cia_srm_writeb; - alpha_mv.mv_writew = cia_srm_writew; - } else { - *((vuip)CIA_IOC_HAE_MEM) = 0; mb(); - *((vuip)CIA_IOC_HAE_MEM); /* read it back. */ - *((vuip)CIA_IOC_HAE_IO) = 0; mb(); - *((vuip)CIA_IOC_HAE_IO); /* read it back. */ - } + hose = alloc_pci_controler(mem_start); + hae_mem = alloc_resource(mem_start); + + hose->io_space = &ioport_resource; + hose->mem_space = hae_mem; + hose->config_space = CIA_CONF; + hose->index = 0; + + hae_mem->start = 0; + hae_mem->end = CIA_MEM_R1_MASK; + hae_mem->name = pci_hae0_name; + + request_resource(&iomem_resource, hae_mem); } static inline void diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c --- v2.3.15/linux/arch/alpha/kernel/core_lca.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_lca.c Tue Aug 31 10:50:39 1999 @@ -1,12 +1,13 @@ /* * linux/arch/alpha/kernel/core_lca.c * - * Code common to all LCA core logic chips. - * * Written by David Mosberger (davidm@cs.arizona.edu) with some code * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit * bios code. + * + * Code common to all LCA core logic chips. */ + #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #define __EXTERN_INLINE inline #include @@ -24,6 +26,8 @@ #undef __EXTERN_INLINE #include "proto.h" +#include "pci_impl.h" + /* * BIOS32-style PCI interface: @@ -97,9 +101,11 @@ */ static int -mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr) +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr) { unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; if (bus == 0) { int device = device_fn >> 3; @@ -194,154 +200,103 @@ __restore_flags(flags); } -int -lca_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +lca_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr = LCA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + if (mk_conf_addr(dev, where, &pci_addr)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + 0x00 + LCA_CONF; *value = conf_read(addr) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -lca_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +lca_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = LCA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + if (mk_conf_addr(dev, where, &pci_addr)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x08; + addr = (pci_addr << 5) + 0x08 + LCA_CONF; *value = conf_read(addr) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -lca_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +lca_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = LCA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + if (mk_conf_addr(dev, where, &pci_addr)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x18; + addr = (pci_addr << 5) + 0x18 + LCA_CONF; *value = conf_read(addr); return PCIBIOS_SUCCESSFUL; } -int -lca_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +lca_write_config(struct pci_dev *dev, int where, u32 value, long mask) { - unsigned long addr = LCA_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + if (mk_conf_addr(dev, where, &pci_addr)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + mask + LCA_CONF; conf_write(addr, value << ((where & 3) * 8)); return PCIBIOS_SUCCESSFUL; } -int -lca_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +lca_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = LCA_CONF; - unsigned long pci_addr; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr |= (pci_addr << 5) + 0x08; - conf_write(addr, value << ((where & 3) * 8)); - return PCIBIOS_SUCCESSFUL; + return lca_write_config(dev, where, value, 0x00); } -int -lca_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +lca_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = LCA_CONF; - unsigned long pci_addr; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) - return PCIBIOS_DEVICE_NOT_FOUND; + return lca_write_config(dev, where, value, 0x08); +} - addr |= (pci_addr << 5) + 0x18; - conf_write(addr, value << ((where & 3) * 8)); - return PCIBIOS_SUCCESSFUL; +static int +lca_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + return lca_write_config(dev, where, value, 0x18); } +struct pci_ops lca_pci_ops = +{ + read_byte: lca_read_config_byte, + read_word: lca_read_config_word, + read_dword: lca_read_config_dword, + write_byte: lca_write_config_byte, + write_word: lca_write_config_word, + write_dword: lca_write_config_dword +}; + void __init lca_init_arch(unsigned long *mem_start, unsigned long *mem_end) { - switch (alpha_use_srm_setup) - { - default: -#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) - /* Check window 0 for enabled and mapped to 0. */ - if ((*(vulp)LCA_IOC_W_BASE0 & (1UL<<33)) - && (*(vulp)LCA_IOC_T_BASE0 == 0)) { - LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE0 & 0xffffffffUL; - LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK0 & 0xffffffffUL; - LCA_DMA_WIN_SIZE += 1; -#if 0 - printk("lca_init: using Window 0 settings\n"); - printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)LCA_IOC_W_BASE0, - *(vulp)LCA_IOC_W_MASK0, - *(vulp)LCA_IOC_T_BASE0); -#endif - break; - } + struct pci_controler *hose; - /* Check window 2 for enabled and mapped to 0. */ - if ((*(vulp)LCA_IOC_W_BASE1 & (1UL<<33)) - && (*(vulp)LCA_IOC_T_BASE1 == 0)) { - LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE1 & 0xffffffffUL; - LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK1 & 0xffffffffUL; - LCA_DMA_WIN_SIZE += 1; -#if 1 - printk("lca_init: using Window 1 settings\n"); - printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)LCA_IOC_W_BASE1, - *(vulp)LCA_IOC_W_MASK1, - *(vulp)LCA_IOC_T_BASE1); -#endif - break; - } + /* + * Set up the PCI->physical memory translation windows. + * For now, window 1 is disabled. In the future, we may + * want to use it to do scatter/gather DMA. + * + * Window 0 goes at 1 GB and is 1 GB large. + */ + *(vulp)LCA_IOC_W_BASE0 = 1UL << 33 | LCA_DMA_WIN_BASE; + *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1; + *(vulp)LCA_IOC_T_BASE0 = 0; - /* Otherwise, we must use our defaults. */ - LCA_DMA_WIN_BASE = LCA_DMA_WIN_BASE_DEFAULT; - LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT; -#endif - case 0: - /* - * Set up the PCI->physical memory translation windows. - * For now, window 1 is disabled. In the future, we may - * want to use it to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. - */ - *(vulp)LCA_IOC_W_BASE1 = 0UL<<33; - - *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE_DEFAULT; - *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE_DEFAULT - 1; - *(vulp)LCA_IOC_T_BASE0 = 0; - break; - } + *(vulp)LCA_IOC_W_BASE1 = 0UL; /* * Disable PCI parity for now. The NCR53c810 chip has @@ -349,6 +304,16 @@ * data parity errors. */ *(vulp)LCA_IOC_PAR_DIS = 1UL<<5; + + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(mem_start); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = LCA_CONF; + hose->index = 0; } /* @@ -376,7 +341,7 @@ #define IOC_P_NBR ((__u32) ~((1<<13) - 1)) static void -mem_error (unsigned long esr, unsigned long ear) +mem_error(unsigned long esr, unsigned long ear) { printk(" %s %s error to %s occurred at address %x\n", ((esr & ESR_CEE) ? "Correctable" : @@ -399,7 +364,7 @@ } static void -ioc_error (__u32 stat0, __u32 stat1) +ioc_error(__u32 stat0, __u32 stat1) { static const char * const pci_cmd[] = { "Interrupt Acknowledge", "Special", "I/O Read", "I/O Write", @@ -430,8 +395,8 @@ } void -lca_machine_check (unsigned long vector, unsigned long la_ptr, - struct pt_regs *regs) +lca_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs *regs) { const char * reason; union el_lca el; diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.3.15/linux/arch/alpha/kernel/core_mcpcia.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_mcpcia.c Tue Aug 31 10:50:39 1999 @@ -1,11 +1,11 @@ /* * linux/arch/alpha/kernel/core_mcpcia.c * - * Code common to all MCbus-PCI Adaptor core logic chipsets - * * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). * + * Code common to all MCbus-PCI Adaptor core logic chipsets */ + #include #include #include @@ -25,7 +25,7 @@ #undef __EXTERN_INLINE #include "proto.h" -#include "bios32.h" +#include "pci_impl.h" /* * NOTE: Herein lie back-to-back mb instructions. They are magic. @@ -47,6 +47,11 @@ #define MCPCIA_MAX_HOSES 2 +/* Dodge has PCI0 and PCI1 at MID 4 and 5 respectively. Durango adds + PCI2 and PCI3 at MID 6 and 7 respectively. */ + +#define hose2mid(h) ((h) + 4) + /* * Given a bus, device, and function number, compute resulting @@ -92,10 +97,10 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1, - struct linux_hose_info *hose) + struct pci_controler *hose) { unsigned long flags; - unsigned long hoseno = hose->pci_hose_index; + unsigned long mid = hose2mid(hose->index); unsigned int stat0, value, temp, cpu; cpu = smp_processor_id(); @@ -103,19 +108,20 @@ __save_and_cli(flags); DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n", - addr, type1, hoseno)); + addr, type1, mid)); /* Reset status register to avoid losing errors. */ - stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno); - *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb(); - temp = *(vuip)MCPCIA_CAP_ERR(hoseno); - DBG_CFG(("conf_read: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0)); + stat0 = *(vuip)MCPCIA_CAP_ERR(mid); + *(vuip)MCPCIA_CAP_ERR(mid) = stat0; + mb(); + temp = *(vuip)MCPCIA_CAP_ERR(mid); + DBG_CFG(("conf_read: MCPCIA_CAP_ERR(%d) was 0x%x\n", mid, stat0)); mb(); draina(); mcheck_expected(cpu) = 1; mcheck_taken(cpu) = 0; - mcheck_hose(cpu) = hoseno; + mcheck_extra(cpu) = mid; mb(); /* Access configuration space. */ @@ -139,10 +145,10 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char type1, - struct linux_hose_info *hose) + struct pci_controler *hose) { unsigned long flags; - unsigned long hoseno = hose->pci_hose_index; + unsigned long mid = hose2mid(hose->index); unsigned int stat0, temp, cpu; cpu = smp_processor_id(); @@ -150,21 +156,21 @@ __save_and_cli(flags); /* avoid getting hit by machine check */ /* Reset status register to avoid losing errors. */ - stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno); - *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb(); - temp = *(vuip)MCPCIA_CAP_ERR(hoseno); - DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0)); + stat0 = *(vuip)MCPCIA_CAP_ERR(mid); + *(vuip)MCPCIA_CAP_ERR(mid) = stat0; mb(); + temp = *(vuip)MCPCIA_CAP_ERR(mid); + DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", mid, stat0)); draina(); mcheck_expected(cpu) = 1; - mcheck_hose(cpu) = hoseno; + mcheck_extra(cpu) = mid; mb(); /* Access configuration space. */ *((vuip)addr) = value; mb(); mb(); /* magic */ - temp = *(vuip)MCPCIA_CAP_ERR(hoseno); /* read to force the write */ + temp = *(vuip)MCPCIA_CAP_ERR(mid); /* read to force the write */ mcheck_expected(cpu) = 0; mb(); @@ -173,71 +179,71 @@ } static int -mk_conf_addr(struct linux_hose_info *hose, - u8 bus, u8 device_fn, u8 where, +mk_conf_addr(struct pci_dev *dev, int where, struct pci_controler *hose, unsigned long *pci_addr, unsigned char *type1) { + u8 bus = dev->bus->number; + u8 devfn = dev->devfn; unsigned long addr; - if (!pci_probe_enabled) - return -1; - - DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," + DBG_CFG(("mk_conf_addr(bus=%d,devfn=0x%x,hose=%d,where=0x%x," " pci_addr=0x%p, type1=0x%p)\n", - bus, device_fn, where, pci_addr, type1)); + bus, devfn, hose->index, where, pci_addr, type1)); /* Type 1 configuration cycle for *ALL* busses. */ *type1 = 1; - if (hose->pci_first_busno == bus) + if (dev->bus->number == hose->first_busno) bus = 0; - addr = (bus << 16) | (device_fn << 8) | (where); + addr = (bus << 16) | (devfn << 8) | (where); addr <<= 5; /* swizzle for SPARSE */ - addr |= hose->pci_config_space; + addr |= hose->config_space; *pci_addr = addr; DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); return 0; } -int -mcpcia_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +mcpcia_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr; + struct pci_controler *hose = dev->sysdata ? : probing_hose; + unsigned long addr, w; unsigned char type1; - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + if (mk_conf_addr(dev, where, hose, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; addr |= 0x00; - *value = conf_read(addr, type1, hose) >> ((where & 3) * 8); + w = conf_read(addr, type1, hose); + *value = __kernel_extbl(w, where & 3); return PCIBIOS_SUCCESSFUL; } -int -mcpcia_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +mcpcia_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr; + struct pci_controler *hose = dev->sysdata ? : probing_hose; + unsigned long addr, w; unsigned char type1; - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + if (mk_conf_addr(dev, where, hose, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; addr |= 0x08; - *value = conf_read(addr, type1, hose) >> ((where & 3) * 8); + w = conf_read(addr, type1, hose); + *value = __kernel_extwl(w, where & 3); return PCIBIOS_SUCCESSFUL; } -int -mcpcia_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +mcpcia_read_config_dword(struct pci_dev *dev, int where, u32 *value) { + struct pci_controler *hose = dev->sysdata ? : probing_hose; unsigned long addr; unsigned char type1; - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + if (mk_conf_addr(dev, where, hose, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; addr |= 0x18; @@ -245,311 +251,213 @@ return PCIBIOS_SUCCESSFUL; } -int -mcpcia_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +mcpcia_write_config(struct pci_dev *dev, int where, u32 value, long mask) { + struct pci_controler *hose = dev->sysdata ? : probing_hose; unsigned long addr; unsigned char type1; - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + if (mk_conf_addr(dev, where, hose, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= 0x00; - conf_write(addr, value << ((where & 3) * 8), type1, hose); + addr |= mask; + value = __kernel_insql(value, where & 3); + conf_write(addr, value, type1, hose); return PCIBIOS_SUCCESSFUL; } -int -mcpcia_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +mcpcia_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr |= 0x08; - conf_write(addr, value << ((where & 3) * 8), type1, hose); - return PCIBIOS_SUCCESSFUL; + return mcpcia_write_config(dev, where, value, 0x00); } -int -mcpcia_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +mcpcia_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; + return mcpcia_write_config(dev, where, value, 0x08); +} - addr |= 0x18; - conf_write(addr, value << ((where & 3) * 8), type1, hose); - return PCIBIOS_SUCCESSFUL; +static int +mcpcia_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + return mcpcia_write_config(dev, where, value, 0x18); } -void __init -mcpcia_init_arch(unsigned long *mem_start, unsigned long *mem_end) +struct pci_ops mcpcia_pci_ops = { - extern asmlinkage void entInt(void); - struct linux_hose_info *hose; - unsigned int mcpcia_err; + read_byte: mcpcia_read_config_byte, + read_word: mcpcia_read_config_word, + read_dword: mcpcia_read_config_dword, + write_byte: mcpcia_write_config_byte, + write_word: mcpcia_write_config_word, + write_dword: mcpcia_write_config_dword +}; + +static int __init +mcpcia_probe_hose(int h) +{ + int cpu = smp_processor_id(); + int mid = hose2mid(h); unsigned int pci_rev; - int h, cpu; - /* Ho hum.. init_arch is called before init_IRQ, but we need to be - able to handle machine checks. So install the handler now. */ - wrent(entInt, 0); - - /* Align memory to cache line; we'll be allocating from it. */ - *mem_start = (*mem_start | 31) + 1; + /* Gotta be REAL careful. If hose is absent, we get an mcheck. */ - cpu = smp_processor_id(); - - /* First, find how many hoses we have. */ - for (h = 0; h < MCPCIA_MAX_HOSES; h++) { + mb(); + mb(); + draina(); + mcheck_expected(cpu) = 1; + mcheck_taken(cpu) = 0; + mcheck_extra(cpu) = mid; + mb(); - /* Gotta be REAL careful. If hose is absent, we get a - machine check. */ + /* Access the bus revision word. */ + pci_rev = *(vuip)MCPCIA_REV(mid); - mb(); - mb(); - draina(); - mcheck_expected(cpu) = 1; + mb(); + mb(); /* magic */ + if (mcheck_taken(cpu)) { mcheck_taken(cpu) = 0; + pci_rev = 0xffffffff; mb(); + } + mcheck_expected(cpu) = 0; + mb(); - /* Access the bus revision word. */ - pci_rev = *(vuip)MCPCIA_REV(h); + return (pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST; +} - mb(); - mb(); /* magic */ - if (mcheck_taken(cpu)) { - mcheck_taken(cpu) = 0; - pci_rev = 0xffffffff; - mb(); - } - mcheck_expected(cpu) = 0; - mb(); +static void __init +mcpcia_new_hose(unsigned long *mem_start, int h) +{ + struct pci_controler *hose; + struct resource *io, *mem, *hae_mem; + int mid = hose2mid(h); -#if 0 - printk("mcpcia_init_arch: got 0x%x for PCI_REV for hose %d\n", - pci_rev, h); -#endif - if ((pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST) { - hose_count++; + hose = alloc_pci_controler(mem_start); + io = alloc_resource(mem_start); + mem = alloc_resource(mem_start); + hae_mem = alloc_resource(mem_start); + + hose->io_space = io; + hose->mem_space = hae_mem; + hose->config_space = MCPCIA_CONF(mid); + hose->index = h; - hose = (struct linux_hose_info *)*mem_start; - *mem_start = (unsigned long)(hose + 1); + io->start = MCPCIA_IO(mid) - MCPCIA_IO_BIAS; + io->end = io->start + 0xffff; + io->name = pci_io_names[h]; - memset(hose, 0, sizeof(*hose)); + mem->start = MCPCIA_DENSE(mid) - MCPCIA_MEM_BIAS; + mem->end = mem->start + 0xffffffff; + mem->name = pci_mem_names[h]; - *hose_tail = hose; - hose_tail = &hose->next; + hae_mem->start = mem->start; + hae_mem->end = mem->start + MCPCIA_MEM_MASK; + hae_mem->name = pci_hae0_name; - hose->pci_io_space = MCPCIA_IO(h); - hose->pci_mem_space = MCPCIA_DENSE(h); - hose->pci_config_space = MCPCIA_CONF(h); - hose->pci_sparse_space = MCPCIA_SPARSE(h); - hose->pci_hose_index = h; - hose->pci_first_busno = 255; - hose->pci_last_busno = 0; - } - } + request_resource(&ioport_resource, io); + request_resource(&iomem_resource, mem); + request_resource(mem, hae_mem); +} -#if 1 - printk("mcpcia_init_arch: found %d hoses\n", hose_count); -#endif +static void __init +mcpcia_startup_hose(struct pci_controler *hose) +{ + int mid = hose2mid(hose->index); + unsigned int tmp; - /* Now do init for each hose. */ - for (hose = hose_head; hose; hose = hose->next) { - h = hose->pci_hose_index; + /* + * Set up error reporting. Make sure CPU_PE is OFF in the mask. + */ #if 0 - printk("mcpcia_init_arch: -------- hose %d --------\n",h); - printk("MCPCIA_REV 0x%x\n", *(vuip)MCPCIA_REV(h)); - printk("MCPCIA_WHOAMI 0x%x\n", *(vuip)MCPCIA_WHOAMI(h)); - printk("MCPCIA_HAE_MEM 0x%x\n", *(vuip)MCPCIA_HAE_MEM(h)); - printk("MCPCIA_HAE_IO 0x%x\n", *(vuip)MCPCIA_HAE_IO(h)); - printk("MCPCIA_HAE_DENSE 0x%x\n", *(vuip)MCPCIA_HAE_DENSE(h)); - printk("MCPCIA_INT_CTL 0x%x\n", *(vuip)MCPCIA_INT_CTL(h)); - printk("MCPCIA_INT_REQ 0x%x\n", *(vuip)MCPCIA_INT_REQ(h)); - printk("MCPCIA_INT_TARG 0x%x\n", *(vuip)MCPCIA_INT_TARG(h)); - printk("MCPCIA_INT_ADR 0x%x\n", *(vuip)MCPCIA_INT_ADR(h)); - printk("MCPCIA_INT_ADR_EXT 0x%x\n", *(vuip)MCPCIA_INT_ADR_EXT(h)); - printk("MCPCIA_INT_MASK0 0x%x\n", *(vuip)MCPCIA_INT_MASK0(h)); - printk("MCPCIA_INT_MASK1 0x%x\n", *(vuip)MCPCIA_INT_MASK1(h)); - printk("MCPCIA_HBASE 0x%x\n", *(vuip)MCPCIA_HBASE(h)); + tmp = *(vuip)MCPCIA_ERR_MASK(mid); + tmp &= ~4; + *(vuip)MCPCIA_ERR_MASK(mid) = tmp; + mb(); + tmp = *(vuip)MCPCIA_ERR_MASK(mid); #endif - /* - * Set up error reporting. Make sure CPU_PE is OFF in the mask. - */ -#if 0 - mcpcia_err = *(vuip)MCPCIA_ERR_MASK(h); - mcpcia_err &= ~4; - *(vuip)MCPCIA_ERR_MASK(h) = mcpcia_err; - mb(); - mcpcia_err = *(vuip)MCPCIA_ERR_MASK; -#endif + tmp = *(vuip)MCPCIA_CAP_ERR(mid); + tmp |= 0x0006; /* master/target abort */ + *(vuip)MCPCIA_CAP_ERR(mid) = tmp; + mb(); + tmp = *(vuip)MCPCIA_CAP_ERR(mid); - mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h); - mcpcia_err |= 0x0006; /* master/target abort */ - *(vuip)MCPCIA_CAP_ERR(h) = mcpcia_err; - mb() ; - mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h); - - switch (alpha_use_srm_setup) - { - default: -#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) - /* Check window 0 for enabled and mapped to 0. */ - if (((*(vuip)MCPCIA_W0_BASE(h) & 3) == 1) - && (*(vuip)MCPCIA_T0_BASE(h) == 0) - && ((*(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W0_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init_arch: using Window 0 settings\n"); - printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W0_BASE(h), - *(vuip)MCPCIA_W0_MASK(h), - *(vuip)MCPCIA_T0_BASE(h)); -#endif - break; - } + /* + * 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 2 GB and is 2 GB large. + */ + + *(vuip)MCPCIA_W0_BASE(mid) = 1U | (MCPCIA_DMA_WIN_BASE & 0xfff00000U); + *(vuip)MCPCIA_W0_MASK(mid) = (MCPCIA_DMA_WIN_SIZE - 1) & 0xfff00000U; + *(vuip)MCPCIA_T0_BASE(mid) = 0; + + *(vuip)MCPCIA_W1_BASE(mid) = 0x0; + *(vuip)MCPCIA_W2_BASE(mid) = 0x0; + *(vuip)MCPCIA_W3_BASE(mid) = 0x0; - /* Check window 1 for enabled and mapped to 0. */ - if (((*(vuip)MCPCIA_W1_BASE(h) & 3) == 1) - && (*(vuip)MCPCIA_T1_BASE(h) == 0) - && ((*(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W1_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init_arch: using Window 1 settings\n"); - printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W1_BASE(h), - *(vuip)MCPCIA_W1_MASK(h), - *(vuip)MCPCIA_T1_BASE(h)); -#endif - break; - } + *(vuip)MCPCIA_HBASE(mid) = 0x0; + mb(); - /* Check window 2 for enabled and mapped to 0. */ - if (((*(vuip)MCPCIA_W2_BASE(h) & 3) == 1) - && (*(vuip)MCPCIA_T2_BASE(h) == 0) - && ((*(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W2_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init_arch: using Window 2 settings\n"); - printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W2_BASE(h), - *(vuip)MCPCIA_W2_MASK(h), - *(vuip)MCPCIA_T2_BASE(h)); +#if 0 + tmp = *(vuip)MCPCIA_INT_CTL(mid); + printk("mcpcia_init_arch: INT_CTL was 0x%x\n", tmp); + *(vuip)MCPCIA_INT_CTL(mid) = 1U; + mb(); + tmp = *(vuip)MCPCIA_INT_CTL(mid); #endif - break; - } - /* Check window 3 for enabled and mapped to 0. */ - if (((*(vuip)MCPCIA_W3_BASE(h) & 3) == 1) - && (*(vuip)MCPCIA_T3_BASE(h) == 0) - && ((*(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W3_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init_arch: using Window 3 settings\n"); - printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W3_BASE(h), - *(vuip)MCPCIA_W3_MASK(h), - *(vuip)MCPCIA_T3_BASE(h)); -#endif - break; - } + *(vuip)MCPCIA_HAE_MEM(mid) = 0U; + mb(); + *(vuip)MCPCIA_HAE_MEM(mid); /* read it back. */ + *(vuip)MCPCIA_HAE_IO(mid) = 0; + mb(); + *(vuip)MCPCIA_HAE_IO(mid); /* read it back. */ +} - /* Otherwise, we must use our defaults. */ - MCPCIA_DMA_WIN_BASE = MCPCIA_DMA_WIN_BASE_DEFAULT; - MCPCIA_DMA_WIN_SIZE = MCPCIA_DMA_WIN_SIZE_DEFAULT; -#endif - case 0: - /* - * 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 2 GB and is 2 GB large. - */ - - *(vuip)MCPCIA_W0_BASE(h) = 1U | (MCPCIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); - *(vuip)MCPCIA_W0_MASK(h) = (MCPCIA_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; - *(vuip)MCPCIA_T0_BASE(h) = 0; - - *(vuip)MCPCIA_W1_BASE(h) = 0x0 ; - *(vuip)MCPCIA_W2_BASE(h) = 0x0 ; - *(vuip)MCPCIA_W3_BASE(h) = 0x0 ; +void __init +mcpcia_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + extern asmlinkage void entInt(void); + struct pci_controler *hose; + int h, hose_count = 0; - *(vuip)MCPCIA_HBASE(h) = 0x0 ; - mb(); - break; - } -#if 0 - { - unsigned int mcpcia_int_ctl = *((vuip)MCPCIA_INT_CTL(h)); - printk("mcpcia_init_arch: INT_CTL was 0x%x\n", mcpcia_int_ctl); - *(vuip)MCPCIA_INT_CTL(h) = 1U; mb(); - mcpcia_int_ctl = *(vuip)MCPCIA_INT_CTL(h); - } -#endif + /* Ho hum.. init_arch is called before init_IRQ, but we need to be + able to handle machine checks. So install the handler now. */ + wrent(entInt, 0); + + /* With multiple PCI busses, we play with I/O as physical addrs. */ + ioport_resource.end = ~0UL; + iomem_resource.end = ~0UL; - /* - * Sigh... For the SRM setup, unless we know apriori what the HAE - * contents will be, we need to setup the arbitrary region bases - * so we can test against the range of addresses and tailor the - * region chosen for the SPARSE memory access. - * - * See include/asm-alpha/mcpcia.h for the SPARSE mem read/write. - */ - if (alpha_use_srm_setup) { - unsigned int mcpcia_hae_mem = *(vuip)MCPCIA_HAE_MEM(h); - - alpha_mv.sm_base_r1 = (mcpcia_hae_mem ) & 0xe0000000UL; - alpha_mv.sm_base_r2 = (mcpcia_hae_mem << 16) & 0xf8000000UL; - alpha_mv.sm_base_r3 = (mcpcia_hae_mem << 24) & 0xfc000000UL; - - /* - * Set the HAE cache, so that setup_arch() code - * will use the SRM setting always. Our readb/writeb - * code in mcpcia.h expects never to have to change - * the contents of the HAE. - */ - alpha_mv.hae_cache = mcpcia_hae_mem; - - alpha_mv.mv_readb = mcpcia_srm_readb; - alpha_mv.mv_readw = mcpcia_srm_readw; - alpha_mv.mv_writeb = mcpcia_srm_writeb; - alpha_mv.mv_writew = mcpcia_srm_writew; - } else { - *(vuip)MCPCIA_HAE_MEM(h) = 0U; mb(); - *(vuip)MCPCIA_HAE_MEM(h); /* read it back. */ - *(vuip)MCPCIA_HAE_IO(h) = 0; mb(); - *(vuip)MCPCIA_HAE_IO(h); /* read it back. */ + /* First, find how many hoses we have. */ + for (h = 0; h < MCPCIA_MAX_HOSES; ++h) { + if (mcpcia_probe_hose(h)) { + mcpcia_new_hose(mem_start, h); + hose_count++; } } + + printk("mcpcia_init_arch: found %d hoses\n", hose_count); + + /* Now do init for each hose. */ + for (hose = hose_head; hose; hose = hose->next) + mcpcia_startup_hose(hose); } static void -mcpcia_pci_clr_err(int hose) +mcpcia_pci_clr_err(int mid) { - *(vuip)MCPCIA_CAP_ERR(hose); - *(vuip)MCPCIA_CAP_ERR(hose) = 0xffffffff; /* Clear them all. */ + *(vuip)MCPCIA_CAP_ERR(mid); + *(vuip)MCPCIA_CAP_ERR(mid) = 0xffffffff; /* Clear them all. */ mb(); - *(vuip)MCPCIA_CAP_ERR(hose); /* Re-read for force write. */ + *(vuip)MCPCIA_CAP_ERR(mid); /* Re-read for force write. */ } static void @@ -639,19 +547,21 @@ mb(); /* magic */ draina(); if (mcheck_expected(cpu)) { - mcpcia_pci_clr_err(mcheck_hose(cpu)); + mcpcia_pci_clr_err(mcheck_extra(cpu)); } else { /* FIXME: how do we figure out which hose the error was on? */ - mcpcia_pci_clr_err(0); - mcpcia_pci_clr_err(1); + struct pci_controler *hose; + for (hose = hose_head; hose; hose = hose->next) + mcpcia_pci_clr_err(hose2mid(hose->index)); } wrmces(0x7); mb(); - process_mcheck_info(vector, la_ptr, regs, "MCPCIA", - mcheck_expected(cpu)); - - if (vector != 0x620 && vector != 0x630) { - mcpcia_print_uncorrectable(mchk_logout); + if (mcheck_expected(cpu)) { + process_mcheck_info(vector, la_ptr, regs, "MCPCIA", 1); + } else { + process_mcheck_info(vector, la_ptr, regs, "MCPCIA", 0); + if (vector != 0x620 && vector != 0x630) + mcpcia_print_uncorrectable(mchk_logout); } } diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c --- v2.3.15/linux/arch/alpha/kernel/core_polaris.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_polaris.c Tue Aug 31 10:50:39 1999 @@ -2,8 +2,8 @@ * linux/arch/alpha/kernel/core_polaris.c * * POLARIS chip-specific code - * */ + #include #include #include @@ -20,7 +20,7 @@ #undef __EXTERN_INLINE #include "proto.h" -#include "bios32.h" +#include "pci_impl.h" /* * BIOS32-style PCI interface: @@ -66,8 +66,11 @@ */ static int -mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, u8 *type1) +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, u8 *type1) { + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + *type1 = (bus == 0) ? 0 : 1; *pci_addr = (bus << 16) | (device_fn << 8) | (where) | POLARIS_DENSE_CONFIG_BASE; @@ -79,59 +82,52 @@ return 0; } -int -polaris_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +polaris_read_config_byte(struct pci_dev *dev, int where, u8 *value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = __kernel_ldbu(*(vucp)pci_addr); return PCIBIOS_SUCCESSFUL; } - -int -polaris_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +polaris_read_config_word(struct pci_dev *dev, int where, u16 *value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = __kernel_ldwu(*(vusp)pci_addr); return PCIBIOS_SUCCESSFUL; } - -int -polaris_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +polaris_read_config_dword(struct pci_dev *dev, int where, u32 *value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = *(vuip)pci_addr; return PCIBIOS_SUCCESSFUL; } - -int -polaris_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +polaris_write_config_byte(struct pci_dev *dev, int where, u8 value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stb(value, *(vucp)pci_addr); @@ -140,15 +136,13 @@ return PCIBIOS_SUCCESSFUL; } - -int -polaris_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +polaris_write_config_word(struct pci_dev *dev, int where, u16 value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stw(value, *(vusp)pci_addr); @@ -157,15 +151,13 @@ return PCIBIOS_SUCCESSFUL; } - -int -polaris_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +polaris_write_config_dword(struct pci_dev *dev, int where, u32 value) { unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *(vuip)pci_addr = value; @@ -174,9 +166,21 @@ return PCIBIOS_SUCCESSFUL; } +struct pci_ops polaris_pci_ops = +{ + read_byte: polaris_read_config_byte, + read_word: polaris_read_config_word, + read_dword: polaris_read_config_dword, + write_byte: polaris_write_config_byte, + write_word: polaris_write_config_word, + write_dword: polaris_write_config_dword +}; + void __init polaris_init_arch(unsigned long *mem_start, unsigned long *mem_end) { + struct pci_controler *hose; + /* May need to initialize error reporting (see PCICTL0/1), but * for now assume that the firmware has done the right thing * already. @@ -184,6 +188,16 @@ #if 0 printk("polaris_init_arch(): trusting firmware for setup\n"); #endif + + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(mem_start); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = POLARIS_DENSE_CONFIG_BASE; + hose->index = 0; } static inline void diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c --- v2.3.15/linux/arch/alpha/kernel/core_pyxis.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_pyxis.c Tue Aug 31 10:50:39 1999 @@ -1,11 +1,11 @@ /* * linux/arch/alpha/kernel/core_pyxis.c * - * Code common to all PYXIS core logic chips. - * * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). * + * Code common to all PYXIS core logic chips. */ + #include #include #include @@ -15,6 +15,7 @@ #include #include +#include #define __EXTERN_INLINE inline #include @@ -22,6 +23,8 @@ #undef __EXTERN_INLINE #include "proto.h" +#include "pci_impl.h" + /* NOTE: Herein are back-to-back mb instructions. They are magic. One plausible explanation is that the I/O controller does not properly @@ -83,9 +86,12 @@ */ static int -mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + *type1 = (bus == 0) ? 0 : 1; *pci_addr = (bus << 16) | (device_fn << 8) | (where); @@ -196,106 +202,95 @@ addr, value, type1)); } -int -pyxis_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +pyxis_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + 0x00 + PYXIS_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -pyxis_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +pyxis_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x08; + addr = (pci_addr << 5) + 0x08 + PYXIS_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -pyxis_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +pyxis_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x18; + addr = (pci_addr << 5) + 0x18 + PYXIS_CONF; *value = conf_read(addr, type1); return PCIBIOS_SUCCESSFUL; } -int -pyxis_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +pyxis_write_config(struct pci_dev *dev, int where, u32 value, long mask) { - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + mask + PYXIS_CONF; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } -int -pyxis_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +pyxis_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr |= (pci_addr << 5) + 0x08; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; + return pyxis_write_config(dev, where, value, 0x00); } -int -pyxis_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +pyxis_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; + return pyxis_write_config(dev, where, value, 0x08); +} - addr |= (pci_addr << 5) + 0x18; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; +static int +pyxis_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + return pyxis_write_config(dev, where, value, 0x18); } +struct pci_ops pyxis_pci_ops = +{ + read_byte: pyxis_read_config_byte, + read_word: pyxis_read_config_word, + read_dword: pyxis_read_config_dword, + write_byte: pyxis_write_config_byte, + write_word: pyxis_write_config_word, + write_dword: pyxis_write_config_dword +}; + void __init -pyxis_enable_errors (void) +pyxis_init_arch(unsigned long *mem_start, unsigned long *mem_end) { - unsigned int pyxis_err; + struct pci_controler *hose; + unsigned int temp; #if 0 printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK); @@ -311,105 +306,16 @@ /* * Set up error reporting. Make sure CPU_PE is OFF in the mask. */ - pyxis_err = *(vuip)PYXIS_ERR_MASK; - pyxis_err &= ~4; - *(vuip)PYXIS_ERR_MASK = pyxis_err; mb(); - pyxis_err = *(vuip)PYXIS_ERR_MASK; /* re-read to force write */ - - pyxis_err = *(vuip)PYXIS_ERR ; - pyxis_err |= 0x180; /* master/target abort */ - *(vuip)PYXIS_ERR = pyxis_err; mb(); - pyxis_err = *(vuip)PYXIS_ERR; /* re-read to force write */ -} - -int __init -pyxis_srm_window_setup (void) -{ - switch (alpha_use_srm_setup) - { - default: -#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) - /* Check window 0 for enabled and mapped to 0. */ - if (((*(vuip)PYXIS_W0_BASE & 3) == 1) - && (*(vuip)PYXIS_T0_BASE == 0) - && ((*(vuip)PYXIS_W0_MASK & 0xfff00000U) > 0x0ff00000U)) { - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W0_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W0_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 0 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W0_BASE, - *(vuip)PYXIS_W0_MASK, - *(vuip)PYXIS_T0_BASE); -#endif - break; - } + temp = *(vuip)PYXIS_ERR_MASK; + temp &= ~4; + *(vuip)PYXIS_ERR_MASK = temp; mb(); + temp = *(vuip)PYXIS_ERR_MASK; /* re-read to force write */ + + temp = *(vuip)PYXIS_ERR ; + temp |= 0x180; /* master/target abort */ + *(vuip)PYXIS_ERR = temp; mb(); + temp = *(vuip)PYXIS_ERR; /* re-read to force write */ - /* Check window 1 for enabled and mapped to 0. */ - if (((*(vuip)PYXIS_W1_BASE & 3) == 1) - && (*(vuip)PYXIS_T1_BASE == 0) - && ((*(vuip)PYXIS_W1_MASK & 0xfff00000U) > 0x0ff00000U)) { - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W1_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W1_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 1 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W1_BASE, - *(vuip)PYXIS_W1_MASK, - *(vuip)PYXIS_T1_BASE); -#endif - break; - } - - /* Check window 2 for enabled and mapped to 0. */ - if (((*(vuip)PYXIS_W2_BASE & 3) == 1) - && (*(vuip)PYXIS_T2_BASE == 0) - && ((*(vuip)PYXIS_W2_MASK & 0xfff00000U) > 0x0ff00000U)) { - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W2_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W2_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 2 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W2_BASE, - *(vuip)PYXIS_W2_MASK, - *(vuip)PYXIS_T2_BASE); -#endif - break; - } - - /* Check window 3 for enabled and mapped to 0. */ - if (((*(vuip)PYXIS_W3_BASE & 3) == 1) - && (*(vuip)PYXIS_T3_BASE == 0) - && ((*(vuip)PYXIS_W3_MASK & 0xfff00000U) > 0x0ff00000U)) { - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W3_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W3_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 3 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W3_BASE, - *(vuip)PYXIS_W3_MASK, - *(vuip)PYXIS_T3_BASE); -#endif - break; - } - - /* Otherwise, we must use our defaults. */ - PYXIS_DMA_WIN_BASE = PYXIS_DMA_WIN_BASE_DEFAULT; - PYXIS_DMA_WIN_SIZE = PYXIS_DMA_WIN_SIZE_DEFAULT; -#endif - case 0: - return 0; - } - return 1; -} - -void __init -pyxis_native_window_setup(void) -{ /* * Set up the PCI->physical memory translation windows. * For now, windows 2 and 3 are disabled. In the future, we may @@ -430,11 +336,7 @@ *(vuip)PYXIS_W2_BASE = 0x0; *(vuip)PYXIS_W3_BASE = 0x0; mb(); -} -void __init -pyxis_finish_init_arch(void) -{ /* * Next, clear the PYXIS_CFG register, which gets used * for PCI Config Space accesses. That is the way @@ -453,42 +355,11 @@ } } - /* - * Sigh... For the SRM setup, unless we know apriori what the HAE - * contents will be, we need to setup the arbitrary region bases - * so we can test against the range of addresses and tailor the - * region chosen for the SPARSE memory access. - * - * See include/asm-alpha/pyxis.h for the SPARSE mem read/write. - */ - if (alpha_use_srm_setup) { - unsigned int pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM; - - alpha_mv.sm_base_r1 = (pyxis_hae_mem ) & 0xe0000000UL; - alpha_mv.sm_base_r2 = (pyxis_hae_mem << 16) & 0xf8000000UL; - alpha_mv.sm_base_r3 = (pyxis_hae_mem << 24) & 0xfc000000UL; - - /* - * Set the HAE cache, so that setup_arch() code - * will use the SRM setting always. Our readb/writeb - * code in pyxis.h expects never to have to change - * the contents of the HAE. - */ - alpha_mv.hae_cache = pyxis_hae_mem; - -#ifndef CONFIG_ALPHA_GENERIC - /* In a generic kernel, we can always use BWIO. */ - alpha_mv.mv_readb = pyxis_srm_readb; - alpha_mv.mv_readw = pyxis_srm_readw; - alpha_mv.mv_writeb = pyxis_srm_writeb; - alpha_mv.mv_writew = pyxis_srm_writew; -#endif - } else { - *(vuip)PYXIS_HAE_MEM = 0U; mb(); - *(vuip)PYXIS_HAE_MEM; /* re-read to force write */ - *(vuip)PYXIS_HAE_IO = 0; mb(); - *(vuip)PYXIS_HAE_IO; /* re-read to force write */ - } + /* Zero the HAE. */ + *(vuip)PYXIS_HAE_MEM = 0U; mb(); + *(vuip)PYXIS_HAE_MEM; /* re-read to force write */ + *(vuip)PYXIS_HAE_IO = 0; mb(); + *(vuip)PYXIS_HAE_IO; /* re-read to force write */ /* * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for @@ -505,15 +376,16 @@ ctrl1 = *(vuip)PYXIS_CTRL1; /* re-read */ } } -} -void __init -pyxis_init_arch(unsigned long *mem_start, unsigned long *mem_end) -{ - pyxis_enable_errors(); - if (!pyxis_srm_window_setup()) - pyxis_native_window_setup(); - pyxis_finish_init_arch(); + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(mem_start); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = PYXIS_CONF; + hose->index = 0; } static inline void diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c --- v2.3.15/linux/arch/alpha/kernel/core_t2.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_t2.c Tue Aug 31 10:50:39 1999 @@ -1,14 +1,14 @@ /* * linux/arch/alpha/kernel/core_t2.c * - * Code common to all T2 core logic 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) * + * Code common to all T2 core logic chips. */ + #include #include #include @@ -18,6 +18,7 @@ #include #include +#include #define __EXTERN_INLINE #include @@ -25,6 +26,8 @@ #undef __EXTERN_INLINE #include "proto.h" +#include "pci_impl.h" + /* * NOTE: Herein lie back-to-back mb instructions. They are magic. @@ -88,10 +91,12 @@ */ static int -mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; DBG(("mk_conf_addr(bus=%d, dfn=0x%x, where=0x%x," " addr=0x%lx, type1=0x%x)\n", @@ -234,105 +239,94 @@ __restore_flags(flags); } -int -t2_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +t2_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr = T2_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + 0x00 + T2_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -t2_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +t2_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = T2_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x08; + addr = (pci_addr << 5) + 0x08 + T2_CONF; *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } -int -t2_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +t2_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = T2_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x18; + addr = (pci_addr << 5) + 0x18 + T2_CONF; *value = conf_read(addr, type1); return PCIBIOS_SUCCESSFUL; } -int -t2_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +t2_write_config(struct pci_dev *dev, int where, u32 value, long mask) { - unsigned long addr = T2_CONF; - unsigned long pci_addr; + unsigned long addr, pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + if (mk_conf_addr(dev, where, &pci_addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; - addr |= (pci_addr << 5) + 0x00; + addr = (pci_addr << 5) + mask + T2_CONF; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } -int -t2_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +t2_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = T2_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr |= (pci_addr << 5) + 0x08; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; + return t2_write_config(dev, where, value, 0x00); } -int -t2_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +t2_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = T2_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) - return PCIBIOS_DEVICE_NOT_FOUND; + return t2_write_config(dev, where, value, 0x08); +} - addr |= (pci_addr << 5) + 0x18; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; +static int +t2_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + return t2_write_config(dev, where, value, 0x18); } +struct pci_ops t2_pci_ops = +{ + read_byte: t2_read_config_byte, + read_word: t2_read_config_word, + read_dword: t2_read_config_dword, + write_byte: t2_write_config_byte, + write_word: t2_write_config_word, + write_dword: t2_write_config_dword +}; + void __init t2_init_arch(unsigned long *mem_start, unsigned long *mem_end) { + struct pci_controler *hose; unsigned int i; for (i = 0; i < NR_CPUS; i++) { @@ -364,100 +358,39 @@ *(vulp)T2_TBASE2); #endif - switch (alpha_use_srm_setup) - { - default: -#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) - /* Check window 1 for enabled and mapped to 0. */ - if (((*(vulp)T2_WBASE1 & (3UL<<18)) == (2UL<<18)) - && (*(vulp)T2_TBASE1 == 0)) { - T2_DMA_WIN_BASE = *(vulp)T2_WBASE1 & 0xfff00000UL; - T2_DMA_WIN_SIZE = *(vulp)T2_WMASK1 & 0xfff00000UL; - T2_DMA_WIN_SIZE += 0x00100000UL; - /* DISABLE window 2!! ?? */ -#if 1 - printk("t2_init: using Window 1 settings\n"); - printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)T2_WBASE1, - *(vulp)T2_WMASK1, - *(vulp)T2_TBASE1); -#endif - break; - } - - /* Check window 2 for enabled and mapped to 0. */ - if (((*(vulp)T2_WBASE2 & (3UL<<18)) == (2UL<<18)) - && (*(vulp)T2_TBASE2 == 0)) { - T2_DMA_WIN_BASE = *(vulp)T2_WBASE2 & 0xfff00000UL; - T2_DMA_WIN_SIZE = *(vulp)T2_WMASK2 & 0xfff00000UL; - T2_DMA_WIN_SIZE += 0x00100000UL; - /* DISABLE window 1!! ?? */ -#if 1 - printk("t2_init: using Window 2 settings\n"); - printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)T2_WBASE2, - *(vulp)T2_WMASK2, - *(vulp)T2_TBASE2); -#endif - break; - } - - /* Otherwise, we must use our defaults. */ - T2_DMA_WIN_BASE = T2_DMA_WIN_BASE_DEFAULT; - T2_DMA_WIN_SIZE = T2_DMA_WIN_SIZE_DEFAULT; -#endif - case 0: - /* - * 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!!! */ - *(vulp)T2_WBASE1 = 0x400807ffU; - *(vulp)T2_WMASK1 = 0x3ff00000U; - *(vulp)T2_TBASE1 = 0; - - *(vulp)T2_WBASE2 = 0x0; - *(vulp)T2_HBASE = 0x0; - break; - } - /* - * Sigh... For the SRM setup, unless we know apriori what the HAE - * contents will be, we need to setup the arbitrary region bases - * so we can test against the range of addresses and tailor the - * region chosen for the SPARSE memory access. + * 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. * - * See include/asm-alpha/t2.h for the SPARSE mem read/write. + * Window 1 goes at 1 GB and is 1 GB large. */ - if (alpha_use_srm_setup) { - unsigned long t2_hae_1 = *(vulp)T2_HAE_1; - - alpha_mv.sm_base_r1 = (t2_hae_1 << 27) & 0xf8000000UL; - /* - * Set the HAE cache, so that setup_arch() code - * will use the SRM setting always. Our readb/writeb - * code in .h expects never to have to change - * the contents of the HAE. - */ - alpha_mv.hae_cache = t2_hae_1; - - alpha_mv.mv_readb = t2_srm_readb; - alpha_mv.mv_readw = t2_srm_readw; - alpha_mv.mv_writeb = t2_srm_writeb; - alpha_mv.mv_writew = t2_srm_writew; - } else { - *(vulp)T2_HAE_1 = 0; mb(); - *(vulp)T2_HAE_2 = 0; mb(); - *(vulp)T2_HAE_3 = 0; mb(); + /* WARNING!! must correspond to the DMA_WIN params!!! */ + *(vulp)T2_WBASE1 = 0x400807ffU; + *(vulp)T2_WMASK1 = 0x3ff00000U; + *(vulp)T2_TBASE1 = 0; + + *(vulp)T2_WBASE2 = 0x0; + *(vulp)T2_HBASE = 0x0; + + /* Zero HAE. */ + *(vulp)T2_HAE_1 = 0; mb(); + *(vulp)T2_HAE_2 = 0; mb(); + *(vulp)T2_HAE_3 = 0; mb(); #if 0 - *(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */ + *(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */ #endif - } + + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(mem_start); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = T2_CONF; + hose->index = 0; } #define SIC_SEIC (1UL << 33) /* System Event Clear */ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.3.15/linux/arch/alpha/kernel/core_tsunami.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/core_tsunami.c Tue Aug 31 10:50:39 1999 @@ -1,10 +1,9 @@ /* * linux/arch/alpha/kernel/core_tsunami.c * - * Code common to all TSUNAMI core logic chips. - * * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com). * + * Code common to all TSUNAMI core logic chips. */ #include @@ -25,7 +24,7 @@ #undef __EXTERN_INLINE #include "proto.h" -#include "bios32.h" +#include "pci_impl.h" int TSUNAMI_bootcpu; @@ -84,115 +83,118 @@ */ static int -mk_conf_addr(u8 bus, u8 device_fn, u8 where, struct linux_hose_info *hose, - unsigned long *pci_addr, unsigned char *type1) +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, + unsigned char *type1) { + struct pci_controler *hose = dev->sysdata ? : probing_hose; unsigned long addr; - - if (!pci_probe_enabled) - return -1; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; DBG_CFG(("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)); - *type1 = (bus != 0); - - if (hose->pci_first_busno == bus) + if (hose->first_busno == dev->bus->number) bus = 0; + *type1 = (bus != 0); addr = (bus << 16) | (device_fn << 8) | where; - addr |= hose->pci_config_space; + addr |= hose->config_space; *pci_addr = addr; DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); return 0; } -int -tsunami_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, - struct linux_hose_info *hose) +static int +tsunami_read_config_byte(struct pci_dev *dev, int where, u8 *value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1)) + if (mk_conf_addr(dev, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = __kernel_ldbu(*(vucp)addr); return PCIBIOS_SUCCESSFUL; } -int -tsunami_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, - struct linux_hose_info *hose) +static int +tsunami_read_config_word(struct pci_dev *dev, int where, u16 *value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1)) + if (mk_conf_addr(dev, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = __kernel_ldwu(*(vusp)addr); return PCIBIOS_SUCCESSFUL; } -int -tsunami_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, - struct linux_hose_info *hose) +static int +tsunami_read_config_dword(struct pci_dev *dev, int where, u32 *value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1)) + if (mk_conf_addr(dev, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *value = *(vuip)addr; return PCIBIOS_SUCCESSFUL; } -int -tsunami_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, - struct linux_hose_info *hose) +static int +tsunami_write_config_byte(struct pci_dev *dev, int where, u8 value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1)) + if (mk_conf_addr(dev, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stb(value, *(vucp)addr); return PCIBIOS_SUCCESSFUL; } -int -tsunami_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, - struct linux_hose_info *hose) +static int +tsunami_write_config_word(struct pci_dev *dev, int where, u16 value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1)) + if (mk_conf_addr(dev, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stw(value, *(vusp)addr); return PCIBIOS_SUCCESSFUL; } -int -tsunami_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, - struct linux_hose_info *hose) +static int +tsunami_write_config_dword(struct pci_dev *dev, int where, u32 value) { unsigned long addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1)) + if (mk_conf_addr(dev, where, &addr, &type1)) return PCIBIOS_DEVICE_NOT_FOUND; *(vuip)addr = value; return PCIBIOS_SUCCESSFUL; } +struct pci_ops tsunami_pci_ops = +{ + read_byte: tsunami_read_config_byte, + read_word: tsunami_read_config_word, + read_dword: tsunami_read_config_dword, + write_byte: tsunami_write_config_byte, + write_word: tsunami_write_config_word, + write_dword: tsunami_write_config_dword +}; + #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI static long tsunami_probe_read(volatile unsigned long *vaddr) @@ -246,75 +248,51 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index, unsigned long *mem_start) { - struct linux_hose_info *hose; - int i; + struct pci_controler *hose; if (tsunami_probe_read(&pchip->pctl.csr) == 0) return; - hose = (struct linux_hose_info *)*mem_start; - *mem_start = (unsigned long)(hose + 1); - memset(hose, 0, sizeof(*hose)); - - *hose_tail = hose; - hose_tail = &hose->next; - - hose->pci_io_space = TSUNAMI_IO(index); - hose->pci_mem_space = TSUNAMI_MEM(index); - hose->pci_config_space = TSUNAMI_CONF(index); - hose->pci_sparse_space = 0; - hose->pci_hose_index = index; - - switch (alpha_use_srm_setup) - { - default: -#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) - for (i = 0; i < 4; ++i) { - if ((pchip->wsba[i].csr & 3) == 1 - && pchip->tba[i].csr == 0 - && (pchip->wsm[i].csr & 0xfff00000) > 0x0ff00000) { - TSUNAMI_DMA_WIN_BASE = pchip->wsba[i].csr & 0xfff00000; - TSUNAMI_DMA_WIN_SIZE = pchip->wsm[i].csr & 0xfff00000; - TSUNAMI_DMA_WIN_SIZE += 0x00100000; -#if 1 - printk("%s: using Window %d settings\n", FN, i); - printk("%s: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - FN, pchip->wsba[i].csr, pchip->wsm[i].csr, - pchip->tba[i].csr); -#endif - goto found; - } - } - - /* Otherwise, we must use our defaults. */ - TSUNAMI_DMA_WIN_BASE = TSUNAMI_DMA_WIN_BASE_DEFAULT; - TSUNAMI_DMA_WIN_SIZE = TSUNAMI_DMA_WIN_SIZE_DEFAULT; -#endif - case 0: - /* - * 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, mapping to 0. - * Window 1 goes at 2 GB and is 1 GB large, mapping to 1GB. - */ - - pchip->wsba[0].csr = TSUNAMI_DMA_WIN0_BASE_DEFAULT | 1UL; - pchip->wsm[0].csr = (TSUNAMI_DMA_WIN0_SIZE_DEFAULT - 1) & - 0xfff00000UL; - pchip->tba[0].csr = TSUNAMI_DMA_WIN0_TRAN_DEFAULT; - - pchip->wsba[1].csr = TSUNAMI_DMA_WIN1_BASE_DEFAULT | 1UL; - pchip->wsm[1].csr = (TSUNAMI_DMA_WIN1_SIZE_DEFAULT - 1) & - 0xfff00000UL; - pchip->tba[1].csr = TSUNAMI_DMA_WIN1_TRAN_DEFAULT; - - pchip->wsba[2].csr = 0; - pchip->wsba[3].csr = 0; - mb(); - } -found:; + hose = alloc_pci_controler(mem_start); + hose->io_space = alloc_resource(mem_start); + hose->mem_space = alloc_resource(mem_start); + + hose->config_space = TSUNAMI_CONF(index); + hose->index = index; + + hose->io_space->start = TSUNAMI_IO(index) - TSUNAMI_IO_BIAS; + hose->io_space->end = hose->io_space->start + 0xffff; + hose->io_space->name = pci_io_names[index]; + + hose->mem_space->start = TSUNAMI_MEM(index) - TSUNAMI_MEM_BIAS; + hose->mem_space->end = hose->mem_space->start + 0xffffffff; + hose->mem_space->name = pci_mem_names[index]; + + request_resource(&ioport_resource, hose->io_space); + request_resource(&iomem_resource, hose->mem_space); + + /* + * 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, mapping to 0. + * Window 1 goes at 2 GB and is 1 GB large, mapping to 1GB. + */ + + pchip->wsba[0].csr = TSUNAMI_DMA_WIN0_BASE_DEFAULT | 1UL; + pchip->wsm[0].csr = (TSUNAMI_DMA_WIN0_SIZE_DEFAULT - 1) & + 0xfff00000UL; + pchip->tba[0].csr = TSUNAMI_DMA_WIN0_TRAN_DEFAULT; + + pchip->wsba[1].csr = TSUNAMI_DMA_WIN1_BASE_DEFAULT | 1UL; + pchip->wsm[1].csr = (TSUNAMI_DMA_WIN1_SIZE_DEFAULT - 1) & + 0xfff00000UL; + pchip->tba[1].csr = TSUNAMI_DMA_WIN1_TRAN_DEFAULT; + + pchip->wsba[2].csr = 0; + pchip->wsba[3].csr = 0; + mb(); } void __init @@ -353,17 +331,18 @@ printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr); printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr); #endif - - /* Align memory to cache line; we'll be allocating from it. */ - *mem_start = (*mem_start | 31) + 1; - TSUNAMI_bootcpu = __hard_smp_processor_id(); + /* With multiple PCI busses, we play with I/O as physical addrs. */ + ioport_resource.end = ~0UL; + iomem_resource.end = ~0UL; + /* Find how many hoses we have, and initialize them. TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10). */ + tsunami_init_one_pchip(TSUNAMI_pchip0, 0, mem_start); if (TSUNAMI_cchip->csc.csr & 1L<<14) - tsunami_init_one_pchip(TSUNAMI_pchip1, 1, mem_start); + tsunami_init_one_pchip(TSUNAMI_pchip1, 1, mem_start); } static inline void diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.3.15/linux/arch/alpha/kernel/entry.S Wed Aug 4 15:48:00 1999 +++ linux/arch/alpha/kernel/entry.S Tue Aug 31 10:50:44 1999 @@ -8,7 +8,7 @@ #define SIGCHLD 20 -#define NR_SYSCALLS 371 +#define NR_SYSCALLS 373 /* * These offsets must match with alpha_mv in . @@ -1147,3 +1147,5 @@ .quad sys_capget .quad sys_capset .quad sys_sendfile /* 370 */ + .quad sys_setresgid + .quad sys_getresgid diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.3.15/linux/arch/alpha/kernel/head.S Tue Jun 22 10:46:52 1999 +++ linux/arch/alpha/kernel/head.S Tue Aug 31 10:50:44 1999 @@ -95,3 +95,21 @@ .prologue 0 call_pal PAL_halt .end halt + + # + # Having the delay loop out of line guarantees that we wont + # run into weird alignment conditions (on new processors) + # that vary the speed of the loop. + # + .align 5 + .globl ___delay + .ent ___delay +___delay: + .set noat + .frame $30,0,$28,0 + .prologue 0 +1: subq $0,1,$0 + bge $0,1b + ret $31,($28),0 + .set at + .end ___delay diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.3.15/linux/arch/alpha/kernel/irq.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/irq.c Tue Aug 31 10:50:44 1999 @@ -30,7 +30,7 @@ #include #include "proto.h" -#include "irq.h" +#include "irq_impl.h" #define vulp volatile unsigned long * #define vuip volatile unsigned int * @@ -67,7 +67,7 @@ */ void -generic_ack_irq(unsigned long irq) +common_ack_irq(unsigned long irq) { if (irq < 16) { /* Ack the interrupt making it the lowest priority */ @@ -987,7 +987,9 @@ printk(KERN_CRIT "machine check type: %s%s\n", reason, mchk_header->retry ? " (retryable)" : ""); - + + dik_show_regs(regs, NULL); + #if DEBUG_MCHECK > 1 { /* Dump the logout area to give all info. */ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/irq.h linux/arch/alpha/kernel/irq.h --- v2.3.15/linux/arch/alpha/kernel/irq.h Mon Jul 12 07:49:36 1999 +++ linux/arch/alpha/kernel/irq.h Wed Dec 31 16:00:00 1969 @@ -1,49 +0,0 @@ -/* - * linux/arch/alpha/kernel/irq.h - * - * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1998 Richard Henderson - * - * This file contains declarations and inline functions for interfacing - * with the IRQ handling routines in irq.c. - */ - -#include - -#define STANDARD_INIT_IRQ_PROLOG \ - outb(0, DMA1_RESET_REG); \ - outb(0, DMA2_RESET_REG); \ - outb(0, DMA1_CLR_MASK_REG); \ - outb(0, DMA2_CLR_MASK_REG) - -extern unsigned long alpha_irq_mask; - -extern void generic_ack_irq(unsigned long irq); -extern void isa_device_interrupt(unsigned long vector, struct pt_regs * regs); -extern void srm_device_interrupt(unsigned long vector, struct pt_regs * regs); - -extern void handle_irq(int irq, int ack, struct pt_regs * regs); - -#define RTC_IRQ 8 -#ifdef CONFIG_RTC -#define TIMER_IRQ 0 /* timer is the pit */ -#else -#define TIMER_IRQ RTC_IRQ /* timer is the rtc */ -#endif - -extern char _stext; -static inline void alpha_do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } -} diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/irq_impl.h linux/arch/alpha/kernel/irq_impl.h --- v2.3.15/linux/arch/alpha/kernel/irq_impl.h Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/irq_impl.h Tue Aug 31 10:50:44 1999 @@ -0,0 +1,49 @@ +/* + * linux/arch/alpha/kernel/irq.h + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 1998 Richard Henderson + * + * This file contains declarations and inline functions for interfacing + * with the IRQ handling routines in irq.c. + */ + +#include + +#define STANDARD_INIT_IRQ_PROLOG \ + outb(0, DMA1_RESET_REG); \ + outb(0, DMA2_RESET_REG); \ + outb(0, DMA1_CLR_MASK_REG); \ + outb(0, DMA2_CLR_MASK_REG) + +extern unsigned long alpha_irq_mask; + +extern void common_ack_irq(unsigned long irq); +extern void isa_device_interrupt(unsigned long vector, struct pt_regs * regs); +extern void srm_device_interrupt(unsigned long vector, struct pt_regs * regs); + +extern void handle_irq(int irq, int ack, struct pt_regs * regs); + +#define RTC_IRQ 8 +#ifdef CONFIG_RTC +#define TIMER_IRQ 0 /* timer is the pit */ +#else +#define TIMER_IRQ RTC_IRQ /* timer is the rtc */ +#endif + +extern char _stext; +static inline void alpha_do_profile (unsigned long pc) +{ + if (prof_buffer && current->pid) { + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Don't ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len - 1) + pc = prof_len - 1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } +} diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/machvec.h linux/arch/alpha/kernel/machvec.h --- v2.3.15/linux/arch/alpha/kernel/machvec.h Mon Aug 16 10:33:58 1999 +++ linux/arch/alpha/kernel/machvec.h Wed Dec 31 16:00:00 1969 @@ -1,140 +0,0 @@ -/* - * linux/arch/alpha/kernel/machvec.h - * - * Copyright (C) 1997, 1998 Richard Henderson - * - * This file has goodies to help simplify instantiation of machine vectors. - */ - -#include - -/* Whee. Both TSUNAMI and POLARIS don't have an HAE. Fix things up for - the GENERIC kernel by defining the HAE address to be that of the cache. - Now we can read and write it as we like. ;-) */ -#define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) -#define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache) - -/* Only a few systems don't define IACK_SC, handling all interrupts through - the SRM console. But splitting out that one case from IO() below - seems like such a pain. Define this to get things to compile. */ -#define JENSEN_IACK_SC 1 -#define T2_IACK_SC 1 - - -/* - * Some helpful macros for filling in the blanks. - */ - -#define CAT1(x,y) x##y -#define CAT(x,y) CAT1(x,y) - -#define DO_DEFAULT_RTC rtc_port: 0x70 - -#define DO_EV4_MMU \ - max_asn: EV4_MAX_ASN, \ - mv_switch_mm: ev4_switch_mm, \ - mv_activate_mm: ev4_activate_mm, \ - mv_flush_tlb_current: ev4_flush_tlb_current, \ - mv_flush_tlb_other: ev4_flush_tlb_other, \ - mv_flush_tlb_current_page: ev4_flush_tlb_current_page - -#define DO_EV5_MMU \ - max_asn: EV5_MAX_ASN, \ - mv_switch_mm: ev5_switch_mm, \ - mv_activate_mm: ev5_activate_mm, \ - mv_flush_tlb_current: ev5_flush_tlb_current, \ - mv_flush_tlb_other: ev5_flush_tlb_other, \ - mv_flush_tlb_current_page: ev5_flush_tlb_current_page - -#define DO_EV6_MMU \ - max_asn: EV6_MAX_ASN, \ - mv_switch_mm: ev5_switch_mm, \ - mv_activate_mm: ev5_activate_mm, \ - mv_flush_tlb_current: ev5_flush_tlb_current, \ - mv_flush_tlb_other: ev5_flush_tlb_other, \ - mv_flush_tlb_current_page: ev5_flush_tlb_current_page - -#define IO_LITE(UP,low1,low2) \ - hae_register: (unsigned long *) CAT(UP,_HAE_ADDRESS), \ - iack_sc: CAT(UP,_IACK_SC), \ - mv_inb: CAT(low1,_inb), \ - mv_inw: CAT(low1,_inw), \ - mv_inl: CAT(low1,_inl), \ - mv_outb: CAT(low1,_outb), \ - mv_outw: CAT(low1,_outw), \ - mv_outl: CAT(low1,_outl), \ - mv_readb: CAT(low1,_readb), \ - mv_readw: CAT(low1,_readw), \ - mv_readl: CAT(low1,_readl), \ - mv_readq: CAT(low1,_readq), \ - mv_writeb: CAT(low1,_writeb), \ - mv_writew: CAT(low1,_writew), \ - mv_writel: CAT(low1,_writel), \ - mv_writeq: CAT(low1,_writeq), \ - mv_ioremap: CAT(low2,_ioremap), \ - mv_is_ioaddr: CAT(low2,_is_ioaddr) - -#define IO(UP,low1,low2) \ - IO_LITE(UP,low1,low2), \ - hose_read_config_byte: CAT(low2,_hose_read_config_byte), \ - hose_read_config_word: CAT(low2,_hose_read_config_word), \ - hose_read_config_dword: CAT(low2,_hose_read_config_dword), \ - hose_write_config_byte: CAT(low2,_hose_write_config_byte), \ - hose_write_config_word: CAT(low2,_hose_write_config_word), \ - hose_write_config_dword: CAT(low2,_hose_write_config_dword), \ - dma_win_base: CAT(UP,_DMA_WIN_BASE_DEFAULT), \ - dma_win_size: CAT(UP,_DMA_WIN_SIZE_DEFAULT) - -/* Any assembler that can generate a GENERIC kernel can generate BWX - instructions. So always use them for PYXIS I/O. */ - -#define DO_APECS_IO IO(APECS,apecs,apecs) -#define DO_CIA_IO IO(CIA,cia,cia) -#define DO_LCA_IO IO(LCA,lca,lca) -#define DO_MCPCIA_IO IO(MCPCIA,mcpcia,mcpcia) -#define DO_PYXIS_IO IO(PYXIS,pyxis_bw,pyxis) -#define DO_POLARIS_IO IO(POLARIS,polaris,polaris) -#define DO_T2_IO IO(T2,t2,t2) -#define DO_TSUNAMI_IO IO(TSUNAMI,tsunami,tsunami) - -#define BUS(which) \ - mv_virt_to_bus: CAT(which,_virt_to_bus), \ - mv_bus_to_virt: CAT(which,_bus_to_virt) - -#define DO_APECS_BUS BUS(apecs) -#define DO_CIA_BUS BUS(cia) -#define DO_LCA_BUS BUS(lca) -#define DO_MCPCIA_BUS BUS(mcpcia) -#define DO_PYXIS_BUS BUS(pyxis) -#define DO_POLARIS_BUS BUS(polaris) -#define DO_T2_BUS BUS(t2) -#define DO_TSUNAMI_BUS BUS(tsunami) - - -/* - * In a GENERIC kernel, we have lots of these vectors floating about, - * all but one of which we want to go away. In a non-GENERIC kernel, - * we want only one, ever. - * - * Accomplish this in the GENERIC kernel by puting all of the vectors - * in the .init.data section where they'll go away. We'll copy the - * one we want to the real alpha_mv vector in setup_arch. - * - * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but - * one of the vectors, which will not reside in .init.data. We then - * alias this one vector to alpha_mv, so no copy is needed. - * - * Upshot: set __initdata to nothing for non-GENERIC kernels. - */ - -#ifdef CONFIG_ALPHA_GENERIC -#define __initmv __initdata -#define ALIAS_MV(x) -#else -#define __initmv - -/* GCC actually has a syntax for defining aliases, but is under some - delusion that you shouldn't be able to declare it extern somewhere - else beforehand. Fine. We'll do it ourselves. */ -#define ALIAS_MV(system) asm(".global alpha_mv\nalpha_mv = " #system "_mv"); -#endif diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/machvec_impl.h linux/arch/alpha/kernel/machvec_impl.h --- v2.3.15/linux/arch/alpha/kernel/machvec_impl.h Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/machvec_impl.h Tue Aug 31 10:50:44 1999 @@ -0,0 +1,146 @@ +/* + * linux/arch/alpha/kernel/machvec.h + * + * Copyright (C) 1997, 1998 Richard Henderson + * + * This file has goodies to help simplify instantiation of machine vectors. + */ + +#include + +/* Whee. Both TSUNAMI and POLARIS don't have an HAE. Fix things up for + the GENERIC kernel by defining the HAE address to be that of the cache. + Now we can read and write it as we like. ;-) */ +#define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) +#define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache) + +#if CIA_ONE_HAE_WINDOW +#define CIA_HAE_ADDRESS (&alpha_mv.hae_cache) +#endif +#if MCPCIA_ONE_HAE_WINDOW +#define MCPCIA_HAE_ADDRESS (&alpha_mv.hae_cache) +#endif + +/* Only a few systems don't define IACK_SC, handling all interrupts through + the SRM console. But splitting out that one case from IO() below + seems like such a pain. Define this to get things to compile. */ +#define JENSEN_IACK_SC 1 +#define T2_IACK_SC 1 + + +/* + * Some helpful macros for filling in the blanks. + */ + +#define CAT1(x,y) x##y +#define CAT(x,y) CAT1(x,y) + +#define DO_DEFAULT_RTC rtc_port: 0x70 + +#define DO_EV4_MMU \ + max_asn: EV4_MAX_ASN, \ + mv_switch_mm: ev4_switch_mm, \ + mv_activate_mm: ev4_activate_mm, \ + mv_flush_tlb_current: ev4_flush_tlb_current, \ + mv_flush_tlb_other: ev4_flush_tlb_other, \ + mv_flush_tlb_current_page: ev4_flush_tlb_current_page + +#define DO_EV5_MMU \ + max_asn: EV5_MAX_ASN, \ + mv_switch_mm: ev5_switch_mm, \ + mv_activate_mm: ev5_activate_mm, \ + mv_flush_tlb_current: ev5_flush_tlb_current, \ + mv_flush_tlb_other: ev5_flush_tlb_other, \ + mv_flush_tlb_current_page: ev5_flush_tlb_current_page + +#define DO_EV6_MMU \ + max_asn: EV6_MAX_ASN, \ + mv_switch_mm: ev5_switch_mm, \ + mv_activate_mm: ev5_activate_mm, \ + mv_flush_tlb_current: ev5_flush_tlb_current, \ + mv_flush_tlb_other: ev5_flush_tlb_other, \ + mv_flush_tlb_current_page: ev5_flush_tlb_current_page + +#define IO_LITE(UP,low) \ + hae_register: (unsigned long *) CAT(UP,_HAE_ADDRESS), \ + iack_sc: CAT(UP,_IACK_SC), \ + mv_inb: CAT(low,_inb), \ + mv_inw: CAT(low,_inw), \ + mv_inl: CAT(low,_inl), \ + mv_outb: CAT(low,_outb), \ + mv_outw: CAT(low,_outw), \ + mv_outl: CAT(low,_outl), \ + mv_readb: CAT(low,_readb), \ + mv_readw: CAT(low,_readw), \ + mv_readl: CAT(low,_readl), \ + mv_readq: CAT(low,_readq), \ + mv_writeb: CAT(low,_writeb), \ + mv_writew: CAT(low,_writew), \ + mv_writel: CAT(low,_writel), \ + mv_writeq: CAT(low,_writeq), \ + mv_ioremap: CAT(low,_ioremap), \ + mv_is_ioaddr: CAT(low,_is_ioaddr) + +#define IO(UP,low) \ + IO_LITE(UP,low), \ + pci_ops: &CAT(low,_pci_ops) + +/* Any assembler that can generate a GENERIC kernel can generate BWX + instructions. So always use them for PYXIS I/O. */ + +#define DO_APECS_IO IO(APECS,apecs) +#define DO_CIA_IO IO(CIA,cia) +#define DO_LCA_IO IO(LCA,lca) +#define DO_MCPCIA_IO IO(MCPCIA,mcpcia) +#define DO_PYXIS_IO IO(PYXIS,pyxis) +#define DO_POLARIS_IO IO(POLARIS,polaris) +#define DO_T2_IO IO(T2,t2) +#define DO_TSUNAMI_IO IO(TSUNAMI,tsunami) + +#define BUS(which) \ + mv_virt_to_bus: CAT(which,_virt_to_bus), \ + mv_bus_to_virt: CAT(which,_bus_to_virt) + +#define DO_APECS_BUS BUS(apecs) +#define DO_CIA_BUS BUS(cia) +#define DO_LCA_BUS BUS(lca) +#define DO_MCPCIA_BUS BUS(mcpcia) +#define DO_PYXIS_BUS BUS(pyxis) +#define DO_POLARIS_BUS BUS(polaris) +#define DO_T2_BUS BUS(t2) +#define DO_TSUNAMI_BUS BUS(tsunami) + + +/* + * In a GENERIC kernel, we have lots of these vectors floating about, + * all but one of which we want to go away. In a non-GENERIC kernel, + * we want only one, ever. + * + * Accomplish this in the GENERIC kernel by puting all of the vectors + * in the .init.data section where they'll go away. We'll copy the + * one we want to the real alpha_mv vector in setup_arch. + * + * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but + * one of the vectors, which will not reside in .init.data. We then + * alias this one vector to alpha_mv, so no copy is needed. + * + * Upshot: set __initdata to nothing for non-GENERIC kernels. + */ + +#ifdef CONFIG_ALPHA_GENERIC +#define __initmv __initdata +#define ALIAS_MV(x) +#else +#define __initmv + +/* GCC actually has a syntax for defining aliases, but is under some + delusion that you shouldn't be able to declare it extern somewhere + else beforehand. Fine. We'll do it ourselves. */ +#if 0 +#define ALIAS_MV(system) \ + struct alpha_machine_vector alpha_mv __attribute__((alias(#system "_mv"))); +#else +#define ALIAS_MV(system) \ + asm(".global alpha_mv\nalpha_mv = " #system "_mv"); +#endif +#endif /* GENERIC */ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/ns87312.c linux/arch/alpha/kernel/ns87312.c --- v2.3.15/linux/arch/alpha/kernel/ns87312.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/ns87312.c Tue Aug 31 10:50:44 1999 @@ -0,0 +1,38 @@ +/* + * linux/arch/alpha/kernel/ns87312.c + */ + +#include +#include +#include "proto.h" + + +/* + * The SRM console *disables* the IDE interface, this code ensures it's + * enabled. + * + * This code bangs on a control register of the 87312 Super I/O chip + * that implements parallel port/serial ports/IDE/FDI. Depending on + * the motherboard, the Super I/O chip can be configured through a + * pair of registers that are located either at I/O ports 0x26e/0x26f + * or 0x398/0x399. Unfortunately, autodetecting which base address is + * in use works only once (right after a reset). The Super I/O chip + * has the additional quirk that configuration register data must be + * written twice (I believe this is a safety feature to prevent + * accidental modification---fun, isn't it?). + */ + +void __init +ns87312_enable_ide(long ide_base) +{ + int data; + unsigned long flags; + + __save_and_cli(flags); + outb(0, ide_base); /* set the index register for reg #0 */ + data = inb(ide_base+1); /* read the current contents */ + outb(0, ide_base); /* set the index register for reg #0 */ + outb(data | 0x40, ide_base+1); /* turn on IDE */ + outb(data | 0x40, ide_base+1); /* turn on IDE, really! */ + __restore_flags(flags); +} diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.3.15/linux/arch/alpha/kernel/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/pci.c Tue Aug 31 10:50:44 1999 @@ -0,0 +1,230 @@ +/* + * linux/arch/alpha/kernel/pci.c + * + * Extruded from code written by + * Dave Rusling (david.rusling@reo.mts.dec.com) + * David Mosberger (davidm@cs.arizona.edu) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "proto.h" +#include "pci_impl.h" + + +/* + * Some string constants used by the various core logics. + */ + +const char *const pci_io_names[] = { + "PCI IO bus 0", "PCI IO bus 1", "PCI IO bus 2", "PCI IO bus 3" +}; + +const char *const pci_mem_names[] = { + "PCI mem bus 0", "PCI mem bus 1", "PCI mem bus 2", "PCI mem bus 3" +}; + +const char pci_hae0_name[] = "HAE0"; + + +/* + * The PCI controler list. + */ + +struct pci_controler *hose_head, **hose_tail = &hose_head; +struct pci_controler *probing_hose; + +/* + * Quirks. + */ + +static void __init +quirk_eisa_bridge(struct pci_dev *dev) +{ + dev->class = PCI_CLASS_BRIDGE_EISA; +} + +static void __init +quirk_isa_bridge(struct pci_dev *dev) +{ + dev->class = PCI_CLASS_BRIDGE_ISA; +} + +struct pci_fixup pcibios_fixups[] __initdata = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, + quirk_eisa_bridge }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, + quirk_isa_bridge }, + { 0 } +}; + + +/* + * Pre-layout host-independant device initialization. + */ + +static void __init +pci_assign_special(void) +{ + struct pci_dev *dev; + + /* The first three resources of the Cypress IDE controler need + to remain unchanged. So allocate them as-is. */ + dev = NULL; + while ((dev = pci_find_device(PCI_VENDOR_ID_CONTAQ, + PCI_DEVICE_ID_CONTAQ_82C693, dev))) { + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + pci_record_assignment(dev, 0); + pci_record_assignment(dev, 1); + pci_record_assignment(dev, 2); + } + } +} + + +void __init +pcibios_init(void) +{ + if (!alpha_mv.init_pci) + return; + alpha_mv.init_pci(); +} + +char * __init +pcibios_setup(char *str) +{ + return str; +} + +void __init +pcibios_fixup_bus(struct pci_bus *bus) +{ + /* Propogate hose info into the subordinate devices. */ + + struct pci_dev *dev; + void *sysdata; + + sysdata = (bus->parent ? bus->parent->sysdata : bus->sysdata); + for (dev = bus->devices; dev; dev = dev->sibling) + dev->sysdata = sysdata; +} + +void __init +pcibios_base_address_update(struct pci_dev *dev, int resource) +{ + struct pci_controler *hose = dev->sysdata; + struct resource *res = &dev->resource[resource]; + unsigned long base, where, size; + u32 reg; + + if (res->flags & IORESOURCE_IO) + base = hose->io_space->start; + else + base = hose->mem_space->start; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - base)) & ~size); + pci_write_config_dword(dev, where, reg); + + /* ??? FIXME -- record old value for shutdown. */ +} + +void __init +pcibios_irq_update(struct pci_dev *dev, u8 irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + + /* ??? FIXME -- record old value for shutdown. */ +} + +/* Most Alphas have straight-forward swizzling needs. */ + +u8 __init +common_swizzle(struct pci_dev *dev, u8 *pinp) +{ + struct pci_controler *hose = dev->sysdata; + + if (dev->bus->number != hose->first_busno) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the slot of the last bridge. */ + } + + return PCI_SLOT(dev->devfn); +} + +void __init +common_init_pci(void) +{ + struct pci_controler *hose; + struct pci_bus *bus; + int next_busno; + + /* Scan all of the recorded PCI controlers. */ + for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { + hose->first_busno = next_busno; + hose->last_busno = 0xff; + probing_hose = hose; + bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose); + hose->bus = bus; + next_busno = hose->last_busno = bus->subordinate; + next_busno += 1; + } + probing_hose = NULL; + + pci_assign_special(); + pci_assign_unassigned(alpha_mv.min_io_address, + alpha_mv.min_mem_address); + pci_fixup_irq(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); + pci_set_bus_ranges(); +} + + +struct pci_controler * __init +alloc_pci_controler(unsigned long *mem_start) +{ + unsigned long start = *mem_start; + struct pci_controler *hose; + if (start & 31) + start = (start | 31) + 1; + hose = (void *) start; + start = (unsigned long) (hose + 1); + *mem_start = start; + + memset(hose, 0, sizeof(*hose)); + + *hose_tail = hose; + hose_tail = &hose->next; + + return hose; +} + +struct resource * __init +alloc_resource(unsigned long *mem_start) +{ + unsigned long start = *mem_start; + struct resource *res; + if (start & 31) + start = (start | 31) + 1; + res = (void *) start; + start = (unsigned long) (res + 1); + *mem_start = start; + + memset(res, 0, sizeof(*res)); + + return res; +} diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h --- v2.3.15/linux/arch/alpha/kernel/pci_impl.h Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/pci_impl.h Tue Aug 31 10:50:44 1999 @@ -0,0 +1,146 @@ +/* + * linux/arch/alpha/kernel/pci_impl.h + * + * This file contains declarations and inline functions for interfacing + * with the PCI initialization routines. + */ + +struct pci_dev; +struct pci_controler; + + +/* + * 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. + */ + +#define EISA_DEFAULT_IO_BASE 0x9000 /* start above 8th slot */ +#define DEFAULT_IO_BASE 0x8000 /* start at 8th slot */ + +/* + * We try to make the DEFAULT_MEM_BASE addresses *always* have more than + * a single 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. + */ + +/* + * 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. + */ +#define XL_DEFAULT_MEM_BASE ((16+2)*1024*1024) /* 16M to 64M-1 is avail */ + +/* + * APECS and LCA have only 34 bits for physical addresses, thus limiting PCI + * bus memory addresses for SPARSE access to be less than 128Mb. + */ +#define APECS_AND_LCA_DEFAULT_MEM_BASE ((32+2)*1024*1024) + +/* + * Because the MCPCIA core logic supports more bits for physical addresses, + * it should allow an expanded range of SPARSE memory addresses. + * However, we do not use them all, in order to avoid the HAE manipulation + * that would be needed. + */ +#define MCPCIA_DEFAULT_MEM_BASE ((32+2)*1024*1024) + +/* + * Because CIA and PYXIS and T2 have more bits for physical addresses, + * they support an expanded range of SPARSE memory addresses. + */ +#define DEFAULT_MEM_BASE ((128+16)*1024*1024) + +/* ??? Experimenting with no HAE for CIA. */ +#define CIA_DEFAULT_MEM_BASE ((32+2)*1024*1024) + + +/* + * 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 + * Device Connector + * + * 4 A A + * B B + * C C + * D D + * + * 5 A B + * B C + * C D + * D A + * + * 6 A C + * B D + * C A + * D B + * + * 7 A D + * B A + * C B + * D C + * + * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. + * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 + * + * The following code swizzles for exactly one bridge. The routine + * common_swizzle below handles multiple bridges. But there are a + * couple boards that do strange things, so we define this here. + */ + +static inline u8 bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + + +/* The following macro is used to implement the table-based irq mapping + function for all single-bus Alphas. */ + +#define COMMON_TABLE_LOOKUP \ +({ long _ctl_ = -1; \ + if (slot >= min_idsel && slot <= max_idsel && pin < irqs_per_slot) \ + _ctl_ = irq_tab[slot - min_idsel][pin]; \ + _ctl_; }) + + +/* The hose list. */ +extern struct pci_controler *hose_head, **hose_tail; +extern struct pci_controler *probing_hose; + +/* pci_common.c */ +extern void common_init_pci(void); +extern u8 common_swizzle(struct pci_dev *, u8 *); +extern struct pci_controler *alloc_pci_controler(unsigned long *); +extern struct resource *alloc_resource(unsigned long *); + +extern const char *const pci_io_names[]; +extern const char *const pci_mem_names[]; +extern const char pci_hae0_name[]; + +/* pci_setup.c */ +void pci_record_assignment(struct pci_dev *dev, int resource); +void pci_assign_unassigned(int, int); +void pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *), + int (*map_irq)(struct pci_dev *, u8, u8)); +void pci_set_bus_ranges(void); + diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/pci_setup.c linux/arch/alpha/kernel/pci_setup.c --- v2.3.15/linux/arch/alpha/kernel/pci_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/pci_setup.c Tue Aug 31 10:50:44 1999 @@ -0,0 +1,328 @@ +/* + * linux/arch/alpha/kernel/pci_setup.c + * + * Extruded from code written by + * Dave Rusling (david.rusling@reo.mts.dec.com) + * David Mosberger (davidm@cs.arizona.edu) + * David Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include + + +#define DEBUG_CONFIG 0 +#if DEBUG_CONFIG +# define DBGC(args) printk args +#else +# define DBGC(args) +#endif + + +void __init +pci_record_assignment(struct pci_dev *dev, int resource) +{ + struct pci_controler *hose = dev->sysdata; + struct resource *res = &dev->resource[resource]; + struct resource *base; + int ok; + + if (res->flags == 0) + return; + if (res->flags & IORESOURCE_IO) + base = hose->io_space; + else + base = hose->mem_space; + + res->start += base->start; + res->end += base->start; + + ok = request_resource(base, res); + + DBGC(("PCI record assignment: (%s) resource %d %s\n", + dev->name, resource, (ok < 0 ? "failed" : "ok"))); +} + +static void inline +pdev_assign_unassigned(struct pci_dev *dev, int min_io, int min_mem) +{ + u32 reg; + u16 cmd; + int i; + + DBGC(("PCI assign resources : (%s)\n", dev->name)); + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct pci_controler *hose; + struct resource *root, *res; + unsigned long size, min, max; + + res = &dev->resource[i]; + + if (res->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + else if (res->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + + /* If it is already assigned or the resource does + not exist, there is nothing to do. */ + if (res->parent != NULL || res->flags == 0UL) + continue; + + hose = dev->sysdata; + + /* Determine the root we allocate from. */ + if (res->flags & IORESOURCE_IO) { + root = hose->io_space; + min = root->start + min_io; + max = root->end; + } else { + root = hose->mem_space; + min = root->start + min_mem; + max = root->end; + } + + size = res->end - res->start + 1; + + DBGC((" for root[%016lx:%016lx]\n" + " res[%016lx:%016lx]\n" + " span[%016lx:%016lx] size[%lx]\n", + root->start, root->end, res->start, res->end, + min, max, size)); + + if (allocate_resource(root, res, size, min, max, size) < 0) { + printk(KERN_ERR + "PCI: Failed to allocate resource %d for %s\n", + i, dev->name); + } + + DBGC((" got res[%016lx:%016lx] for resource %d\n", + res->start, res->end, i)); + + /* Update PCI config space. */ + pcibios_base_address_update(dev, i); + } + + /* Special case, disable the ROM. Several devices act funny + (ie. do not respond to memory space writes) when it is left + enabled. A good example are QlogicISP adapters. */ + + pci_read_config_dword(dev, PCI_ROM_ADDRESS, ®); + reg &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg); + + /* All of these (may) have I/O scattered all around and may not + use IO-base address registers at all. So we just have to + always enable IO to these devices. */ + if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED + || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA + || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE + || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + cmd |= PCI_COMMAND_IO; + } + + /* ??? Always turn on bus mastering. */ + cmd |= PCI_COMMAND_MASTER; + + /* Enable the appropriate bits in the PCI command register. */ + pci_write_config_word(dev, PCI_COMMAND, cmd); + + DBGC((" cmd reg 0x%x\n", cmd)); + + /* If this is a PCI bridge, set the cache line correctly. */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + /* ??? EV4/EV5 cache line is 32 bytes. */ + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + (64 / sizeof(u32))); + } +} + +void __init +pci_assign_unassigned(int min_io, int min_mem) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) + pdev_assign_unassigned(dev, min_io, min_mem); +} + +struct pbus_set_ranges_data +{ + int found_vga; + unsigned int io_start, io_end; + unsigned int mem_start, mem_end; +}; + +static void __init +pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer) +{ + struct pbus_set_ranges_data inner; + struct pci_bus *child; + struct pci_dev *dev; + + inner.found_vga = 0; + inner.mem_start = inner.io_start = ~0; + inner.mem_end = inner.io_end = 0; + + /* Collect information about how our direct children are layed out. */ + for (dev = bus->devices; dev; dev = dev->sibling) { + int i; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + if (res->flags & IORESOURCE_IO) { + if (res->start < inner.io_start) + inner.io_start = res->start; + if (res->end > inner.io_end) + inner.io_end = res->end; + } else if (res->flags & IORESOURCE_MEM) { + if (res->start < inner.mem_start) + inner.mem_start = res->start; + if (res->end > inner.mem_end) + inner.mem_end = res->end; + } + } + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + inner.found_vga = 1; + } + + /* And for all of the sub-busses. */ + for (child = bus->children; child; child = child->next) + pbus_set_ranges(child, &inner); + + /* Align the values. */ + inner.io_start &= ~(4*1024 - 1); + inner.mem_start &= ~(1*1024*1024 - 1); + if (inner.io_end & (4*1024-1)) + inner.io_end = (inner.io_end | (4*1024 - 1)) + 1; + if (inner.mem_end & (1*1024*1024-1)) + inner.mem_end = (inner.mem_end | (1*1024*1024 - 1)) + 1; + + /* Configure the bridge, if possible. */ + if (bus->self) { + struct pci_dev *bridge = bus->self; + u32 l; + + /* Set up the top and bottom of the PCI I/O segment + for this bus. */ + pci_read_config_dword(bridge, PCI_IO_BASE, &l); + l &= 0xffff0000; + l |= (inner.io_start >> 8) & 0x00f0; + l |= (inner.io_end - 1) & 0xf000; + pci_write_config_dword(bridge, PCI_IO_BASE, l); + + /* + * Clear out the upper 16 bits of IO base/limit. + * Clear out the upper 32 bits of PREF base/limit. + */ + pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0); + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); + + /* Set up the top and bottom of the PCI Memory segment + for this bus. */ + l = (inner.mem_start & 0xfff00000) >> 16; + l |= (inner.mem_end - 1) & 0xfff00000; + pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); + + /* + * Turn off downstream PF memory address range, unless + * there is a VGA behind this bridge, in which case, we + * enable the PREFETCH range to include BIOS ROM at C0000. + * + * NOTE: this is a bit of a hack, done with PREFETCH for + * simplicity, rather than having to add it into the above + * non-PREFETCH range, which could then be bigger than we want. + * We might assume that we could relocate the BIOS ROM, but + * that would depend on having it found by those who need it + * (the DEC BIOS emulator would find it, but I do not know + * about the Xservers). So, we do it this way for now... ;-) + */ + l = (inner.found_vga) ? 0 : 0x0000ffff; + pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); + + /* + * Tell bridge that there is an ISA bus in the system, + * and (possibly) a VGA as well. + */ + l = (inner.found_vga) ? 0x0c : 0x04; + pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l); + + /* + * Clear status bits, + * turn on I/O enable (for downstream I/O), + * turn on memory enable (for downstream memory), + * turn on master enable (for upstream memory and I/O). + */ + pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007); + } + + if (outer) { + outer->found_vga |= inner.found_vga; + if (inner.io_start < outer->io_start) + outer->io_start = inner.io_start; + if (inner.io_end > outer->io_end) + outer->io_end = inner.io_end; + if (inner.mem_start < outer->mem_start) + outer->mem_start = inner.mem_start; + if (inner.mem_end > outer->mem_end) + outer->mem_end = inner.mem_end; + } +} + +void __init +pci_set_bus_ranges(void) +{ + struct pci_bus *bus; + + for (bus = pci_root; bus; bus = bus->next) + pbus_set_ranges(bus, NULL); +} + +static void inline +pdev_fixup_irq(struct pci_dev *dev, + u8 (*swizzle)(struct pci_dev *, u8 *), + int (*map_irq)(struct pci_dev *, u8, u8)) +{ + u8 pin, slot; + int irq; + + /* If 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. */ + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + /* Cope with 0 and illegal. */ + if (pin == 0 || pin > 4) + pin = 1; + + /* Follow the chain of bridges, swizzling as we go. */ + slot = (*swizzle)(dev, &pin); + + irq = (*map_irq)(dev, slot, pin); + if (irq == -1) + irq = 0; + dev->irq = irq; + + DBGC(("PCI fixup irq : (%s) got %d\n", dev->name, dev->irq)); + + /* Always tell the device, so the driver knows what is + the real IRQ to use; the device does not use it. */ + pcibios_irq_update(dev, irq); +} + +void __init +pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *), + int (*map_irq)(struct pci_dev *, u8, u8)) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) + pdev_fixup_irq(dev, swizzle, map_irq); +} diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/pci_syscall.c linux/arch/alpha/kernel/pci_syscall.c --- v2.3.15/linux/arch/alpha/kernel/pci_syscall.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/pci_syscall.c Tue Aug 31 10:50:44 1999 @@ -0,0 +1,148 @@ +/* + * pci_syscall.c + */ + +#include +#include +#include +#include +#include + + +#ifndef CONFIG_PCI + +asmlinkage int sys_pciconfig_read() { return -ENOSYS; } +asmlinkage int sys_pciconfig_write() { return -ENOSYS; } + +#else + +asmlinkage long +sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, void *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + long err, cfg_ret; + + err = -EPERM; + if (!capable(CAP_SYS_ADMIN)) + goto error; + + err = -ENODEV; + dev = pci_find_slot(bus, dfn); + if (!dev) + goto error; + + lock_kernel(); + switch (len) { + case 1: + cfg_ret = pci_read_config_byte(dev, off, &byte); + break; + case 2: + cfg_ret = pci_read_config_word(dev, off, &word); + break; + case 4: + cfg_ret = pci_read_config_dword(dev, off, &dword); + break; + default: + err = -EINVAL; + unlock_kernel(); + goto error; + }; + unlock_kernel(); + + err = -EIO; + if (cfg_ret != PCIBIOS_SUCCESSFUL) + goto error; + + switch (len) { + case 1: + err = put_user(byte, (unsigned char *)buf); + break; + case 2: + err = put_user(word, (unsigned short *)buf); + break; + case 4: + err = put_user(dword, (unsigned int *)buf); + break; + }; + return err; + +error: + /* ??? XFree86 doesn't even check the return value. They + just look for 0xffffffff in the output, since that's what + they get instead of a machine check on x86. */ + switch (len) { + case 1: + put_user(-1, (unsigned char *)buf); + break; + case 2: + put_user(-1, (unsigned short *)buf); + break; + case 4: + put_user(-1, (unsigned int *)buf); + break; + }; + return err; +} + +asmlinkage long +sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, void *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + int err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + dev = pci_find_slot(bus, dfn); + if (!dev) + return -ENODEV; + + lock_kernel(); + switch(len) { + case 1: + err = get_user(byte, (u8 *)buf); + if (err) + break; + err = pci_write_config_byte(dev, off, byte); + if (err != PCIBIOS_SUCCESSFUL) + err = -EIO; + break; + + case 2: + err = get_user(word, (u16 *)buf); + if (err) + break; + err = pci_write_config_byte(dev, off, word); + if (err != PCIBIOS_SUCCESSFUL) + err = -EIO; + break; + + case 4: + err = get_user(dword, (u32 *)buf); + if (err) + break; + pci_write_config_byte(dev, off, dword); + if (err != PCIBIOS_SUCCESSFUL) + err = -EIO; + break; + + default: + err = -EINVAL; + break; + }; + unlock_kernel(); + + return err; +} + +#endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.3.15/linux/arch/alpha/kernel/process.c Tue Aug 3 08:20:45 1999 +++ linux/arch/alpha/kernel/process.c Tue Aug 31 10:50:44 1999 @@ -43,7 +43,7 @@ #include #include "proto.h" -#include "bios32.h" +#include "pci_impl.h" /* * Initial task structure. Make this a per-architecture thing, @@ -95,7 +95,7 @@ } void -generic_kill_arch (int mode, char *restart_cmd) +common_kill_arch (int mode, char *restart_cmd) { /* The following currently only has any effect on SRM. We should fix MILO to understand it. Should be pretty easy. Also we can @@ -130,7 +130,7 @@ cpup->flags = flags; mb(); - reset_for_srm(); + /* reset_for_srm(); */ set_hae(srm_hae); #ifdef CONFIG_DUMMY_CONSOLE diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.3.15/linux/arch/alpha/kernel/proto.h Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/proto.h Tue Aug 31 10:50:44 1999 @@ -6,141 +6,48 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -struct linux_hose_info; +struct pt_regs; +struct task_struct; +struct pci_dev; /* core_apecs.c */ -extern int apecs_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int apecs_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int apecs_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int apecs_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int apecs_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int apecs_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); +extern struct pci_ops apecs_pci_ops; extern void apecs_init_arch(unsigned long *, unsigned long *); - -extern volatile unsigned int apecs_mcheck_expected; -extern volatile unsigned int apecs_mcheck_taken; extern void apecs_pci_clr_err(void); extern void apecs_machine_check(u64, u64, struct pt_regs *); /* core_cia.c */ -extern int cia_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int cia_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int cia_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int cia_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int cia_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int cia_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); +extern struct pci_ops cia_pci_ops; extern void cia_init_arch(unsigned long *, unsigned long *); extern void cia_machine_check(u64, u64, struct pt_regs *); /* core_lca.c */ -extern int lca_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int lca_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int lca_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int lca_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int lca_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int lca_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); +extern struct pci_ops lca_pci_ops; extern void lca_init_arch(unsigned long *, unsigned long *); extern void lca_machine_check(u64, u64, struct pt_regs *); /* core_mcpcia.c */ -extern int mcpcia_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int mcpcia_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int mcpcia_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int mcpcia_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int mcpcia_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int mcpcia_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); +extern struct pci_ops mcpcia_pci_ops; extern void mcpcia_init_arch(unsigned long *, unsigned long *); extern void mcpcia_machine_check(u64, u64, struct pt_regs *); /* core_polaris.c */ -extern int polaris_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int polaris_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int polaris_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int polaris_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int polaris_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int polaris_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); +extern struct pci_ops polaris_pci_ops; extern void polaris_init_arch(unsigned long *, unsigned long *); extern void polaris_machine_check(u64, u64, struct pt_regs *); /* core_pyxis.c */ -extern int pyxis_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int pyxis_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int pyxis_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int pyxis_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int pyxis_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int pyxis_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); -extern void pyxis_enable_errors (void); -extern int pyxis_srm_window_setup (void); -extern void pyxis_native_window_setup(void); -extern void pyxis_finish_init_arch(void); +extern struct pci_ops pyxis_pci_ops; extern void pyxis_init_arch(unsigned long *, unsigned long *); extern void pyxis_machine_check(u64, u64, struct pt_regs *); /* core_t2.c */ -extern int t2_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int t2_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int t2_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int t2_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int t2_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int t2_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); +extern struct pci_ops t2_pci_ops; extern void t2_init_arch(unsigned long *, unsigned long *); extern void t2_machine_check(u64, u64, struct pt_regs *); /* core_tsunami.c */ -extern int tsunami_hose_read_config_byte (u8, u8, u8, u8 *value, - struct linux_hose_info *hose); -extern int tsunami_hose_read_config_word (u8, u8, u8, u16 *value, - struct linux_hose_info *hose); -extern int tsunami_hose_read_config_dword (u8, u8, u8, u32 *value, - struct linux_hose_info *hose); -extern int tsunami_hose_write_config_byte (u8, u8, u8, u8 value, - struct linux_hose_info *hose); -extern int tsunami_hose_write_config_word (u8, u8, u8, u16 value, - struct linux_hose_info *hose); -extern int tsunami_hose_write_config_dword (u8, u8, u8, u32 value, - struct linux_hose_info *hose); +extern struct pci_ops tsunami_pci_ops; extern void tsunami_init_arch(unsigned long *, unsigned long *); extern void tsunami_machine_check(u64, u64, struct pt_regs *); @@ -155,14 +62,13 @@ extern int smp_boot_cpuid; /* bios32.c */ -extern void reset_for_srm(void); +/* extern void reset_for_srm(void); */ /* time.c */ extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs); extern void rtc_init_pit(void); -extern void generic_init_pit(void); +extern void common_init_pit(void); extern unsigned long est_cycle_freq; -extern struct resource timer_resource; /* smc37c93x.c */ extern void SMC93x_Init(void); @@ -173,6 +79,9 @@ /* es1888.c */ extern void es1888_init(void); +/* ns87312.c */ +extern void ns87312_enable_ide(long ide_base); + /* fpregs.c */ extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); extern unsigned long alpha_read_fp_reg (unsigned long reg); @@ -193,13 +102,17 @@ extern void entDbg(void); /* process.c */ -extern void generic_kill_arch (int mode, char *reboot_cmd); +extern void common_kill_arch (int mode, char *reboot_cmd); extern void cpu_idle(void) __attribute__((noreturn)); /* ptrace.c */ extern int ptrace_set_bpt (struct task_struct *child); extern int ptrace_cancel_bpt (struct task_struct *child); +/* traps.c */ +extern void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15); +extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *); + /* ../mm/init.c */ void srm_paging_stop(void); @@ -208,18 +121,18 @@ #ifdef __SMP__ #define mcheck_expected(cpu) (cpu_data[cpu].mcheck_expected) #define mcheck_taken(cpu) (cpu_data[cpu].mcheck_taken) -#define mcheck_hose(cpu) (cpu_data[cpu].mcheck_hose) +#define mcheck_extra(cpu) (cpu_data[cpu].mcheck_extra) #else extern struct mcheck_info { unsigned char expected __attribute__((aligned(8))); unsigned char taken; - unsigned char hose; + unsigned char extra; } __mcheck_info; #define mcheck_expected(cpu) (__mcheck_info.expected) #define mcheck_taken(cpu) (__mcheck_info.taken) -#define mcheck_hose(cpu) (__mcheck_info.hose) +#define mcheck_extra(cpu) (__mcheck_info.extra) #endif #define DEBUG_MCHECK 0 /* 0 = minimal, 1 = debug, 2 = debug+dump. */ diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.3.15/linux/arch/alpha/kernel/setup.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/setup.c Tue Aug 31 10:50:44 1999 @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef CONFIG_RTC #include @@ -39,16 +40,18 @@ #include #include #include - +#include #include "proto.h" +#include "pci_impl.h" + struct hwrpb_struct *hwrpb; unsigned long srm_hae; #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; -int alpha_using_srm, alpha_use_srm_setup; +int alpha_using_srm; #endif unsigned char aux_device_present = 0xaa; @@ -90,6 +93,7 @@ orig_video_points: 16 }; + /* * Declare all of the machine vectors. */ @@ -136,6 +140,47 @@ #undef WEAK +/* + * I/O resources inherited from PeeCees. Except for perhaps the + * turbochannel alphas, everyone has these on some sort of SuperIO chip. + * + * ??? If this becomes less standard, move the struct out into the + * machine vector. + */ + +static void __init +reserve_std_resources(void) +{ + static struct resource standard_io_resources[] = { + { "rtc", -1, -1 }, + { "dma1", 0x00, 0x1f }, + { "pic1", 0x20, 0x3f }, + { "timer", 0x40, 0x5f }, + { "keyboard", 0x60, 0x6f }, + { "dma page reg", 0x80, 0x8f }, + { "pic2", 0xa0, 0xbf }, + { "dma2", 0xc0, 0xdf }, + }; + + struct resource *io = &ioport_resource; + long i; + + if (hose_head) { + struct pci_controler *hose; + for (hose = hose_head; hose; hose = hose->next) + if (hose->index == 0) { + io = hose->io_space; + break; + } + } + + /* Fix up for the Jensen's queer RTC placement. */ + standard_io_resources[0].start = RTC_PORT(0); + standard_io_resources[0].end = RTC_PORT(0) + 0x10; + + for (i = 0; i < N(standard_io_resources); ++i) + request_resource(io, standard_io_resources+i); +} void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, @@ -171,20 +216,10 @@ */ for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) { -#ifndef alpha_use_srm_setup - /* Allow a command-line option to respect the - SRM's configuration. */ - if (strncmp(p, "srm_setup=", 10) == 0) { - alpha_use_srm_setup = (p[10] != '0'); - continue; - } -#endif - if (strncmp(p, "alpha_mv=", 9) == 0) { vec = get_sysvec_byname(p+9); continue; } - if (strncmp(p, "cycle=", 6) == 0) { est_cycle_freq = simple_strtol(p+6, NULL, 0); continue; @@ -270,6 +305,9 @@ DMA windows and the like. */ if (alpha_mv.init_arch) alpha_mv.init_arch(memory_start_p, memory_end_p); + + /* Reserve standard resources. */ + reserve_std_resources(); /* Initialize the timers. */ /* ??? There is some circumstantial evidence that this needs diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.3.15/linux/arch/alpha/kernel/smp.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/smp.c Tue Aug 31 10:50:44 1999 @@ -30,7 +30,7 @@ #include #include "proto.h" -#include "irq.h" +#include "irq_impl.h" #define DEBUG_SMP 0 diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_alcor.c linux/arch/alpha/kernel/sys_alcor.c --- v2.3.15/linux/arch/alpha/kernel/sys_alcor.c Sun Sep 6 10:34:33 1998 +++ linux/arch/alpha/kernel/sys_alcor.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the ALCOR and XLT (XL-300/366/433). */ @@ -27,9 +27,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -158,7 +158,7 @@ */ static int __init -alcor_map_irq(struct pci_dev *dev, int slot, int pin) +alcor_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[7][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -175,16 +175,8 @@ return COMMON_TABLE_LOOKUP; } -static void __init -alcor_pci_fixup(void) -{ - layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(alcor_map_irq, common_swizzle); -} - - static void -alcor_kill_arch (int mode, char *reboot_cmd) +alcor_kill_arch(int mode, char *reboot_cmd) { /* Who said DEC engineer's have no sense of humor? ;-) */ if (alpha_using_srm) { @@ -192,7 +184,7 @@ mb(); } - generic_kill_arch(mode, reboot_cmd); + common_kill_arch(mode, reboot_cmd); } @@ -209,6 +201,8 @@ DO_CIA_BUS, machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: EISA_DEFAULT_IO_BASE, + min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 48, irq_probe_mask: ALCOR_PROBE_MASK, @@ -218,9 +212,11 @@ init_arch: cia_init_arch, init_irq: alcor_init_irq, - init_pit: generic_init_pit, - pci_fixup: alcor_pci_fixup, + init_pit: common_init_pit, + init_pci: common_init_pci, kill_arch: alcor_kill_arch, + pci_map_irq: alcor_map_irq, + pci_swizzle: common_swizzle, sys: { cia: { gru_int_req_bits: ALCOR_GRU_INT_REQ_BITS @@ -238,6 +234,8 @@ DO_CIA_BUS, machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: EISA_DEFAULT_IO_BASE, + min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 48, irq_probe_mask: ALCOR_PROBE_MASK, @@ -247,9 +245,11 @@ init_arch: cia_init_arch, init_irq: alcor_init_irq, - init_pit: generic_init_pit, - pci_fixup: alcor_pci_fixup, + init_pit: common_init_pit, + init_pci: common_init_pci, kill_arch: alcor_kill_arch, + pci_map_irq: alcor_map_irq, + pci_swizzle: common_swizzle, sys: { cia: { gru_int_req_bits: XLT_GRU_INT_REQ_BITS diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_cabriolet.c linux/arch/alpha/kernel/sys_cabriolet.c --- v2.3.15/linux/arch/alpha/kernel/sys_cabriolet.c Sun Sep 6 10:34:33 1998 +++ linux/arch/alpha/kernel/sys_cabriolet.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164, * PC164 and LX164. @@ -31,9 +31,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -124,7 +124,7 @@ */ static inline int __init -eb66p_map_irq(struct pci_dev *dev, int slot, int pin) +eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[5][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -138,14 +138,6 @@ return COMMON_TABLE_LOOKUP; } -static inline void __init -eb66p_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - common_pci_fixup(eb66p_map_irq, common_swizzle); - enable_ide(0x398); -} - /* * The AlphaPC64 is very similar to the EB66+ except that its slots @@ -162,7 +154,7 @@ */ static inline int __init -cabriolet_map_irq(struct pci_dev *dev, int slot, int pin) +cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[5][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -177,19 +169,10 @@ } static inline void __init -cabriolet_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - common_pci_fixup(cabriolet_map_irq, common_swizzle); - enable_ide(0x398); -} - -static inline void __init -eb164_pci_fixup(void) +cabriolet_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(cabriolet_map_irq, common_swizzle); - enable_ide(0x398); + common_init_pci(); + ns87312_enable_ide(0x398); } @@ -236,7 +219,7 @@ */ static inline int __init -alphapc164_map_irq(struct pci_dev *dev, int slot, int pin) +alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[7][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -253,13 +236,13 @@ } static inline void __init -alphapc164_pci_fixup(void) +alphapc164_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(alphapc164_map_irq, common_swizzle); + common_init_pci(); SMC93x_Init(); } + /* * The System Vector */ @@ -273,18 +256,22 @@ DO_APECS_BUS, machine_check: apecs_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 35, irq_probe_mask: _PROBE_MASK(35), update_irq_hw: cabriolet_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: apecs_init_arch, init_irq: cabriolet_init_irq, - init_pit: generic_init_pit, - pci_fixup: cabriolet_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: cabriolet_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: cabriolet_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(cabriolet) #endif @@ -298,18 +285,22 @@ DO_CIA_BUS, machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 35, irq_probe_mask: _PROBE_MASK(35), update_irq_hw: cabriolet_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: cia_init_arch, init_irq: cabriolet_init_irq, - init_pit: generic_init_pit, - pci_fixup: eb164_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: cabriolet_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: cabriolet_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(eb164) #endif @@ -323,18 +314,22 @@ DO_LCA_BUS, machine_check: lca_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 35, irq_probe_mask: _PROBE_MASK(35), update_irq_hw: cabriolet_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: lca_init_arch, init_irq: cabriolet_init_irq, - init_pit: generic_init_pit, - pci_fixup: eb66p_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: cabriolet_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: eb66p_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(eb66p) #endif @@ -348,18 +343,22 @@ DO_PYXIS_BUS, machine_check: pyxis_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 35, irq_probe_mask: _PROBE_MASK(35), update_irq_hw: cabriolet_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: pyxis_init_arch, init_irq: cabriolet_init_irq, - init_pit: generic_init_pit, - pci_fixup: alphapc164_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: alphapc164_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: alphapc164_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(lx164) #endif @@ -373,19 +372,22 @@ DO_CIA_BUS, machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 35, irq_probe_mask: _PROBE_MASK(35), update_irq_hw: cabriolet_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: cia_init_arch, init_irq: cabriolet_init_irq, - init_pit: generic_init_pit, - pci_fixup: alphapc164_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: alphapc164_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: alphapc164_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(pc164) #endif - diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- v2.3.15/linux/arch/alpha/kernel/sys_dp264.c Mon Jul 12 07:49:36 1999 +++ linux/arch/alpha/kernel/sys_dp264.c Tue Aug 31 10:50:44 1999 @@ -28,11 +28,10 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" -#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index) /* * HACK ALERT! only the boot cpu is used for interrupts. @@ -260,7 +259,7 @@ */ static int __init -dp264_map_irq(struct pci_dev *dev, int slot, int pin) +dp264_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[6][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -272,16 +271,18 @@ { 16+ 3, 16+ 3, 16+ 2, 16+ 1, 16+ 0} /* IdSel 10 slot 3 */ }; const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5; + + struct pci_controler *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq > 0) - irq += 16 * dev2hose(dev); + irq += 16 * hose->index; return irq; } static int __init -monet_map_irq(struct pci_dev *dev, int slot, int pin) +monet_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[13][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -308,19 +309,23 @@ return COMMON_TABLE_LOOKUP; } -static int __init -monet_swizzle(struct pci_dev *dev, int *pinp) +static u8 __init +monet_swizzle(struct pci_dev *dev, u8 *pinp) { + struct pci_controler *hose = dev->sysdata; int slot, pin = *pinp; - /* Check first for the built-in bridge on hose 1. */ - if (dev2hose(dev) == 1 && PCI_SLOT(dev->bus->self->devfn) == 8) { + if (hose->first_busno == dev->bus->number) { + slot = PCI_SLOT(dev->devfn); + } + /* Check for the built-in bridge on hose 1. */ + else if (hose->index == 1 && PCI_SLOT(dev->bus->self->devfn) == 8) { slot = PCI_SLOT(dev->devfn); } else { /* Must be a card-based bridge. */ do { /* Check for built-in bridge on hose 1. */ - if (dev2hose(dev) == 1 && + if (hose->index == 1 && PCI_SLOT(dev->bus->self->devfn) == 8) { slot = PCI_SLOT(dev->devfn); break; @@ -338,7 +343,7 @@ } static int __init -webbrick_map_irq(struct pci_dev *dev, int slot, int pin) +webbrick_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[13][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -359,7 +364,7 @@ } static int __init -clipper_map_irq(struct pci_dev *dev, int slot, int pin) +clipper_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[7][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -372,46 +377,31 @@ { -1, -1, -1, -1, -1} /* IdSel 7 ISA Bridge */ }; const long min_idsel = 1, max_idsel = 7, irqs_per_slot = 5; + + struct pci_controler *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq > 0) - irq += 16 * dev2hose(dev); + irq += 16 * hose->index; return irq; } static void __init -dp264_pci_fixup(void) +dp264_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(dp264_map_irq, common_swizzle); + common_init_pci(); SMC669_Init(0); } static void __init -monet_pci_fixup(void) +monet_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(monet_map_irq, monet_swizzle); + common_init_pci(); SMC669_Init(1); es1888_init(); } -static void __init -webbrick_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(webbrick_map_irq, common_swizzle); - SMC669_Init(0); -} - -static void __init -clipper_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(clipper_map_irq, common_swizzle); -} - /* * The System Vectors @@ -425,18 +415,22 @@ DO_TSUNAMI_BUS, machine_check: tsunami_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, irq_probe_mask: _PROBE_MASK(64), update_irq_hw: dp264_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: dp264_init_irq, - init_pit: generic_init_pit, - pci_fixup: dp264_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: dp264_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: dp264_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(dp264) @@ -448,18 +442,22 @@ DO_TSUNAMI_BUS, machine_check: tsunami_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, irq_probe_mask: _PROBE_MASK(64), update_irq_hw: dp264_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: dp264_init_irq, - init_pit: generic_init_pit, - pci_fixup: monet_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: monet_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: monet_map_irq, + pci_swizzle: monet_swizzle, }; struct alpha_machine_vector webbrick_mv __initmv = { @@ -470,18 +468,22 @@ DO_TSUNAMI_BUS, machine_check: tsunami_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, irq_probe_mask: _PROBE_MASK(64), update_irq_hw: dp264_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: dp264_init_irq, - init_pit: generic_init_pit, - pci_fixup: webbrick_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: dp264_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: webbrick_map_irq, + pci_swizzle: common_swizzle, }; struct alpha_machine_vector clipper_mv __initmv = { @@ -492,18 +494,22 @@ DO_TSUNAMI_BUS, machine_check: tsunami_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, irq_probe_mask: _PROBE_MASK(64), update_irq_hw: clipper_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: clipper_init_irq, - init_pit: generic_init_pit, - pci_fixup: clipper_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: clipper_map_irq, + pci_swizzle: common_swizzle, }; /* No alpha_mv alias for webbrick/monet/clipper, since we compile them diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_eb64p.c linux/arch/alpha/kernel/sys_eb64p.c --- v2.3.15/linux/arch/alpha/kernel/sys_eb64p.c Sun Sep 6 10:34:33 1998 +++ linux/arch/alpha/kernel/sys_eb64p.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the EB64+ and EB66. */ @@ -28,9 +28,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -142,7 +142,7 @@ */ static int __init -eb64p_map_irq(struct pci_dev *dev, int slot, int pin) +eb64p_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[5][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -156,13 +156,6 @@ return COMMON_TABLE_LOOKUP; } -static void __init -eb64p_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - common_pci_fixup(eb64p_map_irq, common_swizzle); -} - /* * The System Vector @@ -177,18 +170,22 @@ DO_APECS_BUS, machine_check: apecs_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 32, irq_probe_mask: _PROBE_MASK(32), update_irq_hw: eb64p_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: eb64p_device_interrupt, init_arch: apecs_init_arch, init_irq: eb64p_init_irq, - init_pit: generic_init_pit, - pci_fixup: eb64p_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: eb64p_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(eb64p) #endif @@ -202,18 +199,22 @@ DO_LCA_BUS, machine_check: lca_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 32, irq_probe_mask: _PROBE_MASK(32), update_irq_hw: eb64p_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: eb64p_device_interrupt, init_arch: lca_init_arch, init_irq: eb64p_init_irq, - init_pit: generic_init_pit, - pci_fixup: eb64p_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: eb64p_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(eb66) #endif diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c --- v2.3.15/linux/arch/alpha/kernel/sys_jensen.c Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/kernel/sys_jensen.c Tue Aug 31 10:50:44 1999 @@ -2,7 +2,7 @@ * linux/arch/alpha/kernel/sys_jensen.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the Jensen. */ @@ -28,8 +28,8 @@ #include #include "proto.h" -#include "irq.h" -#include "machvec.h" +#include "irq_impl.h" +#include "machvec_impl.h" static void @@ -124,7 +124,7 @@ struct alpha_machine_vector jensen_mv __initmv = { vector_name: "Jensen", DO_EV4_MMU, - IO_LITE(JENSEN,jensen,jensen), + IO_LITE(JENSEN,jensen), BUS(jensen), machine_check: jensen_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, @@ -133,12 +133,13 @@ nr_irqs: 16, irq_probe_mask: _PROBE_MASK(16), update_irq_hw: jensen_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: jensen_device_interrupt, init_arch: NULL, init_irq: jensen_init_irq, - init_pit: generic_init_pit, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: NULL, + kill_arch: common_kill_arch, }; ALIAS_MV(jensen) diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c --- v2.3.15/linux/arch/alpha/kernel/sys_miata.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/sys_miata.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the MIATA (EV56+PYXIS). */ @@ -25,9 +25,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -202,7 +202,7 @@ */ static int __init -miata_map_irq(struct pci_dev *dev, int slot, int pin) +miata_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[18][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -224,21 +224,24 @@ {16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 28, slot 1 */ {16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 29, slot 2 */ {16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 30, slot 3 */ - /* this bridge is on the main bus of the later original MIATA */ + /* This bridge is on the main bus of the later orig MIATA */ { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI */ }; const long min_idsel = 3, max_idsel = 20, irqs_per_slot = 5; return COMMON_TABLE_LOOKUP; } -static int __init -miata_swizzle(struct pci_dev *dev, int *pinp) +static u8 __init +miata_swizzle(struct pci_dev *dev, u8 *pinp) { int slot, pin = *pinp; - /* Check first for the built-in bridge. */ - if ((PCI_SLOT(dev->bus->self->devfn) == 8) || - (PCI_SLOT(dev->bus->self->devfn) == 20)) { + if (dev->bus->number == 0) { + slot = PCI_SLOT(dev->devfn); + } + /* Check for the built-in bridge. */ + else if ((PCI_SLOT(dev->bus->self->devfn) == 8) || + (PCI_SLOT(dev->bus->self->devfn) == 20)) { slot = PCI_SLOT(dev->devfn) + 9; } else @@ -263,10 +266,9 @@ } static void __init -miata_pci_fixup(void) +miata_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(miata_map_irq, miata_swizzle); + common_init_pci(); SMC669_Init(0); /* it might be a GL (fails harmlessly if not) */ es1888_init(); } @@ -279,7 +281,7 @@ *(vuip) PYXIS_RESET = 0x0000dead; mb(); } - generic_kill_arch(mode, reboot_cmd); + common_kill_arch(mode, reboot_cmd); } @@ -295,17 +297,21 @@ DO_PYXIS_BUS, machine_check: pyxis_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 48, irq_probe_mask: _PROBE_MASK(48), update_irq_hw: miata_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: miata_device_interrupt, init_arch: pyxis_init_arch, init_irq: miata_init_irq, - init_pit: generic_init_pit, - pci_fixup: miata_pci_fixup, + init_pit: common_init_pit, + init_pci: miata_init_pci, kill_arch: miata_kill_arch, + pci_map_irq: miata_map_irq, + pci_swizzle: miata_swizzle, }; ALIAS_MV(miata) diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_mikasa.c linux/arch/alpha/kernel/sys_mikasa.c --- v2.3.15/linux/arch/alpha/kernel/sys_mikasa.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/sys_mikasa.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the MIKASA (AlphaServer 1000). */ @@ -28,9 +28,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void mikasa_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) @@ -120,7 +120,7 @@ */ static int __init -mikasa_map_irq(struct pci_dev *dev, int slot, int pin) +mikasa_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[8][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -137,19 +137,6 @@ return COMMON_TABLE_LOOKUP; } -static void __init -mikasa_pci_fixup(void) -{ - layout_all_busses(EISA_DEFAULT_IO_BASE,APECS_AND_LCA_DEFAULT_MEM_BASE); - common_pci_fixup(mikasa_map_irq, common_swizzle); -} - -static void __init -mikasa_primo_pci_fixup(void) -{ - layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(mikasa_map_irq, common_swizzle); -} #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) static void @@ -180,6 +167,7 @@ } #endif + /* * The System Vector */ @@ -193,18 +181,22 @@ DO_APECS_BUS, machine_check: mikasa_apecs_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 32, irq_probe_mask: _PROBE_MASK(32), update_irq_hw: mikasa_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: mikasa_device_interrupt, init_arch: apecs_init_arch, init_irq: mikasa_init_irq, - init_pit: generic_init_pit, - pci_fixup: mikasa_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: mikasa_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(mikasa) #endif @@ -218,18 +210,22 @@ DO_CIA_BUS, machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 32, irq_probe_mask: _PROBE_MASK(32), update_irq_hw: mikasa_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: mikasa_device_interrupt, init_arch: cia_init_arch, init_irq: mikasa_init_irq, - init_pit: generic_init_pit, - pci_fixup: mikasa_primo_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: mikasa_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(mikasa_primo) #endif diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_noritake.c linux/arch/alpha/kernel/sys_noritake.c --- v2.3.15/linux/arch/alpha/kernel/sys_noritake.c Sun Sep 6 10:34:33 1998 +++ linux/arch/alpha/kernel/sys_noritake.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the NORITAKE (AlphaServer 1000A), * CORELLE (AlphaServer 800), and ALCOR Primo (AlphaStation 600A). @@ -29,9 +29,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -168,7 +168,7 @@ */ static int __init -noritake_map_irq(struct pci_dev *dev, int slot, int pin) +noritake_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[15][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -195,13 +195,16 @@ return COMMON_TABLE_LOOKUP; } -static int __init -noritake_swizzle(struct pci_dev *dev, int *pinp) +static u8 __init +noritake_swizzle(struct pci_dev *dev, u8 *pinp) { int slot, pin = *pinp; - /* Check first for the built-in bridge */ - if (PCI_SLOT(dev->bus->self->devfn) == 8) { + if (dev->bus->number == 0) { + slot = PCI_SLOT(dev->devfn); + } + /* Check for the built-in bridge */ + else if (PCI_SLOT(dev->bus->self->devfn) == 8) { slot = PCI_SLOT(dev->devfn) + 15; /* WAG! */ } else @@ -224,20 +227,6 @@ return slot; } -static void __init -noritake_pci_fixup(void) -{ - layout_all_busses(EISA_DEFAULT_IO_BASE,APECS_AND_LCA_DEFAULT_MEM_BASE); - common_pci_fixup(noritake_map_irq, noritake_swizzle); -} - -static void __init -noritake_primo_pci_fixup(void) -{ - layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(noritake_map_irq, noritake_swizzle); -} - /* * The System Vectors @@ -252,18 +241,22 @@ DO_APECS_BUS, machine_check: apecs_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: EISA_DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 48, irq_probe_mask: _PROBE_MASK(48), update_irq_hw: noritake_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: noritake_device_interrupt, init_arch: apecs_init_arch, init_irq: noritake_init_irq, - init_pit: generic_init_pit, - pci_fixup: noritake_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: noritake_map_irq, + pci_swizzle: noritake_swizzle, }; ALIAS_MV(noritake) #endif @@ -277,18 +270,22 @@ DO_CIA_BUS, machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: EISA_DEFAULT_IO_BASE, + min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 48, irq_probe_mask: _PROBE_MASK(48), update_irq_hw: noritake_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: noritake_device_interrupt, init_arch: cia_init_arch, init_irq: noritake_init_irq, - init_pit: generic_init_pit, - pci_fixup: noritake_primo_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: noritake_map_irq, + pci_swizzle: noritake_swizzle, }; ALIAS_MV(noritake_primo) #endif diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c --- v2.3.15/linux/arch/alpha/kernel/sys_rawhide.c Sun Jan 10 09:59:59 1999 +++ linux/arch/alpha/kernel/sys_rawhide.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the RAWHIDE. */ @@ -24,11 +24,12 @@ #include #include #include +#include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -36,19 +37,19 @@ { if (irq >= 40) { /* PCI bus 1 with builtin NCR810 SCSI */ - *(vuip)MCPCIA_INT_MASK0(1) = + *(vuip)MCPCIA_INT_MASK0(5) = (~((mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb(); /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(1); + *(vuip)MCPCIA_INT_MASK0(5); } else if (irq >= 16) { /* PCI bus 0 with EISA bridge */ - *(vuip)MCPCIA_INT_MASK0(0) = + *(vuip)MCPCIA_INT_MASK0(4) = (~((mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb(); /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(0); + *(vuip)MCPCIA_INT_MASK0(4); } else if (irq >= 8) outb(mask >> 8, 0xA1); /* ISA PIC2 */ @@ -63,6 +64,10 @@ ack = irq = (vector - 0x800) >> 4; + /* ??? A 4 bus RAWHIDE has 67 interrupts. Oops. We need + something wider than one word for our own internal + manipulations. */ + /* * The RAWHIDE SRM console reports PCI interrupts with a vector * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) @@ -90,17 +95,17 @@ STANDARD_INIT_IRQ_PROLOG; /* HACK ALERT! only PCI busses 0 and 1 are used currently, - and routing is only to CPU #1*/ + (MIDs 4 and 5 respectively) and routing is only to CPU #1*/ - *(vuip)MCPCIA_INT_MASK0(0) = + *(vuip)MCPCIA_INT_MASK0(4) = (~((alpha_irq_mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb(); /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(0); + *(vuip)MCPCIA_INT_MASK0(4); - *(vuip)MCPCIA_INT_MASK0(1) = + *(vuip)MCPCIA_INT_MASK0(5) = (~((alpha_irq_mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb(); /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(1); + *(vuip)MCPCIA_INT_MASK0(5); enable_irq(2); } @@ -139,7 +144,7 @@ */ static int __init -rawhide_map_irq(struct pci_dev *dev, int slot, int pin) +rawhide_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[5][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -150,19 +155,14 @@ { 16+12, 16+12, 16+13, 16+14, 16+15} /* IdSel 5 slot 5 */ }; const long min_idsel = 1, max_idsel = 5, irqs_per_slot = 5; + + struct pci_controler *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq >= 0) - irq += 24 * bus2hose[dev->bus->number]->pci_hose_index; + irq += 24 * hose->index; return irq; } -static void __init -rawhide_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, RAWHIDE_DEFAULT_MEM_BASE); - common_pci_fixup(rawhide_map_irq, common_swizzle); -} - /* * The System Vector @@ -176,17 +176,21 @@ DO_MCPCIA_BUS, machine_check: mcpcia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: MCPCIA_DEFAULT_MEM_BASE, nr_irqs: 64, irq_probe_mask: _PROBE_MASK(64), update_irq_hw: rawhide_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: rawhide_srm_device_interrupt, init_arch: mcpcia_init_arch, init_irq: rawhide_init_irq, - init_pit: generic_init_pit, - pci_fixup: rawhide_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: rawhide_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(rawhide) diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c --- v2.3.15/linux/arch/alpha/kernel/sys_ruffian.c Tue Aug 3 08:20:45 1999 +++ linux/arch/alpha/kernel/sys_ruffian.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the RUFFIAN. */ @@ -26,9 +26,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void ruffian_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) @@ -164,18 +164,6 @@ } -/* - * For RUFFIAN, we do not want to make any modifications to the PCI - * setup. But we may need to do some kind of init. - */ - -static void __init -ruffian_pci_fixup(void) -{ - /* layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); */ -} - - #ifdef BUILDING_FOR_MILO /* * The DeskStation Ruffian motherboard firmware does not place @@ -215,31 +203,9 @@ } #endif /* BUILDING_FOR_MILO */ -static void __init -ruffian_init_arch(unsigned long *mem_start, unsigned long *mem_end) -{ - /* FIXME: What do we do with ruffian_get_bank_size above? */ - -#if 1 - pyxis_init_arch(mem_start, mem_end); -#else - pyxis_enable_errors(); - if (!pyxis_srm_window_setup()) { - printk("ruffian_init_arch: Skipping window register rewrites." - "\n... Trust DeskStation firmware!\n"); - } - pyxis_finish_init_arch(); -#endif -} - static void ruffian_init_pit (void) { - /* Ruffian depends on the system timer established in MILO! */ - timer_resource.start = 0x70; - timer_resource.end = 0x70 + 0x10; - request_resource(&ioport_resource, &timer_resource); - outb(0xb6, 0x43); /* pit counter 2: speaker */ outb(0x31, 0x42); outb(0x13, 0x42); @@ -254,7 +220,15 @@ *(vuip) PYXIS_RESET = 0x0000dead; mb(); #endif - generic_kill_arch(mode, reboot_cmd); + common_kill_arch(mode, reboot_cmd); +} + +static int __init +ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + /* We don't know anything about the PCI routing, so leave + the IRQ unchanged. */ + return dev->irq; } @@ -266,11 +240,12 @@ vector_name: "Ruffian", DO_EV5_MMU, DO_DEFAULT_RTC, - /* For the moment, do not use BWIO on RUFFIAN. */ - IO(PYXIS,pyxis,pyxis), + DO_PYXIS_IO, DO_PYXIS_BUS, machine_check: pyxis_machine_check, max_dma_address: ALPHA_RUFFIAN_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 48, irq_probe_mask: RUFFIAN_PROBE_MASK, @@ -278,10 +253,12 @@ ack_irq: ruffian_ack_irq, device_interrupt: ruffian_device_interrupt, - init_arch: ruffian_init_arch, + init_arch: pyxis_init_arch, init_irq: ruffian_init_irq, init_pit: ruffian_init_pit, - pci_fixup: ruffian_pci_fixup, + init_pci: common_init_pci, kill_arch: ruffian_kill_arch, + pci_map_irq: ruffian_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(ruffian) diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_rx164.c linux/arch/alpha/kernel/sys_rx164.c --- v2.3.15/linux/arch/alpha/kernel/sys_rx164.c Fri Aug 13 11:53:50 1999 +++ linux/arch/alpha/kernel/sys_rx164.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the RX164 (PCA56+POLARIS). */ @@ -26,9 +26,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -138,6 +138,8 @@ enable_irq(16 + 20); /* enable ISA interrupts */ enable_irq(2); /* enable cascade */ } + + /* The RX164 changed its interrupt routing between pass1 and pass2... * * PASS1: @@ -171,7 +173,7 @@ */ static int __init -rx164_map_irq(struct pci_dev *dev, int slot, int pin) +rx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { #if 0 char irq_tab_pass1[6][5] = { @@ -183,7 +185,7 @@ { 16+2, 16+2, 16+7, 16+12, 16+17}, /* IdSel 9, slot 3 */ { 16+1, 16+1, 16+6, 16+11, 16+16}, /* IdSel 10, slot 4 */ }; -#endif +#else char irq_tab[6][5] = { /*INT INTA INTB INTC INTD */ { 16+0, 16+0, 16+6, 16+11, 16+16}, /* IdSel 5, slot 0 */ @@ -193,20 +195,14 @@ { 16+3, 16+3, 16+9, 16+14, 16+19}, /* IdSel 9, slot 3 */ { 16+4, 16+4, 16+10, 16+15, 16+5}, /* IdSel 10, PCI-PCI */ }; +#endif const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5; + /* JRP - Need to figure out how to distinguish pass1 from pass2, - * and use the correct table... - */ + and use the correct table. */ return COMMON_TABLE_LOOKUP; } -void __init -rx164_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(rx164_map_irq, common_swizzle); -} - /* * The System Vector @@ -220,17 +216,21 @@ DO_POLARIS_BUS, machine_check: polaris_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 40, irq_probe_mask: _PROBE_MASK(40), update_irq_hw: rx164_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: rx164_device_interrupt, init_arch: polaris_init_arch, init_irq: rx164_init_irq, - init_pit: generic_init_pit, - pci_fixup: rx164_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: rx164_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(rx164) diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_sable.c linux/arch/alpha/kernel/sys_sable.c --- v2.3.15/linux/arch/alpha/kernel/sys_sable.c Sun Sep 6 10:34:33 1998 +++ linux/arch/alpha/kernel/sys_sable.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the Sable and Sable-Gamma systems. */ @@ -26,9 +26,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" /* @@ -198,7 +198,7 @@ */ static int __init -sable_map_irq(struct pci_dev *dev, int slot, int pin) +sable_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[9][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -216,13 +216,6 @@ return COMMON_TABLE_LOOKUP; } -void __init -sable_pci_fixup(void) -{ - layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(sable_map_irq, common_swizzle); -} - /* * The System Vectors @@ -242,6 +235,8 @@ DO_T2_BUS, machine_check: t2_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: EISA_DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 40, irq_probe_mask: _PROBE_MASK(40), @@ -251,9 +246,11 @@ init_arch: t2_init_arch, init_irq: sable_init_irq, - init_pit: generic_init_pit, - pci_fixup: sable_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: sable_map_irq, + pci_swizzle: common_swizzle, sys: { t2: { gamma_bias: 0 @@ -273,6 +270,8 @@ DO_T2_BUS, machine_check: t2_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: EISA_DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 40, irq_probe_mask: _PROBE_MASK(40), @@ -282,9 +281,11 @@ init_arch: t2_init_arch, init_irq: sable_init_irq, - init_pit: generic_init_pit, - pci_fixup: sable_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: sable_map_irq, + pci_swizzle: common_swizzle, sys: { t2: { gamma_bias: _GAMMA_BIAS diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c --- v2.3.15/linux/arch/alpha/kernel/sys_sio.c Thu Jan 21 11:26:30 1999 +++ linux/arch/alpha/kernel/sys_sio.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code for all boards that route the PCI interrupts through the SIO * PCI/ISA bridge. This includes Noname (AXPpci33), Multia (UDB), @@ -28,11 +28,12 @@ #include #include #include +#include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void sio_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) @@ -57,6 +58,8 @@ static inline void __init xl_init_arch(unsigned long *mem_start, unsigned long *mem_end) { + struct pci_controler *hose; + /* * Set up the PCI->physical memory translation windows. For * the XL we *must* use both windows, in order to maximize the @@ -86,6 +89,16 @@ */ *(vuip)APECS_IOC_HAXR2 = 0; mb(); + + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(mem_start); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = LCA_CONF; + hose->index = 0; } static inline void __init @@ -114,26 +127,12 @@ * This is NOT how we should do it. PIRQ0-X should have * their own IRQ's, the way intel uses the IO-APIC irq's. */ -static unsigned long sio_route_tab __initdata = 0; static void __init -sio_pci_fixup(int (*map_irq)(struct pci_dev *dev, int sel, int pin), - unsigned long new_route_tab) +sio_pci_route(void) { - unsigned int route_tab; - - /* Examine or update the PCI routing table. */ - pcibios_read_config_dword(0, PCI_DEVFN(7, 0), 0x60, &route_tab); - - sio_route_tab = route_tab; - if (PCI_MODIFY) { - sio_route_tab = new_route_tab; - pcibios_write_config_dword(0, PCI_DEVFN(7, 0), 0x60, - new_route_tab); - } - - /* Update all the IRQs. */ - common_pci_fixup(map_irq, common_swizzle); + pcibios_write_config_dword(0, PCI_DEVFN(7, 0), 0x60, + alpha_mv.sys.sio.route_tab); } static unsigned int __init @@ -180,7 +179,7 @@ } static inline int __init -noname_map_irq(struct pci_dev *dev, int slot, int pin) +noname_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { /* * The Noname board has 5 PCI slots with each of the 4 @@ -214,49 +213,12 @@ }; const long min_idsel = 6, max_idsel = 14, irqs_per_slot = 5; int irq = COMMON_TABLE_LOOKUP, tmp; - tmp = __kernel_extbl(sio_route_tab, irq); + tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq); return irq >= 0 ? tmp : -1; } -static inline void __init -noname_pci_fixup(void) -{ - /* - * For UDB, the only available PCI slot must not map to IRQ 9, - * since that's the builtin MSS sound chip. That PCI slot - * will map to PIRQ1 (for INTA at least), so we give it IRQ 15 - * instead. - * - * Unfortunately we have to do this for NONAME as well, since - * they are co-indicated when the platform type "Noname" is - * selected... :-( - */ - layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - sio_pci_fixup(noname_map_irq, 0x0b0a0f0d); - sio_fixup_irq_levels(sio_collect_irq_levels()); - enable_ide(0x26e); -} - -static inline void __init -avanti_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - sio_pci_fixup(noname_map_irq, 0x0b0a0e0f); - sio_fixup_irq_levels(sio_collect_irq_levels()); - enable_ide(0x26e); -} - -static inline void __init -xl_pci_fixup(void) -{ - layout_all_busses(DEFAULT_IO_BASE, XL_DEFAULT_MEM_BASE); - sio_pci_fixup(noname_map_irq, 0x0b0a090f); - sio_fixup_irq_levels(sio_collect_irq_levels()); - enable_ide(0x26e); -} - static inline int __init -p2k_map_irq(struct pci_dev *dev, int slot, int pin) +p2k_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[][5] __initlocaldata = { /*INT A B C D */ @@ -270,29 +232,27 @@ }; const long min_idsel = 6, max_idsel = 12, irqs_per_slot = 5; int irq = COMMON_TABLE_LOOKUP, tmp; - tmp = __kernel_extbl(sio_route_tab, irq); + tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq); return irq >= 0 ? tmp : -1; } static inline void __init -p2k_pci_fixup(void) +noname_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - sio_pci_fixup(p2k_map_irq, 0x0b0a090f); + sio_pci_route(); + common_init_pci(); sio_fixup_irq_levels(sio_collect_irq_levels()); - enable_ide(0x26e); + ns87312_enable_ide(0x26e); } static inline void __init -alphabook1_pci_fixup(void) +alphabook1_init_pci(void) { struct pci_dev *dev; unsigned char orig, config; - layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - - /* For the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15. */ - sio_pci_fixup(noname_map_irq, 0x0e0f0a0a); + sio_pci_route(); + common_init_pci(); /* * On the AlphaBook1, the PCMCIA chip (Cirrus 6729) @@ -304,20 +264,17 @@ * moment (2.0.29), ncr53c8xx.c does NOT do this, but * 53c7,8xx.c DOES. */ - for (dev = pci_devices; dev; dev = dev->next) { - 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; + + dev = NULL; + while ((dev = pci_find_device(PCI_VENDOR_ID_NCR, PCI_ANY_ID, dev))) { + if (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 long 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; + io_port = dev->resource[0].start; ctest4 = inb(io_port+0x21); if (!(ctest4 & 0x80)) { printk("AlphaBook1 NCR init: setting" @@ -356,18 +313,27 @@ DO_LCA_BUS, machine_check: lca_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, irq_probe_mask: _PROBE_MASK(16), update_irq_hw: sio_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, init_arch: alphabook1_init_arch, init_irq: sio_init_irq, - init_pit: generic_init_pit, - pci_fixup: alphabook1_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: alphabook1_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: noname_map_irq, + pci_swizzle: common_swizzle, + + sys: { sio: { + /* NCR810 SCSI is 14, PCMCIA controller is 15. */ + route_tab: 0x0e0f0a0a, + }} }; ALIAS_MV(alphabook1) #endif @@ -381,18 +347,26 @@ DO_APECS_BUS, machine_check: apecs_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, irq_probe_mask: _PROBE_MASK(16), update_irq_hw: sio_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, init_arch: apecs_init_arch, init_irq: sio_init_irq, - init_pit: generic_init_pit, - pci_fixup: avanti_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: noname_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: noname_map_irq, + pci_swizzle: common_swizzle, + + sys: { sio: { + route_tab: 0x0b0a0e0f, + }} }; ALIAS_MV(avanti) #endif @@ -406,18 +380,35 @@ DO_LCA_BUS, machine_check: lca_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, irq_probe_mask: _PROBE_MASK(16), update_irq_hw: sio_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: srm_device_interrupt, init_arch: lca_init_arch, init_irq: sio_init_irq, - init_pit: generic_init_pit, - pci_fixup: noname_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: noname_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: noname_map_irq, + pci_swizzle: common_swizzle, + + sys: { sio: { + /* For UDB, the only available PCI slot must not map to IRQ 9, + since that's the builtin MSS sound chip. That PCI slot + will map to PIRQ1 (for INTA at least), so we give it IRQ 15 + instead. + + Unfortunately we have to do this for NONAME as well, since + they are co-indicated when the platform type "Noname" is + selected... :-( */ + + route_tab: 0x0b0a0f0d, + }} }; ALIAS_MV(noname) #endif @@ -431,18 +422,26 @@ DO_LCA_BUS, machine_check: lca_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, irq_probe_mask: P2K_PROBE_MASK, update_irq_hw: sio_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: srm_device_interrupt, init_arch: lca_init_arch, init_irq: sio_init_irq, - init_pit: generic_init_pit, - pci_fixup: p2k_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: noname_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: p2k_map_irq, + pci_swizzle: common_swizzle, + + sys: { sio: { + route_tab: 0x0b0a090f, + }} }; ALIAS_MV(p2k) #endif @@ -456,18 +455,26 @@ BUS(apecs_xl), machine_check: apecs_machine_check, max_dma_address: ALPHA_XL_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: XL_DEFAULT_MEM_BASE, nr_irqs: 16, irq_probe_mask: _PROBE_MASK(16), update_irq_hw: sio_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, init_arch: xl_init_arch, init_irq: sio_init_irq, - init_pit: generic_init_pit, - pci_fixup: xl_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: noname_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: noname_map_irq, + pci_swizzle: common_swizzle, + + sys: { sio: { + route_tab: 0x0b0a090f, + }} }; ALIAS_MV(xl) #endif diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_sx164.c linux/arch/alpha/kernel/sys_sx164.c --- v2.3.15/linux/arch/alpha/kernel/sys_sx164.c Sun Feb 21 19:06:36 1999 +++ linux/arch/alpha/kernel/sys_sx164.c Tue Aug 31 10:50:44 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1995 David A Rusling * Copyright (C) 1996 Jay A Estabrook - * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1998, 1999 Richard Henderson * * Code supporting the SX164 (PCA56+PYXIS). */ @@ -26,9 +26,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -164,7 +164,7 @@ */ static int __init -sx164_map_irq(struct pci_dev *dev, int slot, int pin) +sx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[5][5] __initlocaldata = { /*INT INTA INTB INTC INTD */ @@ -179,10 +179,9 @@ } void __init -sx164_pci_fixup(void) +sx164_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(sx164_map_irq, common_swizzle); + common_init_pci(); SMC669_Init(0); } @@ -199,17 +198,21 @@ DO_PYXIS_BUS, machine_check: pyxis_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 40, irq_probe_mask: _PROBE_MASK(40), update_irq_hw: sx164_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: sx164_device_interrupt, init_arch: pyxis_init_arch, init_irq: sx164_init_irq, - init_pit: generic_init_pit, - pci_fixup: sx164_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: sx164_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: sx164_map_irq, + pci_swizzle: common_swizzle, }; ALIAS_MV(sx164) diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/sys_takara.c linux/arch/alpha/kernel/sys_takara.c --- v2.3.15/linux/arch/alpha/kernel/sys_takara.c Tue Jun 22 10:46:52 1999 +++ linux/arch/alpha/kernel/sys_takara.c Tue Aug 31 10:50:44 1999 @@ -25,9 +25,9 @@ #include #include "proto.h" -#include "irq.h" -#include "bios32.h" -#include "machvec.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" static void @@ -127,7 +127,7 @@ */ static int __init -takara_map_irq(struct pci_dev *dev, int slot, int pin) +takara_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[15][5] __initlocaldata = { { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 6 == device 3 */ @@ -150,16 +150,18 @@ return COMMON_TABLE_LOOKUP; } -static int __init -takara_swizzle(struct pci_dev *dev, int *pinp) +static u8 __init +takara_swizzle(struct pci_dev *dev, u8 *pinp) { int slot = PCI_SLOT(dev->devfn); int pin = *pinp; unsigned int ctlreg = inl(0x500); unsigned int busslot = PCI_SLOT(dev->bus->self->devfn); - /* Check first for built-in bridges. */ - if (busslot > 16 && ((1<<(36-busslot)) & ctlreg)) { + /* Check for built-in bridges. */ + if (dev->bus->number != 0 + && busslot > 16 + && ((1<<(36-busslot)) & ctlreg)) { if (pin == 1) pin += (20 - busslot); else { @@ -174,11 +176,10 @@ } static void __init -takara_pci_fixup(void) +takara_init_pci(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); - common_pci_fixup(takara_map_irq, takara_swizzle); - /* enable_ide(0x26e); */ + common_init_pci(); + /* ns87312_enable_ide(0x26e); */ } @@ -194,17 +195,21 @@ DO_CIA_BUS, machine_check: cia_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 20, irq_probe_mask: _PROBE_MASK(20), update_irq_hw: takara_update_irq_hw, - ack_irq: generic_ack_irq, + ack_irq: common_ack_irq, device_interrupt: takara_device_interrupt, init_arch: cia_init_arch, init_irq: takara_init_irq, - init_pit: generic_init_pit, - pci_fixup: takara_pci_fixup, - kill_arch: generic_kill_arch, + init_pit: common_init_pit, + init_pci: takara_init_pci, + kill_arch: common_kill_arch, + pci_map_irq: takara_map_irq, + pci_swizzle: takara_swizzle, }; ALIAS_MV(takara) diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.3.15/linux/arch/alpha/kernel/time.c Thu Jul 29 13:37:22 1999 +++ linux/arch/alpha/kernel/time.c Tue Aug 31 10:50:44 1999 @@ -40,19 +40,13 @@ #include #include "proto.h" -#include "irq.h" +#include "irq_impl.h" extern rwlock_t xtime_lock; extern volatile unsigned long lost_ticks; /* kernel/sched.c */ static int set_rtc_mmss(unsigned long); -#ifdef CONFIG_RTC -struct resource timer_resource = { "pit", 0x40, 0x40+0x20 }; -#else -struct resource timer_resource = { "rtc", 0, 0 }; -#endif - /* * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting @@ -190,8 +184,6 @@ CMOS_WRITE(control, RTC_CONTROL); (void) CMOS_READ(RTC_INTR_FLAGS); - request_resource(&ioport_resource, &timer_resource); - /* Setup interval timer. */ outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb(LATCH & 0xff, 0x40); /* LSB */ @@ -204,7 +196,7 @@ #endif void -generic_init_pit (void) +common_init_pit (void) { unsigned char x; @@ -225,10 +217,6 @@ } (void) CMOS_READ(RTC_INTR_FLAGS); - timer_resource.start = RTC_PORT(0); - timer_resource.end = RTC_PORT(0) + 0x10; - request_resource(&ioport_resource, &timer_resource); - outb(0x36, 0x43); /* pit counter 0: system timer */ outb(0x00, 0x40); outb(0x00, 0x40); @@ -331,7 +319,7 @@ /* setup timer */ irq_handler = timer_interrupt; - if (request_irq(TIMER_IRQ, irq_handler, 0, timer_resource.name, NULL)) + if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL)) panic("Could not allocate timer IRQ!"); } diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.3.15/linux/arch/alpha/kernel/traps.c Thu Jul 29 13:37:22 1999 +++ linux/arch/alpha/kernel/traps.c Tue Aug 31 10:50:44 1999 @@ -22,7 +22,7 @@ #include "proto.h" -static void +void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15) { printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n", diff -u --recursive --new-file v2.3.15/linux/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds --- v2.3.15/linux/arch/alpha/vmlinux.lds Wed Aug 4 15:48:00 1999 +++ linux/arch/alpha/vmlinux.lds Tue Aug 31 10:50:44 1999 @@ -59,4 +59,27 @@ .mdebug 0 : { *(.mdebug) } .note 0 : { *(.note) } .comment 0 : { *(.comment) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } } diff -u --recursive --new-file v2.3.15/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.3.15/linux/arch/arm/Makefile Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/Makefile Mon Aug 30 18:14:55 1999 @@ -12,21 +12,52 @@ # # Copyright (C) 1995-1999 by Russell King -CFLAGS_PROC := -ASFLAGS_PROC := - # GCC 2.7 uses different options to later compilers; sort out which we have CONFIG_GCC_NEW := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi) -# Hack to get around RiscPC with StrongARM optimistaion -# problem - force ARM710 optimisation for now. +# See if this is ld "2.9.4" or later +NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) + +# CFLAGS_PROC - processor dependent CFLAGS +# PROCESSOR - processor type +# TEXTADDR - Uncompressed kernel link text address +# ZTEXTADDR - Compressed kernel link text address +# ZRELADDR - Compressed kernel relocating address +# (point at which uncompressed kernel is loaded). + +# +# select flags depending on the compiler +# ifeq ($(CONFIG_GCC_NEW),y) - ifeq ($(CONFIG_ARCH_RPC),y) - ifeq ($(CONFIG_CPU_SA110),y) - CONFIG_CPU_SA110 := n - CONFIG_CPU_ARM7 := y - endif - endif + CFLAGS_PROC := -mshort-load-bytes -msoft-float + CFLAGS_PROC_CPU_26 := -mcpu=arm3 -Os + CFLAGS_PROC_CPU_32v3 := -march=armv3 + CFLAGS_PROC_CPU_32v4 := -march=armv4 + CFLAGS_ARM6 := -mtune=arm6 + CFLAGS_ARM7 := -mtune=arm7 + CFLAGS_SA110 := -mtune=strongarm110 +else + CFLAGS_PROC := + CFLAGS_PROC_CPU_26 := -m3 + CFLAGS_PROC_CPU_32v3 := + CFLAGS_PROC_CPU_32v4 := + CFLAGS_ARM6 := -m6 + CFLAGS_ARM7 := -m6 + CFLAGS_SA110 := -m6 +endif + +ifeq ($(NEW_LINKER),y) + ASFLAGS_PROC := -mno-fpu + ASFLAGS_PROC_CPU_26 := -mapcs-26 + ASFLAGS_PROC_CPU_32v3 := -mapcs-32 -marmv3m + ASFLAGS_PROC_CPU_32v4 := -mapcs-32 -marmv4t + LINKFLAGS := -p +else + ASFLAGS_PROC := + ASFLAGS_PROC_CPU_26 := -m3 + ASFLAGS_PROC_CPU_32v3 := -m6 + ASFLAGS_PROC_CPU_32v4 := -m6 + LINKFLAGS := endif ifeq ($(CONFIG_CPU_26),y) @@ -34,56 +65,36 @@ TEXTADDR = 0x02080000 ZTEXTADDR = 0x01800000 ZRELADDR = 0x02080000 - ifeq ($(CONFIG_GCC_NEW),y) - CFLAGS_PROC += -mapcs-26 -mshort-load-bytes - ifeq ($(CONFIG_CPU_ARM2),y) - CFLAGS_PROC += -mcpu=arm2 - ASFLAGS_PROC += -m2 - endif - ifeq ($(CONFIG_CPU_ARM3),y) - CFLAGS_PROC += -mcpu=arm3 - ASFLAGS_PROC += -m3 - endif - else - ifeq ($(CONFIG_CPU_ARM2),y) - CFLAGS_PROC += -m2 - ASFLAGS_PROC += -m2 - endif - ifeq ($(CONFIG_CPU_ARM3),y) - CFLAGS_PROC += -m3 - ASFLAGS_PROC += -m3 - endif - endif + CFLAGS_PROC += $(CFLAGS_PROC_CPU_26) + ASFLAGS_PROC += $(ASFLAGS_PROC_CPU_26) endif ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv TEXTADDR = 0xC0008000 - ifeq ($(CONFIG_GCC_NEW),y) - CFLAGS_PROC += -mapcs-32 -mshort-load-bytes - ifeq ($(CONFIG_CPU_ARM6),y) - CFLAGS_PROC += -mcpu=arm6 - endif - ifeq ($(CONFIG_CPU_ARM7),y) - CFLAGS_PROC += -mcpu=arm7 - endif - ifeq ($(CONFIG_CPU_SA110),y) - CFLAGS_PROC += -mcpu=strongarm110 - endif + ifeq ($(CONFIG_CPU_32v4),y) + CFLAGS_PROC += $(CFLAGS_PROC_CPU_32v4) + ASFLAGS_PROC += $(ASFLAGS_PROC_CPU_32v4) + else + CFLAGS_PROC += $(CFLAGS_PROC_CPU_32v3) + ASFLAGS_PROC += $(ASFLAGS_PROC_CPU_32v3) + endif + # + # Exactly one of the following must be selected + # + ifeq ($(CONFIG_CPU_ARM6),y) + CFLAGS_PROC += $(CFLAGS_ARM6) + else + ifeq ($(CONFIG_CPU_ARM7),y) + CFLAGS_PROC += $(CFLAGS_ARM7) else - CFLAGS_PROC += -m6 + ifeq ($(CONFIG_CPU_SA110),y) + CFLAGS_PROC += $(CFLAGS_SA110) + endif + endif endif - ASFLAGS_PROC += -m6 endif -# Processor Architecture -# CFLAGS_PROC - processor dependent CFLAGS -# PROCESSOR - processor type -# TEXTADDR - Uncompressed kernel link text address -# ZTEXTADDR - Compressed kernel link text address -# ZRELADDR - Compressed kernel relocating address -# (point at which uncompressed kernel is loaded). -# COMPRESSED_HEAD = head.o @@ -131,6 +142,8 @@ COMPRESSED_HEAD = head-nexuspci.o endif + + PERL = perl LD = $(CROSS_COMPILE)ld OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S @@ -144,7 +157,7 @@ endif CFLAGS := $(CFLAGS_PROC) $(CFLAGS) -pipe ASFLAGS := $(ASFLAGS_PROC) $(ASFLAGS) -LINKFLAGS = -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext -Ttext $(TEXTADDR) +LINKFLAGS += -X -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext ZLINKFLAGS = -Ttext $(ZTEXTADDR) # If we're intending to debug the kernel, make sure it has line number @@ -175,12 +188,31 @@ DRIVERS += arch/arm/nwfpe/math-emu.a endif -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +# The following is a hack to get 'constants.h' up +# to date before starting compilation +CONSTANTS := constants + +constants: dummy + @$(MAKE) -C arch/arm/lib constants.h -symlinks:: +symlinks: archsymlinks + +archsymlinks: $(RM) include/asm-arm/arch include/asm-arm/proc (cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc) +# We need to rebuild the linker script +# each time, in case the architecture has +# changed. +.PHONY: arch/arm/vmlinux-$(PROCESSOR).lds + +vmlinux: arch/arm/vmlinux-$(PROCESSOR).lds + +arch/arm/vmlinux-$(PROCESSOR).lds: $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds.in + @sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@ + arch/arm/kernel: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel @@ -197,6 +229,7 @@ archmrproper: rm -f include/asm-arm/arch include/asm-arm/proc @$(MAKE) -C arch/$(ARCH)/special mrproper + rm -f $(TOPDIR)/arch/arm/vmlinux-*.lds archclean: @$(MAKEBOOT) clean diff -u --recursive --new-file v2.3.15/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.3.15/linux/arch/arm/boot/compressed/Makefile Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/boot/compressed/Makefile Mon Aug 30 18:14:55 1999 @@ -17,6 +17,13 @@ OBJS += ll_char_wr.o font.o endif +ifeq ($(NEW_LINKER),y) +BINFMT := elf32-littlearm +else +BINFMT := elf32-arm +endif + + all: vmlinux vmlinux: $(OBJS) piggy.o @@ -31,7 +38,7 @@ $(OBJCOPY) $(SYSTEM) $$tmppiggy; \ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ - $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \ + $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b $(BINFMT) -T $$tmppiggy.lnk; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; font.o: $(FONTC) diff -u --recursive --new-file v2.3.15/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.3.15/linux/arch/arm/config.in Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/config.in Mon Aug 30 18:14:55 1999 @@ -17,7 +17,7 @@ FootBridge-based CONFIG_FOOTBRIDGE" RiscPC if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE + bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then define_bool CONFIG_ADDIN_FOOTBRIDGE n else @@ -37,8 +37,10 @@ define_bool CONFIG_ARCH_CO285 y fi +# # Select various configuration options depending on the machine type # Easy check for Acorn-style architectures +# if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -47,17 +49,53 @@ define_bool CONFIG_ARCH_ACORN n fi -#if [ "$CONFIG_ARCH_TBOX" = "y" ]; then -# define_bool CONFIG_BUS_I2C y -#fi +# +# Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has +# ever built a machine that can take both, and now that ARM3 is obsolete +# nobody is likely to either. +# +if [ "$CONFIG_ARCH_ARC" = "y" -o \ + "$CONFIG_ARCH_A5K" = "y" ]; then + define_bool CONFIG_CPU_32 n + define_bool CONFIG_CPU_26 y + # + # Select memory size + # + bool '2MB physical memory' CONFIG_PAGESIZE_16 +else + define_bool CONFIG_CPU_32 y + define_bool CONFIG_CPU_26 n + + # + # Select CPU and optimisation dependent on architecture + # + if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then + define_bool CONFIG_CPU_32v4 y + define_bool CONFIG_CPU_SA110 y + else + if [ "$CONFIG_ARCH_RPC" = "y" ]; then + define_bool CONFIG_CPU_32v3 y + bool 'Support ARM610' CONFIG_CPU_ARM6 + bool 'Support ARM710' CONFIG_CPU_ARM7 + bool 'Support StrongARM110' CONFIG_CPU_SA110 + fi + fi +fi + +# # These machines always have PCI +# if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then define_bool CONFIG_PCI y fi +# # These machines have ISA-DMA +# if [ "$CONFIG_CATS" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" ]; then define_bool CONFIG_ISA_DMA y @@ -65,34 +103,6 @@ define_bool CONFIG_ISA_DMA n fi -# Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has -# ever built a machine that can take both, and now that ARM3 is obsolete -# nobody is likely to either. -if [ "$CONFIG_ARCH_ARC" = "y" -o \ - "$CONFIG_ARCH_A5K" = "y" ]; then - define_bool CONFIG_CPU_32 n - define_bool CONFIG_CPU_26 y -else - define_bool CONFIG_CPU_32 y - define_bool CONFIG_CPU_26 n -fi - -# Now allow the user to choose a more precise CPU. This is only used to set -# the flags we pass to GCC, not in any code. -choice 'Optimise for CPU' \ - "ARM2 CONFIG_CPU_ARM2 \ - ARM3 CONFIG_CPU_ARM3 \ - ARM6 CONFIG_CPU_ARM6 \ - ARM7 CONFIG_CPU_ARM7 \ - SA110 CONFIG_CPU_SA110" ARM6 - -if [ "$CONFIG_CPU_26" = "y" ]; then -# For 26-bit CPUs, the page size changes with the amount of physical RAM! -# The default is 4MB but if the user has less they have to own up to it here. - choice 'Physical memory size' \ - "4MB+ CONFIG_PAGESIZE_32 \ - 2MB CONFIG_PAGESIZE_16" 4MB+ -fi endmenu mainmenu_option next_comment @@ -101,7 +111,7 @@ if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP fi -bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS +#bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS endmenu mainmenu_option next_comment diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.3.15/linux/arch/arm/kernel/Makefile Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/Makefile Mon Aug 30 18:14:55 1999 @@ -9,8 +9,8 @@ ENTRY_OBJ = entry-$(PROCESSOR).o O_TARGET := kernel.o -O_OBJS := $(ENTRY_OBJ) irq.o process.o ptrace.o setup.o \ - signal.o sys_arm.o time.o traps.o +O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o \ + semaphore.o setup.o signal.o sys_arm.o time.o traps.o ifeq ($(CONFIG_ISA_DMA),y) ISA_DMA_OBJS += dma-isa.o @@ -30,7 +30,7 @@ OX_OBJS_footbridge= dma.o hw-footbridge.o OX_OBJS_nexuspci = -all: lib kernel.o $(HEAD_OBJ) init_task.o +all: kernel.o $(HEAD_OBJ) init_task.o O_OBJS += $(O_OBJS_$(MACHINE)) @@ -48,7 +48,7 @@ endif else ifdef CONFIG_PCI - O_OBJS += dec21285.o + O_OBJS += bios32.o dec21285.o endif endif @@ -79,11 +79,6 @@ include $(TOPDIR)/Rules.make $(ENTRY_OBJ): ../lib/constants.h - -.PHONY: lib - -lib: - $(MAKE) -C ../lib constants.h # Spell out some dependencies that `make dep' doesn't spot entry-armv.o: calls.S diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.3.15/linux/arch/arm/kernel/armksyms.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/armksyms.c Mon Aug 30 18:14:55 1999 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -25,9 +26,6 @@ extern unsigned int local_bh_count[NR_CPUS]; extern unsigned int local_irq_count[NR_CPUS]; -extern void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); -extern void iounmap(void *addr); - extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); /* @@ -36,7 +34,6 @@ extern int sys_write(int, const char *, int); extern int sys_read(int, char *, int); extern int sys_lseek(int, off_t, int); -extern int sys_open(const char *, int, int); extern int sys_exit(int); extern int sys_wait4(int, int *, int, struct rusage *); @@ -93,7 +90,7 @@ EXPORT_SYMBOL(local_irq_count); #ifdef CONFIG_CPU_32 EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(__iounmap); #endif EXPORT_SYMBOL(kernel_thread); @@ -101,11 +98,28 @@ EXPORT_SYMBOL(disable_irq); /* processor dependencies */ +#ifdef MULTI_CPU EXPORT_SYMBOL(processor); +#else +EXPORT_SYMBOL(cpu_flush_cache_all); +EXPORT_SYMBOL(cpu_flush_cache_area); +EXPORT_SYMBOL(cpu_flush_cache_entry); +EXPORT_SYMBOL(cpu_clean_cache_area); +EXPORT_SYMBOL(cpu_flush_ram_page); +EXPORT_SYMBOL(cpu_flush_tlb_all); +EXPORT_SYMBOL(cpu_flush_tlb_area); +EXPORT_SYMBOL(cpu_switch_mm); +EXPORT_SYMBOL(cpu_set_pmd); +EXPORT_SYMBOL(cpu_set_pte); +EXPORT_SYMBOL(cpu_flush_icache_area); +EXPORT_SYMBOL(cpu_cache_wback_area); +EXPORT_SYMBOL(cpu_cache_purge_area); +#endif EXPORT_SYMBOL(__machine_arch_type); /* networking */ EXPORT_SYMBOL(csum_partial_copy); +EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(__csum_ipv6_magic); /* io */ @@ -150,6 +164,7 @@ EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL_NOVERS(strstr); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); @@ -198,9 +213,8 @@ EXPORT_SYMBOL(find_next_zero_bit); /* elf */ -EXPORT_SYMBOL(armidlist); -EXPORT_SYMBOL(armidindex); EXPORT_SYMBOL(elf_platform); +EXPORT_SYMBOL(elf_hwcap); /* syscalls */ EXPORT_SYMBOL(sys_write); @@ -213,5 +227,5 @@ /* semaphores */ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); +EXPORT_SYMBOL_NOVERS(__down_trylock_failed); EXPORT_SYMBOL_NOVERS(__up_wakeup); - diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.3.15/linux/arch/arm/kernel/bios32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/bios32.c Mon Aug 30 18:14:55 1999 @@ -0,0 +1,352 @@ +/* + * arch/arm/kernel/bios32.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include +#include + +#include +#include + +int have_isa_bridge; + +int (*pci_irq_fixup)(struct pci_dev *dev); + +extern struct pci_ops *dc21285_init(int pass); +extern void pcibios_fixup_ebsa285(struct pci_dev *dev); +extern void hw_init(void); + +void +pcibios_report_device_errors(void) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + u16 status; + + pci_read_config_word(dev, PCI_STATUS, &status); + + if (status & 0xf900) { + pci_write_config_word(dev, PCI_STATUS, status & 0xf900); + printk(KERN_DEBUG "PCI: %02x:%02x status = %X\n", + dev->bus->number, dev->devfn, status); + } + } +} + +/* + * We don't use this to fix the device, but more our initialisation. + * It's not the correct use for this, but it works. The actions we + * take are: + * - enable only IO + * - set memory region to start at zero + * - (0x48) enable all memory requests from ISA to be channeled to PCI + * - (0x42) disable ping-pong (as per errata) + * - (0x40) enable PCI packet retry + * - (0x83) don't use CPU park enable, park on last master, disable GAT bit + * - (0x80) default rotating priorities + * - (0x81) rotate bank 4 + */ +static void __init pci_fixup_83c553(struct pci_dev *dev) +{ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_SPACE_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_IO); + + dev->resource[0].end -= dev->resource[0].start; + dev->resource[0].start = 0; + + pci_write_config_byte(dev, 0x48, 0xff); + pci_write_config_byte(dev, 0x42, 0x00); + pci_write_config_byte(dev, 0x40, 0x22); + pci_write_config_byte(dev, 0x83, 0x02); + pci_write_config_byte(dev, 0x80, 0xe0); + pci_write_config_byte(dev, 0x81, 0x01); +} + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553 }, + { 0 } +}; + +/* + * Assign an address to an I/O range. + */ +static void __init pcibios_fixup_io_addr(struct pci_dev *dev, struct resource *r, int idx) +{ + unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2); + unsigned int size = r->end - r->start + 1; + u32 try; + + /* + * We need to avoid collisions with `mirrored' VGA ports and other strange + * ISA hardware, so we always want the addresses kilobyte aligned. + */ + if (!size || size > 256) { + printk(KERN_ERR "PCI: Cannot assign I/O space to %s, " + "%d bytes are too much.\n", dev->name, size); + return; + } + + if (allocate_resource(&ioport_resource, r, size, 0x9000, ~0, 1024)) { + printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O " + "space for %s.\n", size, dev->name); + return; + } + + printk("PCI: Assigning I/O space %04lx-%04lx to %s\n", + r->start, r->end, dev->name); + + pci_write_config_dword(dev, reg, r->start | PCI_BASE_ADDRESS_SPACE_IO); + pci_read_config_dword(dev, reg, &try); + + if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) { + r->start = 0; + pci_write_config_dword(dev, reg, 0); + printk(KERN_ERR "PCI: I/O address setup failed, got %04x\n", try); + } +} + +/* + * Assign an address to an memory range. + */ +static void __init pcibios_fixup_mem_addr(struct pci_dev *dev, struct resource *r, int idx) +{ + unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2); + unsigned int size = r->end - r->start + 1; + u32 try; + + if (!size) { + printk(KERN_ERR "PCI: Cannot assign memory space to %s, " + "%d bytes are too much.\n", dev->name, size); + return; + } + + if (allocate_resource(&iomem_resource, r, size, + 0x00100000, 0x0fffffff, 1024)) { + printk(KERN_ERR "PCI: Unable to find free %d bytes of memory " + "space for %s.\n", size, dev->name); + return; + } + + printk("PCI: Assigning memory space %08lx-%08lx to %s\n", + r->start, r->end, dev->name); + + pci_write_config_dword(dev, reg, r->start); + pci_read_config_dword(dev, reg, &try); + + if (try != r->start) { + r->start = 0; + pci_write_config_dword(dev, reg, 0); + printk(KERN_ERR "PCI: memory address setup failed, " + "got %08x\n", try); + } +} + +#define _PCI_REGION_IO 1 +#define _PCI_REGION_MEM 2 + +/* + * Fix up one PCI devices regions, enables and interrupt lines + */ +static void __init pcibios_fixup_device(struct pci_dev *dev, u16 *cmd) +{ + int i, has_regions = 0; + + /* + * Fix up the regions. Any regions which aren't allocated + * are given a free region. + */ + for (i = 0; i < 6; i++) { + struct resource *r = dev->resource + i; + + if (r->flags & IORESOURCE_IO) { + has_regions |= _PCI_REGION_IO; + + if (!r->start || r->end == 0xffffffff) + pcibios_fixup_io_addr(dev, r, i); + } else if (r->end) { + has_regions |= _PCI_REGION_MEM; + + if (!r->start) + pcibios_fixup_mem_addr(dev, r, i); + } + } + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_ISA: + case PCI_CLASS_BRIDGE_EISA: + /* + * If this device is an ISA bridge, set the have_isa_bridge + * flag. We will then go looking for things like keyboard, + * etc + */ + have_isa_bridge = !0; + /* FALL THROUGH */ + + default: + /* + * Don't enable VGA-compatible cards since they have + * fixed I/O and memory space. + * + * Don't enabled disabled IDE interfaces either because + * some BIOSes may reallocate the same address when they + * find that no devices are attached. + */ + if (has_regions & _PCI_REGION_IO && + !((*cmd) & PCI_COMMAND_IO)) { + printk("PCI: Enabling I/O for %s\n", dev->name); + *cmd |= PCI_COMMAND_IO; + } + + if (has_regions & _PCI_REGION_MEM && + !((*cmd) & PCI_COMMAND_MEMORY)) { + printk("PCI: Enabling memory for %s\n", dev->name); + *cmd |= PCI_COMMAND_MEMORY; + } + } +} + +/* + * Fix base addresses, I/O and memory enables and IRQ's + */ +static void __init pcibios_fixup_devices(void) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + u16 cmd; + + /* + * architecture specific hacks. + * I don't really want this here, + * but I don't see any other place + * for it to live. + */ + if (machine_is_netwinder() && + dev->vendor == PCI_VENDOR_ID_DEC && + dev->device == PCI_DEVICE_ID_DEC_21142) + /* Put the chip to sleep in case the driver isn't loaded */ + pci_write_config_dword(dev, 0x40, 0x80000000); + + /* + * Set latency timer to 32, and a cache line size to 32 bytes. + * Also, set system error enable, parity error enable, and + * fast back to back transaction enable. Disable ROM. + */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + cmd |= PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | + PCI_COMMAND_PARITY; + + pcibios_fixup_device(dev, &cmd); + + pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + /* + * now fixup the IRQs, if required + */ + if (pci_irq_fixup) + dev->irq = pci_irq_fixup(dev); + + /* + * If any remaining IRQs are weird, fix it now. + */ + if (dev->irq >= NR_IRQS) + dev->irq = 0; + + /* + * catch any drivers still reading this from the + * device itself. This can be removed once + * all drivers are fixed. (are there any?) + */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } +} + +/* + * Allocate resources for all PCI devices that have been enabled. + * We need to do that before we try to fix up anything. + */ +static void __init pcibios_claim_resources(void) +{ + struct pci_dev *dev; + int idx; + + for (dev = pci_devices; dev; dev = dev->next) + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *a, *r = &dev->resource[idx]; + + /* + * Ignore regions that start at 0 or + * end at 0xffffffff + */ + if (!r->start || r->end == 0xffffffff) + continue; + + if (r->flags & IORESOURCE_IO) + a = &ioport_resource; + else + a = &iomem_resource; + + if (request_resource(a, r) < 0) + printk(KERN_ERR "PCI: Address space collision " + "on region %d of %s\n", + idx, dev->name); + /* We probably should disable the region, + * shouldn't we? + */ + } +} + +/* + * Called after each bus is probed, but before its children + * are examined. + * + * No fixup of bus required + */ +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ +} + +void __init pcibios_init(void) +{ + struct pci_ops *ops; + + /* + * Pre-initialisation. Set up the host bridge. + */ + ops = dc21285_init(0); + + printk("PCI: Probing PCI hardware\n"); + + pci_scan_bus(0, ops, NULL); + pcibios_claim_resources(); + pcibios_fixup_devices(); + + /* + * Now clear down any PCI error IRQs and + * register the error handler + */ + dc21285_init(1); + + /* + * Initialise any other hardware after we've + * got the PCI bus initialised. We may need + * the PCI bus to talk to this other hardware. + */ + hw_init(); +} + +char * __init pcibios_setup(char *str) +{ + return str; +} diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S --- v2.3.15/linux/arch/arm/kernel/calls.S Wed Jul 28 10:30:10 1999 +++ linux/arch/arm/kernel/calls.S Mon Aug 30 18:14:55 1999 @@ -119,9 +119,9 @@ .long SYMBOL_NAME(sys_newlstat) .long SYMBOL_NAME(sys_newfstat) .long SYMBOL_NAME(sys_uname) -/* 110 */ .long SYMBOL_NAME(sys_ni_syscall) +/* 110 */ .long SYMBOL_NAME(sys_iopl) .long SYMBOL_NAME(sys_vhangup) - .long SYMBOL_NAME(sys_idle) + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_syscall) /* call a syscall */ .long SYMBOL_NAME(sys_wait4) /* 115 */ .long SYMBOL_NAME(sys_swapoff) @@ -129,7 +129,7 @@ .long SYMBOL_NAME(sys_ipc) .long SYMBOL_NAME(sys_fsync) .long SYMBOL_NAME(sys_sigreturn_wrapper) - .long SYMBOL_NAME(sys_clone_wapper) +/* 120 */ .long SYMBOL_NAME(sys_clone_wapper) .long SYMBOL_NAME(sys_setdomainname) .long SYMBOL_NAME(sys_newuname) .long SYMBOL_NAME(sys_ni_syscall) /* .long SYMBOL_NAME(sys_modify_ldt) */ diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.3.15/linux/arch/arm/kernel/dec21285.c Wed Jun 30 11:24:54 1999 +++ linux/arch/arm/kernel/dec21285.c Mon Aug 30 18:14:55 1999 @@ -1,7 +1,7 @@ /* - * arch/arm/kernel/dec21285.c: PCI functions for DEC 21285 + * arch/arm/kernel/dec21285.c: PCI functions for DC21285 * - * Copyright (C) 1998 Russell King, Phil Blundell + * Copyright (C) 1998-1999 Russell King, Phil Blundell */ #include #include @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -129,7 +130,7 @@ return PCIBIOS_SUCCESSFUL; } -__initfunc(void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set)) +void __init pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set) { unsigned short cmd; @@ -138,7 +139,7 @@ pci_write_config_word(dev, PCI_COMMAND, cmd); } -__initfunc(void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr)) +void __init pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr) { int reg = PCI_BASE_ADDRESS_0 + (idx << 2); @@ -148,7 +149,7 @@ dev->base_address[idx] = addr; } -__initfunc(void pcibios_fixup(void)) +void __init pcibios_fixup(void) { struct pci_dev *dev; @@ -167,7 +168,7 @@ hw_init(); } -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET; unsigned long cntl; @@ -242,11 +243,11 @@ printk(KERN_DEBUG"PCI: DEC21285 revision %02lX\n", *CSR_CLASSREV & 0xff); } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +void __init pcibios_fixup_bus(struct pci_bus *bus) { } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { return str; } diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dma-a5k.c linux/arch/arm/kernel/dma-a5k.c --- v2.3.15/linux/arch/arm/kernel/dma-a5k.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/dma-a5k.c Thu Aug 26 12:42:30 1999 @@ -91,7 +91,7 @@ return 0; } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { dma[DMA_VIRTUAL_FLOPPY].dma_irq = 64; } diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c --- v2.3.15/linux/arch/arm/kernel/dma-arc.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/dma-arc.c Mon Aug 30 18:15:02 1999 @@ -15,8 +15,11 @@ #include "dma.h" +#define DEBUG + int arch_request_dma(dmach_t channel, dma_t *dma, const char * dev_id) { + printk("arch_request_dma channel=%d F0=%d F1=%d\n",channel,DMA_VIRTUAL_FLOPPY0,DMA_VIRTUAL_FLOPPY1); if (channel == DMA_VIRTUAL_FLOPPY0 || channel == DMA_VIRTUAL_FLOPPY1) return 0; @@ -30,8 +33,9 @@ void arch_enable_dma(dmach_t channel, dma_t *dma) { + printk("arch_enable_dma channel=%d F0=%d F1=%d\n",channel,DMA_VIRTUAL_FLOPPY0,DMA_VIRTUAL_FLOPPY1); switch (channel) { -#ifdef CONFIG_BLK_DEV_FD +#ifdef CONFIG_BLK_DEV_FD1772 case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */ switch (dma->dma_mode) { case DMA_MODE_READ: /* read */ @@ -139,7 +143,7 @@ return 0; } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64; dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65; diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dma-dummy.c linux/arch/arm/kernel/dma-dummy.c --- v2.3.15/linux/arch/arm/kernel/dma-dummy.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/dma-dummy.c Thu Aug 26 12:42:31 1999 @@ -27,6 +27,6 @@ return 0; } -__initfunc(void init_dma(void)) +void __init init_dma(void) { } diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dma-footbridge.c linux/arch/arm/kernel/dma-footbridge.c --- v2.3.15/linux/arch/arm/kernel/dma-footbridge.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/dma-footbridge.c Thu Aug 26 12:42:31 1999 @@ -104,7 +104,7 @@ return 0; } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { #ifdef CONFIG_ISA_DMA has_isa_dma = isa_init_dma(); diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dma-isa.c linux/arch/arm/kernel/dma-isa.c --- v2.3.15/linux/arch/arm/kernel/dma-isa.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/dma-isa.c Mon Aug 30 18:15:07 1999 @@ -11,6 +11,7 @@ * Copyright (C) 1998 Phil Blundell */ #include +#include #include #include @@ -125,7 +126,7 @@ outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); } -__initfunc(int isa_init_dma(void)) +int __init isa_init_dma(void) { int dmac_found; @@ -138,7 +139,7 @@ dmac_found = inb(0x00) == 0x55 && inb(0x00) == 0xaa; if (dmac_found) { - int channel; + int channel, i; for (channel = 0; channel < 8; channel++) isa_disable_dma(channel, NULL); @@ -173,6 +174,9 @@ outb(0x33, 0x4d6); request_dma(DMA_ISA_CASCADE, "cascade"); + + for (i = 0; i < sizeof(dma_resources) / sizeof(dma_resources[0]); i++) + request_resource(&ioport_resource, dma_resources + i); } return dmac_found; diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.3.15/linux/arch/arm/kernel/dma-rpc.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/dma-rpc.c Thu Aug 26 12:42:31 1999 @@ -359,7 +359,7 @@ outb(tcr, IOMD_DMATCR); } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { outb(0, IOMD_IO0CR); outb(0, IOMD_IO1CR); diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c --- v2.3.15/linux/arch/arm/kernel/dma.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/dma.c Thu Aug 26 12:42:31 1999 @@ -221,7 +221,7 @@ EXPORT_SYMBOL(set_dma_sg); EXPORT_SYMBOL(set_dma_speed); -__initfunc(void init_dma(void)) +void __init init_dma(void) { arch_dma_init(dma_chan); } diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.3.15/linux/arch/arm/kernel/ecard.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/ecard.c Mon Aug 30 18:15:11 1999 @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef CONFIG_ARCH_ARC #include @@ -231,8 +232,42 @@ static wait_queue_head_t ecard_done; static struct ecard_request *ecard_req; +/* to be removed when exec_mmap becomes extern */ +static int exec_mmap(void) +{ + struct mm_struct * mm, * old_mm; + + old_mm = current->mm; + if (old_mm && atomic_read(&old_mm->mm_users) == 1) { + flush_cache_mm(old_mm); + mm_release(); + exit_mmap(old_mm); + flush_tlb_mm(old_mm); + return 0; + } + + mm = mm_alloc(); + if (mm) { + struct mm_struct *active_mm = current->active_mm; + + current->mm = mm; + current->active_mm = mm; + activate_mm(active_mm, mm); + mm_release(); + if (old_mm) { + if (active_mm != old_mm) BUG(); + mmput(old_mm); + return 0; + } + mmdrop(active_mm); + return 0; + } + return -ENOMEM; +} + /* - * Set up the expansion card daemon's environment. + * Set up the expansion card + * daemon's environment. */ static void ecard_init_task(void) @@ -251,6 +286,8 @@ pgd_t *src_pgd, *dst_pgd; unsigned int dst_addr = IO_START; + exec_mmap(); + src_pgd = pgd_offset(current->mm, IO_BASE); dst_pgd = pgd_offset(current->mm, dst_addr); @@ -333,7 +370,7 @@ * call the loader. We can't schedule, or * sleep for this call. */ - if ((current == task[0] || in_interrupt()) && + if ((current == &init_task || in_interrupt()) && req->req == req_reset && req->ec == NULL) { ecard_init_task(); ecard_task_reset(req); @@ -721,8 +758,8 @@ printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); } -__initfunc(static void -ecard_probeirqhw(void)) +static void __init +ecard_probeirqhw(void) { ecard_t *ec; int found; @@ -798,8 +835,6 @@ return address; } -static const char *unknown = "*unknown*"; - static int ecard_prints(char *buffer, ecard_t *ec) { char *start = buffer; @@ -818,7 +853,7 @@ ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL); if (ec->card_desc) - strcpy(ec->card_desc, incd.d.string); + strcpy((char *)ec->card_desc, incd.d.string); } buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); @@ -872,8 +907,8 @@ * If bit 1 of the first byte of the card is set, then the * card does not exist. */ -__initfunc(static int -ecard_probe(int slot, card_type_t type)) +static int __init +ecard_probe(int slot, card_type_t type) { ecard_t **ecp; ecard_t *ec; @@ -1009,7 +1044,7 @@ return finding_pos; } -__initfunc(static void ecard_free_all(void)) +static void __init ecard_free_all(void) { ecard_t *ec, *ecn; @@ -1029,7 +1064,7 @@ * Locate all hardware - interrupt management and * actual cards. */ -__initfunc(void ecard_init(void)) +void __init ecard_init(void) { int slot; diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S --- v2.3.15/linux/arch/arm/kernel/entry-armo.S Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/kernel/entry-armo.S Mon Aug 30 18:15:11 1999 @@ -653,10 +653,10 @@ * Register switch for older 26-bit only ARMs */ ENTRY(__switch_to) - stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously + ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously /* *============================================================================= diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.3.15/linux/arch/arm/kernel/entry-armv.S Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/kernel/entry-armv.S Mon Aug 30 18:15:11 1999 @@ -16,6 +16,7 @@ #include #include #include +#include #include "../lib/constants.h" @@ -453,9 +454,13 @@ biceq r0, r0, #I_BIT @ previously msreq cpsr, r0 mov r0, r2 +#ifdef MULTI_CPU ldr r2, .LCprocfns mov lr, pc - ldr pc, [r2, #4] @ call processor specific code + ldr pc, [r2] @ call processor specific code +#else + bl cpu_data_abort +#endif mov r3, sp bl SYMBOL_NAME(do_DataAbort) ldr r0, [sp, #S_PSR] @@ -507,7 +512,9 @@ .LCirq: .word __temp_irq .LCund: .word __temp_und .LCabt: .word __temp_abt +#ifdef MULTI_CPU .LCprocfns: .word SYMBOL_NAME(processor) +#endif .LCfp: .word SYMBOL_NAME(fp_enter) #ifdef CONFIG_ALIGNMENT_TRAP .LCswi: .word SYMBOL_NAME(cr_alignment) @@ -540,9 +547,13 @@ mrs r2, cpsr @ Enable interrupts if they were bic r2, r2, #I_BIT @ previously msr cpsr, r2 +#ifdef MULTI_CPU ldr r2, .LCprocfns mov lr, pc - ldr pc, [r2, #4] @ call processor specific code + ldr pc, [r2] @ call processor specific code +#else + bl cpu_data_abort +#endif mov r3, sp adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_DataAbort) @@ -661,7 +672,7 @@ * previous and next are guaranteed not to be the same. */ ENTRY(__switch_to) - stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr stmfd sp!, {ip} @ Save cpsr_SVC ldr r2, [r1, #TSS_DOMAIN] @@ -670,7 +681,7 @@ mcr p15, 0, r2, c3, c0 @ Set domain register ldmfd sp!, {ip} msr spsr, ip @ Save tasks CPSR into SPSR for this return - ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously + ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously .section ".text.init",#alloc,#execinstr /* diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.3.15/linux/arch/arm/kernel/entry-common.S Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/entry-common.S Mon Aug 30 18:15:11 1999 @@ -2,6 +2,16 @@ /*============================================================================ * All exits to user mode from the kernel go through this code. */ + +/* + * Define to favour ARM8, ARM9 and StrongARM cpus. This says that it is + * cheaper to use two LDR instructions than a two-register LDM, if the + * latter would entail calculating an address specially. + */ +#if defined(CONFIG_CPU_SA110) +#define HARVARD_CACHE +#endif + .globl ret_from_sys_call .align 5 @@ -10,18 +20,23 @@ slow_syscall_return: add sp, sp, #4 ret_from_sys_call: +#ifdef HARVARD_CACHE + ldr r0, bh_data + ldr r4, bh_data+4 +#else adr r0, bh_data ldmia r0, {r0, r4} +#endif ldr r0, [r0] ldr r1, [r4] tst r0, r1 blne SYMBOL_NAME(do_bottom_half) ret_with_reschedule: - get_current_task r1 @ check for scheduling - ldr r0, [r1, #TSK_NEED_RESCHED] + get_current_task r5 + ldr r0, [r5, #TSK_NEED_RESCHED] + ldr r1, [r5, #TSK_SIGPENDING] teq r0, #0 bne ret_reschedule - ldr r1, [r1, #TSK_SIGPENDING] teq r1, #0 @ check for signals bne ret_signal @@ -37,8 +52,13 @@ .globl ret_from_exception ret_from_exception: +#ifdef HARVARD_CACHE + ldr r0, bh_data + ldr r1, bh_data + 4 +#else adr r0, bh_data ldmia r0, {r0, r1} +#endif ldr r0, [r0] ldr r1, [r1] mov r4, #0 diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c --- v2.3.15/linux/arch/arm/kernel/fiq.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/kernel/fiq.c Thu Aug 26 12:42:31 1999 @@ -213,7 +213,7 @@ while (current_fiq->fiq_op(current_fiq->dev_id, 0)); } -__initfunc(void init_FIQ(void)) +void __init init_FIQ(void) { no_fiq_insn = *(unsigned long *)FIQ_VECTOR; set_fs(get_fs()); diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.3.15/linux/arch/arm/kernel/head-armv.S Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/head-armv.S Mon Aug 30 18:15:12 1999 @@ -164,9 +164,16 @@ addne r0, r4, #0x3600 @ d8000000 strne r3, [r0] #endif -@ -@ The following should work on both v3 and v4 implementations -@ + b aligned_call +/* + * The following should work on both v3 and v4 implementations + * Note: it seems that if the mov pc,lr is on the next cache + * line, it doesn't get fetched before the MMU starts + * translating, which prevents the kernel from booting. + * Ensure that this never happens. + */ + .align 5 +aligned_call: mov lr, pc mov pc, r10 @ Call processor flush (returns ctrl reg) adr r5, __entry @@ -180,7 +187,7 @@ #ifdef CONFIG_ARCH_RPC /* Turn the screen red on a error - RiscPC only. */ -1: mov r0, #0x02000000 + mov r0, #0x02000000 mov r3, #0x11 orr r3, r3, r3, lsl #8 orr r3, r3, r3, lsl #16 @@ -189,6 +196,7 @@ str r3, [r0], #4 str r3, [r0], #4 #endif +1: mov r0, r0 b 1b .Lbranch: .long .Lalready_done_mmap @ Real address of routine diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c --- v2.3.15/linux/arch/arm/kernel/hw-footbridge.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/hw-footbridge.c Mon Aug 30 18:15:12 1999 @@ -44,7 +44,7 @@ static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; -__initfunc(static int ebsa_irqval(struct pci_dev *dev)) +static int __init ebsa_irqval(struct pci_dev *dev) { unsigned char pin; @@ -59,7 +59,7 @@ #ifdef CONFIG_CATS static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; -__initfunc(static int cats_irqval(struct pci_dev *dev)) +static int __init cats_irqval(struct pci_dev *dev) { if (dev->irq >= 128) return 16 + (dev->irq & 0x1f); @@ -80,7 +80,7 @@ } #endif -__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev)) +void __init pcibios_fixup_ebsa285(struct pci_dev *dev) { /* Latency timer of 32 */ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); @@ -284,7 +284,7 @@ irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL }; -__initfunc(void pcibios_init_ebsa285(void)) +void __init pcibios_init_ebsa285(void) { setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error); } @@ -592,7 +592,7 @@ /* * Initialise the Winbond W83977F chip. */ -__initfunc(static void wb977_init(void)) +static void __init wb977_init(void) { request_region(0x370, 2, "W83977AF configuration"); @@ -642,7 +642,7 @@ gpio_modify_op(GPIO_IOLOAD, 0); } -__initfunc(static void cpld_init(void)) +static void __init cpld_init(void) { unsigned long flags; @@ -662,7 +662,7 @@ #define dprintk printk #endif -#define WRITE_RWA(r,v) do { outb((r), 0x279); outb((v), 0xa79); } while (0) +#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) static inline void rwa010_unlock(void) { @@ -671,8 +671,10 @@ WRITE_RWA(2, 2); mdelay(10); - for (i = 0; i < sizeof(rwa_unlock); i++) + for (i = 0; i < sizeof(rwa_unlock); i++) { outb(rwa_unlock[i], 0x279); + udelay(10); + } } static inline void rwa010_read_ident(void) @@ -685,22 +687,22 @@ outb(1, 0x279); - mdelay(10); + mdelay(1); dprintk("Identifier: "); for (i = 0; i < 9; i++) { si[i] = 0; for (j = 0; j < 8; j++) { int bit; - mdelay(1); + udelay(250); inb(0x203); - mdelay(1); + udelay(250); bit = inb(0x203); dprintk("%02X ", bit); + bit = (bit == 0xaa) ? 1 : 0; si[i] |= bit << j; } - mdelay(10); - dprintk("%02X ", si[i]); + dprintk("(%02X) ", si[i]); } dprintk("\n"); } @@ -842,7 +844,7 @@ outb(1, 0x38b); } -__initfunc(static void rwa010_init(void)) +static void __init rwa010_init(void) { rwa010_unlock(); rwa010_read_ident(); @@ -918,7 +920,7 @@ #endif -__initfunc(void hw_init(void)) +void __init hw_init(void) { extern void register_isa_ports(unsigned int, unsigned int, unsigned int); @@ -943,9 +945,10 @@ spin_unlock_irqrestore(&gpio_lock, flags); } #endif - +#ifdef CONFIG_CATS if (machine_is_cats()) cats_hw_init(); +#endif leds_event(led_start); } diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/ioport.c linux/arch/arm/kernel/ioport.c --- v2.3.15/linux/arch/arm/kernel/ioport.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/ioport.c Mon Aug 30 18:15:12 1999 @@ -0,0 +1,27 @@ +/* + * linux/arch/arm/kernel/ioport.c + * + * IO permission support for ARM. + */ + +#include +#include +#include +#include +#include + +#include +#include + +asmlinkage int sys_iopl(unsigned long turn_on) +{ + if (turn_on && !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* + * We only support an on_off approach + */ + modify_domain(DOMAIN_IO, turn_on ? DOMAIN_MANAGER : DOMAIN_CLIENT); + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.3.15/linux/arch/arm/kernel/irq.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/irq.c Thu Aug 26 12:42:31 1999 @@ -479,7 +479,7 @@ return irq_found; } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { extern void init_dma(void); int irq; diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/isa.c linux/arch/arm/kernel/isa.c --- v2.3.15/linux/arch/arm/kernel/isa.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/isa.c Mon Aug 30 18:15:15 1999 @@ -37,8 +37,8 @@ static ctl_table ctl_bus[2] = {{CTL_BUS, "bus", NULL, 0, 0555, ctl_isa}, {0}}; -__initfunc(void -register_isa_ports(unsigned int membase, unsigned int portbase, unsigned int portshift)) +void __init +register_isa_ports(unsigned int membase, unsigned int portbase, unsigned int portshift) { isa_membase = membase; isa_portbase = portbase; diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c --- v2.3.15/linux/arch/arm/kernel/leds-footbridge.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/leds-footbridge.c Mon Aug 30 18:15:15 1999 @@ -223,8 +223,8 @@ { } -__initfunc(void -init_leds_event(led_event_t evt)) +void __init +init_leds_event(led_event_t evt) { switch (machine_arch_type) { #ifdef CONFIG_FOOTBRIDGE diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.3.15/linux/arch/arm/kernel/process.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/kernel/process.c Mon Aug 30 18:15:15 1999 @@ -9,7 +9,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#define __KERNEL_SYSCALLS__ #include #include @@ -54,16 +53,15 @@ /* * The idle loop on an ARM... */ -asmlinkage int sys_idle(void) +void cpu_idle(void) { - if (current->pid != 0) - return -EPERM; - /* endless idle loop with no priority at all */ + init_idle(); + current->priority = 0; + current->counter = -100; while (1) { if (!current->need_resched && !hlt_counter) proc_idle(); - current->policy = SCHED_YIELD; schedule(); #ifndef CONFIG_NO_PGT_CACHE check_pgt_cache(); @@ -73,7 +71,7 @@ static char reboot_mode = 'h'; -__initfunc(void reboot_setup(char *str, int *ints)) +void __init reboot_setup(char *str, int *ints) { reboot_mode = str[0]; } @@ -283,7 +281,6 @@ */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { - extern int sys_exit(int) __attribute__((noreturn)); pid_t __ret; __asm__ __volatile__( diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.3.15/linux/arch/arm/kernel/ptrace.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/kernel/ptrace.c Mon Aug 30 18:15:15 1999 @@ -130,7 +130,7 @@ val = (((signed long)val) >> shift); break; case 3: - __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + val = (val >> shift) | (val << (32 - shift)); break; } printk ("=%08lX ", val); @@ -158,7 +158,7 @@ val = (((signed long)val) >> shift); break; case 3: - __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + val = (val >> shift) | (val << (32 - shift)); break; } printk ("=%08lX ", val); diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c --- v2.3.15/linux/arch/arm/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/semaphore.c Mon Aug 30 18:15:15 1999 @@ -0,0 +1,202 @@ +/* + * ARM semaphore implementation, taken from + * + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + * + * Modified for ARM by Russell King + */ +#include + +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to aquire the semaphore, while the "sleeping" + * variable is a count of such aquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is + * protected by the semaphore spinlock. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; + +void __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + wake_up(&sem->wait); + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +int __down_interruptible(struct semaphore * sem) +{ + int retval; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers ++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + retval = -EINTR; + if (signal_pending(current)) { + sem->sleepers = 0; + if (atomic_add_negative(sleepers, &sem->count)) + break; + wake_up(&sem->wait); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. The + * "-1" is because we're still hoping to get + * the lock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + wake_up(&sem->wait); + retval = 0; + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + * + * We could have done the trylock with a + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +int __down_trylock(struct semaphore * sem) +{ + int sleepers; + + spin_lock_irq(&semaphore_lock); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers, &sem->count)) + wake_up(&sem->wait); + + spin_unlock_irq(&semaphore_lock); + return 1; +} + +/* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. + * + * r0 contains the semaphore pointer on entry. Save the C-clobbered + * registers (r0 to r3, ip and lr) except r0 in the cases where it + * is used as a return value.. + */ +asm(".align 5 + .globl __down_failed +__down_failed: + stmfd sp!, {r0 - r3, ip, lr} + bl __down + ldmfd sp!, {r0 - r3, ip, pc}"); + +asm(".align 5 + .globl __down_interruptible_failed +__down_interruptible_failed: + stmfd sp!, {r1 - r3, ip, lr} + bl __down_interruptible + ldmfd sp!, {r1 - r3, ip, pc}"); + +asm(".align 5 + .globl __down_trylock_failed +__down_trylock_failed: + stmfd sp!, {r1 - r3, ip, lr} + bl __down_trylock + ldmfd sp!, {r1 - r3, ip, pc}"); + +asm(".align 5 + .globl __up_wakeup +__up_wakeup: + stmfd sp!, {r0 - r3, ip, lr} + bl __up + ldmfd sp!, {r0 - r3, ip, pc}"); diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.3.15/linux/arch/arm/kernel/setup.c Fri Jul 23 12:20:23 1999 +++ linux/arch/arm/kernel/setup.c Mon Aug 30 18:15:15 1999 @@ -1,7 +1,7 @@ /* * linux/arch/arm/kernel/setup.c * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1999 Russell King */ /* @@ -38,24 +38,6 @@ #include #include -/* Work out which CPUs to support */ -#ifdef CONFIG_ARCH_ACORN -#define SUPPORT_CPU_ARM6 -#define SUPPORT_CPU_ARM7 -#define SUPPORT_CPU_SA110 -#else -#define SUPPORT_CPU_SA110 -#endif -#ifdef CONFIG_CPU_ARM6 -#define SUPPORT_CPU_ARM6 -#endif -#ifdef CONFIG_CPU_ARM7 -#define SUPPORT_CPU_ARM7 -#endif -#ifdef CONFIG_CPU_SA110 -#define SUPPORT_CPU_SA110 -#endif - #define MEM_SIZE (16*1024*1024) #define COMMAND_LINE_SIZE 256 @@ -63,6 +45,10 @@ #define CONFIG_CMDLINE "" #endif +#ifndef PARAMS_BASE +#define PARAMS_BASE NULL +#endif + extern void reboot_setup(char *str, int *ints); extern void fpe_init(void); extern void disable_hlt(void); @@ -76,71 +62,32 @@ orig_video_isVGA: 1, orig_video_points: 8 }; -struct processor processor; + +extern int root_mountflags; +extern int _etext, _edata, _end; + unsigned char aux_device_present; -extern const struct processor arm2_processor_functions; -extern const struct processor arm250_processor_functions; -extern const struct processor arm3_processor_functions; -extern const struct processor arm6_processor_functions; -extern const struct processor arm7_processor_functions; -extern const struct processor sa110_processor_functions; - -char elf_platform[ELF_PLATFORM_SIZE]; - -const struct armversions armidlist[] = { - /*-- Match -- --- Mask -- -- Manu -- Processor uname -m --- ELF STUFF --- - --- processor asm funcs --- */ -#if defined(CONFIG_CPU_26) - /* ARM2 fake ident */ - { 0x41560200, 0xfffffff0, "ARM/VLSI", "arm2" , "armv1" , "v1", 0, - &arm2_processor_functions }, - /* ARM250 fake ident */ - { 0x41560250, 0xfffffff0, "ARM/VLSI", "arm250" , "armv2" , "v2", HWCAP_SWP, - &arm250_processor_functions }, - /* ARM3 processors */ - { 0x41560300, 0xfffffff0, "ARM/VLSI", "arm3" , "armv2" , "v2", HWCAP_SWP, - &arm3_processor_functions }, -#elif defined(CONFIG_CPU_32) -#ifdef SUPPORT_CPU_ARM6 - /* ARM6 */ - { 0x41560600, 0xfffffff0, "ARM/VLSI", "arm6" , "armv3" , "v3", HWCAP_SWP, - &arm6_processor_functions }, - /* ARM610 */ - { 0x41560610, 0xfffffff0, "ARM/VLSI", "arm610" , "armv3" , "v3", HWCAP_SWP, - &arm6_processor_functions }, -#endif -#ifdef SUPPORT_CPU_ARM7 - /* ARM7's have a strange numbering */ - { 0x41007000, 0xffffff00, "ARM/VLSI", "arm7" , "armv3" , "v3", HWCAP_SWP, - &arm7_processor_functions }, - /* ARM710 IDs are non-standard */ - { 0x41007100, 0xfff8ff00, "ARM/VLSI", "arm710" , "armv3" , "v3", HWCAP_SWP, - &arm7_processor_functions }, -#endif -#ifdef SUPPORT_CPU_SA110 -#ifdef CONFIG_ARCH_RPC - /* Acorn RiscPC's can't handle ARMv4 half-word instructions */ - { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP, - &sa110_processor_functions }, -#else - { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP|HWCAP_HALF, - &sa110_processor_functions }, -#endif -#endif -#endif - { 0x00000000, 0x00000000, "***", "unknown", "unknown", "**", 0, NULL } -}; + char elf_platform[ELF_PLATFORM_SIZE]; +unsigned int elf_hwcap; /* * From head-armv.S */ unsigned int processor_id; unsigned int __machine_arch_type; -int armidindex; +#ifdef MULTI_CPU +struct processor processor; +#endif +#ifdef CONFIG_ARCH_ACORN +int memc_ctrl_reg; +int number_mfm_drives; +unsigned int vram_size; +#endif -extern int root_mountflags; -extern int _etext, _edata, _end; +static struct proc_info_item proc_info; +static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; +#define ENDIANNESS ((char)endian_test.l) /*------------------------------------------------------------------------- * Early initialisation routines for various configurable items in the @@ -152,8 +99,8 @@ * initial ram disk */ #ifdef CONFIG_BLK_DEV_INITRD -__initfunc(static void -check_initrd(unsigned long mem_start, unsigned long mem_end)) +static void __init +check_initrd(unsigned long mem_start, unsigned long mem_end) { if (initrd_end > mem_end) { printk ("initrd extends beyond end of memory " @@ -167,8 +114,8 @@ #define check_initrd(ms,me) #endif -__initfunc(void -setup_processor(void)) +void __init +setup_processor(void) { armidindex = 0; @@ -187,8 +134,8 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; -__initfunc(static void -setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz)) +static void __init +setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz) { char c = ' ', *to = command_line; int len = 0; @@ -233,8 +180,8 @@ *to = '\0'; } -__initfunc(static void -setup_ram(int doload, int prompt, int image_start)) +static void __init +setup_ram(int doload, int prompt, int image_start) { #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; @@ -250,8 +197,8 @@ /* * initial ram disk */ -__initfunc(static void -setup_initrd(unsigned int start, unsigned int size)) +static void __init +setup_initrd(unsigned int start, unsigned int size) { #ifdef CONFIG_BLK_DEV_INITRD if (start) { @@ -277,8 +224,8 @@ static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; #define ENDIANNESS ((char)endian_test.l) -__initfunc(void -setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init +setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { struct param_struct *params = (struct param_struct *)PARAMS_BASE; static unsigned char smptrap; @@ -298,9 +245,9 @@ setup_processor(); init_mm.start_code = TASK_SIZE; - init_mm.end_code = TASK_SIZE + (unsigned long) &_etext; - init_mm.end_data = TASK_SIZE + (unsigned long) &_edata; - init_mm.brk = TASK_SIZE + (unsigned long) &_end; + init_mm.end_code = TASK_SIZE + (unsigned long) &_etext; + init_mm.end_data = TASK_SIZE + (unsigned long) &_edata; + init_mm.brk = TASK_SIZE + (unsigned long) &_end; /* * Add your machine dependencies here @@ -313,6 +260,11 @@ params = NULL; break; + case MACH_TYPE_RISCPC: + /* RiscPC can't handle half-word loads and stores */ + elf_hwcap &= ~HWCAP_HALF; + break; + case MACH_TYPE_EBSA285: if (params) { ORIG_X = params->u1.s.video_x; @@ -416,7 +368,7 @@ from = params->commandline; } else { - ROOT_DEV = 0x00ff; + ROOT_DEV = to_kdev_t(0x00ff); setup_ram(1, 1, 0); setup_initrd(0, 0); @@ -442,9 +394,6 @@ check_initrd(*memory_start_p, memory_end); - sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, ENDIANNESS); - sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, ENDIANNESS); - #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -463,7 +412,7 @@ "unknown", "Nexus-FTV/PCI", "EBSA285", - "Corel-NetWinder", + "Rebel-NetWinder", "Chalice-CATS", "unknown-TBOX", "co-EBSA285", @@ -477,12 +426,13 @@ int len; len = sprintf(buffer, - "Processor\t: %s %s rev %d\n" + "Processor\t: %s %s rev %d (%s)\n" "BogoMips\t: %lu.%02lu\n" "Hardware\t: %s\n", - armidlist[armidindex].manu, - armidlist[armidindex].name, + proc_info.manufacturer, + proc_info.cpu_name, (int)processor_id & 15, + elf_platform, (loops_per_sec+2500) / 500000, ((loops_per_sec+2500) / 5000) % 100, machine_desc[machine_arch_type]); diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.3.15/linux/arch/arm/kernel/time.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/kernel/time.c Thu Aug 26 12:42:31 1999 @@ -149,7 +149,7 @@ sti(); } -__initfunc(void time_init(void)) +void __init time_init(void) { xtime.tv_usec = 0; diff -u --recursive --new-file v2.3.15/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.3.15/linux/arch/arm/kernel/traps.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/kernel/traps.c Mon Aug 30 18:15:16 1999 @@ -292,9 +292,7 @@ case 2: /* sys_cacheflush */ #ifdef CONFIG_CPU_32 /* r0 = start, r1 = length, r2 = flags */ - processor.u.armv3v4._flush_cache_area(regs->ARM_r0, - regs->ARM_r1, - 1); + cpu_flush_cache_area(regs->ARM_r0, regs->ARM_r1, 1); #endif break; diff -u --recursive --new-file v2.3.15/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.3.15/linux/arch/arm/lib/Makefile Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/lib/Makefile Mon Aug 30 18:15:16 1999 @@ -6,7 +6,7 @@ L_TARGET := lib.a L_OBJS := backtrace.o bitops.o checksum.o delay.o memcpy.o \ - semaphore.o string.o system.o uaccess.o + string.o system.o uaccess.o ifeq ($(PROCESSOR),armo) L_OBJS += uaccess-armo.o diff -u --recursive --new-file v2.3.15/linux/arch/arm/lib/semaphore.S linux/arch/arm/lib/semaphore.S --- v2.3.15/linux/arch/arm/lib/semaphore.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/lib/semaphore.S Wed Dec 31 16:00:00 1969 @@ -1,34 +0,0 @@ -/* - * linux/arch/arm/lib/semaphore.S - * - * Idea from i386 code, Copyright Linus Torvalds. - * Converted for ARM by Russell King - */ -#include -#include - -/* - * The semaphore operations have a special calling sequence - * that allows us to keep the distruption of the main code - * path to a minimum. These routines save and restore the - * registers that will be touched by __down etc. - */ -ENTRY(__down_failed) - stmfd sp!, {r0 - r3, ip, lr} - bl SYMBOL_NAME(__down) - LOADREGS(fd, sp!, {r0 - r3, ip, pc}) - -ENTRY(__down_interruptible_failed) - stmfd sp!, {r1 - r3, ip, lr} - bl SYMBOL_NAME(__down_interruptible) - LOADREGS(fd, sp!, {r1 - r3, ip, pc}) - -ENTRY(__down_trylock_failed) - stmfd sp!, {r1 - r3, ip, lr} - bl SYMBOL_NAME(__down_trylock) - LOADREGS(fd, sp!, {r1 - r3, ip, pc}) - -ENTRY(__up_wakeup) - stmfd sp!, {r0 - r3, ip, lr} - bl SYMBOL_NAME(__up) - LOADREGS(fd, sp!, {r0 - r3, ip, pc}) diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.3.15/linux/arch/arm/mm/Makefile Sat May 8 11:06:56 1999 +++ linux/arch/arm/mm/Makefile Mon Aug 30 18:15:16 1999 @@ -7,26 +7,30 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -all: lib first_rule +O_TARGET := mm.o +O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o -O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o - -ifeq ($(PROCESSOR),armo) - O_OBJS += proc-arm2,3.o +ifeq ($(CONFIG_CPU_26),y) + O_OBJS += proc-arm2,3.o endif -ifeq ($(PROCESSOR),armv) - O_OBJS += mm-$(MACHINE).o proc-arm6,7.o proc-sa110.o ioremap.o +ifeq ($(CONFIG_CPU_32),y) + ifeq ($(CONFIG_CPU_ARM6),y) + P_OBJS += proc-arm6,7.o + endif + ifeq ($(CONFIG_CPU_ARM7),y) + P_OBJS += proc-arm6,7.o + endif + ifeq ($(CONFIG_CPU_SA110),y) + P_OBJS += proc-sa110.o + endif + O_OBJS += mm-$(MACHINE).o ioremap.o $(sort $(P_OBJS)) endif include $(TOPDIR)/Rules.make %.o: %.S $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< - -.PHONY: lib -lib:; @$(MAKE) -C ../lib constants.h # Special dependencies fault-armv.o: fault-common.c diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.3.15/linux/arch/arm/mm/fault-armv.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/mm/fault-armv.c Mon Aug 30 18:15:16 1999 @@ -205,6 +205,7 @@ return len; } +#ifdef CONFIG_SYSCTL /* * This needs to be done after sysctl_init, otherwise sys/ * will be overwritten. @@ -219,6 +220,9 @@ e->read_proc = proc_alignment_read; } +__initcall(alignment_init); +#endif + static int do_alignment_exception(struct pt_regs *regs) { @@ -405,8 +409,25 @@ asmlinkage void do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) { - if (user_mode(regs)) + if (user_mode(regs)) { + if (addr == regs->ARM_pc) { + static int first = 1; + if (first) { + /* + * I want statistical information on this problem! + */ + printk(KERN_ERR "Buggy processor (%08X), " + "trying to continue.\n" + "Please send contents of /proc/cpuinfo " + "and this message to linux@arm.linux.org.uk", + fsr); + first = 0; + } + return; + } + error_code |= FAULT_CODE_USER; + } #define DIE(signr,nam)\ force_sig(signr, current);\ diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.3.15/linux/arch/arm/mm/init.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/mm/init.c Thu Aug 26 12:42:31 1999 @@ -123,7 +123,7 @@ /* * paging_init() sets up the page tables... */ -__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) { extern unsigned long free_area_init(unsigned long, unsigned long); @@ -156,7 +156,7 @@ * memory is free. This is done after various parts of the system have * claimed their memory after the kernel image. */ -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { extern void sound_init(void); int codepages = 0; diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c --- v2.3.15/linux/arch/arm/mm/ioremap.c Sun Jul 25 13:45:25 1999 +++ linux/arch/arm/mm/ioremap.c Mon Aug 30 18:15:18 1999 @@ -143,7 +143,7 @@ return (void *) (offset + (char *)addr); } -void iounmap(void *addr) +void __iounmap(void *addr) { return vfree((void *) (PAGE_MASK & (unsigned long) addr)); } diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.3.15/linux/arch/arm/mm/mm-armv.c Sat May 8 11:06:57 1999 +++ linux/arch/arm/mm/mm-armv.c Thu Aug 26 12:42:31 1999 @@ -25,7 +25,7 @@ #define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0])) -__initfunc(unsigned long setup_io_pagetables(unsigned long start_mem)) +unsigned long __init setup_io_pagetables(unsigned long start_mem) { const struct mapping *mp; int i; diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c --- v2.3.15/linux/arch/arm/mm/mm-rpc.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/mm/mm-rpc.c Mon Aug 30 18:15:19 1999 @@ -68,8 +68,8 @@ return phys + rambank[bank].phys_offset; } -__initfunc(void -init_dram_banks(struct param_struct *params)) +void __init +init_dram_banks(struct param_struct *params) { unsigned int bank; unsigned int bytes = 0; diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S --- v2.3.15/linux/arch/arm/mm/proc-arm2,3.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/mm/proc-arm2,3.S Mon Aug 30 18:15:19 1999 @@ -1,14 +1,14 @@ /* - * linux/arch/arm/mm/arm2,3.S: MMU functions for ARM2,3 + * linux/arch/arm/mm/proc-arm2,3.S: MMU functions for ARM2,3 * - * (C) 1997 Russell King + * (C) 1997-1999 Russell King * * These are the low level assembler for performing cache * and memory functions on ARM2, ARM250 and ARM3 processors. */ #include - #include +#include #include "../lib/constants.h" /* @@ -424,17 +424,18 @@ movs pc, lr +armvlsi_name: .asciz "ARM/VLSI" +_arm2_name: .asciz "arm2" +_arm250_name: .asciz "arm250" +_arm3_name: .asciz "arm3" + + .section ".text.init", #alloc, #execinstr /* * Purpose : Function pointers used to access above functions - all calls * come through these */ -_arm2_name: - .ascii "arm2\0" - .align - .globl SYMBOL_NAME(arm2_processor_functions) SYMBOL_NAME(arm2_processor_functions): - .word _arm2_name @ 0 .word _arm2_switch_to @ 4 .word _arm2_3_data_abort @ 8 .word _arm2_3_check_bugs @ 12 @@ -448,13 +449,8 @@ .word SYMBOL_NAME(abort) @ 40 .word _arm2_xchg_4 @ 44 -_arm250_name: - .ascii "arm250\0" - .align - .globl SYMBOL_NAME(arm250_processor_functions) SYMBOL_NAME(arm250_processor_functions): - .word _arm250_name @ 0 .word _arm2_switch_to @ 4 .word _arm2_3_data_abort @ 8 .word _arm2_3_check_bugs @ 12 @@ -468,13 +464,8 @@ .word SYMBOL_NAME(abort) @ 40 .word _arm3_xchg_4 @ 44 -_arm3_name: - .ascii "arm3\0" - .align - .globl SYMBOL_NAME(arm3_processor_functions) SYMBOL_NAME(arm3_processor_functions): - .word _arm3_name @ 0 .word _arm3_switch_to @ 4 .word _arm2_3_data_abort @ 8 .word _arm2_3_check_bugs @ 12 @@ -487,4 +478,48 @@ .word _arm3_xchg_1 @ 36 .word SYMBOL_NAME(abort) @ 40 .word _arm3_xchg_4 @ 44 + +cpu_arm2_info: + .long armvlsi_name + .long _arm2_name + +cpu_arm250_info: + .long armvlsi_name + .long _arm250_name + +cpu_arm3_info: + .long armvlsi_name + .long _arm3_name + +arm2_arch_name: .asciz "armv1" +arm3_arch_name: .asciz "armv2" +arm2_elf_name: .asciz "v1" +arm3_elf_name: .asciz "v2" + .align + + .section ".proc.info", #alloc + + .long 0x41560200 + .long 0xfffffff0 + .long arm2_arch_name + .long arm2_elf_name + .long 0 + .long cpu_arm2_info + .long SYMBOL_NAME(arm2_processor_functions) + + .long 0x41560250 + .long 0xfffffff0 + .long arm3_arch_name + .long arm3_elf_name + .long 0 + .long cpu_arm250_info + .long SYMBOL_NAME(arm250_processor_functions) + + .long 0x41560300 + .long 0xfffffff0 + .long arm3_arch_name + .long arm3_elf_name + .long 0 + .long cpu_arm3_info + .long SYMBOL_NAME(arm3_processor_functions) diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.3.15/linux/arch/arm/mm/proc-arm6,7.S Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/mm/proc-arm6,7.S Mon Aug 30 18:15:19 1999 @@ -1,13 +1,14 @@ /* - * linux/arch/arm/mm/arm6.S: MMU functions for ARM6 + * linux/arch/arm/mm/proc-arm6,7.S: MMU functions for ARM6 * - * (C) 1997 Russell King + * (C) 1997-1999 Russell King * * These are the low level assembler for performing cache and TLB * functions on the ARM6 & ARM7. */ #include #include +#include #include "../lib/constants.h" /* @@ -20,10 +21,24 @@ * * Purpose : Flush all cache lines */ -_arm6_7_flush_cache: +ENTRY(cpu_arm6_flush_cache_all) +ENTRY(cpu_arm7_flush_cache_all) +ENTRY(cpu_arm6_flush_cache_area) +ENTRY(cpu_arm7_flush_cache_area) +ENTRY(cpu_arm6_flush_cache_entry) +ENTRY(cpu_arm7_flush_cache_entry) +ENTRY(cpu_arm6_flush_icache_area) +ENTRY(cpu_arm7_flush_icache_area) +ENTRY(cpu_arm6_cache_wback_area) +ENTRY(cpu_arm7_cache_wback_area) +ENTRY(cpu_arm6_cache_purge_area) +ENTRY(cpu_arm7_cache_purge_area) mov r0, #0 mcr p15, 0, r0, c7, c0, 0 @ flush cache -_arm6_7_null: +ENTRY(cpu_arm6_clean_cache_area) +ENTRY(cpu_arm7_clean_cache_area) +ENTRY(cpu_arm6_flush_ram_page) +ENTRY(cpu_arm7_flush_ram_page) mov pc, lr /* @@ -31,7 +46,8 @@ * * Purpose : flush all TLB entries in all caches */ -_arm6_7_flush_tlb_all: +ENTRY(cpu_arm6_flush_tlb_all) +ENTRY(cpu_arm7_flush_tlb_all) mov r0, #0 mcr p15, 0, r0, c5, c0, 0 @ flush TLB mov pc, lr @@ -45,7 +61,8 @@ * * Purpose : flush a TLB entry */ -_arm6_7_flush_tlb_area: +ENTRY(cpu_arm6_flush_tlb_area) +ENTRY(cpu_arm7_flush_tlb_area) 1: mcr p15, 0, r0, c6, c0, 0 @ flush TLB add r0, r0, #4096 cmp r0, r1 @@ -71,7 +88,7 @@ msg: .ascii "DA*%p=%p\n\0" .align -_arm6_data_abort: +ENTRY(cpu_arm6_data_abort) ldr r4, [r0] @ read instruction causing problem mov r2, r4, lsr #19 @ r2 b1 = L and r1, r4, #15 << 24 @@ -102,7 +119,7 @@ bl SYMBOL_NAME(panic) Lstop: b Lstop -_arm7_data_abort: +ENTRY(cpu_arm7_data_abort) ldr r4, [r0] @ read instruction causing problem mov r2, r4, lsr #19 @ r2 b1 = L and r1, r4, #15 << 24 @@ -297,12 +314,15 @@ * * Notes : This processor does not require these */ -_arm6_7_check_bugs: +ENTRY(cpu_arm6_check_bugs) +ENTRY(cpu_arm7_check_bugs) mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip -_arm6_7_proc_init: -_arm6_7_proc_fin: +ENTRY(cpu_arm6_proc_init) +ENTRY(cpu_arm7_proc_init) +ENTRY(cpu_arm6_proc_fin) +ENTRY(cpu_arm7_proc_fin) mov pc, lr /* @@ -311,7 +331,8 @@ * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. */ -_arm6_7_set_pgd: +ENTRY(cpu_arm6_set_pgd) +ENTRY(cpu_arm7_set_pgd) mov r1, #0 mcr p15, 0, r1, c7, c0, 0 @ flush cache mcr p15, 0, r0, c2, c0, 0 @ update page table ptr @@ -326,7 +347,8 @@ * * Purpose : Set a PMD and flush it out of any WB cache */ -_arm6_set_pmd: and r2, r1, #11 +ENTRY(cpu_arm6_set_pmd) + and r2, r1, #11 teq r2, #1 teqne r2, #9 teqne r2, #10 @@ -342,7 +364,8 @@ * * Purpose : Set a PMD and flush it out of any WB cache */ -_arm7_set_pmd: tst r1, #3 +ENTRY(cpu_arm7_set_pmd) + tst r1, #3 orrne r1, r1, #16 @ Updatable bit is always set on ARM7 str r1, [r0] mov pc, lr @@ -354,7 +377,8 @@ * Purpose : Set a PTE and flush it out of any WB cache */ .align 5 -_arm6_7_set_pte: +ENTRY(cpu_arm6_set_pte) +ENTRY(cpu_arm7_set_pte) str r1, [r0], #-1024 @ linux version bic r2, r1, #0xff0 @@ -381,7 +405,9 @@ * * Notes : This sets up everything for a reset */ -_arm6_7_reset: mrs r1, cpsr +ENTRY(cpu_arm6_reset) +ENTRY(cpu_arm7_reset) + mrs r1, cpsr orr r1, r1, #F_BIT|I_BIT msr cpsr, r1 mov r0, #0 @@ -390,62 +416,145 @@ mov r1, #F_BIT | I_BIT | 3 mov pc, lr +cpu_armvlsi_name: + .asciz "ARM/VLSI" +cpu_arm6_name: .asciz "arm6" +cpu_arm610_name: + .asciz "arm610" +cpu_arm7_name: .asciz "arm7" +cpu_arm710_name: + .asciz "arm710" + .align + + .section ".text.init", #alloc, #execinstr + /* * Purpose : Function pointers used to access above functions - all calls * come through these */ -_arm6_name: .ascii "arm6\0" - .align - + .type arm6_processor_functions, #object ENTRY(arm6_processor_functions) - .word _arm6_name @ 0 - .word _arm6_data_abort @ 4 - .word _arm6_7_check_bugs @ 8 - .word _arm6_7_proc_init @ 12 - .word _arm6_7_proc_fin @ 16 - - .word _arm6_7_flush_cache @ 20 - .word _arm6_7_flush_cache @ 24 - .word _arm6_7_flush_cache @ 28 - .word _arm6_7_null @ 32 - .word _arm6_7_flush_cache @ 36 - .word _arm6_7_flush_tlb_all @ 40 - .word _arm6_7_flush_tlb_area @ 44 - .word _arm6_7_set_pgd @ 48 - .word _arm6_set_pmd @ 52 - .word _arm6_7_set_pte @ 56 - .word _arm6_7_reset @ 60 - .word _arm6_7_flush_cache @ 64 - - .word _arm6_7_flush_cache @ 68 - .word _arm6_7_flush_cache @ 72 + .word cpu_arm6_data_abort + .word cpu_arm6_check_bugs + .word cpu_arm6_proc_init + .word cpu_arm6_proc_fin + .word cpu_arm6_flush_cache_all + .word cpu_arm6_flush_cache_area + .word cpu_arm6_flush_cache_entry + .word cpu_arm6_clean_cache_area + .word cpu_arm6_flush_ram_page + .word cpu_arm6_flush_tlb_all + .word cpu_arm6_flush_tlb_area + .word cpu_arm6_set_pgd + .word cpu_arm6_set_pmd + .word cpu_arm6_set_pte + .word cpu_arm6_reset + .word cpu_arm6_flush_icache_area + .word cpu_arm6_cache_wback_area + .word cpu_arm6_cache_purge_area + .size arm6_processor_functions, . - arm6_processor_functions /* * Purpose : Function pointers used to access above functions - all calls * come through these */ -_arm7_name: .ascii "arm7\0" + .type arm7_processor_functions, #object +ENTRY(arm7_processor_functions) + .word cpu_arm7_data_abort + .word cpu_arm7_check_bugs + .word cpu_arm7_proc_init + .word cpu_arm7_proc_fin + .word cpu_arm7_flush_cache_all + .word cpu_arm7_flush_cache_area + .word cpu_arm7_flush_cache_entry + .word cpu_arm7_clean_cache_area + .word cpu_arm7_flush_ram_page + .word cpu_arm7_flush_tlb_all + .word cpu_arm7_flush_tlb_area + .word cpu_arm7_set_pgd + .word cpu_arm7_set_pmd + .word cpu_arm7_set_pte + .word cpu_arm7_reset + .word cpu_arm7_flush_icache_area + .word cpu_arm7_cache_wback_area + .word cpu_arm7_cache_purge_area + .size arm7_processor_functions, . - arm7_processor_functions + + .type cpu_arm6_info, #object +cpu_arm6_info: + .long cpu_armvlsi_name + .long cpu_arm6_name + .size cpu_arm6_info, . - cpu_arm6_info + + .type cpu_arm610_info, #object +cpu_arm610_info: + .long cpu_armvlsi_name + .long cpu_arm610_name + .size cpu_arm610_info, . - cpu_Arm610_info + + .type cpu_arm7_info, #object +cpu_arm7_info: + .long cpu_armvlsi_name + .long cpu_arm7_name + .size cpu_arm7_info, . - cpu_arm7_info + + .type cpu_arm710_info, #object +cpu_arm710_info: + .long cpu_armvlsi_name + .long cpu_arm710_name + .size cpu_arm710_info, . - cpu_arm710_info + + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv3" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v3" + .size cpu_elf_name, . - cpu_elf_name .align -ENTRY(arm7_processor_functions) - .word _arm7_name @ 0 - .word _arm7_data_abort @ 4 - .word _arm6_7_check_bugs @ 8 - .word _arm6_7_proc_init @ 12 - .word _arm6_7_proc_fin @ 16 - - .word _arm6_7_flush_cache @ 20 - .word _arm6_7_flush_cache @ 24 - .word _arm6_7_flush_cache @ 28 - .word _arm6_7_null @ 32 - .word _arm6_7_flush_cache @ 36 - .word _arm6_7_flush_tlb_all @ 40 - .word _arm6_7_flush_tlb_area @ 44 - .word _arm6_7_set_pgd @ 48 - .word _arm7_set_pmd @ 52 - .word _arm6_7_set_pte @ 56 - .word _arm6_7_reset @ 60 - .word _arm6_7_flush_cache @ 64 + .section ".proc.info", #alloc - .word _arm6_7_flush_cache @ 68 - .word _arm6_7_flush_cache @ 72 + .type __arm6_proc_info, #object +__arm6_proc_info: + .long 0x41560600 + .long 0xfffffff0 + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP + .long cpu_arm6_info + .long arm6_processor_functions + .size __arm6_proc_info, . - __arm6_proc_info + + .type __arm610_proc_info, #object +__arm610_proc_info: + .long 0x41560610 + .long 0xfffffff0 + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP + .long cpu_arm610_info + .long arm6_processor_functions + .size __arm610_proc_info, . - __arm610_proc_info + + .type __arm7_proc_info, #object +__arm7_proc_info: + .long 0x41007000 + .long 0xffffff00 + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP + .long cpu_arm7_info + .long arm7_processor_functions + .size __arm7_proc_info, . - __arm7_proc_info + + .type __arm710_proc_info, #object +__arm710_proc_info: + .long 0x41007100 + .long 0xfff8ff00 + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP + .long cpu_arm710_info + .long arm7_processor_functions + .size __arm710_proc_info, . - __arm710_proc_info diff -u --recursive --new-file v2.3.15/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.3.15/linux/arch/arm/mm/proc-sa110.S Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/mm/proc-sa110.S Mon Aug 30 18:15:19 1999 @@ -1,13 +1,15 @@ /* - * linux/arch/arm/mm/sa110.S: MMU functions for SA110 + * linux/arch/arm/mm/proc-sa110.S: MMU functions for SA110 * - * (C) 1997 Russell King + * (C) 1997-1999 Russell King * * These are the low level assembler for performing cache and TLB * functions on the sa110. */ +#include #include #include +#include #include #include "../lib/constants.h" @@ -25,9 +27,9 @@ * Purpose : Flush all cache lines */ .align 5 -_sa110_flush_cache_all: @ preserves r0 +ENTRY(cpu_sa110_flush_cache_all) @ preserves r0 mov r2, #1 -_sa110_flush_cache_all_r2: +cpu_sa110_flush_cache_all_r2: ldr r3, =Lclean_switch ldr ip, =FLUSH_BASE ldr r1, [r3] @@ -53,10 +55,10 @@ * Purpose : clean & flush all cache lines associated with this area of memory */ .align 5 -_sa110_flush_cache_area: +ENTRY(cpu_sa110_flush_cache_area) sub r3, r1, r0 cmp r3, #MAX_AREA_SIZE - bgt _sa110_flush_cache_all_r2 + bgt cpu_sa110_flush_cache_all_r2 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c6, 1 @ flush D entry add r0, r0, #32 @@ -78,11 +80,11 @@ * written out to memory (for DMA) */ .align 5 -_sa110_cache_wback_area: +ENTRY(cpu_sa110_cache_wback_area) sub r3, r1, r0 cmp r3, #MAX_AREA_SIZE mov r2, #0 - bgt _sa110_flush_cache_all_r2 + bgt cpu_sa110_flush_cache_all_r2 bic r0, r0, #31 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #32 @@ -103,7 +105,7 @@ * start and/or end address are not cache aligned. */ .align 5 -_sa110_cache_purge_area: +ENTRY(cpu_sa110_cache_purge_area) tst r0, #31 bic r0, r0, #31 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -121,7 +123,7 @@ * Purpose : clean & flush an entry */ .align 5 -_sa110_flush_cache_entry: +ENTRY(cpu_sa110_flush_cache_entry) mov r1, #0 mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r1, c7, c10, 4 @ drain WB @@ -134,7 +136,7 @@ * Purpose : Ensure that physical memory reflects cache at this location * for page table purposes. */ -_sa110_clean_cache_area: +ENTRY(cpu_sa110_clean_cache_area) 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) add r0, r0, #32 subs r1, r1, #32 @@ -143,25 +145,24 @@ /* * Function: sa110_flush_ram_page (unsigned long page) - * Params : address Area start address - * : size size of area - * : flags b0 = I cache as well - * Purpose : clean & flush all cache lines associated with this area of memory + * Params : page Area start address + * Purpose : clean all cache lines associated with this area of memory */ .align 5 -_sa110_flush_ram_page: +ENTRY(cpu_sa110_flush_ram_page) mov r1, #4096 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c6, 1 @ flush D entry add r0, r0, #32 mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c6, 1 @ flush D entry add r0, r0, #32 - subs r1, r1, #64 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #32 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #32 + subs r1, r1, #128 bne 1b mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c7, c5, 0 @ flush I cache mov pc, lr /* @@ -169,7 +170,7 @@ * Purpose : flush all TLB entries in all caches */ .align 5 -_sa110_flush_tlb_all: +ENTRY(cpu_sa110_flush_tlb_all) mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c8, c7, 0 @ flush I & D tlbs @@ -179,11 +180,11 @@ * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags) * Params : address Area start address * : end Area end address - * : flags b0 = I cache as well + * : flags b0 = I-TLB as well * Purpose : flush a TLB entry */ .align 5 -_sa110_flush_tlb_area: +ENTRY(cpu_sa110_flush_tlb_area) mov r3, #0 mcr p15, 0, r3, c7, c10, 4 @ drain WB 1: cmp r0, r1 @@ -198,7 +199,7 @@ mov pc, lr .align 5 -_sa110_flush_icache_area: +ENTRY(cpu_sa110_flush_icache_area) 1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry add r0, r0, #32 subs r1, r1, #32 @@ -217,7 +218,7 @@ * : r2 != 0 if writing */ .align 5 -_sa110_data_abort: +ENTRY(cpu_sa110_data_abort) ldr r2, [r0] @ read instruction causing problem mrc p15, 0, r0, c6, c0, 0 @ get FAR mov r2, r2, lsr #19 @ b1 = L @@ -235,7 +236,7 @@ * the new. */ .align 5 -_sa110_set_pgd: +ENTRY(cpu_sa110_set_pgd) ldr r3, =Lclean_switch ldr r2, [r3] ands r2, r2, #1 @@ -261,7 +262,8 @@ * Purpose : Set a PMD and flush it out */ .align 5 -_sa110_set_pmd: str r1, [r0] +ENTRY(cpu_sa110_set_pmd) + str r1, [r0] mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 4 @ drain WB (TLB bypasses WB) mov pc, lr @@ -273,7 +275,8 @@ * Purpose : Set a PTE and flush it out */ .align 5 -_sa110_set_pte: str r1, [r0], #-1024 @ linux version +ENTRY(cpu_sa110_set_pte) + str r1, [r0], #-1024 @ linux version eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY @@ -302,26 +305,27 @@ * : sa110_proc_fin (void) * Notes : This processor does not require these */ -_sa110_check_bugs: +ENTRY(cpu_sa110_check_bugs) mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip -_sa110_proc_init: -_sa110_proc_fin: +ENTRY(cpu_sa110_proc_init) +ENTRY(cpu_sa110_proc_fin) mov pc, lr /* * Function: sa110_reset * Notes : This sets up everything for a reset */ -_sa110_reset: mrs r1, cpsr +ENTRY(cpu_sa110_reset) + mrs r1, cpsr orr r1, r1, #F_BIT | I_BIT msr cpsr, r1 stmfd sp!, {r1, lr} mov r2, #1 - bl _sa110_flush_cache_all - bl _sa110_flush_tlb_all + bl cpu_sa110_flush_cache_all + bl cpu_sa110_flush_tlb_all mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches mrc p15, 0, r0, c1, c0, 0 @ ctrl register bic r0, r0, #0x1800 @@ -331,29 +335,60 @@ * Purpose : Function pointers used to access above functions - all calls * come through these */ -_sa110_name: .ascii "sa110\0" + +cpu_manu_name: .asciz "Intel" +ENTRY(cpu_sa110_name) + .asciz "sa110" .align + .section ".text.init", #alloc, #execinstr + + .type sa110_processor_functions, #object ENTRY(sa110_processor_functions) - .word _sa110_name @ 0 - .word _sa110_data_abort @ 4 - .word _sa110_check_bugs @ 8 - .word _sa110_proc_init @ 12 - .word _sa110_proc_fin @ 16 - - .word _sa110_flush_cache_all @ 20 - .word _sa110_flush_cache_area @ 24 - .word _sa110_flush_cache_entry @ 28 - .word _sa110_clean_cache_area @ 32 - .word _sa110_flush_ram_page @ 36 - .word _sa110_flush_tlb_all @ 40 - .word _sa110_flush_tlb_area @ 44 - - .word _sa110_set_pgd @ 48 - .word _sa110_set_pmd @ 52 - .word _sa110_set_pte @ 56 - .word _sa110_reset @ 60 - .word _sa110_flush_icache_area @ 64 + .word cpu_sa110_data_abort + .word cpu_sa110_check_bugs + .word cpu_sa110_proc_init + .word cpu_sa110_proc_fin + .word cpu_sa110_flush_cache_all + .word cpu_sa110_flush_cache_area + .word cpu_sa110_flush_cache_entry + .word cpu_sa110_clean_cache_area + .word cpu_sa110_flush_ram_page + .word cpu_sa110_flush_tlb_all + .word cpu_sa110_flush_tlb_area + .word cpu_sa110_set_pgd + .word cpu_sa110_set_pmd + .word cpu_sa110_set_pte + .word cpu_sa110_reset + .word cpu_sa110_flush_icache_area + .word cpu_sa110_cache_wback_area + .word cpu_sa110_cache_purge_area + + .size sa110_processor_functions, . - sa110_processor_functions + + .type cpu_sa110_info, #object +cpu_sa110_info: + .long cpu_manu_name + .long cpu_sa110_name + .size cpu_sa110_info, . - cpu_sa110_info + + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align - .word _sa110_cache_wback_area @ 68 - .word _sa110_cache_purge_area @ 72 + .section ".proc.info", #alloc, #execinstr + .type __sa110_proc_info,#object +__sa110_proc_info: + .long 0x4401a100 + .long 0xfffffff0 + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF + .long cpu_sa110_info + .long sa110_processor_functions + .size __sa110_proc_info, . - __sa110_proc_info diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/config.h linux/arch/arm/nwfpe/config.h --- v2.3.15/linux/arch/arm/nwfpe/config.h Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/config.h Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/double_cpdo.c linux/arch/arm/nwfpe/double_cpdo.c --- v2.3.15/linux/arch/arm/nwfpe/double_cpdo.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/double_cpdo.c Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/extended_cpdo.c linux/arch/arm/nwfpe/extended_cpdo.c --- v2.3.15/linux/arch/arm/nwfpe/extended_cpdo.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/extended_cpdo.c Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpa11.c linux/arch/arm/nwfpe/fpa11.c --- v2.3.15/linux/arch/arm/nwfpe/fpa11.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpa11.c Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpa11.h linux/arch/arm/nwfpe/fpa11.h --- v2.3.15/linux/arch/arm/nwfpe/fpa11.h Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpa11.h Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpa11_cpdo.c linux/arch/arm/nwfpe/fpa11_cpdo.c --- v2.3.15/linux/arch/arm/nwfpe/fpa11_cpdo.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpa11_cpdo.c Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpa11_cpdt.c linux/arch/arm/nwfpe/fpa11_cpdt.c --- v2.3.15/linux/arch/arm/nwfpe/fpa11_cpdt.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpa11_cpdt.c Mon Aug 30 18:15:19 1999 @@ -1,9 +1,9 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 (c) Philip Blundell, 1998 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpa11_cprt.c linux/arch/arm/nwfpe/fpa11_cprt.c --- v2.3.15/linux/arch/arm/nwfpe/fpa11_cprt.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpa11_cprt.c Mon Aug 30 18:15:19 1999 @@ -1,9 +1,9 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 (c) Philip Blundell, 1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c --- v2.3.15/linux/arch/arm/nwfpe/fpmodule.c Mon Jul 5 20:35:17 1999 +++ linux/arch/arm/nwfpe/fpmodule.c Mon Aug 30 18:15:19 1999 @@ -1,9 +1,9 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 (c) Philip Blundell, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 @@ -62,7 +62,7 @@ int fp_printk(const char *,...); void fp_send_sig(unsigned long sig, PTASK p, int priv); #if LINUX_VERSION_CODE > 0x20115 -MODULE_AUTHOR("Scott Bambrough "); +MODULE_AUTHOR("Scott Bambrough "); MODULE_DESCRIPTION("NWFPE floating point emulator"); #endif @@ -91,7 +91,7 @@ { static const char szTitle[] = "<4>NetWinder Floating Point Emulator "; static const char szVersion[] = "V0.94.1 "; - static const char szCopyright[] = "(c) 1998 Corel Computer Corp.\n"; + static const char szCopyright[] = "(c) 1998-1999 Rebel.com\n"; C_SYMBOL_NAME(fp_printk)(szTitle); C_SYMBOL_NAME(fp_printk)(szVersion); C_SYMBOL_NAME(fp_printk)(szCopyright); diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpmodule.h linux/arch/arm/nwfpe/fpmodule.h --- v2.3.15/linux/arch/arm/nwfpe/fpmodule.h Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpmodule.h Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpopcode.c linux/arch/arm/nwfpe/fpopcode.c --- v2.3.15/linux/arch/arm/nwfpe/fpopcode.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpopcode.c Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpopcode.h linux/arch/arm/nwfpe/fpopcode.h --- v2.3.15/linux/arch/arm/nwfpe/fpopcode.h Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpopcode.h Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/fpsr.h linux/arch/arm/nwfpe/fpsr.h --- v2.3.15/linux/arch/arm/nwfpe/fpsr.h Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpsr.h Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/nwfpe/single_cpdo.c linux/arch/arm/nwfpe/single_cpdo.c --- v2.3.15/linux/arch/arm/nwfpe/single_cpdo.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/single_cpdo.c Mon Aug 30 18:15:19 1999 @@ -1,8 +1,8 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 diff -u --recursive --new-file v2.3.15/linux/arch/arm/vmlinux-armo.lds linux/arch/arm/vmlinux-armo.lds --- v2.3.15/linux/arch/arm/vmlinux-armo.lds Sun Sep 6 10:44:47 1998 +++ linux/arch/arm/vmlinux-armo.lds Wed Dec 31 16:00:00 1969 @@ -1,61 +0,0 @@ -/* ld script to make ARM Linux kernel - * taken from the i386 version by Russell King - * Written by Martin Mares - */ -OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - _text = .; /* Text and read-only data */ - .text : { - *(.text) - *(.fixup) - *(.gnu.warning) - } = 0x9090 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } - .kstrtab : { *(.kstrtab) } - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - _etext = .; /* End of text section */ - - . = ALIGN(8192); - .data : { /* Data */ - *(.init.task) - *(.data) - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - . = ALIGN(32768); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(32768); - __init_end = .; - - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } - _end = . ; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } -} diff -u --recursive --new-file v2.3.15/linux/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in --- v2.3.15/linux/arch/arm/vmlinux-armo.lds.in Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/vmlinux-armo.lds.in Mon Aug 30 18:15:19 1999 @@ -0,0 +1,64 @@ +/* ld script to make ARM Linux kernel + * taken from the i386 version by Russell King + * Written by Martin Mares + */ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = TEXTADDR; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + . = ALIGN(8192); + .data : { /* Data */ + *(.init.task) + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(32768); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + __proc_info_begin = .; + .proc.info : { *(.proc.info) } + __proc_info_end = .; + .data.init : { *(.data.init) } + . = ALIGN(32768); + __init_end = .; + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --recursive --new-file v2.3.15/linux/arch/arm/vmlinux-armv.lds linux/arch/arm/vmlinux-armv.lds --- v2.3.15/linux/arch/arm/vmlinux-armv.lds Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/vmlinux-armv.lds Wed Dec 31 16:00:00 1969 @@ -1,75 +0,0 @@ -/* ld script to make ARM Linux kernel - * taken from the i386 version by Russell King - * Written by Martin Mares - */ -OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - _text = .; /* Text and read-only data */ - .text : { } /* Set text start address */ - - __init_begin = .; /* Init code and data */ - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(4096); - __init_end = .; - - __ebsa285_begin = .; - .text.ebsa285 : { *(.text.ebsa285) } - .data.ebsa285 : { *(.data.ebsa285) } - . = ALIGN(4096); - __ebsa285_end = .; - - __netwinder_begin = .; - .text.netwinder : { *(.text.netwinder) } - .data.netwinder : { *(.data.netwinder) } - . = ALIGN(4096); - __netwinder_end = .; - - .text.real : { /* Real text segment */ - *(.text) - *(.fixup) - *(.gnu.warning) - } - - .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } - .kstrtab : { *(.kstrtab) } - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - _etext = .; /* End of text section */ - - . = ALIGN(8192); - .data : { /* Data */ - *(.init.task) - *(.data) - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } - _end = . ; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } -} diff -u --recursive --new-file v2.3.15/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in --- v2.3.15/linux/arch/arm/vmlinux-armv.lds.in Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/vmlinux-armv.lds.in Mon Aug 30 18:15:19 1999 @@ -0,0 +1,85 @@ +/* ld script to make ARM Linux kernel + * taken from the i386 version by Russell King + * Written by Martin Mares + */ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = TEXTADDR; + _text = .; /* Text and read-only data */ + .text : { } /* Set text start address */ + + __init_begin = .; /* Init code and data */ + .text.init : { *(.text.init) } + __proc_info_begin = .; + .proc.info : { *(.proc.info) } + __proc_info_end = .; + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + + __ebsa285_begin = .; + .text.ebsa285 : { *(.text.ebsa285) } + .data.ebsa285 : { *(.data.ebsa285) } + . = ALIGN(4096); + __ebsa285_end = .; + + __netwinder_begin = .; + .text.netwinder : { *(.text.netwinder) } + .data.netwinder : { *(.data.netwinder) } + . = ALIGN(4096); + __netwinder_end = .; + + .text.real : { /* Real text segment */ + *(.text) + *(.fixup) + *(.gnu.warning) + } + + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + . = ALIGN(8192); + .data : { /* Data */ + *(.init.task) + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --recursive --new-file v2.3.15/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v2.3.15/linux/arch/i386/boot/Makefile Sat Jan 2 10:27:52 1999 +++ linux/arch/i386/boot/Makefile Mon Aug 30 10:18:40 1999 @@ -51,7 +51,7 @@ setup.o: setup.s $(AS86) -o $@ $< -setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h +setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bsetup: bsetup.o @@ -60,7 +60,7 @@ bsetup.o: bsetup.s $(AS86) -o $@ $< -bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h +bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bootsect: bootsect.o diff -u --recursive --new-file v2.3.15/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.3.15/linux/arch/i386/boot/setup.S Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/boot/setup.S Mon Aug 30 10:47:02 1999 @@ -37,6 +37,7 @@ #include #include #include +#include ! Signature words to ensure LILO loaded us right #define SIG1 0xAA55 @@ -59,7 +60,7 @@ entry start start: - jmp start_of_setup + jmp trampoline ! ------------------------ start of header -------------------------------- ! ! SETUP-header, must start at CS:2 (old 0x9020:2) @@ -119,6 +120,8 @@ heap_end_ptr: .word modelist+1024 ! space from here (exclusive) down to ! end of setup code can be used by setup ! for local heap purposes. +trampoline: call start_of_setup + .space 1024 ! ------------------------ end of header ---------------------------------- start_of_setup: @@ -245,37 +248,91 @@ loader_ok: ! Get memory size (extended mem, kB) + xor eax, eax + mov dword ptr [0x1e0], eax #ifndef STANDARD_MEMORY_BIOS_CALL - push ebx - xor ebx,ebx ! preload new memory slot with 0k - mov [0x1e0], ebx + mov byte ptr [E820NR], al - mov ax,#0xe801 - int 0x15 - jc oldstylemem +! Try three different memory detection schemes. First, try +! e820h, which lets us assemble a memory map, then try e801h, +! which returns a 32-bit memory size, and finally 88h, which +! returns 0-64m + +! method E820H: +! the memory map from hell. e820h returns memory classified into +! a whole bunch of different types, and allows memory holes and +! everything. We scan through this memory map and build a list +! of the first 32 memory areas, which we return at [E820MAP]. +! + +meme820: + mov edx, #0x534d4150 ! ascii `SMAP' + xor ebx, ebx ! continuation counter + + mov di, #E820MAP ! point into the whitelist + ! so we can have the bios + ! directly write into it. + +jmpe820: + mov eax, #0x0000e820 ! e820, upper word zeroed + mov ecx, #20 ! size of the e820rec + + push ds ! data record. + pop es + int 0x15 ! make the call + jc bail820 ! fall to e801 if it fails + + cmp eax, #0x534d4150 ! check the return is `SMAP' + jne bail820 ! fall to e801 if it fails -! Memory size is in 1 k chunksizes, to avoid confusing loadlin. -! We store the 0xe801 memory size in a completely different place, +! cmp dword ptr [16+di], #1 ! is this usable memory? +! jne again820 + + ! If this is usable memory, we save it by simply advancing di by + ! sizeof(e820rec). + ! +good820: + mov al, byte ptr [E820NR] ! up to 32 good entries, that is + cmp al, #E820MAX + jnl bail820 + inc byte ptr [E820NR] + mov ax, di + add ax, #20 + mov di, ax + +again820: + cmp ebx, #0 ! check to see if ebx is + jne jmpe820 ! set to EOF + +bail820: + + +! method E801H: +! memory size is in 1k chunksizes, to avoid confusing loadlin. +! we store the 0xe801 memory size in a completely different place, ! because it will most likely be longer than 16 bits. ! (use 1e0 because that's what Larry Augustine uses in his ! alternative new memory detection scheme, and it's sensible ! to write everything into the same place.) - and ebx, #0xffff ! clear sign extend - shl ebx, 6 ! and go from 64k to 1k chunks - mov [0x1e0],ebx ! store extended memory size - - and eax, #0xffff ! clear sign extend - add [0x1e0],eax ! and add lower memory into total size. - - ! and fall into the old memory detection code to populate the - ! compatibility slot. +meme801: + + mov ax,#0xe801 + int 0x15 + jc mem88 + + and edx, #0xffff ! clear sign extend + shl edx, 6 ! and go from 64k to 1k chunks + mov [0x1e0],edx ! store extended memory size + + and ecx, #0xffff ! clear sign extend + add [0x1e0],ecx ! and add lower memory into total size. + +! Ye Olde Traditional Methode. Returns the memory size (up to 16mb or +! 64mb, depending on the bios) in ax. +mem88: -oldstylemem: - pop ebx -#else - mov dword ptr [0x1e0], #0 #endif mov ah,#0x88 int 0x15 diff -u --recursive --new-file v2.3.15/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.15/linux/arch/i386/config.in Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/config.in Thu Aug 26 13:44:03 1999 @@ -4,6 +4,8 @@ # mainmenu_name "Linux Kernel Configuration" +define_bool CONFIG_X86 y + mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -54,6 +56,7 @@ mainmenu_option next_comment comment 'General setup' +bool 'BIGMEM support' CONFIG_BIGMEM bool 'Networking support' CONFIG_NET bool 'PCI support' CONFIG_PCI if [ "$CONFIG_PCI" = "y" ]; then diff -u --recursive --new-file v2.3.15/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.15/linux/arch/i386/defconfig Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/defconfig Tue Aug 31 11:16:45 1999 @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # +CONFIG_X86=y # # Code maturity level options @@ -37,6 +38,7 @@ # # General setup # +# CONFIG_BIGMEM is not set CONFIG_NET=y CONFIG_PCI=y # CONFIG_PCI_GOBIOS is not set @@ -176,6 +178,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -276,7 +279,7 @@ # CONFIG_HAMRADIO is not set # -# IrDA subsystem support +# IrDA (infrared) support # # CONFIG_IRDA is not set @@ -325,6 +328,8 @@ # # CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver @@ -378,8 +383,11 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_SMD_DISKLABEL is not set -# CONFIG_SGI_DISKLABEL is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.15/linux/arch/i386/kernel/apm.c Thu Aug 12 11:53:22 1999 +++ linux/arch/i386/kernel/apm.c Tue Aug 31 11:30:47 1999 @@ -1077,7 +1077,7 @@ return -EAGAIN; add_wait_queue(&apm_waitqueue, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (queue_empty(as) && !signal_pending(current)) { schedule(); goto repeat; diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.3.15/linux/arch/i386/kernel/bios32.c Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/kernel/bios32.c Tue Aug 31 11:02:26 1999 @@ -760,6 +760,36 @@ #endif /* + * Assign new address to PCI resource. We hope our resource information + * is complete. On the PC, we don't re-assign resources unless we are + * forced to do so. + * + * Expects start=0, end=size-1, flags=resource type. + */ + +int __init pcibios_assign_resource(struct pci_dev *dev, int i) +{ + struct resource *r = &dev->resource[i]; + struct resource *pr = pci_find_parent_resource(dev, r); + unsigned long size = r->end + 1; + + if (!pr) + return -EINVAL; + if (r->flags & IORESOURCE_IO) { + if (size > 0x100) + return -EFBIG; + if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) + return -EBUSY; + } else { + if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) + return -EBUSY; + } + if (i < 6) + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start); + return 0; +} + +/* * Several BIOS'es forget to assign addresses to I/O ranges. Try to fix it. */ @@ -792,12 +822,13 @@ } else { u32 try; - if (allocate_resource(&ioport_resource, r, size, 0x1000, ~0, 1024)) { + r->start = 0; + r->end = size - 1; + if (pcibios_assign_resource(dev, idx)) { printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O space for device %s.\n", size, dev->name); return; } - printk("PCI: Assigning I/O space %04lx-%04lx to device %s\n", r->start, r->end, dev->name); - pci_write_config_dword(dev, reg, r->start | PCI_BASE_ADDRESS_SPACE_IO); + printk("PCI: Assigned I/O space %04lx-%04lx to device %s\n", r->start, r->end, dev->name); pci_read_config_dword(dev, reg, &try); if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) { r->start = 0; @@ -819,12 +850,12 @@ struct resource *r = &dev->resource[PCI_ROM_RESOURCE]; unsigned long rom_size = r->end - r->start + 1; - if (allocate_resource(&iomem_resource, r, rom_size, 0xf0000000, ~0, rom_size) < 0) { + r->start = 0; + r->end = rom_size - 1; + if (pcibios_assign_resource(dev, PCI_ROM_RESOURCE)) printk(KERN_ERR "PCI: Unable to find free space for expansion ROM of device %s (0x%lx bytes)\n", dev->name, rom_size); - r->start = 0; - r->end = rom_size - 1; - } else { + else { DBG("PCI: Assigned address %08lx to expansion ROM of %s (0x%lx bytes)\n", r->start, dev->name, rom_size); pci_write_config_dword(dev, reg, r->start | PCI_ROM_ADDRESS_ENABLE); r->flags |= PCI_ROM_ADDRESS_ENABLE; @@ -947,7 +978,8 @@ if (found) { printk("PCI: Discovered primary peer bus %02x\n", n); b = pci_scan_bus(n, ops, NULL); - n = b->subordinate; + if (b) + n = b->subordinate; } n++; } @@ -979,33 +1011,6 @@ pci_probe |= PCI_NO_PEER_FIXUP; } -static void __init pci_fixup_i440bx(struct pci_dev *d) -{ -#if 0 /* Temporarily disabled FIXME */ - /* - * i440BX/ZX -- Occupy the AGP bridge windows. - */ - u16 a, b; - u8 u, v; - pci_read_config_byte(d, 0x1c, &u); - pci_read_config_byte(d, 0x1d, &v); - if (v >= u) { - a = u<<8; - b = ((v-u)<<8) + 0x100; - occupy_region(a, a+b, b, 1, &d->dev); - } - for (u = 0; u < 2; u++) { - pci_read_config_word(d, 0x20+(u*4), &a); - pci_read_config_word(d, 0x22+(u*4), &b); - if (b >= a) { - u32 m = a<<16; - u32 n = ((b-a)<<16) + 0x100000; - occupy_mem_region(m, m+n, n, 1, &d->dev); - } - } -#endif -} - static void __init pci_fixup_umc_ide(struct pci_dev *d) { /* @@ -1021,7 +1026,6 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, pci_fixup_i440bx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, { 0 } }; @@ -1031,20 +1035,28 @@ * we try to fix up anything. */ -static void __init pcibios_claim_resources(void) +static void __init pcibios_claim_resources(struct pci_bus *bus) { struct pci_dev *dev; int idx; - for (dev=pci_devices; dev; dev=dev->next) - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { - struct resource *r = &dev->resource[idx]; - if (!r->start) - continue; - if (request_resource((r->flags & PCI_BASE_ADDRESS_SPACE_IO) ? &ioport_resource : &iomem_resource, r) < 0) - printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); - /* We probably should disable the region, shouldn't we? */ + while (bus) { + for (dev=bus->devices; dev; dev=dev->sibling) + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + struct resource *pr; + if (!r->start) + continue; + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); + /* We probably should disable the region, shouldn't we? */ + } } + if (bus->children) + pcibios_claim_resources(bus->children); + bus = bus->next; + } } /* @@ -1190,7 +1202,7 @@ if (!(pci_probe & PCI_NO_PEER_FIXUP)) pcibios_fixup_peer_bridges(); - pcibios_claim_resources(); + pcibios_claim_resources(pci_root); pcibios_fixup_devices(); #ifdef CONFIG_PCI_BIOS diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.3.15/linux/arch/i386/kernel/i386_ksyms.c Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/kernel/i386_ksyms.c Thu Aug 26 12:47:12 1999 @@ -88,6 +88,7 @@ EXPORT_SYMBOL(global_bh_count); EXPORT_SYMBOL(global_bh_lock); EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(i386_bh_lock); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.3.15/linux/arch/i386/kernel/io_apic.c Wed Aug 18 11:11:15 1999 +++ linux/arch/i386/kernel/io_apic.c Tue Aug 31 11:23:03 1999 @@ -319,7 +319,7 @@ /* * Find a specific PCI IRQ entry. - * Not an initfunc, possibly needed by modules + * Not an __init, possibly needed by modules */ static int __init pin_2_irq(int idx, int apic, int pin); int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin) @@ -836,7 +836,7 @@ } /* - * Not an initfunc, needed by the reboot code + * Not an __init, needed by the reboot code */ void init_pic_mode(void) { diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.15/linux/arch/i386/kernel/irq.c Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/kernel/irq.c Mon Aug 30 21:44:16 1999 @@ -71,11 +71,11 @@ * system. We never hold this lock when we call the actual * IRQ handler. */ -spinlock_t irq_controller_lock ={0}; +spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; /* * Special irq handlers. @@ -125,10 +125,13 @@ return p - buf; } + /* * Global interrupt locks for SMP. Allow interrupts to come in on any * CPU, yet make cli/sti act globally to protect critical regions.. */ +spinlock_t i386_bh_lock = SPIN_LOCK_UNLOCKED; + #ifdef __SMP__ unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; @@ -637,16 +640,22 @@ /* Found it - now remove it from the list of entries */ *pp = action->next; - if (irq_desc[irq].action) - break; - irq_desc[irq].status |= IRQ_DISABLED; - irq_desc[irq].handler->shutdown(irq); - break; + if (!irq_desc[irq].action) { + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->shutdown(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + while (irq_desc[irq].status & IRQ_INPROGRESS) + barrier(); + kfree(action); + return; } printk("Trying to free free IRQ%d\n",irq); - break; + spin_unlock_irqrestore(&irq_controller_lock,flags); + return; } - spin_unlock_irqrestore(&irq_controller_lock,flags); } /* diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/semaphore.c linux/arch/i386/kernel/semaphore.c --- v2.3.15/linux/arch/i386/kernel/semaphore.c Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/kernel/semaphore.c Mon Aug 30 09:56:12 1999 @@ -49,8 +49,8 @@ { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&sem->wait, &wait); + tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; + add_wait_queue_exclusive(&sem->wait, &wait); spin_lock_irq(&semaphore_lock); sem->sleepers++; @@ -63,28 +63,28 @@ */ if (!atomic_add_negative(sleepers - 1, &sem->count)) { sem->sleepers = 0; - wake_up(&sem->wait); break; } sem->sleepers = 1; /* us - see -1 above */ spin_unlock_irq(&semaphore_lock); schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; + tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; spin_lock_irq(&semaphore_lock); } spin_unlock_irq(&semaphore_lock); remove_wait_queue(&sem->wait, &wait); tsk->state = TASK_RUNNING; + wake_up(&sem->wait); } int __down_interruptible(struct semaphore * sem) { - int retval; + int retval = 0; struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue(&sem->wait, &wait); + tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE; + add_wait_queue_exclusive(&sem->wait, &wait); spin_lock_irq(&semaphore_lock); sem->sleepers ++; @@ -98,12 +98,10 @@ * it has contention. Just correct the count * and exit. */ - retval = -EINTR; if (signal_pending(current)) { + retval = -EINTR; sem->sleepers = 0; - if (atomic_add_negative(sleepers, &sem->count)) - break; - wake_up(&sem->wait); + atomic_add(sleepers, &sem->count); break; } @@ -114,8 +112,6 @@ * the lock. */ if (!atomic_add_negative(sleepers - 1, &sem->count)) { - wake_up(&sem->wait); - retval = 0; sem->sleepers = 0; break; } @@ -123,12 +119,13 @@ spin_unlock_irq(&semaphore_lock); schedule(); - tsk->state = TASK_INTERRUPTIBLE; + tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE; spin_lock_irq(&semaphore_lock); } spin_unlock_irq(&semaphore_lock); tsk->state = TASK_RUNNING; remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); return retval; } @@ -142,7 +139,7 @@ */ int __down_trylock(struct semaphore * sem) { - int retval, sleepers; + int sleepers; spin_lock_irq(&semaphore_lock); sleepers = sem->sleepers + 1; diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.15/linux/arch/i386/kernel/setup.c Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/kernel/setup.c Mon Aug 30 10:54:05 1999 @@ -17,6 +17,14 @@ * * IDT Winchip tweaks, misc clean ups. * Dave Jones , August 1999 + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + * + * Better detection of Centaur/IDT WinChip models. + * Bart Hartgers , August 1999. + * + * Memory region support + * David Parsons , July-August 1999 */ /* @@ -42,6 +50,7 @@ #ifdef CONFIG_BLK_DEV_RAM #include #endif +#include #include #include #include @@ -51,6 +60,7 @@ #include #include #include +#include /* * Machine setup.. @@ -84,6 +94,8 @@ unsigned char table[0]; }; +struct e820map e820 = { 0 }; + unsigned char aux_device_present; #ifdef CONFIG_BLK_DEV_RAM @@ -103,6 +115,8 @@ #define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) #define EXT_MEM_K (*(unsigned short *) (PARAM+2)) #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0)) +#define E820_MAP_NR (*(char*) (PARAM+E820NR)) +#define E820_MAP ((unsigned long *) (PARAM+E820MAP)) #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40)) #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0)) @@ -345,12 +359,80 @@ } } +unsigned long __init memparse(char *ptr, char **retptr) +{ + unsigned long ret; + + ret = simple_strtoul(ptr, retptr, 0); + + if (**retptr == 'K' || **retptr == 'k') { + ret <<= 10; + (*retptr)++; + } + else if (**retptr == 'M' || **retptr == 'm') { + ret <<= 20; + (*retptr)++; + } + return ret; +} /* memparse */ + + +void __init add_memory_region(unsigned long start, + unsigned long size, int type) +{ + int x = e820.nr_map; + + if (x == E820MAX) { + printk("Ooops! Too many entries in the memory map!\n"); + return; + } + + e820.map[x].addr = start; + e820.map[x].size = size; + e820.map[x].type = type; + e820.nr_map++; +} /* add_memory_region */ + + +#define LOWMEMSIZE() ((*(unsigned short *)__va(0x413)) * 1024) + + +void __init setup_memory_region(void) +{ + /* + * If we're lucky and live on a modern system, the setup code + * will have given us a memory map that we can use to properly + * set up memory. If we aren't, we'll fake a memory map. + */ + if (E820_MAP_NR) { + /* got a memory map; copy it into a safe place. + */ + e820.nr_map = E820_MAP_NR; + if (e820.nr_map > E820MAX) + e820.nr_map = E820MAX; + memcpy(e820.map, E820_MAP, e820.nr_map * sizeof e820.map[0]); + } + else { + /* otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + unsigned long mem_size; + + mem_size = (ALT_MEM_K < EXT_MEM_K) ? EXT_MEM_K : ALT_MEM_K; + + add_memory_region(0, LOWMEMSIZE(), 1); + add_memory_region(HIGH_MEMORY, mem_size << 10, 1); + } +} /* setup_memory_region */ + + void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { unsigned long memory_start, memory_end; char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; int i; + int usermem=0; #ifdef CONFIG_VISWS visws_get_board_type_and_rev(); @@ -367,24 +449,14 @@ BIOS_revision = SYS_DESC_TABLE.table[2]; } aux_device_present = AUX_DEVICE_INFO; - memory_end = (1<<20) + (EXT_MEM_K<<10); -#ifndef STANDARD_MEMORY_BIOS_CALL - { - unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10); - /* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */ - if (memory_alt_end > memory_end) - memory_end = memory_alt_end; - } -#endif - - ram_resources[1].end = memory_end-1; - memory_end &= PAGE_MASK; #ifdef CONFIG_BLK_DEV_RAM rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif + setup_memory_region(); + if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; memory_start = (unsigned long) &_end; @@ -405,8 +477,10 @@ for (;;) { /* * "mem=nopentium" disables the 4MB page tables. - * "mem=XXX[kKmM]" overrides the BIOS-reported - * memory size + * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM + * to , overriding the bios size. + * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from + * to +, overriding the bios size. */ if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") { if (to != command_line) to--; @@ -414,16 +488,29 @@ from += 9+4; boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE; } else { - memory_end = simple_strtoul(from+4, &from, 0); - if ( *from == 'K' || *from == 'k' ) { - memory_end = memory_end << 10; - from++; - } else if ( *from == 'M' || *from == 'm' ) { - memory_end = memory_end << 20; - from++; + /* If the user specifies memory size, we + * blow away any automatically generated + * size + */ + unsigned long start_at, mem_size; + + if (usermem == 0) { + /* first time in: zap the whitelist + * and reinitialize it with the + * standard low-memory region. + */ + e820.nr_map = 0; + usermem = 1; + add_memory_region(0, LOWMEMSIZE(), 1); } - if (memory_end > ram_resources[1].end) - ram_resources[1].end = memory_end-1; + mem_size = memparse(from+4, &from); + if (*from == '@') + start_at = memparse(from+1,&from); + else { + start_at = HIGH_MEMORY; + mem_size -= HIGH_MEMORY; + } + add_memory_region(start_at, mem_size, 1); } } c = *(from++); @@ -436,23 +523,47 @@ *to = '\0'; *cmdline_p = command_line; - /* Request the standard RAM and ROM resources - they eat up PCI memory space */ - request_resource(&iomem_resource, ram_resources+0); - request_resource(&iomem_resource, ram_resources+1); - request_resource(&iomem_resource, ram_resources+2); - request_resource(ram_resources+1, &code_resource); - request_resource(ram_resources+1, &data_resource); - probe_roms(); - #define VMALLOC_RESERVE (128 << 20) /* 128MB for vmalloc and initrd */ #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) + memory_end = 0; + for (i=0; i < e820.nr_map; i++) { + /* RAM? */ + if (e820.map[i].type == 1) { + unsigned long end = e820.map[i].addr + e820.map[i].size; + + if (end > memory_end) + memory_end = end; + } + } + memory_end &= PAGE_MASK; + ram_resources[1].end = memory_end-1; + +#ifdef CONFIG_BIGMEM + bigmem_start = bigmem_end = memory_end; +#endif if (memory_end > MAXMEM) { +#ifdef CONFIG_BIGMEM +#define MAXBIGMEM ((unsigned long)(~(VMALLOC_RESERVE-1))) + bigmem_start = MAXMEM; + bigmem_end = (memory_end < MAXBIGMEM) ? memory_end : MAXBIGMEM; +#endif memory_end = MAXMEM; +#ifdef CONFIG_BIGMEM + printk(KERN_NOTICE "%ldMB BIGMEM available.\n", + (bigmem_end-bigmem_start)>>20); +#else printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20); +#endif } +#if defined(CONFIG_BIGMEM) && defined(BIGMEM_DEBUG) + else { + memory_end -= memory_end/4; + bigmem_start = memory_end; + } +#endif memory_end += PAGE_OFFSET; *memory_start_p = memory_start; @@ -478,6 +589,17 @@ } #endif + /* + * Request the standard RAM and ROM resources - + * they eat up PCI memory space + */ + request_resource(&iomem_resource, ram_resources+0); + request_resource(&iomem_resource, ram_resources+1); + request_resource(&iomem_resource, ram_resources+2); + request_resource(ram_resources+1, &code_resource); + request_resource(ram_resources+1, &data_resource); + probe_roms(); + /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < STANDARD_IO_RESOURCES; i++) request_resource(&ioport_resource, standard_io_resources+i); @@ -769,6 +891,98 @@ return; } +static void __init centaur_model(struct cpuinfo_x86 *c) +{ + enum { + ECX8=1<<1, + EIERRINT=1<<2, + DPM=1<<3, + DMCE=1<<4, + DSTPCLK=1<<5, + ELINEAR=1<<6, + DSMC=1<<7, + DTLOCK=1<<8, + EDCTLB=1<<8, + EMMX=1<<9, + DPDC=1<<11, + EBRPRED=1<<12, + DIC=1<<13, + DDC=1<<14, + DNA=1<<15, + ERETSTK=1<<16, + E2MMX=1<<19, + EAMD3D=1<<20, + }; + + char *name; + u32 fcr_set=0; + u32 fcr_clr=0; + u32 lo,hi,newlo; + u32 aa,bb,cc,dd; + + switch(c->x86_model) { + case 4: + name="C6"; + fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK; + fcr_clr=DPDC; + break; + case 8: + switch(c->x86_mask) { + default: + name="2"; + break; + case 7 ... 9: + name="2A"; + break; + case 10 ... 15: + name="2B"; + break; + } + fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; + fcr_clr=DPDC; + break; + case 9: + name="3"; + fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; + fcr_clr=DPDC; + break; + case 10: + name="4"; + /* no info on the WC4 yet */ + break; + default: + name="??"; + } + + /* get FCR */ + rdmsr(0x107, lo, hi); + + newlo=(lo|fcr_set) & (~fcr_clr); + + if (newlo!=lo) { + printk("Centaur FCR was 0x%X now 0x%X\n", lo, newlo ); + wrmsr(0x107, newlo, hi ); + } else { + printk("Centaur FCR is 0x%X\n",lo); + } + + /* Emulate MTRRs using Centaur's MCR. */ + c->x86_capability |= X86_FEATURE_MTRR; + /* Report CX8 */ + c->x86_capability |= X86_FEATURE_CX8; + /* Set 3DNow! on Winchip 2 and above. */ + if (c->x86_model >=8) + c->x86_capability |= X86_FEATURE_AMD3D; + /* See if we can find out some more. */ + cpuid(0x80000000,&aa,&bb,&cc,&dd); + if (aa>=0x80000005) { /* Yes, we can. */ + cpuid(0x80000005,&aa,&bb,&cc,&dd); + /* Add L1 data and code cache sizes. */ + c->x86_cache_size = (cc>>24)+(dd>>24); + } + sprintf( c->x86_model_id, "WinChip %s", name ); +} + void __init get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -826,9 +1040,6 @@ { X86_VENDOR_UMC, 4, { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, - { X86_VENDOR_CENTAUR, 5, - { NULL, NULL, NULL, NULL, "C6", NULL, NULL, NULL, "C6-2", NULL, NULL, - NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_NEXGEN, 5, { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, @@ -855,6 +1066,11 @@ if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) return; + + if (c->x86_vendor == X86_VENDOR_CENTAUR) { + centaur_model(c); + return; + } if (c->cpuid_level > 0 && c->x86_vendor == X86_VENDOR_INTEL) { @@ -981,24 +1197,6 @@ if (c->x86_mask || c->cpuid_level>=0) printk(" stepping %02x\n", c->x86_mask); - - if(c->x86_vendor == X86_VENDOR_CENTAUR) { - u32 hv,lv; - rdmsr(0x107, lv, hv); - printk("Centaur FSR was 0x%X ",lv); - lv|=(1<<1 | 1<<2 | 1<<7); - /* lv|=(1<<6); - may help too if the board can cope */ - printk("now 0x%X\n", lv); - wrmsr(0x107, lv, hv); - /* Emulate MTRRs using Centaur's MCR. */ - c->x86_capability |= X86_FEATURE_MTRR; - - /* Set 3DNow! on Winchip 2 and above. */ - if (c->x86_model >=8) - c->x86_capability |= X86_FEATURE_AMD3D; - - c->x86_capability |=X86_FEATURE_CX8; - } } /* diff -u --recursive --new-file v2.3.15/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c --- v2.3.15/linux/arch/i386/kernel/visws_apic.c Sun Jul 11 15:09:29 1999 +++ linux/arch/i386/kernel/visws_apic.c Tue Aug 31 11:23:03 1999 @@ -102,7 +102,7 @@ /* - * Not an initfunc, needed by the reboot code + * Not an __init, needed by the reboot code */ void init_pic_mode(void) { diff -u --recursive --new-file v2.3.15/linux/arch/i386/math-emu/div_Xsig.S linux/arch/i386/math-emu/div_Xsig.S --- v2.3.15/linux/arch/i386/math-emu/div_Xsig.S Thu Oct 5 06:30:43 1995 +++ linux/arch/i386/math-emu/div_Xsig.S Fri Aug 27 10:18:17 1999 @@ -55,7 +55,7 @@ Local storage in a static area: Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 */ - .align 2,0 + .align 4,0 FPU_accum_3: .long 0 FPU_accum_2: diff -u --recursive --new-file v2.3.15/linux/arch/i386/math-emu/reg_round.S linux/arch/i386/math-emu/reg_round.S --- v2.3.15/linux/arch/i386/math-emu/reg_round.S Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/reg_round.S Fri Aug 27 10:18:17 1999 @@ -95,7 +95,7 @@ /* Not re-entrant, so we can gain speed by putting local storage in a static area: */ .data - .align 2,0 + .align 4,0 FPU_bits_lost: .byte 0 FPU_denormal: diff -u --recursive --new-file v2.3.15/linux/arch/i386/math-emu/reg_u_div.S linux/arch/i386/math-emu/reg_u_div.S --- v2.3.15/linux/arch/i386/math-emu/reg_u_div.S Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/reg_u_div.S Fri Aug 27 10:18:17 1999 @@ -52,7 +52,7 @@ Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 Overflow flag: ovfl_flag */ - .align 2,0 + .align 4,0 FPU_accum_3: .long 0 FPU_accum_2: diff -u --recursive --new-file v2.3.15/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile --- v2.3.15/linux/arch/i386/mm/Makefile Fri Nov 1 01:56:43 1996 +++ linux/arch/i386/mm/Makefile Thu Aug 26 12:34:55 1999 @@ -10,4 +10,8 @@ O_TARGET := mm.o O_OBJS := init.o fault.o ioremap.o extable.o +ifeq ($(CONFIG_BIGMEM),y) +O_OBJS += bigmem.o +endif + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/i386/mm/bigmem.c linux/arch/i386/mm/bigmem.c --- v2.3.15/linux/arch/i386/mm/bigmem.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/mm/bigmem.c Thu Aug 26 12:34:55 1999 @@ -0,0 +1,33 @@ +/* + * BIGMEM IA32 code and variables. + * + * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de + * Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de + */ + +#include +#include + +unsigned long bigmem_start, bigmem_end; + +/* NOTE: fixmap_init alloc all the fixmap pagetables contigous on the + physical space so we can cache the place of the first one and move + around without checking the pgd every time. */ +pte_t *kmap_pte; +pgprot_t kmap_prot; + +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + +void __init kmap_init(void) +{ + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); + + kmap_prot = PAGE_KERNEL; + if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) + pgprot_val(kmap_prot) |= _PAGE_GLOBAL; +} diff -u --recursive --new-file v2.3.15/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.3.15/linux/arch/i386/mm/init.c Thu Aug 26 13:05:34 1999 +++ linux/arch/i386/mm/init.c Mon Aug 30 10:47:02 1999 @@ -2,6 +2,8 @@ * linux/arch/i386/mm/init.c * * Copyright (C) 1995 Linus Torvalds + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 */ #include @@ -20,6 +22,7 @@ #ifdef CONFIG_BLK_DEV_INITRD #include #endif +#include #include #include @@ -27,8 +30,10 @@ #include #include #include +#include static unsigned long totalram = 0; +static unsigned long totalbig = 0; extern void show_net_buffers(void); extern unsigned long init_smp_mappings(unsigned long); @@ -150,6 +155,7 @@ { int i,free = 0,total = 0,reserved = 0; int shared = 0, cached = 0; + int bigmem = 0; printk("Mem-info:\n"); show_free_areas(); @@ -157,6 +163,8 @@ i = max_mapnr; while (i-- > 0) { total++; + if (PageBIGMEM(mem_map+i)) + bigmem++; if (PageReserved(mem_map+i)) reserved++; else if (PageSwapCache(mem_map+i)) @@ -167,6 +175,7 @@ shared += page_count(mem_map+i) - 1; } printk("%d pages of RAM\n",total); + printk("%d pages of BIGMEM\n",bigmem); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); @@ -238,7 +247,7 @@ * This routines also unmaps the page at virtual kernel address 0, so * that we can trap those pesky NULL-reference errors in the kernel. */ -__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) { pgd_t * pg_dir; pte_t * pg_table; @@ -315,7 +324,12 @@ #endif local_flush_tlb(); +#ifndef CONFIG_BIGMEM return free_area_init(start_mem, end_mem); +#else + kmap_init(); /* run after fixmap_init */ + return free_area_init(start_mem, bigmem_end + PAGE_OFFSET); +#endif } /* @@ -324,7 +338,7 @@ * before and after the test are here to work-around some nasty CPU bugs. */ -__initfunc(void test_wp_bit(void)) +void __init test_wp_bit(void) { unsigned char tmp_reg; unsigned long old = pg0[0]; @@ -353,7 +367,7 @@ printk(".\n"); } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { unsigned long start_low_mem = PAGE_SIZE; int codepages = 0; @@ -361,11 +375,22 @@ int datapages = 0; int initpages = 0; unsigned long tmp; - unsigned long endbase; + unsigned long addr; + int i, avail; end_mem &= PAGE_MASK; +#ifdef CONFIG_BIGMEM + bigmem_start = PAGE_ALIGN(bigmem_start); + bigmem_end &= PAGE_MASK; +#endif high_memory = (void *) end_mem; +#ifndef CONFIG_BIGMEM max_mapnr = num_physpages = MAP_NR(end_mem); +#else + max_mapnr = num_physpages = PHYSMAP_NR(bigmem_end); + /* cache the bigmem_mapnr */ + bigmem_mapnr = PHYSMAP_NR(bigmem_start); +#endif /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); @@ -385,23 +410,43 @@ #endif start_mem = PAGE_ALIGN(start_mem); - /* - * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000. - * They seem to have done something stupid with the floppy - * controller as well.. - * The amount of available base memory is in WORD 40:13. Except - * when it isn't. + /* walk the whitelist, unreserving good memory */ - endbase = PAGE_OFFSET + 0x9f000; - while (start_low_mem < endbase) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); - start_low_mem += PAGE_SIZE; - } + for (avail = i = 0; i < e820.nr_map; i++) { + if (e820.map[i].type != 1) /* not usable memory */ + continue; + printk("memory region: %luk @ %08lx\n", + ((long)(e820.map[i].size)) / 1024, + (long)(e820.map[i].addr) ); + for (addr=PAGE_ALIGN(((long)(e820.map[i].addr)))+PAGE_OFFSET, + tmp = 0; + tmp < (unsigned long)(e820.map[i].size); + tmp += PAGE_SIZE, + addr += PAGE_SIZE) { + + /* this little bit of grossness is for dealing + * with memory borrowing for system bookkeeping + * (smp stacks, zero page, kernel code, etc) + * without having to go back and edit the e820 + * map to compensate. + * + * if we're in low memory (<1024k), we need to + * avoid the smp stack and zero page. + * if we're in high memory, we need to avoid + * the kernel code. + * in any case, we don't want to hack mem_map + * entries above end_mem. + */ + if ( (addr < start_low_mem) + || (addr >= HIGH_MEMORY && addr <= start_mem) + || (addr > end_mem) ) + continue; - while (start_mem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; + avail++; + clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); + } } + for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) { if (tmp >= MAX_DMA_ADDRESS) clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); @@ -424,21 +469,33 @@ set_page_count(mem_map+MAP_NR(tmp), 1); totalram += PAGE_SIZE; #ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || (tmp < initrd_start || tmp >= - initrd_end)) + if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) #endif free_page(tmp); } - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", +#ifdef CONFIG_BIGMEM + for (tmp = bigmem_start; tmp < bigmem_end; tmp += PAGE_SIZE) { + clear_bit(PG_reserved, &mem_map[PHYSMAP_NR(tmp)].flags); + set_bit(PG_BIGMEM, &mem_map[PHYSMAP_NR(tmp)].flags); + atomic_set(&mem_map[PHYSMAP_NR(tmp)].count, 1); + free_page(tmp + PAGE_OFFSET); + totalbig += PAGE_SIZE; + } + totalram += totalbig; +#endif + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %dk bigmem)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), - initpages << (PAGE_SHIFT-10)); + initpages << (PAGE_SHIFT-10), + (int) (totalbig >> 10) + ); if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); + } void free_initmem(void) @@ -461,5 +518,7 @@ val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; val->bufferram = atomic_read(&buffermem); + val->totalbig = totalbig; + val->freebig = nr_free_bigpages << PAGE_SHIFT; return; } diff -u --recursive --new-file v2.3.15/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c --- v2.3.15/linux/arch/m68k/amiga/amisound.c Mon Jun 16 16:35:53 1997 +++ linux/arch/m68k/amiga/amisound.c Thu Aug 26 12:42:31 1999 @@ -40,7 +40,7 @@ static u_long clock_constant; -__initfunc(void amiga_init_sound(void)) +void __init amiga_init_sound(void) { snd_data = amiga_chip_alloc(sizeof(sine_data)); if (!snd_data) { diff -u --recursive --new-file v2.3.15/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c --- v2.3.15/linux/arch/m68k/amiga/chipram.c Thu Aug 26 13:05:34 1999 +++ linux/arch/m68k/amiga/chipram.c Thu Aug 26 12:42:31 1999 @@ -32,7 +32,7 @@ } -__initfunc(void amiga_chip_init (void)) +void __init amiga_chip_init (void) { struct chip_desc *dp; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c --- v2.3.15/linux/arch/m68k/atari/ataints.c Mon Oct 5 13:54:39 1998 +++ linux/arch/m68k/atari/ataints.c Thu Aug 26 12:42:31 1999 @@ -327,7 +327,7 @@ * the atari IRQ handling routines. */ -__initfunc(void atari_init_IRQ(void)) +void __init atari_init_IRQ(void) { int i; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c --- v2.3.15/linux/arch/m68k/atari/atakeyb.c Mon Apr 26 13:35:34 1999 +++ linux/arch/m68k/atari/atakeyb.c Thu Aug 26 12:42:31 1999 @@ -762,7 +762,7 @@ * Martin Rogge, 20 Aug 1995 */ -__initfunc(int atari_keyb_init(void)) +int __init atari_keyb_init(void) { /* setup key map */ memcpy(key_maps[0], ataplain_map, sizeof(plain_map)); diff -u --recursive --new-file v2.3.15/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c --- v2.3.15/linux/arch/m68k/atari/config.c Tue Jan 19 10:58:26 1999 +++ linux/arch/m68k/atari/config.c Thu Aug 26 12:42:31 1999 @@ -111,8 +111,8 @@ */ #if 0 -__initfunc(static int -hwreg_present_bywrite(volatile void *regp, unsigned char val)) +static int __init +hwreg_present_bywrite(volatile void *regp, unsigned char val) { int ret; long save_sp, save_vbr; @@ -150,7 +150,7 @@ * should be readable without trouble (from channel A!). */ -__initfunc(static int scc_test( volatile char *ctla )) +static int __init scc_test( volatile char *ctla ) { if (!hwreg_present( ctla )) return( 0 ); @@ -177,7 +177,7 @@ * Parse an Atari-specific record in the bootinfo */ -__initfunc(int atari_parse_bootinfo(const struct bi_record *record)) +int __init atari_parse_bootinfo(const struct bi_record *record) { int unknown = 0; const u_long *data = record->data; @@ -197,7 +197,7 @@ /* Parse the Atari-specific switches= option. */ -__initfunc(void atari_switches_setup( const char *str, unsigned len )) +void __init atari_switches_setup( const char *str, unsigned len ) { char switches[len+1]; char *p; @@ -238,7 +238,7 @@ * Setup the Atari configuration info */ -__initfunc(void config_atari(void)) +void __init config_atari(void) { unsigned short tos_version; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/atari/debug.c linux/arch/m68k/atari/debug.c --- v2.3.15/linux/arch/m68k/atari/debug.c Thu Feb 12 16:30:12 1998 +++ linux/arch/m68k/atari/debug.c Thu Aug 26 12:42:31 1999 @@ -168,7 +168,7 @@ * SCC serial ports. They're used by the debugging interface, kgdb, and the * serial console code. */ #ifndef CONFIG_SERIAL_CONSOLE -__initfunc(static void atari_init_mfp_port( int cflag )) +static void __init atari_init_mfp_port( int cflag ) #else void atari_init_mfp_port( int cflag ) #endif @@ -214,7 +214,7 @@ } while(0) #ifndef CONFIG_SERIAL_CONSOLE -__initfunc(static void atari_init_scc_port( int cflag )) +static void __init atari_init_scc_port( int cflag ) #else void atari_init_scc_port( int cflag ) #endif @@ -281,7 +281,7 @@ } #ifndef CONFIG_SERIAL_CONSOLE -__initfunc(static void atari_init_midi_port( int cflag )) +static void __init atari_init_midi_port( int cflag ) #else void atari_init_midi_port( int cflag ) #endif @@ -309,7 +309,7 @@ ACIA_RHTID : ACIA_RLTID); } -__initfunc(void atari_debug_init(void)) +void __init atari_debug_init(void) { #ifdef CONFIG_KGDB /* the m68k_debug_device is used by the GDB stub, do nothing here */ diff -u --recursive --new-file v2.3.15/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c --- v2.3.15/linux/arch/m68k/atari/joystick.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/atari/joystick.c Thu Aug 26 12:42:31 1999 @@ -130,7 +130,7 @@ release_joystick }; -__initfunc(int atari_joystick_init(void)) +int __init atari_joystick_init(void) { joystick[0].active = joystick[1].active = 0; joystick[0].ready = joystick[1].ready = 0; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c --- v2.3.15/linux/arch/m68k/atari/stdma.c Sat May 15 15:05:35 1999 +++ linux/arch/m68k/atari/stdma.c Thu Aug 26 12:42:31 1999 @@ -171,7 +171,7 @@ * */ -__initfunc(void stdma_init(void)) +void __init stdma_init(void) { stdma_isr = NULL; request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW, diff -u --recursive --new-file v2.3.15/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c --- v2.3.15/linux/arch/m68k/atari/time.c Thu Nov 5 09:58:29 1998 +++ linux/arch/m68k/atari/time.c Thu Aug 26 12:42:31 1999 @@ -17,8 +17,8 @@ #include -__initfunc(void -atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) +void __init +atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) { /* set Timer C data Register */ mfp.tim_dt_c = INT_TICKS; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c --- v2.3.15/linux/arch/m68k/bvme6000/config.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/bvme6000/config.c Thu Aug 26 12:42:31 1999 @@ -103,7 +103,7 @@ } -__initfunc(void config_bvme6000(void)) +void __init config_bvme6000(void) { volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/bvme6000/rtc.c linux/arch/m68k/bvme6000/rtc.c --- v2.3.15/linux/arch/m68k/bvme6000/rtc.c Mon Aug 24 13:14:10 1998 +++ linux/arch/m68k/bvme6000/rtc.c Thu Aug 26 12:42:31 1999 @@ -164,7 +164,7 @@ &rtc_fops }; -__initfunc(int rtc_DP8570A_init(void)) +int __init rtc_DP8570A_init(void) { if (!MACH_IS_BVME6000) return -ENODEV; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/hp300/config.c linux/arch/m68k/hp300/config.c --- v2.3.15/linux/arch/m68k/hp300/config.c Tue Jan 19 10:58:26 1999 +++ linux/arch/m68k/hp300/config.c Thu Aug 26 12:42:31 1999 @@ -31,7 +31,7 @@ extern int hp300_keyb_init(void); #else /* Dummy function for when there is no keyboard. */ -__initfunc(int hp300_keyb_init(void)) +int __init hp300_keyb_init(void) { } #endif @@ -60,7 +60,7 @@ strcpy(model, "HP9000/300"); } -__initfunc(void config_hp300(void)) +void __init config_hp300(void) { mach_sched_init = hp300_sched_init; mach_keyb_init = hp300_keyb_init; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/hp300/hil.c linux/arch/m68k/hp300/hil.c --- v2.3.15/linux/arch/m68k/hp300/hil.c Mon Apr 26 13:37:14 1999 +++ linux/arch/m68k/hp300/hil.c Thu Aug 26 12:42:31 1999 @@ -304,7 +304,7 @@ * Initialise HIL. */ -__initfunc(int hp300_keyb_init(void)) +int __init hp300_keyb_init(void) { unsigned char s, c, kbid; unsigned int n = 0; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/hp300/ints.c linux/arch/m68k/hp300/ints.c --- v2.3.15/linux/arch/m68k/hp300/ints.c Wed Sep 2 09:39:18 1998 +++ linux/arch/m68k/hp300/ints.c Thu Aug 26 12:42:31 1999 @@ -153,7 +153,7 @@ return 0; } -__initfunc(void hp300_init_IRQ(void)) +void __init hp300_init_IRQ(void) { spin_lock_init(&irqlist_lock); } diff -u --recursive --new-file v2.3.15/linux/arch/m68k/hp300/time.c linux/arch/m68k/hp300/time.c --- v2.3.15/linux/arch/m68k/hp300/time.c Wed Sep 2 09:39:18 1998 +++ linux/arch/m68k/hp300/time.c Thu Aug 26 12:42:31 1999 @@ -61,7 +61,7 @@ return (USECS_PER_JIFFY * ticks) / INTVAL; } -__initfunc(void hp300_sched_init(void (*vector)(int, void *, struct pt_regs *))) +void __init hp300_sched_init(void (*vector)(int, void *, struct pt_regs *)) { writeb(0x1, CLOCKBASE + CLKCR2); /* select CR1 */ writeb(0x1, CLOCKBASE + CLKCR1); /* reset */ diff -u --recursive --new-file v2.3.15/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c --- v2.3.15/linux/arch/m68k/kernel/bios32.c Sat Jul 18 14:02:10 1998 +++ linux/arch/m68k/kernel/bios32.c Thu Aug 26 12:42:31 1999 @@ -240,7 +240,7 @@ * accesses. */ -__initfunc(static void disable_dev(struct pci_dev *dev)) +static void __init disable_dev(struct pci_dev *dev) { struct pci_bus *bus; unsigned short cmd; @@ -263,8 +263,8 @@ #define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2) -__initfunc(static void layout_dev(struct pci_dev *dev, unsigned long pci_mem_base, - unsigned long pci_io_base)) +static void __init layout_dev(struct pci_dev *dev, unsigned long pci_mem_base, + unsigned long pci_io_base) { struct pci_bus *bus; unsigned short cmd; @@ -400,8 +400,8 @@ bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); } -__initfunc(static void layout_bus(struct pci_bus *bus, unsigned long pci_mem_base, - unsigned long pci_io_base)) +static void __init layout_bus(struct pci_bus *bus, unsigned long pci_mem_base, + unsigned long pci_io_base) { struct pci_dev *dev; @@ -512,7 +512,7 @@ return 0; } -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); @@ -531,7 +531,7 @@ * of the PCI cards. */ -__initfunc(static inline void hades_fixup(void)) +static inline void __init hades_fixup(void) { char irq_tab[4] = { IRQ_TT_MFP_IO0, /* Slot 0. */ @@ -560,7 +560,7 @@ } } -__initfunc(void pcibios_fixup(void)) +void __init pcibios_fixup(void) { #if PCI_MODIFY unsigned long orig_mem_base, orig_io_base; @@ -587,11 +587,11 @@ hades_fixup(); } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +void __init pcibios_fixup_bus(struct pci_bus *bus) { } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { return str; } diff -u --recursive --new-file v2.3.15/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.3.15/linux/arch/m68k/kernel/setup.c Fri Jul 23 12:20:23 1999 +++ linux/arch/m68k/kernel/setup.c Thu Aug 26 12:42:31 1999 @@ -130,7 +130,7 @@ #define MASK_256K 0xfffc0000 -__initfunc(static void m68k_parse_bootinfo(const struct bi_record *record)) +static void __init m68k_parse_bootinfo(const struct bi_record *record) { while (record->tag != BI_LAST) { int unknown = 0; @@ -190,8 +190,8 @@ #endif } -__initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p)) +void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, + unsigned long * memory_end_p) { extern int _etext, _edata, _end; int i; @@ -467,7 +467,7 @@ #endif #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD) -__initfunc(void floppy_setup(char *str, int *ints)) +void __init floppy_setup(char *str, int *ints) { if (mach_floppy_setup) mach_floppy_setup (str, ints); @@ -481,7 +481,7 @@ #endif /* for "kbd-reset" cmdline param */ -__initfunc(void kbd_reset_setup(char *str, int *ints)) +void __init kbd_reset_setup(char *str, int *ints) { } diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c --- v2.3.15/linux/arch/m68k/mac/adb-bus.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/mac/adb-bus.c Tue Aug 31 11:30:47 1999 @@ -2334,8 +2334,8 @@ int ret = 0; DECLARE_WAITQUEUE(wait,current); + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&adb_wait, &wait); - current->state = TASK_INTERRUPTIBLE; while (!state->req.got_reply) { if (file->f_flags & O_NONBLOCK) { @@ -2349,7 +2349,7 @@ schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&adb_wait, &wait); return ret; @@ -2562,8 +2562,8 @@ printk("ADB request: wait_reply (blocking ... \n"); #endif + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&adb_wait, &wait); - current->state = TASK_INTERRUPTIBLE; while (!state->req.got_reply) { if (file->f_flags & O_NONBLOCK) { @@ -2577,7 +2577,7 @@ schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&adb_wait, &wait); return ret; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c --- v2.3.15/linux/arch/m68k/mac/config.c Tue Jan 19 10:58:34 1999 +++ linux/arch/m68k/mac/config.c Thu Aug 26 12:42:31 1999 @@ -227,7 +227,7 @@ * Parse a Macintosh-specific record in the bootinfo */ -__initfunc(int mac_parse_bootinfo(const struct bi_record *record)) +int __init mac_parse_bootinfo(const struct bi_record *record) { int unknown = 0; const u_long *data = record->data; @@ -288,7 +288,7 @@ restore_flags(flags); } -__initfunc(void config_mac(void)) +void __init config_mac(void) { if (!MACH_IS_MAC) { diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c --- v2.3.15/linux/arch/m68k/mac/debug.c Tue Jan 19 10:58:34 1999 +++ linux/arch/m68k/mac/debug.c Thu Aug 26 12:42:31 1999 @@ -305,7 +305,7 @@ } while(0) #ifndef CONFIG_SERIAL_CONSOLE -__initfunc(static void mac_init_scc_port( int cflag, int port )) +static void __init mac_init_scc_port( int cflag, int port ) #else void mac_init_scc_port( int cflag, int port ) #endif @@ -385,7 +385,7 @@ } #endif /* DEBUG_SERIAL */ -__initfunc(void mac_debug_init(void)) +void __init mac_debug_init(void) { #ifdef CONFIG_KGDB /* the m68k_debug_device is used by the GDB stub, do nothing here */ diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mac/mackeyb.c linux/arch/m68k/mac/mackeyb.c --- v2.3.15/linux/arch/m68k/mac/mackeyb.c Mon Apr 26 13:38:03 1999 +++ linux/arch/m68k/mac/mackeyb.c Thu Aug 26 12:42:31 1999 @@ -613,7 +613,7 @@ return 0; } -__initfunc(int mac_keyb_init(void)) +int __init mac_keyb_init(void) { static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req; volatile int ct; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.3.15/linux/arch/m68k/mm/init.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/mm/init.c Thu Aug 26 12:42:31 1999 @@ -120,7 +120,7 @@ unsigned long mm_cachebits = 0; #endif -__initfunc(static pte_t * kernel_page_table(unsigned long *memavailp)) +static pte_t * __init kernel_page_table(unsigned long *memavailp) { pte_t *ptablep; @@ -138,7 +138,7 @@ static pmd_t *last_pgtable __initdata = NULL; static pmd_t *zero_pgtable __initdata = NULL; -__initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp)) +static pmd_t * __init kernel_ptr_table(unsigned long *memavailp) { if (!last_pgtable) { unsigned long pmd, last; @@ -177,8 +177,8 @@ return last_pgtable; } -__initfunc(static unsigned long -map_chunk (unsigned long addr, long size, unsigned long *memavailp)) +static unsigned long __init +map_chunk (unsigned long addr, long size, unsigned long *memavailp) { #define PTRTREESIZE (256*1024) #define ROOTTREESIZE (32*1024*1024) @@ -285,8 +285,8 @@ * paging_init() continues the virtual memory environment setup which * was begun by the code in arch/head.S. */ -__initfunc(unsigned long paging_init(unsigned long start_mem, - unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, + unsigned long end_mem) { int chunk; unsigned long mem_avail = 0; @@ -363,7 +363,7 @@ return PAGE_ALIGN(free_area_init(start_mem, end_mem)); } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { int codepages = 0; int datapages = 0; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v2.3.15/linux/arch/m68k/mm/memory.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/mm/memory.c Thu Aug 26 12:42:31 1999 @@ -98,7 +98,7 @@ #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t)) -__initfunc(void init_pointer_table(unsigned long ptable)) +void __init init_pointer_table(unsigned long ptable) { ptable_desc *dp; unsigned long page = ptable & PAGE_MASK; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c --- v2.3.15/linux/arch/m68k/mvme147/config.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/mvme147/config.c Thu Aug 26 12:42:31 1999 @@ -90,7 +90,7 @@ } -__initfunc(void config_mvme147(void)) +void __init config_mvme147(void) { mach_sched_init = mvme147_sched_init; mach_keyb_init = mvme147_keyb_init; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c --- v2.3.15/linux/arch/m68k/mvme16x/config.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/mvme16x/config.c Thu Aug 26 12:42:31 1999 @@ -131,7 +131,7 @@ #define PccSCCTICR 0x1e #define PccSCCRICR 0x1f -__initfunc(void config_mvme16x(void)) +void __init config_mvme16x(void) { p_bdid p = (p_bdid)mvme_bdid_ptr; char id[40]; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/mvme16x/rtc.c linux/arch/m68k/mvme16x/rtc.c --- v2.3.15/linux/arch/m68k/mvme16x/rtc.c Mon Aug 24 13:14:10 1998 +++ linux/arch/m68k/mvme16x/rtc.c Thu Aug 26 12:42:31 1999 @@ -155,7 +155,7 @@ &rtc_fops }; -__initfunc(int rtc_MK48T08_init(void)) +int __init rtc_MK48T08_init(void) { if (!MACH_IS_MVME16x) return -ENODEV; diff -u --recursive --new-file v2.3.15/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c --- v2.3.15/linux/arch/m68k/q40/config.c Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/q40/config.c Thu Aug 26 12:42:31 1999 @@ -157,7 +157,7 @@ } -__initfunc(void config_q40(void)) +void __init config_q40(void) { mach_sched_init = q40_sched_init; /* ok */ /*mach_kbdrate = q40_kbdrate;*/ /* unneeded ?*/ diff -u --recursive --new-file v2.3.15/linux/arch/m68k/sun3x/config.c linux/arch/m68k/sun3x/config.c --- v2.3.15/linux/arch/m68k/sun3x/config.c Tue May 11 09:57:14 1999 +++ linux/arch/m68k/sun3x/config.c Thu Aug 26 12:42:31 1999 @@ -39,7 +39,7 @@ asm ("reset"); } -__initfunc(int sun3x_keyb_init(void)) +int __init sun3x_keyb_init(void) { return 0; } @@ -75,7 +75,7 @@ *sun3x_intreg &= ~(1 << irq); } -__initfunc(void sun3x_init_IRQ(void)) +void __init sun3x_init_IRQ(void) { /* disable all interrupts initially */ *sun3x_intreg = 1; /* master enable only */ @@ -89,7 +89,7 @@ /* * Setup the sun3x configuration info */ -__initfunc(void config_sun3x(void)) +void __init config_sun3x(void) { mach_get_irq_list = sun3x_get_irq_list; mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */ diff -u --recursive --new-file v2.3.15/linux/arch/m68k/sun3x/sbus.c linux/arch/m68k/sun3x/sbus.c --- v2.3.15/linux/arch/m68k/sun3x/sbus.c Tue May 11 09:57:14 1999 +++ linux/arch/m68k/sun3x/sbus.c Thu Aug 26 12:42:31 1999 @@ -12,7 +12,7 @@ #include #include -__initfunc(void sbus_init(void)) +void __init sbus_init(void) { } diff -u --recursive --new-file v2.3.15/linux/arch/m68k/sun3x/time.c linux/arch/m68k/sun3x/time.c --- v2.3.15/linux/arch/m68k/sun3x/time.c Wed May 12 08:50:00 1999 +++ linux/arch/m68k/sun3x/time.c Thu Aug 26 12:42:31 1999 @@ -72,7 +72,7 @@ vector(irq, NULL, regs); } -__initfunc(void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *))) +void __init sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *)) { sys_request_irq(5, sun3x_timer_tick, IRQ_FLG_STD, "timer tick", vector); diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/cmdline.c linux/arch/mips/arc/cmdline.c --- v2.3.15/linux/arch/mips/arc/cmdline.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/cmdline.c Thu Aug 26 12:42:31 1999 @@ -16,7 +16,7 @@ char arcs_cmdline[CL_SIZE]; -__initfunc(char *prom_getcmdline(void)) +char * __init prom_getcmdline(void) { return &(arcs_cmdline[0]); } @@ -31,7 +31,7 @@ }; #define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0]))))) -__initfunc(void prom_init_cmdline(void)) +void __init prom_init_cmdline(void) { char *cp; int actr, i; diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/console.c linux/arch/mips/arc/console.c --- v2.3.15/linux/arch/mips/arc/console.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/arc/console.c Thu Aug 26 12:42:31 1999 @@ -23,7 +23,7 @@ #ifdef CONFIG_SGI_PROM_CONSOLE void prom_putchar(char c) #else -__initfunc(void prom_putchar(char c)) +void __init prom_putchar(char c) #endif { long cnt; @@ -37,7 +37,7 @@ #ifdef CONFIG_SGI_PROM_CONSOLE char prom_getchar(void) #else -__initfunc(char prom_getchar(void)) +char __init prom_getchar(void) #endif { long cnt; diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/env.c linux/arch/mips/arc/env.c --- v2.3.15/linux/arch/mips/arc/env.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/env.c Thu Aug 26 12:42:31 1999 @@ -11,12 +11,12 @@ #include -__initfunc(char *prom_getenv(char *name)) +char * __init prom_getenv(char *name) { return romvec->get_evar(name); } -__initfunc(long prom_setenv(char *name, char *value)) +long __init prom_setenv(char *name, char *value) { return romvec->set_evar(name, value); } diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/file.c linux/arch/mips/arc/file.c --- v2.3.15/linux/arch/mips/arc/file.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/file.c Thu Aug 26 12:42:31 1999 @@ -8,52 +8,52 @@ #include #include -__initfunc(long prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt)) +long __init prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt) { return romvec->get_vdirent(fd, ent, num, cnt); } -__initfunc(long prom_open(char *name, enum linux_omode md, unsigned long *fd)) +long __init prom_open(char *name, enum linux_omode md, unsigned long *fd) { return romvec->open(name, md, fd); } -__initfunc(long prom_close(unsigned long fd)) +long __init prom_close(unsigned long fd) { return romvec->close(fd); } -__initfunc(long prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt)) +long __init prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt) { return romvec->read(fd, buf, num, cnt); } -__initfunc(long prom_getrstatus(unsigned long fd)) +long __init prom_getrstatus(unsigned long fd) { return romvec->get_rstatus(fd); } -__initfunc(long prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt)) +long __init prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt) { return romvec->write(fd, buf, num, cnt); } -__initfunc(long prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm)) +long __init prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm) { return romvec->seek(fd, off, sm); } -__initfunc(long prom_mount(char *name, enum linux_mountops op)) +long __init prom_mount(char *name, enum linux_mountops op) { return romvec->mount(name, op); } -__initfunc(long prom_getfinfo(unsigned long fd, struct linux_finfo *buf)) +long __init prom_getfinfo(unsigned long fd, struct linux_finfo *buf) { return romvec->get_finfo(fd, buf); } -__initfunc(long prom_setfinfo(unsigned long fd, unsigned long flags, unsigned long msk)) +long __init prom_setfinfo(unsigned long fd, unsigned long flags, unsigned long msk) { return romvec->set_finfo(fd, flags, msk); } diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/init.c linux/arch/mips/arc/init.c --- v2.3.15/linux/arch/mips/arc/init.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/init.c Thu Aug 26 12:42:31 1999 @@ -22,7 +22,7 @@ extern void prom_testtree(void); -__initfunc(int prom_init(int argc, char **argv, char **envp)) +int __init prom_init(int argc, char **argv, char **envp) { struct linux_promblock *pb; diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/memory.c linux/arch/mips/arc/memory.c --- v2.3.15/linux/arch/mips/arc/memory.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/arc/memory.c Thu Aug 26 12:42:31 1999 @@ -20,7 +20,7 @@ /* #define DEBUG */ -__initfunc(struct linux_mdesc *prom_getmdesc(struct linux_mdesc *curr)) +struct linux_mdesc * __init prom_getmdesc(struct linux_mdesc *curr) { return romvec->get_mdesc(curr); } @@ -52,7 +52,7 @@ static struct prom_pmemblock prom_pblocks[PROM_MAX_PMEMBLOCKS]; -__initfunc(struct prom_pmemblock *prom_getpblock_array(void)) +struct prom_pmemblock * __init prom_getpblock_array(void) { return &prom_pblocks[0]; } @@ -89,7 +89,7 @@ } } -__initfunc(static void prom_setup_memupper(void)) +static void __init prom_setup_memupper(void) { struct prom_pmemblock *p, *highest; @@ -106,7 +106,7 @@ #endif } -__initfunc(void prom_meminit(void)) +void __init prom_meminit(void) { struct linux_mdesc *p; int totram; @@ -162,7 +162,7 @@ } /* Called from mem_init() to fixup the mem_map page settings. */ -__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end)) +void __init prom_fixup_mem_map(unsigned long start, unsigned long end) { struct prom_pmemblock *p; int i, nents; diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/misc.c linux/arch/mips/arc/misc.c --- v2.3.15/linux/arch/mips/arc/misc.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/misc.c Thu Aug 26 12:42:31 1999 @@ -78,7 +78,7 @@ return romvec->get_sysid(); } -__initfunc(void prom_cacheflush(void)) +void __init prom_cacheflush(void) { romvec->cache_flush(); } diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/printf.c linux/arch/mips/arc/printf.c --- v2.3.15/linux/arch/mips/arc/printf.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/arc/printf.c Thu Aug 26 12:42:31 1999 @@ -17,7 +17,7 @@ #ifdef CONFIG_SGI_PROM_CONSOLE void prom_printf(char *fmt, ...) #else -__initfunc(void prom_printf(char *fmt, ...)) +void __init prom_printf(char *fmt, ...) #endif { va_list args; diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/salone.c linux/arch/mips/arc/salone.c --- v2.3.15/linux/arch/mips/arc/salone.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/salone.c Thu Aug 26 12:42:31 1999 @@ -9,17 +9,17 @@ #include #include -__initfunc(long prom_load(char *name, unsigned long end, unsigned long *pc, unsigned long *eaddr)) +long __init prom_load(char *name, unsigned long end, unsigned long *pc, unsigned long *eaddr) { return romvec->load(name, end, pc, eaddr); } -__initfunc(long prom_invoke(unsigned long pc, unsigned long sp, long argc, char **argv, char **envp)) +long __init prom_invoke(unsigned long pc, unsigned long sp, long argc, char **argv, char **envp) { return romvec->invoke(pc, sp, argc, argv, envp); } -__initfunc(long prom_exec(char *name, long argc, char **argv, char **envp)) +long __init prom_exec(char *name, long argc, char **argv, char **envp) { return romvec->exec(name, argc, argv, envp); } diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/time.c linux/arch/mips/arc/time.c --- v2.3.15/linux/arch/mips/arc/time.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/time.c Thu Aug 26 12:42:31 1999 @@ -8,12 +8,12 @@ #include #include -__initfunc(struct linux_tinfo *prom_gettinfo(void)) +struct linux_tinfo * __init prom_gettinfo(void) { return romvec->get_tinfo(); } -__initfunc(unsigned long prom_getrtime(void)) +unsigned long __init prom_getrtime(void) { return romvec->get_rtime(); } diff -u --recursive --new-file v2.3.15/linux/arch/mips/arc/tree.c linux/arch/mips/arc/tree.c --- v2.3.15/linux/arch/mips/arc/tree.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/tree.c Thu Aug 26 12:42:31 1999 @@ -10,41 +10,41 @@ #define DEBUG_PROM_TREE -__initfunc(pcomponent *prom_getsibling(pcomponent *this)) +pcomponent * __init prom_getsibling(pcomponent *this) { if(this == PROM_NULL_COMPONENT) return PROM_NULL_COMPONENT; return romvec->next_component(this); } -__initfunc(pcomponent *prom_getchild(pcomponent *this)) +pcomponent * __init prom_getchild(pcomponent *this) { return romvec->child_component(this); } -__initfunc(pcomponent *prom_getparent(pcomponent *child)) +pcomponent * __init prom_getparent(pcomponent *child) { if(child == PROM_NULL_COMPONENT) return PROM_NULL_COMPONENT; return romvec->parent_component(child); } -__initfunc(long prom_getcdata(void *buffer, pcomponent *this)) +long __init prom_getcdata(void *buffer, pcomponent *this) { return romvec->component_data(buffer, this); } -__initfunc(pcomponent *prom_childadd(pcomponent *this, pcomponent *tmp, void *data)) +pcomponent * __init prom_childadd(pcomponent *this, pcomponent *tmp, void *data) { return romvec->child_add(this, tmp, data); } -__initfunc(long prom_delcomponent(pcomponent *this)) +long __init prom_delcomponent(pcomponent *this) { return romvec->comp_del(this); } -__initfunc(pcomponent *prom_componentbypath(char *path)) +pcomponent * __init prom_componentbypath(char *path) { return romvec->component_by_path(path); } @@ -74,7 +74,7 @@ "input", "output" }; -__initfunc(static void dump_component(pcomponent *p)) +static void __init dump_component(pcomponent *p) { prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>", p, classes[p->class], types[p->type], @@ -83,7 +83,7 @@ p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname); } -__initfunc(static void traverse(pcomponent *p, int op)) +static void __init traverse(pcomponent *p, int op) { dump_component(p); if(prom_getchild(p)) @@ -92,7 +92,7 @@ traverse(prom_getsibling(p), 1); } -__initfunc(void prom_testtree(void)) +void __init prom_testtree(void) { pcomponent *p; diff -u --recursive --new-file v2.3.15/linux/arch/mips/baget/irq.c linux/arch/mips/baget/irq.c --- v2.3.15/linux/arch/mips/baget/irq.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/irq.c Thu Aug 26 12:42:31 1999 @@ -422,7 +422,7 @@ *(volatile char*) BAGET_WRERR_ACK = 0; } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { irq_setup(); diff -u --recursive --new-file v2.3.15/linux/arch/mips/baget/print.c linux/arch/mips/baget/print.c --- v2.3.15/linux/arch/mips/baget/print.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/print.c Thu Aug 26 12:42:31 1999 @@ -76,7 +76,7 @@ outs( s ); } -__initfunc(void balo_printf( char *f, ... )) +void __init balo_printf( char *f, ... ) { int *arg = (int*)&f + 1; char c; @@ -111,7 +111,7 @@ } } -__initfunc(void balo_hungup(void)) +void __init balo_hungup(void) { outs("Hunging up.\n"); while(1); diff -u --recursive --new-file v2.3.15/linux/arch/mips/baget/prom/init.c linux/arch/mips/baget/prom/init.c --- v2.3.15/linux/arch/mips/baget/prom/init.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/baget/prom/init.c Thu Aug 26 12:42:31 1999 @@ -10,7 +10,7 @@ char arcs_cmdline[CL_SIZE]; -__initfunc(int prom_init(unsigned int mem_upper)) +int __init prom_init(unsigned int mem_upper) { mips_memory_upper = mem_upper; mips_machgroup = MACH_GROUP_UNKNOWN; diff -u --recursive --new-file v2.3.15/linux/arch/mips/baget/setup.c linux/arch/mips/baget/setup.c --- v2.3.15/linux/arch/mips/baget/setup.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/baget/setup.c Thu Aug 26 12:42:31 1999 @@ -21,7 +21,7 @@ #define CACHEABLE_STR(val) ((val) ? "not cached" : "cached") #define MIN(a,b) (((a)<(b)) ? (a):(b)) -__initfunc(static void vac_show(void)) +static void __init vac_show(void) { int i; unsigned short val, decode = vac_inw(VAC_DECODE_CTRL); @@ -172,7 +172,7 @@ (VAC_CTRL_DELAY_IOSELI_VAL(val)&1) ? ".5" : ""); } -__initfunc(static void vac_init(void)) +static void __init vac_init(void) { unsigned short mem_limit = ((mips_memory_upper-KSEG0) >> 16); @@ -283,7 +283,7 @@ vac_show(); } -__initfunc(static void vac_start(void)) +static void __init vac_start(void) { vac_outw(0, VAC_ID); vac_outw(VAC_INT_CTRL_TIMER_DISABLE| @@ -305,7 +305,7 @@ vac_outw((500000/(384*16))<<8,VAC_CPU_CLK_DIV); } -__initfunc(static void vic_show(void)) +static void __init vic_show(void) { unsigned char val; char *timeout[] = { "4", "16", "32", "64", "128", "256", "disabled" }; @@ -364,7 +364,7 @@ } -__initfunc(static void vic_init(void)) +static void __init vic_init(void) { unsigned char id = vic_inb(VIC_ID); if ((id & 0xf0) != 0xf0) @@ -463,7 +463,7 @@ VIC_INT_ENABLE, VIC_LINT7); } -__initfunc(void baget_irq_setup(void)) +void __init baget_irq_setup(void) { extern void bagetIRQ(void); @@ -475,7 +475,7 @@ extern void baget_machine_halt(void); extern void baget_machine_power_off(void); -__initfunc(void baget_setup(void)) +void __init baget_setup(void) { printk("BT23/63-201n found.\n"); *BAGET_WRERR_ACK = 0; diff -u --recursive --new-file v2.3.15/linux/arch/mips/baget/time.c linux/arch/mips/baget/time.c --- v2.3.15/linux/arch/mips/baget/time.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/time.c Thu Aug 26 12:42:31 1999 @@ -52,7 +52,7 @@ } } -__initfunc(static void timer_enable(void)) +static void __init timer_enable(void) { unsigned char ss0cr0 = vic_inb(VIC_SS0CR0); ss0cr0 &= ~VIC_SS0CR0_TIMER_FREQ_MASK; @@ -63,7 +63,7 @@ VIC_INT_LOW|VIC_INT_ENABLE, VIC_LINT2); } -__initfunc(void time_init(void)) +void __init time_init(void) { if (request_irq(BAGET_VIC_TIMER_IRQ, timer_interrupt, SA_INTERRUPT|SA_STATIC_ALLOC, "timer", NULL) < 0) diff -u --recursive --new-file v2.3.15/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c --- v2.3.15/linux/arch/mips/baget/vacserial.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/vacserial.c Tue Aug 31 11:30:47 1999 @@ -1778,7 +1778,6 @@ baget_printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -1903,7 +1902,7 @@ restore_flags(flags); info->blocked_open++; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -2302,7 +2301,7 @@ /* * The serial driver boot-time initialization code! */ -__initfunc(int rs_init(void)) +int __init rs_init(void) { int i; struct serial_state * state; @@ -2666,7 +2665,7 @@ * - initialize the serial port * Return non-zero if we didn't find a serial port. */ -__initfunc(static int serial_console_setup(struct console *co, char *options)) +static int __init serial_console_setup(struct console *co, char *options) { struct serial_state *ser; unsigned cval; @@ -2821,7 +2820,7 @@ /* * Register console. */ -__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +long __init serial_console_init(long kmem_start, long kmem_end) { register_console(&sercons); return kmem_start; diff -u --recursive --new-file v2.3.15/linux/arch/mips/baget/wbflush.c linux/arch/mips/baget/wbflush.c --- v2.3.15/linux/arch/mips/baget/wbflush.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/wbflush.c Thu Aug 26 12:42:31 1999 @@ -11,7 +11,7 @@ static void wbflush_baget(void); -__initfunc(void wbflush_setup(void)) +void __init wbflush_setup(void) { __wbflush = wbflush_baget; } diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/irq.c linux/arch/mips/dec/irq.c --- v2.3.15/linux/arch/mips/dec/irq.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/dec/irq.c Thu Aug 26 12:42:31 1999 @@ -263,7 +263,7 @@ return 0; } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { irq_setup(); } diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/prom/cmdline.c linux/arch/mips/dec/prom/cmdline.c --- v2.3.15/linux/arch/mips/dec/prom/cmdline.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/dec/prom/cmdline.c Thu Aug 26 12:42:31 1999 @@ -21,7 +21,7 @@ char arcs_cmdline[CL_SIZE]; -__initfunc(void prom_init_cmdline(int argc, char **argv, unsigned long magic)) +void __init prom_init_cmdline(int argc, char **argv, unsigned long magic) { int start_arg, i; diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/prom/identify.c linux/arch/mips/dec/prom/identify.c --- v2.3.15/linux/arch/mips/dec/prom/identify.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/dec/prom/identify.c Thu Aug 26 12:42:31 1999 @@ -21,7 +21,7 @@ extern unsigned long mips_machgroup; extern unsigned long mips_machtype; -__initfunc(void prom_identify_arch (unsigned int magic)) +void __init prom_identify_arch (unsigned int magic) { unsigned char dec_cpunum, dec_firmrev, dec_etc; int dec_systype; diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/prom/init.c linux/arch/mips/dec/prom/init.c --- v2.3.15/linux/arch/mips/dec/prom/init.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/dec/prom/init.c Thu Aug 26 12:42:31 1999 @@ -41,7 +41,7 @@ * Detect which PROM's the DECSTATION has, and set the callback vectors * appropriately. */ -__initfunc(void which_prom(unsigned long magic, int *prom_vec)) +void __init which_prom(unsigned long magic, int *prom_vec) { /* * No sign of the REX PROM's magic number means we assume a non-REX @@ -78,8 +78,8 @@ } } -__initfunc(int prom_init(int argc, char **argv, - unsigned long magic, int *prom_vec)) +int __init prom_init(int argc, char **argv, + unsigned long magic, int *prom_vec) { /* Determine which PROM's we have (and therefore which machine we're on!) */ which_prom(magic, prom_vec); diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/prom/memory.c linux/arch/mips/dec/prom/memory.c --- v2.3.15/linux/arch/mips/dec/prom/memory.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/dec/prom/memory.c Thu Aug 26 12:42:31 1999 @@ -34,7 +34,7 @@ #define CHUNK_SIZE 0x400000 -__initfunc(unsigned long pmax_get_memory_size(void)) +unsigned long __init pmax_get_memory_size(void) { volatile unsigned char *memory_page, dummy; char old_handler[0x80]; @@ -62,7 +62,7 @@ * Use the REX prom calls to get hold of the memory bitmap, and thence * determine memory size. */ -__initfunc(unsigned long rex_get_memory_size(void)) +unsigned long __init rex_get_memory_size(void) { int i, bitmap_size; unsigned long mem_size = 0; @@ -81,7 +81,7 @@ return (mem_size); } -__initfunc(void prom_meminit(unsigned int magic)) +void __init prom_meminit(unsigned int magic) { if (magic != REX_PROM_MAGIC) mips_memory_upper = KSEG0 + pmax_get_memory_size(); @@ -94,7 +94,7 @@ } /* Called from mem_init() to fixup the mem_map page settings. */ -__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end)) +void __init prom_fixup_mem_map(unsigned long start, unsigned long end) { } diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/promcon.c linux/arch/mips/dec/promcon.c --- v2.3.15/linux/arch/mips/dec/promcon.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/dec/promcon.c Thu Aug 26 12:42:31 1999 @@ -35,7 +35,7 @@ return prom_getchar(); } -__initfunc(static int prom_console_setup(struct console *co, char *options)) +static int __init prom_console_setup(struct console *co, char *options) { return 0; } @@ -64,7 +64,7 @@ * Register console. */ -__initfunc(long prom_console_init(long kmem_start, long kmem_end)) +long __init prom_console_init(long kmem_start, long kmem_end) { register_console(&sercons); return kmem_start; diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/serial.c linux/arch/mips/dec/serial.c --- v2.3.15/linux/arch/mips/dec/serial.c Wed Aug 4 16:36:41 1999 +++ linux/arch/mips/dec/serial.c Thu Aug 26 12:42:31 1999 @@ -45,7 +45,7 @@ #ifdef CONFIG_SERIAL -__initfunc(int rs_init(void)) +int __init rs_init(void) { #if defined(CONFIG_ZS) && defined(CONFIG_DZ) @@ -73,7 +73,7 @@ /* serial_console_init handles the special case of starting * up the console on the serial port */ -__initfunc(long serial_console_init(long kmem_start, long kmem_end)) +long __init serial_console_init(long kmem_start, long kmem_end) { #if defined(CONFIG_ZS) && defined(CONFIG_DZ) if (IOASIC) diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/setup.c linux/arch/mips/dec/setup.c --- v2.3.15/linux/arch/mips/dec/setup.c Wed Aug 4 16:36:41 1999 +++ linux/arch/mips/dec/setup.c Thu Aug 26 12:42:31 1999 @@ -60,7 +60,7 @@ void (*board_time_init) (struct irqaction * irq); -__initfunc(static void dec_irq_setup(void)) +static void __init dec_irq_setup(void) { switch (mips_machtype) { case MACH_DS23100: @@ -97,7 +97,7 @@ /* * enable the periodic interrupts */ -__initfunc(static void dec_time_init(struct irqaction *irq)) +static void __init dec_time_init(struct irqaction *irq) { /* * Here we go, enable periodic rtc interrupts. @@ -112,7 +112,7 @@ setup_dec_irq(CLOCK, irq); } -__initfunc(void decstation_setup(void)) +void __init decstation_setup(void) { irq_setup = dec_irq_setup; board_time_init = dec_time_init; @@ -130,7 +130,7 @@ * Machine-specific initialisation for kn01, aka Pmax, aka DS2100, DS3100, * and possibly also the DS5100. */ -__initfunc(void dec_init_kn01(void)) +void __init dec_init_kn01(void) { /* * Setup some memory addresses. @@ -176,7 +176,7 @@ * * There are a lot of experiments to do, this is definitely incomplete. */ -__initfunc(void dec_init_kn230(void)) +void __init dec_init_kn230(void) { /* * Setup some memory addresses. @@ -200,7 +200,7 @@ /* * Machine-specific initialisation for kn02, aka 3max, aka DS5000/2xx. */ -__initfunc(void dec_init_kn02(void)) +void __init dec_init_kn02(void) { /* * Setup some memory addresses. FIXME: probably incomplete! @@ -270,7 +270,7 @@ /* * Machine-specific initialisation for kn02ba, aka 3min, aka DS5000/1xx. */ -__initfunc(void dec_init_kn02ba(void)) +void __init dec_init_kn02ba(void) { /* * Setup some memory addresses. @@ -350,7 +350,7 @@ /* * Machine-specific initialisation for kn02ca, aka maxine, aka DS5000/2x. */ -__initfunc(void dec_init_kn02ca(void)) +void __init dec_init_kn02ca(void) { /* * Setup some memory addresses. FIXME: probably incomplete! @@ -425,7 +425,7 @@ /* * Machine-specific initialisation for kn03, aka 3max+, aka DS5000/240. */ -__initfunc(void dec_init_kn03(void)) +void __init dec_init_kn03(void) { /* * Setup some memory addresses. FIXME: probably incomplete! diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/time.c linux/arch/mips/dec/time.c --- v2.3.15/linux/arch/mips/dec/time.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/dec/time.c Thu Aug 26 12:42:31 1999 @@ -385,7 +385,7 @@ void (*board_time_init) (struct irqaction * irq); -__initfunc(void time_init(void)) +void __init time_init(void) { unsigned int year, mon, day, hour, min, sec; int i; diff -u --recursive --new-file v2.3.15/linux/arch/mips/dec/wbflush.c linux/arch/mips/dec/wbflush.c --- v2.3.15/linux/arch/mips/dec/wbflush.c Wed Aug 4 16:36:41 1999 +++ linux/arch/mips/dec/wbflush.c Thu Aug 26 12:42:31 1999 @@ -23,7 +23,7 @@ void (*__wbflush) (void); -__initfunc(void wbflush_setup(void)) +void __init wbflush_setup(void) { switch (mips_machtype) { case MACH_DS23100: diff -u --recursive --new-file v2.3.15/linux/arch/mips/jazz/setup.c linux/arch/mips/jazz/setup.c --- v2.3.15/linux/arch/mips/jazz/setup.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/jazz/setup.c Thu Aug 26 12:42:31 1999 @@ -52,14 +52,14 @@ void (*board_time_init)(struct irqaction *irq); -__initfunc(static void jazz_time_init(struct irqaction *irq)) +static void __init jazz_time_init(struct irqaction *irq) { /* set the clock to 100 Hz */ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); i8259_setup_irq(JAZZ_TIMER_IRQ, irq); } -__initfunc(static void jazz_irq_setup(void)) +static void __init jazz_irq_setup(void) { set_except_vector(0, jazz_handle_int); r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, @@ -79,7 +79,7 @@ i8259_setup_irq(2, &irq2); } -__initfunc(void jazz_setup(void)) +void __init jazz_setup(void) { add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K); add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M); diff -u --recursive --new-file v2.3.15/linux/arch/mips/kernel/irixinv.c linux/arch/mips/kernel/irixinv.c --- v2.3.15/linux/arch/mips/kernel/irixinv.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/irixinv.c Thu Aug 26 12:42:31 1999 @@ -53,7 +53,7 @@ return inventory_items * sizeof (inventory_t); } -__initfunc(void init_inventory (void)) +void __init init_inventory (void) { /* gross hack while we put the right bits all over the kernel * most likely this will not let just anyone run the X server diff -u --recursive --new-file v2.3.15/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c --- v2.3.15/linux/arch/mips/kernel/irq.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/irq.c Thu Aug 26 12:42:31 1999 @@ -356,7 +356,7 @@ return ((irq == 2) ? 9 : irq); } -__initfunc(static void i8259_init(void)) +static void __init i8259_init(void) { /* Init master interrupt controller */ outb(0x11, 0x20); /* Start init sequence */ @@ -376,7 +376,7 @@ outb(cached_21, 0x21); } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { irq_cannonicalize = i8259_irq_cannonicalize; /* i8259_init(); */ diff -u --recursive --new-file v2.3.15/linux/arch/mips/kernel/pci.c linux/arch/mips/kernel/pci.c --- v2.3.15/linux/arch/mips/kernel/pci.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/pci.c Thu Aug 26 12:42:31 1999 @@ -22,7 +22,7 @@ /* * BIOS32 replacement. */ -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { } @@ -81,12 +81,12 @@ return pci_ops->pcibios_write_config_dword(bus, dev_fn, where, val); } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { return str; } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +void __init pcibios_fixup_bus(struct pci_bus *bus) { } diff -u --recursive --new-file v2.3.15/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c --- v2.3.15/linux/arch/mips/kernel/setup.c Mon Jul 5 20:35:17 1999 +++ linux/arch/mips/kernel/setup.c Thu Aug 26 12:42:31 1999 @@ -135,13 +135,13 @@ */ unsigned long isa_slot_offset; -__initfunc(static void default_irq_setup(void)) +static void __init default_irq_setup(void) { panic("Unknown machtype in init_IRQ"); } -__initfunc(void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) { unsigned long memory_end; #ifdef CONFIG_BLK_DEV_INITRD diff -u --recursive --new-file v2.3.15/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c --- v2.3.15/linux/arch/mips/kernel/time.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/kernel/time.c Thu Aug 26 12:42:31 1999 @@ -479,7 +479,7 @@ void (*board_time_init)(struct irqaction *irq); -__initfunc(void time_init(void)) +void __init time_init(void) { unsigned int epoch, year, mon, day, hour, min, sec; int i; diff -u --recursive --new-file v2.3.15/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c --- v2.3.15/linux/arch/mips/kernel/traps.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/traps.c Thu Aug 26 12:42:32 1999 @@ -467,7 +467,7 @@ extern asmlinkage void *r4xx0_resume(void *last, void *next); extern asmlinkage void *r2300_resume(void *last, void *next); -__initfunc(void trap_init(void)) +void __init trap_init(void) { extern char except_vec0_nevada, except_vec0_r4000; extern char except_vec0_r4600, except_vec0_r2300; diff -u --recursive --new-file v2.3.15/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c --- v2.3.15/linux/arch/mips/mm/andes.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/mm/andes.c Thu Aug 26 12:42:32 1999 @@ -91,7 +91,7 @@ return (regs->cp0_status & ST0_KSU) == KSU_USER; } -__initfunc(void ld_mmu_andes(void)) +void __init ld_mmu_andes(void) { flush_cache_all = andes_flush_cache_all; flush_cache_mm = andes_flush_cache_mm; diff -u --recursive --new-file v2.3.15/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.3.15/linux/arch/mips/mm/init.c Tue Jun 29 09:22:08 1999 +++ linux/arch/mips/mm/init.c Thu Aug 26 12:42:32 1999 @@ -272,7 +272,7 @@ extern unsigned long free_area_init(unsigned long, unsigned long); -__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) { /* Initialize the entire pgd. */ pgd_init((unsigned long)swapper_pg_dir); @@ -280,7 +280,7 @@ return free_area_init(start_mem, end_mem); } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { int codepages = 0; int datapages = 0; @@ -383,8 +383,8 @@ } /* Fixup an immediate instruction */ -__initfunc(static void __i_insn_fixup(unsigned int **start, unsigned int **stop, - unsigned int i_const)) +static void __init __i_insn_fixup(unsigned int **start, unsigned int **stop, + unsigned int i_const) { unsigned int **p, *ip; @@ -402,9 +402,9 @@ } while(0) /* Caller is assumed to flush the caches before the first context switch. */ -__initfunc(void __asid_setup(unsigned int inc, unsigned int mask, +void __init __asid_setup(unsigned int inc, unsigned int mask, unsigned int version_mask, - unsigned int first_version)) + unsigned int first_version) { i_insn_fixup(__asid_inc, inc); i_insn_fixup(__asid_mask, mask); diff -u --recursive --new-file v2.3.15/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c --- v2.3.15/linux/arch/mips/mm/loadmmu.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/mm/loadmmu.c Thu Aug 26 12:42:32 1999 @@ -62,7 +62,7 @@ extern void ld_mmu_tfp(void); extern void ld_mmu_andes(void); -__initfunc(void loadmmu(void)) +void __init loadmmu(void) { switch(mips_cputype) { case CPU_R2000: diff -u --recursive --new-file v2.3.15/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c --- v2.3.15/linux/arch/mips/mm/r2300.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/mm/r2300.c Thu Aug 26 12:42:32 1999 @@ -127,7 +127,7 @@ "I" (PAGE_SIZE)); } -__initfunc(static unsigned long size_cache(unsigned long ca_flags)) +static unsigned long __init size_cache(unsigned long ca_flags) { unsigned long flags, status, dummy, size; volatile unsigned long *p; @@ -161,13 +161,13 @@ return size * sizeof(*p); } -__initfunc(static void probe_dcache(void)) +static void __init probe_dcache(void) { dcache.size = size_cache(dcache.ca_flags = ST0_DE); printk("Data cache %dkb\n", dcache.size >> 10); } -__initfunc(static void probe_icache(void)) +static void __init probe_icache(void) { icache.size = size_cache(icache.ca_flags = ST0_DE|ST0_CE); printk("Instruction cache %dkb\n", icache.size >> 10); @@ -683,7 +683,7 @@ return !(regs->cp0_status & ST0_KUP); } -__initfunc(void ld_mmu_r2300(void)) +void __init ld_mmu_r2300(void) { printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); diff -u --recursive --new-file v2.3.15/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c --- v2.3.15/linux/arch/mips/mm/r4xx0.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/mm/r4xx0.c Thu Aug 26 12:42:32 1999 @@ -2516,7 +2516,7 @@ } /* Detect and size the various r4k caches. */ -__initfunc(static void probe_icache(unsigned long config)) +static void __init probe_icache(unsigned long config) { icache_size = 1 << (12 + ((config >> 9) & 7)); ic_lsize = 16 << ((config >> 5) & 1); @@ -2525,7 +2525,7 @@ icache_size >> 10, ic_lsize); } -__initfunc(static void probe_dcache(unsigned long config)) +static void __init probe_dcache(unsigned long config) { dcache_size = 1 << (12 + ((config >> 6) & 7)); dc_lsize = 16 << ((config >> 4) & 1); @@ -2540,7 +2540,7 @@ * the cache sizing loop that executes in KSEG1 space or else * you will crash and burn badly. You have been warned. */ -__initfunc(static int probe_scache(unsigned long config)) +static int __init probe_scache(unsigned long config) { extern unsigned long stext; unsigned long flags, addr, begin, end, pow2; @@ -2624,7 +2624,7 @@ return 1; } -__initfunc(static void setup_noscache_funcs(void)) +static void __init setup_noscache_funcs(void) { unsigned int prid; @@ -2662,7 +2662,7 @@ dma_cache_inv = r4k_dma_cache_inv_pc; } -__initfunc(static void setup_scache_funcs(void)) +static void __init setup_scache_funcs(void) { switch(sc_lsize) { case 16: @@ -2748,7 +2748,7 @@ typedef int (*probe_func_t)(unsigned long); -__initfunc(static inline void setup_scache(unsigned int config)) +static inline void __init setup_scache(unsigned int config) { probe_func_t probe_scache_kseg1; int sc_present = 0; @@ -2770,7 +2770,7 @@ return (regs->cp0_status & ST0_KSU) == KSU_USER; } -__initfunc(void ld_mmu_r4xx0(void)) +void __init ld_mmu_r4xx0(void) { unsigned long config = read_32bit_cp0_register(CP0_CONFIG); diff -u --recursive --new-file v2.3.15/linux/arch/mips/mm/r6000.c linux/arch/mips/mm/r6000.c --- v2.3.15/linux/arch/mips/mm/r6000.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/mm/r6000.c Thu Aug 26 12:42:32 1999 @@ -169,7 +169,7 @@ return !(regs->cp0_status & 0x4); } -__initfunc(void ld_mmu_r6000(void)) +void __init ld_mmu_r6000(void) { flush_cache_all = r6000_flush_cache_all; flush_cache_mm = r6000_flush_cache_mm; diff -u --recursive --new-file v2.3.15/linux/arch/mips/mm/tfp.c linux/arch/mips/mm/tfp.c --- v2.3.15/linux/arch/mips/mm/tfp.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/mm/tfp.c Thu Aug 26 12:42:32 1999 @@ -93,7 +93,7 @@ return (regs->cp0_status & ST0_KSU) == KSU_USER; } -__initfunc(void ld_mmu_tfp(void)) +void __init ld_mmu_tfp(void) { flush_cache_all = tfp_flush_cache_all; flush_cache_mm = tfp_flush_cache_mm; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/indy_hpc.c linux/arch/mips/sgi/kernel/indy_hpc.c --- v2.3.15/linux/arch/mips/sgi/kernel/indy_hpc.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/indy_hpc.c Thu Aug 26 12:42:32 1999 @@ -25,7 +25,7 @@ int sgi_guiness = 0; int sgi_boardid; -__initfunc(void sgihpc_init(void)) +void __init sgihpc_init(void) { unsigned long sid, crev, brev; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/indy_int.c linux/arch/mips/sgi/kernel/indy_int.c --- v2.3.15/linux/arch/mips/sgi/kernel/indy_int.c Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/sgi/kernel/indy_int.c Thu Aug 26 12:42:32 1999 @@ -422,7 +422,7 @@ return irq; /* Sane hardware, sane code ... */ } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { irq_cannonicalize = indy_irq_cannonicalize; irq_setup(); @@ -527,7 +527,7 @@ return 0; } -__initfunc(void sgint_init(void)) +void __init sgint_init(void) { int i; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/indy_mc.c linux/arch/mips/sgi/kernel/indy_mc.c --- v2.3.15/linux/arch/mips/sgi/kernel/indy_mc.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/indy_mc.c Thu Aug 26 12:42:32 1999 @@ -47,7 +47,7 @@ }; } -__initfunc(void sgimc_init(void)) +void __init sgimc_init(void) { unsigned long tmpreg; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c --- v2.3.15/linux/arch/mips/sgi/kernel/indy_sc.c Thu Jul 1 10:45:57 1999 +++ linux/arch/mips/sgi/kernel/indy_sc.c Thu Aug 26 12:42:32 1999 @@ -150,7 +150,7 @@ " : "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)); } -__initfunc(static inline int indy_sc_probe(void)) +static inline int __init indy_sc_probe(void) { volatile unsigned int *cpu_control; unsigned short cmd = 0xc220; @@ -219,7 +219,7 @@ indy_sc_wback_invalidate }; -__initfunc(void indy_sc_init(void)) +void __init indy_sc_init(void) { if (indy_sc_probe()) { indy_sc_enable(); diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/indy_timer.c linux/arch/mips/sgi/kernel/indy_timer.c --- v2.3.15/linux/arch/mips/sgi/kernel/indy_timer.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/indy_timer.c Thu Aug 26 12:42:32 1999 @@ -176,7 +176,7 @@ )*60 + sec; /* finally seconds */ } -__initfunc(static unsigned long get_indy_time(void)) +static unsigned long __init get_indy_time(void) { struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS; unsigned int year, mon, day, hour, min, sec; @@ -221,7 +221,7 @@ #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) -__initfunc(void indy_timer_init(void)) +void __init indy_timer_init(void) { struct sgi_ioc_timers *p; volatile unsigned char *tcwp, *tc2p; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/promcon.c linux/arch/mips/sgi/kernel/promcon.c --- v2.3.15/linux/arch/mips/sgi/kernel/promcon.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/promcon.c Thu Aug 26 12:42:32 1999 @@ -37,7 +37,7 @@ return prom_getchar(); } -__initfunc(static int prom_console_setup(struct console *co, char *options)) +static int __init prom_console_setup(struct console *co, char *options) { return 0; } @@ -66,7 +66,7 @@ * Register console. */ -__initfunc(long sgi_prom_console_init(long kmem_start, long kmem_end)) +long __init sgi_prom_console_init(long kmem_start, long kmem_end) { register_console(&sercons); return kmem_start; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c --- v2.3.15/linux/arch/mips/sgi/kernel/setup.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/setup.c Thu Aug 26 12:42:32 1999 @@ -118,7 +118,7 @@ sgi_read_status }; -__initfunc(static void sgi_irq_setup(void)) +static void __init sgi_irq_setup(void) { sgint_init(); @@ -129,7 +129,7 @@ #endif } -__initfunc(void sgi_setup(void)) +void __init sgi_setup(void) { #ifdef CONFIG_SERIAL_CONSOLE char *ctype; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/system.c linux/arch/mips/sgi/kernel/system.c --- v2.3.15/linux/arch/mips/sgi/kernel/system.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/system.c Thu Aug 26 12:42:32 1999 @@ -35,7 +35,7 @@ #define NUM_CPUS 9 /* for now */ -__initfunc(static int string_to_cpu(char *s)) +static int __init string_to_cpu(char *s) { int i; @@ -54,7 +54,7 @@ * We' call this early before loadmmu(). If we do the other way around * the firmware will crash and burn. */ -__initfunc(void sgi_sysinit(void)) +void __init sgi_sysinit(void) { pcomponent *p, *toplev, *cpup = 0; int cputype = -1; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sgi/kernel/time.c linux/arch/mips/sgi/kernel/time.c --- v2.3.15/linux/arch/mips/sgi/kernel/time.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/time.c Thu Aug 26 12:42:32 1999 @@ -8,7 +8,7 @@ extern void indy_timer_init(void); -__initfunc(void time_init(void)) +void __init time_init(void) { /* XXX assume INDY for now XXX */ indy_timer_init(); diff -u --recursive --new-file v2.3.15/linux/arch/mips/sni/pcimt_scache.c linux/arch/mips/sni/pcimt_scache.c --- v2.3.15/linux/arch/mips/sni/pcimt_scache.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sni/pcimt_scache.c Thu Aug 26 12:42:32 1999 @@ -16,7 +16,7 @@ #define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF) #define invspace (*(volatile unsigned int *)PCIMT_INVSPACE) -__initfunc(void sni_pcimt_sc_init(void)) +void __init sni_pcimt_sc_init(void) { unsigned int scsiz, sc_size; diff -u --recursive --new-file v2.3.15/linux/arch/mips/sni/setup.c linux/arch/mips/sni/setup.c --- v2.3.15/linux/arch/mips/sni/setup.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sni/setup.c Thu Aug 26 12:42:32 1999 @@ -53,7 +53,7 @@ extern struct rtc_ops std_rtc_ops; extern struct kbd_ops std_kbd_ops; -__initfunc(static void sni_irq_setup(void)) +static void __init sni_irq_setup(void) { set_except_vector(0, sni_rm200_pci_handle_int); request_region(0x20,0x20, "pic1"); @@ -69,7 +69,7 @@ void (*board_time_init)(struct irqaction *irq); -__initfunc(static void sni_rm200_pci_time_init(struct irqaction *irq)) +static void __init sni_rm200_pci_time_init(struct irqaction *irq) { /* set the clock to 100 Hz */ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ @@ -104,7 +104,7 @@ printk("%s.\n", boardtype); } -__initfunc(void sni_rm200_pci_setup(void)) +void __init sni_rm200_pci_setup(void) { tag *atag; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c --- v2.3.15/linux/arch/ppc/8xx_io/fec.c Wed Aug 18 11:39:01 1999 +++ linux/arch/ppc/8xx_io/fec.c Thu Aug 26 12:42:32 1999 @@ -790,7 +790,7 @@ /* Initialize the FECC Ethernet on 860T. */ -__initfunc(int m8xx_enet_init(void)) +int __init m8xx_enet_init(void) { struct net_device *dev; struct fec_enet_private *fep; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c --- v2.3.15/linux/arch/ppc/8xx_io/uart.c Sat May 15 15:05:35 1999 +++ linux/arch/ppc/8xx_io/uart.c Tue Aug 31 11:30:47 1999 @@ -1826,7 +1826,7 @@ serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -2243,7 +2243,7 @@ /* * Register console. */ -__initfunc (long console_8xx_init(long kmem_start, long kmem_end)) +long __init console_8xx_init(long kmem_start, long kmem_end) { register_console(&sercons); return kmem_start; @@ -2254,7 +2254,7 @@ /* * The serial driver boot-time initialization code! */ -__initfunc(int rs_8xx_init(void)) +int __init rs_8xx_init(void) { struct serial_state * state; ser_info_t *info; @@ -2596,7 +2596,7 @@ /* This must always be called before the rs_8xx_init() function, otherwise * it blows away the port control information. */ -__initfunc(static int serial_console_setup(struct console *co, char *options)) +static int __init serial_console_setup(struct console *co, char *options) { struct serial_state *ser; uint mem_addr, dp_addr; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.3.15/linux/arch/ppc/Makefile Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/Makefile Tue Aug 31 11:36:43 1999 @@ -21,8 +21,8 @@ ASFLAGS = 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 \ +CFLAGS := $(CFLAGS) -I$(HPATH) -D__powerpc__ -fsigned-char -msoft-float \ + -pipe -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple \ -mstring CPP = $(CC) -E $(CFLAGS) @@ -34,12 +34,22 @@ CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-mpowerpc64 endif +ifndef CONFIG_8xx HEAD := arch/ppc/kernel/head.o +else +HEAD := arch/ppc/kernel/head_8xx.o +endif ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS) ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES) CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES) + +ifdef CONFIG_8xx +SUBDIRS += arch/ppc/math-emu +ARCHIVES += arch/ppc/math-emu/math-emu.o +CORE_FILES += arch/ppc/math-emu/math-emu.o +endif ifdef CONFIG_XMON SUBDIRS += arch/ppc/xmon diff -u --recursive --new-file v2.3.15/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.3.15/linux/arch/ppc/amiga/amiints.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/amiga/amiints.c Tue Aug 31 11:36:43 1999 @@ -79,7 +79,7 @@ * the amiga IRQ handling routines. */ -__initfunc(void amiga_init_IRQ(void)) +void __init amiga_init_IRQ(void) { int i; @@ -108,7 +108,7 @@ custom.intreq = 0x7fff; #ifdef CONFIG_APUS - /* Clear any inter-CPU interupt requests. Circumvents bug in + /* Clear any inter-CPU interrupt requests. Circumvents bug in Blizzard IPL emulation HW (or so it appears). */ APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/amiga/bootinfo.c linux/arch/ppc/amiga/bootinfo.c --- v2.3.15/linux/arch/ppc/amiga/bootinfo.c Mon Dec 21 08:37:20 1998 +++ linux/arch/ppc/amiga/bootinfo.c Thu Aug 26 12:42:32 1999 @@ -24,7 +24,7 @@ extern int atari_parse_bootinfo(const struct bi_record *); extern int mac_parse_bootinfo(const struct bi_record *); -__initfunc(void parse_bootinfo(const struct bi_record *record)) +void __init parse_bootinfo(const struct bi_record *record) { while (record->tag != BI_LAST) { int unknown = 0; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c --- v2.3.15/linux/arch/ppc/amiga/config.c Tue Jul 13 02:29:35 1999 +++ linux/arch/ppc/amiga/config.c Thu Aug 26 12:42:32 1999 @@ -183,7 +183,7 @@ * Identify builtin hardware */ -__initfunc(static void amiga_identify(void)) +static void __init amiga_identify(void) { /* Fill in some default values, if necessary */ if (amiga_eclock == 0) @@ -344,7 +344,7 @@ * Setup the Amiga configuration info */ -__initfunc(void config_amiga(void)) +void __init config_amiga(void) { amiga_debug_init(); amiga_identify(); @@ -437,8 +437,8 @@ static unsigned short jiffy_ticks; -__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *, - struct pt_regs *))) +static void __init amiga_sched_init(void (*timer_routine)(int, void *, + struct pt_regs *)) { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; @@ -819,7 +819,7 @@ } #endif -__initfunc(static void amiga_debug_init(void)) +static void __init amiga_debug_init(void) { if (!strcmp( m68k_debug_device, "ser" )) { /* no initialization required (?) */ diff -u --recursive --new-file v2.3.15/linux/arch/ppc/amiga/ints.c linux/arch/ppc/amiga/ints.c --- v2.3.15/linux/arch/ppc/amiga/ints.c Tue Aug 4 16:06:36 1998 +++ linux/arch/ppc/amiga/ints.c Thu Aug 26 12:42:32 1999 @@ -42,7 +42,7 @@ * the IRQ handling routines. */ -__initfunc(void apus_init_IRQ(void)) +void __init apus_init_IRQ(void) { int i; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile --- v2.3.15/linux/arch/ppc/boot/Makefile Sat May 22 13:03:00 1999 +++ linux/arch/ppc/boot/Makefile Tue Aug 31 11:36:43 1999 @@ -47,9 +47,9 @@ OBJCOPY_ARGS = -O elf32-powerpc OBJECTS += vreset.o kbd.o of1275.o - ifeq ($(CONFIG_SERIAL_CONSOLE),y) - OBJECTS += ns16550.o - endif +ifeq ($(CONFIG_SERIAL_CONSOLE),y) +OBJECTS += ns16550.o +endif all: zImage @@ -71,9 +71,12 @@ zvmlinux.initrd.tmp $@ rm zvmlinux.initrd.tmp -zImage: zvmlinux mkprep +zImage: zvmlinux mkprep sImage ./mkprep -pbp zvmlinux zImage +sImage: ../../../vmlinux + $(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage + zImage.initrd: zvmlinux.initrd mkprep ./mkprep -pbp zvmlinux.initrd zImage.initrd @@ -105,6 +108,7 @@ znetboot : zImage cp zImage $(TFTPIMAGE) + cp sImage /tftpboot/ znetboot.initrd : zImage.initrd cp zImage.initrd $(TFTPIMAGE) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S --- v2.3.15/linux/arch/ppc/boot/head.S Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/boot/head.S Tue Aug 31 11:36:43 1999 @@ -6,7 +6,7 @@ .text /* - * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $ + * $Id: head.S,v 1.32 1999/08/12 19:51:12 cort Exp $ * * Boot loader philosophy: * ROM loads us to some arbitrary location @@ -126,9 +126,7 @@ * entry. see boot/head.S -- Cort */ li r9,0x0 - lwz r9,0(r9) mtlr r9 - li r9,0 lis r10,0xdeadc0de@h ori r10,r10,0xdeadc0de@l stw r10,0(r9) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c --- v2.3.15/linux/arch/ppc/boot/misc.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/boot/misc.c Tue Aug 31 11:36:43 1999 @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.65 1999/05/17 19:11:13 cort Exp $ + * $Id: misc.c,v 1.67 1999/08/10 22:53:57 cort Exp $ * * Adapted for PowerPC by Gary Thomas * @@ -309,8 +309,6 @@ inflateEnd(&s); } -unsigned char sanity[0x2000]; - unsigned long decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual, void *OFW_interface) @@ -333,7 +331,6 @@ cols = 80; orig_x = 0; orig_y = 24; - /* * IBM's have the MMU on, so we have to disable it or @@ -525,7 +522,6 @@ puts("initrd_start located > 16M\n"); puts("Uncompressing Linux..."); - gunzip(0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); puts("Now booting the kernel\n"); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile --- v2.3.15/linux/arch/ppc/chrpboot/Makefile Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/chrpboot/Makefile Tue Aug 31 11:36:43 1999 @@ -57,7 +57,10 @@ mcopy zImage a:zImage piggyback: piggyback.c - $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c + $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c + +mknote: mknote.c + $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c image.o: piggyback ../coffboot/vmlinux.gz ./piggyback image < ../coffboot/vmlinux.gz | $(AS) -o image.o @@ -69,9 +72,6 @@ $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) ./mknote > note $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment - -mknote: mknote.c - $(HOSTCC) $(HOSTCFLAGS) -o $@ mknote.c zImage.initrd: $(OBJS) initrd.o $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c --- v2.3.15/linux/arch/ppc/chrpboot/main.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/chrpboot/main.c Tue Aug 31 11:36:43 1999 @@ -68,7 +68,7 @@ flush_cache(dst, len); - sa = *(unsigned long *)PROG_START+PROG_START; + sa = (unsigned long)PROG_START; printf("start address = 0x%x\n\r", sa); (*(void (*)())sa)(0, 0, prom, a1, a2); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/coffboot/main.c linux/arch/ppc/coffboot/main.c --- v2.3.15/linux/arch/ppc/coffboot/main.c Tue Aug 4 16:06:36 1998 +++ linux/arch/ppc/coffboot/main.c Tue Aug 31 11:36:43 1999 @@ -100,7 +100,7 @@ flush_cache(dst, len); - sa = *(unsigned *)dst + PROG_START; + sa = (unsigned long)dst; printf("start address = 0x%x\n", sa); #if 0 @@ -165,7 +165,7 @@ printf("gunzip: ran out of data in header\n"); exit(); } - +printf("done 1\n"); s.zalloc = zalloc; s.zfree = zfree; r = inflateInit2(&s, -MAX_WBITS); @@ -177,11 +177,14 @@ s.avail_in = *lenp - i; s.next_out = dst; s.avail_out = dstlen; +printf("doing inflate\n"); r = inflate(&s, Z_FINISH); +printf("done inflate\n"); if (r != Z_OK && r != Z_STREAM_END) { printf("inflate returned %d\n", r); exit(); } *lenp = s.next_out - (unsigned char *) dst; +printf("doing end\n"); inflateEnd(&s); } diff -u --recursive --new-file v2.3.15/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig --- v2.3.15/linux/arch/ppc/common_defconfig Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/common_defconfig Tue Aug 31 11:36:43 1999 @@ -35,7 +35,6 @@ CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set CONFIG_VGA_CONSOLE=y CONFIG_FB=y @@ -44,8 +43,6 @@ CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADBMOUSE=y CONFIG_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -53,11 +50,6 @@ # CONFIG_CMDLINE_BOOL is not set # -# Plug and Play support -# -# CONFIG_PNP is not set - -# # Block devices # CONFIG_BLK_DEV_FD=y @@ -80,9 +72,11 @@ CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -230,10 +224,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y @@ -243,10 +245,10 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y CONFIG_PCNET32=y +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -265,7 +267,10 @@ # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set + +# +# Appletalk devices +# # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set @@ -276,11 +281,21 @@ # # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # # Amateur Radio support @@ -342,14 +357,16 @@ # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_MOUSE=y # # Mice # +CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set +CONFIG_ADBMOUSE=y +CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set @@ -383,17 +400,19 @@ # CONFIG_FT_ALT_FDC is not set # +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -429,38 +448,7 @@ # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_SGI_DISKLABEL is not set # CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_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_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS is not set # # Sound diff -u --recursive --new-file v2.3.15/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.3.15/linux/arch/ppc/config.in Thu Aug 26 13:05:34 1999 +++ linux/arch/ppc/config.in Tue Aug 31 11:36:43 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.95 1999/07/03 08:57:06 davem Exp $ +# $Id: config.in,v 1.102 1999/08/30 10:06:53 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -25,8 +25,12 @@ define_bool CONFIG_MACH_SPECIFIC y fi -if [ "$CONFIG_PPC64" != "y" ];then - define_bool CONFIG_6xx y +if [ "$CONFIG_8xx" = "y" ]; then + bool 'Math emulation' CONFIG_MATH_EMULATION +else + if [ "$CONFIG_PPC64" != "y" ];then + define_bool CONFIG_6xx y + fi fi endmenu @@ -71,11 +75,10 @@ bool 'Power management support for PowerBook 3400/2400' CONFIG_PMAC_PBOOK bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY -bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL +tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL if [ "$CONFIG_MAC_SERIAL" = "y" ]; then bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi -bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT @@ -166,6 +169,7 @@ endmenu source drivers/char/Config.in +source drivers/usb/Config.in source fs/Config.in mainmenu_option next_comment diff -u --recursive --new-file v2.3.15/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.3.15/linux/arch/ppc/defconfig Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/defconfig Tue Aug 31 11:36:43 1999 @@ -43,8 +43,6 @@ CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADBMOUSE=y CONFIG_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -52,11 +50,6 @@ # CONFIG_CMDLINE_BOOL is not set # -# Plug and Play support -# -# CONFIG_PNP is not set - -# # Block devices # CONFIG_BLK_DEV_FD=y @@ -79,9 +72,11 @@ CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -229,10 +224,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y @@ -242,10 +245,10 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y CONFIG_PCNET32=y +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -264,7 +267,10 @@ # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set + +# +# Appletalk devices +# # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set @@ -275,11 +281,21 @@ # # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # # Amateur Radio support @@ -341,14 +357,16 @@ # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_MOUSE=y # # Mice # +CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set +CONFIG_ADBMOUSE=y +CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set @@ -382,17 +400,19 @@ # CONFIG_FT_ALT_FDC is not set # +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -428,38 +448,7 @@ # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_SGI_DISKLABEL is not set # CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_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_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS is not set # # Sound diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.3.15/linux/arch/ppc/kernel/Makefile Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/kernel/Makefile Tue Aug 31 11:36:43 1999 @@ -14,8 +14,11 @@ OX_OBJS := ppc_ksyms.o setup.o -O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \ - bitops.o ptrace.o align.o ppc_htab.o +O_OBJS := entry.o traps.o irq.o idle.o time.o process.o signal.o syscalls.o \ + misc.o bitops.o ptrace.o align.o ppc_htab.o semaphore.o +ifndef CONFIG_8xx +O_OBJS += hashtable.o +endif ifdef CONFIG_PCI O_OBJS += pci.o endif @@ -27,17 +30,18 @@ endif ifeq ($(CONFIG_MBX),y) -O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o +O_OBJS += mbx_setup.o mbx_pci.o i8259.o ppc8xx_pic.o else ifeq ($(CONFIG_APUS),y) -O_OBJS += apus_setup.o prom.o openpic.o +O_OBJS += apus_setup.o prom.o open_pic.o else ifneq ($(CONFIG_MBX),y) O_OBJS += prep_time.o pmac_time.o chrp_time.o \ pmac_setup.o pmac_support.o \ prep_pci.o pmac_pci.o chrp_pci.o \ - residual.o prom.o openpic.o feature.o \ - prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o + residual.o prom.o open_pic.o feature.o \ + prep_nvram.o i8259.o pmac_pic.o indirect_pci.o \ + gemini_pci.o gemini_prom.o gemini_setup.o OX_OBJS += chrp_setup.o prep_setup.o endif endif @@ -49,7 +53,7 @@ all: head.o kernel.o -head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h +head.o: head.S ppc_defs.h ppc_defs.h: mk_defs.c ppc_defs.head \ $(TOPDIR)/include/asm/mmu.h \ @@ -65,7 +69,7 @@ $(HOSTCC) $(HOSTCFLAGS) -o find_name find_name.c checks: checks.c - $(HOSTCC) $(HOSTCFLAGS) -D__KERNEL__ -o checks checks.c + $(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -o checks checks.c ./checks include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/align.c linux/arch/ppc/kernel/align.c --- v2.3.15/linux/arch/ppc/kernel/align.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/align.c Tue Aug 31 11:36:43 1999 @@ -243,10 +243,10 @@ } break; case LD+F: - current->tss.fpr[reg] = data.d; + current->thread.fpr[reg] = data.d; break; case ST+F: - data.d = current->tss.fpr[reg]; + data.d = current->thread.fpr[reg]; break; /* these require some floating point conversions... */ /* we'd like to use the assignment, but we have to compile @@ -254,13 +254,13 @@ * fp regs for copying 8-byte objects. */ case LD+F+S: enable_kernel_fp(); - cvt_fd(&data.f, ¤t->tss.fpr[reg], ¤t->tss.fpscr); - /* current->tss.fpr[reg] = data.f; */ + cvt_fd(&data.f, ¤t->thread.fpr[reg], ¤t->thread.fpscr); + /* current->thread.fpr[reg] = data.f; */ break; case ST+F+S: enable_kernel_fp(); - cvt_df(¤t->tss.fpr[reg], &data.f, ¤t->tss.fpscr); - /* data.f = current->tss.fpr[reg]; */ + cvt_df(¤t->thread.fpr[reg], &data.f, ¤t->thread.fpscr); + /* data.f = current->thread.fpr[reg]; */ break; default: printk("align: can't handle flags=%x\n", flags); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.3.15/linux/arch/ppc/kernel/apus_setup.c Mon Aug 9 12:32:28 1999 +++ linux/arch/ppc/kernel/apus_setup.c Thu Aug 26 12:42:32 1999 @@ -103,8 +103,8 @@ /*********************************************************** SETUP */ /* From arch/m68k/kernel/setup.c. */ -__initfunc(void apus_setup_arch(unsigned long * memory_start_p, - unsigned long * memory_end_p)) +void __init apus_setup_arch(unsigned long * memory_start_p, + unsigned long * memory_end_p) { extern char cmd_line[]; int i; @@ -245,7 +245,7 @@ /*********************************************************** FLOPPY */ #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) -__initfunc(void floppy_setup(char *str, int *ints)) +void __init floppy_setup(char *str, int *ints) { if (mach_floppy_setup) mach_floppy_setup (str, ints); @@ -560,24 +560,24 @@ m68k_ide_fix_driveid(id); } -__initfunc(void -apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)) +void __init +apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq); } #endif -__initfunc(void -apus_local_init_IRQ(void)) +void __init +apus_local_init_IRQ(void) { ppc_md.mask_irq = amiga_disable_irq; ppc_md.unmask_irq = amiga_enable_irq; apus_init_IRQ(); } -__initfunc(void +void __init apus_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { /* Parse bootinfo. The bootinfo is located right after the kernel bss */ diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.3.15/linux/arch/ppc/kernel/chrp_pci.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/kernel/chrp_pci.c Tue Aug 31 11:36:43 1999 @@ -279,8 +279,7 @@ if ( !strncmp("IBM", get_property(find_path_device("/"), "name", NULL),3) ) { - pci_scan_peer_bridge(1); - pci_scan_peer_bridge(2); + } /* PCI interrupts are controlled by the OpenPIC */ @@ -290,22 +289,22 @@ dev->irq = openpic_to_irq( dev->irq ); /* adjust the io_port for the NCR cards for busses other than 0 -- Cort */ if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) ) - dev->base_address[0] += (dev->bus->number*0x08000000); + dev->resource[0].start += (dev->bus->number*0x08000000); /* these need to be absolute addrs for OF and Matrox FB -- Cort */ if ( dev->vendor == PCI_VENDOR_ID_MATROX ) { - if ( dev->base_address[0] < isa_mem_base ) - dev->base_address[0] += isa_mem_base; - if ( dev->base_address[1] < isa_mem_base ) - dev->base_address[1] += isa_mem_base; + if ( dev->resource[0].start < isa_mem_base ) + dev->resource[0].start += isa_mem_base; + if ( dev->resource[1].start < isa_mem_base ) + dev->resource[1].start += isa_mem_base; } /* the F50 identifies the amd as a trident */ if ( (dev->vendor == PCI_VENDOR_ID_TRIDENT) && - (dev->class == PCI_CLASS_NETWORK_ETHERNET) ) + (dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET) ) { dev->vendor = PCI_VENDOR_ID_AMD; - pcibios_write_config_word(dev->bus->number, dev->devfn, - PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); + pcibios_write_config_word(dev->bus->number, + dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); } } } diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.3.15/linux/arch/ppc/kernel/chrp_setup.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/kernel/chrp_setup.c Tue Aug 31 11:36:43 1999 @@ -191,20 +191,20 @@ * for keyboard and mouse */ -__initfunc(static inline void sio_write(u8 val, u8 index)) +static inline void __init sio_write(u8 val, u8 index) { outb(index, 0x15c); outb(val, 0x15d); } -__initfunc(static inline u8 sio_read(u8 index)) +static inline u8 __init sio_read(u8 index) { outb(index, 0x15c); return inb(0x15d); } -__initfunc(static void sio_fixup_irq(const char *name, u8 device, u8 level, - u8 type)) +static void __init sio_fixup_irq(const char *name, u8 device, u8 level, + u8 type) { u8 level0, type0, active; @@ -226,7 +226,7 @@ } -__initfunc(static void sio_init(void)) +static void __init sio_init(void) { /* logical device 0 (KBC/Keyboard) */ sio_fixup_irq("keyboard", 0, 1, 2); @@ -235,8 +235,8 @@ } -__initfunc(void - chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init + chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { extern char cmd_line[]; struct device_node *device; @@ -315,7 +315,10 @@ chrp_event_scan(void) { unsigned char log[1024]; - call_rtas( "event-scan", 4, 1, NULL, 0x0, 1, __pa(log), 1024 ); + unsigned long ret = 0; + /* XXX: we should loop until the hardware says no more error logs -- Cort */ + call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0, + __pa(log), 1024 ); ppc_md.heartbeat_count = ppc_md.heartbeat_reset; } @@ -331,12 +334,8 @@ chrp_power_off(void) { /* allow power on only with power button press */ -#define PWR_FIELD(x) (0x8000000000000000ULL >> ((x)-96)) printk("RTAS power-off returned %d\n", - call_rtas("power-off", 2, 1, NULL, - ((PWR_FIELD(96)|PWR_FIELD(97))>>32)&0xffffffff, - (PWR_FIELD(96)|PWR_FIELD(97))&0xffffffff)); -#undef PWR_FIELD + call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff)); for (;;); } @@ -434,8 +433,8 @@ openpic_eoi(0); } -__initfunc(void - chrp_init_IRQ(void)) +void __init + chrp_init_IRQ(void) { struct device_node *np; int i; @@ -448,12 +447,9 @@ (*(unsigned long *)get_property(np, "8259-interrupt-acknowledge", NULL)); } + open_pic.irq_offset = 16; for ( i = 16 ; i < NR_IRQS ; i++ ) irq_desc[i].ctl = &open_pic; - /* openpic knows that it's at irq 16 offset - * so we don't need to set it in the pic structure - * -- Cort - */ openpic_init(1); for ( i = 0 ; i < 16 ; i++ ) irq_desc[i].ctl = &i8259_pic; @@ -468,8 +464,8 @@ #endif /* __SMP__ */ } -__initfunc(void - chrp_init2(void)) +void __init + chrp_init2(void) { adb_init(); @@ -493,12 +489,9 @@ chrp_ide_ports_known = 1; if(pdev) { - chrp_ide_regbase[0]=pdev->base_address[0] & - PCI_BASE_ADDRESS_IO_MASK; - chrp_ide_regbase[1]=pdev->base_address[2] & - PCI_BASE_ADDRESS_IO_MASK; - chrp_idedma_regbase=pdev->base_address[4] & - PCI_BASE_ADDRESS_IO_MASK; + chrp_ide_regbase[0]=pdev->resource[0].start; + chrp_ide_regbase[1]=pdev->resource[2].start; + chrp_idedma_regbase=pdev->resource[4].start; chrp_ide_irq=pdev->irq; } } @@ -584,9 +577,9 @@ #endif -__initfunc(void +void __init chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { chrp_setup_pci_ptrs(); #ifdef CONFIG_BLK_DEV_INITRD @@ -688,14 +681,18 @@ void chrp_progress(char *s, unsigned short hex) { extern unsigned int rtas_data; - unsigned long width; + int max_width, width; struct device_node *root; char *os = s; - - if ( (root = find_path_device("/rtas")) ) - width = *(unsigned long *)get_property(root, "ibm,display-line-length", NULL); + unsigned long *p; + + if ( (root = find_path_device("/rtas")) && + (p = (unsigned long *)get_property(root, + "ibm,display-line-length", + NULL)) ) + max_width = *p; else - width = 0x10; + max_width = 0x10; if ( (_machine != _MACH_chrp) || !rtas_data ) return; @@ -704,11 +701,22 @@ /* assume no display-character RTAS method - use hex display */ return; } + + width = max_width; while ( *os ) + { + if ( (*os == '\n') || (*os == '\r') ) + width = max_width; + else + width--; call_rtas( "display-character", 1, 1, NULL, *os++ ); - /* scan back for the last newline or carriage return */ - for ( os-- ; (*os != '\n') && (*os != '\r') && (os > s) ; os--, width-- ) - /* nothing */ ; - /*while ( width-- )*/ + /* if we overwrite the screen length */ + if ( width == 0 ) + while ( (*os != 0) && (*os != '\n') && (*os != '\r') ) + os++; + } + + /*while ( width-- > 0 )*/ call_rtas( "display-character", 1, 1, NULL, ' ' ); } + diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c --- v2.3.15/linux/arch/ppc/kernel/chrp_time.c Fri Mar 19 10:50:03 1999 +++ linux/arch/ppc/kernel/chrp_time.c Thu Aug 26 12:42:32 1999 @@ -31,7 +31,7 @@ static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; -__initfunc(void chrp_time_init(void)) +void __init chrp_time_init(void) { struct device_node *rtcs; int base; @@ -151,7 +151,7 @@ } -__initfunc(void chrp_calibrate_decr(void)) +void __init chrp_calibrate_decr(void) { struct device_node *cpu; int *fp, divisor; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.3.15/linux/arch/ppc/kernel/entry.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/entry.S Tue Aug 31 11:36:43 1999 @@ -0,0 +1,436 @@ +/* + * arch/ppc/kernel/entry.S + * + * $Id: entry.S,v 1.2 1999/08/23 02:53:16 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains the system call entry code, context switch + * code, and exception/interrupt return code for PowerPC. + * + * 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 "ppc_asm.h" +#include +#include +#include +#include +#include + +#define SHOW_SYSCALLS +#define SHOW_SYSCALLS_TASK + +#ifdef SHOW_SYSCALLS_TASK + .data +show_syscalls_task: + .long -1 +#endif + +/* + * Handle a system call. + */ + .text +_GLOBAL(DoSyscall) + stw r0,THREAD+LAST_SYSCALL(r2) + lwz r11,_CCR(r1) /* Clear SO bit in CR */ + lis r10,0x1000 + andc r11,r11,r10 + stw r11,_CCR(r1) +#ifdef SHOW_SYSCALLS +#ifdef SHOW_SYSCALLS_TASK + lis r31,show_syscalls_task@ha + lwz r31,show_syscalls_task@l(r31) + cmp 0,r2,r31 + bne 1f +#endif + lis r3,7f@ha + addi r3,r3,7f@l + lwz r4,GPR0(r1) + lwz r5,GPR3(r1) + lwz r6,GPR4(r1) + lwz r7,GPR5(r1) + lwz r8,GPR6(r1) + lwz r9,GPR7(r1) + bl printk + lis r3,77f@ha + addi r3,r3,77f@l + lwz r4,GPR8(r1) + lwz r5,GPR9(r1) + mr r6,r2 + bl printk + lwz r0,GPR0(r1) + lwz r3,GPR3(r1) + lwz r4,GPR4(r1) + lwz r5,GPR5(r1) + lwz r6,GPR6(r1) + lwz r7,GPR7(r1) + lwz r8,GPR8(r1) +1: +#endif /* SHOW_SYSCALLS */ + cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */ + beq- 10f + lwz r10,TASK_FLAGS(r2) + andi. r10,r10,PF_TRACESYS + bne- 50f + cmpli 0,r0,NR_syscalls + bge- 66f + lis r10,sys_call_table@h + ori r10,r10,sys_call_table@l + slwi r0,r0,2 + lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ + cmpi 0,r10,0 + beq- 66f + mtlr r10 + addi r9,r1,STACK_FRAME_OVERHEAD + blrl /* Call handler */ + .globl ret_from_syscall_1 +ret_from_syscall_1: +20: stw r3,RESULT(r1) /* Save result */ +#ifdef SHOW_SYSCALLS +#ifdef SHOW_SYSCALLS_TASK + cmp 0,r2,r31 + bne 91f +#endif + mr r4,r3 + lis r3,79f@ha + addi r3,r3,79f@l + bl printk + lwz r3,RESULT(r1) +91: +#endif + li r10,-_LAST_ERRNO + cmpl 0,r3,r10 + blt 30f + neg r3,r3 + cmpi 0,r3,ERESTARTNOHAND + bne 22f + li r3,EINTR +22: lwz r10,_CCR(r1) /* Set SO bit in CR */ + oris r10,r10,0x1000 + stw r10,_CCR(r1) +30: stw r3,GPR3(r1) /* Update return value */ + b ret_from_except +66: li r3,ENOSYS + b 22b +/* sys_sigreturn */ +10: addi r3,r1,STACK_FRAME_OVERHEAD + bl sys_sigreturn + cmpi 0,r3,0 /* Check for restarted system call */ + bge ret_from_except + b 20b +/* Traced system call support */ +50: bl syscall_trace + lwz r0,GPR0(r1) /* Restore original registers */ + lwz r3,GPR3(r1) + lwz r4,GPR4(r1) + lwz r5,GPR5(r1) + lwz r6,GPR6(r1) + lwz r7,GPR7(r1) + lwz r8,GPR8(r1) + lwz r9,GPR9(r1) + cmpli 0,r0,NR_syscalls + bge- 66f + lis r10,sys_call_table@h + ori r10,r10,sys_call_table@l + slwi r0,r0,2 + lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ + cmpi 0,r10,0 + beq- 66f + mtlr r10 + addi r9,r1,STACK_FRAME_OVERHEAD + blrl /* Call handler */ + .globl ret_from_syscall_2 +ret_from_syscall_2: + stw r3,RESULT(r1) /* Save result */ + stw r3,GPR0(r1) /* temporary gross hack to make strace work */ + li r10,-_LAST_ERRNO + cmpl 0,r3,r10 + blt 60f + neg r3,r3 + cmpi 0,r3,ERESTARTNOHAND + bne 52f + li r3,EINTR +52: lwz r10,_CCR(r1) /* Set SO bit in CR */ + oris r10,r10,0x1000 + stw r10,_CCR(r1) +60: stw r3,GPR3(r1) /* Update return value */ + bl syscall_trace + b ret_from_except +66: li r3,ENOSYS + b 52b +#ifdef SHOW_SYSCALLS +7: .string "syscall %d(%x, %x, %x, %x, %x, " +77: .string "%x, %x), current=%p\n" +79: .string " -> %x\n" + .align 2 +#endif + +/* + * This routine switches between two different tasks. The process + * state of one is saved on its kernel stack. Then the state + * of the other is restored from its kernel stack. The memory + * management hardware is updated to the second process's state. + * Finally, we can return to the second process, via ret_from_except. + * On entry, r3 points to the THREAD for the current task, r4 + * points to the THREAD for the new task. + * + * Note: there are two ways to get to the "going out" portion + * of this code; either by coming in via the entry (_switch) + * or via "fork" which must set up an environment equivalent + * to the "_switch" path. If you change this (or in particular, the + * SAVE_REGS macro), you'll have to change the fork code also. + * + * The code which creates the new task context is in 'copy_thread' + * in arch/ppc/kernel/process.c + */ +_GLOBAL(_switch) + stwu r1,-INT_FRAME_SIZE(r1) + stw r0,GPR0(r1) + lwz r0,0(r1) + stw r0,GPR1(r1) + /* r3-r13 are caller saved -- Cort */ + SAVE_GPR(2, r1) + SAVE_8GPRS(14, r1) + SAVE_10GPRS(22, r1) + mflr r20 /* Return to switch caller */ + mfmsr r22 + li r0,MSR_FP /* Disable floating-point */ + andc r22,r22,r0 + stw r20,_NIP(r1) + stw r22,_MSR(r1) + stw r20,_LINK(r1) + mfcr r20 + mfctr r22 + mfspr r23,XER + stw r20,_CCR(r1) + stw r22,_CTR(r1) + stw r23,_XER(r1) + li r0,0x0ff0 + stw r0,TRAP(r1) + stw r1,KSP(r3) /* Set old stack pointer */ + sync + tophys(r0,r4) + mtspr SPRG3,r0 /* Update current THREAD phys addr */ +#ifdef CONFIG_8xx + /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */ + lwz r9,PGDIR(r4) /* cache the page table root */ + tophys(r9,r9) /* convert to phys addr */ + mtspr M_TWB,r9 /* Update MMU base address */ +#endif /* CONFIG_8xx */ + lwz r1,KSP(r4) /* Load new stack pointer */ + /* save the old current 'last' for return value */ + mr r3,r2 + addi r2,r4,-THREAD /* Update current */ + lwz r9,_MSR(r1) /* Returning to user mode? */ + andi. r9,r9,MSR_PR + beq+ 10f /* if not, don't adjust kernel stack */ +8: addi r4,r1,INT_FRAME_SIZE /* size of frame */ + stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ + tophys(r9,r1) + mtspr SPRG2,r9 /* phys exception stack pointer */ +10: lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + /* r3-r13 are destroyed -- Cort */ + REST_GPR(14, r1) + REST_8GPRS(15, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +/* + * ret_from_int(): + * + * Return from an interrupt (external interrupt and + * decrementer). This checks the first argument so + * we know if rtl_intercept wants us to check for + * a bottom half, signals and so on (normal return) or + * we're returning from a real-time interrupt or have + * interrupts soft disabled so we cannot enter Linux. + * -- Cort + */ + .globl ret_from_int +ret_from_int: + cmpi 0,r3,0 + beq 10f + /* we're allowed to do signal/bh checks */ + b ret_from_syscall +#ifdef __SMP__ + .globl ret_from_smpfork +ret_from_smpfork: + bl schedule_tail +#endif + .globl ret_from_syscall +ret_from_syscall: + .globl ret_from_except +ret_from_except: +0: mfmsr r30 /* Disable interrupts */ + li r3,0 + ori r3,r3,MSR_EE + andc r30,r30,r3 + SYNC /* Some chip revs need this... */ + mtmsr r30 + SYNC + lwz r5,_MSR(r1) + and. r5,r5,r4 + beq 2f +3: lis r4,ppc_n_lost_interrupts@ha + lwz r4,ppc_n_lost_interrupts@l(r4) + cmpi 0,r4,0 + beq+ 1f + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_IRQ + .globl lost_irq_ret +lost_irq_ret: + b 3b +1: lis r4,bh_mask@ha + lwz r4,bh_mask@l(r4) + lis r5,bh_active@ha + lwz r5,bh_active@l(r5) + and. r4,r4,r5 + beq+ 2f + bl do_bottom_half + .globl do_bottom_half_ret +do_bottom_half_ret: +2: SYNC + mtmsr r30 /* disable interrupts again */ + SYNC + lwz r3,_MSR(r1) /* Returning to user mode? */ + andi. r3,r3,MSR_PR + beq+ 10f /* if so, check need_resched and signals */ + lwz r3,NEED_RESCHED(r2) + cmpi 0,r3,0 /* check need_resched flag */ + beq+ 7f + bl schedule + b 0b +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 do_signal + .globl do_signal_ret +do_signal_ret: + b 0b +8: addi r4,r1,INT_FRAME_SIZE /* size of frame */ + stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ + tophys(r3,r1) + mtspr SPRG2,r3 /* phys exception stack pointer */ +10: lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +/* + * Fake an interrupt from kernel mode. + * This is used when enable_irq loses an interrupt. + * We only fill in the stack frame minimally. + */ +_GLOBAL(fake_interrupt) + mflr r0 + stw r0,4(r1) + stwu r1,-INT_FRAME_SIZE(r1) + stw r0,_NIP(r1) + stw r0,_LINK(r1) + mfmsr r3 + stw r3,_MSR(r1) + li r0,0x0fac + stw r0,TRAP(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + li r4,1 + bl do_IRQ + addi r1,r1,INT_FRAME_SIZE + lwz r0,4(r1) + mtlr r0 + blr + +#ifndef CONFIG_8xx +/* + * PROM code for specific machines follows. Put it + * here so it's easy to add arch-specific sections later. + * -- Cort + */ + +/* + * On CHRP, the Run-Time Abstraction Services (RTAS) have to be + * called with the MMU off. + */ + .globl enter_rtas +enter_rtas: + mflr r0 + stw r0,20(r1) + lis r4,rtas_data@ha + lwz r4,rtas_data@l(r4) + addis r4,r4,-KERNELBASE@h + 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 + addis r7,r7,-KERNELBASE@h + lis r8,rtas_entry@ha + lwz r8,rtas_entry@l(r8) + addis r5,r8,-KERNELBASE@h + mfmsr r9 + stw r9,8(r1) + 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 */ +#endif /* CONFIG_8xx */ diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/gemini_pci.c linux/arch/ppc/kernel/gemini_pci.c --- v2.3.15/linux/arch/ppc/kernel/gemini_pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/gemini_pci.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,268 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pci.h" + +#define pci_config_addr(bus,dev,offset) \ + (0x80000000 | (bus<<16) | (dev<<8) | offset) + + +int +gemini_pcibios_read_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char *val) +{ + unsigned long reg; + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short *val) +{ + unsigned long reg; + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int *val) +{ + *val = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char val) +{ + unsigned long reg; + int shifts = offset & 0x3; + + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short val) +{ + unsigned long reg; + int shifts = offset & 0x3; + + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int val) +{ + grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), val ); + return PCIBIOS_SUCCESSFUL; +} + +struct gemini_device { + unsigned short vendor, device; + unsigned char irq; + unsigned short cmd; + unsigned char cache_line, latency; + void (*init)(struct pci_dev *dev); +}; + +static struct gemini_device gemini_map[] = { + { PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885, 11, 0x15, 32, 248, NULL }, + { PCI_VENDOR_ID_NCR, 0x701, 10, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C042, 3, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_MPIC, 0xff, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_670, 0xff, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_MOTOROLA, PCI_DEVICE_ID_MOTOROLA_MPC106, 0xff, 0, 0, 0, NULL }, +}; + +static int gemini_map_count = (sizeof( gemini_map ) / + sizeof( gemini_map[0] )); + + + +/* This just sets up the known devices on the board. */ +static void __init mapin_device( struct pci_dev *dev ) +{ + struct gemini_device *p; + unsigned short cmd; + int i; + + + for( i=0; i < gemini_map_count; i++ ) { + p = &(gemini_map[i]); + + if ( p->vendor == dev->vendor && + p->device == dev->device ) { + + if (p->irq != 0xff) { + pci_write_config_byte( dev, PCI_INTERRUPT_LINE, p->irq ); + dev->irq = p->irq; + } + + if (p->cmd) { + pci_read_config_word( dev, PCI_COMMAND, &cmd ); + pci_write_config_word( dev, PCI_COMMAND, (p->cmd|cmd)); + } + + if (p->cache_line) + pci_write_config_byte( dev, PCI_CACHE_LINE_SIZE, p->cache_line ); + + if (p->latency) + pci_write_config_byte( dev, PCI_LATENCY_TIMER, p->latency ); + } + } +} + +#define KB 1024 +#define MB (KB*KB) + +#define ALIGN(val,align) (((val) + ((align) -1))&(~((align) -1))) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define FIRST_IO_ADDR 0x10000 +#define FIRST_MEM_ADDR 0x02000000 + +#define GEMINI_PCI_MEM_BASE (0xf0000000) +#define GEMINI_PCI_IO_BASE (0xfe800000) + +static unsigned long pci_mem_base = GEMINI_PCI_MEM_BASE; +static unsigned long pci_io_base = GEMINI_PCI_IO_BASE; + +static unsigned int io_base = FIRST_IO_ADDR; +static unsigned int mem_base = FIRST_MEM_ADDR; + + + +static __init void layout_dev( struct pci_dev *dev ) +{ + int i; + struct pci_bus *bus; + unsigned short cmd; + unsigned int reg, base, mask, size, alignto, type; + + bus = dev->bus; + + /* make any known settings happen */ + mapin_device( dev ); + + gemini_pcibios_read_config_word( bus->number, dev->devfn, PCI_COMMAND, &cmd ); + + for( reg = PCI_BASE_ADDRESS_0, i=0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++ ) { + + /* MPIC already done */ + if (dev->vendor == PCI_VENDOR_ID_IBM && + dev->device == PCI_DEVICE_ID_IBM_MPIC) + return; + + gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 0xffffffff ); + gemini_pcibios_read_config_dword( bus->number, dev->devfn, reg, &base ); + if (!base) { + dev->resource[i].start = 0; + continue; + } + + if (base & PCI_BASE_ADDRESS_SPACE_IO) { + cmd |= PCI_COMMAND_IO; + base &= PCI_BASE_ADDRESS_IO_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + alignto = MAX(0x400, size); + base = ALIGN(io_base, alignto); + io_base = base + size; + gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, + ((pci_io_base + base) & 0x00ffffff) | 0x1); + dev->resource[i].start = (pci_io_base + base) | 0x1; + } + + else { + cmd |= PCI_COMMAND_MEMORY; + type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + switch( type ) { + + case PCI_BASE_ADDRESS_MEM_TYPE_32: + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + printk("Warning: Ignoring 64-bit device; slot %d, function %d.\n", + PCI_SLOT( dev->devfn ), PCI_FUNC( dev->devfn )); + reg += 4; + continue; + } + + alignto = MAX(0x1000, size); + base = ALIGN(mem_base, alignto); + mem_base = base + size; + gemini_pcibios_write_config_dword( bus->number, dev->devfn, + reg, (pci_mem_base + base)); + dev->resource[i].start = pci_mem_base + base; + } + } + + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + cmd |= PCI_COMMAND_IO; + + gemini_pcibios_write_config_word( bus->number, dev->devfn, PCI_COMMAND, + (cmd|PCI_COMMAND_MASTER)); +} + +static __init void layout_bus( struct pci_bus *bus ) +{ + struct pci_dev *dev; + + if (!bus->devices && !bus->children) + return; + + io_base = ALIGN(io_base, 4*KB); + mem_base = ALIGN(mem_base, 4*KB); + + for( dev = bus->devices; dev; dev = dev->sibling ) { + if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) || + ((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER)) + layout_dev( dev ); + } +} + +void __init gemini_pcibios_fixup(void) +{ + struct pci_bus *bus; + unsigned long orig_mem_base, orig_io_base; + + orig_mem_base = pci_mem_base; + orig_io_base = pci_io_base; + + for( bus = &pci_root; bus; bus = bus->children ) + layout_bus( bus ); + + pci_mem_base = orig_mem_base; + pci_io_base = orig_io_base; +} + +decl_config_access_method(gemini); + +/* The "bootloader" for Synergy boards does none of this for us, so we need to + lay it all out ourselves... --Dan */ +void __init gemini_setup_pci_ptrs(void) +{ + set_config_access_method(gemini); + ppc_md.pcibios_fixup = gemini_pcibios_fixup; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/gemini_prom.S linux/arch/ppc/kernel/gemini_prom.S --- v2.3.15/linux/arch/ppc/kernel/gemini_prom.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/gemini_prom.S Tue Aug 31 11:36:43 1999 @@ -0,0 +1,95 @@ +/* + * arch/ppc/kernel/gemini_prom.S + * + * Not really prom support code (yet), but sort of anti-prom code. The current + * bootloader does a number of things it shouldn't and doesn't do things that it + * should. The stuff in here is mainly a hodge-podge collection of setup code + * to get the board up and running. + * ---Dan + */ + +#include "ppc_asm.tmpl" +#include "ppc_defs.h" +#include +#include +#include +#include + +#define HID0_ABE (1<<3) + +/* + * On 750's the MMU is on when Linux is booted, so we need to clear out the + * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), + * and turn off the MMU. + * + */ + +_GLOBAL(gemini_prom_init) +#ifdef __SMP__ + /* Since the MMU's on, get stuff in rom space that we'll need */ + lis r4,GEMINI_CPUSTAT@h + ori r4,r4,GEMINI_CPUSTAT@l + lbz r5,0(r4) + andi. r5,r5,3 + mr r24,r5 /* cpu # used later on */ +#endif + mfmsr r4 + li r3,MSR_PR /* ensure supervisor! */ + ori r3,r3,MSR_IR|MSR_DR + andc r4,r4,r3 + mtmsr r4 +#if 0 + /* zero out the bats now that the MMU is off */ +prom_no_mmu: + li r3,0 + mtspr IBAT0U,r3 + mtspr IBAT0L,r3 + mtspr IBAT1U,r3 + mtspr IBAT1L,r3 + mtspr IBAT2U,r3 + mtspr IBAT2L,r3 + mtspr IBAT3U,r3 + mtspr IBAT3L,r3 + + mtspr DBAT0U,r3 + mtspr DBAT0L,r3 + mtspr DBAT1U,r3 + mtspr DBAT1L,r3 + mtspr DBAT2U,r3 + mtspr DBAT2L,r3 + mtspr DBAT3U,r3 + mtspr DBAT3L,r3 +#endif + + /* the bootloader (as far as I'm currently aware) doesn't mess with page + tables, but since we're already here, might as well zap these, too */ + li r4,0 + mtspr SDR1,r4 + + li r4,16 + mtctr r4 + li r3,0 + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 + bdnz 3b + +#ifdef __SMP__ + /* The 750 book (and Mot/IBM support) says that this will "assist" snooping + when in SMP. Not sure yet whether this should stay or leave... */ + mfspr r4,HID0 + ori r4,r4,HID0_ABE + mtspr HID0,r4 + sync +#endif /* __SMP__ */ + blr + +/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and + branch to 0xfff00100 */ +_GLOBAL(_gemini_reboot) + lis r5,GEMINI_BOOT_INIT@h + ori r5,r5,GEMINI_BOOT_INIT@l + li r6,MSR_IP + mtspr SRR0,r5 + mtspr SRR1,r6 + rfi diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.3.15/linux/arch/ppc/kernel/gemini_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/gemini_setup.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,525 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "time.h" +#include "local_irq.h" +#include "open_pic.h" + +void gemini_setup_pci_ptrs(void); + +static int l2_printed = 0; +static unsigned char gemini_switch_map = 0; +static char *gemini_board_families[] = { + "VGM", "VSS", "KGM", "VGR", "KSS" +}; + +static char *gemini_memtypes[] = { + "EDO DRAM, 60nS", "SDRAM, 15nS, CL=2", "SDRAM, 15nS, CL=2 with ECC" +}; + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + + +static inline unsigned long _get_HID1(void) +{ + unsigned long val; + + __asm__ __volatile__("mfspr %0,1009" : "=r" (val)); + return val; +} + +int +gemini_get_cpuinfo(char *buffer) +{ + int i, len; + unsigned char reg, rev; + char *family; + unsigned int type; + + reg = readb(GEMINI_FEAT); + family = gemini_board_families[((reg>>4) & 0xf)]; + if (((reg>>4) & 0xf) > 2) + printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); + + reg = readb(GEMINI_BREV); + type = (reg>>4) & 0xf; + rev = reg & 0xf; + + reg = readb(GEMINI_BECO); + + len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", + family, type, (rev + 'A'), (reg & 0xf)); + + len += sprintf( buffer+len, "vendor\t\t: %s\n", + (_get_PVR() & (1<<15)) ? "IBM" : "Motorola"); + + reg = readb(GEMINI_MEMCFG); + len += sprintf( buffer+len, "memory type\t: %s\n", + gemini_memtypes[(reg & 0xc0)>>6]); + len += sprintf( buffer+len, "switches on\t: "); + for( i=0; i < 8; i++ ) { + if ( gemini_switch_map & (1<>16) == 8) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + reg = readb(GEMINI_BSTAT) & 0xc0; + + switch( reg >> 2 ) { + + case 0: + default: + clock = (hid1*100)/3; + break; + + case 1: + clock = (hid1*125)/3; + break; + + case 2: + clock = (hid1*50)/3; + break; + } + + return clock; +} + + +#define L2CR_PIPE_LATEWR (0x01800000) /* late-write SRAM */ +#define L2CR_L2CTL (0x00100000) /* RAM control */ +#define L2CR_INST_DISABLE (0x00400000) /* disable for insn's */ +#define L2CR_L2I (0x00200000) /* global invalidate */ +#define L2CR_L2E (0x80000000) /* enable */ +#define L2CR_L2WT (0x00080000) /* write-through */ + +void __init gemini_init_l2(void) +{ + unsigned char reg; + unsigned long cache; + int speed; + + reg = readb(GEMINI_L2CFG); + + /* 750's L2 initializes differently from a 604's. Also note that a Grackle + bug will hang a dual-604 board, so make sure that doesn't happen by not + turning on the L2 */ + if ( _get_PVR() >> 16 != 8 ) { + + /* check for dual cpus and cry sadly about the loss of an L2... */ + if ((( readb(GEMINI_CPUSTAT) & 0x0c ) >> 2) != 1) + printk("Sorry. Your dual-604 does not allow the L2 to be enabled due " + "to a Grackle bug.\n"); + else if ( reg & GEMINI_L2_SIZE_MASK ) { + printk("Enabling 604 L2 cache: %dKb\n", + (128<<((reg & GEMINI_L2_SIZE_MASK)>>6))); + writeb( 1, GEMINI_L2CFG ); + } + } + + /* do a 750 */ + else { + /* Synergy's first round of 750 boards had the L2 size stuff into the + board register above. If it's there, it's used; if not, the + standard default is 1Mb. The L2 type, I'm told, is "most likely + probably always going to be late-write". --Dan */ + + if (reg & 0xc0) { + if (!l2_printed) { + printk("Enabling 750 L2 cache: %dKb\n", + (128 << ((reg & 0xc0)>>6))); + l2_printed=1; + } + + /* take the size given */ + cache = (((reg>>6) & 0x3)<<28); + } + else + /* default of 1Mb */ + cache = 0x3<<28; + + reg &= 0x3; + + /* a cache ratio of 1:1 and CPU clock speeds in excess of 300Mhz are bad + things. If found, tune it down to 1:1.5. -- Dan */ + if (!reg) { + + speed = gemini_get_clock_speed(); + + if (speed >= 300) { + printk("Warning: L2 ratio is 1:1 on a %dMhz processor. Dropping to 1:1.5.\n", + speed ); + printk("Contact Synergy Microsystems for an ECO to fix this problem\n"); + reg = 0x1; + } + } + + /* standard stuff */ + cache |= ((1<>8) & 0xf) <= 2) + cache |= L2CR_L2WT; +#endif + cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE; + _set_L2CR(0); + _set_L2CR(cache|L2CR_L2I|L2CR_L2E); + } +} + +void +gemini_restart(char *cmd) +{ + __cli(); + /* make a clean restart, not via the MPIC */ + _gemini_reboot(); + for(;;); +} + +void +gemini_power_off(void) +{ + for(;;); +} + +void +gemini_halt(void) +{ + gemini_restart(NULL); +} + +void __init gemini_init_IRQ(void) +{ + int i; + + /* gemini has no 8259 */ + open_pic.irq_offset = 0; + for( i=0; i < 16; i++ ) + irq_desc[i].ctl = &open_pic; + openpic_init(1); +} + +#define gemini_rtc_read(x) (readb(GEMINI_RTC+(x))) +#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) + +/* ensure that the RTC is up and running */ +void __init gemini_time_init(void) +{ + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + + if ( reg & M48T35_RTC_STOPPED ) { + printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n"); + gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); + gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); + } +} + +#undef DEBUG_RTC + +unsigned long +gemini_get_rtc_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL); +#ifdef DEBUG_RTC + printk("get rtc: reg = %x\n", reg); +#endif + + do { + sec = gemini_rtc_read(M48T35_RTC_SECONDS); + min = gemini_rtc_read(M48T35_RTC_MINUTES); + hour = gemini_rtc_read(M48T35_RTC_HOURS); + day = gemini_rtc_read(M48T35_RTC_DOM); + mon = gemini_rtc_read(M48T35_RTC_MONTH); + year = gemini_rtc_read(M48T35_RTC_YEAR); + } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS)); +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ((year += 1900) < 1970) + year += 100; +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + return mktime( year, mon, day, hour, min, sec ); +} + + +int +gemini_set_rtc_time( unsigned long now ) +{ + unsigned char reg; + struct rtc_time tm; + + to_tm( now, &tm ); + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); +#if DEBUG_RTC + printk("set rtc: reg = %x\n", reg); +#endif + + gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL); +#if DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + tm.tm_year -= 1900; + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); +#ifdef DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS); + gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES); + gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS); + gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM); + gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH); + gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR); + + /* done writing */ + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + if ((time_state == TIME_ERROR) || (time_state == TIME_BAD)) + time_state = TIME_OK; + + return 0; +} + +/* use the RTC to determine the decrementer count */ +void __init gemini_calibrate_decr(void) +{ + int freq, divisor; + unsigned char reg; + + /* determine processor bus speed */ + reg = readb(GEMINI_BSTAT); + + switch(((reg & 0x0c)>>2)&0x3) { + case 0: + default: + freq = 66; + break; + case 1: + freq = 83; + break; + case 2: + freq = 100; + break; + } + + freq *= 1000000; + divisor = 4; + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; +} + + +void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + void chrp_do_IRQ(struct pt_regs *, int, int); + gemini_setup_pci_ptrs(); + + ISA_DMA_THRESHOLD = 0; + DMA_MODE_READ = 0; + DMA_MODE_WRITE = 0; + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + ppc_md.setup_arch = gemini_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = gemini_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = gemini_init_IRQ; + ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.init = NULL; + + ppc_md.restart = gemini_restart; + ppc_md.power_off = gemini_power_off; + ppc_md.halt = gemini_halt; + + ppc_md.time_init = gemini_time_init; + ppc_md.set_rtc_time = gemini_set_rtc_time; + ppc_md.get_rtc_time = gemini_get_rtc_time; + ppc_md.calibrate_decr = gemini_calibrate_decr; + + /* no keyboard/mouse/video stuff yet.. */ + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = NULL; +#endif +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/hashtable.S linux/arch/ppc/kernel/hashtable.S --- v2.3.15/linux/arch/ppc/kernel/hashtable.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/hashtable.S Tue Aug 31 11:36:43 1999 @@ -0,0 +1,476 @@ +/* + * arch/ppc/kernel/hashtable.S + * + * $Id: hashtable.S,v 1.2 1999/08/23 02:53:17 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * This file contains low-level assembler routines for managing + * the PowerPC MMU hash table. (PPC 8xx processors don't use a + * hash table, so this file is not used on them.) + * + * 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 "ppc_asm.h" +#include +#include +#include + +/* + * Load a PTE into the hash table, if possible. + * The address is in r3, and r4 contains access flags: + * _PAGE_USER (4) if a user-mode access, ored with + * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1, + * so bit 1 (0x40000000) is set if the exception was due + * to no matching PTE being found in the hash table. + * r5 contains the physical address of the current task's thread. + * + * Returns to the caller if the access is illegal or there is no + * mapping for the address. Otherwise it places an appropriate PTE + * in the hash table and returns from the exception. + * Uses r0, r2 - r6, ctr, lr. + * + * For speed, 4 of the instructions get patched once the size and + * physical address of the hash table are known. These definitions + * of Hash_base and Hash_bits below are just an example. + */ +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__ + eieio + lis r2,hash_table_lock@h + ori r2,r2,hash_table_lock@l + tophys(r2,r2) + lis r6,100000000@h + mtctr r6 + lwz r0,PROCESSOR-THREAD(r5) + or r0,r0,r6 +10: lwarx r6,0,r2 + cmpi 0,r6,0 + bne- 12f + stwcx. r0,0,r2 + beq+ 11f +12: cmpw r6,r0 + bdnzf 2,10b + tw 31,31,31 +11: eieio +#endif + /* Get PTE (linux-style) and check access */ + mfspr r2,SPRG3 /* current task's THREAD (phys) */ + lwz r5,PGDIR(r2) /* virt page-table root */ + tophys(r5,r5) /* 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 */ +#ifdef __SMP__ + beq- hash_page_out /* return if no mapping */ +#else + /* XXX it seems like the 601 will give a machine fault on the + rfi if its alignment is wrong (bottom 4 bits of address are + 8 or 0xc) and we have had a not-taken conditional branch + to the address following the rfi. */ + beqlr- +#endif + tophys(r2,r5) + 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 */ +#ifdef __SMP__ + bne- hash_page_out /* return if access not permitted */ +#else + bnelr- +#endif + + 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 */ + or r6,r6,r5 + stw r6,0(r2) /* update PTE (accessed/dirty bits) */ + + /* Convert linux-style PTE to low word of PPC-style PTE */ +#ifdef CONFIG_PPC64 + /* clear the high 32 bits just in case */ + clrldi r6,r6,32 + clrldi r4,r4,32 +#endif /* CONFIG_PPC64 */ + rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ + rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ + ori r4,r4,0xe04 /* clear out reserved bits */ + andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */ + + /* Construct the high word of the PPC-style PTE */ + mfsrin r5,r3 /* get segment reg for segment */ +#ifdef CONFIG_PPC64 + sldi r5,r5,12 +#else /* CONFIG_PPC64 */ + rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ +#endif /* CONFIG_PPC64 */ + +#ifndef __SMP__ /* do this later for SMP */ +#ifdef CONFIG_PPC64 + ori r5,r5,1 /* set V (valid) bit */ +#else /* CONFIG_PPC64 */ + oris r5,r5,0x8000 /* set V (valid) bit */ +#endif /* CONFIG_PPC64 */ +#endif + +#ifdef CONFIG_PPC64 +/* XXX: does this insert the api correctly? -- Cort */ + rlwimi r5,r3,17,21,25 /* put in API (abbrev page index) */ +#else /* CONFIG_PPC64 */ + rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ +#endif /* CONFIG_PPC64 */ + /* Get the address of the primary PTE group in the hash table */ + .globl hash_page_patch_A +hash_page_patch_A: + lis r4,Hash_base@h /* base address of hash table */ +#ifdef CONFIG_PPC64 + /* just in case */ + clrldi r4,r4,32 +#endif + rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ + rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ + xor r4,r4,r0 /* make primary hash */ + + /* See whether it was a PTE not found exception or a + protection violation. */ + andis. r0,r20,0x4000 + li r2,8 /* PTEs/group */ + bne 10f /* no PTE: go look for an empty slot */ + tlbie r3 /* invalidate TLB entry */ + + /* Search the primary PTEG for a PTE whose 1st word matches r5 */ + mtctr r2 + addi r3,r4,-8 +1: lwzu r0,8(r3) /* get next PTE */ + cmp 0,r0,r5 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_slot + + /* Search the secondary PTEG for a matching PTE */ + ori r5,r5,0x40 /* set H (secondary hash) bit */ + .globl hash_page_patch_B +hash_page_patch_B: + xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ + xori r3,r3,0xffc0 + addi r3,r3,-8 + mtctr r2 +2: lwzu r0,8(r3) + cmp 0,r0,r5 + bdnzf 2,2b + beq+ found_slot + xori r5,r5,0x40 /* clear H bit again */ + + /* Search the primary PTEG for an empty slot */ +10: mtctr r2 + addi r3,r4,-8 /* search primary PTEG */ +1: lwzu r0,8(r3) /* get next PTE */ + srwi. r0,r0,31 /* only want to check valid bit */ + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_empty + + /* Search the secondary PTEG for an empty slot */ + ori r5,r5,0x40 /* set H (secondary hash) bit */ + .globl hash_page_patch_C +hash_page_patch_C: + xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ + xori r3,r3,0xffc0 + addi r3,r3,-8 + mtctr r2 +2: lwzu r0,8(r3) + 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. + * Since both the primary and secondary PTEGs are full, and we + * have no information that the PTEs in the primary PTEG are + * more important or useful than those in the secondary PTEG, + * and we know there is a definite (although small) speed + * advantage to putting the PTE in the primary PTEG, we always + * put the PTE in the primary PTEG. + */ + 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 +11: + /* update counter of evicted pages */ + lis r2,htab_evicts@h + ori r2,r2,htab_evicts@l + tophys(r2,r2) + lwz r4,0(r2) + addi r4,r4,1 + stw r4,0(r2) + +#ifndef __SMP__ + /* Store PTE in PTEG */ +found_empty: + stw r5,0(r3) +found_slot: + stw r6,4(r3) + sync + +#else /* __SMP__ */ +/* + * Between the tlbie above and updating the hash table entry below, + * another CPU could read the hash table entry and put it in its TLB. + * There are 3 cases: + * 1. using an empty slot + * 2. updating an earlier entry to change permissions (i.e. enable write) + * 3. taking over the PTE for an unrelated address + * + * In each case it doesn't really matter if the other CPUs have the old + * PTE in their TLB. So we don't need to bother with another tlbie here, + * which is convenient as we've overwritten the register that had the + * address. :-) The tlbie above is mainly to make sure that this CPU comes + * and gets the new PTE from the hash table. + * + * We do however have to make sure that the PTE is never in an invalid + * state with the V bit set. + */ +found_empty: +found_slot: + stw r5,0(r3) /* clear V (valid) bit in PTE */ + sync + tlbsync + sync + stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */ + sync + oris r5,r5,0x8000 + stw r5,0(r3) /* finally set V bit in PTE */ +#endif /* __SMP__ */ + +/* + * 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) + lwz r3,0(r2) + addi r3,r3,1 + stw r3,0(r2) + +#ifdef __SMP__ + lis r2,hash_table_lock@ha + tophys(r2,r2) + li r0,0 + stw r0,hash_table_lock@l(r2) + eieio +#endif + + /* Return from the exception */ + lwz r3,_CCR(r21) + lwz r4,_LINK(r21) + lwz r5,_CTR(r21) + mtcrf 0xff,r3 + mtlr r4 + mtctr r5 + lwz r0,GPR0(r21) + lwz r1,GPR1(r21) + lwz r2,GPR2(r21) + lwz r3,GPR3(r21) + lwz r4,GPR4(r21) + lwz r5,GPR5(r21) + lwz r6,GPR6(r21) + /* we haven't used xer */ + mtspr SRR1,r23 + mtspr SRR0,r22 + lwz r20,GPR20(r21) + lwz r22,GPR22(r21) + lwz r23,GPR23(r21) + lwz r21,GPR21(r21) + rfi + +#ifdef __SMP__ +hash_page_out: + lis r2,hash_table_lock@ha + tophys(r2,r2) + li r0,0 + stw r0,hash_table_lock@l(r2) + eieio + blr + + .globl hash_table_lock +hash_table_lock: + .long 0 +#endif + +next_slot: + .long 0 + +/* + * Flush entries from the hash table with VSIDs in the range + * given. + */ +_GLOBAL(flush_hash_segments) + lis r5,Hash@ha + lwz r5,Hash@l(r5) /* base of hash table */ + cmpwi 0,r5,0 + bne+ 99f + tlbia + sync +#ifdef __SMP__ + tlbsync + sync +#endif + blr +99: +#ifdef __SMP__ + /* Note - we had better not do anything which could generate + a hash table miss while we have the hash table locked, + or we'll get a deadlock. -paulus */ + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,8 +10: lwarx r6,0,r9 + cmpi 0,r6,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif + 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 */ + oris r4,r4,0x8000 + ori r4,r4,0x7f + lis r6,Hash_size@ha + lwz r6,Hash_size@l(r6) /* size in bytes */ + srwi r6,r6,3 /* # PTEs */ + mtctr r6 + addi r5,r5,-8 + li r0,0 +1: lwzu r6,8(r5) /* get next tag word */ + cmplw 0,r6,r3 + cmplw 1,r6,r4 + cror 0,0,5 /* set cr0.lt if out of range */ + blt 2f /* branch if out of range */ + stw r0,0(r5) /* invalidate entry */ +2: bdnz 1b /* continue with loop */ + sync + tlbia + sync +#ifdef __SMP__ + tlbsync + sync + lis r3,hash_table_lock@ha + stw r0,hash_table_lock@l(r3) + mtmsr r10 + SYNC +#endif + blr + +/* + * Flush the entry for a particular page from the hash table. + * + * flush_hash_page(unsigned context, unsigned long va) + */ +_GLOBAL(flush_hash_page) + lis r6,Hash@ha + lwz r6,Hash@l(r6) /* hash table base */ + cmpwi 0,r6,0 /* hash table in use? */ + bne+ 99f + tlbie r4 /* in hw tlb too */ + sync +#ifdef __SMP__ + tlbsync + sync +#endif + blr +99: +#ifdef __SMP__ + /* Note - we had better not do anything which could generate + a hash table miss while we have the hash table locked, + or we'll get a deadlock. -paulus */ + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,9 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif + 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 */ + rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */ + rlwinm r7,r4,32-6,10,25 /* get page index << 6 */ + rlwinm r5,r3,32-1,7,25 /* vsid << 6 */ + xor r7,r7,r5 /* primary hash << 6 */ + lis r5,Hash_mask@ha + lwz r5,Hash_mask@l(r5) /* hash mask */ + slwi r5,r5,6 /* << 6 */ + and r7,r7,r5 + add r6,r6,r7 /* address of primary PTEG */ + li r8,8 + mtctr r8 + addi r7,r6,-8 +1: lwzu r0,8(r7) /* get next PTE */ + cmpw 0,r0,r3 /* see if tag matches */ + bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */ + beq 3f /* if we found it */ + ori r3,r3,0x40 /* set H (alt. hash) bit */ + xor r6,r6,r5 /* address of secondary PTEG */ + mtctr r8 + addi r7,r6,-8 +2: lwzu r0,8(r7) /* get next PTE */ + cmpw 0,r0,r3 /* see if tag matches */ + bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */ + bne 4f /* if we didn't find it */ +3: li r0,0 + stw r0,0(r7) /* invalidate entry */ +4: sync + tlbie r4 /* in hw tlb too */ + sync +#ifdef __SMP__ + tlbsync + sync + lis r3,hash_table_lock@h + li r0,0 + stw r0,hash_table_lock@l(r3) + mtmsr r10 + SYNC +#endif + blr diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.3.15/linux/arch/ppc/kernel/head.S Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/kernel/head.S Tue Aug 31 11:36:43 1999 @@ -1,12 +1,13 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.134 1999/06/30 05:05:52 paulus Exp $ + * $Id: head.S,v 1.142 1999/08/23 02:53:18 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan * Adapted for Power Macintosh by Paul Mackerras. * Low-level exception handlers and MMU support * rewritten by Paul Mackerras. @@ -16,7 +17,7 @@ * * This file contains the low-level support and setup for the * PowerPC platform, including trap and interrupt dispatch. - * Also included here is low-level thread/task switch support. + * (The PPC 8xx embedded CPUs use head_8xx.S instead.) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,118 +26,42 @@ * */ -#include "ppc_asm.tmpl" -#include "ppc_defs.h" +#include "ppc_asm.h" #include #include -#include -#include -#include #include #include -#include -#include #ifdef CONFIG_APUS #include #endif -/* optimization for 603 to load the tlb directly from the linux table */ -#define NO_RELOAD_HTAB 1 - -#ifndef CONFIG_8xx -CACHE_LINE_SIZE = 32 -LG_CACHE_LINE_SIZE = 5 -#else -CACHE_LINE_SIZE = 16 -LG_CACHE_LINE_SIZE = 4 -#endif - -#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 - -#ifndef CONFIG_8xx -/* This instruction is not implemented on the PPC 603 or 601 */ -#define tlbia \ - li r4,128; \ - mtctr r4; \ - lis r4,KERNELBASE@h; \ -0: tlbie r4; \ - addi r4,r4,0x1000; \ - bdnz 0b -#endif - #ifdef CONFIG_PPC64 -#define LOAD_BAT(n, offset, reg, RA, RB) \ - ld RA,offset+0(reg); \ - ld RB,offset+8(reg); \ +#define LOAD_BAT(n, reg, RA, RB) \ + ld RA,(n*32)+0(reg); \ + ld RB,(n*32)+8(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ - ld RA,offset+16(reg); \ - ld RB,offset+24(reg); \ + ld RA,(n*32)+16(reg); \ + ld RB,(n*32)+24(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ #else /* CONFIG_PPC64 */ -/* 601 only have IBAT cr0.eq is set on 601 when using this macro */ -#define LOAD_BAT(n, offset, reg, RA, RB) \ - lwz RA,offset+0(reg); \ - lwz RB,offset+4(reg); \ +/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ +#define LOAD_BAT(n, reg, RA, RB) \ + lwz RA,(n*16)+0(reg); \ + lwz RB,(n*16)+4(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ beq 1f; \ - lwz RA,offset+8(reg); \ - lwz RB,offset+12(reg); \ + lwz RA,(n*16)+8(reg); \ + lwz RB,(n*16)+12(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ 1: #endif /* CONFIG_PPC64 */ - -#ifndef CONFIG_APUS -#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h -#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 .text .globl _stext @@ -149,7 +74,15 @@ .text .globl _start _start: - .long TOPHYS(__start),0,0 + /* + * These are here for legacy reasons, the kernel used to + * need to look like a coff function entry for the pmac + * but we're always started by some kind of bootloader now. + * -- Cort + */ + nop + nop + nop /* PMAC * Enter here with the kernel text, data and bss loaded starting at @@ -168,6 +101,7 @@ * * APUS * r3: 'APUS' + * r4: physical address of memory base * Linux/m68k style BootInfo structure at &_end. * * PREP @@ -183,39 +117,6 @@ * This just gets a minimal mmu environment setup so we can call * start_here() to do the real work. * -- Cort - * - * MPC8xx - * This port was done on an MBX board with an 860. Right now I only - * support an ELF compressed (zImage) boot from EPPC-Bug because the - * code there loads up some registers before calling us: - * r3: ptr to board info data - * r4: initrd_start or if no initrd then 0 - * r5: initrd_end - unused if r4 is 0 - * r6: Start of command line string - * r7: End of command line string - * - * I decided to use conditional compilation instead of checking PVR and - * adding more processor specific branches around code I don't need. - * Since this is an embedded processor, I also appreciate any memory - * savings I can get. - * - * The MPC8xx does not have any BATs, but it supports large page sizes. - * We first initialize the MMU to support 8M byte pages, then load one - * entry into each of the instruction and data TLBs to map the first - * 8M 1:1. I also mapped an additional I/O space 1:1 so we can get to - * the "internal" processor registers before MMU_init is called. - * - * The TLB code currently contains a major hack. Since I use the condition - * code register, I have to save and restore it. I am out of registers, so - * I just store it in memory location 0 (the TLB handlers are not reentrant). - * To avoid making any decisions, I need to use the "segment" valid bit - * in the first level table, but that would require many changes to the - * Linux page directory/table functions that I don't want to do right now. - * - * I used to use SPRG2 for a temporary register in the TLB handler, but it - * has since been put to other uses. I now use a hack to save a register - * and the CCR at memory location 0.....Someday I'll fix this..... - * -- Dan */ .globl __start @@ -241,8 +142,14 @@ mr r28,r6 mr r27,r7 li r24,0 /* cpu # */ -#ifndef CONFIG_8xx bl prom_init +#ifdef CONFIG_APUS +/* On APUS the __va/__pa constants need to be set to the correct + * values before continuing. + */ + mr r4,r30 + bl fix_mem_constants +#endif .globl __secondary_start __secondary_start: /* @@ -267,16 +174,9 @@ b 5f #endif /* CONFIG_PPC64 */ 4: -#ifdef CONFIG_APUS - ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */ - ori r11,r11,0xfe /* set up an 8MB mapping */ - lis r8,CYBERBASEp@h - lwz r8,0(r8) - addis r8,r8,KERNELBASE@h - addi r8,r8,2 -#else + tophys(r8,r11) + ori r8,r8,2 /* R/W access */ ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ - li r8,2 /* R/W access */ #ifdef CONFIG_PPC64 /* clear out the high 32 bits in the BAT */ clrldi r11,r11,32 @@ -295,15 +195,16 @@ mtspr DBAT1U,r21 /* bit in upper BAT register */ mtspr IBAT1L,r18 mtspr IBAT1U,r21 - + +#if 0 /* for now, otherwise we overflow the 0x100 bytes we have here */ oris r18,r8,0x20000000@h oris r21,r11,(KERNELBASE+0x20000000)@h mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ mtspr DBAT2U,r21 /* bit in upper BAT register */ mtspr IBAT2L,r18 mtspr IBAT2U,r21 +#endif /* 0 */ #endif /* CONFIG_PPC64 */ -#endif mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ mtspr DBAT0U,r11 /* bit in upper BAT register */ mtspr IBAT0L,r8 @@ -325,7 +226,7 @@ /* Copy exception code to exception vector base. */ lis r3,KERNELBASE@h - tophys(r4,r3,r5) + tophys(r4,r3) lis r3,0xfff0 /* Copy to 0xfff00000 on APUS */ li r5,0x4000 /* # bytes of memory to copy */ li r6,0 @@ -359,80 +260,6 @@ * this shouldn't bother the pmac since it just gets turned on again * as we jump to our code at KERNELBASE. -- Cort */ - -#else /* CONFIG_8xx */ - tlbia /* Invalidate all TLB entries */ - li r8, 0 - mtspr MI_CTR, r8 /* Set instruction control to zero */ - lis r8, MD_RESETVAL@h - mtspr MD_CTR, r8 /* Set data TLB control */ - - /* Now map the lower 8 Meg into the TLBs. For this quick hack, - * we can load the instruction and data TLB registers with the - * same values. - */ - lis r8, KERNELBASE@h /* Create vaddr for TLB */ - ori r8, r8, MI_EVALID /* Mark it valid */ - mtspr MI_EPN, r8 - mtspr MD_EPN, r8 - li r8, MI_PS8MEG /* Set 8M byte page */ - ori r8, r8, MI_SVALID /* Make it valid */ - mtspr MI_TWC, r8 - mtspr MD_TWC, r8 - li r8, MI_BOOTINIT /* Create RPN for address 0 */ - mtspr MI_RPN, r8 /* Store TLB entry */ - mtspr MD_RPN, r8 - lis r8, MI_Kp@h /* Set the protection mode */ - mtspr MI_AP, r8 - mtspr MD_AP, r8 - -/* We will get these from a configuration file as soon as I verify - * the extraneous bits don't cause problems in the TLB. - */ -#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE) -#define BOOT_IMMR 0xfa000000 -#endif -#ifdef CONFIG_BSEIP -#define BOOT_IMMR 0xff000000 -#endif - /* Map another 8 MByte at 0xfa000000 to get the processor - * internal registers (among other things). - */ - lis r8, BOOT_IMMR@h /* Create vaddr for TLB */ - ori r8, r8, MD_EVALID /* Mark it valid */ - mtspr MD_EPN, r8 - li r8, MD_PS8MEG /* Set 8M byte page */ - ori r8, r8, MD_SVALID /* Make it valid */ - mtspr MD_TWC, r8 - lis r8, BOOT_IMMR@h /* Create paddr for TLB */ - ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ - mtspr MD_RPN, r8 - - /* Since the cache is enabled according to the information we - * just loaded into the TLB, invalidate and enable the caches here. - * We should probably check/set other modes....later. - */ - lis r8, IDC_INVALL@h - mtspr IC_CST, r8 - mtspr DC_CST, r8 - lis r8, IDC_ENABLE@h - mtspr IC_CST, r8 -#if 0 - mtspr DC_CST, r8 -#else - /* For a debug option, I left this here to easily enable - * the write through cache mode - */ - lis r8, DC_SFWT@h - mtspr DC_CST, r8 - lis r8, IDC_ENABLE@h - mtspr DC_CST, r8 -#endif - -/* We now have the lower 8 Meg mapped into TLB entries, and the caches - * ready to work. - */ -#endif /* CONFIG_8xx */ turn_on_mmu: mfmsr r0 @@ -445,14 +272,6 @@ rfi /* enables MMU */ /* - * GCC sometimes accesses words at negative offsets from the stack - * pointer, although the SysV ABI says it shouldn't. To cope with - * this, we leave this much untouched space on the stack on exception - * entry. - */ -#define STACK_UNDERHEAD 0 - -/* * Exception entry code. This code runs with address translation * turned off, i.e. using physical addresses. * We assume sprg3 has the physical address of the current @@ -465,8 +284,8 @@ 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 */\ + tophys(r21,r1); /* use tophys(kernel sp) otherwise */ \ + subi r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\ 1: stw r20,_CCR(r21); /* save registers */ \ stw r22,GPR22(r21); \ stw r23,GPR23(r21); \ @@ -486,7 +305,7 @@ stw r1,GPR1(r21); \ stw r2,GPR2(r21); \ stw r1,0(r21); \ - tovirt(r1,r21,r1); /* set new kernel sp */ \ + tovirt(r1,r21); /* set new kernel sp */ \ SAVE_4GPRS(3, r21); /* * Note: code which follows this uses cr0.eq (set if from kernel), @@ -504,7 +323,7 @@ li r20,MSR_KERNEL; \ bl transfer_to_handler; \ .long hdlr; \ - .long int_return + .long ret_from_except /* System reset */ #ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ @@ -516,23 +335,18 @@ /* Machine check */ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) -/* Data access exception. - * This is "never generated" by the MPC8xx. We jump to it for other - * translation errors. - */ +/* Data access exception. */ . = 0x300 DataAccess: EXCEPTION_PROLOG mfspr r20,DSISR -#ifndef CONFIG_8xx 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 */ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ - mfspr r5,SPRG3 /* phys addr of TSS */ + mfspr r5,SPRG3 /* phys addr of THREAD */ bl hash_page -#endif 1: stw r20,_DSISR(r21) mr r5,r20 mfspr r4,DAR @@ -542,24 +356,19 @@ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long do_page_fault - .long int_return + .long ret_from_except -/* Instruction access exception. - * This is "never generated" by the MPC8xx. We jump to it for other - * translation errors. - */ +/* Instruction access exception. */ . = 0x400 InstructionAccess: EXCEPTION_PROLOG -#ifndef CONFIG_8xx andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* 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 */ - mfspr r5,SPRG3 /* phys addr of TSS */ + mfspr r5,SPRG3 /* phys addr of THREAD */ bl hash_page -#endif 1: addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r22 mr r5,r23 @@ -567,7 +376,7 @@ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long do_page_fault - .long int_return + .long ret_from_except /* External interrupt */ . = 0x500; @@ -606,7 +415,7 @@ li r4,0 bl transfer_to_handler .long do_IRQ; - .long int_return + .long ret_from_except /* Alignment exception */ @@ -622,7 +431,7 @@ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long AlignmentException - .long int_return + .long ret_from_except /* Program check exception */ . = 0x700 @@ -633,9 +442,8 @@ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long ProgramCheckException - .long int_return + .long ret_from_except -#ifndef CONFIG_8xx /* Floating-point unavailable */ . = 0x800 FPUnavailable: @@ -644,12 +452,7 @@ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ .long KernelFP - .long int_return -#else -/* No FPU on MPC8xx. This exception is not supposed to happen. -*/ - STD_EXCEPTION(0x800, FPUnavailable, UnknownException) -#endif + .long ret_from_except STD_EXCEPTION(0x900, Decrementer, timer_interrupt) STD_EXCEPTION(0xa00, Trap_0a, UnknownException) @@ -664,7 +467,7 @@ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long DoSyscall - .long int_return + .long ret_from_except /* Single step - not used on 601 */ STD_EXCEPTION(0xd00, SingleStep, SingleStepException) @@ -672,14 +475,12 @@ STD_EXCEPTION(0xe00, Trap_0e, UnknownException) STD_EXCEPTION(0xf00, Trap_0f, UnknownException) -#ifndef CONFIG_8xx /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. */ . = 0x1000 InstructionTLBMiss: -#ifdef NO_RELOAD_HTAB /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -689,14 +490,14 @@ mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r2,SPRG3 - lwz r2,PG_TABLES(r2) - tophys(r2,r2,r3) + lwz r2,PGDIR(r2) + tophys(r2,r2) 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) + tophys(r2,r2) 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 */ @@ -719,40 +520,11 @@ 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 */ -00: li r1,8 /* 8 items / bucket */ - mtctr r1 - subi r2,r2,8 /* Preset pointer */ -10: lwzu r1,8(r2) /* Get next PTE */ - cmp 0,r1,r3 /* Found entry yet? */ - bdnzf 2,10b /* Jump back if not, until CTR==0 */ - bne 30f /* Try secondary hash if CTR==0 */ - lwz r1,4(r2) /* Get second word of entry */ -20: mtctr r0 /* Restore CTR */ - mfspr r3,SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - mfspr r0,IMISS /* Set to update TLB */ - mtspr RPA,r1 - tlbli r0 - rfi /* All done */ -/* Secondary hash */ -30: andi. r1,r3,0x40 /* Already doing secondary hash? */ - bne InstructionAddressInvalid /* Yes - item not in hash table */ - 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 */ -#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 */ @@ -769,20 +541,12 @@ sync /* Some chip revs have problems here... */ mtmsr r0 b InstructionAccess -#else -/* On the MPC8xx, this is a software emulation interrupt. It occurs - * for all unimplemented and illegal instructions. - */ - STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation) -#endif /* * Handle TLB miss for DATA Load operation on 603/603e */ . = 0x1100 -#ifndef CONFIG_8xx DataLoadTLBMiss: -#ifdef NO_RELOAD_HTAB /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -792,14 +556,14 @@ mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r2,SPRG3 - lwz r2,PG_TABLES(r2) - tophys(r2,r2,r3) + lwz r2,PGDIR(r2) + tophys(r2,r2) 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) + tophys(r2,r2) 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 */ @@ -823,40 +587,10 @@ 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 */ -00: li r1,8 /* 8 items / bucket */ - mtctr r1 - subi r2,r2,8 /* Preset pointer */ -10: lwzu r1,8(r2) /* Get next PTE */ - cmp 0,r1,r3 /* Found entry yet? */ - bdnzf 2,10b /* Jump back if not, until CTR==0 */ - bne 30f /* Try secondary hash if CTR==0 */ - lwz r1,4(r2) /* Get second word of entry */ -20: mtctr r0 /* Restore CTR */ - mfspr r3,SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - mfspr r0,DMISS /* Set to update TLB */ - mtspr RPA,r1 - tlbld r0 - rfi /* All done */ -/* Secondary hash */ -30: andi. r1,r3,0x40 /* Already doing secondary hash? */ - bne DataAddressInvalid /* Yes - item not in hash table */ - 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 */ @@ -872,79 +606,12 @@ sync /* Some chip revs have problems here... */ mtmsr r0 b DataAccess -#else -/* - * For the MPC8xx, this is a software tablewalk to load the instruction - * TLB. It is modelled after the example in the Motorola manual. The task - * switch loads the M_TWB register with the pointer to the first level table. - * If we discover there is no second level table (the value is zero), the - * plan was to load that into the TLB, which causes another fault into the - * TLB Error interrupt where we can handle such problems. However, that did - * not work, so if we discover there is no second level table, we restore - * registers and branch to the error exception. We have to use the MD_xxx - * registers for the tablewalk because the equivalent MI_xxx registers - * only perform the attribute functions. - */ -InstructionTLBMiss: - mtspr M_TW, r20 /* Save a couple of working registers */ - mfcr r20 - stw r20, 0(r0) - stw r21, 4(r0) - mfspr r20, SRR0 /* Get effective address of fault */ - mtspr MD_EPN, r20 /* Have to use MD_EPN for walk, MI_EPN can't */ - mfspr r20, M_TWB /* Get level 1 table entry address */ - lwz r21, 0(r20) /* Get the level 1 entry */ - rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ - - /* We have a pte table, so load the MI_TWC with the attributes - * for this page, which has only bit 31 set. - */ - tophys(r21,r21,0) - ori r21,r21,1 /* Set valid bit */ - mtspr MI_TWC, r21 /* Set page attributes */ - mtspr MD_TWC, r21 /* Load pte table base address */ - mfspr r21, MD_TWC /* ....and get the pte address */ - lwz r21, 0(r21) /* Get the pte */ - - /* Set four subpage valid bits (24, 25, 26, and 27). - * Since we currently run MI_CTR.PPCS = 0, the manual says, - * "If the page size is larger than 4k byte, then all the - * 4 bits should have the same value." - * I don't really know what to do if the page size is 4k Bytes, - * but I know setting them all to 0 does not work, and setting them - * all to 1 does, so that is the way it is right now. - * BTW, these four bits map to the software only bits in the - * linux page table. I used to turn them all of, but now just - * set them all for the hardware. - li r20, 0x00f0 - andc r20, r21, r20 - ori r20, r20, 0x0080 - */ - ori r20, r21, 0x00f0 - - mtspr MI_RPN, r20 /* Update TLB entry */ - - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - rfi - -2: mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - b InstructionAccess -#endif /* CONFIG_8xx */ /* * Handle TLB miss for DATA Store on 603/603e */ . = 0x1200 DataStoreTLBMiss: -#ifndef CONFIG_8xx -#ifdef NO_RELOAD_HTAB /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -954,14 +621,14 @@ mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r2,SPRG3 - lwz r2,PG_TABLES(r2) - tophys(r2,r2,r3) + lwz r2,PGDIR(r2) + tophys(r2,r2) 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) + tophys(r2,r2) 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 */ @@ -985,171 +652,12 @@ 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 */ -00: li r1,8 /* 8 items / bucket */ - mtctr r1 - subi r2,r2,8 /* Preset pointer */ -10: lwzu r1,8(r2) /* Get next PTE */ - cmp 0,r1,r3 /* Found entry yet? */ - bdnzf 2,10b /* Jump back if not, until CTR==0 */ - bne 30f /* Try secondary hash if CTR==0 */ - lwz r1,4(r2) /* Get second word of entry */ -20: mtctr r0 /* Restore CTR */ - mfspr r3,SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - mfspr r0,DMISS /* Set to update TLB */ - mtspr RPA,r1 - tlbld r0 - rfi /* All done */ -/* Secondary hash */ -30: andi. r1,r3,0x40 /* Already doing secondary hash? */ - bne DataAddressInvalid /* Yes - item not in hash table */ - mfspr r2,HASH2 /* Get hash table pointer */ - ori r3,r3,0x40 /* Set secondary hash */ - b 00b /* Try lookup again */ -#endif /* NO_RELOAD_HTAB */ -#else /* CONFIG_8xx */ - mtspr M_TW, r20 /* Save a couple of working registers */ - mfcr r20 - stw r20, 0(r0) - stw r21, 4(r0) - mfspr r20, M_TWB /* Get level 1 table entry address */ - lwz r21, 0(r20) /* Get the level 1 entry */ - rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ - - /* We have a pte table, so load fetch the pte from the table. - */ - tophys(r21, r21, 0) - ori r21, r21, 1 /* Set valid bit in physical L2 page */ - mtspr MD_TWC, r21 /* Load pte table base address */ - mfspr r21, MD_TWC /* ....and get the pte address */ - lwz r21, 0(r21) /* Get the pte */ - - /* Set four subpage valid bits (24, 25, 26, and 27). - * Since we currently run MD_CTR.PPCS = 0, the manual says, - * "If the page size is larger than 4k byte, then all the - * 4 bits should have the same value." - * I don't really know what to do if the page size is 4k Bytes, - * but I know setting them all to 0 does not work, and setting them - * all to 1 does, so that is the way it is right now. - * BTW, these four bits map to the software only bits in the - * linux page table. I used to turn them all of, but now just - * set them all for the hardware. - li r20, 0x00f0 - andc r20, r21, r20 - ori r20, r20, 0x0080 - */ - ori r20, r21, 0x00f0 - - mtspr MD_RPN, r20 /* Update TLB entry */ - - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - rfi - -2: mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - b DataAccess -#endif /* CONFIG_8xx */ -#ifndef CONFIG_8xx /* Instruction address breakpoint exception (on 603/604) */ STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) -#else - -/* This is an instruction TLB error on the MPC8xx. This could be due - * to many reasons, such as executing guarded memory or illegal instruction - * addresses. There is nothing to do but handle a big time error fault. - */ - . = 0x1300 -InstructionTLBError: - b InstructionAccess -#endif /* System management exception (603?) */ -#ifndef CONFIG_8xx STD_EXCEPTION(0x1400, Trap_14, UnknownException) -#else - -/* This is the data TLB error on the MPC8xx. This could be due to - * many reasons, including a dirty update to a pte. We can catch that - * one here, but anything else is an error. First, we track down the - * Linux pte. If it is valid, write access is allowed, but the - * page dirty bit is not set, we will set it and reload the TLB. For - * any other case, we bail out to a higher level function that can - * handle it. - */ - . = 0x1400 -DataTLBError: - mtspr M_TW, r20 /* Save a couple of working registers */ - mfcr r20 - stw r20, 0(r0) - stw r21, 4(r0) - - /* First, make sure this was a store operation. - */ - mfspr r20, DSISR - andis. r21, r20, 0x0200 /* If set, indicates store op */ - beq 2f - - mfspr r20, M_TWB /* Get level 1 table entry address */ - lwz r21, 0(r20) /* Get the level 1 entry */ - rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ - beq 2f /* If zero, bail */ - - /* We have a pte table, so fetch the pte from the table. - */ - tophys(r21, r21, 0) - ori r21, r21, 1 /* Set valid bit in physical L2 page */ - mtspr MD_TWC, r21 /* Load pte table base address */ - mfspr r21, MD_TWC /* ....and get the pte address */ - lwz r21, 0(r21) /* Get the pte */ - - andi. r20, r21, _PAGE_RW /* Is it writeable? */ - beq 2f /* Bail out if not */ - - ori r21, r21, _PAGE_DIRTY /* Update changed bit */ - mfspr r20, MD_TWC /* Get pte address again */ - stw r21, 0(r20) /* and update pte in table */ - - /* Set four subpage valid bits (24, 25, 26, and 27). - * Since we currently run MD_CTR.PPCS = 0, the manual says, - * "If the page size is larger than 4k byte, then all the - * 4 bits should have the same value." - * I don't really know what to do if the page size is 4k Bytes, - * but I know setting them all to 0 does not work, and setting them - * all to 1 does, so that is the way it is right now. - * BTW, these four bits map to the software only bits in the - * linux page table. I used to turn them all of, but now just - * set them all for the hardware. - li r20, 0x00f0 - andc r20, r21, r20 - ori r20, r20, 0x0080 - */ - ori r20, r21, 0x00f0 - - mtspr MD_RPN, r20 /* Update TLB entry */ - - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - rfi -2: - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - b DataAccess -#endif /* CONFIG_8xx */ STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) @@ -1158,16 +666,11 @@ STD_EXCEPTION(0x1900, Trap_19, UnknownException) STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) -/* On the MPC8xx, these next four traps are used for development - * support of breakpoints and such. Someday I will get around to - * using them. - */ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) -#ifndef CONFIG_8xx /* Run mode exception */ STD_EXCEPTION(0x2000, RunMode, RunModeException) @@ -1188,9 +691,6 @@ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException) . = 0x3000 -#else - . = 0x2000 -#endif /* * This code finishes saving the registers to the exception frame @@ -1208,12 +708,12 @@ SAVE_8GPRS(12, r21) SAVE_8GPRS(24, r21) andi. r23,r23,MSR_PR - mfspr r23,SPRG3 /* if from user, fix up tss.regs */ + mfspr r23,SPRG3 /* if from user, fix up THREAD.regs */ beq 2f addi r24,r1,STACK_FRAME_OVERHEAD stw r24,PT_REGS(r23) -2: addi r2,r23,-TSS /* set r2 to current */ - tovirt(r2,r2,r23) +2: addi r2,r23,-THREAD /* set r2 to current */ + tovirt(r2,r2) mflr r23 andi. r24,r23,0x3f00 /* get vector offset */ stw r24,TRAP(r21) @@ -1252,300 +752,6 @@ SYNC rfi -#ifndef CONFIG_8xx -/* - * Load a PTE into the hash table, if possible. - * The address is in r3, and r4 contains access flags: - * _PAGE_USER (4) if a user-mode access, ored with - * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1, - * so bit 1 (0x40000000) is set if the exception was due - * to no matching PTE being found in the hash table. - * r5 contains the physical address of the current task's tss. - * - * Returns to the caller if the access is illegal or there is no - * mapping for the address. Otherwise it places an appropriate PTE - * in the hash table and returns from the exception. - * Uses r0, r2 - r6, ctr, lr. - * - * For speed, 4 of the instructions get patched once the size and - * physical address of the hash table are known. These definitions - * of Hash_base and Hash_bits below are just an example. - */ -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__ - eieio - lis r2,hash_table_lock@h - ori r2,r2,hash_table_lock@l - tophys(r2,r2,r6) - lis r6,100000000@h - mtctr r6 - lwz r0,PROCESSOR-TSS(r5) - or r0,r0,r6 -10: lwarx r6,0,r2 - cmpi 0,r6,0 - bne- 12f - stwcx. r0,0,r2 - beq+ 11f -12: cmpw r6,r0 - bdnzf 2,10b - tw 31,31,31 -11: eieio -#endif - /* Get PTE (linux-style) and check access */ - 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 */ -#ifdef __SMP__ - beq- hash_page_out /* return if no mapping */ -#else - /* XXX it seems like the 601 will give a machine fault on the - rfi if its alignment is wrong (bottom 4 bits of address are - 8 or 0xc) and we have had a not-taken conditional branch - to the address following the rfi. */ - beqlr- -#endif - 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 */ -#ifdef __SMP__ - bne- hash_page_out /* return if access not permitted */ -#else - bnelr- -#endif - - 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 */ - or r6,r6,r5 - stw r6,0(r2) /* update PTE (accessed/dirty bits) */ - - /* Convert linux-style PTE to low word of PPC-style PTE */ -#ifdef CONFIG_PPC64 - /* clear the high 32 bits just in case */ - clrldi r6,r6,32 - clrldi r4,r4,32 -#endif /* CONFIG_PPC64 */ - rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ - rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ - ori r4,r4,0xe04 /* clear out reserved bits */ - andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */ - - /* Construct the high word of the PPC-style PTE */ - mfsrin r5,r3 /* get segment reg for segment */ -#ifdef CONFIG_PPC64 - sldi r5,r5,12 -#else /* CONFIG_PPC64 */ - rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ -#endif /* CONFIG_PPC64 */ - -#ifndef __SMP__ /* do this later for SMP */ -#ifdef CONFIG_PPC64 - ori r5,r5,1 /* set V (valid) bit */ -#else /* CONFIG_PPC64 */ - oris r5,r5,0x8000 /* set V (valid) bit */ -#endif /* CONFIG_PPC64 */ -#endif - -#ifdef CONFIG_PPC64 -/* XXX: does this insert the api correctly? -- Cort */ - rlwimi r5,r3,17,21,25 /* put in API (abbrev page index) */ -#else /* CONFIG_PPC64 */ - rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ -#endif /* CONFIG_PPC64 */ - /* Get the address of the primary PTE group in the hash table */ - .globl hash_page_patch_A -hash_page_patch_A: - lis r4,Hash_base@h /* base address of hash table */ -#ifdef CONFIG_PPC64 - /* just in case */ - clrldi r4,r4,32 -#endif - rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ - rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ - xor r4,r4,r0 /* make primary hash */ - - /* See whether it was a PTE not found exception or a - protection violation. */ - andis. r0,r20,0x4000 - li r2,8 /* PTEs/group */ - bne 10f /* no PTE: go look for an empty slot */ - tlbie r3 /* invalidate TLB entry */ - - /* Search the primary PTEG for a PTE whose 1st word matches r5 */ - mtctr r2 - addi r3,r4,-8 -1: lwzu r0,8(r3) /* get next PTE */ - cmp 0,r0,r5 - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_slot - - /* Search the secondary PTEG for a matching PTE */ - ori r5,r5,0x40 /* set H (secondary hash) bit */ - .globl hash_page_patch_B -hash_page_patch_B: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xffc0 - addi r3,r3,-8 - mtctr r2 -2: lwzu r0,8(r3) - cmp 0,r0,r5 - bdnzf 2,2b - beq+ found_slot - xori r5,r5,0x40 /* clear H bit again */ - - /* Search the primary PTEG for an empty slot */ -10: mtctr r2 - addi r3,r4,-8 /* search primary PTEG */ -1: lwzu r0,8(r3) /* get next PTE */ - srwi. r0,r0,31 /* only want to check valid bit */ - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_empty - - /* Search the secondary PTEG for an empty slot */ - ori r5,r5,0x40 /* set H (secondary hash) bit */ - .globl hash_page_patch_C -hash_page_patch_C: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xffc0 - addi r3,r3,-8 - mtctr r2 -2: lwzu r0,8(r3) - 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. - * Since both the primary and secondary PTEGs are full, and we - * have no information that the PTEs in the primary PTEG are - * more important or useful than those in the secondary PTEG, - * and we know there is a definite (although small) speed - * advantage to putting the PTE in the primary PTEG, we always - * put the PTE in the primary PTEG. - */ - 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 -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) - -#ifndef __SMP__ - /* Store PTE in PTEG */ -found_empty: - stw r5,0(r3) -found_slot: - stw r6,4(r3) - sync - -#else /* __SMP__ */ -/* - * Between the tlbie above and updating the hash table entry below, - * another CPU could read the hash table entry and put it in its TLB. - * There are 3 cases: - * 1. using an empty slot - * 2. updating an earlier entry to change permissions (i.e. enable write) - * 3. taking over the PTE for an unrelated address - * - * In each case it doesn't really matter if the other CPUs have the old - * PTE in their TLB. So we don't need to bother with another tlbie here, - * which is convenient as we've overwritten the register that had the - * address. :-) The tlbie above is mainly to make sure that this CPU comes - * and gets the new PTE from the hash table. - * - * We do however have to make sure that the PTE is never in an invalid - * state with the V bit set. - */ -found_empty: -found_slot: - stw r5,0(r3) /* clear V (valid) bit in PTE */ - sync - tlbsync - sync - stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */ - sync - oris r5,r5,0x8000 - stw r5,0(r3) /* finally set V bit in PTE */ -#endif /* __SMP__ */ - -/* - * 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) - -#ifdef __SMP__ - lis r2,hash_table_lock@ha - tophys(r2,r2,r6) - li r0,0 - stw r0,hash_table_lock@l(r2) - eieio -#endif - - /* Return from the exception */ - lwz r3,_CCR(r21) - lwz r4,_LINK(r21) - lwz r5,_CTR(r21) - mtcrf 0xff,r3 - mtlr r4 - mtctr r5 - REST_GPR(0, r21) - REST_2GPRS(1, r21) - REST_4GPRS(3, r21) - /* we haven't used xer */ - mtspr SRR1,r23 - mtspr SRR0,r22 - REST_GPR(20, r21) - REST_2GPRS(22, r21) - lwz r21,GPR21(r21) - rfi - -#ifdef __SMP__ -hash_page_out: - lis r2,hash_table_lock@ha - tophys(r2,r2,r6) - li r0,0 - stw r0,hash_table_lock@l(r2) - eieio - blr - - .globl hash_table_lock -hash_table_lock: - .long 0 -#endif - -next_slot: - .long 0 - -load_up_fpu: /* * Disable FP for the task which had the FPU previously, * and save its floating-point registers in its thread_struct. @@ -1553,6 +759,7 @@ * On SMP we know the fpu is free, since we give it up every * switch. -- Cort */ +load_up_fpu: mfmsr r5 ori r5,r5,MSR_FP SYNC @@ -1564,21 +771,17 @@ * to another. Instead we call giveup_fpu in switch_to. */ #ifndef __SMP__ -#ifndef CONFIG_APUS - lis r6,-KERNELBASE@h -#else - lis r6,CYBERBASEp@h - lwz r6,0(r6) -#endif + lis r6,0 /* get __pa constant */ + tophys(r6,r6) addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) cmpi 0,r4,0 beq 1f add r4,r4,r6 - addi r4,r4,TSS /* want TSS of last_task_used_math */ + addi r4,r4,THREAD /* want THREAD of last_task_used_math */ SAVE_32FPRS(0, r4) mffs fr0 - stfd fr0,TSS_FPSCR-4(r4) + stfd fr0,THREAD_FPSCR-4(r4) lwz r5,PT_REGS(r4) add r5,r5,r6 lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) @@ -1589,12 +792,12 @@ #endif /* __SMP__ */ /* enable use of FP after return */ ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 - mfspr r5,SPRG3 /* current task's TSS (phys) */ - lfd fr0,TSS_FPSCR-4(r5) + mfspr r5,SPRG3 /* current task's THREAD (phys) */ + lfd fr0,THREAD_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) #ifndef __SMP__ - subi r4,r5,TSS + subi r4,r5,THREAD sub r4,r4,r6 stw r4,last_task_used_math@l(r3) #endif /* __SMP__ */ @@ -1627,7 +830,7 @@ mr r4,r2 /* current */ lwz r5,_NIP(r1) bl printk - b int_return + b ret_from_except 86: .string "floating point used in kernel (task=%p, pc=%x)\n" .align 4 @@ -1646,12 +849,12 @@ SYNC cmpi 0,r3,0 beqlr- /* if no previous owner, done */ - addi r3,r3,TSS /* want TSS of task */ + addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) cmpi 0,r5,0 SAVE_32FPRS(0, r3) mffs fr0 - stfd fr0,TSS_FPSCR-4(r3) + stfd fr0,THREAD_FPSCR-4(r3) beq 1f lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r3,MSR_FP|MSR_FE0|MSR_FE1 @@ -1665,12 +868,6 @@ #endif /* __SMP__ */ blr -#else /* CONFIG_8xx */ - .globl giveup_fpu -giveup_fpu: - blr -#endif /* CONFIG_8xx */ - /* * This code is jumped to from the startup code to copy * the kernel image to physical address 0. @@ -1721,11 +918,66 @@ blr #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. - */ +/* + * On APUS the physical base address of the kernel is not known at compile + * time, which means the __pa/__va constants used are incorect. In the + * __init section is recorded the virtual addresses of instructions using + * these constants, so all that has to be done is fix these before + * continuing the kernel boot. + * + * r4 = The physical address of the kernel base. + */ +fix_mem_constants: + mr r10,r4 + addis r10,r10,-KERNELBASE@h /* virt_to_phys constant */ + neg r11,r10 /* phys_to_virt constant */ + + lis r12,__vtop_table_begin@h + ori r12,r12,__vtop_table_begin@l + add r12,r12,r10 /* table begin phys address */ + lis r13,__vtop_table_end@h + ori r13,r13,__vtop_table_end@l + add r13,r13,r10 /* table end phys address */ + subi r12,r12,4 + subi r13,r13,4 +1: lwzu r14,4(r12) /* virt address of instruction */ + add r14,r14,r10 /* phys address of instruction */ + lwz r15,0(r14) /* instruction, now insert top */ + rlwimi r15,r10,16,16,31 /* half of vp const in low half */ + stw r15,0(r14) /* of instruction and restore. */ + dcbst r0,r14 /* write it to memory */ + sync + icbi r0,r14 /* flush the icache line */ + cmpw r12,r13 + bne 1b + + lis r12,__ptov_table_begin@h + ori r12,r12,__ptov_table_begin@l + add r12,r12,r10 /* table begin phys address */ + lis r13,__ptov_table_end@h + ori r13,r13,__ptov_table_end@l + add r13,r13,r10 /* table end phys address */ + subi r12,r12,4 + subi r13,r13,4 +1: lwzu r14,4(r12) /* virt address of instruction */ + add r14,r14,r10 /* phys address of instruction */ + lwz r15,0(r14) /* instruction, now insert top */ + rlwimi r15,r11,16,16,31 /* half of pv const in low half*/ + stw r15,0(r14) /* of instruction and restore. */ + dcbst r0,r14 /* write it to memory */ + sync + icbi r0,r14 /* flush the icache line */ + cmpw r12,r13 + bne 1b + + isync /* No speculative loading until now */ + blr + + /* 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 @@ -1752,7 +1004,7 @@ /* our cpu # was at addr 0 - go */ lis r5,__secondary_start@h ori r5,r5,__secondary_start@l - tophys(r5,r5,r4) + tophys(r5,r5) mtlr r5 mr r24,r3 /* cpu # */ blr @@ -1762,7 +1014,6 @@ * This is where the main kernel code starts. */ start_here: -#ifndef CONFIG_8xx /* * Enable caches and 604-specific features if necessary. */ @@ -1794,7 +1045,6 @@ ori r11,r11,HID0_BTCD 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ 4: -#endif /* CONFIG_8xx */ #ifdef __SMP__ /* if we're the second cpu stack and r2 are different * and we want to not clear the bss -- Cort */ @@ -1848,33 +1098,21 @@ mr r7,r27 bl identify_machine bl MMU_init + /* * 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. - * On the 8xx, all we have to do is invalidate the TLB to clear - * the old 8M byte TLB mappings and load the page table base register. */ -#ifndef CONFIG_8xx lis r6,_SDR1@ha #ifdef CONFIG_PPC64 ld r6,_SDR1@l(r6) #else lwz r6,_SDR1@l(r6) #endif -#else - /* The right way to do this would be to track it down through - * init's TSS like the context switch code does, but this is - * easier......until someone changes init's static structures. - */ - lis r6, swapper_pg_dir@h - tophys(r6,r6,0) - ori r6, r6, swapper_pg_dir@l - mtspr M_TWB, r6 -#endif lis r4,2f@h ori r4,r4,2f@l - tophys(r4,r4,r3) + tophys(r4,r4) li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) mtspr SRR0,r4 mtspr SRR1,r3 @@ -1888,7 +1126,6 @@ tlbsync /* ... on all CPUs */ sync #endif -#ifndef CONFIG_8xx mtspr SDR1,r6 #ifdef CONFIG_PPC64 /* clear the v bit in the ASR so we can @@ -1913,23 +1150,23 @@ cmpwi r3,1 lis r3,BATS@ha addi r3,r3,BATS@l - tophys(r3,r3,r4) + tophys(r3,r3) #ifdef CONFIG_PPC64 - LOAD_BAT(0,0,r3,r4,r5) - LOAD_BAT(1,32,r3,r4,r5) - LOAD_BAT(2,64,r3,r4,r5) - LOAD_BAT(3,96,r3,r4,r5) + LOAD_BAT(0,r3,r4,r5) + LOAD_BAT(1,r3,r4,r5) + LOAD_BAT(2,r3,r4,r5) + LOAD_BAT(3,r3,r4,r5) #else /* CONFIG_PPC64 */ - LOAD_BAT(0,0,r3,r4,r5) - LOAD_BAT(1,16,r3,r4,r5) - LOAD_BAT(2,32,r3,r4,r5) - LOAD_BAT(3,48,r3,r4,r5) + LOAD_BAT(0,r3,r4,r5) + LOAD_BAT(1,r3,r4,r5) + LOAD_BAT(2,r3,r4,r5) + LOAD_BAT(3,r3,r4,r5) #endif /* CONFIG_PPC64 */ -#endif /* CONFIG_8xx */ + /* Set up for using our exception vectors */ - /* ptr to phys current tss */ - tophys(r4,r2,r4) - addi r4,r4,TSS /* init task's TSS */ + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ mtspr SPRG3,r4 li r3,0 mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ @@ -1943,7 +1180,7 @@ */ lis r5,first_cpu_booted@h ori r5,r5,first_cpu_booted@l - tophys(r5,r5,r3) + tophys(r5,r5) lwz r5,0(r5) cmpi 0,r5,0 beq 10f @@ -1956,371 +1193,6 @@ rfi /* enable MMU and jump to start_kernel */ /* - * Handle a system call. - */ -DoSyscall: - stw r0,TSS+LAST_SYSCALL(r2) - lwz r11,_CCR(r1) /* Clear SO bit in CR */ - lis r10,0x1000 - andc r11,r11,r10 - stw r11,_CCR(r1) -#ifdef SHOW_SYSCALLS -#ifdef SHOW_SYSCALLS_TASK - lis r31,show_syscalls_task@ha - lwz r31,show_syscalls_task@l(r31) - cmp 0,r2,r31 - bne 1f -#endif - lis r3,7f@ha - addi r3,r3,7f@l - lwz r4,GPR0(r1) - lwz r5,GPR3(r1) - lwz r6,GPR4(r1) - lwz r7,GPR5(r1) - lwz r8,GPR6(r1) - lwz r9,GPR7(r1) - bl printk - lis r3,77f@ha - addi r3,r3,77f@l - lwz r4,GPR8(r1) - lwz r5,GPR9(r1) - mr r6,r2 - bl printk - lwz r0,GPR0(r1) - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) -1: -#endif /* SHOW_SYSCALLS */ - cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */ - beq- 10f - lwz r10,TASK_FLAGS(r2) - andi. r10,r10,PF_TRACESYS - bne- 50f - cmpli 0,r0,NR_syscalls - bge- 66f - lis r10,sys_call_table@h - ori r10,r10,sys_call_table@l - slwi r0,r0,2 - lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ - cmpi 0,r10,0 - beq- 66f - mtlr r10 - addi r9,r1,STACK_FRAME_OVERHEAD - blrl /* Call handler */ - .globl syscall_ret_1 -syscall_ret_1: -20: stw r3,RESULT(r1) /* Save result */ -#ifdef SHOW_SYSCALLS -#ifdef SHOW_SYSCALLS_TASK - cmp 0,r2,r31 - bne 91f -#endif - mr r4,r3 - lis r3,79f@ha - addi r3,r3,79f@l - bl printk - lwz r3,RESULT(r1) -91: -#endif - li r10,-_LAST_ERRNO - cmpl 0,r3,r10 - blt 30f - neg r3,r3 - cmpi 0,r3,ERESTARTNOHAND - bne 22f - li r3,EINTR -22: lwz r10,_CCR(r1) /* Set SO bit in CR */ - oris r10,r10,0x1000 - stw r10,_CCR(r1) -30: stw r3,GPR3(r1) /* Update return value */ - b int_return -66: li r3,ENOSYS - b 22b -/* sys_sigreturn */ -10: addi r3,r1,STACK_FRAME_OVERHEAD - bl sys_sigreturn - cmpi 0,r3,0 /* Check for restarted system call */ - bge int_return - b 20b -/* Traced system call support */ -50: bl syscall_trace - lwz r0,GPR0(r1) /* Restore original registers */ - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) - lwz r9,GPR9(r1) - cmpli 0,r0,NR_syscalls - bge- 66f - lis r10,sys_call_table@h - ori r10,r10,sys_call_table@l - slwi r0,r0,2 - lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ - cmpi 0,r10,0 - beq- 66f - mtlr r10 - addi r9,r1,STACK_FRAME_OVERHEAD - blrl /* Call handler */ - .globl syscall_ret_2 -syscall_ret_2: - stw r3,RESULT(r1) /* Save result */ - stw r3,GPR0(r1) /* temporary gross hack to make strace work */ - li r10,-_LAST_ERRNO - cmpl 0,r3,r10 - blt 60f - neg r3,r3 - cmpi 0,r3,ERESTARTNOHAND - bne 52f - li r3,EINTR -52: lwz r10,_CCR(r1) /* Set SO bit in CR */ - oris r10,r10,0x1000 - stw r10,_CCR(r1) -60: stw r3,GPR3(r1) /* Update return value */ - bl syscall_trace - b int_return -66: li r3,ENOSYS - b 52b -#ifdef SHOW_SYSCALLS -7: .string "syscall %d(%x, %x, %x, %x, %x, " -77: .string "%x, %x), current=%p\n" -79: .string " -> %x\n" - .align 2 -#endif - -/* - * This routine switches between two different tasks. The process - * state of one is saved on its kernel stack. Then the state - * of the other is restored from its kernel stack. The memory - * management hardware is updated to the second process's state. - * Finally, we can return to the second process, via int_return. - * On entry, r3 points to the TSS for the current task, r4 - * points to the TSS for the new task, and r5 contains the - * MMU context number for the new task. - * - * Note: there are two ways to get to the "going out" portion - * of this code; either by coming in via the entry (_switch) - * or via "fork" which must set up an environment equivalent - * to the "_switch" path. If you change this (or in particular, the - * SAVE_REGS macro), you'll have to change the fork code also. - * - * The code which creates the new task context is in 'copy_thread' - * in arch/ppc/kernel/process.c - * - * The MPC8xx has something that currently happens "automagically." - * Unshared user space address translations are subject to ASID (context) - * match. During each task switch, the ASID is incremented. We can - * guarantee (I hope :-) that no entries currently match this ASID - * because every task will cause at least a TLB entry to be loaded for - * the first instruction and data access, plus the kernel running will - * have displaced several more TLBs. The MMU contains 32 entries for - * each TLB, and there are 16 contexts, so we just need to make sure - * two pages get replaced for every context switch, which currently - * happens. There are other TLB management techniques that I will - * eventually implement, but this is the easiest for now. -- Dan - */ -_GLOBAL(_switch) - stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1) - stw r0,GPR0(r1) - lwz r0,0(r1) - stw r0,GPR1(r1) - /* r3-r13 are caller saved -- Cort */ - SAVE_GPR(2, r1) - SAVE_8GPRS(14, r1) - SAVE_10GPRS(22, r1) - mflr r20 /* Return to switch caller */ - mfmsr r22 - li r0,MSR_FP /* Disable floating-point */ - andc r22,r22,r0 - stw r20,_NIP(r1) - stw r22,_MSR(r1) - stw r20,_LINK(r1) - mfcr r20 - mfctr r22 - mfspr r23,XER - stw r20,_CCR(r1) - stw r22,_CTR(r1) - stw r23,_XER(r1) - li r0,0x0ff0 - stw r0,TRAP(r1) - stw r1,KSP(r3) /* Set old stack pointer */ - sync - tophys(r0,r4,r3) - mtspr SPRG3,r0 /* Update current TSS phys addr */ - SYNC - lwz r1,KSP(r4) /* Load new stack pointer */ - /* save the old current 'last' for return value */ - mr r3,r2 - addi r2,r4,-TSS /* Update current */ -#ifndef CONFIG_8xx - /* Set up segment registers for new task */ - rlwinm r5,r5,4,8,27 /* VSID = context << 4 */ - addis r5,r5,0x6000 /* Set Ks, Ku bits */ - li r0,12 /* TASK_SIZE / SEGMENT_SIZE */ - mtctr r0 - li r9,0 -3: mtsrin r5,r9 - addi r5,r5,1 /* next VSID */ - addis r9,r9,0x1000 /* address of next segment */ - bdnz 3b -#else -/* On the MPC8xx, we place the physical address of the new task - * page directory loaded into the MMU base register, and set the - * ASID compare register with the new "context". - */ - lwz r9,MM-TSS(r4) /* Get virtual address of mm */ - lwz r9,PGD(r9) /* get new->mm->pgd */ - addis r9,r9,-KERNELBASE@h /* convert to phys addr */ - mtspr M_TWB, r9 /* Update MMU base address */ - mtspr M_CASID, r5 /* Update context */ - tlbia -#endif - SYNC -2: lwz r9,_MSR(r1) /* Returning to user mode? */ - andi. r9,r9,MSR_PR - beq+ 10f /* if not, don't adjust kernel stack */ -8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ - stw r4,TSS+KSP(r2) /* save kernel stack pointer */ - tophys(r9,r1,r9) - mtspr SPRG2,r9 /* phys exception stack pointer */ -10: lwz r2,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r2 - mtlr r0 - lwz r2,_XER(r1) - lwz r0,_CCR(r1) - mtspr XER,r2 - mtcrf 0xFF,r0 - /* r3-r13 are destroyed -- Cort */ - REST_GPR(14, r1) - REST_8GPRS(15, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - lwz r2,_NIP(r1) /* Restore environment */ - lwz r0,_MSR(r1) - mtspr SRR0,r2 - mtspr SRR1,r0 - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - lwz r1,GPR1(r1) - SYNC - rfi - -/* - * Trap exit. - */ -#ifdef __SMP__ - .globl ret_from_smpfork -ret_from_smpfork: - bl schedule_tail -#endif - .globl ret_from_syscall -ret_from_syscall: - .globl int_return -int_return: -0: mfmsr r30 /* Disable interrupts */ - li r4,0 - ori r4,r4,MSR_EE - andc r30,r30,r4 - SYNC /* Some chip revs need this... */ - mtmsr r30 - SYNC - lwz r5,_MSR(r1) - and. r5,r5,r4 - beq 2f -3: lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) - cmpi 0,r4,0 - beq+ 1f - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_IRQ - .globl lost_irq_ret -lost_irq_ret: - b 3b -1: lis r4,bh_mask@ha - lwz r4,bh_mask@l(r4) - lis r5,bh_active@ha - lwz r5,bh_active@l(r5) - and. r4,r4,r5 - beq+ 2f - bl do_bottom_half - .globl do_bottom_half_ret -do_bottom_half_ret: - SYNC - mtmsr r30 /* disable interrupts again */ - SYNC -2: lwz r3,_MSR(r1) /* Returning to user mode? */ - andi. r3,r3,MSR_PR - beq+ 10f /* if so, check need_resched and signals */ - lwz r3,NEED_RESCHED(r2) - cmpi 0,r3,0 /* check need_resched flag */ - beq+ 7f - bl schedule - b 0b -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 do_signal - .globl do_signal_ret -do_signal_ret: - b 0b -8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ - stw r4,TSS+KSP(r2) /* save kernel stack pointer */ - tophys(r3,r1,r3) - mtspr SPRG2,r3 /* phys exception stack pointer */ -10: lwz r2,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r2 - mtlr r0 - lwz r2,_XER(r1) - lwz r0,_CCR(r1) - mtspr XER,r2 - mtcrf 0xFF,r0 - REST_10GPRS(3, r1) - REST_10GPRS(13, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - lwz r2,_NIP(r1) /* Restore environment */ - lwz r0,_MSR(r1) - mtspr SRR0,r2 - mtspr SRR1,r0 - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - lwz r1,GPR1(r1) - SYNC - rfi - -/* - * Fake an interrupt from kernel mode. - * This is used when enable_irq loses an interrupt. - * We only fill in the stack frame minimally. - */ -_GLOBAL(fake_interrupt) - mflr r0 - stw r0,4(r1) - stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1) - stw r0,_NIP(r1) - stw r0,_LINK(r1) - mfmsr r3 - stw r3,_MSR(r1) - li r0,0x0fac - stw r0,TRAP(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - li r4,1 - bl do_IRQ - addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD - lwz r0,4(r1) - mtlr r0 - blr - -/* * Set up the segment registers for a new context. */ _GLOBAL(set_context) @@ -2336,349 +1208,6 @@ SYNC blr -/* - * Flush instruction cache. - * This is a no-op on the 601. - */ -_GLOBAL(flush_instruction_cache) - mfspr r3,PVR - rlwinm r3,r3,16,16,31 - cmpi 0,r3,1 - beqlr /* for 601, do nothing */ - /* 603/604 processor - use invalidate-all bit in HID0 */ - mfspr r3,HID0 - ori r3,r3,HID0_ICFI - mtspr HID0,r3 - SYNC - blr - -/* - * Write any modified data cache blocks out to memory - * and invalidate the corresponding instruction cache blocks. - * This is a no-op on the 601. - * - * flush_icache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(flush_icache_range) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ - li r5,CACHE_LINE_SIZE-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,LG_CACHE_LINE_SIZE - beqlr - mtctr r4 - mr r6,r3 -1: dcbst 0,r3 - addi r3,r3,CACHE_LINE_SIZE - bdnz 1b - sync /* wait for dcbst's to get to ram */ - mtctr r4 -2: icbi 0,r6 - addi r6,r6,CACHE_LINE_SIZE - bdnz 2b - sync - isync - blr - -/* - * Like above, but only do the D-cache. This is used by the 8xx - * to push the cache so the CPM doesn't get stale data. - * - * flush_dcache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(flush_dcache_range) - li r5,CACHE_LINE_SIZE-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,LG_CACHE_LINE_SIZE - beqlr - mtctr r4 - -1: dcbst 0,r3 - addi r3,r3,CACHE_LINE_SIZE - bdnz 1b - sync /* wait for dcbst's to get to ram */ - blr - -/* - * Flush a particular page from the DATA cache - * Note: this is necessary because the instruction cache does *not* - * snoop from the data cache. - * This is a no-op on the 601 which has a unified cache. - * - * void flush_page_to_ram(void *page) - */ -_GLOBAL(flush_page_to_ram) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ - li r4,0x0FFF - andc r3,r3,r4 /* Get page base address */ - li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ - mtctr r4 - mr r6,r3 -0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,CACHE_LINE_SIZE - bdnz 0b - sync - mtctr r4 -1: icbi 0,r6 - addi r6,r6,CACHE_LINE_SIZE - bdnz 1b - sync - isync - blr - -/* - * Clear a page using the dcbz instruction, which doesn't cause any - * memory traffic (except to write out any cache lines which get - * displaced). This only works on cacheable memory. - */ -_GLOBAL(clear_page) - li r0,4096/CACHE_LINE_SIZE - mtctr r0 -1: dcbz 0,r3 - addi r3,r3,CACHE_LINE_SIZE - bdnz 1b - blr - -/* - * Flush entries from the hash table with VSIDs in the range - * given. - */ -#ifndef CONFIG_8xx -_GLOBAL(flush_hash_segments) - lis r5,Hash@ha - lwz r5,Hash@l(r5) /* base of hash table */ -#ifdef NO_RELOAD_HTAB - cmpwi 0,r5,0 - bne+ 99f - tlbia - sync -#ifdef __SMP__ - tlbsync - sync -#endif - blr -99: -#endif /* NO_RELOAD_HTAB */ -#ifdef __SMP__ - /* Note - we had better not do anything which could generate - a hash table miss while we have the hash table locked, - or we'll get a deadlock. -paulus */ - mfmsr r10 - sync - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - mtmsr r0 - SYNC - lis r9,hash_table_lock@h - ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) - oris r8,r8,8 -10: lwarx r6,0,r9 - cmpi 0,r6,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - eieio -#endif - 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 */ - oris r4,r4,0x8000 - ori r4,r4,0x7f - lis r6,Hash_size@ha - lwz r6,Hash_size@l(r6) /* size in bytes */ - srwi r6,r6,3 /* # PTEs */ - mtctr r6 - addi r5,r5,-8 - li r0,0 -1: lwzu r6,8(r5) /* get next tag word */ - cmplw 0,r6,r3 - cmplw 1,r6,r4 - cror 0,0,5 /* set cr0.lt if out of range */ - blt 2f /* branch if out of range */ - stw r0,0(r5) /* invalidate entry */ -2: bdnz 1b /* continue with loop */ - sync - tlbia - sync -#ifdef __SMP__ - tlbsync - sync - lis r3,hash_table_lock@ha - stw r0,hash_table_lock@l(r3) - mtmsr r10 - SYNC -#endif - blr - -/* - * Flush the entry for a particular page from the hash table. - * - * flush_hash_page(unsigned context, unsigned long va) - */ -_GLOBAL(flush_hash_page) - lis r6,Hash@ha - lwz r6,Hash@l(r6) /* hash table base */ -#ifdef NO_RELOAD_HTAB - cmpwi 0,r6,0 /* hash table in use? */ - bne+ 99f - tlbie r4 /* in hw tlb too */ - sync -#ifdef __SMP__ - tlbsync - sync -#endif - blr -99: -#endif /* NO_RELOAD_HTAB */ -#ifdef __SMP__ - /* Note - we had better not do anything which could generate - a hash table miss while we have the hash table locked, - or we'll get a deadlock. -paulus */ - mfmsr r10 - sync - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - mtmsr r0 - SYNC - lis r9,hash_table_lock@h - ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) - oris r8,r8,9 -10: lwarx r7,0,r9 - cmpi 0,r7,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - eieio -#endif - 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 */ - rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */ - rlwinm r7,r4,32-6,10,25 /* get page index << 6 */ - rlwinm r5,r3,32-1,7,25 /* vsid << 6 */ - xor r7,r7,r5 /* primary hash << 6 */ - lis r5,Hash_mask@ha - lwz r5,Hash_mask@l(r5) /* hash mask */ - slwi r5,r5,6 /* << 6 */ - and r7,r7,r5 - add r6,r6,r7 /* address of primary PTEG */ - li r8,8 - mtctr r8 - addi r7,r6,-8 -1: lwzu r0,8(r7) /* get next PTE */ - cmpw 0,r0,r3 /* see if tag matches */ - bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */ - beq 3f /* if we found it */ - ori r3,r3,0x40 /* set H (alt. hash) bit */ - xor r6,r6,r5 /* address of secondary PTEG */ - mtctr r8 - addi r7,r6,-8 -2: lwzu r0,8(r7) /* get next PTE */ - cmpw 0,r0,r3 /* see if tag matches */ - bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */ - bne 4f /* if we didn't find it */ -3: li r0,0 - stw r0,0(r7) /* invalidate entry */ -4: sync - tlbie r4 /* in hw tlb too */ - sync -#ifdef __SMP__ - tlbsync - sync - lis r3,hash_table_lock@h - li r0,0 - stw r0,hash_table_lock@l(r3) - mtmsr r10 - SYNC -#endif - blr -#endif /* CONFIG_8xx */ - -/* - * This routine is just here to keep GCC happy - sigh... - */ -_GLOBAL(__main) - blr - -/* - * PROM code for specific machines follows. Put it - * here so it's easy to add arch-specific sections later. - * -- Cort - */ - -#ifndef CONFIG_8xx -/* - * On CHRP, the Run-Time Abstraction Services (RTAS) have to be - * called with the MMU off. - */ - .globl enter_rtas -enter_rtas: - mflr r0 - stw r0,20(r1) - lis r4,rtas_data@ha - lwz r4,rtas_data@l(r4) - addis r4,r4,-KERNELBASE@h - 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) - addis r5,r8,-KERNELBASE@h - mfmsr r9 - stw r9,8(r1) - 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 */ -#endif /* CONFIG_8xx */ - -#ifdef CONFIG_8xx -/* Jump into the system reset for the rom. - * We first disable the MMU, and then jump to the ROM reset address. - * - * r3 is the board info structure, r4 is the location for starting. - * I use this for building a small kernel that can load other kernels, - * rather than trying to write or rely on a rom monitor that can tftp load. - */ - .globl m8xx_gorom -m8xx_gorom: - li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) - lis r6,2f@h - addis r6,r6,-KERNELBASE@h - ori r6,r6,2f@l - mtspr SRR0,r6 - mtspr SRR1,r5 - rfi -2: - mtlr r4 - blr -#endif /* CONFIG_8xx */ - /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S --- v2.3.15/linux/arch/ppc/kernel/head_8xx.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/head_8xx.S Tue Aug 31 11:36:43 1999 @@ -0,0 +1,903 @@ +/* + * arch/ppc/kernel/except_8xx.S + * + * $Id: head_8xx.S,v 1.2 1999/08/23 02:53:19 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications by Dan Malek + * Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains low-level support and setup for PowerPC 8xx + * embedded processors, including trap and interrupt dispatch. + * + * 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 "ppc_asm.h" +#include +#include +#include +#include + + .text + .globl _stext +_stext: + +/* + * _start is defined this way because the XCOFF loader in the OpenFirmware + * on the powermac expects the entry point to be a procedure descriptor. + */ + .text + .globl _start +_start: + +/* MPC8xx + * This port was done on an MBX board with an 860. Right now I only + * support an ELF compressed (zImage) boot from EPPC-Bug because the + * code there loads up some registers before calling us: + * r3: ptr to board info data + * r4: initrd_start or if no initrd then 0 + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + * + * I decided to use conditional compilation instead of checking PVR and + * adding more processor specific branches around code I don't need. + * Since this is an embedded processor, I also appreciate any memory + * savings I can get. + * + * The MPC8xx does not have any BATs, but it supports large page sizes. + * We first initialize the MMU to support 8M byte pages, then load one + * entry into each of the instruction and data TLBs to map the first + * 8M 1:1. I also mapped an additional I/O space 1:1 so we can get to + * the "internal" processor registers before MMU_init is called. + * + * The TLB code currently contains a major hack. Since I use the condition + * code register, I have to save and restore it. I am out of registers, so + * I just store it in memory location 0 (the TLB handlers are not reentrant). + * To avoid making any decisions, I need to use the "segment" valid bit + * in the first level table, but that would require many changes to the + * Linux page directory/table functions that I don't want to do right now. + * + * I used to use SPRG2 for a temporary register in the TLB handler, but it + * has since been put to other uses. I now use a hack to save a register + * and the CCR at memory location 0.....Someday I'll fix this..... + * -- Dan + */ + + .globl __start +__start: + mr r31,r3 /* save parameters */ + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + li r24,0 /* cpu # */ + + tlbia /* Invalidate all TLB entries */ + li r8, 0 + mtspr MI_CTR, r8 /* Set instruction control to zero */ + lis r8, MD_RESETVAL@h + mtspr MD_CTR, r8 /* Set data TLB control */ + + /* Now map the lower 8 Meg into the TLBs. For this quick hack, + * we can load the instruction and data TLB registers with the + * same values. + */ + lis r8, KERNELBASE@h /* Create vaddr for TLB */ + ori r8, r8, MI_EVALID /* Mark it valid */ + mtspr MI_EPN, r8 + mtspr MD_EPN, r8 + li r8, MI_PS8MEG /* Set 8M byte page */ + ori r8, r8, MI_SVALID /* Make it valid */ + mtspr MI_TWC, r8 + mtspr MD_TWC, r8 + li r8, MI_BOOTINIT /* Create RPN for address 0 */ + mtspr MI_RPN, r8 /* Store TLB entry */ + mtspr MD_RPN, r8 + lis r8, MI_Kp@h /* Set the protection mode */ + mtspr MI_AP, r8 + mtspr MD_AP, r8 + +/* We will get these from a configuration file as soon as I verify + * the extraneous bits don't cause problems in the TLB. + */ +#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE) +#define BOOT_IMMR 0xfa000000 +#endif +#ifdef CONFIG_BSEIP +#define BOOT_IMMR 0xff000000 +#endif + /* Map another 8 MByte at 0xfa000000 to get the processor + * internal registers (among other things). + */ + lis r8, BOOT_IMMR@h /* Create vaddr for TLB */ + ori r8, r8, MD_EVALID /* Mark it valid */ + mtspr MD_EPN, r8 + li r8, MD_PS8MEG /* Set 8M byte page */ + ori r8, r8, MD_SVALID /* Make it valid */ + mtspr MD_TWC, r8 + lis r8, BOOT_IMMR@h /* Create paddr for TLB */ + ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ + mtspr MD_RPN, r8 + + /* Since the cache is enabled according to the information we + * just loaded into the TLB, invalidate and enable the caches here. + * We should probably check/set other modes....later. + */ + lis r8, IDC_INVALL@h + mtspr IC_CST, r8 + mtspr DC_CST, r8 + lis r8, IDC_ENABLE@h + mtspr IC_CST, r8 +#if 0 + mtspr DC_CST, r8 +#else + /* For a debug option, I left this here to easily enable + * the write through cache mode + */ + lis r8, DC_SFWT@h + mtspr DC_CST, r8 + lis r8, IDC_ENABLE@h + mtspr DC_CST, r8 +#endif + +/* We now have the lower 8 Meg mapped into TLB entries, and the caches + * ready to work. + */ + +turn_on_mmu: + mfmsr r0 + ori r0,r0,MSR_DR|MSR_IR + mtspr SRR1,r0 + lis r0,start_here@h + ori r0,r0,start_here@l + mtspr SRR0,r0 + SYNC + rfi /* enables MMU */ + +/* + * Exception entry code. This code runs with address translation + * turned off, i.e. using physical addresses. + * We assume sprg3 has the physical address of the current + * task's thread_struct. + */ +#define EXCEPTION_PROLOG \ + mtspr SPRG0,r20; \ + mtspr SPRG1,r21; \ + mfcr r20; \ + mfspr r21,SPRG2; /* exception stack to use from */ \ + cmpwi 0,r21,0; /* user mode or RTAS */ \ + bne 1f; \ + tophys(r21,r1); /* use tophys(kernel sp) otherwise */ \ + subi r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\ +1: stw r20,_CCR(r21); /* save registers */ \ + stw r22,GPR22(r21); \ + stw r23,GPR23(r21); \ + mfspr r20,SPRG0; \ + stw r20,GPR20(r21); \ + mfspr r22,SPRG1; \ + stw r22,GPR21(r21); \ + mflr r20; \ + stw r20,_LINK(r21); \ + mfctr r22; \ + stw r22,_CTR(r21); \ + mfspr r20,XER; \ + stw r20,_XER(r21); \ + mfspr r22,SRR0; \ + mfspr r23,SRR1; \ + stw r0,GPR0(r21); \ + stw r1,GPR1(r21); \ + stw r2,GPR2(r21); \ + stw r1,0(r21); \ + tovirt(r1,r21); /* set new kernel sp */ \ + SAVE_4GPRS(3, r21); +/* + * Note: code which follows this uses cr0.eq (set if from kernel), + * r21, r22 (SRR0), and r23 (SRR1). + */ + +/* + * Exception vectors. + */ +#define STD_EXCEPTION(n, label, hdlr) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r20,MSR_KERNEL; \ + bl transfer_to_handler; \ + .long hdlr; \ + .long ret_from_except + +/* System reset */ +#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ + STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#else + STD_EXCEPTION(0x100, Reset, UnknownException) +#endif + +/* Machine check */ + STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data access exception. + * This is "never generated" by the MPC8xx. We jump to it for other + * translation errors. + */ + . = 0x300 +DataAccess: + EXCEPTION_PROLOG + mfspr r20,DSISR + stw r20,_DSISR(r21) + mr r5,r20 + mfspr r4,DAR + stw r4,_DAR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long do_page_fault + .long ret_from_except + +/* Instruction access exception. + * This is "never generated" by the MPC8xx. We jump to it for other + * translation errors. + */ + . = 0x400 +InstructionAccess: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + mr r4,r22 + mr r5,r23 + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long do_page_fault + .long ret_from_except + +/* External interrupt */ + . = 0x500; +HardwareInterrupt: + EXCEPTION_PROLOG; +#ifdef CONFIG_APUS + /* This is horrible, but there's no way around it. Enable the + data cache so the IRQ hardware register can be accessed + without cache intervention. Then disable interrupts and get + the current emulated m68k IPL value. */ + + mfmsr 20 + xori r20,r20,MSR_DR + sync + mtmsr r20 + sync + + lis r3,APUS_IPL_EMU@h + + li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT) + stb r20,APUS_IPL_EMU@l(r3) + eieio + + lbz r3,APUS_IPL_EMU@l(r3) + + mfmsr r20 + xori r20,r20,MSR_DR + sync + mtmsr r20 + sync + + stw r3,(_CCR+4)(r21); +#endif + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + li r4,0 + bl transfer_to_handler + .long do_IRQ; + .long ret_from_except + + +/* Alignment exception */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG + mfspr r4,DAR + stw r4,_DAR(r21) + mfspr r5,DSISR + stw r5,_DSISR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long AlignmentException + .long ret_from_except + +/* Program check exception */ + . = 0x700 +ProgramCheck: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long ProgramCheckException + .long ret_from_except + +/* No FPU on MPC8xx. This exception is not supposed to happen. +*/ + STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + + STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + STD_EXCEPTION(0xa00, Trap_0a, UnknownException) + STD_EXCEPTION(0xb00, Trap_0b, UnknownException) + +/* System call */ + . = 0xc00 +SystemCall: + EXCEPTION_PROLOG + stw r3,ORIG_GPR3(r21) + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long DoSyscall + .long ret_from_except + +/* Single step - not used on 601 */ + STD_EXCEPTION(0xd00, SingleStep, SingleStepException) + + STD_EXCEPTION(0xe00, Trap_0e, UnknownException) + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + +/* On the MPC8xx, this is a software emulation interrupt. It occurs + * for all unimplemented and illegal instructions. + */ + STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation) + + . = 0x1100 +/* + * For the MPC8xx, this is a software tablewalk to load the instruction + * TLB. It is modelled after the example in the Motorola manual. The task + * switch loads the M_TWB register with the pointer to the first level table. + * If we discover there is no second level table (the value is zero), the + * plan was to load that into the TLB, which causes another fault into the + * TLB Error interrupt where we can handle such problems. However, that did + * not work, so if we discover there is no second level table, we restore + * registers and branch to the error exception. We have to use the MD_xxx + * registers for the tablewalk because the equivalent MI_xxx registers + * only perform the attribute functions. + */ +InstructionTLBMiss: + mtspr M_TW, r20 /* Save a couple of working registers */ + mfcr r20 + stw r20, 0(r0) + stw r21, 4(r0) + mfspr r20, SRR0 /* Get effective address of fault */ + mtspr MD_EPN, r20 /* Have to use MD_EPN for walk, MI_EPN can't */ + mfspr r20, M_TWB /* Get level 1 table entry address */ + lwz r21, 0(r20) /* Get the level 1 entry */ + rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ + beq 2f /* If zero, don't try to find a pte */ + + /* We have a pte table, so load the MI_TWC with the attributes + * for this page, which has only bit 31 set. + */ + tophys(r21,r21) + ori r21,r21,1 /* Set valid bit */ + mtspr MI_TWC, r21 /* Set page attributes */ + mtspr MD_TWC, r21 /* Load pte table base address */ + mfspr r21, MD_TWC /* ....and get the pte address */ + lwz r21, 0(r21) /* Get the pte */ + + /* Set four subpage valid bits (24, 25, 26, and 27). + * Since we currently run MI_CTR.PPCS = 0, the manual says, + * "If the page size is larger than 4k byte, then all the + * 4 bits should have the same value." + * I don't really know what to do if the page size is 4k Bytes, + * but I know setting them all to 0 does not work, and setting them + * all to 1 does, so that is the way it is right now. + * BTW, these four bits map to the software only bits in the + * linux page table. I used to turn them all of, but now just + * set them all for the hardware. + li r20, 0x00f0 + andc r20, r21, r20 + ori r20, r20, 0x0080 + */ + ori r20, r21, 0x00f0 + + mtspr MI_RPN, r20 /* Update TLB entry */ + + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + rfi + +2: mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + b InstructionAccess + + . = 0x1200 +DataStoreTLBMiss: + mtspr M_TW, r20 /* Save a couple of working registers */ + mfcr r20 + stw r20, 0(r0) + stw r21, 4(r0) + mfspr r20, M_TWB /* Get level 1 table entry address */ + lwz r21, 0(r20) /* Get the level 1 entry */ + rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ + beq 2f /* If zero, don't try to find a pte */ + + /* We have a pte table, so load fetch the pte from the table. + */ + tophys(r21, r21) + ori r21, r21, 1 /* Set valid bit in physical L2 page */ + mtspr MD_TWC, r21 /* Load pte table base address */ + mfspr r21, MD_TWC /* ....and get the pte address */ + lwz r21, 0(r21) /* Get the pte */ + + /* Set four subpage valid bits (24, 25, 26, and 27). + * Since we currently run MD_CTR.PPCS = 0, the manual says, + * "If the page size is larger than 4k byte, then all the + * 4 bits should have the same value." + * I don't really know what to do if the page size is 4k Bytes, + * but I know setting them all to 0 does not work, and setting them + * all to 1 does, so that is the way it is right now. + * BTW, these four bits map to the software only bits in the + * linux page table. I used to turn them all of, but now just + * set them all for the hardware. + li r20, 0x00f0 + andc r20, r21, r20 + ori r20, r20, 0x0080 + */ + ori r20, r21, 0x00f0 + + mtspr MD_RPN, r20 /* Update TLB entry */ + + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + rfi + +2: mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + b DataAccess + +/* This is an instruction TLB error on the MPC8xx. This could be due + * to many reasons, such as executing guarded memory or illegal instruction + * addresses. There is nothing to do but handle a big time error fault. + */ + . = 0x1300 +InstructionTLBError: + b InstructionAccess + +/* This is the data TLB error on the MPC8xx. This could be due to + * many reasons, including a dirty update to a pte. We can catch that + * one here, but anything else is an error. First, we track down the + * Linux pte. If it is valid, write access is allowed, but the + * page dirty bit is not set, we will set it and reload the TLB. For + * any other case, we bail out to a higher level function that can + * handle it. + */ + . = 0x1400 +DataTLBError: + mtspr M_TW, r20 /* Save a couple of working registers */ + mfcr r20 + stw r20, 0(r0) + stw r21, 4(r0) + + /* First, make sure this was a store operation. + */ + mfspr r20, DSISR + andis. r21, r20, 0x0200 /* If set, indicates store op */ + beq 2f + + mfspr r20, M_TWB /* Get level 1 table entry address */ + lwz r21, 0(r20) /* Get the level 1 entry */ + rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ + beq 2f /* If zero, bail */ + + /* We have a pte table, so fetch the pte from the table. + */ + tophys(r21, r21) + ori r21, r21, 1 /* Set valid bit in physical L2 page */ + mtspr MD_TWC, r21 /* Load pte table base address */ + mfspr r21, MD_TWC /* ....and get the pte address */ + lwz r21, 0(r21) /* Get the pte */ + + andi. r20, r21, _PAGE_RW /* Is it writeable? */ + beq 2f /* Bail out if not */ + + ori r21, r21, _PAGE_DIRTY /* Update changed bit */ + mfspr r20, MD_TWC /* Get pte address again */ + stw r21, 0(r20) /* and update pte in table */ + + /* Set four subpage valid bits (24, 25, 26, and 27). + * Since we currently run MD_CTR.PPCS = 0, the manual says, + * "If the page size is larger than 4k byte, then all the + * 4 bits should have the same value." + * I don't really know what to do if the page size is 4k Bytes, + * but I know setting them all to 0 does not work, and setting them + * all to 1 does, so that is the way it is right now. + * BTW, these four bits map to the software only bits in the + * linux page table. I used to turn them all of, but now just + * set them all for the hardware. + li r20, 0x00f0 + andc r20, r21, r20 + ori r20, r20, 0x0080 + */ + ori r20, r21, 0x00f0 + + mtspr MD_RPN, r20 /* Update TLB entry */ + + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + rfi +2: + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + b DataAccess +#endif /* CONFIG_8xx */ + + STD_EXCEPTION(0x1500, Trap_15, UnknownException) + STD_EXCEPTION(0x1600, Trap_16, UnknownException) + STD_EXCEPTION(0x1700, Trap_17, TAUException) + STD_EXCEPTION(0x1800, Trap_18, UnknownException) + STD_EXCEPTION(0x1900, Trap_19, UnknownException) + STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) + STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) +/* On the MPC8xx, these next four traps are used for development + * support of breakpoints and such. Someday I will get around to + * using them. + */ + STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) + STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) + STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) + STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) + + . = 0x2000 + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception, turning + * on address translation. + */ + .globl transfer_to_handler +transfer_to_handler: + stw r22,_NIP(r21) + lis r22,MSR_POW@h + andc r23,r23,r22 + stw r23,_MSR(r21) + SAVE_GPR(7, r21) + SAVE_4GPRS(8, r21) + SAVE_8GPRS(12, r21) + SAVE_8GPRS(24, r21) + andi. r23,r23,MSR_PR + mfspr r23,SPRG3 /* if from user, fix up THREAD.regs */ + beq 2f + addi r24,r1,STACK_FRAME_OVERHEAD + stw r24,PT_REGS(r23) +2: addi r2,r23,-THREAD /* set r2 to current */ + tovirt(r2,r2) + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r21) + li r22,RESULT + stwcx. r22,r22,r21 /* to clear the reservation */ + 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 + mtspr SRR1,r20 + mtlr r23 + SYNC + 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 + + .globl giveup_fpu +giveup_fpu: + blr + +/* + * This code is jumped to from the startup code to copy + * the kernel image to physical address 0. + */ +relocate_kernel: + lis r9,0x426f /* if booted from BootX, don't */ + addi r9,r9,0x6f58 /* translate source addr */ + cmpw r31,r9 /* (we have to on chrp) */ + beq 7f + rlwinm r4,r4,0,8,31 /* translate source address */ + add r4,r4,r3 /* to region mapped with BATs */ +7: addis r9,r26,klimit@ha /* fetch klimit */ + lwz r25,klimit@l(r9) + addis r25,r25,-KERNELBASE@h + li r6,0 /* Destination offset */ + li r5,0x4000 /* # bytes of memory to copy */ + bl copy_and_flush /* copy the first 0x4000 bytes */ + addi r0,r3,4f@l /* jump to the address of 4f */ + mtctr r0 /* in copy and do the rest. */ + bctr /* jump to the copy */ +4: mr r5,r25 + bl copy_and_flush /* copy the rest */ + b turn_on_mmu + +/* + * Copy routine used to copy the kernel to start at physical address 0 + * and flush and invalidate the caches as needed. + * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset + * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. + */ +copy_and_flush: + addi r5,r5,-4 + addi r6,r6,-4 +4: li r0,8 + mtctr r0 +3: addi r6,r6,4 /* copy a cache line */ + lwzx r0,r6,r4 + stwx r0,r6,r3 + bdnz 3b + dcbst r6,r3 /* write it to memory */ + sync + icbi r6,r3 /* flush the icache line */ + cmplw 0,r6,r5 + blt 4b + isync + addi r5,r5,4 + addi r6,r6,4 + blr + +#ifdef CONFIG_SMP + .globl __secondary_start_psurge +__secondary_start_psurge: + li r24,1 /* cpu # */ + b __secondary_start + + .globl __secondary_hold +__secondary_hold: + /* tell the master we're here */ + lis r5,0x4@h + ori r5,r5,0x4@l + stw r3,0(r5) + dcbf 0,r5 +100: + lis r5,0 + dcbi 0,r5 + lwz r4,0(r5) + /* wait until we're told to start */ + cmp 0,r4,r3 + bne 100b + /* our cpu # was at addr 0 - go */ + lis r5,__secondary_start@h + ori r5,r5,__secondary_start@l + tophys(r5,r5) + mtlr r5 + mr r24,r3 /* cpu # */ + blr +#endif /* CONFIG_SMP */ + +/* + * This is where the main kernel code starts. + */ +start_here: +#ifdef __SMP__ + /* if we're the second cpu stack and r2 are different + * and we want to not clear the bss -- Cort */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + lwz r5,0(r5) + cmpi 0,r5,0 + beq 99f + + /* get current */ + lis r2,current_set@h + ori r2,r2,current_set@l + slwi r24,r24,2 /* cpu # to current_set[cpu#] */ + add r2,r2,r24 + lwz r2,0(r2) + b 10f +99: +#endif /* __SMP__ */ + /* ptr to current */ + lis r2,init_task_union@h + ori r2,r2,init_task_union@l + /* Clear out the BSS */ + lis r11,_end@ha + addi r11,r11,_end@l + lis r8,__bss_start@ha + addi r8,r8,__bss_start@l + subf r11,r8,r11 + addi r11,r11,3 + rlwinm. r11,r11,30,2,31 + beq 2f + addi r8,r8,-4 + mtctr r11 + li r0,0 +3: stwu r0,4(r8) + bdnz 3b +2: +#ifdef __SMP__ +10: +#endif /* __SMP__ */ + /* stack */ + addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) +/* + * 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 MMU_init + +/* + * 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. + * On the 8xx, all we have to do is invalidate the TLB to clear + * the old 8M byte TLB mappings and load the page table base register. + */ + /* The right way to do this would be to track it down through + * init's THREAD like the context switch code does, but this is + * easier......until someone changes init's static structures. + */ + lis r6, swapper_pg_dir@h + tophys(r6,r6) + ori r6, r6, swapper_pg_dir@l + mtspr M_TWB, r6 + lis r4,2f@h + ori r4,r4,2f@l + tophys(r4,r4) + 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 */ + sync /* wait for tlbia/tlbie to finish */ +#ifdef __SMP__ + tlbsync /* ... on all CPUs */ + sync +#endif +/* Set up for using our exception vectors */ + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ +/* Now turn on the MMU for real! */ + li r4,MSR_KERNEL + lis r3,start_kernel@h + ori r3,r3,start_kernel@l +#ifdef __SMP__ + /* the second time through here we go to + * start_secondary(). -- Cort + */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + tophys(r5,r5) + lwz r5,0(r5) + cmpi 0,r5,0 + beq 10f + lis r3,start_secondary@h + ori r3,r3,start_secondary@l +10: +#endif /* __SMP__ */ + mtspr SRR0,r3 + mtspr SRR1,r4 + rfi /* enable MMU and jump to start_kernel */ + +/* + * Set up to use a given MMU context. + * + * The MPC8xx has something that currently happens "automagically." + * Unshared user space address translations are subject to ASID (context) + * match. During each task switch, the ASID is incremented. We can + * guarantee (I hope :-) that no entries currently match this ASID + * because every task will cause at least a TLB entry to be loaded for + * the first instruction and data access, plus the kernel running will + * have displaced several more TLBs. The MMU contains 32 entries for + * each TLB, and there are 16 contexts, so we just need to make sure + * two pages get replaced for every context switch, which currently + * happens. There are other TLB management techniques that I will + * eventually implement, but this is the easiest for now. -- Dan + * + * On the MPC8xx, we place the physical address of the new task + * page directory loaded into the MMU base register, and set the + * ASID compare register with the new "context". + */ +_GLOBAL(set_context) + mtspr M_CASID,r3 /* Update context */ + tlbia + SYNC + blr + +/* Jump into the system reset for the rom. + * We first disable the MMU, and then jump to the ROM reset address. + * + * r3 is the board info structure, r4 is the location for starting. + * I use this for building a small kernel that can load other kernels, + * rather than trying to write or rely on a rom monitor that can tftp load. + */ + .globl m8xx_gorom +m8xx_gorom: + li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) + lis r6,2f@h + addis r6,r6,-KERNELBASE@h + ori r6,r6,2f@l + mtspr SRR0,r6 + mtspr SRR1,r5 + rfi +2: + mtlr r4 + blr + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the data segment, + * which is page-aligned. + */ + .data + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.3.15/linux/arch/ppc/kernel/idle.c Fri Jul 23 12:20:23 1999 +++ linux/arch/ppc/kernel/idle.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.63 1999/06/10 22:55:35 geert Exp $ + * $Id: idle.c,v 1.65 1999/08/03 19:16:19 cort Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -69,7 +69,6 @@ return 0; } -#ifdef __SMP__ /* * SMP entry into the idle task - calls the same thing as the * non-smp versions. -- Cort @@ -78,19 +77,6 @@ { idled(unused); return 0; -} -#endif /* __SMP__ */ - -/* - * 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 */ } /* diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.15/linux/arch/ppc/kernel/irq.c Tue Jul 13 02:29:35 1999 +++ linux/arch/ppc/kernel/irq.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: irq.c,v 1.107 1999/06/17 05:39:12 paulus Exp $ + * $Id: irq.c,v 1.108 1999/07/23 01:55:44 davem Exp $ * * arch/ppc/kernel/irq.c * diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/local_irq.h linux/arch/ppc/kernel/local_irq.h --- v2.3.15/linux/arch/ppc/kernel/local_irq.h Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/local_irq.h Tue Aug 31 11:36:43 1999 @@ -19,10 +19,6 @@ int irq_offset; }; -#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);}) -#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);}) -#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);}) - struct irqdesc { struct irqaction *action; struct hw_interrupt_type *ctl; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/mbx_pci.c linux/arch/ppc/kernel/mbx_pci.c --- v2.3.15/linux/arch/ppc/kernel/mbx_pci.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/mbx_pci.c Thu Aug 26 12:42:32 1999 @@ -253,16 +253,14 @@ return PCIBIOS_DEVICE_NOT_FOUND; } -__initfunc( -void -mbx_pcibios_fixup(void)) +void __init +mbx_pcibios_fixup(void) { /* Nothing to do here? */ } -__initfunc( -void -mbx_setup_pci_ptrs(void)) +void __init +mbx_setup_pci_ptrs(void) { set_config_access_method(mbx); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c --- v2.3.15/linux/arch/ppc/kernel/mbx_setup.c Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/kernel/mbx_setup.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: mbx_setup.c,v 1.11 1999/06/28 17:59:43 cort Exp $ + * $Id: mbx_setup.c,v 1.12 1999/08/31 06:53:56 davem Exp $ * * linux/arch/ppc/kernel/setup.c * @@ -75,8 +75,8 @@ { } -__initfunc(void -mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init +mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { int cpm_page; extern char cmd_line[]; @@ -141,7 +141,7 @@ * sixteen, or external oscillator divided by four. Currently, we only * support the MBX, which is system clock divided by sixteen. */ -__initfunc(void mbx_calibrate_decr(void)) +void __init mbx_calibrate_decr(void) { bd_t *binfo = (bd_t *)&res; int freq, fp, divisor; @@ -182,8 +182,7 @@ return(0); } -initfunc(unsigned long -mbx_get_rtc_time(void) +unsigned long __init mbx_get_rtc_time(void) { /* First, unlock all of the registers we are going to modify. * To protect them from corruption during power down, registers @@ -310,8 +309,8 @@ * interrupts can be either edge or level triggered, but there is no * reason for us to change the EPPC-bug values (it would not work if we did). */ -__initfunc(void -mbx_init_IRQ(void)) +void __init +mbx_init_IRQ(void) { int i; @@ -413,9 +412,9 @@ } #endif -__initfunc(void +void __init mbx_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { if ( r3 ) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.3.15/linux/arch/ppc/kernel/misc.S Wed Jul 28 10:30:10 1999 +++ linux/arch/ppc/kernel/misc.S Tue Aug 31 11:36:43 1999 @@ -17,19 +17,17 @@ #include #include #include -#include "ppc_asm.tmpl" -#include "ppc_defs.h" +#include +#include "ppc_asm.h" #ifndef CONFIG_8xx -/* This instruction is not implemented on the PPC 601 or 603 */ -#define tlbia \ - li r4,128; \ - mtspr CTR,r4; \ - li r4,0; \ -0: tlbie r4; \ - addi r4,r4,0x1000; \ - bdnz 0b -#endif +CACHE_LINE_SIZE = 32 +LG_CACHE_LINE_SIZE = 5 +#else +CACHE_LINE_SIZE = 16 +LG_CACHE_LINE_SIZE = 4 +#endif /* CONFIG_8xx */ + .text /* @@ -146,6 +144,117 @@ blr /* + * Flush instruction cache. + * This is a no-op on the 601. + */ +_GLOBAL(flush_instruction_cache) + mfspr r3,PVR + rlwinm r3,r3,16,16,31 + cmpi 0,r3,1 + beqlr /* for 601, do nothing */ + /* 603/604 processor - use invalidate-all bit in HID0 */ + mfspr r3,HID0 + ori r3,r3,HID0_ICFI + mtspr HID0,r3 + SYNC + blr + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * This is a no-op on the 601. + * + * flush_icache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_icache_range) + mfspr r5,PVR + rlwinm r5,r5,16,16,31 + cmpi 0,r5,1 + beqlr /* for 601, do nothing */ + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + mr r6,r3 +1: dcbst 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + mtctr r4 +2: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 2b + sync + isync + blr + +/* + * Like above, but only do the D-cache. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_dcache_range) + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + +1: dcbst 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + blr + +/* + * Flush a particular page from the DATA cache + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * This is a no-op on the 601 which has a unified cache. + * + * void flush_page_to_ram(void *page) + */ +_GLOBAL(flush_page_to_ram) + mfspr r5,PVR + rlwinm r5,r5,16,16,31 + cmpi 0,r5,1 + beqlr /* for 601, do nothing */ + li r4,0x0FFF + andc r3,r3,r4 /* Get page base address */ + li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ + mtctr r4 + mr r6,r3 +0: dcbst 0,r3 /* Write line to ram */ + addi r3,r3,CACHE_LINE_SIZE + bdnz 0b + sync + mtctr r4 +1: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 1b + sync + isync + blr + +/* + * Clear a page using the dcbz instruction, which doesn't cause any + * memory traffic (except to write out any cache lines which get + * displaced). This only works on cacheable memory. + */ +_GLOBAL(clear_page) + li r0,4096/CACHE_LINE_SIZE + mtctr r0 +1: dcbz 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + blr + +/* * Atomic [test&set] exchange * * unsigned long xchg_u32(void *ptr, unsigned long val) @@ -659,8 +768,8 @@ sc cmpi 0,r3,0 /* parent or child? */ bnelr /* return if parent */ - li r0,0 /* clear out p->tss.regs */ - stw r0,TSS+PT_REGS(r2) /* since we don't have user ctx */ + li r0,0 /* clear out p->thread.regs */ + stw r0,THREAD+PT_REGS(r2) /* since we don't have user ctx */ mtlr r6 /* fn addr in lr */ mr r3,r4 /* load arg and call fn */ blrl @@ -668,6 +777,12 @@ li r3,0 sc +/* + * This routine is just here to keep GCC happy - sigh... + */ +_GLOBAL(__main) + blr + #define SYSCALL(name) \ _GLOBAL(name) \ li r0,__NR_##name; \ @@ -680,7 +795,6 @@ #define __NR__exit __NR_exit -SYSCALL(idle) SYSCALL(sync) SYSCALL(setsid) SYSCALL(write) @@ -812,7 +926,7 @@ .long sys_uname .long sys_iopl /* 110 */ .long sys_vhangup - .long sys_idle + .long sys_ni_syscall /* old 'idle' syscall */ .long sys_vm86 .long sys_wait4 .long sys_swapoff /* 115 */ diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c --- v2.3.15/linux/arch/ppc/kernel/mk_defs.c Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/kernel/mk_defs.c Tue Aug 31 11:36:43 1999 @@ -35,19 +35,19 @@ DEFINE(COUNTER, offsetof(struct task_struct, counter)); DEFINE(PROCESSOR, offsetof(struct task_struct, processor)); DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending)); - DEFINE(TSS, offsetof(struct task_struct, tss)); + DEFINE(THREAD, offsetof(struct task_struct, thread)); DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(ACTIVE_MM, offsetof(struct task_struct, active_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(PGDIR, offsetof(struct thread_struct, pgdir)); DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); DEFINE(PF_TRACESYS, PF_TRACESYS); DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); - DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0])); - DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr)); + DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); + DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); /* Interrupt register frame */ DEFINE(TASK_UNION_SIZE, sizeof(union task_union)); DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.3.15/linux/arch/ppc/kernel/open_pic.c Tue May 11 08:24:32 1999 +++ linux/arch/ppc/kernel/open_pic.c Tue Aug 31 11:36:43 1999 @@ -1,11 +1,87 @@ -#include -#include +/* + * arch/ppc/kernel/openpic.c -- OpenPIC Interrupt Handling + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include #include -#include +#include #include +#include +#include +#include #include -#include "open_pic.h" -#include "i8259.h" +#include "local_irq.h" + +volatile struct OpenPIC *OpenPIC = NULL; +u_int OpenPIC_NumInitSenses __initdata = 0; +u_char *OpenPIC_InitSenses __initdata = NULL; + +void chrp_mask_irq(unsigned int); +void chrp_unmask_irq(unsigned int); + +static u_int NumProcessors; +static u_int NumSources; + +struct hw_interrupt_type open_pic = { + " OpenPIC ", + NULL, + NULL, + NULL, + openpic_enable_irq, + openpic_disable_irq, + 0, + 0 +}; + +/* + * Accesses to the current processor's registers + */ +#ifndef __powerpc__ +#define THIS_CPU Private +#define CHECK_THIS_CPU do {} while (0) +#else +#define THIS_CPU Processor[cpu] +#define CHECK_THIS_CPU check_arg_cpu(cpu) +#endif + +#if 1 +#define check_arg_ipi(ipi) \ + if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ + printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi); +#define check_arg_timer(timer) \ + if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ + printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer); +#define check_arg_vec(vec) \ + if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ + printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec); +#define check_arg_pri(pri) \ + if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ + printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri); +#define check_arg_irq(irq) \ + if (irq < 0 || irq >= (NumSources+open_pic.irq_offset)) \ + printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq); +#define check_arg_cpu(cpu) \ + if (cpu < 0 || cpu >= NumProcessors) \ + printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu); +#else +#define check_arg_ipi(ipi) do {} while (0) +#define check_arg_timer(timer) do {} while (0) +#define check_arg_vec(vec) do {} while (0) +#define check_arg_pri(pri) do {} while (0) +#define check_arg_irq(irq) do {} while (0) +#define check_arg_cpu(cpu) do {} while (0) +#endif + +static void no_action(int ir1, void *dev, struct pt_regs *regs) +{ +} #ifdef __SMP__ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) @@ -14,35 +90,349 @@ } #endif /* __SMP__ */ -void chrp_mask_and_ack_irq(unsigned int irq_nr) +#ifdef __i386__ +static inline u_int ld_le32(volatile u_int *addr) { - if (is_8259_irq(irq_nr)) - i8259_pic.mask_and_ack(irq_nr); + return *addr; } -static void chrp_mask_irq(unsigned int irq_nr) +static inline void out_le32(volatile u_int *addr, u_int val) { - if (is_8259_irq(irq_nr)) - i8259_pic.disable(irq_nr); - else - openpic_disable_irq(irq_to_openpic(irq_nr)); + *addr = val; +} +#endif + +u_int openpic_read(volatile u_int *addr) +{ + u_int val; + + val = ld_le32(addr); + return val; +} + +static inline void openpic_write(volatile u_int *addr, u_int val) +{ + out_le32(addr, val); +} + +static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) +{ + u_int val = openpic_read(addr); + return val & mask; +} + +inline void openpic_writefield(volatile u_int *addr, u_int mask, + u_int field) +{ + u_int val = openpic_read(addr); + openpic_write(addr, (val & ~mask) | (field & mask)); +} + +static inline void openpic_clearfield(volatile u_int *addr, u_int mask) +{ + openpic_writefield(addr, mask, 0); +} + +static inline void openpic_setfield(volatile u_int *addr, u_int mask) +{ + openpic_writefield(addr, mask, mask); +} + +static void openpic_safe_writefield(volatile u_int *addr, u_int mask, + u_int field) +{ + openpic_setfield(addr, OPENPIC_MASK); + /* wait until it's not in use */ + while (openpic_read(addr) & OPENPIC_ACTIVITY); + openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); } -static void chrp_unmask_irq(unsigned int irq_nr) +void __init openpic_init(int main_pic) { - if (is_8259_irq(irq_nr)) - i8259_pic.enable(irq_nr); + u_int t, i; + u_int timerfreq; + const char *version; + + if (!OpenPIC) + panic("No OpenPIC found"); + + if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122); + + t = openpic_read(&OpenPIC->Global.Feature_Reporting0); + switch (t & OPENPIC_FEATURE_VERSION_MASK) { + case 1: + version = "1.0"; + break; + case 2: + version = "1.2"; + break; + case 3: + version = "1.3"; + break; + default: + 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); + timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); + printk("OpenPIC timer frequency is "); + if (timerfreq) + printk("%d Hz\n", timerfreq); else - openpic_enable_irq(irq_to_openpic(irq_nr)); + printk("not set\n"); + + if ( main_pic ) + { + /* Initialize timer interrupts */ + if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba); + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + /* Disabled, Priority 0 */ + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); + /* No processor */ + openpic_maptimer(i, 0); + } + + /* Initialize IPI interrupts */ + if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb); + for (i = 0; i < OPENPIC_NUM_IPI; i++) { + /* Disabled, Priority 0 */ + openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); + } + + /* Initialize external interrupts */ + if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc); + /* SIOint (8259 cascade) is special */ + openpic_initirq(0, 8, open_pic.irq_offset, 1, 1); + openpic_mapirq(0, 1<<0); + for (i = 1; i < NumSources; i++) { + /* Enabled, Priority 8 */ + openpic_initirq(i, 8, open_pic.irq_offset+i, 0, + i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); + /* Processor 0 */ + openpic_mapirq(i, 1<<0); + } + + /* Initialize the spurious interrupt */ + if ( ppc_md.progress ) ppc_md.progress("openpic spurious",0x3bd); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); + if ( _machine != _MACH_gemini ) + { + if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, + "82c59 cascade", NULL)) + printk("Unable to get OpenPIC IRQ 0 for cascade\n"); + } + openpic_set_priority(0, 0); + openpic_disable_8259_pass_through(); + } + if ( ppc_md.progress ) ppc_md.progress("openpic exit",0x222); } -struct hw_interrupt_type open_pic = { - " OpenPIC ", - NULL, - NULL, - NULL, - chrp_unmask_irq, - chrp_mask_irq, - chrp_mask_and_ack_irq, - 0 -}; +void openpic_reset(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET); +} + +void openpic_enable_8259_pass_through(void) +{ + openpic_clearfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + +void openpic_disable_8259_pass_through(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + +#ifndef __i386__ +/* + * Find out the current interrupt + */ +u_int openpic_irq(u_int cpu) +{ + u_int vec; + + check_arg_cpu(cpu); + vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, + OPENPIC_VECTOR_MASK); + return vec; +} +#endif + +#ifndef __powerpc__ +void openpic_eoi(void) +#else +void openpic_eoi(u_int cpu) +#endif +{ + check_arg_cpu(cpu); + openpic_write(&OpenPIC->THIS_CPU.EOI, 0); +} + + +#ifndef __powerpc__ +u_int openpic_get_priority(void) +#else +u_int openpic_get_priority(u_int cpu) +#endif +{ + CHECK_THIS_CPU; + return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK); +} + +#ifndef __powerpc__ +void openpic_set_priority(u_int pri) +#else +void openpic_set_priority(u_int cpu, u_int pri) +#endif +{ + CHECK_THIS_CPU; + check_arg_pri(pri); + openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); +} + +/* + * Get/set the spurious vector + */ +u_int openpic_get_spurious(void) +{ + return openpic_readfield(&OpenPIC->Global.Spurious_Vector, + OPENPIC_VECTOR_MASK); +} + +void openpic_set_spurious(u_int vec) +{ + check_arg_vec(vec); + openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, + vec); +} + +void openpic_init_processor(u_int cpumask) +{ + openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask); +} + +/* + * Initialize an interprocessor interrupt (and disable it) + * + * ipi: OpenPIC interprocessor interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + */ +void openpic_initipi(u_int ipi, u_int pri, u_int vec) +{ + check_arg_timer(ipi); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi), + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + +/* + * Send an IPI to one or more CPUs + */ +#ifndef __powerpc__ +void openpic_cause_IPI(u_int ipi, u_int cpumask) +#else +void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask) +#endif +{ + CHECK_THIS_CPU; + check_arg_ipi(ipi); + openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask); +} + +/* + * Initialize a timer interrupt (and disable it) + * + * timer: OpenPIC timer number + * pri: interrupt source priority + * vec: the vector it will produce + */ +void openpic_inittimer(u_int timer, u_int pri, u_int vec) +{ + check_arg_timer(timer); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + +/* + * Map a timer interrupt to one or more CPUs + */ +void openpic_maptimer(u_int timer, u_int cpumask) +{ + check_arg_timer(timer); + openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask); +} + +/* + * Enable/disable an interrupt source + */ +void openpic_enable_irq(u_int irq) +{ + check_arg_irq(irq); + openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); +} + +void openpic_disable_irq(u_int irq) +{ + check_arg_irq(irq); + openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); +} + +/* + * Initialize an interrupt source (and disable it!) + * + * irq: OpenPIC interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + * pol: polarity (1 for positive, 0 for negative) + * sense: 1 for level, 0 for edge + */ +void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) +{ + check_arg_irq(irq); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | + OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL, + (pri << OPENPIC_PRIORITY_SHIFT) | vec | + (pol ? OPENPIC_SENSE_POLARITY : 0) | + (sense ? OPENPIC_SENSE_LEVEL : 0)); +} + +/* + * Map an interrupt source to one or more CPUs + */ +void openpic_mapirq(u_int irq, u_int cpumask) +{ + check_arg_irq(irq); + openpic_write(&OpenPIC->Source[irq].Destination, cpumask); +} + +/* + * Set the sense for an interrupt source (and disable it!) + * + * sense: 1 for level, 0 for edge + */ +void openpic_set_sense(u_int irq, int sense) +{ + check_arg_irq(irq); + openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_SENSE_LEVEL, + (sense ? OPENPIC_SENSE_LEVEL : 0)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h --- v2.3.15/linux/arch/ppc/kernel/open_pic.h Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/open_pic.h Tue Aug 31 11:36:43 1999 @@ -1,8 +1,5 @@ - #ifndef _PPC_KERNEL_OPEN_PIC_H #define _PPC_KERNEL_OPEN_PIC_H - -#include "local_irq.h" extern struct hw_interrupt_type open_pic; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c --- v2.3.15/linux/arch/ppc/kernel/openpic.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/kernel/openpic.c Wed Dec 31 16:00:00 1969 @@ -1,520 +0,0 @@ -/* - * arch/ppc/kernel/openpic.c -- OpenPIC Interrupt Handling - * - * Copyright (C) 1997 Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - - -/* - * Note: Interprocessor Interrupt (IPI) and Timer support is incomplete - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define REGISTER_DEBUG -#undef REGISTER_DEBUG - - -volatile struct OpenPIC *OpenPIC = NULL; -u_int OpenPIC_NumInitSenses __initdata = 0; -u_char *OpenPIC_InitSenses __initdata = NULL; - -static u_int NumProcessors; -static u_int NumSources; - - - /* - * Accesses to the current processor's registers - */ - -#ifndef __powerpc__ -#define THIS_CPU Private -#define CHECK_THIS_CPU do {} while (0) -#else -#define THIS_CPU Processor[cpu] -#define CHECK_THIS_CPU check_arg_cpu(cpu) -#endif - - - /* - * Sanity checks - */ - -#if 1 -#define check_arg_ipi(ipi) \ - if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ - printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi); -#define check_arg_timer(timer) \ - if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ - printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer); -#define check_arg_vec(vec) \ - if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ - printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec); -#define check_arg_pri(pri) \ - if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ - printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri); -#define check_arg_irq(irq) \ - if (irq < 0 || irq >= NumSources) \ - printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq); -#define check_arg_cpu(cpu) \ - if (cpu < 0 || cpu >= NumProcessors) \ - printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu); -#else -#define check_arg_ipi(ipi) do {} while (0) -#define check_arg_timer(timer) do {} while (0) -#define check_arg_vec(vec) do {} while (0) -#define check_arg_pri(pri) do {} while (0) -#define check_arg_irq(irq) do {} while (0) -#define check_arg_cpu(cpu) do {} while (0) -#endif - - - /* - * Dummy interrupt handler - */ - -static void no_action(int ir1, void *dev, struct pt_regs *regs) -{} - - - /* - * I/O functions - */ - -#ifdef __i386__ -static inline u_int ld_le32(volatile u_int *addr) -{ - return *addr; -} - -static inline void out_le32(volatile u_int *addr, u_int val) -{ - *addr = val; -} -#endif - -u_int openpic_read(volatile u_int *addr) -{ - u_int val; - - val = ld_le32(addr); -#ifdef REGISTER_DEBUG - printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val); -#endif - return val; -} - -static inline void openpic_write(volatile u_int *addr, u_int val) -{ -#ifdef REGISTER_DEBUG - printk("openpic_write(0x%08x, 0x%08x)\n", (u_int)addr, val); -#endif - out_le32(addr, val); -} - - -static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) -{ - u_int val = openpic_read(addr); - return val & mask; -} - -inline void openpic_writefield(volatile u_int *addr, u_int mask, - u_int field) -{ - u_int val = openpic_read(addr); - openpic_write(addr, (val & ~mask) | (field & mask)); -} - -static inline void openpic_clearfield(volatile u_int *addr, u_int mask) -{ - openpic_writefield(addr, mask, 0); -} - -static inline void openpic_setfield(volatile u_int *addr, u_int mask) -{ - openpic_writefield(addr, mask, mask); -} - - - /* - * Update a Vector/Priority register in a safe manner. The interrupt will - * be disabled. - */ - -static void openpic_safe_writefield(volatile u_int *addr, u_int mask, - u_int field) -{ - openpic_setfield(addr, OPENPIC_MASK); - /* wait until it's not in use */ - while (openpic_read(addr) & OPENPIC_ACTIVITY); - openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); -} - - -/* -------- Global Operations ---------------------------------------------- */ - - - /* - * Initialize the OpenPIC - */ - -__initfunc(void openpic_init(int main_pic)) -{ - u_int t, i; - u_int timerfreq; - const char *version; - - if (!OpenPIC) - panic("No OpenPIC found"); - - if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122); - - t = openpic_read(&OpenPIC->Global.Feature_Reporting0); - switch (t & OPENPIC_FEATURE_VERSION_MASK) { - case 1: - version = "1.0"; - break; - case 2: - version = "1.2"; - break; - case 3: - version = "1.3"; - break; - default: - 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); - timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); - printk("OpenPIC timer frequency is "); - if (timerfreq) - printk("%d Hz\n", timerfreq); - else - printk("not set\n"); - - if ( main_pic ) - { - if ( ppc_md.progress ) ppc_md.progress("openpic main",0x3ff); - - /* Initialize timer interrupts */ - for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { - /* Disabled, Priority 0 */ - openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); - /* No processor */ - openpic_maptimer(i, 0); - } - - /* Initialize IPI interrupts */ - for (i = 0; i < OPENPIC_NUM_IPI; i++) { - /* Disabled, Priority 0 */ - openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); - } - - if ( ppc_md.progress ) ppc_md.progress("openpic initirq",0x3bb); - /* Initialize external interrupts */ - /* SIOint (8259 cascade) is special */ - openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1); - - if ( ppc_md.progress ) ppc_md.progress("openpic map",0x3cc); - /* Processor 0 */ - openpic_mapirq(0, 1<<0); - for (i = 1; i < NumSources; i++) { - /* Enabled, Priority 8 */ - 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(OPENPIC_VEC_SPURIOUS); - - if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, - "82c59 cascade", NULL)) - printk("Unable to get OpenPIC IRQ 0 for cascade\n"); - openpic_set_priority(0, 0); - openpic_disable_8259_pass_through(); - } - if ( ppc_md.progress ) ppc_md.progress("openpic exit",0x222); -} - - - /* - * Reset the OpenPIC - */ - -void openpic_reset(void) -{ - openpic_setfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_RESET); -} - - - /* - * Enable/disable 8259 Pass Through Mode - */ - -void openpic_enable_8259_pass_through(void) -{ - openpic_clearfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); -} - -void openpic_disable_8259_pass_through(void) -{ - openpic_setfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); -} - - -#ifndef __i386__ - /* - * Find out the current interrupt - */ - -u_int openpic_irq(u_int cpu) -{ - u_int vec; - - check_arg_cpu(cpu); - vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, - OPENPIC_VECTOR_MASK); -#if 0 -if (vec != 22 /* SCSI */) -printk("++openpic_irq: %d\n", vec); -#endif - return vec; -} -#endif - - - /* - * Signal end of interrupt (EOI) processing - */ - -#ifndef __powerpc__ -void openpic_eoi(void) -#else -void openpic_eoi(u_int cpu) -#endif -{ - check_arg_cpu(cpu); - openpic_write(&OpenPIC->THIS_CPU.EOI, 0); -} - - - /* - * Get/set the current task priority - */ - -#ifndef __powerpc__ -u_int openpic_get_priority(void) -#else -u_int openpic_get_priority(u_int cpu) -#endif -{ - CHECK_THIS_CPU; - return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, - OPENPIC_CURRENT_TASK_PRIORITY_MASK); -} - -#ifndef __powerpc__ -void openpic_set_priority(u_int pri) -#else -void openpic_set_priority(u_int cpu, u_int pri) -#endif -{ - CHECK_THIS_CPU; - check_arg_pri(pri); - openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, - OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); -} - - /* - * Get/set the spurious vector - */ - -u_int openpic_get_spurious(void) -{ - return openpic_readfield(&OpenPIC->Global.Spurious_Vector, - OPENPIC_VECTOR_MASK); -} - -void openpic_set_spurious(u_int vec) -{ - check_arg_vec(vec); - openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, - vec); -} - - - /* - * Initialize one or more CPUs - */ - -void openpic_init_processor(u_int cpumask) -{ - openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask); -} - - -/* -------- Interprocessor Interrupts -------------------------------------- */ - - - /* - * Initialize an interprocessor interrupt (and disable it) - * - * ipi: OpenPIC interprocessor interrupt number - * pri: interrupt source priority - * vec: the vector it will produce - */ - -void openpic_initipi(u_int ipi, u_int pri, u_int vec) -{ - check_arg_timer(ipi); - check_arg_pri(pri); - check_arg_vec(vec); - openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi), - OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, - (pri << OPENPIC_PRIORITY_SHIFT) | vec); -} - - - /* - * Send an IPI to one or more CPUs - */ - -#ifndef __powerpc__ -void openpic_cause_IPI(u_int ipi, u_int cpumask) -#else -void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask) -#endif -{ - CHECK_THIS_CPU; - check_arg_ipi(ipi); - openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask); -} - - -/* -------- Timer Interrupts ----------------------------------------------- */ - - - /* - * Initialize a timer interrupt (and disable it) - * - * timer: OpenPIC timer number - * pri: interrupt source priority - * vec: the vector it will produce - */ - -void openpic_inittimer(u_int timer, u_int pri, u_int vec) -{ - check_arg_timer(timer); - check_arg_pri(pri); - check_arg_vec(vec); - openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, - OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, - (pri << OPENPIC_PRIORITY_SHIFT) | vec); -} - - - /* - * Map a timer interrupt to one or more CPUs - */ - -void openpic_maptimer(u_int timer, u_int cpumask) -{ - check_arg_timer(timer); - openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask); -} - - -/* -------- Interrupt Sources ---------------------------------------------- */ - - - /* - * Enable/disable an interrupt source - */ - -void openpic_enable_irq(u_int irq) -{ - check_arg_irq(irq); - openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); -} - -void openpic_disable_irq(u_int irq) -{ - check_arg_irq(irq); - openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); -} - - - /* - * Initialize an interrupt source (and disable it!) - * - * irq: OpenPIC interrupt number - * pri: interrupt source priority - * vec: the vector it will produce - * pol: polarity (1 for positive, 0 for negative) - * sense: 1 for level, 0 for edge - */ - -void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) -{ - check_arg_irq(irq); - check_arg_pri(pri); - check_arg_vec(vec); - openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | - OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL, - (pri << OPENPIC_PRIORITY_SHIFT) | vec | - (pol ? OPENPIC_SENSE_POLARITY : 0) | - (sense ? OPENPIC_SENSE_LEVEL : 0)); -} - - - /* - * Map an interrupt source to one or more CPUs - */ - -void openpic_mapirq(u_int irq, u_int cpumask) -{ - check_arg_irq(irq); - openpic_write(&OpenPIC->Source[irq].Destination, cpumask); -} - - - /* - * Set the sense for an interrupt source (and disable it!) - * - * sense: 1 for level, 0 for edge - */ - -void openpic_set_sense(u_int irq, int sense) -{ - check_arg_irq(irq); - openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_SENSE_LEVEL, - (sense ? OPENPIC_SENSE_LEVEL : 0)); -} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.3.15/linux/arch/ppc/kernel/pci.c Tue Jul 13 02:29:35 1999 +++ linux/arch/ppc/kernel/pci.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $ + * $Id: pci.c,v 1.56 1999/08/31 15:42:37 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -26,46 +26,51 @@ unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; -int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val) +struct pci_fixup pcibios_fixups[] = { + { 0 } +}; + +int generic_pcibios_read_byte(struct pci_dev *dev, int where, u8 *val) { - return ppc_md.pcibios_read_config_byte(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_byte(dev->bus->number,dev->devfn,where,val); } -int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val) +int generic_pcibios_read_word(struct pci_dev *dev, int where, u16 *val) { - return ppc_md.pcibios_read_config_word(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_word(dev->bus->number,dev->devfn,where,val); } -int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val) +int generic_pcibios_read_dword(struct pci_dev *dev, int where, u32 *val) { - return ppc_md.pcibios_read_config_dword(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_dword(dev->bus->number,dev->devfn,where,val); } -int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val) +int generic_pcibios_write_byte(struct pci_dev *dev, int where, u8 val) { - return ppc_md.pcibios_write_config_byte(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_byte(dev->bus->number,dev->devfn,where,val); } -int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val) +int generic_pcibios_write_word(struct pci_dev *dev, int where, u16 val) { - return ppc_md.pcibios_write_config_word(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_word(dev->bus->number,dev->devfn,where,val); } -int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val) +int generic_pcibios_write_dword(struct pci_dev *dev, int where, u32 val) { - return ppc_md.pcibios_write_config_dword(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_dword(dev->bus->number,dev->devfn,where,val); } -int pcibios_present(void) +struct pci_ops generic_pci_ops = { - return 1; -} + generic_pcibios_read_byte, + generic_pcibios_read_word, + generic_pcibios_read_dword, + generic_pcibios_write_byte, + generic_pcibios_write_word, + generic_pcibios_write_dword +}; void __init pcibios_init(void) { + printk("PCI: Probing PCI hardware\n"); + pci_scan_bus(0, &generic_pci_ops, NULL); + } - void __init pcibios_fixup(void) { diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/pci.h linux/arch/ppc/kernel/pci.h --- v2.3.15/linux/arch/ppc/kernel/pci.h Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/pci.h Tue Aug 31 11:36:43 1999 @@ -11,6 +11,18 @@ void fix_intr(struct device_node *node, struct pci_dev *dev); +#if 0 +#define decl_config_access_method(name) \ +struct pci_ops name##_pci_ops = { \ + name##_pcibios_read_config_byte, \ + name##_pcibios_read_config_word, \ + name##_pcibios_read_config_dword, \ + name##_pcibios_write_config_byte, \ + name##_pcibios_write_config_word, \ + name##_pcibios_write_config_dword \ +} +#endif + #define decl_config_access_method(name) \ extern int name##_pcibios_read_config_byte(unsigned char bus, \ unsigned char dev_fn, unsigned char offset, unsigned char *val); \ diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.3.15/linux/arch/ppc/kernel/pmac_pci.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/pmac_pci.c Tue Aug 31 11:36:43 1999 @@ -17,6 +17,8 @@ #include #include #include + +#include #include #include #include @@ -315,7 +317,7 @@ * N.B. we can't use pcibios_*_config_* here because bridges[] * is not initialized yet. */ -__initfunc(static void init_bandit(struct bridge_data *bp)) +static void __init init_bandit(struct bridge_data *bp) { unsigned int vendev, magic; int rev; @@ -360,7 +362,7 @@ bp->io_base); } -__initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)) +unsigned long __init pmac_find_bridges(unsigned long mem_start, unsigned long mem_end) { int bus; struct bridge_data *bridge; @@ -385,7 +387,7 @@ * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, * if we have one or more bandit or chaos bridges, we don't have a MPC106. */ -__initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)) +static void __init add_bridges(struct device_node *dev, unsigned long *mem_ptr) { int *bus_range; int len; @@ -442,9 +444,8 @@ } } -__initfunc( -void -pmac_pcibios_fixup(void)) +void __init +pmac_pcibios_fixup(void) { struct pci_dev *dev; @@ -472,9 +473,8 @@ } } -__initfunc( -void -pmac_setup_pci_ptrs(void)) +void __init +pmac_setup_pci_ptrs(void) { if (find_devices("pci") != 0) { /* looks like a G3 powermac */ diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.3.15/linux/arch/ppc/kernel/pmac_pic.c Wed May 12 08:50:00 1999 +++ linux/arch/ppc/kernel/pmac_pic.c Tue Aug 31 11:36:43 1999 @@ -3,6 +3,8 @@ #include #include #include + +#include #include #include #include @@ -290,8 +292,8 @@ } } -__initfunc(void -pmac_pic_init(void)) +void __init +pmac_pic_init(void) { int i; struct device_node *irqctrler; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.3.15/linux/arch/ppc/kernel/pmac_setup.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/kernel/pmac_setup.c Tue Aug 31 11:36:43 1999 @@ -43,6 +43,8 @@ #include #include #include + +#include #include #include #include @@ -227,8 +229,8 @@ static volatile u32 *sysctrl_regs; -__initfunc(void -pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) +void __init +pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p) { struct device_node *cpu; int *fp; @@ -308,7 +310,7 @@ /* * Tweak the PCI-PCI bridge chip on the blue & white G3s. */ -__initfunc(static void init_p2pbridge(void)) +static void __init init_p2pbridge(void) { struct device_node *p2pbridge; unsigned char bus, devfn; @@ -330,7 +332,7 @@ pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); } -__initfunc(static void ohare_init(void)) +static void __init ohare_init(void) { /* * Turn on the L2 cache. @@ -355,8 +357,8 @@ int boot_part; kdev_t boot_dev; -__initfunc(void -pmac_init2(void)) +void __init +pmac_init2(void) { adb_init(); pmac_nvram_init(); @@ -364,8 +366,8 @@ } #ifdef CONFIG_SCSI -__initfunc(void -note_scsi_host(struct device_node *node, void *host)) +void __init +note_scsi_host(struct device_node *node, void *host) { int l; char *p; @@ -399,7 +401,7 @@ extern struct device_node *pmac_ide_node[]; static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89 }; -__initfunc(kdev_t find_ide_boot(void)) +kdev_t __init find_ide_boot(void) { char *p; int i, n; @@ -426,7 +428,7 @@ } #endif /* CONFIG_BLK_DEV_IDE_PMAC */ -__initfunc(void find_boot_device(void)) +void __init find_boot_device(void) { #ifdef CONFIG_SCSI if (boot_host != NULL) { @@ -440,7 +442,7 @@ #endif } -/* can't be initfunc - can be called whenever a disk is first accessed */ +/* can't be __init - can be called whenever a disk is first accessed */ __pmac void note_bootable_part(kdev_t dev, int part) { @@ -589,9 +591,9 @@ #endif #endif -__initfunc(void +void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { pmac_setup_pci_ptrs(); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c --- v2.3.15/linux/arch/ppc/kernel/pmac_support.c Wed Aug 4 16:36:41 1999 +++ linux/arch/ppc/kernel/pmac_support.c Tue Aug 31 11:36:43 1999 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.3.15/linux/arch/ppc/kernel/pmac_time.c Tue Aug 4 23:57:51 1998 +++ linux/arch/ppc/kernel/pmac_time.c Tue Aug 31 11:36:43 1999 @@ -15,6 +15,8 @@ #include #include #include + +#include #include #include #include @@ -91,7 +93,7 @@ * Calibrate the decrementer register using VIA timer 1. * This is used both on powermacs and CHRP machines. */ -__initfunc(int via_calibrate_decr(void)) +int __init via_calibrate_decr(void) { struct device_node *vias; volatile unsigned char *via; @@ -168,7 +170,7 @@ * This was taken from the pmac time_init() when merging the prep/pmac * time functions. */ -__initfunc(void pmac_calibrate_decr(void)) +void __init pmac_calibrate_decr(void) { struct device_node *cpu; int freq, *fp, divisor; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c --- v2.3.15/linux/arch/ppc/kernel/ppc-stub.c Tue Jul 13 02:29:35 1999 +++ linux/arch/ppc/kernel/ppc-stub.c Tue Aug 31 11:36:43 1999 @@ -1,4 +1,4 @@ -/* $Id: ppc-stub.c,v 1.4 1998/07/28 08:25:01 paulus Exp $ +/* $Id: ppc-stub.c,v 1.6 1999/08/12 22:18:11 cort Exp $ * ppc-stub.c: KGDB support for the Linux kernel. * * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC @@ -438,13 +438,13 @@ { 0x400, SIGBUS }, /* instruction bus error */ { 0x500, SIGINT }, /* interrupt */ { 0x600, SIGBUS }, /* alingment */ - { 0x700, SIGILL }, /* reserved instruction or sumpin' */ + { 0x700, SIGTRAP }, /* breakpoint trap */ { 0x800, SIGFPE }, /* fpu unavail */ { 0x900, SIGALRM }, /* decrementer */ { 0xa00, SIGILL }, /* reserved */ { 0xb00, SIGILL }, /* reserved */ { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGINT }, /* watch */ + { 0xd00, SIGTRAP }, /* single-step/watch */ { 0xe00, SIGFPE }, /* fp assist */ { 0, 0} /* Must be last */ }; @@ -482,8 +482,10 @@ } kgdb_active = 1; +#ifdef KGDB_DEBUG printk("kgdb: entering handle_exception; trap [0x%x]\n", (unsigned int)regs->trap); +#endif kgdb_interruptible(0); lock_kernel(); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/ppc_asm.h linux/arch/ppc/kernel/ppc_asm.h --- v2.3.15/linux/arch/ppc/kernel/ppc_asm.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/ppc_asm.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,73 @@ +/* + * arch/ppc/kernel/ppc_asm.h + * + * Definitions used by various bits of low-level assembly code on PowerPC. + * + * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. + * + * 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 "ppc_asm.tmpl" +#include "ppc_defs.h" + +/* + * 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,THREAD_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,THREAD_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 + +/* This instruction is not implemented on the PPC 603 or 601 */ +#define tlbia \ + li r4,128; \ + mtctr r4; \ + lis r4,KERNELBASE@h; \ +0: tlbie r4; \ + addi r4,r4,0x1000; \ + bdnz 0b + +/* + * On APUS (Amiga PowerPC cpu upgrade board), we don't know the + * physical base address of RAM at compile time. + */ +#define tophys(rd,rs) \ +0: addis rd,rs,-KERNELBASE@h; \ + .section ".vtop_fixup","aw"; \ + .align 1; \ + .long 0b; \ + .previous + +#define tovirt(rd,rs) \ +0: addis rd,rs,KERNELBASE@h; \ + .section ".ptov_fixup","aw"; \ + .align 1; \ + .long 0b; \ + .previous diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.3.15/linux/arch/ppc/kernel/ppc_ksyms.c Mon Aug 9 11:39:37 1999 +++ linux/arch/ppc/kernel/ppc_ksyms.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -35,7 +36,6 @@ #define EXPORT_SYMTAB_STROPS extern void transfer_to_handler(void); -extern void int_return(void); extern void syscall_trace(void); extern void do_IRQ(struct pt_regs *regs, int isfake); extern void MachineCheckException(struct pt_regs *regs); @@ -53,7 +53,6 @@ EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(syscall_trace); EXPORT_SYMBOL(transfer_to_handler); -EXPORT_SYMBOL(int_return); EXPORT_SYMBOL(do_IRQ); EXPORT_SYMBOL(init_task_union); EXPORT_SYMBOL(MachineCheckException); @@ -153,11 +152,9 @@ EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(__cli); -EXPORT_SYMBOL(__sti); /*EXPORT_SYMBOL(__restore_flags);*/ -EXPORT_SYMBOL(_disable_interrupts); -EXPORT_SYMBOL(_enable_interrupts); +/*EXPORT_SYMBOL(_disable_interrupts); + EXPORT_SYMBOL(_enable_interrupts);*/ EXPORT_SYMBOL(flush_instruction_cache); EXPORT_SYMBOL(_get_PVR); EXPORT_SYMBOL(giveup_fpu); @@ -189,6 +186,7 @@ EXPORT_SYMBOL(pmu_poll); #ifdef CONFIG_PMAC_PBOOK EXPORT_SYMBOL(sleep_notifier_list); +EXPORT_SYMBOL(pmu_enable_irled); #endif CONFIG_PMAC_PBOOK EXPORT_SYMBOL(abort); EXPORT_SYMBOL(find_devices); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/prep_nvram.c linux/arch/ppc/kernel/prep_nvram.c --- v2.3.15/linux/arch/ppc/kernel/prep_nvram.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/prep_nvram.c Tue Aug 31 11:36:43 1999 @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -57,7 +58,7 @@ rs_pcNvRAM[addr]=val; } -__initfunc(void init_prep_nvram(void)) +void __init init_prep_nvram(void) { unsigned char *nvp; int i; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.3.15/linux/arch/ppc/kernel/prep_pci.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/kernel/prep_pci.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: prep_pci.c,v 1.35 1999/05/10 23:31:03 cort Exp $ + * $Id: prep_pci.c,v 1.39 1999/08/31 15:42:39 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -685,7 +686,7 @@ int prep_keybd_present = 1; int MotMPIC = 0; -__initfunc(int raven_init(void)) +int __init raven_init(void) { unsigned int devid; unsigned int pci_membase; @@ -788,7 +789,7 @@ {0x000, 0x00, 0x00, "", NULL, NULL} }; -__initfunc(unsigned long prep_route_pci_interrupts(void)) +unsigned long __init prep_route_pci_interrupts(void) { unsigned char *ibc_pirq = (unsigned char *)0x80800860; unsigned char *ibc_pcicon = (unsigned char *)0x80800840; @@ -976,9 +977,8 @@ return 0; } -__initfunc( -void -prep_pcibios_fixup(void)) +void __init +prep_pcibios_fixup(void) { struct pci_dev *dev; extern unsigned char *Motherboard_map; @@ -1017,17 +1017,17 @@ for ( i = 0 ; i <= 5 ; i++ ) { - if ( dev->base_address[i] > 0x10000000 ) + if ( dev->resource[i].start > 0x10000000 ) { printk("Relocating PCI address %lx -> %lx\n", - dev->base_address[i], - (dev->base_address[i] & 0x00FFFFFF) + dev->resource[i].start, + (dev->resource[i].start & 0x00FFFFFF) | 0x01000000); - dev->base_address[i] = - (dev->base_address[i] & 0x00FFFFFF) | 0x01000000; + dev->resource[i].start = + (dev->resource[i].start & 0x00FFFFFF) | 0x01000000; pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+(i*0x4), - dev->base_address[i] ); + dev->resource[i].start ); } } #if 0 @@ -1044,9 +1044,8 @@ decl_config_access_method(indirect); -__initfunc( -void -prep_setup_pci_ptrs(void)) +void __init +prep_setup_pci_ptrs(void) { PPC_DEVICE *hostbridge; @@ -1055,7 +1054,7 @@ { pci_config_address = (unsigned *)0x80000cf8; pci_config_data = (char *)0x80000cfc; - set_config_access_method(indirect); + set_config_access_method(indirect); } else { diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.3.15/linux/arch/ppc/kernel/prep_setup.c Tue Jul 13 02:29:35 1999 +++ linux/arch/ppc/kernel/prep_setup.c Tue Aug 31 11:36:43 1999 @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -211,8 +212,8 @@ return len; } -__initfunc(void -prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init +prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { extern char cmd_line[]; unsigned char reg; @@ -365,7 +366,7 @@ * This allows for a faster boot as we do not need to calibrate the * decrementer against another clock. This is important for embedded systems. */ -__initfunc(void prep_res_calibrate_decr(void)) +void __init prep_res_calibrate_decr(void) { int freq, divisor; @@ -386,10 +387,10 @@ int calibrate_done = 0; volatile int *done_ptr = &calibrate_done; -__initfunc(void +void __init prep_calibrate_decr_handler(int irq, void *dev, - struct pt_regs *regs)) + struct pt_regs *regs) { unsigned long freq, divisor; static unsigned long t1 = 0, t2 = 0; @@ -412,7 +413,7 @@ } } -__initfunc(void prep_calibrate_decr(void)) +void __init prep_calibrate_decr(void) { unsigned long flags; @@ -437,7 +438,7 @@ /* We use the NVRAM RTC to time a second to calibrate the decrementer. */ -__initfunc(void mk48t59_calibrate_decr(void)) +void __init mk48t59_calibrate_decr(void) { unsigned long freq, divisor; unsigned long t1, t2; @@ -491,7 +492,7 @@ unsigned long i = 10000; - _disable_interrupts(); + __cli(); /* set exception prefix high - to the prom */ _nmask_and_or_msr(0, MSR_IP); @@ -518,7 +519,7 @@ * This will ALWAYS work regardless of port 92 * functionality */ - _disable_interrupts(); + __cli(); __asm__ __volatile__("\n\ mtspr 26, %1 /* SRR0 */ @@ -535,7 +536,7 @@ prep_halt(void) { unsigned long flags; - _disable_interrupts(); + __cli(); /* set exception prefix high - to the prom */ save_flags( flags ); restore_flags( flags|MSR_IP ); @@ -603,8 +604,8 @@ ppc_irq_dispatch_handler( regs, irq ); } -__initfunc(void -prep_init_IRQ(void)) +void __init +prep_init_IRQ(void) { int i; @@ -691,8 +692,8 @@ { } -__initfunc(void -prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)) +void __init +prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { ide_ioreg_t reg = data_port; int i; @@ -711,9 +712,9 @@ } #endif -__initfunc(void +void __init prep_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { /* make a copy of residual data */ if ( r3 ) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c --- v2.3.15/linux/arch/ppc/kernel/prep_time.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/prep_time.c Tue Aug 31 11:36:43 1999 @@ -19,6 +19,7 @@ #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.3.15/linux/arch/ppc/kernel/process.c Mon Jul 26 22:41:09 1999 +++ linux/arch/ppc/kernel/process.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: process.c,v 1.87 1999/07/03 08:57:07 davem Exp $ + * $Id: process.c,v 1.95 1999/08/31 06:54:07 davem Exp $ * * linux/arch/ppc/kernel/process.c * @@ -50,7 +50,10 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); -union task_union init_task_union = { INIT_TASK(init_task_union.task) }; +/* this is 16-byte aligned because it has a stack in it */ +union task_union __attribute((aligned(16))) init_task_union = { + INIT_TASK(init_task_union.task) +}; /* only used to get secondary processor up */ struct task_struct *current_set[NR_CPUS] = {&init_task, }; @@ -74,7 +77,7 @@ { if (regs->msr & MSR_FP) giveup_fpu(current); - memcpy(fpregs, ¤t->tss.fpr[0], sizeof(*fpregs)); + memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); return 1; } @@ -82,7 +85,7 @@ enable_kernel_fp(void) { #ifdef __SMP__ - if (current->tss.regs && (current->tss.regs->msr & MSR_FP)) + if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) giveup_fpu(current); else giveup_fpu(NULL); /* just enables FP for kernel */ @@ -99,11 +102,11 @@ int ret = 0; #if 0 - /* check tss magic */ - if ( tsk->tss.magic != TSS_MAGIC ) + /* check thread magic */ + if ( tsk->thread.magic != THREAD_MAGIC ) { ret |= 1; - printk("tss.magic bad: %08x\n", tsk->tss.magic); + printk("thread.magic bad: %08x\n", tsk->thread.magic); } #endif @@ -111,12 +114,12 @@ printk("check_stack(): tsk bad tsk %p\n",tsk); /* check if stored ksp is bad */ - if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) ) + if ( (tsk->thread.ksp > stack_top) || (tsk->thread.ksp < tsk_top) ) { printk("stack out of bounds: %s/%d\n" " tsk_top %08lx ksp %08lx stack_top %08lx\n", tsk->comm,tsk->pid, - tsk_top, tsk->tss.ksp, stack_top); + tsk_top, tsk->thread.ksp, stack_top); ret |= 2; } @@ -158,8 +161,11 @@ _switch_to(struct task_struct *prev, struct task_struct *new, struct task_struct **last) { - struct thread_struct *new_tss, *old_tss; - int s = _disable_interrupts(); + struct thread_struct *new_thread, *old_thread; + int s; + + __save_flags(s); + __cli(); #if CHECK_STACK check_stack(prev); check_stack(new); @@ -168,7 +174,7 @@ #ifdef SHOW_TASK_SWITCHES printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n", prev->comm,prev->pid, - new->comm,new->pid,new->tss.regs->nip,new->processor, + new->comm,new->pid,new->thread.regs->nip,new->processor, new->fs->root,prev->fs->root); #endif #ifdef __SMP__ @@ -181,16 +187,16 @@ * every switch, just a save. * -- Cort */ - if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP)) + if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP)) giveup_fpu(prev); prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* __SMP__ */ - new_tss = &new->tss; - old_tss = ¤t->tss; - *last = _switch(old_tss, new_tss, new->mm->context); - _enable_interrupts(s); + new_thread = &new->thread; + old_thread = ¤t->thread; + *last = _switch(old_thread, new_thread); + __restore_flags(s); } void show_regs(struct pt_regs * regs) @@ -204,9 +210,9 @@ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, regs->msr&MSR_IR ? 1 : 0, regs->msr&MSR_DR ? 1 : 0); - 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("TASK = %p[%d] '%s' ", + current, current->pid, current->comm); + printk("Last syscall: %ld ", current->thread.last_syscall); printk("\nlast math %p", last_task_used_math); #ifdef __SMP__ @@ -271,10 +277,10 @@ if ((childregs->msr & MSR_PR) == 0) childregs->gpr[2] = (unsigned long) p; /* `current' in new task */ childregs->gpr[3] = 0; /* Result from fork() */ - p->tss.regs = childregs; - p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; - p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; - kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD); + p->thread.regs = childregs; + p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; + p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; + kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD); #ifdef __SMP__ kregs->nip = (unsigned long)ret_from_smpfork; #else @@ -291,7 +297,7 @@ /* Provided stack is in user space */ childregs->gpr[1] = usp; } - p->tss.last_syscall = -1; + p->thread.last_syscall = -1; /* * copy fpu info - assume lazy fpu switch now always @@ -300,11 +306,10 @@ if (regs->msr & MSR_FP) giveup_fpu(current); - memcpy(&p->tss.fpr, ¤t->tss.fpr, sizeof(p->tss.fpr)); - p->tss.fpscr = current->tss.fpscr; + memcpy(&p->thread.fpr, ¤t->thread.fpr, sizeof(p->thread.fpr)); + p->thread.fpscr = current->thread.fpscr; childregs->msr &= ~MSR_FP; - p->processor = 0; #ifdef __SMP__ p->last_processor = NO_PROC_ID; #endif /* __SMP__ */ @@ -362,7 +367,7 @@ shove_aux_table(sp); if (last_task_used_math == current) last_task_used_math = 0; - current->tss.fpscr = 0; + current->thread.fpscr = 0; } asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, @@ -453,7 +458,7 @@ /* * Low level print for debugging - Cort */ -__initfunc(int ll_printk(const char *fmt, ...)) +int __init ll_printk(const char *fmt, ...) { va_list args; char buf[256]; @@ -482,7 +487,7 @@ prom_print(buf); } -__initfunc(void ll_puts(const char *s)) +void __init ll_puts(const char *s) { int x,y; char *vidmem = (char *)/*(_ISA_MEM_BASE + 0xB8000) */0xD00B8000; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.3.15/linux/arch/ppc/kernel/prom.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/kernel/prom.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.62 1999/07/02 19:59:31 cort Exp $ + * $Id: prom.c,v 1.70 1999/08/25 21:26:08 cort Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -16,6 +16,8 @@ #include #include #include + +#include #include #include #include @@ -257,6 +259,9 @@ } } +unsigned long smp_ibm_chrp_hack __initdata = 0; +unsigned long smp_chrp_cpu_nr __initdata = 1; + /* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. @@ -266,7 +271,7 @@ prom_init(int r3, int r4, prom_entry pp) { #ifdef CONFIG_SMP - int cpu = 0, i; + int i; phandle node; char type[16], *path; #endif @@ -275,7 +280,7 @@ unsigned long offset = reloc_offset(); int l; char *p, *d; - + /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) return; @@ -524,17 +529,18 @@ node, path, 255) < 0) continue; /* XXX: hack - don't start cpu 0, this cpu -- Cort */ - if ( cpu++ == 0 ) + if ( smp_chrp_cpu_nr++ == 0 ) continue; + RELOC(smp_ibm_chrp_hack) = 1; prom_print(RELOC("starting cpu ")); prom_print(path); *(unsigned long *)(0x4) = 0; asm volatile("dcbf 0,%0": : "r" (0x4) : "memory"); - call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, cpu-1); + call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, smp_chrp_cpu_nr-1); for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == (ulong)0); i++ ) ; - if (*(ulong *)(0x4) == (ulong)cpu-1 ) + if (*(ulong *)(0x4) == (ulong)smp_chrp_cpu_nr-1 ) prom_print(RELOC("...ok\n")); else prom_print(RELOC("...failed\n")); @@ -1296,8 +1302,6 @@ } #endif -spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED; - /* this can be called after setup -- Cort */ __openfirmware int @@ -1328,12 +1332,12 @@ for (i = 0; i < nargs; ++i) u.words[i+3] = va_arg(list, unsigned long); va_end(list); + + save_flags(s); + cli(); - s = _disable_interrupts(); - spin_lock(&rtas_lock); enter_rtas((void *)__pa(&u)); - spin_unlock(&rtas_lock); - _enable_interrupts(s); + restore_flags(s); if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = u.words[i+nargs+4]; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.3.15/linux/arch/ppc/kernel/ptrace.c Mon Jul 12 15:12:55 1999 +++ linux/arch/ppc/kernel/ptrace.c Tue Aug 31 11:36:43 1999 @@ -47,7 +47,7 @@ static inline long get_reg(struct task_struct *task, int regno) { if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)) - return ((unsigned long *)task->tss.regs)[regno]; + return ((unsigned long *)task->thread.regs)[regno]; return (0); } @@ -60,8 +60,8 @@ 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; + | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); + ((unsigned long *)task->thread.regs)[regno] = data; return 0; } return -1; @@ -70,14 +70,14 @@ static inline void set_single_step(struct task_struct *task) { - struct pt_regs *regs = task->tss.regs; + struct pt_regs *regs = task->thread.regs; regs->msr |= MSR_SE; } static inline void clear_single_step(struct task_struct *task) { - struct pt_regs *regs = task->tss.regs; + struct pt_regs *regs = task->thread.regs; regs->msr &= ~MSR_SE; } @@ -384,9 +384,9 @@ tmp = get_reg(child, addr); } else if (addr >= PT_FPR0 && addr <= PT_FPSCR) { - if (child->tss.regs->msr & MSR_FP) + if (child->thread.regs->msr & MSR_FP) giveup_fpu(child); - tmp = ((long *)child->tss.fpr)[addr - PT_FPR0]; + tmp = ((long *)child->thread.fpr)[addr - PT_FPR0]; } else ret = -EIO; @@ -419,9 +419,9 @@ goto out; } if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) { - if (child->tss.regs->msr & MSR_FP) + if (child->thread.regs->msr & MSR_FP) giveup_fpu(child); - ((long *)child->tss.fpr)[addr - PT_FPR0] = data; + ((long *)child->thread.fpr)[addr - PT_FPR0] = data; ret = 0; goto out; } diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/semaphore.c linux/arch/ppc/kernel/semaphore.c --- v2.3.15/linux/arch/ppc/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/semaphore.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,139 @@ +/* + * $Id: semaphore.c,v 1.1 1999/08/31 15:11:44 cort Exp $ + * + * PowerPC-specific semaphore code. + * + * Copyright (C) 1999 Cort Dougan + * + * 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 + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.15/linux/arch/ppc/kernel/setup.c Fri Jul 23 12:20:23 1999 +++ linux/arch/ppc/kernel/setup.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.138 1999/07/11 16:32:21 cort Exp $ + * $Id: setup.c,v 1.146 1999/08/31 06:54:08 davem Exp $ * Common prep/pmac/chrp boot and setup code. */ @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,12 @@ unsigned long r6, unsigned long r7); +extern void gemini_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + extern boot_infos_t *boot_infos; extern char cmd_line[512]; char saved_command_line[256]; @@ -121,11 +128,11 @@ /* * I really need to add multiple-console support... -- Cort */ -__initfunc(int pmac_display_supported(char *name)) +int __init pmac_display_supported(char *name) { return 0; } -__initfunc(void pmac_find_display(void)) +void __init pmac_find_display(void) { } @@ -267,6 +274,15 @@ cpu_node = find_type_devices("cpu"); if ( !cpu_node ) break; + { + int s; + for ( s = 0; (s < i) && cpu_node->next ; + s++, cpu_node = cpu_node->next ) + /* nothing */ ; + if ( s != i ) + printk("get_cpuinfo(): ran out of " + "cpu nodes.\n"); + } fp = (int *) get_property(cpu_node, "clock-frequency", NULL); if ( !fp ) break; len += sprintf(len+buffer, "clock\t\t: %dMHz\n", @@ -392,6 +408,8 @@ _machine = _MACH_fads; #elif defined(CONFIG_APUS) _machine = _MACH_apus; +#elif defined(CONFIG_GEMINI) + _machine = _MACH_gemini; #else #error "Machine not defined correctly" #endif /* CONFIG_APUS */ @@ -475,6 +493,9 @@ mbx_init(r3, r4, r5, r6, r7); break; #endif + case _MACH_gemini: + gemini_init(r3, r4, r5, r6, r7); + break; default: printk("Unknown machine type in identify_machine!\n"); } @@ -500,16 +521,18 @@ } } -__initfunc(void - ppc_init(void)) +void __init ppc_init(void) { + /* clear the progress line */ + if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); + if (ppc_md.init != NULL) { ppc_md.init(); } } -__initfunc(void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) { extern int panic_timeout; extern char _etext[], _edata[]; @@ -526,7 +549,7 @@ /* reboot on panic */ panic_timeout = 180; - + init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) _etext; init_mm.end_data = (unsigned long) _edata; @@ -541,7 +564,7 @@ ppc_md.setup_arch(memory_start_p, memory_end_p); /* clear the progress line */ - if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); + if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); } void ppc_generic_ide_fix_driveid(struct hd_driveid *id) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.3.15/linux/arch/ppc/kernel/signal.c Thu Jul 22 09:47:55 1999 +++ linux/arch/ppc/kernel/signal.c Tue Aug 31 11:36:43 1999 @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/signal.c * - * $Id: signal.c,v 1.25 1999/06/17 05:40:20 paulus Exp $ + * $Id: signal.c,v 1.27 1999/08/03 19:16:38 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -227,7 +227,7 @@ | (saved_regs[PT_MSR] & MSR_USERCHANGE); memcpy(regs, saved_regs, GP_REGS_SIZE); - if (copy_from_user(current->tss.fpr, &sr->fp_regs, + if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs))) goto badframe; @@ -269,7 +269,7 @@ if (regs->msr & MSR_FP) giveup_fpu(current); if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) - || __copy_to_user(&frame->fp_regs, current->tss.fpr, + || __copy_to_user(&frame->fp_regs, current->thread.fpr, ELF_NFPREG * sizeof(double)) || __put_user(0x38007777UL, &frame->tramp[0]) /* li r0,0x7777 */ || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.3.15/linux/arch/ppc/kernel/smp.c Thu Aug 12 11:50:14 1999 +++ linux/arch/ppc/kernel/smp.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: smp.c,v 1.55 1999/07/03 08:57:09 davem Exp $ + * $Id: smp.c,v 1.61 1999/08/24 22:06:26 cort Exp $ * * Smp support for ppc. * @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -31,8 +30,10 @@ #include #include #include +#include #include #include +#include #include "time.h" int first_cpu_booted = 0; @@ -241,6 +242,7 @@ void __init smp_boot_cpus(void) { extern struct task_struct *current_set[NR_CPUS]; + extern unsigned long smp_chrp_cpu_nr; extern void __secondary_start_psurge(void); extern void __secondary_start_chrp(void); int i, cpu_nr; @@ -285,9 +287,13 @@ cpu_nr = 2; break; case _MACH_chrp: + /* openpic doesn't report # of cpus, just # possible -- Cort */ +#if 0 cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0) & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1; +#endif + cpu_nr = smp_chrp_cpu_nr; break; } @@ -301,7 +307,7 @@ /* create a process for the processor */ kernel_thread(start_secondary, NULL, CLONE_PID); - p = task[i]; + p = init_tasks[i]; if ( !p ) panic("No idle task for secondary processor\n"); p->processor = i; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/softemu8xx.c linux/arch/ppc/kernel/softemu8xx.c --- v2.3.15/linux/arch/ppc/kernel/softemu8xx.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/kernel/softemu8xx.c Tue Aug 31 11:36:43 1999 @@ -64,7 +64,7 @@ disp = instword & 0xffff; ea = (uint *)(regs->gpr[idxreg] + disp); - ip = (uint *)¤t->tss.fpr[flreg]; + ip = (uint *)¤t->thread.fpr[flreg]; switch ( inst ) { @@ -108,7 +108,7 @@ break; case FMR: /* assume this is a fp move -- Cort */ - memcpy( ip, ¤t->tss.fpr[(instword>>11)&0x1f], + memcpy( ip, ¤t->thread.fpr[(instword>>11)&0x1f], sizeof(double) ); break; default: diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.3.15/linux/arch/ppc/kernel/time.c Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/kernel/time.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: time.c,v 1.50 1999/06/05 00:23:20 cort Exp $ + * $Id: time.c,v 1.55 1999/08/31 06:54:09 davem Exp $ * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -52,7 +52,7 @@ void smp_local_timer_interrupt(struct pt_regs *); /* keep track of when we need to update the rtc */ -unsigned long last_rtc_update = 0; +time_t last_rtc_update = 0; /* The decrementer counts down by 128 every 128ns on a 601. */ #define DECREMENTER_COUNT_601 (1000000000 / HZ) @@ -110,15 +110,15 @@ /* * update the rtc when needed */ - if ( xtime.tv_sec > last_rtc_update + 660 ) + if ( (time_status & STA_UNSYNC) && + ((xtime.tv_sec > last_rtc_update + 60) || + (xtime.tv_sec < last_rtc_update)) ) { - if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) { + if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; - } - else { + else /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec - 60; - } + last_rtc_update = xtime.tv_sec; } } } @@ -176,7 +176,7 @@ } -__initfunc(void time_init(void)) +void __init time_init(void) { if (ppc_md.time_init != NULL) { @@ -196,10 +196,8 @@ xtime.tv_usec = 0; set_dec(decrementer_count); - /* mark the rtc/on-chip timer as in sync - * so we don't update right away - */ - last_rtc_update = xtime.tv_sec; + /* allow setting the time right away */ + last_rtc_update = 0; } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/time.h linux/arch/ppc/kernel/time.h --- v2.3.15/linux/arch/ppc/kernel/time.h Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/time.h Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: time.h,v 1.11 1999/03/18 04:16:34 cort Exp $ + * $Id: time.h,v 1.12 1999/08/27 04:21:23 cort Exp $ * Common time prototypes and such for all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -15,7 +15,7 @@ extern unsigned long mktime(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; +extern time_t last_rtc_update; int via_calibrate_decr(void); diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/totalmp.c linux/arch/ppc/kernel/totalmp.c --- v2.3.15/linux/arch/ppc/kernel/totalmp.c Wed Sep 30 10:14:17 1998 +++ linux/arch/ppc/kernel/totalmp.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: totalmp.c,v 1.5 1998/08/26 13:58:50 cort Exp $ + * $Id: totalmp.c,v 1.6 1999/08/31 06:54:10 davem Exp $ * * Support for Total Impact's TotalMP PowerPC accelerator board. * @@ -25,7 +25,7 @@ extern inline void openpic_writefield(volatile u_int *addr, u_int mask, u_int field); -__initfunc(void totalmp_init(void)) +void __init totalmp_init(void) { struct pci_dev *dev; u32 val; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.3.15/linux/arch/ppc/kernel/traps.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/kernel/traps.c Tue Aug 31 11:36:43 1999 @@ -229,26 +229,26 @@ void SoftwareEmulation(struct pt_regs *regs) { - int errcode; - extern int Soft_emulate_8xx (struct pt_regs *regs); - extern void print_8xx_pte(struct mm_struct *, unsigned long); + extern int do_mathemu(struct pt_regs *); + int errcode; - if (user_mode(regs)) - { - if ((errcode = Soft_emulate_8xx(regs))) { -printk("Software Emulation %s/%d NIP: %lx *NIP: 0x%x code: %x", - current->comm,current->pid, - regs->nip, *((uint *)regs->nip), errcode); -/*print_8xx_pte(current->mm, regs->nip);*/ - if (errcode == EFAULT) - _exception(SIGBUS, regs); - else - _exception(SIGILL, regs); - } - } - else { + if (!user_mode(regs)) { + show_regs(regs); +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + debugger(regs); +#endif + print_backtrace((unsigned long *)regs->gpr[1]); panic("Kernel Mode Software FPU Emulation"); } + + if ((errcode = do_mathemu(regs))) { + if (errcode > 0) + _exception(SIGFPE, regs); + else if (errcode == -EFAULT; + _exception(SIGSEGV, regs); + else + _exception(SIGILL, regs); + } } #endif @@ -259,6 +259,6 @@ regs->nip, regs->msr, regs->trap); } -__initfunc(void trap_init(void)) +void __init trap_init(void) { } diff -u --recursive --new-file v2.3.15/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c --- v2.3.15/linux/arch/ppc/lib/locks.c Wed Mar 10 21:30:32 1999 +++ linux/arch/ppc/lib/locks.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: locks.c,v 1.23 1999/02/12 07:06:32 cort Exp $ + * $Id: locks.c,v 1.24 1999/08/03 19:16:47 cort Exp $ * * Locks for smp ppc * @@ -113,7 +113,7 @@ #ifdef DEBUG_LOCKS if ( rw->lock == 0 ) printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n", - current->comm,current->pid,current->tss.regs->nip, + current->comm,current->pid,current->thread.regs->nip, rw->lock); #endif /* DEBUG_LOCKS */ wmb(); @@ -173,7 +173,7 @@ #ifdef DEBUG_LOCKS if ( !(rw->lock & (1<<31)) ) printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n", - current->comm,current->pid,current->tss.regs->nip, + current->comm,current->pid,current->thread.regs->nip, rw->lock); #endif /* DEBUG_LOCKS */ wmb(); @@ -189,7 +189,7 @@ 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->comm,task->pid,task->thread.regs->nip, task->lock_depth); } #endif /* DEBUG_LOCKS */ @@ -219,7 +219,7 @@ { printk("__unlock_kernel(): %s/%d (nip %08lX) " "lock depth %x flags %lx\n", - task->comm,task->pid,task->tss.regs->nip, + task->comm,task->pid,task->thread.regs->nip, task->lock_depth, klock_info.kernel_flag); klock_info.akp = NO_PROC_ID; klock_info.kernel_flag = 0; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/Makefile linux/arch/ppc/math-emu/Makefile --- v2.3.15/linux/arch/ppc/math-emu/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/Makefile Tue Aug 31 11:36:43 1999 @@ -0,0 +1,20 @@ +# +# +# + +O_TARGET := math-emu.o + +O_OBJS := math.o fmr.o lfd.o stfd.o + +ifdef CONFIG_MATH_EMULATION +O_OBJS += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o fctiw.o fctiwz.o \ + fdiv.o fdivs.o fmadd.o fmadds.o fmsub.o fmsubs.o \ + fmul.o fmuls.o fnabs.o fneg.o fnmadd.o fnmadds.o \ + fnmsub.o fnmsubs.o fres.o frsp.o frsqrte.o fsel.o \ + fsqrt.o fsqrts.o fsub.o fsubs.o lfs.o \ + mcrfs.o mffs.o mtfsb0.o mtfsb1.o mtfsf.o mtfsfi.o \ + stfiwx.o stfs.o udivmodti4.o types.o +endif + +include $(TOPDIR)/Rules.make + diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/double.h linux/arch/ppc/math-emu/double.h --- v2.3.15/linux/arch/ppc/math-emu/double.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/double.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,129 @@ +/* + * Definitions for IEEE Double Precision + */ + +#if _FP_W_TYPE_SIZE < 32 +#error "Here's a nickel 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.3.15/linux/arch/ppc/math-emu/fabs.c linux/arch/ppc/math-emu/fabs.c --- v2.3.15/linux/arch/ppc/math-emu/fabs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fabs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,21 @@ +/* $Id: fabs.c,v 1.1 1999/08/23 18:59:21 cort Exp $ + */ + +#include +#include +#include + +int +fabs(u32 *frD, u32 *frB) +{ + frD[0] = frB[0] & 0x7fffffff; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fadd.c linux/arch/ppc/math-emu/fadd.c --- v2.3.15/linux/arch/ppc/math-emu/fadd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fadd.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,41 @@ +/* $Id: fadd.c,v 1.1 1999/08/23 18:59:22 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fadd(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fadds.c linux/arch/ppc/math-emu/fadds.c --- v2.3.15/linux/arch/ppc/math-emu/fadds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fadds.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,42 @@ +/* $Id: fadds.c,v 1.1 1999/08/23 18:59:25 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fadds(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fcmpo.c linux/arch/ppc/math-emu/fcmpo.c --- v2.3.15/linux/arch/ppc/math-emu/fcmpo.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fcmpo.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,49 @@ +/* $Id: fcmpo.c,v 1.1 1999/08/23 18:59:26 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fcmpo(u32 *ccr, int crfD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) }; + long cmp; + int ret = 0; + +#ifdef DEBUG + printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_c == FP_CLS_NAN || B_c == FP_CLS_NAN) + ret |= EFLAG_VXVC; + + FP_CMP_D(cmp, A, B, 2); + cmp = code[(cmp + 1) & 3]; + + __FPU_FPSCR &= ~(0x1f000); + __FPU_FPSCR |= (cmp << 12); + + *ccr &= ~(15 << ((7 - crfD) << 2)); + *ccr |= (cmp << ((7 - crfD) << 2)); + +#ifdef DEBUG + printk("CR: %08x\n", *ccr); +#endif + + return ret; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fcmpu.c linux/arch/ppc/math-emu/fcmpu.c --- v2.3.15/linux/arch/ppc/math-emu/fcmpu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fcmpu.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,45 @@ +/* $Id: fcmpu.c,v 1.1 1999/08/23 18:59:28 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fcmpu(u32 *ccr, int crfD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) }; + long cmp; + +#ifdef DEBUG + printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + FP_CMP_D(cmp, A, B, 2); + cmp = code[(cmp + 1) & 3]; + + __FPU_FPSCR &= ~(0x1f000); + __FPU_FPSCR |= (cmp << 12); + + *ccr &= ~(15 << ((7 - crfD) << 2)); + *ccr |= (cmp << ((7 - crfD) << 2)); + +#ifdef DEBUG + printk("CR: %08x\n", *ccr); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fctiw.c linux/arch/ppc/math-emu/fctiw.c --- v2.3.15/linux/arch/ppc/math-emu/fctiw.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fctiw.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,28 @@ +/* $Id: fctiw.c,v 1.1 1999/08/23 18:59:30 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fctiw(u32 *frD, void *frB) +{ + FP_DECL_D(B); + unsigned int r; + + __FP_UNPACK_D(B, frB); + FP_TO_INT_D(r, B, 32, 1); + frD[1] = r; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fctiwz.c linux/arch/ppc/math-emu/fctiwz.c --- v2.3.15/linux/arch/ppc/math-emu/fctiwz.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fctiwz.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,35 @@ +/* $Id: fctiwz.c,v 1.1 1999/08/23 18:59:31 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fctiwz(u32 *frD, void *frB) +{ + FP_DECL_D(B); + u32 fpscr; + unsigned int r; + + fpscr = __FPU_FPSCR; + __FPU_FPSCR &= ~(3); + __FPU_FPSCR |= FP_RND_ZERO; + + __FP_UNPACK_D(B, frB); + FP_TO_INT_D(r, B, 32, 1); + frD[1] = r; + + __FPU_FPSCR = fpscr; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fdiv.c linux/arch/ppc/math-emu/fdiv.c --- v2.3.15/linux/arch/ppc/math-emu/fdiv.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fdiv.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,56 @@ +/* $Id: fdiv.c,v 1.1 1999/08/23 18:59:33 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fdiv(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { + ret |= EFLAG_VXZDZ; +#ifdef DEBUG + printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__); +#endif + } + if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { + ret |= EFLAG_VXIDI; +#ifdef DEBUG + printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__); +#endif + } + + if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if (__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } + FP_DIV_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fdivs.c linux/arch/ppc/math-emu/fdivs.c --- v2.3.15/linux/arch/ppc/math-emu/fdivs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fdivs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,58 @@ +/* $Id: fdivs.c,v 1.1 1999/08/23 18:59:35 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fdivs(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { + ret |= EFLAG_VXZDZ; +#ifdef DEBUG + printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__); +#endif + } + if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { + ret |= EFLAG_VXIDI; +#ifdef DEBUG + printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__); +#endif + } + + if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if (__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } + + FP_DIV_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fmadd.c linux/arch/ppc/math-emu/fmadd.c --- v2.3.15/linux/arch/ppc/math-emu/fmadd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fmadd.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,51 @@ +/* $Id: fmadd.c,v 1.1 1999/08/23 18:59:36 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fmadd(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fmadds.c linux/arch/ppc/math-emu/fmadds.c --- v2.3.15/linux/arch/ppc/math-emu/fmadds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fmadds.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,52 @@ +/* $Id: fmadds.c,v 1.1 1999/08/23 18:59:38 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fmadds(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fmr.c linux/arch/ppc/math-emu/fmr.c --- v2.3.15/linux/arch/ppc/math-emu/fmr.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fmr.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,21 @@ +/* $Id: fmr.c,v 1.1 1999/08/23 18:59:40 cort Exp $ + */ + +#include +#include +#include + +int +fmr(u32 *frD, u32 *frB) +{ + frD[0] = frB[0]; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fmsub.c linux/arch/ppc/math-emu/fmsub.c --- v2.3.15/linux/arch/ppc/math-emu/fmsub.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fmsub.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,54 @@ +/* $Id: fmsub.c,v 1.1 1999/08/23 18:59:41 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fmsub(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fmsubs.c linux/arch/ppc/math-emu/fmsubs.c --- v2.3.15/linux/arch/ppc/math-emu/fmsubs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fmsubs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,55 @@ +/* $Id: fmsubs.c,v 1.1 1999/08/23 18:59:42 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fmsubs(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fmul.c linux/arch/ppc/math-emu/fmul.c --- v2.3.15/linux/arch/ppc/math-emu/fmul.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fmul.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,45 @@ +/* $Id: fmul.c,v 1.1 1999/08/23 18:59:44 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fmul(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023); + printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023); +#endif + + if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fmuls.c linux/arch/ppc/math-emu/fmuls.c --- v2.3.15/linux/arch/ppc/math-emu/fmuls.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fmuls.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,46 @@ +/* $Id: fmuls.c,v 1.1 1999/08/23 18:59:45 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fmuls(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023); + printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023); +#endif + + if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fnabs.c linux/arch/ppc/math-emu/fnabs.c --- v2.3.15/linux/arch/ppc/math-emu/fnabs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fnabs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,21 @@ +/* $Id: fnabs.c,v 1.1 1999/08/23 18:59:47 cort Exp $ + */ + +#include +#include +#include + +int +fnabs(u32 *frD, u32 *frB) +{ + frD[0] = frB[0] | 0x80000000; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fneg.c linux/arch/ppc/math-emu/fneg.c --- v2.3.15/linux/arch/ppc/math-emu/fneg.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fneg.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,21 @@ +/* $Id: fneg.c,v 1.1 1999/08/23 18:59:48 cort Exp $ + */ + +#include +#include +#include + +int +fneg(u32 *frD, u32 *frB) +{ + frD[0] = frB[0] ^ 0x80000000; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fnmadd.c linux/arch/ppc/math-emu/fnmadd.c --- v2.3.15/linux/arch/ppc/math-emu/fnmadd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fnmadd.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,54 @@ +/* $Id: fnmadd.c,v 1.1 1999/08/23 18:59:50 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fnmadd(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fnmadds.c linux/arch/ppc/math-emu/fnmadds.c --- v2.3.15/linux/arch/ppc/math-emu/fnmadds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fnmadds.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,55 @@ +/* $Id: fnmadds.c,v 1.1 1999/08/23 18:59:51 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fnmadds(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fnmsub.c linux/arch/ppc/math-emu/fnmsub.c --- v2.3.15/linux/arch/ppc/math-emu/fnmsub.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fnmsub.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,57 @@ +/* $Id: fnmsub.c,v 1.1 1999/08/23 18:59:53 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fnmsub(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fnmsubs.c linux/arch/ppc/math-emu/fnmsubs.c --- v2.3.15/linux/arch/ppc/math-emu/fnmsubs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fnmsubs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,58 @@ +/* $Id: fnmsubs.c,v 1.1 1999/08/23 18:59:54 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fnmsubs(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fres.c linux/arch/ppc/math-emu/fres.c --- v2.3.15/linux/arch/ppc/math-emu/fres.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fres.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,15 @@ +/* $Id: fres.c,v 1.1 1999/08/23 18:59:56 cort Exp $ + */ + +#include +#include +#include + +int +fres(void *frD, void *frB) +{ +#ifdef DEBUG + printk("%s: %p %p\n", __FUNCTION__, frD, frB); +#endif + return -ENOSYS; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/frsp.c linux/arch/ppc/math-emu/frsp.c --- v2.3.15/linux/arch/ppc/math-emu/frsp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/frsp.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,28 @@ +/* $Id: frsp.c,v 1.1 1999/08/23 18:59:57 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +frsp(void *frD, void *frB) +{ + FP_DECL_D(B); + +#ifdef DEBUG + printk("%s: D %p, B %p\n", __FUNCTION__, frD, frB); +#endif + + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + return __FP_PACK_DS(frD, B); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/frsqrte.c linux/arch/ppc/math-emu/frsqrte.c --- v2.3.15/linux/arch/ppc/math-emu/frsqrte.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/frsqrte.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,15 @@ +/* $Id: frsqrte.c,v 1.1 1999/08/23 18:59:58 cort Exp $ + */ + +#include +#include +#include + +int +frsqrte(void *frD, void *frB) +{ +#ifdef DEBUG + printk("%s: %p %p\n", __FUNCTION__, frD, frB); +#endif + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fsel.c linux/arch/ppc/math-emu/fsel.c --- v2.3.15/linux/arch/ppc/math-emu/fsel.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fsel.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,41 @@ +/* $Id: fsel.c,v 1.1 1999/08/23 18:59:59 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fsel(u32 *frD, void *frA, u32 *frB, u32 *frC) +{ + FP_DECL_D(A); + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %08x %08x\n", frB[0], frB[1]); + printk("C: %08x %08x\n", frC[0], frC[1]); +#endif + + if (A_c == FP_CLS_NAN || (A_c != FP_CLS_ZERO && A_s)) { + frD[0] = frB[0]; + frD[1] = frB[1]; + } else { + frD[0] = frC[0]; + frD[1] = frC[1]; + } + +#ifdef DEBUG + printk("D: %08x.%08x\n", frD[0], frD[1]); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fsqrt.c linux/arch/ppc/math-emu/fsqrt.c --- v2.3.15/linux/arch/ppc/math-emu/fsqrt.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fsqrt.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,40 @@ +/* $Id: fsqrt.c,v 1.1 1999/08/23 19:00:01 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fsqrt(void *frD, void *frB) +{ + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB); +#endif + + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_s && B_c != FP_CLS_ZERO) + ret |= EFLAG_VXSQRT; + if (B_c == FP_CLS_NAN) + ret |= EFLAG_VXSNAN; + + FP_SQRT_D(R, B); + +#ifdef DEBUG + printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fsqrts.c linux/arch/ppc/math-emu/fsqrts.c --- v2.3.15/linux/arch/ppc/math-emu/fsqrts.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fsqrts.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,41 @@ +/* $Id: fsqrts.c,v 1.1 1999/08/23 19:00:03 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fsqrts(void *frD, void *frB) +{ + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB); +#endif + + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_s && B_c != FP_CLS_ZERO) + ret |= EFLAG_VXSQRT; + if (B_c == FP_CLS_NAN) + ret |= EFLAG_VXSNAN; + + FP_SQRT_D(R, B); + +#ifdef DEBUG + printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fsub.c linux/arch/ppc/math-emu/fsub.c --- v2.3.15/linux/arch/ppc/math-emu/fsub.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fsub.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,44 @@ +/* $Id: fsub.c,v 1.1 1999/08/23 19:00:05 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" + +int +fsub(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/fsubs.c linux/arch/ppc/math-emu/fsubs.c --- v2.3.15/linux/arch/ppc/math-emu/fsubs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/fsubs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,45 @@ +/* $Id: fsubs.c,v 1.1 1999/08/23 19:00:07 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fsubs(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/lfd.c linux/arch/ppc/math-emu/lfd.c --- v2.3.15/linux/arch/ppc/math-emu/lfd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/lfd.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,22 @@ +/* $Id: lfd.c,v 1.1 1999/08/23 19:00:08 cort Exp $ + */ + +#include +#include +#include + +#include "sfp-machine.h" +#include "double.h" + +int +lfd(void *frD, void *ea) +{ + if (copy_from_user(frD, ea, sizeof(double))) + return -EFAULT; +#ifdef DEBUG + printk("%s: D %p, ea %p: ", __FUNCTION__, frD, ea); + dump_double(frD); + printk("\n"); +#endif + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/lfs.c linux/arch/ppc/math-emu/lfs.c --- v2.3.15/linux/arch/ppc/math-emu/lfs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/lfs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,40 @@ +/* $Id: lfs.c,v 1.1 1999/08/23 19:00:10 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +lfs(void *frD, void *ea) +{ + FP_DECL_D(R); + FP_DECL_S(A); + float f; + +#ifdef DEBUG + printk("%s: D %p, ea %p\n", __FUNCTION__, frD, ea); +#endif + + if (copy_from_user(&f, ea, sizeof(float))) + return -EFAULT; + + __FP_UNPACK_S(A, &f); + +#ifdef DEBUG + printk("A: %ld %lu %ld (%ld) [%08lx]\n", A_s, A_f, A_e, A_c, + *(unsigned long *)&f); +#endif + + FP_CONV(D, S, 2, 1, R, A); + +#ifdef DEBUG + printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return __FP_PACK_D(frD, R); +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/math.c linux/arch/ppc/math-emu/math.c --- v2.3.15/linux/arch/ppc/math-emu/math.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/math.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,485 @@ +/* $Id: math.c,v 1.1 1999/08/23 19:00:11 cort Exp $ + * arch/ppc/math-emu/math.c + * + * Copyright (C) 1999 Eddie C. Dost (ecd@atecom.com) + */ + +#include +#include +#include + +#include +#include + +#include "sfp-machine.h" +#include "double.h" + +#define FLOATFUNC(x) extern int x(void *, void *, void *, void *) + +FLOATFUNC(fadd); +FLOATFUNC(fadds); +FLOATFUNC(fdiv); +FLOATFUNC(fdivs); +FLOATFUNC(fmul); +FLOATFUNC(fmuls); +FLOATFUNC(fsub); +FLOATFUNC(fsubs); + +FLOATFUNC(fmadd); +FLOATFUNC(fmadds); +FLOATFUNC(fmsub); +FLOATFUNC(fmsubs); +FLOATFUNC(fnmadd); +FLOATFUNC(fnmadds); +FLOATFUNC(fnmsub); +FLOATFUNC(fnmsubs); + +FLOATFUNC(fctiw); +FLOATFUNC(fctiwz); +FLOATFUNC(frsp); + +FLOATFUNC(fcmpo); +FLOATFUNC(fcmpu); + +FLOATFUNC(mcrfs); +FLOATFUNC(mffs); +FLOATFUNC(mtfsb0); +FLOATFUNC(mtfsb1); +FLOATFUNC(mtfsf); +FLOATFUNC(mtfsfi); + +FLOATFUNC(lfd); +FLOATFUNC(lfs); + +FLOATFUNC(stfd); +FLOATFUNC(stfs); +FLOATFUNC(stfiwx); + +FLOATFUNC(fabs); +FLOATFUNC(fmr); +FLOATFUNC(fnabs); +FLOATFUNC(fneg); + +/* Optional */ +FLOATFUNC(fres); +FLOATFUNC(frsqrte); +FLOATFUNC(fsel); +FLOATFUNC(fsqrt); +FLOATFUNC(fsqrts); + + +#define OP31 0x1f /* 31 */ +#define LFS 0x30 /* 48 */ +#define LFSU 0x31 /* 49 */ +#define LFD 0x32 /* 50 */ +#define LFDU 0x33 /* 51 */ +#define STFS 0x34 /* 52 */ +#define STFSU 0x35 /* 53 */ +#define STFD 0x36 /* 54 */ +#define STFDU 0x37 /* 55 */ +#define OP59 0x3b /* 59 */ +#define OP63 0x3f /* 63 */ + +/* Opcode 31: */ +/* X-Form: */ +#define LFSX 0x217 /* 535 */ +#define LFSUX 0x237 /* 567 */ +#define LFDX 0x257 /* 599 */ +#define LFDUX 0x277 /* 631 */ +#define STFSX 0x297 /* 663 */ +#define STFSUX 0x2b7 /* 695 */ +#define STFDX 0x2d7 /* 727 */ +#define STFDUX 0x2f7 /* 759 */ +#define STFIWX 0x3d7 /* 983 */ + +/* Opcode 59: */ +/* A-Form: */ +#define FDIVS 0x012 /* 18 */ +#define FSUBS 0x014 /* 20 */ +#define FADDS 0x015 /* 21 */ +#define FSQRTS 0x016 /* 22 */ +#define FRES 0x018 /* 24 */ +#define FMULS 0x019 /* 25 */ +#define FMSUBS 0x01c /* 28 */ +#define FMADDS 0x01d /* 29 */ +#define FNMSUBS 0x01e /* 30 */ +#define FNMADDS 0x01f /* 31 */ + +/* Opcode 63: */ +/* A-Form: */ +#define FDIV 0x012 /* 18 */ +#define FSUB 0x014 /* 20 */ +#define FADD 0x015 /* 21 */ +#define FSQRT 0x016 /* 22 */ +#define FSEL 0x017 /* 23 */ +#define FMUL 0x019 /* 25 */ +#define FRSQRTE 0x01a /* 26 */ +#define FMSUB 0x01c /* 28 */ +#define FMADD 0x01d /* 29 */ +#define FNMSUB 0x01e /* 30 */ +#define FNMADD 0x01f /* 31 */ + +/* X-Form: */ +#define FCMPU 0x000 /* 0 */ +#define FRSP 0x00c /* 12 */ +#define FCTIW 0x00e /* 14 */ +#define FCTIWZ 0x00f /* 15 */ +#define FCMPO 0x020 /* 32 */ +#define MTFSB1 0x026 /* 38 */ +#define FNEG 0x028 /* 40 */ +#define MCRFS 0x040 /* 64 */ +#define MTFSB0 0x046 /* 70 */ +#define FMR 0x048 /* 72 */ +#define MTFSFI 0x086 /* 134 */ +#define FNABS 0x088 /* 136 */ +#define FABS 0x108 /* 264 */ +#define MFFS 0x247 /* 583 */ +#define MTFSF 0x2c7 /* 711 */ + + +#define AB 2 +#define AC 3 +#define ABC 4 +#define D 5 +#define DU 6 +#define X 7 +#define XA 8 +#define XB 9 +#define XCR 11 +#define XCRB 12 +#define XCRI 13 +#define XCRL 16 +#define XE 14 +#define XEU 15 +#define XFLB 10 + +#ifdef CONFIG_MATH_EMULATION +static int +record_exception(struct pt_regs *regs, int eflag) +{ + u32 fpscr; + + fpscr = __FPU_FPSCR; + + if (eflag) { + fpscr |= FPSCR_FX; + if (eflag & EFLAG_OVERFLOW) + fpscr |= FPSCR_OX; + if (eflag & EFLAG_UNDERFLOW) + fpscr |= FPSCR_UX; + if (eflag & EFLAG_DIVZERO) + fpscr |= FPSCR_ZX; + if (eflag & EFLAG_INEXACT) + fpscr |= FPSCR_XX; + if (eflag & EFLAG_VXSNAN) + fpscr |= FPSCR_VXSNAN; + if (eflag & EFLAG_VXISI) + fpscr |= FPSCR_VXISI; + if (eflag & EFLAG_VXIDI) + fpscr |= FPSCR_VXIDI; + if (eflag & EFLAG_VXZDZ) + fpscr |= FPSCR_VXZDZ; + if (eflag & EFLAG_VXIMZ) + fpscr |= FPSCR_VXIMZ; + if (eflag & EFLAG_VXVC) + fpscr |= FPSCR_VXVC; + if (eflag & EFLAG_VXSOFT) + fpscr |= FPSCR_VXSOFT; + if (eflag & EFLAG_VXSQRT) + fpscr |= FPSCR_VXSQRT; + if (eflag & EFLAG_VXCVI) + fpscr |= FPSCR_VXCVI; + } + + fpscr &= ~(FPSCR_VX); + if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | + FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | + FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI)) + fpscr |= FPSCR_VX; + + fpscr &= ~(FPSCR_FEX); + if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) || + ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) || + ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) || + ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) || + ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE))) + fpscr |= FPSCR_FEX; + + __FPU_FPSCR = fpscr; + + return (fpscr & FPSCR_FEX) ? 1 : 0; +} +#endif /* CONFIG_MATH_EMULATION */ + +int +do_mathemu(struct pt_regs *regs) +{ + void *op0 = 0, *op1 = 0, *op2 = 0, *op3 = 0; + unsigned long pc = regs->nip; + signed short sdisp; + u32 insn = 0; + int idx = 0; +#ifdef CONFIG_MATH_EMULATION + int (*func)(void *, void *, void *, void *); + int type = 0; + int eflag, trap; +#endif + + if (get_user(insn, (u32 *)pc)) + return -EFAULT; + +#ifndef CONFIG_MATH_EMULATION + switch (insn >> 26) { + case LFD: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + lfd(op0, op1, op2, op3); + break; + case LFDU: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + lfd(op0, op1, op2, op3); + regs->gpr[idx] = (unsigned long)op1; + break; + case STFD: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + stfd(op0, op1, op2, op3); + break; + case STFDU: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + stfd(op0, op1, op2, op3); + regs->gpr[idx] = (unsigned long)op1; + break; + case OP63: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + fmr(op0, op1, op2, op3); + break; + default: + goto illegal; + } +#else /* CONFIG_MATH_EMULATION */ + switch (insn >> 26) { + case LFS: func = lfs; type = D; break; + case LFSU: func = lfs; type = DU; break; + case LFD: func = lfd; type = D; break; + case LFDU: func = lfd; type = DU; break; + case STFS: func = stfs; type = D; break; + case STFSU: func = stfs; type = DU; break; + case STFD: func = stfd; type = D; break; + case STFDU: func = stfd; type = DU; break; + + case OP31: + switch ((insn >> 1) & 0x3ff) { + case LFSX: func = lfs; type = XE; break; + case LFSUX: func = lfs; type = XEU; break; + case LFDX: func = lfd; type = XE; break; + case LFDUX: func = lfd; type = XEU; break; + case STFSX: func = stfs; type = XE; break; + case STFSUX: func = stfs; type = XEU; break; + case STFDX: func = stfd; type = XE; break; + case STFDUX: func = stfd; type = XEU; break; + case STFIWX: func = stfiwx; type = XE; break; + default: + goto illegal; + } + break; + + case OP59: + switch ((insn >> 1) & 0x1f) { + case FDIVS: func = fdivs; type = AB; break; + case FSUBS: func = fsubs; type = AB; break; + case FADDS: func = fadds; type = AB; break; + case FSQRTS: func = fsqrts; type = AB; break; + case FRES: func = fres; type = AB; break; + case FMULS: func = fmuls; type = AC; break; + case FMSUBS: func = fmsubs; type = ABC; break; + case FMADDS: func = fmadds; type = ABC; break; + case FNMSUBS: func = fnmsubs; type = ABC; break; + case FNMADDS: func = fnmadds; type = ABC; break; + default: + goto illegal; + } + break; + + case OP63: + if (insn & 0x20) { + switch ((insn >> 1) & 0x1f) { + case FDIV: func = fdiv; type = AB; break; + case FSUB: func = fsub; type = AB; break; + case FADD: func = fadd; type = AB; break; + case FSQRT: func = fsqrt; type = AB; break; + case FSEL: func = fsel; type = ABC; break; + case FMUL: func = fmul; type = AC; break; + case FRSQRTE: func = frsqrte; type = AB; break; + case FMSUB: func = fmsub; type = ABC; break; + case FMADD: func = fmadd; type = ABC; break; + case FNMSUB: func = fnmsub; type = ABC; break; + case FNMADD: func = fnmadd; type = ABC; break; + default: + goto illegal; + } + break; + } + + switch ((insn >> 1) & 0x3ff) { + case FCMPU: func = fcmpu; type = XCR; break; + case FRSP: func = frsp; type = XB; break; + case FCTIW: func = fctiw; type = XB; break; + case FCTIWZ: func = fctiwz; type = XB; break; + case FCMPO: func = fcmpo; type = XCR; break; + case MTFSB1: func = mtfsb1; type = XCRB; break; + case FNEG: func = fneg; type = XB; break; + case MCRFS: func = mcrfs; type = XCRL; break; + case MTFSB0: func = mtfsb0; type = XCRB; break; + case FMR: func = fmr; type = XB; break; + case MTFSFI: func = mtfsfi; type = XCRI; break; + case FNABS: func = fnabs; type = XB; break; + case FABS: func = fabs; type = XB; break; + case MFFS: func = mffs; type = X; break; + case MTFSF: func = mtfsf; type = XFLB; break; + default: + goto illegal; + } + break; + + default: + goto illegal; + } + + switch (type) { + case AB: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op2 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + case AC: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op2 = (void *)¤t->tss.fpr[(insn >> 6) & 0x1f]; + break; + + case ABC: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op2 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + op3 = (void *)¤t->tss.fpr[(insn >> 6) & 0x1f]; + break; + + case D: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + break; + + case DU: + idx = (insn >> 16) & 0x1f; + if (!idx) + goto illegal; + + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)(regs->gpr[idx] + sdisp); + break; + + case X: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + break; + + case XA: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + break; + + case XB: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + case XE: + idx = (insn >> 16) & 0x1f; + if (!idx) + goto illegal; + + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]); + break; + + case XEU: + idx = (insn >> 16) & 0x1f; + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + + regs->gpr[(insn >> 11) & 0x1f]); + break; + + case XCR: + op0 = (void *)®s->ccr; + op1 = (void *)((insn >> 23) & 0x7); + op2 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op3 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + case XCRL: + op0 = (void *)®s->ccr; + op1 = (void *)((insn >> 23) & 0x7); + op2 = (void *)((insn >> 18) & 0x7); + break; + + case XCRB: + op0 = (void *)((insn >> 21) & 0x1f); + break; + + case XCRI: + op0 = (void *)((insn >> 23) & 0x7); + op1 = (void *)((insn >> 12) & 0xf); + break; + + case XFLB: + op0 = (void *)((insn >> 17) & 0xff); + op1 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + default: + goto illegal; + } + + eflag = func(op0, op1, op2, op3); + + if (insn & 1) { + regs->ccr &= ~(0x0f000000); + regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000; + } + + trap = record_exception(regs, eflag); + if (trap) + return 1; + + switch (type) { + case DU: + case XEU: + regs->gpr[idx] = (unsigned long)op1; + break; + + default: + break; + } +#endif /* CONFIG_MATH_EMULATION */ + + regs->nip += 4; + return 0; + +illegal: + return -ENOSYS; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/mcrfs.c linux/arch/ppc/math-emu/mcrfs.c --- v2.3.15/linux/arch/ppc/math-emu/mcrfs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/mcrfs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,34 @@ +/* $Id: mcrfs.c,v 1.1 1999/08/23 19:00:13 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" + +int +mcrfs(u32 *ccr, u32 crfD, u32 crfS) +{ + u32 value, clear; + +#ifdef DEBUG + printk("%s: %p (%08x) %d %d\n", __FUNCTION__, ccr, *ccr, crfD, crfS); +#endif + + clear = 15 << ((7 - crfS) << 2); + if (!crfS) + clear = 0x90000000; + + value = (__FPU_FPSCR >> ((7 - crfS) << 2)) & 15; + __FPU_FPSCR &= ~(clear); + + *ccr &= ~(15 << ((7 - crfD) << 2)); + *ccr |= (value << ((7 - crfD) << 2)); + +#ifdef DEBUG + printk("CR: %08x\n", __FUNCTION__, *ccr); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/mffs.c linux/arch/ppc/math-emu/mffs.c --- v2.3.15/linux/arch/ppc/math-emu/mffs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/mffs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,20 @@ +/* $Id: mffs.c,v 1.1 1999/08/23 19:00:14 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" + +int +mffs(u32 *frD) +{ + frD[1] = __FPU_FPSCR; + +#ifdef DEBUG + printk("%s: frD %p: %08x.%08x\n", __FUNCTION__, frD, frD[0], frD[1]); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/mtfsb0.c linux/arch/ppc/math-emu/mtfsb0.c --- v2.3.15/linux/arch/ppc/math-emu/mtfsb0.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/mtfsb0.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,21 @@ +/* $Id: mtfsb0.c,v 1.1 1999/08/23 19:00:16 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" + +int +mtfsb0(int crbD) +{ + if ((crbD != 1) && (crbD != 2)) + __FPU_FPSCR &= ~(1 << (31 - crbD)); + +#ifdef DEBUG + printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/mtfsb1.c linux/arch/ppc/math-emu/mtfsb1.c --- v2.3.15/linux/arch/ppc/math-emu/mtfsb1.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/mtfsb1.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,21 @@ +/* $Id: mtfsb1.c,v 1.1 1999/08/23 19:00:17 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" + +int +mtfsb1(int crbD) +{ + if ((crbD != 1) && (crbD != 2)) + __FPU_FPSCR |= (1 << (31 - crbD)); + +#ifdef DEBUG + printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/mtfsf.c linux/arch/ppc/math-emu/mtfsf.c --- v2.3.15/linux/arch/ppc/math-emu/mtfsf.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/mtfsf.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,48 @@ +/* $Id: mtfsf.c,v 1.1 1999/08/23 19:00:19 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" + +int +mtfsf(unsigned int FM, u32 *frB) +{ + u32 mask; + + if (FM == 0) + return 0; + + if (FM == 0xff) + mask = 0x9fffffff; + else { + mask = 0; + if (FM & (1 << 0)) + mask |= 0x90000000; + if (FM & (1 << 1)) + mask |= 0x0f000000; + if (FM & (1 << 2)) + mask |= 0x00f00000; + if (FM & (1 << 3)) + mask |= 0x000f0000; + if (FM & (1 << 4)) + mask |= 0x0000f000; + if (FM & (1 << 5)) + mask |= 0x00000f00; + if (FM & (1 << 6)) + mask |= 0x000000f0; + if (FM & (1 << 7)) + mask |= 0x0000000f; + } + + __FPU_FPSCR &= ~(mask); + __FPU_FPSCR |= (frB[1] & mask); + +#ifdef DEBUG + printk("%s: %02x %p: %08lx\n", __FUNCTION__, FM, frB, __FPU_FPSCR); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/mtfsfi.c linux/arch/ppc/math-emu/mtfsfi.c --- v2.3.15/linux/arch/ppc/math-emu/mtfsfi.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/mtfsfi.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,26 @@ +/* $Id: mtfsfi.c,v 1.1 1999/08/23 19:00:20 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" + +int +mtfsfi(unsigned int crfD, unsigned int IMM) +{ + u32 mask = 0xf; + + if (!crfD) + mask = 9; + + __FPU_FPSCR &= ~(mask << ((7 - crfD) << 2)); + __FPU_FPSCR |= (IMM & 0xf) << ((7 - crfD) << 2); + +#ifdef DEBUG + printk("%s: %d %x: %08lx\n", __FUNCTION__, crfD, IMM, __FPU_FPSCR); +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/op-1.h linux/arch/ppc/math-emu/op-1.h --- v2.3.15/linux/arch/ppc/math-emu/op-1.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/op-1.h Tue Aug 31 11:36:43 1999 @@ -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.3.15/linux/arch/ppc/math-emu/op-2.h linux/arch/ppc/math-emu/op-2.h --- v2.3.15/linux/arch/ppc/math-emu/op-2.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/op-2.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,433 @@ +/* + * 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), \ + 0, _b_f1, _b_f0, 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)); \ + __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), \ + 0, _c_f1, _c_f0, 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)); \ + \ + /* 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) + +/* This next macro appears to be totally broken. Fortunately nowhere + * seems to use it :-> The problem is that we define _z[4] but + * then use it in _FP_FRAC_SRS_4, which will attempt to access + * _z_f[n] which will cause an error. The fix probably involves + * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998 + */ +#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: + * This seems to be giving me difficulties -- PMM + * Look, NetBSD seems to be able to comment algorithms. Can't you? + * I've thrown printks at the problem. + * This now appears to work, but I still don't really know why. + * Also, I don't think the result is properly normalised... + */ + +#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]; \ + /* I think this check is to ensure that the result is normalised. \ + * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in \ + * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y. \ + * In this case we tweak things. (this is based on comments in \ + * the NetBSD FPU emulation code. ) \ + * We know X,Y are normalised because we ensure this as part of \ + * the unpacking process. -- PMM \ + */ \ + 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 \ + { \ + R##_e--; \ + _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. CHANGED: - 1 to nothing -- PMM */ \ + _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); \ + /* adjust so answer is normalized again. I'm not sure what the \ + * final sz param should be. In practice it's never used since \ + * N is 1 which is always going to be < _FP_W_TYPE_SIZE... \ + */ \ + /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */ \ + } 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.3.15/linux/arch/ppc/math-emu/op-4.h linux/arch/ppc/math-emu/op-4.h --- v2.3.15/linux/arch/ppc/math-emu/op-4.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/op-4.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,297 @@ +/* + * Basic four-word fraction declaration and manipulation. + * + * When adding quadword support for 32 bit machines, we need + * to be a little careful as double multiply uses some of these + * macros: (in op-2.h) + * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4, + * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4 + * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use + * _FP_FRAC_DECL_4: it appears to be broken and is not used + * anywhere anyway. ) + * + * I've now fixed all the macros that were here from the sparc64 code. + * [*none* of the shift macros were correct!] -- PMM 02/1998 + * + * The only quadword stuff that remains to be coded is: + * 1) the conversion to/from ints, which requires + * that we check (in op-common.h) that the following do the right thing + * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt) + * 2) multiply, divide and sqrt, which require: + * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q), + * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to + * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h. + * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for + * these; they are used nowhere else. ] + */ + +#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]) +/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another + * macro such as _FP_ZEROFRAC_n which returns n comma separated values. + * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3) + * which just assigns the In values to the array X##_f[]. + * This is why the number of parameters doesn't appear to match + * at first glance... -- PMM + */ +#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; \ +/* bugfixed: was X##_f[_i] <<= _up; -- PMM 02/1998 */ \ + X##_f[_i] = X##_f[0] << _up; \ + for (--_i; _i >= 0; --_i) \ + X##_f[_i] = 0; \ + } while (0) + +/* This one was broken too */ +#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 < 3-_skip; ++_i) \ + X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ + X##_f[_i] = X##_f[3] >> _down; \ + for (++_i; _i < 4; ++_i) \ + X##_f[_i] = 0; \ + } while (0) + + +/* Right shift with sticky-lsb. + * What this actually means is that we do a standard right-shift, + * but that if any of the bits that fall off the right hand side + * were one then we always set the LSbit. + */ +#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; \ +/* s is now != 0 if we want to set the LSbit */ \ + for (_i = 0; _i < 3-_skip; ++_i) \ + X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ + X##_f[_i] = X##_f[3] >> _down; \ + for (++_i; _i < 4; ++_i) \ + X##_f[_i] = 0; \ + /* don't fix the LSB until the very end when we're sure f[0] is stable */ \ + X##_f[0] |= (_s != 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]) + +#define _FP_FRAC_SUB_4(R,X,Y) \ + __FP_FRAC_SUB_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]) + +#define _FP_FRAC_ADDI_4(X,I) \ + __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I) + +#define _FP_ZEROFRAC_4 0,0,0,0 +#define _FP_MINFRAC_4 0,0,0,1 + +#define _FP_FRAC_ZEROP_4(X) ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0) +#define _FP_FRAC_NEGP_4(X) ((_FP_WS_TYPE)X##_f[3] < 0) +#define _FP_FRAC_OVERP_4(fs,X) (X##_f[0] & _FP_OVERFLOW_##fs) + +#define _FP_FRAC_EQ_4(X,Y) \ + (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1] \ + && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3]) + +#define _FP_FRAC_GT_4(X,Y) \ + (X##_f[3] > Y##_f[3] || \ + (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ + (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ + (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0]) \ + )) \ + )) \ + ) + +#define _FP_FRAC_GE_4(X,Y) \ + (X##_f[3] > Y##_f[3] || \ + (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ + (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ + (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0]) \ + )) \ + )) \ + ) + + +#define _FP_FRAC_CLZ_4(R,X) \ + do { \ + if (X##_f[3]) \ + { \ + __FP_CLZ(R,X##_f[3]); \ + } \ + else if (X##_f[2]) \ + { \ + __FP_CLZ(R,X##_f[2]); \ + R += _FP_W_TYPE_SIZE; \ + } \ + else if (X##_f[1]) \ + { \ + __FP_CLZ(R,X##_f[2]); \ + R += _FP_W_TYPE_SIZE*2; \ + } \ + else \ + { \ + __FP_CLZ(R,X##_f[0]); \ + R += _FP_W_TYPE_SIZE*3; \ + } \ + } while(0) + + +#define _FP_UNPACK_RAW_4(fs, X, val) \ + do { \ + union _FP_UNION_##fs _flo; _flo.flt = (val); \ + X##_f[0] = _flo.bits.frac0; \ + X##_f[1] = _flo.bits.frac1; \ + X##_f[2] = _flo.bits.frac2; \ + X##_f[3] = _flo.bits.frac3; \ + X##_e = _flo.bits.exp; \ + X##_s = _flo.bits.sign; \ + } while (0) + +#define _FP_PACK_RAW_4(fs, val, X) \ + do { \ + union _FP_UNION_##fs _flo; \ + _flo.bits.frac0 = X##_f[0]; \ + _flo.bits.frac1 = X##_f[1]; \ + _flo.bits.frac2 = X##_f[2]; \ + _flo.bits.frac3 = X##_f[3]; \ + _flo.bits.exp = X##_e; \ + _flo.bits.sign = X##_s; \ + (val) = _flo.flt; \ + } while (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 + +#ifndef __FP_FRAC_SUB_4 +#define __FP_FRAC_SUB_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 + +#ifndef __FP_FRAC_ADDI_4 +/* I always wanted to be a lisp programmer :-> */ +#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \ + (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2))) +#endif + +/* Convert FP values between word sizes. This appears to be more + * complicated than I'd have expected it to be, so these might be + * wrong... These macros are in any case somewhat bogus because they + * use information about what various FRAC_n variables look like + * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do + * the ones in op-2.h and op-1.h. + */ +#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S) \ + do { \ + _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + D##_f = S##_f[0]; \ + } while (0) + +#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S) \ + do { \ + _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + D##_f0 = S##_f[0]; \ + D##_f1 = S##_f[1]; \ + } while (0) + +/* Assembly/disassembly for converting to/from integral types. + * No shifting or overflow handled here. + */ +/* Put the FP value X into r, which is an integer of size rsize. */ +#define _FP_FRAC_ASSEMBLE_4(r, X, rsize) \ + do { \ + if (rsize <= _FP_W_TYPE_SIZE) \ + r = X##_f[0]; \ + else if (rsize <= 2*_FP_W_TYPE_SIZE) \ + { \ + r = X##_f[1]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[0]; \ + } \ + else \ + { \ + /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \ + /* and int == 4words as a single case. */ \ + r = X##_f[3]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[2]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[1]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[0]; \ + } \ + } while (0) + +/* "No disassemble Number Five!" */ +/* move an integer of size rsize into X's fractional part. We rely on + * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid + * having to mask the values we store into it. + */ +#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize) \ + do { \ + X##_f[0] = r; \ + X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ + X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \ + X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \ + } while (0); + +#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \ + do { \ + D##_f[0] = S##_f; \ + D##_f[1] = D##_f[2] = D##_f[3] = 0; \ + _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ + } while (0) + +#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S) \ + do { \ + D##_f[0] = S##_f0; \ + D##_f[1] = S##_f1; \ + D##_f[2] = D##_f[3] = 0; \ + _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ + } while (0) + +/* FIXME! This has to be written */ +#define _FP_SQRT_MEAT_4(R, S, T, X, q) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/op-common.h linux/arch/ppc/math-emu/op-common.h --- v2.3.15/linux/arch/ppc/math-emu/op-common.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/op-common.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,690 @@ + +#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) \ +({int __ret = 0; \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + X##_e += _FP_EXPBIAS_##fs; \ + if (X##_e > 0) \ + { \ + __ret |= _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); \ + __ret |= EFLAG_OVERFLOW; \ + } \ + } \ + 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); \ + __ret |= _FP_ROUND(wc, X); \ + _FP_FRAC_SLL_##wc(X, 1); \ + if (_FP_FRAC_OVERP_##wc(fs, X)) \ + { \ + X##_e = 1; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + } \ + else \ + { \ + X##_e = 0; \ + _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \ + __ret |= EFLAG_UNDERFLOW; \ + } \ + } \ + else \ + { \ + /* underflow to zero */ \ + X##_e = 0; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + __ret |= EFLAG_UNDERFLOW; \ + } \ + } \ + 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; \ + } \ + __ret; \ +}) + + +/* + * 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 \ + { \ + int __x_zero = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ + int __y_zero = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ + \ + if (__x_zero && __y_zero) \ + ret = 0; \ + else if (__x_zero) \ + ret = Y##_s ? 1 : -1; \ + else if (__y_zero) \ + ret = X##_s ? -1 : 1; \ + else 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 + */ + +/* "When a NaN, infinity, large positive argument >= 2147483648.0, or + * large negative argument <= -2147483649.0 is converted to an integer, + * the invalid_current bit...should be set and fp_exception_IEEE_754 should + * be raised. If the floating point invalid trap is disabled, no trap occurs + * and a numerical result is generated: if the sign bit of the operand + * is 0, the result is 2147483647; if the sign bit of the operand is 1, + * the result is -2147483648." + * Similarly for conversion to extended ints, except that the boundaries + * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and + * -2^63 for s=1. + * -- SPARC Architecture Manual V9, Appendix B, which specifies how + * SPARCs resolve implementation dependencies in the IEEE-754 spec. + * I don't believe that the code below follows this. I'm not even sure + * it's right! + * It doesn't cope with needing to convert to an n bit integer when there + * is no n bit integer type. Fortunately gcc provides long long so this + * isn't a problem for sparc32. + * I have, however, fixed its NaN handling to conform as above. + * -- PMM 02/1998 + * NB: rsigned is not 'is r declared signed?' but 'should the value stored + * in r be signed or unsigned?'. r is always(?) declared unsigned. + * Comments below are mine, BTW -- PMM + */ +#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: see above! */ \ + case FP_CLS_ZERO: \ + r = 0; \ + } \ + else if (X##_e >= rsize - (rsigned != 0)) \ + { /* overflow */ \ + case FP_CLS_NAN: \ + 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 +#if _FP_W_TYPE_SIZE < 64 +/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */ +#define __FP_CLZ(r, x) \ + do { \ + _FP_W_TYPE _t = (x); \ + r = _FP_W_TYPE_SIZE - 1; \ + 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) +#else /* not _FP_W_TYPE_SIZE < 64 */ +#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 /* not _FP_W_TYPE_SIZE < 64 */ +#endif /* ndef __FP_CLZ */ + +#define _FP_DIV_HELP_imm(q, r, n, d) \ + do { \ + q = n / d, r = n % d; \ + } while (0) + diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/sfp-machine.h linux/arch/ppc/math-emu/sfp-machine.h --- v2.3.15/linux/arch/ppc/math-emu/sfp-machine.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/sfp-machine.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,377 @@ +/* Machine-dependent software floating-point definitions. PPC 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. + + Actually, this is a PPC (32bit) version, written based on the + i386, sparc, and sparc64 versions, by me, + Peter Maydell (pmaydell@chiark.greenend.org.uk). + Comments are by and large also mine, although they may be inaccurate. + + In picking out asm fragments I've gone with the lowest common + denominator, which also happens to be the hardware I have :-> + That is, a SPARC without hardware multiply and divide. + */ + +/* basic word size definitions */ +#define _FP_W_TYPE_SIZE 32 +#define _FP_W_TYPE unsigned long +#define _FP_WS_TYPE signed long +#define _FP_I_TYPE long + +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +/* You can optionally code some things like addition in asm. For + * example, i386 defines __FP_FRAC_ADD_2 as asm. If you don't + * then you get a fragment of C code [if you change an #ifdef 0 + * in op-2.h] or a call to add_ssaaaa (see below). + * Good places to look for asm fragments to use are gcc and glibc. + * gcc's longlong.h is useful. + */ + +/* We need to know how to multiply and divide. If the host word size + * is >= 2*fracbits you can use FP_MUL_MEAT_n_imm(t,R,X,Y) which + * codes the multiply with whatever gcc does to 'a * b'. + * _FP_MUL_MEAT_n_wide(t,R,X,Y,f) is used when you have an asm + * function that can multiply two 1W values and get a 2W result. + * Otherwise you're stuck with _FP_MUL_MEAT_n_hard(t,R,X,Y) which + * does bitshifting to avoid overflow. + * For division there is FP_DIV_MEAT_n_imm(t,R,X,Y,f) for word size + * >= 2*fracbits, where f is either _FP_DIV_HELP_imm or + * _FP_DIV_HELP_ldiv (see op-1.h). + * _FP_DIV_MEAT_udiv() is if you have asm to do 2W/1W => (1W, 1W). + * [GCC and glibc have longlong.h which has the asm macro udiv_qrnnd + * to do this.] + * In general, 'n' is the number of words required to hold the type, + * and 't' is either S, D or Q for single/double/quad. + * -- PMM + */ +/* Example: SPARC64: + * #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) + * + * Example: i386: + * #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,_i386_mul_32_64) + * #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,_i386_mul_32_64) + * + * #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y,_i386_div_64_32) + * #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y) + */ + +#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm) + +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) +#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y) + +/* These macros define what NaN looks like. They're supposed to expand to + * a comma-separated set of 32bit unsigned ints that encode NaN. + */ +#define _FP_NANFRAC_S _FP_QNANBIT_S +#define _FP_NANFRAC_D _FP_QNANBIT_D, 0 +#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0 + +#define _FP_KEEPNANFRACP 1 + +/* This macro appears to be called when both X and Y are NaNs, and + * has to choose one and copy it to R. i386 goes for the larger of the + * two, sparc64 just picks Y. I don't understand this at all so I'll + * go with sparc64 because it's shorter :-> -- PMM + */ +#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) + + +extern void fp_unpack_d(long *, unsigned long *, unsigned long *, + long *, long *, void *); +extern int fp_pack_d(void *, long, unsigned long, unsigned long, long, long); +extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long); + +#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_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_UNPACK_S(X,val) \ + do { \ + __FP_UNPACK_RAW_1(S,X,val); \ + _FP_UNPACK_CANONICAL(S,1,X); \ + } while (0) + +#define __FP_UNPACK_D(X,val) \ + fp_unpack_d(&X##_s, &X##_f1, &X##_f0, &X##_e, &X##_c, val) + +#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_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) + +#include +#include + +#define __FPU_FPSCR (current->tss.fpscr) + +/* We only actually write to the destination register + * if exceptions signalled (if any) will not trap. + */ +#define __FPU_ENABLED_EXC \ +({ \ + (__FPU_FPSCR >> 3) & 0x1f; \ +}) + +#define __FPU_TRAP_P(bits) \ + ((__FPU_ENABLED_EXC & (bits)) != 0) + +#define __FP_PACK_S(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(S,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(S,val,X); \ + __exc; \ +}) + +#define __FP_PACK_D(val,X) \ + fp_pack_d(val, X##_s, X##_f1, X##_f0, X##_e, X##_c) + +#define __FP_PACK_DS(val,X) \ + fp_pack_ds(val, X##_s, X##_f1, X##_f0, X##_e, X##_c) + +/* Obtain the current rounding mode. */ +#define FP_ROUNDMODE \ +({ \ + __FPU_FPSCR & 0x3; \ +}) + +/* the asm fragments go here: all these are taken from glibc-2.0.5's + * stdlib/longlong.h + */ + +#include +#include + +/* add_ssaaaa is used in op-2.h and should be equivalent to + * #define add_ssaaaa(sh,sl,ah,al,bh,bl) (sh = ah+bh+ (( sl = al+bl) < al)) + * add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, + * high_addend_2, low_addend_2) adds two UWtype integers, composed by + * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 + * respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow + * (i.e. carry out) is not stored anywhere, and is lost. + */ +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + } while (0) + +/* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to + * #define sub_ddmmss(sh, sl, ah, al, bh, bl) (sh = ah-bh - ((sl = al-bl) > al)) + * sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, + * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, + * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and + * LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE + * and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + * and is lost. + */ +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + } while (0) + +/* asm fragments for mul and div */ + +/* umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two + * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype + * word product in HIGH_PROD and LOW_PROD. + */ +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhwu %0,%1,%2" \ + : "=r" ((USItype)(ph)) \ + : "%r" (__m0), \ + "r" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) + +/* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + * denominator) divides a UDWtype, composed by the UWtype integers + * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient + * in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less + * than DENOMINATOR for correct operation. If, in addition, the most + * significant bit of DENOMINATOR must be 1, then the pre-processor symbol + * UDIV_NEEDS_NORMALIZATION is defined to 1. + */ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* 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 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __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 + +/* Exception flags. */ +#define EFLAG_INVALID (1 << (31 - 2)) +#define EFLAG_OVERFLOW (1 << (31 - 3)) +#define EFLAG_UNDERFLOW (1 << (31 - 4)) +#define EFLAG_DIVZERO (1 << (31 - 5)) +#define EFLAG_INEXACT (1 << (31 - 6)) + +#define EFLAG_VXSNAN (1 << (31 - 7)) +#define EFLAG_VXISI (1 << (31 - 8)) +#define EFLAG_VXIDI (1 << (31 - 9)) +#define EFLAG_VXZDZ (1 << (31 - 10)) +#define EFLAG_VXIMZ (1 << (31 - 11)) +#define EFLAG_VXVC (1 << (31 - 12)) +#define EFLAG_VXSOFT (1 << (31 - 21)) +#define EFLAG_VXSQRT (1 << (31 - 22)) +#define EFLAG_VXCVI (1 << (31 - 23)) diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/single.h linux/arch/ppc/math-emu/single.h --- v2.3.15/linux/arch/ppc/math-emu/single.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/single.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,66 @@ +/* + * Definitions for IEEE Single Precision + */ + +#if _FP_W_TYPE_SIZE < 32 +#error "Here's a nickel 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.3.15/linux/arch/ppc/math-emu/soft-fp.h linux/arch/ppc/math-emu/soft-fp.h --- v2.3.15/linux/arch/ppc/math-emu/soft-fp.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/soft-fp.h Tue Aug 31 11:36:43 1999 @@ -0,0 +1,104 @@ +#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 +#ifndef FP_ROUNDMODE +# define FP_ROUNDMODE FP_RND_NEAREST +#endif +#endif + +#define _FP_ROUND_NEAREST(wc, X) \ +({ int __ret = 0; \ + int __frac = _FP_FRAC_LOW_##wc(X) & 15; \ + if (__frac & 7) { \ + __ret = EFLAG_INEXACT; \ + if ((__frac & 7) != _FP_WORK_ROUND) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ + else if (__frac & _FP_WORK_LSB) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ + } \ + __ret; \ +}) + +#define _FP_ROUND_ZERO(wc, X) \ +({ int __ret = 0; \ + if (_FP_FRAC_LOW_##wc(X) & 7) \ + __ret = EFLAG_INEXACT; \ + __ret; \ +}) + +#define _FP_ROUND_PINF(wc, X) \ +({ int __ret = EFLAG_INEXACT; \ + if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ + else __ret = 0; \ + __ret; \ +}) + +#define _FP_ROUND_MINF(wc, X) \ +({ int __ret = EFLAG_INEXACT; \ + if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ + else __ret = 0; \ + __ret; \ +}) + +#define _FP_ROUND(wc, X) \ +({ int __ret = 0; \ + switch (FP_ROUNDMODE) \ + { \ + case FP_RND_NEAREST: \ + __ret |= _FP_ROUND_NEAREST(wc,X); \ + break; \ + case FP_RND_ZERO: \ + __ret |= _FP_ROUND_ZERO(wc,X); \ + break; \ + case FP_RND_PINF: \ + __ret |= _FP_ROUND_PINF(wc,X); \ + break; \ + case FP_RND_MINF: \ + __ret |= _FP_ROUND_MINF(wc,X); \ + break; \ + }; \ + __ret; \ +}) + +#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.3.15/linux/arch/ppc/math-emu/stfd.c linux/arch/ppc/math-emu/stfd.c --- v2.3.15/linux/arch/ppc/math-emu/stfd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/stfd.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,23 @@ +/* $Id: stfd.c,v 1.1 1999/08/23 19:00:33 cort Exp $ + */ + +#include +#include +#include + +int +stfd(void *frS, void *ea) +{ +#if 0 +#ifdef DEBUG + printk("%s: S %p, ea %p: ", __FUNCTION__, frS, ea); + dump_double(frS); + printk("\n"); +#endif +#endif + + if (copy_to_user(ea, frS, sizeof(double))) + return -EFAULT; + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/stfiwx.c linux/arch/ppc/math-emu/stfiwx.c --- v2.3.15/linux/arch/ppc/math-emu/stfiwx.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/stfiwx.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,19 @@ +/* $Id: stfiwx.c,v 1.1 1999/08/23 19:00:34 cort Exp $ + */ + +#include +#include +#include + +int +stfiwx(u32 *frS, void *ea) +{ +#ifdef DEBUG + printk("%s: %p %p\n", __FUNCTION__, frS, ea); +#endif + + if (copy_to_user(ea, &frS[1], sizeof(frS[1]))) + return -EFAULT; + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/stfs.c linux/arch/ppc/math-emu/stfs.c --- v2.3.15/linux/arch/ppc/math-emu/stfs.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/stfs.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,44 @@ +/* $Id: stfs.c,v 1.1 1999/08/23 19:00:35 cort Exp $ + */ + +#include +#include +#include + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +stfs(void *frS, void *ea) +{ + FP_DECL_D(A); + FP_DECL_S(R); + float f; + int err; + +#ifdef DEBUG + printk("%s: S %p, ea %p\n", __FUNCTION__, frS, ea); +#endif + + __FP_UNPACK_D(A, frS); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); +#endif + + FP_CONV(S, D, 1, 2, R, A); + +#ifdef DEBUG + printk("R: %ld %lu %ld (%ld)\n", R_s, R_f, R_e, R_c); +#endif + + err = _FP_PACK_CANONICAL(S, 1, R); + if (!err || !__FPU_TRAP_P(err)) { + __FP_PACK_RAW_1(S, &f, R); + if (copy_to_user(ea, &f, sizeof(float))) + return -EFAULT; + } + + return err; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/types.c linux/arch/ppc/math-emu/types.c --- v2.3.15/linux/arch/ppc/math-emu/types.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/types.c Tue Aug 31 11:36:43 1999 @@ -0,0 +1,52 @@ + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +void +fp_unpack_d(long *_s, unsigned long *_f1, unsigned long *_f0, + long *_e, long *_c, void *val) +{ + FP_DECL_D(X); + + __FP_UNPACK_RAW_2(D, X, val); + + _FP_UNPACK_CANONICAL(D, 2, X); + + *_s = X_s; + *_f1 = X_f1; + *_f0 = X_f0; + *_e = X_e; + *_c = X_c; +} + +int +fp_pack_d(void *val, long X_s, unsigned long X_f1, + unsigned long X_f0, long X_e, long X_c) +{ + int exc; + + exc = _FP_PACK_CANONICAL(D, 2, X); + if (!exc || !__FPU_TRAP_P(exc)) + __FP_PACK_RAW_2(D, val, X); + return exc; +} + +int +fp_pack_ds(void *val, long X_s, unsigned long X_f1, + unsigned long X_f0, long X_e, long X_c) +{ + FP_DECL_S(__X); + int exc; + + FP_CONV(S, D, 1, 2, __X, X); + exc = _FP_PACK_CANONICAL(S, 1, __X); + if (!exc || !__FPU_TRAP_P(exc)) { + _FP_UNPACK_CANONICAL(S, 1, __X); + FP_CONV(D, S, 2, 1, X, __X); + exc |= _FP_PACK_CANONICAL(D, 2, X); + if (!exc || !__FPU_TRAP_P(exc)) + __FP_PACK_RAW_2(D, val, X); + } + return exc; +} diff -u --recursive --new-file v2.3.15/linux/arch/ppc/math-emu/udivmodti4.c linux/arch/ppc/math-emu/udivmodti4.c --- v2.3.15/linux/arch/ppc/math-emu/udivmodti4.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/math-emu/udivmodti4.c Tue Aug 31 11:36:43 1999 @@ -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.3.15/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.3.15/linux/arch/ppc/mm/fault.c Fri Jul 23 12:20:23 1999 +++ linux/arch/ppc/mm/fault.c Tue Aug 31 11:36:43 1999 @@ -82,20 +82,16 @@ return; } #endif - if (in_interrupt() || !mm) { + if (in_interrupt()) { static int complained; if (complained < 20) { ++complained; printk("page fault in interrupt handler, addr=%lx\n", address); show_regs(regs); -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - if (debugger_kernel_faults) - debugger(regs); -#endif } } - if (current == NULL) { + if (current == NULL || mm == NULL) { bad_page_fault(regs, address); return; } @@ -161,6 +157,7 @@ bad_page_fault(struct pt_regs *regs, unsigned long address) { unsigned long fixup; + if (user_mode(regs)) { force_sig(SIGSEGV, current); return; @@ -174,11 +171,11 @@ /* kernel has accessed a bad area */ show_regs(regs); - print_backtrace( (unsigned long *)regs->gpr[1] ); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_kernel_faults) debugger(regs); #endif + print_backtrace( (unsigned long *)regs->gpr[1] ); panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d", regs->nip,regs->link,address,current->comm,current->pid); } diff -u --recursive --new-file v2.3.15/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.15/linux/arch/ppc/mm/init.c Sun Jul 25 13:45:25 1999 +++ linux/arch/ppc/mm/init.c Tue Aug 31 11:36:43 1999 @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.171 1999/07/08 23:20:14 cort Exp $ + * $Id: init.c,v 1.180 1999/08/31 06:54:13 davem Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -51,10 +51,9 @@ #include #include #include -/* APUS includes */ #include #include -/* END APUS includes */ +#include int prom_trashed; atomic_t next_mmu_context; @@ -66,6 +65,7 @@ extern char __init_begin, __init_end; extern char __prep_begin, __prep_end; extern char __pmac_begin, __pmac_end; +extern char __apus_begin, __apus_end; extern char __openfirmware_begin, __openfirmware_end; char *klimit = _end; struct device_node *memory_node; @@ -84,6 +84,7 @@ unsigned long *prep_find_end_of_memory(void); unsigned long *pmac_find_end_of_memory(void); unsigned long *apus_find_end_of_memory(void); +unsigned long *gemini_find_end_of_memory(void); extern unsigned long *find_end_of_memory(void); #ifdef CONFIG_MBX unsigned long *mbx_find_end_of_memory(void); @@ -126,6 +127,7 @@ unsigned long _SDR1; #endif static void hash_init(void); + union ubat { /* BAT register values to be loaded */ BAT bat; #ifdef CONFIG_PPC64 @@ -140,8 +142,38 @@ unsigned long limit; unsigned long phys; } bat_addrs[4]; -unsigned long inline v_mapped_by_bats(unsigned long); -unsigned long inline p_mapped_by_bats(unsigned long); + +/* + * Return PA for this VA if it is mapped by a BAT, or 0 + */ +static inline unsigned long v_mapped_by_bats(unsigned long va) +{ + int b; + for (b = 0; b < 4; ++b) + if (va >= bat_addrs[b].start && va < bat_addrs[b].limit) + return bat_addrs[b].phys + (va - bat_addrs[b].start); + return 0; +} + +/* + * Return VA for a given PA or 0 if not mapped + */ +static inline unsigned long p_mapped_by_bats(unsigned long pa) +{ + int b; + for (b = 0; b < 4; ++b) + if (pa >= bat_addrs[b].phys + && pa < (bat_addrs[b].limit-bat_addrs[b].start) + +bat_addrs[b].phys) + return bat_addrs[b].start+(pa-bat_addrs[b].phys); + return 0; +} + +#else /* CONFIG_8xx */ + +/* 8xx doesn't have BATs */ +#define v_mapped_by_bats(x) (0UL) +#define p_mapped_by_bats(x) (0UL) #endif /* CONFIG_8xx */ /* @@ -151,8 +183,6 @@ */ int __map_without_bats = 0; -/* optimization for 603 to load the tlb directly from the linux table -- Cort */ -#define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */ void __bad_pte(pmd_t *pmd) { @@ -162,10 +192,12 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) { - pte_t *pte/* = (pte_t *) __get_free_page(GFP_KERNEL)*/; + pte_t *pte; if (pmd_none(*pmd)) { - if ( (pte = (pte_t *) get_zero_page_fast()) == NULL ) + if (!mem_init_done) + pte = (pte_t *) MMU_get_page(); + else if ((pte = (pte_t *) get_zero_page_fast()) == NULL) if ((pte = (pte_t *) __get_free_page(GFP_KERNEL))) clear_page((unsigned long)pte); if (pte) { @@ -175,7 +207,6 @@ pmd_val(*pmd) = (unsigned long)BAD_PAGETABLE; return NULL; } - /*free_page((unsigned long)pte);*/ if (pmd_bad(*pmd)) { __bad_pte(pmd); return NULL; @@ -258,7 +289,7 @@ #ifdef CONFIG_NET show_net_buffers(); #endif - printk("%-8s %3s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Cnt", + printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Ctx", "Ctx<<4", "Last Sys", "pc", "task"); #ifdef __SMP__ printk(" %3s", "CPU"); @@ -266,14 +297,13 @@ printk("\n"); for_each_task(p) { - printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ", + printk("%-8.8s %3d %8ld %8ld %8ld %c%08lx %08lx ", p->comm,p->pid, - (p->mm)?atomic_read(&p->mm->count):0, (p->mm)?p->mm->context:0, (p->mm)?(p->mm->context<<4):0, - p->tss.last_syscall, - (p->tss.regs)?user_mode(p->tss.regs) ? 'u' : 'k' : '?', - (p->tss.regs)?p->tss.regs->nip:0, + p->thread.last_syscall, + (p->thread.regs)?user_mode(p->thread.regs) ? 'u' : 'k' : '?', + (p->thread.regs)?p->thread.regs->nip:0, (ulong)p); { int iscur = 0; @@ -369,7 +399,6 @@ if (size == 0) return NULL; -#ifndef CONFIG_8xx /* * Is it already mapped? Perhaps overlapped by a previous * BAT mapping. If the whole area is mapped then we're done, @@ -381,9 +410,8 @@ * same virt address (and this is contiguous). * -- Cort */ - if ( (v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ ) + if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ ) goto out; -#endif /* CONFIG_8xx */ if (mem_init_done) { struct vm_struct *area; @@ -403,11 +431,9 @@ if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU)) flags |= _PAGE_GUARDED; -#ifndef CONFIG_8xx /* * Is it a candidate for a BAT mapping? */ -#endif /* CONFIG_8xx */ for (i = 0; i < size; i += PAGE_SIZE) map_page(&init_task, v+i, p+i, flags); @@ -422,27 +448,15 @@ unsigned long iopa(unsigned long addr) { - unsigned long idx; + unsigned long pa; pmd_t *pd; pte_t *pg; -#ifndef CONFIG_8xx - int b; -#endif - idx = addr & ~PAGE_MASK; - addr = addr & PAGE_MASK; -#ifndef CONFIG_8xx /* Check the BATs */ - for (b = 0; b < 4; ++b) - if (addr >= bat_addrs[b].start && addr <= bat_addrs[b].limit) -#ifndef CONFIG_APUS - return bat_addrs[b].phys | idx; -#else - /* Do a more precise remapping of virtual address */ - /* --Carsten */ - return (bat_addrs[b].phys - bat_addrs[b].start + addr) | idx; -#endif /* CONFIG_APUS */ -#endif /* CONFIG_8xx */ + pa = v_mapped_by_bats(addr); + if (pa) + return pa; + /* Do we have a page table? */ if (init_mm.pgd == NULL) return 0; @@ -454,36 +468,21 @@ /* Use middle 10 bits of addr to index the second-level map */ pg = pte_offset(pd, addr); - return (pte_val(*pg) & PAGE_MASK) | idx; + return (pte_val(*pg) & PAGE_MASK) | (addr & ~PAGE_MASK); } void map_page(struct task_struct *tsk, unsigned long va, unsigned long pa, int flags) { - pmd_t *pd; - pte_t *pg; - - if (tsk->mm->pgd == NULL) { - /* Allocate upper level page map */ - tsk->mm->pgd = (pgd_t *) MMU_get_page(); - } - /* 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)) { - if ( v_mapped_by_bats(va) ) - return; - pg = (pte_t *) MMU_get_page(); - pmd_val(*pd) = (unsigned long) pg; - } - /* Use middle 10 bits of VA to index the second-level map */ - pg = pte_offset(pd, va); - set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); -#ifndef CONFIG_8xx + pte_t * pte; + + pte = pte_alloc(pmd_offset(pgd_offset_k(va), va), va); + set_pte(pte, mk_pte_phys(pa, __pgprot(flags))); flush_hash_page(0, va); -#endif } +#ifndef CONFIG_8xx /* * TLB flushing: * @@ -504,12 +503,8 @@ void local_flush_tlb_all(void) { -#ifndef CONFIG_8xx __clear_user(Hash, Hash_size); _tlbia(); -#else - asm volatile ("tlbia" : : ); -#endif } /* @@ -520,26 +515,18 @@ void local_flush_tlb_mm(struct mm_struct *mm) { -#ifndef CONFIG_8xx mm->context = NO_CONTEXT; if (mm == current->mm) - activate_context(current); -#else - asm volatile ("tlbia" : : ); -#endif + activate_mm(mm, mm); } void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { -#ifndef CONFIG_8xx if (vmaddr < TASK_SIZE) flush_hash_page(vma->vm_mm->context, vmaddr); else flush_hash_page(0, vmaddr); -#else - asm volatile ("tlbia" : : ); -#endif } @@ -553,7 +540,6 @@ void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { -#ifndef CONFIG_8xx start &= PAGE_MASK; if (end - start > 20 * PAGE_SIZE) @@ -566,9 +552,6 @@ { flush_hash_page(mm->context, start); } -#else - asm volatile ("tlbia" : : ); -#endif } /* @@ -580,7 +563,6 @@ void mmu_context_overflow(void) { -#ifndef CONFIG_8xx struct task_struct *tsk; printk(KERN_DEBUG "mmu_context_overflow\n"); @@ -595,19 +577,13 @@ /* make sure current always has a context */ current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context)); set_context(current->mm->context); -#else - /* We set the value to -1 because it is pre-incremented before - * before use. - */ - atomic_set(&next_mmu_context, -1); -#endif } +#endif /* CONFIG_8xx */ /* * Scan a region for a piece of a given size with the required alignment. */ -__initfunc(void * -find_mem_piece(unsigned size, unsigned align)) +void __init *find_mem_piece(unsigned size, unsigned align) { int i; unsigned a, e; @@ -630,9 +606,9 @@ /* * Remove some memory from an array of pieces */ -__initfunc(static void +static void __init remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size, - int must_exist)) + int must_exist) { int i, j; unsigned end, rs, re; @@ -686,7 +662,7 @@ } } -__initfunc(static void print_mem_pieces(struct mem_pieces *mp)) +static void __init print_mem_pieces(struct mem_pieces *mp) { int i; @@ -699,8 +675,8 @@ /* * Add some memory to an array of pieces */ -__initfunc(static void - append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)) +static void __init +append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size) { struct reg_property *rp; @@ -717,34 +693,7 @@ static void sort_mem_pieces(struct mem_pieces *); static void coalesce_mem_pieces(struct mem_pieces *); -/* - * Return 1 if this VA is mapped by BATs - */ -unsigned long inline v_mapped_by_bats(unsigned long va) -{ - int b; - for (b = 0; b < 4; ++b) - if (va >= bat_addrs[b].start - && va < bat_addrs[b].limit) - return 1; - return 0; -} - -/* - * Return VA for a given PA or 0 if not mapped - */ -unsigned long inline p_mapped_by_bats(unsigned long pa) -{ - int b; - for (b = 0; b < 4; ++b) - if (pa >= bat_addrs[b].phys - && pa < (bat_addrs[b].limit-bat_addrs[b].start) - +bat_addrs[b].phys) - return bat_addrs[b].start+(pa-bat_addrs[b].phys); - return 0; -} - -__initfunc(static void sort_mem_pieces(struct mem_pieces *mp)) +static void __init sort_mem_pieces(struct mem_pieces *mp) { unsigned long a, s; int i, j; @@ -762,7 +711,7 @@ } } -__initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp)) +static void __init coalesce_mem_pieces(struct mem_pieces *mp) { unsigned long a, s, ns; int i, j, d; @@ -788,7 +737,7 @@ * Read in a property describing some pieces of memory. */ -__initfunc(static void get_mem_prop(char *name, struct mem_pieces *mp)) +static void __init get_mem_prop(char *name, struct mem_pieces *mp) { struct reg_property *rp; int s; @@ -807,16 +756,13 @@ coalesce_mem_pieces(mp); } -#endif /* CONFIG_8xx */ - -#ifndef CONFIG_8xx /* * 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. */ -__initfunc(void setbat(int index, unsigned long virt, unsigned long phys, - unsigned int size, int flags)) +void __init setbat(int index, unsigned long virt, unsigned long phys, + unsigned int size, int flags) { unsigned int bl; int wimgxpp; @@ -870,7 +816,7 @@ */ #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) -__initfunc(static void mapin_ram(void)) +static void __init mapin_ram(void) { int i; unsigned long v, p, s, f; @@ -922,15 +868,22 @@ /* 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 /* CONFIG_8xx */ - for (i = 0; i < phys_mem.n_regions; ++i) { - v = (ulong)__va(phys_mem.regions[i].address); - p = phys_mem.regions[i].address; - for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { + + for (i = 0; i < phys_mem.n_regions; ++i) { + v = (ulong)__va(phys_mem.regions[i].address); + p = phys_mem.regions[i].address; + for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { /* On the MPC8xx, we want the page shared so we * don't get ASID compares on kernel space. */ - f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; + f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; /* I don't really need the rest of this code, but * I grabbed it because I think the line: @@ -940,18 +893,18 @@ * the MPC8xx, the PAGE_DIRTY takes care of that * for us (along with the RW software state). */ - if ((char *) v < _stext || (char *) v >= etext) - f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; -#endif /* CONFIG_8xx */ + if ((char *) v < _stext || (char *) v >= etext) + f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; map_page(&init_task, v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; } } +#endif /* CONFIG_8xx */ } -/* This can get called from ioremap, so don't make it an initfunc, OK? */ -static void *MMU_get_page(void) +/* This can get called from ioremap, so don't make it an __init, OK? */ +static void __init *MMU_get_page(void) { void *p; @@ -966,11 +919,12 @@ return p; } -__initfunc(void free_initmem(void)) +void __init free_initmem(void) { unsigned long a; unsigned long num_freed_pages = 0, num_prep_pages = 0, - num_pmac_pages = 0, num_openfirmware_pages = 0; + num_pmac_pages = 0, num_openfirmware_pages = 0, + num_apus_pages = 0; #define FREESEC(START,END,CNT) do { \ a = (unsigned long)(&START); \ for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ @@ -985,16 +939,24 @@ switch (_machine) { case _MACH_Pmac: + FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; case _MACH_chrp: + FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; case _MACH_prep: + FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); break; case _MACH_mbx: + FREESEC(__apus_begin,__apus_end,num_apus_pages); + FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); + FREESEC(__prep_begin,__prep_end,num_prep_pages); + break; + case _MACH_apus: FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; @@ -1012,6 +974,8 @@ printk(" %ldk pmac",(num_pmac_pages*PAGE_SIZE)>>10); if ( num_openfirmware_pages ) printk(" %ldk open firmware",(num_openfirmware_pages*PAGE_SIZE)>>10); + if ( num_apus_pages ) + printk(" %ldk apus",(num_apus_pages*PAGE_SIZE)>>10); printk("\n"); } @@ -1022,7 +986,7 @@ * still be merged. * -- Cort */ -__initfunc(void MMU_init(void)) +void __init MMU_init(void) { #ifdef __SMP__ if ( first_cpu_booted ) return; @@ -1035,6 +999,8 @@ else if (_machine == _MACH_apus ) end_of_DRAM = apus_find_end_of_memory(); #endif + else if ( _machine == _MACH_gemini ) + end_of_DRAM = gemini_find_end_of_memory(); else /* prep */ end_of_DRAM = prep_find_end_of_memory(); @@ -1083,6 +1049,10 @@ (kernel_map) remaps individual IO regions to 0x90000000. */ break; + case _MACH_gemini: + setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + break; } ioremap_bot = ioremap_base; #else /* CONFIG_8xx */ @@ -1114,7 +1084,7 @@ * that setup_arch returns, making sure that there are at * least 32 pages unused before this for MMU_get_page to use. */ -__initfunc(unsigned long find_available_memory(void)) +unsigned long __init find_available_memory(void) { int i, rn; unsigned long a, free; @@ -1150,7 +1120,7 @@ /* * paging_init() sets up the page tables - in fact we've already done this. */ -__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) { extern unsigned long free_area_init(unsigned long, unsigned long); /* @@ -1166,7 +1136,7 @@ return start_mem; } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { unsigned long addr; int i; @@ -1262,7 +1232,7 @@ * functions in the image just to get prom_init, all we really need right * now is the initialization of the physical memory region. */ -__initfunc(unsigned long *mbx_find_end_of_memory(void)) +unsigned long __init *mbx_find_end_of_memory(void) { unsigned long kstart, ksize; bd_t *binfo; @@ -1299,6 +1269,7 @@ return ret; } #endif /* CONFIG_MBX */ + #ifndef CONFIG_8xx /* * On systems with Open Firmware, collect information about @@ -1307,7 +1278,7 @@ * Our text, data, bss use something over 1MB, starting at 0. * Open Firmware may be using 1MB at the 4MB point. */ -__initfunc(unsigned long *pmac_find_end_of_memory(void)) +unsigned long __init *pmac_find_end_of_memory(void) { unsigned long a, total; unsigned long kstart, ksize; @@ -1399,7 +1370,7 @@ * this will likely stay separate from the pmac. * -- Cort */ -__initfunc(unsigned long *prep_find_end_of_memory(void)) +unsigned long __init *prep_find_end_of_memory(void) { unsigned long kstart, ksize; unsigned long total; @@ -1425,9 +1396,30 @@ return (__va(total)); } +unsigned long __init *gemini_find_end_of_memory(void) +{ + unsigned long total, kstart, ksize, *ret; + unsigned char reg; + + reg = readb(GEMINI_MEMCFG); + total = ((1<<((reg & 0x7) - 1)) * + (8<<((reg >> 3) & 0x7))); + total *= (1024*1024); + phys_mem.regions[0].address = 0; + phys_mem.regions[0].size = total; + phys_mem.n_regions = 1; + + ret = __va(phys_mem.regions[0].size); + phys_avail = phys_mem; + kstart = __pa(_stext); + ksize = PAGE_ALIGN( _end - _stext ); + remove_mem_piece( &phys_avail, kstart, ksize, 0 ); + return ret; +} + #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) -__initfunc(unsigned long *apus_find_end_of_memory(void)) +unsigned long __init *apus_find_end_of_memory(void) { int shadow = 0; @@ -1505,7 +1497,7 @@ /* * Initialize the hash table and patch the instructions in head.S. */ -__initfunc(static void hash_init(void)) +static void __init hash_init(void) { int Hash_bits; unsigned long h, ramsize; @@ -1532,7 +1524,6 @@ Hash_mask = (h >> 6) - 1; #endif -#ifdef NO_RELOAD_HTAB /* shrink the htab since we don't use it on 603's -- Cort */ switch (_get_PVR()>>16) { case 3: /* 603 */ @@ -1545,7 +1536,6 @@ /* on 601/4 let things be */ break; } -#endif /* NO_RELOAD_HTAB */ if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322); /* Find some memory for the hash table. */ @@ -1558,12 +1548,6 @@ ramsize >> 20, Hash_size >> 10, Hash); if ( Hash_size ) { -#ifdef CONFIG_APUS -#define b(x) ((unsigned int*)(((unsigned long)(x)) - KERNELBASE + 0xfff00000)) -#else -#define b(x) (x) -#endif - Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); __clear_user(Hash, Hash_size); @@ -1572,20 +1556,20 @@ * Patch up the instructions in head.S:hash_page */ Hash_bits = ffz(~Hash_size) - 6; - *b(hash_page_patch_A) = (*b(hash_page_patch_A) & ~0xffff) + hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) | (__pa(Hash) >> 16); - *b(hash_page_patch_A + 1) = (*b(hash_page_patch_A + 1)& ~0x7c0) + hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | ((26 - Hash_bits) << 6); if (Hash_bits > 16) Hash_bits = 16; - *b(hash_page_patch_A + 2) = (*b(hash_page_patch_A + 2)& ~0x7c0) + hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | ((26 - Hash_bits) << 6); - *b(hash_page_patch_B) = (*b(hash_page_patch_B) & ~0xffff) + hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) | (Hash_mask >> 10); - *b(hash_page_patch_C) = (*b(hash_page_patch_C) & ~0xffff) + hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | (Hash_mask >> 10); #if 0 /* see hash_page in head.S, note also patch_C ref below */ - *b(hash_page_patch_D) = (*b(hash_page_patch_D) & ~0xffff) + hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff) | (Hash_mask >> 10); #endif /* @@ -1593,8 +1577,8 @@ * out from the data cache and invalidated in the instruction * cache, on those machines with split caches. */ - flush_icache_range((unsigned long) b(hash_page_patch_A), - (unsigned long) b(hash_page_patch_C + 1)); + flush_icache_range((unsigned long) &hash_page_patch_A[0], + (unsigned long) &hash_page_patch_C[1]); } else { Hash_end = 0; @@ -1603,9 +1587,9 @@ * start of hash_page, since we can still get DSI * exceptions on a 603. */ - *b(hash_page) = 0x4e800020; - flush_icache_range((unsigned long) b(hash_page), - (unsigned long) b(hash_page + 1)); + hash_page[0] = 0x4e800020; + flush_icache_range((unsigned long) &hash_page[0], + (unsigned long) &hash_page[1]); } if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } diff -u --recursive --new-file v2.3.15/linux/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds --- v2.3.15/linux/arch/ppc/vmlinux.lds Wed Dec 30 10:55:07 1998 +++ linux/arch/ppc/vmlinux.lds Tue Aug 31 11:36:43 1999 @@ -70,10 +70,24 @@ . = ALIGN(4096); __init_begin = .; .text.init : { *(.text.init) } - .data.init : { *(.data.init) } + .data.init : { + *(.data.init); + __vtop_table_begin = .; + *(.vtop_fixup); + __vtop_table_end = .; + __ptov_table_begin = .; + *(.ptov_fixup); + __ptov_table_end = .; + } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; - . = ALIGN(4096); __pmac_begin = .; .text.pmac : { *(.text.pmac) } @@ -87,6 +101,13 @@ .data.prep : { *(.data.prep) } . = ALIGN(4096); __prep_end = .; + + . = ALIGN(4096); + __apus_begin = .; + .text.apus : { *(.text.apus) } + .data.apus : { *(.data.apus) } + . = ALIGN(4096); + __apus_end = .; . = ALIGN(4096); __openfirmware_begin = .; diff -u --recursive --new-file v2.3.15/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.3.15/linux/arch/ppc/xmon/start.c Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/xmon/start.c Tue Aug 31 11:36:43 1999 @@ -13,7 +13,7 @@ unsigned long TXRDY, RXRDY; extern void xmon_printf(const char *fmt, ...); -static int console = 0; +static int console = 1; void buf_access(void) { diff -u --recursive --new-file v2.3.15/linux/arch/ppc/xmon/subr_prf.c linux/arch/ppc/xmon/subr_prf.c --- v2.3.15/linux/arch/ppc/xmon/subr_prf.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/xmon/subr_prf.c Tue Aug 31 11:36:43 1999 @@ -1,6 +1,7 @@ /* - * Written by Cort Dougan to replace the version written by - * Paul Mackerras that had copyright conflicts with Linux. + * Written by Cort Dougan to replace the version originally used + * by Paul Mackerras, which came from NetBSD and thus had copyright + * conflicts with Linux. * * This file makes liberal use of the standard linux utility * routines to reduce the size of the binary. We assume we can @@ -20,9 +21,11 @@ void xmon_vfprintf(void *f, const char *fmt, va_list ap) { - char buf[2048]; - vsprintf( buf, fmt, ap ); - xmon_write( f, buf, strlen(buf) ); + static char xmon_buf[2048]; + int n; + + n = vsprintf(xmon_buf, fmt, ap); + xmon_write(f, xmon_buf, n); } void diff -u --recursive --new-file v2.3.15/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.3.15/linux/arch/ppc/xmon/xmon.c Mon Jun 28 13:40:39 1999 +++ linux/arch/ppc/xmon/xmon.c Tue Aug 31 11:36:43 1999 @@ -116,13 +116,11 @@ struct pt_regs regs; int msr, cmd; - printk("Entering xmon kernel debugger.\n"); - if (excp == NULL) { asm volatile ("stw 0,0(%0)\n\ lwz 0,0(1)\n\ stw 0,4(%0)\n\ - stmw 2,8(%0)" : : "r" (®s)); + stmw 2,8(%0)" : : "b" (®s)); regs.nip = regs.link = ((unsigned long *)regs.gpr[1])[1]; regs.msr = get_msr(); regs.ctr = get_ctr(); @@ -472,8 +470,9 @@ unsigned sp; unsigned stack[2]; struct pt_regs regs; - extern char int_return, syscall_ret_1, syscall_ret_2; + extern char ret_from_int, ret_from_syscall_1, ret_from_syscall_2; extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; + extern char ret_from_except; if (excp != NULL) sp = excp->gpr[1]; @@ -485,9 +484,10 @@ if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) break; printf("%x ", stack[1]); - if (stack[1] == (unsigned) &int_return - || stack[1] == (unsigned) &syscall_ret_1 - || stack[1] == (unsigned) &syscall_ret_2 + if (stack[1] == (unsigned) &ret_from_int + || stack[1] == (unsigned) &ret_from_except + || stack[1] == (unsigned) &ret_from_syscall_1 + || stack[1] == (unsigned) &ret_from_syscall_2 || stack[1] == (unsigned) &lost_irq_ret || stack[1] == (unsigned) &do_bottom_half_ret || stack[1] == (unsigned) &do_signal_ret) { diff -u --recursive --new-file v2.3.15/linux/arch/sh/Makefile linux/arch/sh/Makefile --- v2.3.15/linux/arch/sh/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/Makefile Mon Aug 30 18:12:59 1999 @@ -0,0 +1,82 @@ +# $Id$ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# + +# +# Select the object file format to substitute into the linker script. +# +tool-prefix = sh-gniibe- +oformat = elf + +ifdef CONFIG_CROSSCOMPILE +CROSS_COMPILE = $(tool-prefix) +endif + +LINKFLAGS = # -EL # -static #-N +MODFLAGS += + +# +# +CFLAGS += -m3 # -ml +LINKFLAGS += +LDFLAGS += # -EL + +# +# +HOSTCC = cc + +# +# Choosing incompatible machines durings configuration will result in +# error messages during linking. Select a default linkscript if +# none has been choosen above. +# +LINKSCRIPT = arch/sh/vmlinux.lds +LINKFLAGS += -T $(word 1,$(LINKSCRIPT)) -e __stext + +ifdef LOADADDR +LINKFLAGS += -Ttext $(word 1,$(LOADADDR)) +endif + +# +CFLAGS += -pipe + +HEAD := arch/sh/kernel/head.o arch/sh/kernel/init_task.o + +SUBDIRS := $(SUBDIRS) $(addprefix arch/sh/, kernel mm lib) +CORE_FILES := arch/sh/kernel/kernel.o arch/sh/mm/mm.o $(CORE_FILES) +LIBS := $(TOPDIR)/arch/sh/lib/lib.a $(LIBS) $(TOPDIR)/arch/sh/lib/lib.a /home/niibe/lib/gcc-lib/sh-gniibe-elf/egcs-2.91.66/libgcc.a + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +vmlinux: arch/sh/vmlinux.lds + +arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE + gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/linux/config.h -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds + +FORCE: ; + +zImage: vmlinux + @$(MAKEBOOT) zImage + +compressed: zImage + +zdisk: vmlinux + @$(MAKEBOOT) zdisk + +archclean: + @$(MAKEBOOT) clean + $(MAKE) -C arch/$(ARCH)/kernel clean +# $(MAKE) -C arch/$(ARCH)/tools clean + +archmrproper: + +archdep: + @$(MAKEBOOT) dep diff -u --recursive --new-file v2.3.15/linux/arch/sh/boot/Makefile linux/arch/sh/boot/Makefile --- v2.3.15/linux/arch/sh/boot/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/boot/Makefile Mon Aug 30 18:12:59 1999 @@ -0,0 +1,41 @@ +# +# arch/mips/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +OBJS = + +# +# Drop some uninteresting sections in the kernel. +# +drop-sections = .reginfo .mdebug +strip-flags = $(addprefix --remove-section=,$(drop-sections)) + +# +# Fake compressed boot +# +zImage: $(CONFIGURE) mkboot $(TOPDIR)/vmlinux + $(OBJCOPY) $(strip-flags) $(TOPDIR)/vmlinux zImage.tmp + ./mkboot zImage.tmp zImage + rm -f zImage.tmp + +mkboot: mkboot.c + $(HOSTCC) -o $@ $^ + +# Don't build dependencies, this may die if $(CC) isn't gcc +dep: + +clean: + rm -f zImage zImage.tmp mkboot + +dummy: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.3.15/linux/arch/sh/config.in Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/config.in Mon Aug 30 18:12:59 1999 @@ -0,0 +1,78 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu_name "Linux/SuperH Kernel Configuration" + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Processor type and features' +choice 'Processor family' \ + "SH3 CONFIG_CPU_SH3 \ + SH4 CONFIG_CPU_SH4" SH3 +bool 'Little Endian' CONFIG_LITTLE_ENDIAN +hex 'Physical memory start address' CONFIG_MEMORY_START 0c000000 +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD +fi +endmenu + +define_bool CONFIG_SERIAL n +define_bool CONFIG_SH3SCI_SERIAL y +define_bool CONFIG_SERIAL_CONSOLE y + +mainmenu_option next_comment +comment 'Floppy, IDE, and other block devices' + +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 ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + +tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then + bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD +fi + +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +tristate 'Network block device support' CONFIG_BLK_DEV_NBD +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +mainmenu_option next_comment +comment 'Unix 98 PTY support' +bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS +if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then + int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 +fi +endmenu + +source fs/Config.in + +mainmenu_option next_comment +comment 'Watchdog' + +tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG +endmenu + +mainmenu_option next_comment +comment 'Kernel hacking' + +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu diff -u --recursive --new-file v2.3.15/linux/arch/sh/defconfig linux/arch/sh/defconfig --- v2.3.15/linux/arch/sh/defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/defconfig Mon Aug 30 18:12:59 1999 @@ -0,0 +1,101 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Processor type and features +# +CONFIG_CPU_SH3=y +# CONFIG_CPU_SH4 is not set +# CONFIG_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0c000000 + +# +# Loadable module support +# +# CONFIG_MODULES is not set +# CONFIG_SERIAL is not set +CONFIG_SH3SCI_SERIAL=y +CONFIG_SERIAL_CONSOLE=y + +# +# Floppy, IDE, and other block devices +# +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_FILTER is not set +# CONFIG_UNIX is not set +# CONFIG_INET is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Unix 98 PTY support +# +# CONFIG_UNIX98_PTYS is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SGI_DISKLABEL is not set +# CONFIG_NLS is not set + +# +# Watchdog +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile --- v2.3.15/linux/arch/sh/kernel/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/Makefile Mon Aug 30 18:12:59 1999 @@ -0,0 +1,27 @@ +# +# Makefile for the Linux/SuperH kernel. +# +# 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). +# + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + +O_TARGET := kernel.o +O_OBJS := process.o signal.o entry.o traps.o irq.o irq_onchip.o \ + ptrace.o setup.o time.o sys_sh.o test-img.o semaphore.o +OX_OBJS := sh_ksyms.o +MX_OBJS := + +all: kernel.o head.o init_task.o + +entry.o: entry.S + +head.o: head.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o + +clean: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.3.15/linux/arch/sh/kernel/entry.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/entry.S Mon Aug 30 18:12:59 1999 @@ -0,0 +1,683 @@ +/* $Id$ + * + * linux/arch/sh/entry.S + * + * Copyright (C) 1999 Niibe Yutaka + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include + +! NOTE: +! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address +! to be jumped is too far, but it causes illegal slot exception. + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * Stack layout in 'ret_from_syscall': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in process.c:copy_thread, signal.c:do_signal, + * ptrace.c and ptrace.h + * + * syscall # + * r0 + * ... + * r15 + * gbr + * mach + * macl + * pr + * ssr + * spc + * + */ + +/* + * these are offsets into the task-struct. + */ +state = 0 +flags = 4 +sigpending = 8 +addr_limit = 12 +need_resched = 20 + +PF_TRACESYS = 0x20 + +ENOSYS = 38 + +TRA = 0xffffffd0 +EXPEVT = 0xffffffd4 +INTEVT = 0xffffffd8 + +/* Offsets to the stack */ +SYSCALL_NR = 0 +R0 = 4 +R15 = 64 + +#define k0 r0 +#define k1 r1 +#define k2 r2 +#define k3 r3 + +#define kernel_sp r4 /* r4_bank1 */ +#define ksp r4_bank /* r4_bank1 */ +#define k_ex_code r2_bank /* r2_bank1 */ + +/* Kernel mode register usage: + k0 scratch + k1 scratch + k2 scratch (Exception code) + k3 scratch (Return address) + k4 Stack base = current+8192 + k5 reserved + k6 reserved + k7 reserved +*/ + +! +! TLB Miss / Initial Page write exception handling +! _and_ +! TLB hits, but the access violate the protection. +! It can be valid access, such as stack grow and/or C-O-W. +! +! +! Find the pmd/pte entry and loadtlb +! If it's not found, cause address error (SEGV) +! +! Although this could be written in assembly language (and it'd be faster), +! this first version depends *much* on C implementation. +! +MMU_TEA = 0xfffffffc ! TLB Exception Address Register + +#define DO_FAULT(write) \ + mov #MMU_TEA,r0; \ + mov.l @r0,r6; \ + /* STI */ \ + mov.l 3f,r1; \ + stc sr,r0; \ + and r1,r0; \ + ldc r0,sr; \ + /* */ \ + mov r15,r4; \ + mov.l 2f,r0; \ + jmp @r0; \ + mov #write,r5; + + .balign 4 +tlb_protection_violation_load: +tlb_miss_load: + mov #-1,r0 + mov.l r0,@r15 ! syscall nr = -1 + DO_FAULT(0) + + .balign 4 +tlb_protection_violation_store: +tlb_miss_store: +initial_page_write: + mov #-1,r0 + mov.l r0,@r15 ! syscall nr = -1 + DO_FAULT(1) + + .balign 4 +2: .long SYMBOL_NAME(do_page_fault) +3: .long 0xefffffff ! BL=0 + + + .balign 4 +error: mov #-1,r0 + ! STI + mov.l 2f,r1 + stc sr,r0 + and r1,r0 + ldc r0,sr + ! + mov.l r0,@r15 ! syscall nr = -1 + mov.l 1f,r1 + jmp @r1 + nop + .balign 4 +1: .long SYMBOL_NAME(do_exception_error) + +reschedule: + mova SYMBOL_NAME(ret_from_syscall),r0 + mov.l 1f,r1 + jmp @r1 + lds r0,pr + .balign 4 +1: .long SYMBOL_NAME(schedule) + +badsys: mov #-ENOSYS,r0 + bra SYMBOL_NAME(ret_from_syscall) + mov.l r0,@(R0,r15) + +signal_return: + ! We can reach here from an interrupt handler, + ! so, we need to unblock interrupt. + mov.l 1f,r1 + stc sr,r0 + and r1,r0 + ldc r0,sr + ! + mov r15,r4 + mov #0,r5 + mov.l 2f,r1 + mova restore_all,r0 + jmp @r1 + lds r0,pr + .balign 4 +1: .long 0xefffffff ! BL=0 +2: .long SYMBOL_NAME(do_signal) + +! +! +! +ENTRY(ret_from_fork) + bra SYMBOL_NAME(ret_from_syscall) + add #4,r15 ! pop down bogus r0 + +! +! The immediate value of "trapa" indicates the number of arguments +! placed on the stack. +! +system_call: + mov #TRA,r2 + mov.l @r2,r8 + ! STI + mov.l 2f,r1 + stc sr,r2 + and r1,r2 + ldc r2,sr + ! + mov.l __n_sys,r1 + cmp/ge r1,r0 + bt badsys + ! + stc ksp,r1 ! + mov.l __tsk_flags,r0 ! + add r0,r1 ! + mov.l @r1,r0 ! Is it trace? + tst #PF_TRACESYS,r0 + bt 6f + ! Trace system call + mov #-ENOSYS,r1 + mov.l r1,@(R0,r15) + mov.l 3f,r1 + jsr @r1 + nop + mova 4f,r0 + bra 7f + lds r0,pr + ! +6: mova 1f,r0 + lds r0,pr + ! Build the stack frame if TRA > 0 +7: cmp/pl r8 + bf 9f + shll2 r8 ! x4 + mov #R15,r0 + mov.l @(r0,r15),r0 ! get original stack +8: add #-4,r8 + mov.l @(r0,r8),r1 + mov.l r1,@-r15 + cmp/pl r8 + bt 8b + ! +9: mov.l @(SYSCALL_NR,r15),r0 + shll2 r0 ! x4 + mov.l __sct,r1 + add r1,r0 + mov.l @r0,r1 + jmp @r1 + nop + .balign 4 +4: mov.l r0,@(R0,r15) ! save the return value + mov.l 3f,r1 + mova SYMBOL_NAME(ret_from_syscall),r0 + jmp @r1 + lds r0,pr + .balign 4 +3: .long SYMBOL_NAME(syscall_trace) +2: .long 0xefffffff ! BL=0 +1: mov.l r0,@(R0,r15) ! save the return value + /* fall through */ + +ENTRY(ret_from_syscall) +ENTRY(ret_from_irq) + mov.l __bh_mask,r0 + mov.l @r0,r1 + mov.l __bh_active,r0 + mov.l @r0,r2 + tst r2,r1 + bt ret_with_reschedule +handle_bottom_half: + mov.l __dbh,r0 + jsr @r0 + nop +ret_with_reschedule: + stc ksp,r1 + mov.l __minus8192,r0 + add r0,r1 + mov.l @(need_resched,r1),r0 + tst #0xff,r0 + bf reschedule + mov.l @(sigpending,r1),r0 + tst #0xff,r0 + bf signal_return + ! + .balign 4 +restore_all: + add #4,r15 ! skip syscall number + mov.l @r15+,r0 + mov.l @r15+,r1 + mov.l @r15+,r2 + mov.l @r15+,r3 + mov.l @r15+,r4 + mov.l @r15+,r5 + mov.l @r15+,r6 + mov.l @r15+,r7 + stc sr,r14 + mov.l __blrb_flags,r9 ! BL =1, RB=1 + or r9,r14 + ldc r14,sr ! here, change the register bank + mov.l @r15+,r8 + mov.l @r15+,r9 + mov.l @r15+,r10 + mov.l @r15+,r11 + mov.l @r15+,r12 + mov.l @r15+,r13 + mov.l @r15+,r14 + mov.l @r15+,k0 + ldc.l @r15+,gbr + lds.l @r15+,mach + lds.l @r15+,macl + lds.l @r15+,pr + ldc.l @r15+,ssr + ldc.l @r15+,spc + mov k0,r15 + rte + nop + + .balign 4 +__n_sys: .long NR_syscalls +__sct: .long SYMBOL_NAME(sys_call_table) +__bh_mask: .long SYMBOL_NAME(bh_mask) +__bh_active: .long SYMBOL_NAME(bh_active) +__dbh: .long SYMBOL_NAME(do_bottom_half) +__blrb_flags: .long 0x30000000 +__minus8192: .long -8192 ! offset from stackbase to tsk +__tsk_flags: .long flags-8192 ! offset from stackbase to tsk->flags + + +! Exception Vector Base +! +! Should be aligned page boundary. +! + .balign 4096,0,4096 +ENTRY(vbr_base) + .long 0 +! + .balign 256,0,256 +general_exception: + mov #EXPEVT,k2 + mov.l 2f,k3 + bra handle_exception + mov.l @k2,k2 + .balign 4 +2: .long SYMBOL_NAME(ret_from_syscall) +! +! + .balign 1024,0,1024 +tlb_miss: + mov #EXPEVT,k2 + mov.l 3f,k3 + bra handle_exception + mov.l @k2,k2 +! + .balign 512,0,512 +interrupt: + mov #INTEVT,k2 + mov.l 4f,k3 + bra handle_exception + mov.l @k2,k2 + + .balign 4 +3: .long SYMBOL_NAME(ret_from_syscall) +4: .long SYMBOL_NAME(ret_from_irq) + +! +! +handle_exception: + ! Using k0, k1 for scratch registers (r0_bank1, and r1_bank1), + ! save all registers onto stack. + ! + mov.l 2f,k1 + stc ssr,k0 ! from kernel space? + shll k0 ! Check MD bit (bit30) + shll k0 + bt/s 1f ! it's from kernel to kernel transition + mov r15,k0 ! save original stack to k0 anyway + mov kernel_sp,r15 ! change to kernel stack +1: stc.l spc,@-r15 ! save control registers + stc.l ssr,@-r15 + sts.l pr,@-r15 + ! + lds k3,pr ! Set the return address to pr + ! + sts.l macl,@-r15 + sts.l mach,@-r15 + stc.l gbr,@-r15 + mov.l k0,@-r15 ! save orignal stack, and general registers + mov.l r14,@-r15 + ! + stc sr,r14 ! back to normal register bank, and + and k1,r14 ! .. + ldc r14,sr ! ...changed here. + ! + mov.l r13,@-r15 + mov.l r12,@-r15 + mov.l r11,@-r15 + mov.l r10,@-r15 + mov.l r9,@-r15 + mov.l r8,@-r15 + mov.l r7,@-r15 + mov.l r6,@-r15 + mov.l r5,@-r15 + mov.l r4,@-r15 + mov.l r3,@-r15 + mov.l r2,@-r15 + mov.l r1,@-r15 + mov.l r0,@-r15 + mov.l r0,@-r15 ! push r0 again (for syscall number) + ! Then, dispatch to the handler, according to the excepiton code. + stc k_ex_code,r1 + shlr2 r1 + shlr r1 + mov.l 1f,r0 + add r1,r0 + mov.l @r0,r0 + jmp @r0 + mov.l @r15,r0 ! recovering r0.. + .balign 4 +1: .long SYMBOL_NAME(exception_handling_table) +2: .long 0xdfffffff ! RB=0, BL=1 + +.data +ENTRY(exception_handling_table) + .long 0 + .long 0 + .long tlb_miss_load + .long tlb_miss_store + .long initial_page_write + .long tlb_protection_violation_load + .long tlb_protection_violation_store + .long error ! address_error_load (filled by trap_init) + .long error ! address_error_store (filled by trap_init) + .long 0 + .long 0 + .long system_call ! Unconditional Trap + .long error ! reserved_instruction (filled by trap_init) + .long error ! illegal_slot_instruction (filled by trap_init) +ENTRY(nmi_slot) + .long error ! Not implemented yet +ENTRY(user_break_point_trap) + .long error ! Not implemented yet +ENTRY(interrupt_table) + ! external hardware + .long SYMBOL_NAME(do_IRQ) ! 0000 + .long SYMBOL_NAME(do_IRQ) ! 0001 + .long SYMBOL_NAME(do_IRQ) ! 0010 + .long SYMBOL_NAME(do_IRQ) ! 0011 + .long SYMBOL_NAME(do_IRQ) ! 0100 + .long SYMBOL_NAME(do_IRQ) ! 0101 + .long SYMBOL_NAME(do_IRQ) ! 0110 + .long SYMBOL_NAME(do_IRQ) ! 0111 + .long SYMBOL_NAME(do_IRQ) ! 1000 + .long SYMBOL_NAME(do_IRQ) ! 1001 + .long SYMBOL_NAME(do_IRQ) ! 1010 + .long SYMBOL_NAME(do_IRQ) ! 1011 + .long SYMBOL_NAME(do_IRQ) ! 1100 + .long SYMBOL_NAME(do_IRQ) ! 1101 + .long SYMBOL_NAME(do_IRQ) ! 1110 + .long 0 + ! Internal hardware + .long SYMBOL_NAME(do_IRQ) ! TMU0 tuni0 + .long SYMBOL_NAME(do_IRQ) ! TMU1 tuni1 + .long SYMBOL_NAME(do_IRQ) ! TMU2 tuni2 + .long SYMBOL_NAME(do_IRQ) ! ticpi2 + .long SYMBOL_NAME(do_IRQ) ! RTC ati + .long SYMBOL_NAME(do_IRQ) ! pri + .long SYMBOL_NAME(do_IRQ) ! cui + .long SYMBOL_NAME(do_IRQ) ! SCI eri + .long SYMBOL_NAME(do_IRQ) ! rxi + .long SYMBOL_NAME(do_IRQ) ! txi + .long SYMBOL_NAME(do_IRQ) ! tei + .long SYMBOL_NAME(do_IRQ) ! WDT iti + .long SYMBOL_NAME(do_IRQ) ! REF rcmi + .long SYMBOL_NAME(do_IRQ) ! rovi + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) + +ENTRY(sys_call_table) + .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ + .long SYMBOL_NAME(sys_exit) + .long SYMBOL_NAME(sys_fork) + .long SYMBOL_NAME(sys_read) + .long SYMBOL_NAME(sys_write) + .long SYMBOL_NAME(sys_open) /* 5 */ + .long SYMBOL_NAME(sys_close) + .long SYMBOL_NAME(sys_waitpid) + .long SYMBOL_NAME(sys_creat) + .long SYMBOL_NAME(sys_link) + .long SYMBOL_NAME(sys_unlink) /* 10 */ + .long SYMBOL_NAME(sys_execve) + .long SYMBOL_NAME(sys_chdir) + .long SYMBOL_NAME(sys_time) + .long SYMBOL_NAME(sys_mknod) + .long SYMBOL_NAME(sys_chmod) /* 15 */ + .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ + .long SYMBOL_NAME(sys_stat) + .long SYMBOL_NAME(sys_lseek) + .long SYMBOL_NAME(sys_getpid) /* 20 */ + .long SYMBOL_NAME(sys_mount) + .long SYMBOL_NAME(sys_oldumount) + .long SYMBOL_NAME(sys_setuid) + .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_stime) /* 25 */ + .long SYMBOL_NAME(sys_ptrace) + .long SYMBOL_NAME(sys_alarm) + .long SYMBOL_NAME(sys_fstat) + .long SYMBOL_NAME(sys_pause) + .long SYMBOL_NAME(sys_utime) /* 30 */ + .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ + .long SYMBOL_NAME(sys_access) + .long SYMBOL_NAME(sys_nice) + .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */ + .long SYMBOL_NAME(sys_sync) + .long SYMBOL_NAME(sys_kill) + .long SYMBOL_NAME(sys_rename) + .long SYMBOL_NAME(sys_mkdir) + .long SYMBOL_NAME(sys_rmdir) /* 40 */ + .long SYMBOL_NAME(sys_dup) + .long SYMBOL_NAME(sys_pipe) + .long SYMBOL_NAME(sys_times) + .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ + .long SYMBOL_NAME(sys_brk) /* 45 */ + .long SYMBOL_NAME(sys_setgid) + .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_signal) + .long SYMBOL_NAME(sys_geteuid) + .long SYMBOL_NAME(sys_getegid) /* 50 */ + .long SYMBOL_NAME(sys_acct) + .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ + .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ + .long SYMBOL_NAME(sys_ioctl) + .long SYMBOL_NAME(sys_fcntl) /* 55 */ + .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ + .long SYMBOL_NAME(sys_setpgid) + .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_olduname */ + .long SYMBOL_NAME(sys_umask) /* 60 */ + .long SYMBOL_NAME(sys_chroot) + .long SYMBOL_NAME(sys_ustat) + .long SYMBOL_NAME(sys_dup2) + .long SYMBOL_NAME(sys_getppid) + .long SYMBOL_NAME(sys_getpgrp) /* 65 */ + .long SYMBOL_NAME(sys_setsid) + .long SYMBOL_NAME(sys_sigaction) + .long SYMBOL_NAME(sys_sgetmask) + .long SYMBOL_NAME(sys_ssetmask) + .long SYMBOL_NAME(sys_setreuid) /* 70 */ + .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_sigsuspend) + .long SYMBOL_NAME(sys_sigpending) + .long SYMBOL_NAME(sys_sethostname) + .long SYMBOL_NAME(sys_setrlimit) /* 75 */ + .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_getrusage) + .long SYMBOL_NAME(sys_gettimeofday) + .long SYMBOL_NAME(sys_settimeofday) + .long SYMBOL_NAME(sys_getgroups) /* 80 */ + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_ni_syscall) /* old_select */ + .long SYMBOL_NAME(sys_symlink) + .long SYMBOL_NAME(sys_lstat) + .long SYMBOL_NAME(sys_readlink) /* 85 */ + .long SYMBOL_NAME(sys_uselib) + .long SYMBOL_NAME(sys_swapon) + .long SYMBOL_NAME(sys_reboot) + .long SYMBOL_NAME(old_readdir) + .long SYMBOL_NAME(sys_ni_syscall) /* old_mmap */ /* 90 */ + .long SYMBOL_NAME(sys_munmap) + .long SYMBOL_NAME(sys_truncate) + .long SYMBOL_NAME(sys_ftruncate) + .long SYMBOL_NAME(sys_fchmod) + .long SYMBOL_NAME(sys_fchown) /* 95 */ + .long SYMBOL_NAME(sys_getpriority) + .long SYMBOL_NAME(sys_setpriority) + .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ + .long SYMBOL_NAME(sys_statfs) + .long SYMBOL_NAME(sys_fstatfs) /* 100 */ + .long SYMBOL_NAME(sys_ni_syscall) /* ioperm */ + .long SYMBOL_NAME(sys_socketcall) + .long SYMBOL_NAME(sys_syslog) + .long SYMBOL_NAME(sys_setitimer) + .long SYMBOL_NAME(sys_getitimer) /* 105 */ + .long SYMBOL_NAME(sys_newstat) + .long SYMBOL_NAME(sys_newlstat) + .long SYMBOL_NAME(sys_newfstat) + .long SYMBOL_NAME(sys_uname) + .long SYMBOL_NAME(sys_ni_syscall) /* 110 */ /* iopl */ + .long SYMBOL_NAME(sys_vhangup) + .long SYMBOL_NAME(sys_ni_syscall) /* idle */ + .long SYMBOL_NAME(sys_ni_syscall) /* vm86old */ + .long SYMBOL_NAME(sys_wait4) + .long SYMBOL_NAME(sys_swapoff) /* 115 */ + .long SYMBOL_NAME(sys_sysinfo) + .long SYMBOL_NAME(sys_ipc) + .long SYMBOL_NAME(sys_fsync) + .long SYMBOL_NAME(sys_sigreturn) + .long SYMBOL_NAME(sys_clone) /* 120 */ + .long SYMBOL_NAME(sys_setdomainname) + .long SYMBOL_NAME(sys_newuname) + .long SYMBOL_NAME(sys_ni_syscall) /* sys_modify_ldt */ + .long SYMBOL_NAME(sys_adjtimex) + .long SYMBOL_NAME(sys_mprotect) /* 125 */ + .long SYMBOL_NAME(sys_sigprocmask) + .long SYMBOL_NAME(sys_create_module) + .long SYMBOL_NAME(sys_init_module) + .long SYMBOL_NAME(sys_delete_module) + .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */ + .long SYMBOL_NAME(sys_quotactl) + .long SYMBOL_NAME(sys_getpgid) + .long SYMBOL_NAME(sys_fchdir) + .long SYMBOL_NAME(sys_bdflush) + .long SYMBOL_NAME(sys_sysfs) /* 135 */ + .long SYMBOL_NAME(sys_personality) + .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */ + .long SYMBOL_NAME(sys_setfsuid) + .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_llseek) /* 140 */ + .long SYMBOL_NAME(sys_getdents) + .long SYMBOL_NAME(sys_select) + .long SYMBOL_NAME(sys_flock) + .long SYMBOL_NAME(sys_msync) + .long SYMBOL_NAME(sys_readv) /* 145 */ + .long SYMBOL_NAME(sys_writev) + .long SYMBOL_NAME(sys_getsid) + .long SYMBOL_NAME(sys_fdatasync) + .long SYMBOL_NAME(sys_sysctl) + .long SYMBOL_NAME(sys_mlock) /* 150 */ + .long SYMBOL_NAME(sys_munlock) + .long SYMBOL_NAME(sys_mlockall) + .long SYMBOL_NAME(sys_munlockall) + .long SYMBOL_NAME(sys_sched_setparam) + .long SYMBOL_NAME(sys_sched_getparam) /* 155 */ + .long SYMBOL_NAME(sys_sched_setscheduler) + .long SYMBOL_NAME(sys_sched_getscheduler) + .long SYMBOL_NAME(sys_sched_yield) + .long SYMBOL_NAME(sys_sched_get_priority_max) + .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */ + .long SYMBOL_NAME(sys_sched_rr_get_interval) + .long SYMBOL_NAME(sys_nanosleep) + .long SYMBOL_NAME(sys_mremap) + .long SYMBOL_NAME(sys_setresuid) + .long SYMBOL_NAME(sys_getresuid) /* 165 */ + .long SYMBOL_NAME(sys_ni_syscall) /* vm86 */ + .long SYMBOL_NAME(sys_query_module) + .long SYMBOL_NAME(sys_poll) + .long SYMBOL_NAME(sys_nfsservctl) + .long SYMBOL_NAME(sys_setresgid) /* 170 */ + .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_prctl) + .long SYMBOL_NAME(sys_rt_sigreturn) + .long SYMBOL_NAME(sys_rt_sigaction) + .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */ + .long SYMBOL_NAME(sys_rt_sigpending) + .long SYMBOL_NAME(sys_rt_sigtimedwait) + .long SYMBOL_NAME(sys_rt_sigqueueinfo) + .long SYMBOL_NAME(sys_rt_sigsuspend) + .long SYMBOL_NAME(sys_pread) /* 180 */ + .long SYMBOL_NAME(sys_pwrite) + .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_getcwd) + .long SYMBOL_NAME(sys_capget) + .long SYMBOL_NAME(sys_capset) /* 185 */ + .long SYMBOL_NAME(sys_sigaltstack) + .long SYMBOL_NAME(sys_sendfile) + .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ + .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_vfork) /* 190 */ + + /* + * NOTE!! This doesn't have to be exact - we just have + * to make sure we have _enough_ of the "sys_ni_syscall" + * entries. Don't panic if you notice that this hasn't + * been shrunk every time we add a new system call. + */ + .rept NR_syscalls-190 + .long SYMBOL_NAME(sys_ni_syscall) + .endr + +/* End of entry.S */ diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S --- v2.3.15/linux/arch/sh/kernel/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/head.S Mon Aug 30 18:12:59 1999 @@ -0,0 +1,69 @@ +/* $Id$ + * + * arch/sh/kernel/head.S + * + * Copyright (C) 1999 Niibe Yutaka + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Head.S contains the SH exception handlers and startup code. + */ +#include +#include +#include +#include +#include + +#ifdef CONFIG_CPU_SH3 +/* Following values are assumed to be as small as immediate. */ +#define CCR 0xffffffec /* Address of Cache Control Register */ +#define CACHE_INIT 0x00000009 /* 8k-byte cache, flush, enable */ +#elif CONFIG_CPU_SH4 +/* Should fill here. */ +#endif + +ENTRY(_stext) + ! Switch to register bank 0 + stc sr,r1 ! + mov.l 1f,r0 ! RB=0, BL=1 + and r1,r0 + ldc r0,sr + ! Enable cache +#ifdef CONFIG_CPU_SH3 + mov #CCR,r1 + mov.l @r1,r0 + cmp/eq #1,r0 ! If it's enabled already, don't flush it + bt/s 8f + mov #CACHE_INIT,r0 + mov.l r0,@r1 +#elif CONFIG_CPU_SH4 + ! Should fill here. +#endif +8: + ! + mov.l 2f,r0 + mov r0,r15 ! Set initial r15 (stack pointer) + ldc r0,r4_bank ! and stack base + ! Clear BSS area + mov.l 3f,r1 + mov.l 4f,r2 + mov #0,r0 +9: mov.l r0,@r1 + cmp/hs r2,r1 + bf/s 9b + add #4,r1 + ! Start kernel + mov.l 5f,r0 + jmp @r0 + nop + + .balign 4 +1: .long 0xdfffffff ! RB=0, BL=1 +2: .long SYMBOL_NAME(stack) +3: .long SYMBOL_NAME(__bss_start) +4: .long SYMBOL_NAME(_end) +5: .long SYMBOL_NAME(start_kernel) + +.data diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/init_task.c linux/arch/sh/kernel/init_task.c --- v2.3.15/linux/arch/sh/kernel/init_task.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/init_task.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,23 @@ +#include +#include +#include + +#include +#include + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM(init_mm); + +/* + * Initial task structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union task_union init_task_union + __attribute__((__section__(".data.init_task"))) = + { INIT_TASK(init_task_union.task) }; diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c --- v2.3.15/linux/arch/sh/kernel/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/irq.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,485 @@ +/* + * linux/arch/sh/kernel/irq.c + * + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * + * SuperH version: Copyright (C) 1999 Niibe Yutaka + */ + +/* + * IRQs are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; + +/* + * Micro-access to controllers is serialized over the whole + * system. We never hold this lock when we call the actual + * IRQ handler. + */ +spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; + +/* + * Special irq handlers. + */ + +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * Generic, controller-independent functions: + */ + +int get_irq_list(char *buf) +{ + int i, j; + struct irqaction * action; + char *p = buf; + + p += sprintf(p, " "); + for (j=0; jtypename); + p += sprintf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) { + p += sprintf(p, ", %s", action->name); + } + *p++ = '\n'; + } + return p - buf; +} + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) +{ + int status; + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + + status = 1; /* Force the "do bottom halves" bit */ + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + + irq_exit(cpu, irq); + + return status; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ +void disable_irq_nosync(unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); + if (!irq_desc[irq].depth++) { + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->disable(irq); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/* + * Synchronous version of the above, making sure the IRQ is + * no longer running on any other IRQ.. + */ +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + + if (!local_irq_count[smp_processor_id()]) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } +} + +void enable_irq(unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); + switch (irq_desc[irq].depth) { + case 1: { + unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED; + irq_desc[irq].status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + irq_desc[irq].status = status | IRQ_REPLAY; + hw_resend_irq(irq_desc[irq].handler,irq); + } + irq_desc[irq].handler->enable(irq); + /* fall-through */ + } + default: + irq_desc[irq].depth--; + break; + case 0: + printk("enable_irq() unbalanced from %p\n", + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/* + * do_IRQ handles all normal device IRQ's. + */ +asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + int irq; + int cpu = smp_processor_id(); + irq_desc_t *desc; + struct irqaction * action; + unsigned int status; + + /* Get IRQ number */ + asm volatile("stc r2_bank,%0\n\t" + "shlr2 %0\n\t" + "shlr2 %0\n\t" + "shlr %0\n\t" + "add #-16,%0\n\t" + :"=z" (irq)); + + kstat.irqs[cpu][irq]++; + desc = irq_desc + irq; + spin_lock(&irq_controller_lock); + irq_desc[irq].handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + spin_unlock(&irq_controller_lock); + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (!action) + return 1; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + handle_IRQ_event(irq, ®s, action); + spin_lock(&irq_controller_lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + spin_unlock(&irq_controller_lock); + } + desc->status &= ~IRQ_INPROGRESS; + if (!(desc->status & IRQ_DISABLED)){ + irq_desc[irq].handler->end(irq); + } + spin_unlock(&irq_controller_lock); + + /* + * This should be conditional: we should really get + * a return code from the irq handler to tell us + * whether the handler wants us to do software bottom + * half handling or not.. + */ + if (1) { + if (bh_active & bh_mask) + do_bottom_half(); + } + return 1; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + spin_lock_irqsave(&irq_controller_lock,flags); + p = &irq_desc[irq].action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (irq_desc[irq].action) + break; + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->shutdown(irq); + break; + } + printk("Trying to free free IRQ%d\n",irq); + break; + } + spin_unlock_irqrestore(&irq_controller_lock,flags); +} + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ +unsigned long probe_irq_on(void) +{ + unsigned int i; + unsigned long delay; + + /* + * first, enable any unassigned irqs + */ + spin_lock_irq(&irq_controller_lock); + for (i = NR_IRQS-1; i > 0; i--) { + if (!irq_desc[i].action) { + irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; + if(irq_desc[i].handler->startup(i)) + irq_desc[i].status |= IRQ_PENDING; + } + } + spin_unlock_irq(&irq_controller_lock); + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ synchronize_irq(); + + /* + * Now filter out any obviously spurious interrupts + */ + spin_lock_irq(&irq_controller_lock); + for (i=0; ishutdown(i); + } + } + spin_unlock_irq(&irq_controller_lock); + + return 0x12345678; +} + +int probe_irq_off(unsigned long unused) +{ + int i, irq_found, nr_irqs; + + if (unused != 0x12345678) + printk("Bad IRQ probe from %lx\n", (&unused)[-1]); + + nr_irqs = 0; + irq_found = 0; + spin_lock_irq(&irq_controller_lock); + for (i=0; ishutdown(i); + } + spin_unlock_irq(&irq_controller_lock); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&irq_controller_lock,flags); + p = &irq_desc[irq].action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&irq_controller_lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + irq_desc[irq].depth = 0; + irq_desc[irq].status &= ~IRQ_DISABLED; + irq_desc[irq].handler->startup(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c --- v2.3.15/linux/arch/sh/kernel/irq_onchip.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/irq_onchip.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,169 @@ +/* + * linux/arch/sh/kernel/irq_onchip.c + * + * Copyright (C) 1999 Niibe Yutaka + * + * Interrupt handling for on-chip supporting modules (TMU, RTC, etc.). + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* + * SH (non-)specific no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +struct ipr_data { + int offset; + int priority; +}; +static struct ipr_data ipr_data[NR_IRQS-TIMER_IRQ]; + +void set_ipr_data(unsigned int irq, int offset, int priority) +{ + ipr_data[irq-TIMER_IRQ].offset = offset; + ipr_data[irq-TIMER_IRQ].priority = priority; +} + +static void enable_onChip_irq(unsigned int irq); +void disable_onChip_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define shutdown_onChip_irq disable_onChip_irq + +static void mask_and_ack_onChip(unsigned int); +static void end_onChip_irq(unsigned int irq); + +static unsigned int startup_onChip_irq(unsigned int irq) +{ + enable_onChip_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type onChip_irq_type = { + "On-Chip Supporting Module", + startup_onChip_irq, + shutdown_onChip_irq, + enable_onChip_irq, + disable_onChip_irq, + mask_and_ack_onChip, + end_onChip_irq +}; + +/* + * These have to be protected by the irq controller spinlock + * before being called. + * + * + * IPRA 15-12 11-8 7-4 3-0 + * IPRB 15-12 11-8 7-4 3-0 + * IPRC 15-12 11-8 7-4 3-0 + * + */ +#define INTC_IPR 0xfffffee2UL /* Word access */ + +void disable_onChip_irq(unsigned int irq) +{ + /* Set priority in IPR to 0 */ + int offset = ipr_data[irq-TIMER_IRQ].offset; + unsigned long intc_ipr_address = INTC_IPR + offset/16; + unsigned short mask = 0xffff ^ (0xf << (offset%16)); + unsigned long __dummy; + + asm volatile("mov.w @%1,%0\n\t" + "and %2,%0\n\t" + "mov.w %0,@%1" + : "=&z" (__dummy) + : "r" (intc_ipr_address), "r" (mask) + : "memory" ); +} + +static void enable_onChip_irq(unsigned int irq) +{ + /* Set priority in IPR back to original value */ + int offset = ipr_data[irq-TIMER_IRQ].offset; + int priority = ipr_data[irq-TIMER_IRQ].priority; + unsigned long intc_ipr_address = INTC_IPR + offset/16; + unsigned short value = (priority << (offset%16)); + unsigned long __dummy; + + asm volatile("mov.w @%1,%0\n\t" + "or %2,%0\n\t" + "mov.w %0,@%1" + : "=&z" (__dummy) + : "r" (intc_ipr_address), "r" (value) + : "memory" ); +} + +void make_onChip_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &onChip_irq_type; + enable_irq(irq); +} + +static void mask_and_ack_onChip(unsigned int irq) +{ + disable_onChip_irq(irq); + sti(); +} + +static void end_onChip_irq(unsigned int irq) +{ + enable_onChip_irq(irq); + cli(); +} + +void __init init_IRQ(void) +{ + int i; + + for (i = TIMER_IRQ; i < NR_IRQS; i++) { + irq_desc[i].handler = &onChip_irq_type; + } +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.3.15/linux/arch/sh/kernel/process.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/process.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,304 @@ +/* + * linux/arch/sh/kernel/process.c + * + * Copyright (C) 1995 Linus Torvalds + * + * SuperH version: Copyright (C) 1999 Niibe Yutaka + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#define __KERNEL_SYSCALLS__ +#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 + +static int hlt_counter=0; + +#define HARD_IDLE_TIMEOUT (HZ / 3) + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +/* + * The idle loop on a uniprocessor i386.. + */ +void cpu_idle(void *unused) +{ + /* endless idle loop with no priority at all */ + init_idle(); + current->priority = 0; + current->counter = -100; + + while (1) { + while (!current->need_resched) { + if (hlt_counter) + continue; + __sti(); + asm volatile("sleep" : : : "memory"); + } + schedule(); + check_pgt_cache(); + } +} + +void machine_restart(char * __unused) +{ /* Need to set MMU_TTB?? */ +} + +void machine_halt(void) +{ +} + +void machine_power_off(void) +{ +} + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("PC: [<%08lx>]", regs->pc); + printk(" SP: %08lx", regs->u_regs[UREG_SP]); + printk(" SR: %08lx\n", regs->sr); + printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", + regs->u_regs[0],regs->u_regs[1], + regs->u_regs[2],regs->u_regs[3]); + printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", + regs->u_regs[4],regs->u_regs[5], + regs->u_regs[6],regs->u_regs[7]); + printk("R8 : %08lx R9 : %08lx R10: %08lx R11: %08lx\n", + regs->u_regs[8],regs->u_regs[9], + regs->u_regs[10],regs->u_regs[11]); + printk("R12: %08lx R13: %08lx R14: %08lx\n", + regs->u_regs[12],regs->u_regs[13], + regs->u_regs[14]); + printk("MACH: %08lx MACL: %08lx GBR: %08lx PR: %08lx", + regs->mach, regs->macl, regs->gbr, regs->pr); +} + +struct task_struct * alloc_task_struct(void) +{ + /* Get two pages */ + return (struct task_struct *) __get_free_pages(GFP_KERNEL,1); +} + +void free_task_struct(struct task_struct *p) +{ + free_pages((unsigned long) p, 1); +} + +/* + * Create a kernel thread + */ + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ /* Don't use this in BL=1(cli). Or else, CPU resets! */ + register unsigned long __sc0 __asm__ ("r0") = __NR_clone; + register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM; + register unsigned long __sc5 __asm__ ("r5") = 0; + register unsigned long __sc8 __asm__ ("r8") = (long) arg; + register unsigned long __sc9 __asm__ ("r9") = (long) fn; + __asm__ __volatile__( + "trapa #0\n\t" /* Linux/SH system call */ + "tst #0xff,r0\n\t" /* child or parent? */ + "bf 1f\n\t" /* parent - jump */ + "jsr @r9\n\t" /* call fn */ + " mov r8,r4\n\t" /* push argument */ + "mov r0,r4\n\t" /* return value to arg of exit */ + "mov %2,r0\n\t" /* exit */ + "trapa #0\n" + "1:" + :"=z" (__sc0) + :"0" (__sc0), "i" (__NR_exit), + "r" (__sc4), "r" (__sc5), "r" (__sc8), "r" (__sc9) + :"memory"); + return __sc0; +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + /* nothing to do ... */ +} + +void flush_thread(void) +{ + /* do nothing */ + /* Possibly, set clear debug registers */ +} + +void release_thread(struct task_struct *dead_task) +{ + /* do nothing */ +} + +/* Fill in the fpu structure for a core dump.. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) +{ + return 0; /* Task didn't use the fpu at all. */ +} + +asmlinkage void ret_from_fork(void); + +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs *childregs; + + childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1; + + *childregs = *regs; + if (user_mode(regs)) { + childregs->u_regs[UREG_SP] = usp; + } else { + childregs->u_regs[UREG_SP] = (unsigned long)p+2*PAGE_SIZE; + } + childregs->u_regs[0] = 0; /* Set return value for child */ + + p->thread.sp = (unsigned long) childregs; + p->thread.pc = (unsigned long) ret_from_fork; + if (p->mm) + p->mm->context = NO_CONTEXT; + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ +/* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->u_regs[UREG_SP] & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + /* Debug registers will come here. */ + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->regs = *regs; +} + +/* + * switch_to(x,y) should switch tasks from x to y. + * + */ +void __switch_to(struct task_struct *prev, struct task_struct *next) +{ + /* + * Restore the kernel stack onto kernel mode register + * k4 (r4_bank1) + */ + asm volatile("ldc %0,r4_bank" + : /* no output */ + :"r" ((unsigned long)next+8192)); +} + +asmlinkage int sys_fork(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + return do_fork(SIGCHLD, regs.u_regs[UREG_SP], ®s); +} + +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + if (!newsp) + newsp = regs.u_regs[UREG_SP]; + return do_fork(clone_flags, newsp, ®s); +} + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, + regs.u_regs[UREG_SP], ®s); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(char *ufilename, char **uargv, + char **uenvp, unsigned long r7, + struct pt_regs regs) +{ + int error; + char *filename; + + lock_kernel(); + filename = getname(ufilename); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, uargv, uenvp, ®s); + if (error == 0) + current->flags &= ~PF_DTRACE; + putname(filename); +out: + unlock_kernel(); + return error; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c --- v2.3.15/linux/arch/sh/kernel/ptrace.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/ptrace.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,477 @@ +/* + * Surely this doesn't work... (we need to design ptrace for SupreH) + * linux/arch/sh/kernel/ptrace.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which flags the user has access to. */ +/* 1 = access 0 = no access */ +#define FLAG_MASK 0x00044dd5 + +/* set's the trap flag. */ +#define TRAP_FLAG 0x100 + +/* + * Offset of eflags on child stack.. + */ +#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs)) + +/* + * this routine will get a word off of the processes privileged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the privileged stacks are in our + * data space. + */ +static inline int get_stack_long(struct task_struct *task, int offset) +{ + unsigned char *stack; + + stack = (unsigned char *)task->thread.sp; + stack += offset; + return (*((int *)stack)); +} + +/* + * this routine will put a word on the processes privileged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the privileged stacks are in our + * data space. + */ +static inline int put_stack_long(struct task_struct *task, int offset, + unsigned long data) +{ + unsigned char * stack; + + stack = (unsigned char *) task->thread.sp; + stack += offset; + *(unsigned long *) stack = data; + return 0; +} + +static int putreg(struct task_struct *child, + unsigned long regno, unsigned long value) +{ +#if 0 + switch (regno >> 2) { + case ORIG_EAX: + return -EIO; + case FS: + if (value && (value & 3) != 3) + return -EIO; + child->thread.fs = value; + return 0; + case GS: + if (value && (value & 3) != 3) + return -EIO; + child->thread.gs = value; + return 0; + case DS: + case ES: + if (value && (value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + case SS: + case CS: + if ((value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + case EFL: + value &= FLAG_MASK; + value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK; + } + if (regno > GS*4) + regno -= 2*4; + put_stack_long(child, regno - sizeof(struct pt_regs), value); +#endif + return 0; +} + +static unsigned long getreg(struct task_struct *child, + unsigned long regno) +{ + unsigned long retval = ~0UL; + +#if 0 + switch (regno >> 2) { + case FS: + retval = child->thread.fs; + break; + case GS: + retval = child->thread.gs; + break; + case DS: + case ES: + case SS: + case CS: + retval = 0xffff; + /* fall through */ + default: + if (regno > GS*4) + regno -= 2*4; + regno = regno - sizeof(struct pt_regs); + retval &= get_stack_long(child, regno); + } +#endif + return retval; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + struct user * dummy = NULL; + unsigned long flags; + int i, ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->flags |= PF_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!!! */ + if (!child) + goto out; + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out; + if (request == PTRACE_ATTACH) { + if (child == current) + goto out; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out; + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) + goto out; + child->flags |= PF_PTRACED; + + write_lock_irqsave(&tasklist_lock, flags); + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + write_unlock_irqrestore(&tasklist_lock, flags); + + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out; + } + ret = -ESRCH; + if (!(child->flags & PF_PTRACED)) + goto out; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out; + } + if (child->p_pptr != current) + goto out; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + goto out; + ret = put_user(tmp,(unsigned long *) data); + goto out; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + goto out; + + tmp = 0; /* Default return condition */ + if(addr < 17*sizeof(long)) + tmp = getreg(child, addr); +#if 0 + if(addr >= (long) &dummy->u_debugreg[0] && + addr <= (long) &dummy->u_debugreg[7]){ + addr -= (long) &dummy->u_debugreg[0]; + addr = addr >> 2; + tmp = child->thread.debugreg[addr]; + }; +#endif + ret = put_user(tmp,(unsigned long *) data); + goto out; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + goto out; + ret = -EIO; + goto out; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + goto out; + + if (addr < 17*sizeof(long)) { + ret = putreg(child, addr, data); + goto out; + } + + /* We need to be very careful here. We implicitly + want to modify a portion of the task_struct, and we + have to be selective about what portions we allow someone + to modify. */ +#if 0 + if(addr >= (long) &dummy->u_debugreg[0] && + addr <= (long) &dummy->u_debugreg[7]){ + + if(addr == (long) &dummy->u_debugreg[4]) return -EIO; + if(addr == (long) &dummy->u_debugreg[5]) return -EIO; + if(addr < (long) &dummy->u_debugreg[4] && + ((unsigned long) data) >= TASK_SIZE-3) return -EIO; + + ret = -EIO; + if(addr == (long) &dummy->u_debugreg[7]) { + data &= ~DR_CONTROL_RESERVED; + for(i=0; i<4; i++) + if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) + goto out; + }; + + addr -= (long) &dummy->u_debugreg; + addr = addr >> 2; + child->thread.debugreg[addr] = data; + ret = 0; + goto out; + }; +#endif + ret = -EIO; + goto out; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out; + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + /* make sure the single step bit is not set. */ +#if 0 + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET,tmp); +#endif + wake_up_process(child); + ret = 0; + goto out; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + long tmp; + + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + goto out; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ +#if 0 + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); +#endif + wake_up_process(child); + goto out; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out; + child->flags &= ~PF_TRACESYS; + if ((child->flags & PF_DTRACE) == 0) { + /* Spurious delayed TF traps may occur */ + child->flags |= PF_DTRACE; + } +#if 0 + tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); +#endif + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + goto out; + } + + case PTRACE_DETACH: { /* detach a process that was attached. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out; + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->exit_code = data; + write_lock_irqsave(&tasklist_lock, flags); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); + /* make sure the single step bit is not set. */ +#if 0 + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); +#endif + wake_up_process(child); + ret = 0; + goto out; + } +#if 0 + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + if (!access_ok(VERIFY_WRITE, (unsigned *)data, + 17*sizeof(long))) + { + ret = -EIO; + goto out; + } + for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) + { + __put_user(getreg(child, i),(unsigned long *) data); + data += sizeof(long); + } + ret = 0; + goto out; + }; + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + unsigned long tmp; + if (!access_ok(VERIFY_READ, (unsigned *)data, + 17*sizeof(long))) + { + ret = -EIO; + goto out; + } + for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) + { + __get_user(tmp, (unsigned long *) data); + putreg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + goto out; + }; + + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + if (!access_ok(VERIFY_WRITE, (unsigned *)data, + sizeof(struct user_i387_struct))) + { + ret = -EIO; + goto out; + } + ret = 0; + if ( !child->used_math ) { + /* Simulate an empty FPU. */ + child->thread.i387.hard.cwd = 0xffff037f; + child->thread.i387.hard.swd = 0xffff0000; + child->thread.i387.hard.twd = 0xffffffff; + } + __copy_to_user((void *)data, &child->thread.i387.hard, + sizeof(struct user_i387_struct)); + goto out; + }; + + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + if (!access_ok(VERIFY_READ, (unsigned *)data, + sizeof(struct user_i387_struct))) + { + ret = -EIO; + goto out; + } + child->used_math = 1; + __copy_from_user(&child->thread.i387.hard, (void *)data, + sizeof(struct user_i387_struct)); + ret = 0; + goto out; + }; +#endif + default: + ret = -EIO; + goto out; + } +out: + unlock_kernel(); + return ret; +} + +asmlinkage void syscall_trace(void) +{ + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/semaphore.c linux/arch/sh/kernel/semaphore.c --- v2.3.15/linux/arch/sh/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/semaphore.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,133 @@ +/* + * Just taken from alpha implementation. + * This can't work well, perhaps. + */ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c --- v2.3.15/linux/arch/sh/kernel/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/setup.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,188 @@ +/* + * linux/arch/sh/kernel/setup.c + * + * Copyright (C) 1999 Niibe Yutaka + * + */ + +/* + * This file handles the architecture-dependent parts of initialization + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif +#include +#include +#include +#include +#include +#include + +/* + * Machine setup.. + */ + +struct sh_cpuinfo boot_cpu_data = { 0, 0, 0, 0, }; +extern int _text, _etext, _edata, _end, _stext, __bss_start; + +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +extern int root_mountflags; + +#define COMMAND_LINE_SIZE 1024 +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + char saved_command_line[COMMAND_LINE_SIZE]; + +extern unsigned char *root_fs_image; + +struct resource standard_io_resources[] = { + { "dma1", 0x00, 0x1f }, + { "pic1", 0x20, 0x3f }, + { "timer", 0x40, 0x5f }, + { "keyboard", 0x60, 0x6f }, + { "dma page reg", 0x80, 0x8f }, + { "pic2", 0xa0, 0xbf }, + { "dma2", 0xc0, 0xdf }, + { "fpu", 0xf0, 0xff } +}; + +#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) + + +/* System RAM - interrupted by the 640kB-1M hole */ +#define code_resource (ram_resources[3]) +#define data_resource (ram_resources[4]) +static struct resource ram_resources[] = { + { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY }, + { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY }, + { "Video RAM area", 0x0a0000, 0x0bffff }, + { "Kernel code", 0x100000, 0 }, + { "Kernel data", 0, 0 } +}; + +/* System ROM resources */ +#define MAXROMS 6 +static struct resource rom_resources[MAXROMS] = { + { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY }, + { "Video ROM", 0xc0000, 0xc7fff } +}; + + +void __init setup_arch(char **cmdline_p, + unsigned long * memory_start_p, + unsigned long * memory_end_p) +{ + *cmdline_p = command_line; + *memory_start_p = (unsigned long) &_end; + *memory_end_p = 0x8c400000; /* For my board. */ + ram_resources[1].end = *memory_end_p-1; + + init_mm.start_code = (unsigned long)&_stext; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + code_resource.start = virt_to_bus(&_text); + code_resource.end = virt_to_bus(&_etext)-1; + data_resource.start = virt_to_bus(&_etext); + data_resource.end = virt_to_bus(&_edata)-1; + + ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); + + initrd_below_start_ok = 1; + initrd_start = (long)&root_fs_image; + initrd_end = (long)&__bss_start; + mount_initrd = 1; + + +#if 0 + /* Request the standard RAM and ROM resources - they eat up PCI memory space */ + request_resource(&iomem_resource, ram_resources+0); + request_resource(&iomem_resource, ram_resources+1); + request_resource(&iomem_resource, ram_resources+2); + request_resource(ram_resources+1, &code_resource); + request_resource(ram_resources+1, &data_resource); +#endif + +#if 0 + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, standard_io_resources+i); +#endif + +#if 0 + rd_image_start = (long)root_fs_image; + rd_prompt = 0; + rd_doload = 1; +#endif + +#if 0 + ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); +#endif + + if (!MOUNT_ROOT_RDONLY) + root_mountflags &= ~MS_RDONLY; +#endif + +#ifdef CONFIG_BLK_DEV_INITRD +#if 0 + if (LOADER_TYPE) { + initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0; + initrd_end = initrd_start+INITRD_SIZE; + if (initrd_end > memory_end) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end,memory_end); + initrd_start = 0; + } + } +#endif + +#endif +} + +/* + * Get CPU information for use by the procfs. + */ + +int get_cpuinfo(char *buffer) +{ + char *p = buffer; + +#ifdef CONFIG_CPU_SH3 + p += sprintf(p,"cpu family\t: SH3\n" + "cache size\t: 8K-byte\n"); +#elif CONFIG_CPU_SH4 + p += sprintf(p,"cpu family\t: SH4\n" + "cache size\t: ??K-byte\n"); +#endif + p += sprintf(p, "bogomips\t: %lu.%02lu\n\n", + (loops_per_sec+2500)/500000, + ((loops_per_sec+2500)/5000) % 100); + + return p - buffer; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/sh_ksyms.c linux/arch/sh/kernel/sh_ksyms.c --- v2.3.15/linux/arch/sh/kernel/sh_ksyms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/sh_ksyms.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(elf_fpregset_t *); + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) +extern struct drive_info_struct drive_info; +EXPORT_SYMBOL(drive_info); +#endif + +/* platform dependent support */ +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(kernel_thread); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); + +#ifdef CONFIG_VT +EXPORT_SYMBOL(screen_info); +#endif diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c --- v2.3.15/linux/arch/sh/kernel/signal.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/signal.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,597 @@ +/* + * linux/arch/sh/kernel/signal.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson + * + * SuperH version: Copyright (C) 1999 Niibe Yutaka + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_SIG 0 + +#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(struct pt_regs *regs, sigset_t *oldset); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int +sys_sigsuspend(old_sigset_t mask, + unsigned long r5, unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs.u_regs[0] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(®s,&saveset)) + return -EINTR; + } +} + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, + unsigned long r6, unsigned long r7, + 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.u_regs[0] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(®s, &saveset)) + return -EINTR; + } +} + +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); + } + + 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_sigaltstack(const stack_t *uss, stack_t *uoss, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + return do_sigaltstack(uss, uoss, regs.u_regs[UREG_SP]); +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ + struct sigcontext sc; + /* FPU should come here: SH-3 has no FPU */ + unsigned long extramask[_NSIG_WORDS-1]; + char retcode[4]; +}; + +struct rt_sigframe +{ + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + /* FPU should come here: SH-3 has no FPU */ + char retcode[4]; +}; + + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *r0_p) +{ + unsigned int err = 0; + +#define COPY(x) err |= __get_user(regs->x, &sc->x) + COPY(u_regs[1]); + COPY(u_regs[2]); COPY(u_regs[3]); + COPY(u_regs[4]); COPY(u_regs[5]); + COPY(u_regs[6]); COPY(u_regs[7]); + COPY(u_regs[8]); COPY(u_regs[9]); + COPY(u_regs[10]); COPY(u_regs[11]); + COPY(u_regs[12]); COPY(u_regs[13]); + COPY(u_regs[14]); COPY(u_regs[15]); + COPY(gbr); COPY(mach); + COPY(macl); COPY(pr); + COPY(sr); COPY(pc); +#undef COPY + + regs->syscall_nr = -1; /* disable syscall checks */ + err |= __get_user(*r0_p, &sc->u_regs[0]); + + return err; +} + +asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + struct sigframe *frame = (struct sigframe *)regs.u_regs[UREG_SP]; + sigset_t set; + int r0; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(®s, &frame->sc, &r0)) + goto badframe; + return r0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + struct rt_sigframe *frame = (struct rt_sigframe *)regs.u_regs[UREG_SP]; + sigset_t set; + stack_t st; + int r0; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &r0)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs.u_regs[UREG_SP]); + + return r0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +/* + * Set up a signal frame. + */ + +static int +setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + int err = 0; + +#define COPY(x) err |= __put_user(regs->x, &sc->x) + COPY(u_regs[0]); COPY(u_regs[1]); + COPY(u_regs[2]); COPY(u_regs[3]); + COPY(u_regs[4]); COPY(u_regs[5]); + COPY(u_regs[6]); COPY(u_regs[7]); + COPY(u_regs[8]); COPY(u_regs[9]); + COPY(u_regs[10]); COPY(u_regs[11]); + COPY(u_regs[12]); COPY(u_regs[13]); + COPY(u_regs[14]); COPY(u_regs[15]); + COPY(gbr); COPY(mach); + COPY(macl); COPY(pr); + COPY(sr); COPY(pc); +#undef COPY + + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) +{ + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)((sp - frame_size) & -8ul); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig; + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + regs->pr = (unsigned long) ka->sa.sa_restorer; + } else { + /* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */ +#ifdef CONFIG_LITTLE_ENDIAN + unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8); +#else + unsigned long code = 0xe000c300 | (__NR_sigreturn << 16); +#endif + + regs->pr = (unsigned long) frame->retcode; + err |= __put_user(code, (long *)(frame->retcode+0)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->u_regs[UREG_SP] = (unsigned long) frame; + regs->u_regs[4] = signal; /* Arg for signal handler */ + regs->pc = (unsigned long) ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", + current->comm, current->pid, frame, regs->pc, regs->pr); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= __copy_to_user(&frame->info, info, sizeof(*info)); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_SP]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, + regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + regs->pr = (unsigned long) ka->sa.sa_restorer; + } else { + /* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */ +#ifdef CONFIG_LITTLE_ENDIAN + unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8); +#else + unsigned long code = 0xe000c300 | (__NR_sigreturn << 16); +#endif + + regs->pr = (unsigned long) frame->retcode; + err |= __put_user(code, (long *)(frame->retcode+0)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->u_regs[UREG_SP] = (unsigned long) frame; + regs->u_regs[4] = signal; /* Arg for signal handler */ + regs->pc = (unsigned long) ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", + current->comm, current->pid, frame, regs->pc, regs->pr); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +/* + * 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) +{ + /* Are we from a system call? */ + if (regs->syscall_nr >= 0) { + /* If so, check system call restarting.. */ + switch (regs->u_regs[0]) { + case -ERESTARTNOHAND: + regs->u_regs[0] = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->u_regs[0] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->u_regs[0] = regs->syscall_nr; + regs->pc -= 2; + } + } + + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + 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); + } +} + +/* + * 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. + */ +int do_signal(struct pt_regs *regs, sigset_t *oldset) +{ + siginfo_t info; + struct k_sigaction *ka; + + if (!oldset) + oldset = ¤t->blocked; + + 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; + + 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; + + /* 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; + } + } + + 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_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + continue; + } + + 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; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + /* FALLTHRU */ + + case SIGSTOP: + current->state = TASK_STOPPED; + current->exit_code = signr; + 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 SIGABRT: case SIGFPE: case SIGSEGV: + if (do_coredump(signr, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + lock_kernel(); + sigaddset(¤t->signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (regs->syscall_nr >= 0) { + /* Restart the system call - no handlers present */ + if (regs->u_regs[0] == -ERESTARTNOHAND || + regs->u_regs[0] == -ERESTARTSYS || + regs->u_regs[0] == -ERESTARTNOINTR) { + regs->u_regs[0] = regs->syscall_nr; + regs->pc -= 2; + } + } + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c --- v2.3.15/linux/arch/sh/kernel/sys_sh.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/sys_sh.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,249 @@ +/* + * linux/arch/i386/kernel/sys_i386.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/i386 + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way Unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + lock_kernel(); + error = do_pipe(fd); + unlock_kernel(); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/i386 didn't use to be able to handle more than + * 4 system call parameters, so these system calls used a memory + * block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +asmlinkage int old_mmap(struct mmap_arg_struct *arg) +{ + int error = -EFAULT; + struct file * file = NULL; + struct mmap_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + + down(¤t->mm->mmap_sem); + lock_kernel(); + if (!(a.flags & MAP_ANONYMOUS)) { + error = -EBADF; + file = fget(a.fd); + if (!file) + goto out; + } + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); + if (file) + fput(file); +out: + unlock_kernel(); + up(¤t->mm->mmap_sem); + return error; +} + +extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); + +struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; + struct timeval *tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + default: + return -EINVAL; + } + + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, + (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, + second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + return -EINVAL; + return sys_shmat (first, (char *) ptr, + second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); + default: + return -EINVAL; + } + + return -EINVAL; +} + +/* + * Old cruft + */ +asmlinkage int sys_uname(struct old_utsname * name) +{ + int err; + if (!name) + return -EFAULT; + down(&uts_sem); + err=copy_to_user(name, &system_utsname, sizeof (*name)); + up(&uts_sem); + return err?-EFAULT:0; +} + +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; + + down(&uts_sem); + + 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); + + up(&uts_sem); + + error = error ? -EFAULT : 0; + + return error; +} + +asmlinkage int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/test-img.c linux/arch/sh/kernel/test-img.c --- v2.3.15/linux/arch/sh/kernel/test-img.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/test-img.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,69 @@ +unsigned char root_fs_image[] +__attribute__((__section__(".data.disk_image"))) += { +0x1f,0x8b,0x08,0x08,0x5d,0xd5,0xc7,0x37,0x00,0x03,0x72,0x2e,0x62,0x69,0x6e,0x00, +0xed,0xdc,0x3f,0x6c,0x1b,0x55,0x1c,0xc0,0xf1,0xdf,0xf9,0xdc,0x04,0x27,0x69,0xb1, +0x93,0x14,0x10,0x48,0x91,0xd3,0x02,0x4d,0x8a,0xb8,0xd4,0x21,0x8a,0x09,0x02,0x02, +0xb5,0x4a,0xab,0x52,0x65,0x69,0x11,0x03,0x42,0xc2,0xb1,0x8f,0xc4,0x92,0xe3,0x03, +0x9f,0x8d,0xca,0x14,0xd8,0x88,0x2a,0xa6,0x0e,0x88,0xa9,0x20,0xb1,0x87,0x8d,0xa5, +0x5b,0x86,0xcc,0x90,0x78,0x77,0xd4,0x60,0x75,0xa9,0x40,0xe2,0xdf,0xd0,0x42,0x78, +0x77,0xef,0x9c,0x38,0x24,0x72,0x49,0x20,0xc9,0x70,0xdf,0x8f,0xf2,0xf3,0xd9,0x77, +0xbf,0xf3,0xbb,0x67,0xbf,0xdf,0xf9,0x4f,0xf4,0x2c,0x02,0x20,0xac,0xe2,0x2a,0x5e, +0x53,0x61,0xaa,0x18,0x0e,0xd6,0x19,0xad,0x09,0x49,0x1d,0x5e,0x5e,0x7d,0x75,0x39, +0xfd,0x6c,0x6d,0x39,0x6d,0x48,0xbf,0x5c,0xfd,0xc9,0xf0,0xf3,0x56,0xd5,0x3a,0x99, +0xba,0xf7,0xd0,0x76,0x8a,0x53,0x5f,0xc4,0xdf,0xcd,0x24,0x56,0x6e,0x9e,0x59,0xb9, +0x30,0x3e,0x73,0x3b,0xf7,0x3f,0x76,0x01,0xc0,0x3e,0x79,0x75,0x1f,0x55,0x71,0x4c, +0x74,0xfd,0x47,0x8f,0xf6,0x70,0x00,0x1c,0xa2,0x8d,0x8d,0x49,0x6f,0xf1,0xc9,0x06, +0x00,0x00,0x08,0x8d,0xe6,0xfb,0x00,0xef,0x73,0x7c,0x33,0x0e,0xf3,0xfd,0xc7,0xbd, +0xd7,0xc5,0xff,0xd0,0x31,0x5a,0x5b,0x4e,0xf7,0x05,0xa1,0xb7,0x1c,0x93,0x48,0x4b, +0x5e,0xe7,0x61,0x1e,0x14,0x80,0x50,0xf0,0xcf,0x3f,0xe7,0x76,0x3b,0xff,0x45,0xe4, +0x89,0x96,0xbc,0x47,0x54,0xc4,0x54,0x74,0xa9,0xe8,0x56,0xd1,0xa3,0xe2,0xb8,0x8a, +0x13,0x2a,0x1e,0x15,0xfd,0xfd,0x68,0x42,0x45,0xaf,0x8a,0xbe,0xbd,0xb6,0xaf,0xce, +0x7f,0x7f,0xaa,0x76,0xef,0x07,0xd1,0x6c,0xbf,0xf5,0xfc,0xd7,0xbf,0xf7,0xae,0x6d, +0x32,0xda,0x6c,0x6b,0xb6,0x7f,0x56,0x9d,0x77,0x4f,0x05,0xb1,0x5b,0xfb,0x27,0x0f, +0xa8,0xfd,0x6f,0x06,0xf5,0xf2,0xfe,0x8e,0xfe,0xff,0x63,0xaf,0xff,0xf0,0xc5,0x54, +0xdb,0xfe,0x7f,0x7a,0xeb,0xf2,0x15,0x53,0xe4,0xe6,0xaa,0x7e,0xed,0x19,0x0b,0xda, +0xbf,0x75,0xd9,0xd8,0xd6,0xff,0xc7,0xf6,0xdf,0x7c,0xdb,0xf6,0x37,0xbe,0xd6,0x63, +0x6a,0xe7,0xe3,0xbf,0x7d,0x2f,0xcb,0x1a,0x29,0x16,0x4a,0xd5,0xeb,0xe5,0x7d,0x7c, +0x73,0xde,0xae,0x7d,0xaf,0x8f,0x3d,0x2a,0xc3,0xda,0xbc,0x1e,0x51,0x6d,0xe9,0x31, +0xde,0xaf,0x8e,0xac,0xe8,0xb8,0x95,0xe7,0xde,0x77,0xaa,0xa5,0xbc,0x1e,0xf3,0x3d, +0x62,0x4a,0xde,0xfe,0xc8,0x1f,0xfb,0x3d,0xea,0x49,0x71,0xa7,0x0b,0x25,0x6f,0xfc, +0xdf,0x36,0x3b,0x65,0xdf,0x07,0x08,0xe0,0x48,0xe8,0xd7,0xb2,0xad,0xfa,0xff,0xd5, +0xd4,0xf5,0x0f,0x20,0x24,0xf8,0xa7,0x1f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f, +0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f, +0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f, +0x10,0x4a,0x7a,0x4e,0xcf,0xce,0xf9,0x3f,0xde,0xbc,0xb6,0xbb,0x66,0xa7,0xe4,0x9c, +0x92,0xeb,0x14,0xed,0xa3,0x3d,0x48,0x00,0x07,0x42,0xcf,0xe3,0xdb,0x59,0xff,0xde, +0x7c,0xd6,0xbb,0x66,0x54,0x0a,0xa5,0x42,0xe5,0x68,0x8f,0x10,0xc0,0x41,0x99,0xbf, +0x70,0xe5,0x0d,0x23,0xd2,0x32,0x43,0x38,0x22,0x67,0xc5,0x9f,0x32,0x1c,0xff,0x4a, +0x2d,0xc7,0xd4,0xd5,0x75,0x7f,0xfd,0x98,0x24,0xd5,0xb6,0x21,0x89,0xf9,0x53,0xe1, +0x83,0x1d,0xe2,0x41,0x18,0xd3,0x3a,0xfc,0x9f,0x11,0x34,0x74,0x78,0xb7,0x07,0x83, +0xd8,0xd4,0xe1,0x27,0x67,0xd6,0x8d,0x46,0x7c,0xa4,0x51,0x8f,0xd6,0x3a,0x4a,0xbf, +0x2c,0xc9,0x7b,0xa7,0x3f,0x33,0x16,0xcc,0x5a,0xb4,0x61,0xd6,0xa3,0x4b,0xe2,0xdc, +0x91,0xee,0xd2,0xef,0x22,0x89,0xa7,0x55,0xbc,0x38,0xd2,0x98,0xff,0xb9,0x1e,0xf1, +0xb2,0xa6,0xcd,0xf3,0x89,0x85,0xce,0x75,0xa3,0xf6,0x78,0xe3,0xa4,0x97,0x27,0xb1, +0xc5,0xbf,0x24,0x76,0x6a,0x68,0xa1,0x7b,0xa5,0x6f,0x4d,0x3e,0x34,0x52,0xe9,0x1b, +0x0f,0xf2,0xa7,0x7f,0x34,0xea,0xcf,0x2c,0xc9,0xe2,0x1f,0x6b,0x6a,0xfb,0xf7,0x27, +0xd6,0x0d,0xab,0xd7,0xbe,0xb3,0x26,0x03,0x89,0x86,0x0c,0xf4,0xd6,0x33,0x03,0x7d, +0x4b,0xf2,0x43,0xd7,0xba,0x21,0xb1,0x5a,0xac,0x71,0xdc,0xbb,0x17,0x2f,0x4f,0xed, +0x7b,0xe6,0xc6,0x83,0xc5,0xdf,0xbc,0xf5,0xaa,0xcd,0x97,0xe5,0x9d,0xcf,0xe7,0x55, +0xbf,0x2a,0xf2,0xdd,0x93,0x1b,0xea,0xf6,0xb5,0x6b,0xb3,0x05,0x37,0xa9,0xfe,0xae, +0x56,0x3f,0xb0,0xcb,0x97,0x06,0xbd,0xe9,0xda,0x32,0x39,0xd9,0x25,0xae,0x33,0x67, +0x57,0x66,0x0b,0xa5,0x99,0x64,0xb5,0x54,0x75,0xab,0xd9,0xa2,0x65,0x59,0xde,0xc6, +0x4b,0x76,0xb1,0xe8,0x24,0xdf,0x76,0xca,0xc5,0xbc,0x97,0x7c,0x31,0x93,0x79,0x29, +0x39,0x74,0x71,0xea,0xad,0xe1,0xa4,0x3d,0x93,0x73,0x9f,0x1f,0xb5,0x26,0x52,0xd6, +0xf8,0x78,0x32,0x35,0x31,0x31,0x71,0xee,0x85,0xd4,0x58,0x72,0xc8,0x5f,0x9d,0xb2, +0x52,0xd6,0x68,0xb2,0x6c,0x17,0xed,0xac,0x6b,0x0f,0x8b,0x58,0xee,0xc7,0x73,0x95, +0xec,0xb4,0x5a,0x56,0xca,0x7a,0x39,0xdb,0xbc,0x56,0xb1,0xaf,0x57,0xc4,0x2a,0x3b, +0xf9,0x6c,0x25,0x2b,0x96,0xbe,0xcc,0x55,0x9c,0xb2,0xab,0x6e,0xe8,0xc5,0xb4,0xab, +0x2e,0x72,0xce,0xdc,0x9c,0x5d,0xda,0xd3,0xe9,0xfb,0xa9,0xe0,0xf9,0xeb,0xf0,0xfb, +0x2f,0xe2,0xc5,0xb7,0x2d,0xdb,0x9b,0x9f,0x14,0x07,0x83,0xbc,0x88,0x7e,0x9e,0x0c, +0x15,0xf2,0xea,0x2e,0x79,0xc3,0x41,0x9e,0xa9,0xc7,0x81,0xd1,0x3a,0x16,0x64,0x6b, +0x1c,0xc9,0xc8,0xd6,0xb8,0x69,0x9b,0x37,0xfe,0x2f,0xf3,0x5e,0x11,0xfd,0x93,0x0d, +0x0f,0x6b,0xf7,0xbc,0x6c,0x9b,0x1e,0xef,0xe7,0xa5,0x77,0xc9,0x4b,0xe8,0xfb,0xda, +0x5c,0xfd,0xa5,0xba,0x78,0x73,0x97,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x87,0xe8,0x6f,0x20,0x01,0xec,0xc5,0x00,0x00,0x01,0x00, +}; diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.3.15/linux/arch/sh/kernel/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/time.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,225 @@ +/* + * linux/arch/sh/kernel/time.c + * + * Copyright (C) 1999 Niibe Yutaka + * + * Some code taken from i386 version. + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TMU_TOCR 0xfffffe90 /* Byte access */ +#define TMU_TSTR 0xfffffe92 /* Byte access */ + +#define TMU0_TCOR 0xfffffe94 /* Long access */ +#define TMU0_TCNT 0xfffffe98 /* Long access */ +#define TMU0_TCR 0xfffffe9c /* Word access */ + +#define TMU_TOCR_INIT 0x00 +#define TMU0_TCR_INIT 0x0020 +#define TMU_TSTR_INIT 1 + +#define CLOCK_MHZ (60/4) +#define INTERVAL 37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? */ + +extern rwlock_t xtime_lock; +#define TICK_SIZE tick + +void do_gettimeofday(struct timeval *tv) +{ + extern volatile unsigned long lost_ticks; + unsigned long flags; + unsigned long usec, sec; + + read_lock_irqsave(&xtime_lock, flags); + usec = 0; + { + unsigned long lost = lost_ticks; + if (lost) + usec += lost * (1000000 / HZ); + } + sec = xtime.tv_sec; + usec += xtime.tv_usec; + read_unlock_irqrestore(&xtime_lock, flags); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq(&xtime_lock); + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_unlock_irq(&xtime_lock); +} + +/* + */ +static int set_rtc_time(unsigned long nowtime) +{ +/* XXX should be implemented XXXXXXXXXX */ + int retval = -1; + + return retval; +} + +/* last time the RTC clock got updated */ +static long last_rtc_update = 0; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); + +#if 0 + if (!user_mode(regs)) + sh_do_profile(regs->pc); +#endif + + /* + * If we have an externally synchronized Linux clock, then update + * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && + xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { + if (set_rtc_time(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +} + +/* + * This is the same as the above, except we _also_ save the current + * Time Stamp Counter value at the time of the timer interrupt, so that + * we later on can estimate the time of day more exactly. + */ +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long __dummy; + + /* Clear UNF bit */ + asm volatile("mov.w %1,%0\n\t" + "and %2,%0\n\t" + "mov.w %0,%1" + : "=&z" (__dummy) + : "m" (__m(TMU0_TCR)), "r" (~0x100)); + + /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other + * CPU. We need to avoid to SMP race with it. NOTE: we don' t need + * the irq version of write_lock because as just said we have irq + * locally disabled. -arca + */ + write_lock(&xtime_lock); + + do_timer_interrupt(irq, NULL, regs); + + write_unlock(&xtime_lock); +} + +/* 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 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * 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) + */ +static inline 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 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +static unsigned long get_rtc_time(void) +{ +/* XXX not implemented yet */ + return 0; +} + +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + +void __init time_init(void) +{ + unsigned long __dummy; + + xtime.tv_sec = get_rtc_time(); + xtime.tv_usec = 0; + + set_ipr_data(TIMER_IRQ, TIMER_IRP_OFFSET, TIMER_PRIORITY); + setup_irq(TIMER_IRQ, &irq0); + + /* Start TMU0 */ + asm volatile("mov %1,%0\n\t" + "mov.b %0,%2 ! external clock input\n\t" + "mov %3,%0\n\t" + "mov.w %0,%4 ! enable timer0 interrupt\n\t" + "mov.l %5,%6\n\t" + "mov.l %5,%7\n\t" + "mov %8,%0\n\t" + "mov.b %0,%9" + : "=&z" (__dummy) + : "i" (TMU_TOCR_INIT), "m" (__m(TMU_TOCR)), + "i" (TMU0_TCR_INIT), "m" (__m(TMU0_TCR)), + "r" (INTERVAL), "m" (__m(TMU0_TCOR)), "m" (__m(TMU0_TCNT)), + "i" (TMU_TSTR_INIT), "m" (__m(TMU_TSTR))); +#if 0 + /* Start RTC */ + asm volatile(""); +#endif +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c --- v2.3.15/linux/arch/sh/kernel/traps.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/traps.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,128 @@ +/* + * linux/arch/sh/traps.c + * + * SuperH version: Copyright (C) 1999 Niibe Yutaka + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'entry.S'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static inline void console_verbose(void) +{ + extern int console_loglevel; + console_loglevel = 15; +} + +#define DO_ERROR(trapnr, signr, str, name, tsk) \ +asmlinkage void do_##name(unsigned long r4, unsigned long r5, \ + unsigned long r6, unsigned long r7, \ + struct pt_regs regs) \ +{ \ + unsigned long error_code; \ + \ + asm volatile("stc r2_bank,%0": "=r" (error_code)); \ + sti(); \ + regs.syscall_nr = -1; \ + tsk->thread.error_code = error_code; \ + tsk->thread.trap_no = trapnr; \ + force_sig(signr, tsk); \ + die_if_no_fixup(str,®s,error_code); \ +} + +/* + * These constants are for searching for possible module text + * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is + * a guess of how much space is likely to be vmalloced. + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define MODULE_RANGE (8*1024*1024) + +static void show_registers(struct pt_regs *regs) +{/* Not implemented yet. */ +} + +spinlock_t die_lock; + +void die(const char * str, struct pt_regs * regs, long err) +{ + console_verbose(); + spin_lock_irq(&die_lock); + printk("%s: %04lx\n", str, err & 0xffff); + show_registers(regs); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); +} + +static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) +{ + if (!user_mode(regs)) + { + unsigned long fixup; + fixup = search_exception_table(regs->pc); + if (fixup) { + regs->pc = fixup; + return; + } + die(str, regs, err); + } +} + +DO_ERROR( 7, SIGSEGV, "address error (load)", address_error_load, current) +DO_ERROR( 8, SIGSEGV, "address error (store)", address_error_store, current) +DO_ERROR(12, SIGILL, "reserved instruction", reserved_inst, current) +DO_ERROR(13, SIGILL, "illegal slot instruction", illegal_slot_inst, current) + +asmlinkage void do_exception_error (unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + long ex; + asm volatile("stc r2_bank,%0" : "=r" (ex)); + die_if_kernel("exception", ®s, ex); +} + +void __init trap_init(void) +{ + extern void *vbr_base; + extern void *exception_handling_table[14]; + + exception_handling_table[7] = (void *)do_address_error_load; + exception_handling_table[8] = (void *)do_address_error_store; + exception_handling_table[12] = (void *)do_reserved_inst; + exception_handling_table[13] = (void *)do_illegal_slot_inst; + + /* NOTE: The VBR value should be at P1 + (or P2, virtural "fixed" address space). + It's definitely should not in physical address. */ + + asm volatile("ldc %0,vbr" + : /* no output */ + : "r" (&vbr_base) + : "memory"); +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/Makefile linux/arch/sh/lib/Makefile --- v2.3.15/linux/arch/sh/lib/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/Makefile Mon Aug 30 18:12:59 1999 @@ -0,0 +1,14 @@ +# +# Makefile for SuperH-specific library files.. +# + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + +L_TARGET = lib.a +# L_OBJS = checksum.o old-checksum.o semaphore.o delay.o \ +# usercopy.o getuser.o putuser.o +L_OBJS = delay.o memcpy.o memset.o memmove.o csum_partial_copy.o \ + wordcopy.o checksum.o # usercopy.o getuser.o putuser.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/checksum.c linux/arch/sh/lib/checksum.c --- v2.3.15/linux/arch/sh/lib/checksum.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/checksum.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,170 @@ +/* + * Taken from: + * arch/alpha/lib/checksum.c + * + * This file contains network checksum routines that are better done + * in an architecture-specific manner due to speed.. + */ + +#include + +#include + +static inline unsigned short from64to16(unsigned long long x) +{ + /* add up 32-bit words for 33 bits */ + x = (x & 0xffffffff) + (x >> 32); + /* add up 16-bit and 17-bit words for 17+c bits */ + x = (x & 0xffff) + (x >> 16); + /* add up 16-bit and 2-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented. + */ +unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return ~from64to16(saddr + daddr + sum + + ((unsigned long) ntohs(len) << 16) + + ((unsigned long) proto << 8)); +} + +unsigned int csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + unsigned long long result; + + result = (saddr + daddr + sum + + ((unsigned long) ntohs(len) << 16) + + ((unsigned long) proto << 8)); + + /* Fold down to 32-bits so we don't loose in the typedef-less + network stack. */ + /* 64 to 33 */ + result = (result & 0xffffffff) + (result >> 32); + /* 33 to 32 */ + result = (result & 0xffffffff) + (result >> 32); + return result; +} + +/* + * Do a 64-bit checksum on an arbitrary memory area.. + * + * This isn't a great routine, but it's not _horrible_ either. The + * inner loop could be unrolled a bit further, and there are better + * ways to do the carry, but this is reasonable. + */ +static inline unsigned long do_csum(const unsigned char * buff, int len) +{ + int odd, count; + unsigned long long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff << 8; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + if (4 & (unsigned long) buff) { + result += *(unsigned int *) buff; + count--; + len -= 4; + buff += 4; + } + count >>= 1; /* nr of 64-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 8; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffffffff) + (result >> 32); + } + if (len & 4) { + result += *(unsigned int *) buff; + buff += 4; + } + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += *buff; + result = from64to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +{ + return ~do_csum(iph,ihl*4); +} + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) +{ + unsigned long long result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + /* 32+c bits -> 32 bits */ + result = (result & 0xffffffff) + (result >> 32); + return result; +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + return ~from64to16(do_csum(buff,len)); +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/csum_partial_copy.c linux/arch/sh/lib/csum_partial_copy.c --- v2.3.15/linux/arch/sh/lib/csum_partial_copy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/csum_partial_copy.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,75 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * MIPS specific IP/TCP/UDP checksumming routines + * + * Authors: Ralf Baechle, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 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. + * + * $Id: csum_partial_copy.c,v 1.2 1998/09/16 13:29:32 ralf Exp $ + */ +#include +#include +#include +#include +#include + +/* + * copy while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy(const char *src, char *dst, + int len, unsigned int sum) +{ + /* + * It's 2:30 am and I don't feel like doing it real ... + * This is lots slower than the real thing (tm) + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} + +/* + * Copy from userspace and compute checksum. If we catch an exception + * then zero the rest of the buffer. + */ +unsigned int csum_partial_copy_from_user (const char *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + int missing; + + missing = copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len, sum); +} + +/* + * Copy to userspace and compute checksum. + */ +unsigned int csum_partial_copy_to_user (const char *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + sum = csum_partial(src, len, sum); + + if (copy_to_user(dst, src, len)) { + *err_ptr = -EFAULT; + return sum; + } + + return sum; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/delay.c linux/arch/sh/lib/delay.c --- v2.3.15/linux/arch/sh/lib/delay.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/delay.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,21 @@ +/* + * Precise Delay Loops for SuperH + * + * Copyright (C) 1999 Niibe Yutaka + */ + +#include +#include + +inline void __const_udelay(unsigned long xloops) +{ + xloops *= current_cpu_data.loops_per_sec; + __delay(xloops); +} + +#if 0 +void __udelay(unsigned long usecs) +{ + __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */ +} +#endif diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/memcpy.S linux/arch/sh/lib/memcpy.S --- v2.3.15/linux/arch/sh/lib/memcpy.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/memcpy.S Mon Aug 30 18:12:59 1999 @@ -0,0 +1,131 @@ +! Taken from newlib-1.8.0 + +! +! Fast SH memcpy +! +! by Toshiyasu Morita (tm@netcom.com) +! hacked by J"orn Rernnecke (amylaar@cygnus.co.uk) ("o for o-umlaut) +! +! Entry: r4: destination pointer +! r5: source pointer +! r6: byte count +! +! Exit: r0: destination pointer +! r1-r7: trashed +! +! Notes: Usually one wants to do small reads and write a longword, but +! unfortunately it is difficult in some cases to concatanate bytes +! into a longword on the SH, so this does a longword read and small +! writes. +! +! This implementation makes two assumptions about how it is called: +! +! 1.: If the byte count is nonzero, the address of the last byte to be +! copied is unsigned greater than the address of the first byte to +! be copied. This could be easily swapped for a signed comparison, +! but the algorithm used needs some comparison. +! +! 2.: When there are two or three bytes in the last word of an 11-or-bore +! bytes memory chunk to b copied, the rest of the word can be read +! without size effects. +! This could be easily changed by increasing the minumum size of +! a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2, +! however, this would cost a few extra cyles on average. +! + +#include +ENTRY(memcpy) + ! Big endian version copies with decreasing addresses. + mov r4,r0 + add r6,r0 + sub r4,r5 + mov #11,r1 + cmp/hs r1,r6 + bf/s L_small + add #-1,r5 + mov r5,r3 + add r0,r3 + shlr r3 + bt/s L_even + mov r4,r7 + mov.b @(r0,r5),r2 + add #-1,r3 + mov.b r2,@-r0 +L_even: + tst #1,r0 + add #-1,r5 + bf/s L_odddst + add #8,r7 + tst #2,r0 + bt L_al4dst + add #-1,r3 + mov.w @(r0,r5),r1 + mov.w r1,@-r0 +L_al4dst: + shlr r3 + bt L_al4both + mov.w @(r0,r5),r1 + swap.w r1,r1 + add #4,r7 + add #-4,r5 + .align 2 +L_2l_loop: + mov.l @(r0,r5),r2 + xtrct r2,r1 + mov.l r1,@-r0 + cmp/hs r7,r0 + mov.l @(r0,r5),r1 + xtrct r1,r2 + mov.l r2,@-r0 + bt L_2l_loop + bra L_cleanup + add #5,r5 + + nop ! avoid nop in executed code. +L_al4both: + add #-2,r5 + .align 2 +L_al4both_loop: + mov.l @(r0,r5),r1 + cmp/hs r7,r0 + bt/s L_al4both_loop + mov.l r1,@-r0 + bra L_cleanup + add #3,r5 + + nop ! avoid nop in executed code. +L_odddst: + shlr r3 + bt L_al4src + mov.w @(r0,r5),r1 + mov.b r1,@-r0 + shlr8 r1 + mov.b r1,@-r0 +L_al4src: + add #-2,r5 + .align 2 +L_odd_loop: + mov.l @(r0,r5),r2 + cmp/hs r7,r0 + mov.b r2,@-r0 + shlr8 r2 + mov.w r2,@-r0 + shlr16 r2 + mov.b r2,@-r0 + bt L_odd_loop + + add #3,r5 +L_cleanup: +L_small: + cmp/eq r4,r0 + bt L_ready + add #1,r4 + .align 2 +L_cleanup_loop: + mov.b @(r0,r5),r2 + cmp/eq r4,r0 + mov.b r2,@-r0 + bf L_cleanup_loop +L_ready: + rts + nop diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/memmove.S linux/arch/sh/lib/memmove.S --- v2.3.15/linux/arch/sh/lib/memmove.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/memmove.S Mon Aug 30 18:12:59 1999 @@ -0,0 +1,422 @@ +#include +ENTRY(memmove) + mov.l r8,@-r15 + mov.l r9,@-r15 + mov.l r14,@-r15 + sts.l pr,@-r15 + add #-28,r15 + mov r15,r14 + mov.l r4,@r14 + mov.l r5,@(4,r14) + mov.l r6,@(8,r14) + mov.l @r14,r1 + mov.l r1,@(12,r14) + mov.l @(4,r14),r1 + mov.l r1,@(16,r14) + mov.l @(12,r14),r1 + mov.l @(16,r14),r2 + sub r2,r1 + mov.l @(8,r14),r2 + cmp/hs r2,r1 + bt .L54 + bra .L2 + nop +.L54: + mov.l @(8,r14),r1 + mov #15,r2 + cmp/gt r2,r1 + bt .LF100 + bra .L52 + nop +.LF100: + mov.l @(12,r14),r2 + neg r2,r1 + mov #3,r2 + and r1,r2 + mov.l @(8,r14),r1 + mov r1,r9 + sub r2,r9 + mov r9,r2 + mov.l r2,@(8,r14) +.L4: + mov.l @(12,r14),r2 + neg r2,r1 + mov #3,r2 + and r1,r2 + mov.l r2,@(20,r14) +.L7: + mov.l @(20,r14),r1 + cmp/pl r1 + bt .L9 + bra .L6 + nop + .align 2 +.L9: + mov r14,r2 + mov r14,r1 + add #24,r1 + mov.l @(16,r14),r2 + mov.b @r2,r3 + mov.b r3,@r1 + mov.l @(16,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(16,r14) + mov.l @(20,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(20,r14) + mov.l @(12,r14),r1 + mov r14,r2 + mov r14,r3 + add #24,r3 + mov.b @r3,r2 + mov.b r2,@r1 + mov.l @(12,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(12,r14) + bra .L7 + nop + .align 2 +.L8: +.L6: + bra .L5 + nop + .align 2 +.L10: + bra .L4 + nop + .align 2 +.L5: + nop +.L11: + mov.l @(16,r14),r1 + mov #3,r2 + and r1,r2 + tst r2,r2 + bf .L14 + mov r15,r2 + mov.l @(12,r14),r1 + mov.l @(16,r14),r2 + mov.l @(8,r14),r7 + mov r7,r3 + shlr2 r3 + mov r1,r4 + mov r2,r5 + mov r3,r6 + mov.l .L46,r8 + jsr @r8 + nop + bra .L15 + nop + .align 2 +.L14: + mov r15,r2 + mov.l @(12,r14),r1 + mov.l @(16,r14),r2 + mov.l @(8,r14),r7 + mov r7,r3 + shlr2 r3 + mov r1,r4 + mov r2,r5 + mov r3,r6 + mov.l .L47,r8 + jsr @r8 + nop +.L15: + mov.l @(8,r14),r1 + mov #-4,r2 + and r2,r1 + mov.l @(16,r14),r2 + add r2,r1 + mov.l r1,@(16,r14) + mov.l @(8,r14),r1 + mov #-4,r2 + and r2,r1 + mov.l @(12,r14),r2 + add r2,r1 + mov.l r1,@(12,r14) + mov.l @(8,r14),r1 + mov #3,r2 + and r1,r2 + mov.l r2,@(8,r14) +.L13: +.L52: + bra .L3 + nop + .align 2 +.L16: + bra .L11 + nop + .align 2 +.L12: +.L3: + nop +.L17: + mov.l @(8,r14),r1 + mov.l r1,@(20,r14) +.L20: + mov.l @(20,r14),r1 + cmp/pl r1 + bt .L22 + bra .L19 + nop + .align 2 +.L22: + mov r14,r2 + mov r14,r1 + add #24,r1 + mov.l @(16,r14),r2 + mov.b @r2,r3 + mov.b r3,@r1 + mov.l @(16,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(16,r14) + mov.l @(20,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(20,r14) + mov.l @(12,r14),r1 + mov r14,r2 + mov r14,r3 + add #24,r3 + mov.b @r3,r2 + mov.b r2,@r1 + mov.l @(12,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(12,r14) + bra .L20 + nop + .align 2 +.L21: +.L19: + bra .L18 + nop + .align 2 +.L23: + bra .L17 + nop + .align 2 +.L18: + bra .L24 + nop + .align 2 +.L2: + mov.l @(16,r14),r1 + mov.l @(8,r14),r2 + add r2,r1 + mov.l r1,@(16,r14) + mov.l @(12,r14),r1 + mov.l @(8,r14),r2 + add r2,r1 + mov.l r1,@(12,r14) + mov.l @(8,r14),r1 + mov #15,r2 + cmp/gt r2,r1 + bt .LF101 + bra .L53 + nop +.LF101: + mov.l @(12,r14),r1 + mov #3,r2 + and r1,r2 + mov.l @(8,r14),r1 + mov r1,r9 + sub r2,r9 + mov r9,r2 + mov.l r2,@(8,r14) +.L26: + mov.l @(12,r14),r1 + mov #3,r2 + and r1,r2 + mov.l r2,@(20,r14) +.L29: + mov.l @(20,r14),r1 + cmp/pl r1 + bt .L31 + bra .L28 + nop + .align 2 +.L31: + mov.l @(16,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(16,r14) + mov r14,r2 + mov r14,r1 + add #24,r1 + mov.l @(16,r14),r2 + mov.b @r2,r3 + mov.b r3,@r1 + mov.l @(12,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(12,r14) + mov.l @(20,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(20,r14) + mov.l @(12,r14),r1 + mov r14,r2 + mov r14,r3 + add #24,r3 + mov.b @r3,r2 + mov.b r2,@r1 + bra .L29 + nop + .align 2 +.L30: +.L28: + bra .L27 + nop + .align 2 +.L32: + bra .L26 + nop + .align 2 +.L27: + nop +.L33: + mov.l @(16,r14),r1 + mov #3,r2 + and r1,r2 + tst r2,r2 + bf .L36 + mov r15,r2 + mov.l @(12,r14),r1 + mov.l @(16,r14),r2 + mov.l @(8,r14),r7 + mov r7,r3 + shlr2 r3 + mov r1,r4 + mov r2,r5 + mov r3,r6 + mov.l .L48,r8 + jsr @r8 + nop + bra .L37 + nop + .align 2 +.L36: + mov r15,r2 + mov.l @(12,r14),r1 + mov.l @(16,r14),r2 + mov.l @(8,r14),r7 + mov r7,r3 + shlr2 r3 + mov r1,r4 + mov r2,r5 + mov r3,r6 + mov.l .L49,r8 + jsr @r8 + nop +.L37: + mov.l @(8,r14),r1 + mov #-4,r2 + and r2,r1 + mov.l @(16,r14),r2 + mov r2,r9 + sub r1,r9 + mov r9,r1 + mov.l r1,@(16,r14) + mov.l @(8,r14),r1 + mov #-4,r2 + and r2,r1 + mov.l @(12,r14),r2 + mov r2,r9 + sub r1,r9 + mov r9,r1 + mov.l r1,@(12,r14) + mov.l @(8,r14),r1 + mov #3,r2 + and r1,r2 + mov.l r2,@(8,r14) +.L35: +.L53: + bra .L25 + nop + .align 2 +.L38: + bra .L33 + nop + .align 2 +.L34: +.L25: + nop +.L39: + mov.l @(8,r14),r1 + mov.l r1,@(20,r14) +.L42: + mov.l @(20,r14),r1 + cmp/pl r1 + bt .L44 + bra .L41 + nop + .align 2 +.L44: + mov.l @(16,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(16,r14) + mov r14,r2 + mov r14,r1 + add #24,r1 + mov.l @(16,r14),r2 + mov.b @r2,r3 + mov.b r3,@r1 + mov.l @(12,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(12,r14) + mov.l @(20,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(20,r14) + mov.l @(12,r14),r1 + mov r14,r2 + mov r14,r3 + add #24,r3 + mov.b @r3,r2 + mov.b r2,@r1 + bra .L42 + nop + .align 2 +.L43: +.L41: + bra .L24 + nop + .align 2 +.L45: + bra .L39 + nop + .align 2 +.L40: +.L24: + mov.l @r14,r1 + mov r1,r0 + bra .L1 + nop + .align 2 +.L1: + add #28,r14 + mov r14,r15 + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r9 + mov.l @r15+,r8 + rts + nop +.L50: + .align 2 +.L46: + .long __wordcopy_fwd_aligned +.L47: + .long __wordcopy_fwd_dest_aligned +.L48: + .long __wordcopy_bwd_aligned +.L49: + .long __wordcopy_bwd_dest_aligned +.Lfe1: diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/memset.S linux/arch/sh/lib/memset.S --- v2.3.15/linux/arch/sh/lib/memset.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/memset.S Mon Aug 30 18:12:59 1999 @@ -0,0 +1,72 @@ +! Taken from newlib-1.8.0 + +! +! Fast SH memset +! +! by Toshiyasu Morita (tm@netcom.com) +! +! Entry: r4: destination pointer +! r5: fill value +! r6: byte count +! +! Exit: r0-r3: trashed +! +#include + +ENTRY(memset) + mov r4,r3 ! Save return value + + mov r6,r0 ! Check explicitly for zero + cmp/eq #0,r0 + bt L_exit + + mov #12,r0 ! Check for small number of bytes + cmp/gt r6,r0 + bt L_store_byte_loop + + neg r4,r0 ! Align destination + add #4,r0 + and #3,r0 + tst r0,r0 + bt L_dup_bytes + .balignw 4,0x0009 +L_align_loop: + mov.b r5,@r4 + add #-1,r6 + add #1,r4 + dt r0 + bf L_align_loop + +L_dup_bytes: + extu.b r5,r5 ! Duplicate bytes across longword + swap.b r5,r0 + or r0,r5 + swap.w r5,r0 + or r0,r5 + + mov r6,r2 ! Calculate number of double longwords + shlr2 r2 + shlr r2 + + .balignw 4,0x0009 +L_store_long_loop: + mov.l r5,@r4 ! Store double longs to memory + dt r2 + mov.l r5,@(4,r4) + add #8,r4 + bf L_store_long_loop + + mov #7,r0 + and r0,r6 + tst r6,r6 + bt L_exit + .balignw 4,0x0009 +L_store_byte_loop: + mov.b r5,@r4 ! Store bytes to memory + add #1,r4 + dt r6 + bf L_store_byte_loop + +L_exit: + rts + mov r3,r0 diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/old-checksum.c linux/arch/sh/lib/old-checksum.c --- v2.3.15/linux/arch/sh/lib/old-checksum.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/old-checksum.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,19 @@ +/* + * FIXME: old compatibility stuff, will be removed soon. + */ + +#include + +unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum) +{ + int src_err=0, dst_err=0; + + sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err); + + if (src_err || dst_err) + printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n"); + + return sum; +} + + diff -u --recursive --new-file v2.3.15/linux/arch/sh/lib/wordcopy.S linux/arch/sh/lib/wordcopy.S --- v2.3.15/linux/arch/sh/lib/wordcopy.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/wordcopy.S Mon Aug 30 18:12:59 1999 @@ -0,0 +1,1289 @@ +#include +ENTRY(_wordcopy_fwd_aligned) + mov.l r14,@-r15 + add #-20,r15 + mov r15,r14 + mov.l r4,@r14 + mov.l r5,@(4,r14) + mov.l r6,@(8,r14) + mov.l @(8,r14),r2 + mov #7,r1 + and r2,r1 + mov #0,r2 + mov #7,r3 + sub r2,r1 + cmp/hi r3,r1 + bf .L29 + bra .L2 + nop +.L29: + mova .L22,r0 + add r1,r1 + mov.w @(r0,r1),r1 + add r0,r1 + jmp @r1 + nop + .align 2 + .align 2 +.L22: + .word .L15-.L22 + .word .L18-.L22 + .word .L3-.L22 + .word .L5-.L22 + .word .L7-.L22 + .word .L9-.L22 + .word .L11-.L22 + .word .L13-.L22 + .align 2 +.L3: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #-24,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-28,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #6,r2 + mov.l r2,@(8,r14) + bra .L4 + nop + .align 2 +.L5: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #-20,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-24,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #5,r2 + mov.l r2,@(8,r14) + bra .L6 + nop + .align 2 +.L7: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-20,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #4,r2 + mov.l r2,@(8,r14) + bra .L8 + nop + .align 2 +.L9: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #-12,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #3,r2 + mov.l r2,@(8,r14) + bra .L10 + nop + .align 2 +.L11: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-12,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #2,r2 + mov.l r2,@(8,r14) + bra .L12 + nop + .align 2 +.L13: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(8,r14) + bra .L14 + nop + .align 2 +.L15: + bra .L16 + nop + bra .L1 + nop + .align 2 +.L16: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@r14 + bra .L17 + nop + .align 2 +.L18: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #4,r2 + mov.l r2,@(4,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(8,r14) + bra .L19 + nop + bra .L20 + nop + .align 2 +.L19: + bra .L21 + nop + .align 2 +.L23: +.L2: + nop +.L24: +.L21: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L17: + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r2 + mov r2,r1 + add #4,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 +.L14: + mov.l @(4,r14),r2 + mov r2,r1 + add #8,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r2 + mov r2,r1 + add #8,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L12: + mov.l @(4,r14),r2 + mov r2,r1 + add #12,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r2 + mov r2,r1 + add #12,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 +.L10: + mov.l @(4,r14),r2 + mov r2,r1 + add #16,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r2 + mov r2,r1 + add #16,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L8: + mov.l @(4,r14),r2 + mov r2,r1 + add #20,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r2 + mov r2,r1 + add #20,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 +.L6: + mov.l @(4,r14),r2 + mov r2,r1 + add #24,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r2 + mov r2,r1 + add #24,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L4: + mov.l @(4,r14),r2 + mov r2,r1 + add #28,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r2 + mov r2,r1 + add #28,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 + mov.l @(4,r14),r1 + mov r1,r2 + add #32,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #32,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@(8,r14) +.L26: + mov.l @(8,r14),r1 + tst r1,r1 + bf .L27 + bra .L25 + nop + .align 2 +.L27: + bra .L21 + nop + .align 2 +.L25: + nop +.L20: + mov.l @r14,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L1: + add #20,r14 + mov r14,r15 + mov.l @r15+,r14 + rts + nop +.Lfe1: + .size __wordcopy_fwd_aligned,.Lfe1-__wordcopy_fwd_aligned + .global ___lshrsi3 + .global ___ashlsi3 + .align 2 + .global __wordcopy_fwd_dest_aligned + .type __wordcopy_fwd_dest_aligned,@function +__wordcopy_fwd_dest_aligned: + mov.l r8,@-r15 + mov.l r9,@-r15 + mov.l r14,@-r15 + sts.l pr,@-r15 + add #-40,r15 + mov r15,r14 + mov.l r4,@r14 + mov.l r5,@(4,r14) + mov.l r6,@(8,r14) + mov.l @(4,r14),r1 + mov #3,r2 + and r1,r2 + mov r2,r1 + mov r1,r2 + shll2 r2 + add r2,r2 + mov.l r2,@(28,r14) + mov.l @(28,r14),r2 + neg r2,r1 + add #32,r1 + mov.l r1,@(32,r14) + mov.l @(4,r14),r1 + mov #-4,r2 + and r2,r1 + mov.l r1,@(4,r14) + mov.l @(8,r14),r2 + mov #3,r1 + and r2,r1 + mov #0,r2 + mov #3,r3 + sub r2,r1 + cmp/hi r3,r1 + bf .L53 + bra .L31 + nop +.L53: + mova .L43,r0 + add r1,r1 + mov.w @(r0,r1),r1 + add r0,r1 + jmp @r1 + nop + .align 2 + .align 2 +.L43: + .word .L36-.L43 + .word .L39-.L43 + .word .L32-.L43 + .word .L34-.L43 + .align 2 +.L32: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(20,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-12,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #2,r2 + mov.l r2,@(8,r14) + bra .L33 + nop + .align 2 +.L34: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(8,r14) + bra .L35 + nop + .align 2 +.L36: + bra .L37 + nop + bra .L30 + nop + .align 2 +.L37: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(24,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #4,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@r14 + bra .L38 + nop + .align 2 +.L39: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(20,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(24,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #8,r2 + mov.l r2,@(4,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(8,r14) + bra .L40 + nop + bra .L41 + nop + .align 2 +.L40: + bra .L42 + nop + .align 2 +.L44: +.L31: + nop +.L45: +.L42: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r8 + mov.l .L49,r1 + mov.l @(20,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L50,r1 + mov.l @(24,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L38: + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r1 + mov r1,r8 + add #4,r8 + mov.l .L49,r1 + mov.l @(24,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L50,r1 + mov.l @(12,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L35: + mov.l @(4,r14),r2 + mov r2,r1 + add #8,r1 + mov.l @r1,r2 + mov.l r2,@(20,r14) + mov.l @r14,r1 + mov r1,r8 + add #8,r8 + mov.l .L49,r1 + mov.l @(12,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L50,r1 + mov.l @(16,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L33: + mov.l @(4,r14),r2 + mov r2,r1 + add #12,r1 + mov.l @r1,r2 + mov.l r2,@(24,r14) + mov.l @r14,r1 + mov r1,r8 + add #12,r8 + mov.l .L49,r1 + mov.l @(16,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L50,r1 + mov.l @(20,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 + mov.l @(4,r14),r1 + mov r1,r2 + add #16,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #16,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@(8,r14) +.L47: + mov.l @(8,r14),r1 + tst r1,r1 + bf .L48 + bra .L46 + nop + .align 2 +.L48: + bra .L42 + nop + .align 2 +.L46: + nop +.L41: + mov.l @r14,r8 + mov.l .L49,r1 + mov.l @(20,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L50,r1 + mov.l @(24,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L30: + add #40,r14 + mov r14,r15 + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r9 + mov.l @r15+,r8 + rts + nop +.L51: + .align 2 +.L49: + .long ___lshrsi3 +.L50: + .long ___ashlsi3 +.Lfe2: + .size __wordcopy_fwd_dest_aligned,.Lfe2-__wordcopy_fwd_dest_aligned + .align 2 + .global __wordcopy_bwd_aligned + .type __wordcopy_bwd_aligned,@function +__wordcopy_bwd_aligned: + mov.l r14,@-r15 + add #-20,r15 + mov r15,r14 + mov.l r4,@r14 + mov.l r5,@(4,r14) + mov.l r6,@(8,r14) + mov.l @(8,r14),r2 + mov #7,r1 + and r2,r1 + mov #0,r2 + mov #7,r3 + sub r2,r1 + cmp/hi r3,r1 + bf .L82 + bra .L55 + nop +.L82: + mova .L75,r0 + add r1,r1 + mov.w @(r0,r1),r1 + add r0,r1 + jmp @r1 + nop + .align 2 + .align 2 +.L75: + .word .L68-.L75 + .word .L71-.L75 + .word .L56-.L75 + .word .L58-.L75 + .word .L60-.L75 + .word .L62-.L75 + .word .L64-.L75 + .word .L66-.L75 + .align 2 +.L56: + mov.l @(4,r14),r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #6,r2 + mov.l r2,@(8,r14) + bra .L57 + nop + .align 2 +.L58: + mov.l @(4,r14),r1 + mov r1,r2 + add #-12,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #8,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #5,r2 + mov.l r2,@(8,r14) + bra .L59 + nop + .align 2 +.L60: + mov.l @(4,r14),r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-12,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #12,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #4,r2 + mov.l r2,@(8,r14) + bra .L61 + nop + .align 2 +.L62: + mov.l @(4,r14),r1 + mov r1,r2 + add #-20,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #16,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #3,r2 + mov.l r2,@(8,r14) + bra .L63 + nop + .align 2 +.L64: + mov.l @(4,r14),r1 + mov r1,r2 + add #-24,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-20,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #20,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #2,r2 + mov.l r2,@(8,r14) + bra .L65 + nop + .align 2 +.L66: + mov.l @(4,r14),r1 + mov r1,r2 + add #-28,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-24,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #24,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(8,r14) + bra .L67 + nop + .align 2 +.L68: + bra .L69 + nop + bra .L54 + nop + .align 2 +.L69: + mov.l @(4,r14),r1 + mov r1,r2 + add #-32,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-28,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #28,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + bra .L70 + nop + .align 2 +.L71: + mov.l @(4,r14),r1 + mov r1,r2 + add #-36,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-32,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #32,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(8,r14) + bra .L72 + nop + bra .L73 + nop + .align 2 +.L72: + bra .L74 + nop + .align 2 +.L76: +.L55: + nop +.L77: +.L74: + mov.l @(4,r14),r2 + mov r2,r1 + add #28,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r2 + mov r2,r1 + add #28,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L70: + mov.l @(4,r14),r2 + mov r2,r1 + add #24,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r2 + mov r2,r1 + add #24,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 +.L67: + mov.l @(4,r14),r2 + mov r2,r1 + add #20,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r2 + mov r2,r1 + add #20,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L65: + mov.l @(4,r14),r2 + mov r2,r1 + add #16,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r2 + mov r2,r1 + add #16,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 +.L63: + mov.l @(4,r14),r2 + mov r2,r1 + add #12,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r2 + mov r2,r1 + add #12,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L61: + mov.l @(4,r14),r2 + mov r2,r1 + add #8,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r2 + mov r2,r1 + add #8,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 +.L59: + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r2 + mov r2,r1 + add #4,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L57: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r1 + mov.l @(12,r14),r2 + mov.l r2,@r1 + mov.l @(4,r14),r1 + mov r1,r2 + add #-32,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-32,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@(8,r14) +.L79: + mov.l @(8,r14),r1 + tst r1,r1 + bf .L80 + bra .L78 + nop + .align 2 +.L80: + bra .L74 + nop + .align 2 +.L78: + nop +.L73: + mov.l @r14,r2 + mov r2,r1 + add #28,r1 + mov.l @(16,r14),r2 + mov.l r2,@r1 +.L54: + add #20,r14 + mov r14,r15 + mov.l @r15+,r14 + rts + nop +.Lfe3: + .size __wordcopy_bwd_aligned,.Lfe3-__wordcopy_bwd_aligned + .align 2 + .global __wordcopy_bwd_dest_aligned + .type __wordcopy_bwd_dest_aligned,@function +__wordcopy_bwd_dest_aligned: + mov.l r8,@-r15 + mov.l r9,@-r15 + mov.l r14,@-r15 + sts.l pr,@-r15 + add #-40,r15 + mov r15,r14 + mov.l r4,@r14 + mov.l r5,@(4,r14) + mov.l r6,@(8,r14) + mov.l @(4,r14),r1 + mov #3,r2 + and r1,r2 + mov r2,r1 + mov r1,r2 + shll2 r2 + add r2,r2 + mov.l r2,@(28,r14) + mov.l @(28,r14),r2 + neg r2,r1 + add #32,r1 + mov.l r1,@(32,r14) + mov.l @(4,r14),r1 + mov #-4,r2 + and r2,r1 + mov.l r1,@(4,r14) + mov.l @(4,r14),r1 + mov r1,r2 + add #4,r2 + mov.l r2,@(4,r14) + mov.l @(8,r14),r2 + mov #3,r1 + and r2,r1 + mov #0,r2 + mov #3,r3 + sub r2,r1 + cmp/hi r3,r1 + bf .L106 + bra .L84 + nop +.L106: + mova .L96,r0 + add r1,r1 + mov.w @(r0,r1),r1 + add r0,r1 + jmp @r1 + nop + .align 2 + .align 2 +.L96: + .word .L89-.L96 + .word .L92-.L96 + .word .L85-.L96 + .word .L87-.L96 + .align 2 +.L85: + mov.l @(4,r14),r1 + mov r1,r2 + add #-12,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #8,r1 + mov.l @r1,r2 + mov.l r2,@(20,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #2,r2 + mov.l r2,@(8,r14) + bra .L86 + nop + .align 2 +.L87: + mov.l @(4,r14),r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-8,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #12,r1 + mov.l @r1,r2 + mov.l r2,@(24,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #8,r1 + mov.l @r1,r2 + mov.l r2,@(20,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #1,r2 + mov.l r2,@(8,r14) + bra .L88 + nop + .align 2 +.L89: + bra .L90 + nop + bra .L83 + nop + .align 2 +.L90: + mov.l @(4,r14),r1 + mov r1,r2 + add #-20,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-12,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #16,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #12,r1 + mov.l @r1,r2 + mov.l r2,@(24,r14) + bra .L91 + nop + .align 2 +.L92: + mov.l @(4,r14),r1 + mov r1,r2 + add #-24,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@r14 + mov.l @(4,r14),r2 + mov r2,r1 + add #20,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @(4,r14),r2 + mov r2,r1 + add #16,r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @(8,r14),r1 + mov r1,r2 + add #-1,r2 + mov.l r2,@(8,r14) + bra .L93 + nop + bra .L94 + nop + .align 2 +.L93: + bra .L95 + nop + .align 2 +.L97: +.L84: + nop +.L98: +.L95: + mov.l @(4,r14),r2 + mov r2,r1 + add #12,r1 + mov.l @r1,r2 + mov.l r2,@(24,r14) + mov.l @r14,r1 + mov r1,r8 + add #12,r8 + mov.l .L102,r1 + mov.l @(12,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L103,r1 + mov.l @(16,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L91: + mov.l @(4,r14),r2 + mov r2,r1 + add #8,r1 + mov.l @r1,r2 + mov.l r2,@(20,r14) + mov.l @r14,r1 + mov r1,r8 + add #8,r8 + mov.l .L102,r1 + mov.l @(24,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L103,r1 + mov.l @(12,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L88: + mov.l @(4,r14),r2 + mov r2,r1 + add #4,r1 + mov.l @r1,r2 + mov.l r2,@(16,r14) + mov.l @r14,r1 + mov r1,r8 + add #4,r8 + mov.l .L102,r1 + mov.l @(20,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L103,r1 + mov.l @(24,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L86: + mov.l @(4,r14),r1 + mov.l @r1,r2 + mov.l r2,@(12,r14) + mov.l @r14,r8 + mov.l .L102,r1 + mov.l @(16,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L103,r1 + mov.l @(20,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 + mov.l @(4,r14),r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@(4,r14) + mov.l @r14,r1 + mov r1,r2 + add #-16,r2 + mov.l r2,@r14 + mov.l @(8,r14),r1 + mov r1,r2 + add #-4,r2 + mov.l r2,@(8,r14) +.L100: + mov.l @(8,r14),r1 + tst r1,r1 + bf .L101 + bra .L99 + nop + .align 2 +.L101: + bra .L95 + nop + .align 2 +.L99: + nop +.L94: + mov.l @r14,r1 + mov r1,r8 + add #12,r8 + mov.l .L102,r1 + mov.l @(12,r14),r4 + mov.l @(28,r14),r5 + jsr @r1 + nop + mov r0,r9 + mov.l .L103,r1 + mov.l @(16,r14),r4 + mov.l @(32,r14),r5 + jsr @r1 + nop + mov.l r0,@(36,r14) + mov.l @(36,r14),r1 + or r9,r1 + mov.l r1,@r8 +.L83: + add #40,r14 + mov r14,r15 + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r9 + mov.l @r15+,r8 + rts + nop +.L104: + .align 2 +.L102: + .long ___lshrsi3 +.L103: + .long ___ashlsi3 +.Lfe4: diff -u --recursive --new-file v2.3.15/linux/arch/sh/mm/Makefile linux/arch/sh/mm/Makefile --- v2.3.15/linux/arch/sh/mm/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/mm/Makefile Mon Aug 30 18:12:59 1999 @@ -0,0 +1,13 @@ +# +# Makefile for the Linux SuperH-specific parts of the memory manager. +# +# 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 := mm.o +O_OBJS := init.o fault.o ioremap.o extable.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/sh/mm/extable.c linux/arch/sh/mm/extable.c --- v2.3.15/linux/arch/sh/mm/extable.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/mm/extable.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,57 @@ +/* + * linux/arch/sh/mm/extable.c + * Taken from: + * linux/arch/i386/mm/extable.c + */ + +#include +#include +#include + +extern const struct exception_table_entry __start___ex_table[]; +extern const struct exception_table_entry __stop___ex_table[]; + +static inline unsigned long +search_one_table(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid->fixup; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +unsigned long +search_exception_table(unsigned long addr) +{ + unsigned long ret; + +#ifndef CONFIG_MODULES + /* There is only the kernel to search. */ + ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); + if (ret) return ret; +#else + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + for (mp = module_list; mp != NULL; mp = mp->next) { + if (mp->ex_table_start == NULL) + continue; + ret = search_one_table(mp->ex_table_start, + mp->ex_table_end - 1, addr); + if (ret) return ret; + } +#endif + + return 0; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c --- v2.3.15/linux/arch/sh/mm/fault.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/mm/fault.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,327 @@ +/* + * linux/arch/sh/mm/fault.c + * Copyright (C) 1999 Niibe Yutaka + * + * Based on linux/arch/i386/mm/fault.c: + * Copyright (C) 1995 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include /* to get __m() macro */ +#include + +extern void die(const char *,struct pt_regs *,long); + +/* + * Ugly, ugly, but the goto's result in better assembly.. + */ +int __verify_write(const void * addr, unsigned long size) +{ + struct vm_area_struct * vma; + unsigned long start = (unsigned long) addr; + + if (!size) + return 1; + + vma = find_vma(current->mm, start); + if (!vma) + goto bad_area; + if (vma->vm_start > start) + goto check_stack; + +good_area: + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + size--; + size += start & ~PAGE_MASK; + size >>= PAGE_SHIFT; + start &= PAGE_MASK; + + for (;;) { + if (handle_mm_fault(current, vma, start, 1) <= 0) + goto bad_area; + if (!size) + break; + size--; + start += PAGE_SIZE; + if (start < vma->vm_end) + continue; + vma = vma->vm_next; + if (!vma || vma->vm_start != start) + goto bad_area; + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area;; + } + return 1; + +check_stack: + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, start) == 0) + goto good_area; + +bad_area: + return 0; +} + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + */ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, + unsigned long address) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct * vma; + unsigned long page; + unsigned long fixup; + + tsk = current; + mm = tsk->mm; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || !mm) + goto no_context; + + down(&mm->mmap_sem); + + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, address)) + goto bad_area; +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + if (writeaccess) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + { + int fault = handle_mm_fault(tsk, vma, address, writeaccess); + if (fault < 0) + goto out_of_memory; + if (!fault) + goto do_sigbus; + } + + up(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up(&mm->mmap_sem); + + if (user_mode(regs)) { + tsk->thread.address = address; + tsk->thread.error_code = writeaccess; + force_sig(SIGSEGV, tsk); + return; + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + fixup = search_exception_table(regs->pc); + if (fixup != 0) { + regs->pc = fixup; + return; + } + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + * + */ + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n",address); + printk(KERN_ALERT "pc = %08lx\n", regs->pc); + page = (unsigned long)mm->pgd; + page = ((unsigned long *) __va(page))[address >> 22]; + printk(KERN_ALERT "*pde = %08lx\n", page); + if (page & 1) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; + printk(KERN_ALERT "*pte = %08lx\n", page); + } + die("Oops", regs, writeaccess); + do_exit(SIGKILL); + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", tsk->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->thread.address = address; + tsk->thread.error_code = writeaccess; + tsk->thread.trap_no = 14; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; +} + +void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + unsigned long asid; + unsigned long pteval; + + asid = get_asid(); + + save_and_cli(flags); + address &= PAGE_MASK; + /* Set PTEH register */ + asm volatile ("mov.l %0,%1" + : /* no output */ + : "r" (address | asid), "m" (__m(MMU_PTEH))); + + pteval = pte_val(pte); + pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ + pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */ + /* Set PTEL register */ + asm volatile ("mov.l %0,%1" + : /* no output */ + : "r" (pteval), "m" (__m(MMU_PTEL))); + + /* Load the TLB */ + asm volatile ("ldtlb" : /* no output */ : /* no input */ + : "memory"); + restore_flags(flags); +} + +static __inline__ void __flush_tlb_page(unsigned long asid, unsigned long page) +{ + unsigned long addr, data; + + addr = MMU_TLB_ADDRESS_ARRAY | (page & 0x1F000) | MMU_PAGE_ASSOC_BIT; + data = page | asid; /* VALID bit is off */ + __asm__ __volatile__ ("mov.l %0,%1" + : /* no output */ + : "r" (data), "m" (__m(addr))); +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + unsigned long asid; + + if (vma->vm_mm->context != NO_CONTEXT) { + page &= PAGE_MASK; + asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK; + __flush_tlb_page (asid, page); + } +} + +void flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if (mm->context != NO_CONTEXT) { + unsigned long flags; + int size; + + save_and_cli(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (MMU_NTLB_ENTRIES/4)) { /* So many TLB to flush */ + get_new_mmu_context(mm); + if (mm == current->mm) + set_asid(mm->context & MMU_CONTEXT_ASID_MASK); + } else { + unsigned long asid; + + asid = mm->context & MMU_CONTEXT_ASID_MASK; + start &= PAGE_MASK; + end += (PAGE_SIZE - 1); + end &= PAGE_MASK; + while (start < end) { + __flush_tlb_page (asid, start); + start += PAGE_SIZE; + } + } + restore_flags(flags); + } +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + /* Invalidate all TLB of this process. */ + /* Instead of flush TLBs, we get new MMU context. */ + if (mm->context != NO_CONTEXT) { + unsigned long flags; + + save_and_cli(flags); + get_new_mmu_context(mm); + if (mm == current->mm) + set_asid(mm->context & MMU_CONTEXT_ASID_MASK); + restore_flags(flags); + } +} + +void flush_tlb_all(void) +{ + unsigned long flags, __dummy; + + save_and_cli(flags); + asm volatile("mov.l %1,%0\n\t" + "or #4,%0\n\t" /* Set TF-bit to flush */ + "mov.l %0,%1" + : "=&z" (__dummy) + : "m" (__m(MMUCR))); + restore_flags(flags); +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c --- v2.3.15/linux/arch/sh/mm/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/mm/init.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,294 @@ +/* + * linux/arch/sh/mm/init.c + * + * Copyright (C) 1999 Niibe Yutaka + * + * Based on linux/arch/i386/mm/init.c: + * Copyright (C) 1995 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif + +#include +#include +#include +#include +#include + +/* + * Cache of MMU context last used. + */ +unsigned long mmu_context_cache; + +static unsigned long totalram = 0; + +extern void show_net_buffers(void); +extern unsigned long init_smp_mappings(unsigned long); + +void __bad_pte_kernel(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); +} + +void __bad_pte(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); +} + +pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + clear_page((unsigned long)pte); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + return pte + offset; + } + pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); + return NULL; + } + free_page((unsigned long)pte); + if (pmd_bad(*pmd)) { + __bad_pte_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + unsigned long pte; + + pte = (unsigned long) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + clear_page(pte); + pmd_val(*pmd) = _PAGE_TABLE + __pa(pte); + return (pte_t *)(pte + offset); + } + pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); + return NULL; + } + free_page(pte); + if (pmd_bad(*pmd)) { + __bad_pte(pmd); + return NULL; + } + return (pte_t *) (pmd_page(*pmd) + offset); +} + +int do_check_pgt_cache(int low, int high) +{ + int freed = 0; + if(pgtable_cache_size > high) { + do { + if(pgd_quicklist) + free_pgd_slow(get_pgd_fast()), freed++; + if(pmd_quicklist) + free_pmd_slow(get_pmd_fast()), freed++; + if(pte_quicklist) + free_pte_slow(get_pte_fast()), freed++; + } while(pgtable_cache_size > low); + } + return freed; +} + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving an inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +pte_t * __bad_pagetable(void) +{ + extern char empty_bad_page_table[PAGE_SIZE]; + unsigned long page = (unsigned long)empty_bad_page_table; + + clear_page(page); + return (pte_t *)empty_bad_page_table; +} + +pte_t __bad_page(void) +{ + extern char empty_bad_page[PAGE_SIZE]; + unsigned long page = (unsigned long)empty_bad_page; + + clear_page(page); + return pte_mkdirty(mk_pte(page, PAGE_SHARED)); +} + +void show_mem(void) +{ + int i,free = 0,total = 0,reserved = 0; + int shared = 0, cached = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map+i)) + free++; + else + shared += page_count(mem_map+i) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); + printk("%ld pages in page table cache\n",pgtable_cache_size); +#ifdef CONFIG_NET + show_net_buffers(); +#endif +} + +extern unsigned long free_area_init(unsigned long, unsigned long); + +/* References to section boundaries */ + +extern char _text, _etext, _edata, __bss_start, _end; +extern char __init_begin, __init_end; + +pgd_t swapper_pg_dir[1024]; + +/* + * paging_init() sets up the page tables + * + * This routines also unmaps the page at virtual kernel address 0, so + * that we can trap those pesky NULL-reference errors in the kernel. + */ +unsigned long __init +paging_init(unsigned long start_mem, unsigned long end_mem) +{ + pgd_t * pg_dir; + + start_mem = PAGE_ALIGN(start_mem); + + /* We don't need kernel mapping as hardware support that. */ + pg_dir = swapper_pg_dir; + + /* Unmap the original low memory mappings to detect NULL reference */ + pgd_val(pg_dir[0]) = 0; + + /* Enable MMU */ + __asm__ __volatile__ ("mov.l %0,%1" + : /* no output */ + : "r" (MMU_CONTROL_INIT), "m" (__m(MMUCR))); + + return free_area_init(start_mem, end_mem); +} + +unsigned long empty_bad_page[1024]; +unsigned long empty_bad_page_table[1024]; +unsigned long empty_zero_page[1024]; + +void __init mem_init(unsigned long start_mem, unsigned long end_mem) +{ + int codepages = 0; + int reservedpages = 0; + int datapages = 0; + int initpages = 0; + unsigned long tmp; + + end_mem &= PAGE_MASK; + high_memory = (void *) end_mem; + max_mapnr = num_physpages = MAP_NR(end_mem); + + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); + + /* Mark (clear "reserved" bit) usable pages in the mem_map[] */ + /* Note that all are marked reserved already. */ + tmp = start_mem = PAGE_ALIGN(start_mem); + while (tmp < end_mem) { + clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags); + clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); + tmp += PAGE_SIZE; + } + + for (tmp = PAGE_OFFSET; tmp < end_mem; tmp += PAGE_SIZE) { + if (PageReserved(mem_map+MAP_NR(tmp))) { + if (tmp >= (unsigned long) &_text && tmp < (unsigned long) &_edata) { + if (tmp < (unsigned long) &_etext) + codepages++; + else + datapages++; + } else if (tmp >= (unsigned long) &__init_begin + && tmp < (unsigned long) &__init_end) + initpages++; + else if (tmp >= (unsigned long) &__bss_start + && tmp < (unsigned long) start_mem) + datapages++; + else + reservedpages++; + continue; + } + set_page_count(mem_map+MAP_NR(tmp), 1); + totalram += PAGE_SIZE; +#ifdef CONFIG_BLK_DEV_INITRD + if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) +#endif + free_page(tmp); + } + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", + (unsigned long) nr_free_pages << (PAGE_SHIFT-10), + max_mapnr << (PAGE_SHIFT-10), + codepages << (PAGE_SHIFT-10), + reservedpages << (PAGE_SHIFT-10), + datapages << (PAGE_SHIFT-10), + initpages << (PAGE_SHIFT-10)); +} + +void free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + set_page_count(mem_map+MAP_NR(addr), 1); + free_page(addr); + totalram += PAGE_SIZE; + } + printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); +} + +void si_meminfo(struct sysinfo *val) +{ + val->totalram = totalram; + val->sharedram = 0; + val->freeram = nr_free_pages << PAGE_SHIFT; + val->bufferram = atomic_read(&buffermem); + return; +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/mm/ioremap.c linux/arch/sh/mm/ioremap.c --- v2.3.15/linux/arch/sh/mm/ioremap.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/mm/ioremap.c Mon Aug 30 18:12:59 1999 @@ -0,0 +1,140 @@ +/* + * arch/sh/mm/ioremap.c + * + * Re-map IO memory to kernel address space so that we can access it. + * This is needed for high PCI addresses that aren't mapped in the + * 640k-1MB IO memory area on PC's + * + * (C) Copyright 1995 1996 Linus Torvalds + */ + +#include +#include + +static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (!pte_none(*pte)) + printk("remap_area_pte: page already exists\n"); + set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW | + _PAGE_DIRTY | _PAGE_ACCESSED | flags))); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + do { + pte_t * pte = pte_alloc_kernel(pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + while (address < end) { + pmd_t *pmd = pmd_alloc_kernel(dir, address); + if (!pmd) + return -ENOMEM; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + return -ENOMEM; + set_pgdir(address, *dir); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + flush_tlb_all(); + return 0; +} + +/* + * Generic mapping function (not visible outside): + */ + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ +void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void * addr; + struct vm_struct * area; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Don't remap the low PCI/ISA area, it's always mapped.. + */ + if (phys_addr >= 0xA0000 && last_addr <= 0x100000) + return phys_to_virt(phys_addr); + + /* + * Don't allow anybody to remap normal RAM that we're using.. + */ + if (phys_addr < virt_to_phys(high_memory)) + return NULL; + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size); + if (!area) + return NULL; + addr = area->addr; + if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) { + vfree(addr); + return NULL; + } + return (void *) (offset + (char *)addr); +} + +void iounmap(void *addr) +{ + if (addr > high_memory) + return vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} diff -u --recursive --new-file v2.3.15/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S --- v2.3.15/linux/arch/sh/vmlinux.lds.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/vmlinux.lds.S Mon Aug 30 18:12:59 1999 @@ -0,0 +1,113 @@ +/* ld script to make SuperH Linux kernel + * Written by Niibe Yutaka + */ +#ifdef CONFIG_LITTLE_ENDIAN +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +#else +OUTPUT_FORMAT("elf32-sh", "elf32-sh", "elf32-sh") +#endif +OUTPUT_ARCH(sh) +ENTRY(_start) +SECTIONS +{ + . = 0x80000000 + CONFIG_MEMORY_START + 0x1000; + __text = .; /* Text and read-only data */ + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + ___start___ex_table = .; + ___ex_table : { *(__ex_table) } + ___stop___ex_table = .; + + ___start___ksymtab = .; /* Kernel symbol table */ + ___ksymtab : { *(__ksymtab) } + ___stop___ksymtab = .; + + __etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + __edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + /* stack */ + .stack : { _stack = .; __stack = .; } + + . = ALIGN(4096); /* Init code and data */ + ___init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + ___setup_start = .; + .setup.init : { *(.setup.init) } + ___setup_end = .; + ___initcall_start = .; + .initcall.init : { *(.initcall.init) } + ___initcall_end = .; + . = ALIGN(4096); + ___init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + . = ALIGN(4096); + .data.disk_image : { *(.data.disk_image) } + + . = ALIGN(4); + ___bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + . = ALIGN(4); + __end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging section are relative to the beginning + of the section so we begin .debug at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v2.3.15/linux/arch/sparc/Makefile Wed Jun 9 14:44:25 1999 +++ linux/arch/sparc/Makefile Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.41 1999/06/04 13:29:05 jj Exp $ +# $Id: Makefile,v 1.44 1999/08/19 06:22:20 jj Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -15,7 +15,7 @@ # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. -IS_EGCS := $(shell if $(CC) -c -m32 -o _tmp.o arch/sparc/math-emu/fnegs.c >/dev/null 2>&1; then echo y; else echo n; fi; rm -f _tmp.o) +IS_EGCS := $(shell if $(CC) -m32 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) ifeq ($(NEW_GAS),y) @@ -62,10 +62,8 @@ -$(MAKE) -C arch/sparc/boot clean archmrproper: - -$(MAKE) -C arch/sparc/math-emu cleansymlinks archdep: - -$(MAKE) -C arch/sparc/math-emu symlinks check_asm: $(MAKE) -C arch/sparc/kernel check_asm diff -u --recursive --new-file v2.3.15/linux/arch/sparc/ap1000/apmmu.c linux/arch/sparc/ap1000/apmmu.c --- v2.3.15/linux/arch/sparc/ap1000/apmmu.c Fri Jul 23 12:20:23 1999 +++ linux/arch/sparc/ap1000/apmmu.c Tue Aug 31 11:23:29 1999 @@ -527,7 +527,7 @@ { printk("Kernel faults at addr=0x%08lx\n", address); printk("PTE=%08lx\n", apmmu_hwprobe((address & PAGE_MASK))); - die_if_kernel("APMMU bolixed...", current->tss.kregs); + die_if_kernel("APMMU bolixed...", current->thread.kregs); } static inline void alloc_context(struct task_struct *tsk) @@ -775,7 +775,7 @@ return (pte_t *) apmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1)); } -__initfunc(static inline void apmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end)) +static inline void __init apmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end) { pgd_t *pgdp; pmd_t *pmdp; @@ -797,7 +797,7 @@ } -__initfunc(static void make_page(unsigned virt_page, unsigned phys_page, unsigned prot)) +static void __init make_page(unsigned virt_page, unsigned phys_page, unsigned prot) { pgd_t *pgdp; pmd_t *pmdp; @@ -819,7 +819,7 @@ } -__initfunc(static void make_large_page(unsigned virt_page, unsigned phys_page, unsigned prot)) +static void __init make_large_page(unsigned virt_page, unsigned phys_page, unsigned prot) { pgd_t *pgdp; unsigned start = virt_page<<12; @@ -829,7 +829,7 @@ } -__initfunc(static void ap_setup_mappings(void)) +static void __init ap_setup_mappings(void) { unsigned Srwe = APMMU_PRIV | APMMU_VALID; unsigned SrweUr = 0x14 | APMMU_VALID; /* weird! */ @@ -897,7 +897,7 @@ make_page(MSC_REMREPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c004,Srwe); } -__initfunc(static void map_kernel(void)) +static void __init map_kernel(void) { int phys; @@ -917,7 +917,7 @@ extern int physmem_mapped_contig; extern int linux_num_cpus; -__initfunc(unsigned long apmmu_paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init apmmu_paging_init(unsigned long start_mem, unsigned long end_mem) { int i; @@ -979,7 +979,7 @@ { } -__initfunc(static void poke_viking(void)) +static void __init poke_viking(void) { unsigned long mreg = apmmu_get_mmureg(); @@ -991,7 +991,7 @@ apmmu_set_mmureg(mreg); } -__initfunc(static void init_viking(void)) +static void __init init_viking(void) { apmmu_name = "TI Viking/AP1000"; @@ -1024,7 +1024,7 @@ *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \ } while(0); -__initfunc(static void patch_window_trap_handlers(void)) +static void __init patch_window_trap_handlers(void) { unsigned long *iaddr, *daddr; @@ -1038,7 +1038,7 @@ } /* Load up routines and constants for apmmu */ -__initfunc(void ld_mmu_apmmu(void)) +void __init ld_mmu_apmmu(void) { /* First the constants */ BTFIXUPSET_SIMM13(pmd_shift, APMMU_PMD_SHIFT); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c --- v2.3.15/linux/arch/sparc/ap1000/msc.c Tue Aug 4 16:03:34 1998 +++ linux/arch/sparc/ap1000/msc.c Tue Aug 31 11:23:29 1999 @@ -623,8 +623,8 @@ if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { handle_signal(context,vaddr); } else { - task[tsk]->tss.sig_address = vaddr; - task[tsk]->tss.sig_desc = SUBSIG_NOMAPPING; + task[tsk]->thread.sig_address = vaddr; + task[tsk]->thread.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, task[tsk], 1); } } @@ -650,8 +650,8 @@ if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { handle_signal(context,vaddr); } else { - task[tsk]->tss.sig_address = vaddr; - task[tsk]->tss.sig_desc = SUBSIG_NOMAPPING; + task[tsk]->thread.sig_address = vaddr; + task[tsk]->thread.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, task[tsk], 1); } } diff -u --recursive --new-file v2.3.15/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.3.15/linux/arch/sparc/config.in Thu Aug 26 13:05:34 1999 +++ linux/arch/sparc/config.in Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.69 1999/06/25 11:00:20 davem Exp $ +# $Id: config.in,v 1.73 1999/08/31 10:09:01 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -50,6 +50,7 @@ # Global things across all Sun machines. define_bool CONFIG_SBUS y define_bool CONFIG_SBUSCHAR y + define_bool CONFIG_BUSMOUSE y define_bool CONFIG_SUN_MOUSE y define_bool CONFIG_SERIAL y define_bool CONFIG_SUN_SERIAL y @@ -72,6 +73,8 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +source drivers/parport/Config.in +dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT endmenu mainmenu_option next_comment diff -u --recursive --new-file v2.3.15/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.3.15/linux/arch/sparc/defconfig Fri Jun 25 01:05:12 1999 +++ linux/arch/sparc/defconfig Tue Aug 31 11:23:29 1999 @@ -46,6 +46,7 @@ # CONFIG_FBCON_FONTS is not set CONFIG_SBUS=y CONFIG_SBUSCHAR=y +CONFIG_MOUSE=y CONFIG_SUN_MOUSE=y CONFIG_SERIAL=y CONFIG_SUN_SERIAL=y diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.3.15/linux/arch/sparc/kernel/Makefile Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/kernel/Makefile Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.49 1999/01/02 16:45:37 davem Exp $ +# $Id: Makefile,v 1.50 1999/08/31 13:26:13 anton Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -22,7 +22,7 @@ sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \ sunos_ioctl.o time.o windows.o cpu.o devices.o \ sclow.o solaris.o tadpole.o tick14.o ptrace.o sys_solaris.o \ - unaligned.o muldiv.o pcic.o + unaligned.o muldiv.o pcic.o semaphore.o OX_OBJS := sparc_ksyms.o diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/auxio.c linux/arch/sparc/kernel/auxio.c --- v2.3.15/linux/arch/sparc/kernel/auxio.c Sun Oct 4 10:22:42 1998 +++ linux/arch/sparc/kernel/auxio.c Thu Aug 26 12:42:32 1999 @@ -13,7 +13,7 @@ /* Probe and map in the Auxiliary I/O register */ unsigned char *auxio_register; -__initfunc(void auxio_probe(void)) +void __init auxio_probe(void) { int node, auxio_nd; struct linux_prom_registers auxregs[1]; @@ -68,7 +68,7 @@ volatile unsigned char * auxio_power_register = NULL; -__initfunc(void auxio_power_probe(void)) +void __init auxio_power_probe(void) { struct linux_prom_registers regs; int node; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/cpu.c linux/arch/sparc/kernel/cpu.c --- v2.3.15/linux/arch/sparc/kernel/cpu.c Tue Apr 14 17:44:18 1998 +++ linux/arch/sparc/kernel/cpu.c Tue Aug 31 11:23:29 1999 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -123,7 +123,7 @@ unsigned int fsr_storage; -__initfunc(void cpu_probe(void)) +void __init cpu_probe(void) { int psr_impl, psr_vers, fpu_vers; int i, cpuid, psr; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c --- v2.3.15/linux/arch/sparc/kernel/devices.c Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/kernel/devices.c Tue Aug 31 11:23:29 1999 @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include @@ -21,8 +21,8 @@ extern void clock_stop_probe(void); /* tadpole.c */ extern void sun4c_probe_memerr_reg(void); -__initfunc(unsigned long -device_scan(unsigned long mem_start)) +unsigned long __init +device_scan(unsigned long mem_start) { char node_str[128]; int thismid; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/ebus.c linux/arch/sparc/kernel/ebus.c --- v2.3.15/linux/arch/sparc/kernel/ebus.c Wed Jun 9 14:44:25 1999 +++ linux/arch/sparc/kernel/ebus.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.3 1999/06/03 15:02:09 davem Exp $ +/* $Id: ebus.c,v 1.4 1999/08/31 06:54:19 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -57,8 +57,8 @@ return (unsigned long)kmalloc(size, GFP_ATOMIC); } -__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, - struct linux_ebus_child *dev)) +void __init fill_ebus_child(int node, struct linux_prom_registers *preg, + struct linux_ebus_child *dev) { int regs[PROMREG_MAX]; int irqs[PROMREG_MAX]; @@ -128,7 +128,7 @@ #endif } -__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) +void __init fill_ebus_device(int node, struct linux_ebus_device *dev) { struct linux_prom_registers regs[PROMREG_MAX]; struct linux_ebus_child *child; @@ -255,7 +255,7 @@ } } -__initfunc(void ebus_init(void)) +void __init ebus_init(void) { struct linux_prom_pci_registers regs[PROMREG_MAX]; struct linux_pbm_info *pbm; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.3.15/linux/arch/sparc/kernel/entry.S Wed Jun 9 14:44:25 1999 +++ linux/arch/sparc/kernel/entry.S Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.160 1999/06/03 15:02:11 davem Exp $ +/* $Id: entry.S,v 1.161 1999/08/14 03:51:05 anton Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1397,7 +1397,7 @@ rd %wim, %g5 WRITE_PAUSE mov %fp, %o1 ! arg1: usp - std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr] + std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr call C_LABEL(do_fork) mov %l5, %o7 @@ -1419,7 +1419,7 @@ mov %fp, %o1 ! yes, use callers usp andn %o1, 7, %o1 ! no, align to 8 bytes 1: - std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr] + std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr call C_LABEL(do_fork) mov %l5, %o7 @@ -1433,7 +1433,7 @@ WRITE_PAUSE rd %wim, %g5 WRITE_PAUSE - std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr] + std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 mov %fp, %o1 or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 @@ -1854,7 +1854,7 @@ * traps with the old method of just doing flush_user_windows(). */ C_LABEL(kill_user_windows): - ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], %o0 ! get current umask + ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], %o0 ! get current umask orcc %g0, %o0, %g0 ! if no bits set, we are done be 3f ! nothing to do rd %psr, %o5 ! must clear interrupts @@ -1862,7 +1862,7 @@ wr %o4, 0x0, %psr ! the uwinmask state WRITE_PAUSE ! burn them cycles 1: - ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], %o0 ! get consistant state + ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], %o0 ! get consistant state orcc %g0, %o0, %g0 ! did an interrupt come in? be 4f ! yep, we are done rd %wim, %o3 ! get current wim @@ -1874,13 +1874,13 @@ bne kuw_patch1 ! not done yet srl %o3, 1, %o4 ! begin another save simulation wr %o3, 0x0, %wim ! set the new wim - st %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask] ! clear uwinmask + st %g0, [%g6 + AOFF_task_thread + AOFF_thread_uwinmask] ! clear uwinmask 4: wr %o5, 0x0, %psr ! re-enable interrupts WRITE_PAUSE ! burn baby burn 3: retl ! return - st %g0, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] ! no windows saved + st %g0, [%g6 + AOFF_task_thread + AOFF_thread_w_saved] ! no windows saved .align 4 .globl C_LABEL(restore_current) diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S --- v2.3.15/linux/arch/sparc/kernel/etrap.S Tue Apr 14 17:44:18 1998 +++ linux/arch/sparc/kernel/etrap.S Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.29 1998/02/09 13:48:40 jj Exp $ +/* $Id: etrap.S,v 1.30 1999/08/14 03:51:08 anton Exp $ * etrap.S: Sparc trap window preparation for entry into the * Linux kernel. * @@ -101,7 +101,7 @@ mov %t_kstack, %sp ! jump onto new stack trap_setup_kernel_spill: - ld [%curptr + AOFF_task_tss + AOFF_thread_uwinmask], %g1 + ld [%curptr + AOFF_task_thread + AOFF_thread_uwinmask], %g1 orcc %g0, %g1, %g0 bne trap_setup_user_spill ! there are some user windows, yuck /* Spill from kernel, but only kernel windows, adjust @@ -153,8 +153,8 @@ and %t_kstack, %curptr, %curptr #endif - /* Clear current->tss.w_saved */ - st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] + /* Clear current->thread.w_saved */ + st %g0, [%curptr + AOFF_task_thread + AOFF_thread_w_saved] /* See if we are in the trap window. */ andcc %t_twinmask, %t_wim, %g0 @@ -185,7 +185,7 @@ andn %g2, %t_twinmask, %g2 tsetup_patch3: and %g2, 0xff, %g2 ! patched on 7win Sparcs - st %g2, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] ! store new umask + st %g2, [%curptr + AOFF_task_thread + AOFF_thread_uwinmask] ! store new umask jmpl %t_retpc + 0x8, %g0 ! return to caller mov %t_kstack, %sp ! and onto kernel stack @@ -206,7 +206,7 @@ tsetup_patch6: and %g2, 0xff, %g2 ! patched on 7win Sparcs andn %g1, %g2, %g1 ! clear this bit in %g1 - st %g1, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] + st %g1, [%curptr + AOFF_task_thread + AOFF_thread_uwinmask] save %g0, %g0, %g0 diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v2.3.15/linux/arch/sparc/kernel/head.S Wed Jun 9 14:44:25 1999 +++ linux/arch/sparc/kernel/head.S Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.96 1999/06/03 15:02:15 davem Exp $ +/* $Id: head.S,v 1.97 1999/08/14 03:51:10 anton Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1037,7 +1037,7 @@ #endif st %g6, [%g2] - st %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask] + st %g0, [%g6 + AOFF_task_thread + AOFF_thread_uwinmask] /* Compute NWINDOWS and stash it away. Now uses %wim trick explained * in the V8 manual. Ok, this method seems to work, Sparc is cool... diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/idprom.c linux/arch/sparc/kernel/idprom.c --- v2.3.15/linux/arch/sparc/kernel/idprom.c Tue Aug 4 16:03:34 1998 +++ linux/arch/sparc/kernel/idprom.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: idprom.c,v 1.23 1998/07/28 16:52:44 jj Exp $ +/* $Id: idprom.c,v 1.24 1999/08/31 06:54:20 davem Exp $ * idprom.c: Routines to load the idprom into kernel addresses and * interpret the data contained within. * @@ -46,7 +46,7 @@ /* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */ { "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } }; -__initfunc(static void display_system_type(unsigned char machtype)) +static void __init display_system_type(unsigned char machtype) { char sysname[128]; register int i; @@ -69,7 +69,7 @@ } /* Calculate the IDPROM checksum (xor of the data bytes). */ -__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom)) +static unsigned char __init calc_idprom_cksum(struct idprom *idprom) { unsigned char cksum, i, *ptr = (unsigned char *)idprom; @@ -80,7 +80,7 @@ } /* Create a local IDPROM copy, verify integrity, and display information. */ -__initfunc(void idprom_init(void)) +void __init idprom_init(void) { prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer)); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.3.15/linux/arch/sparc/kernel/irq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/kernel/irq.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.94 1999/05/28 14:59:20 anton Exp $ +/* $Id: irq.c,v 1.96 1999/08/31 06:54:21 davem 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 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -711,7 +711,7 @@ * */ -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { extern void sun4c_init_IRQ( void ); extern void sun4m_init_IRQ( void ); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c --- v2.3.15/linux/arch/sparc/kernel/pcic.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/kernel/pcic.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.7 1999/07/23 01:56:07 davem Exp $ +/* $Id: pcic.c,v 1.8 1999/08/31 06:54:22 davem Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -167,7 +167,7 @@ static void pci_do_gettimeofday(struct timeval *tv); static void pci_do_settimeofday(struct timeval *tv); -__initfunc(void pcic_probe(void)) +void __init pcic_probe(void) { struct linux_prom_registers regs[PROMREG_MAX]; struct linux_pbm_info* pbm; @@ -274,7 +274,7 @@ } } -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { /* * PCIC should be initialized at start of the timer. @@ -309,8 +309,8 @@ return pcic != NULL; } -__initfunc(static int pdev_to_pnode(struct linux_pbm_info *pbm, - struct pci_dev *pdev)) +static int __init pdev_to_pnode(struct linux_pbm_info *pbm, + struct pci_dev *pdev) { struct linux_prom_pci_registers regs[PROMREG_MAX]; int err; @@ -506,7 +506,7 @@ /* * Stolen from both i386 and sparc64 branch */ -__initfunc(void pcibios_fixup(void)) +void __init pcibios_fixup(void) { struct pci_dev *dev; int i, has_io, has_mem; @@ -611,7 +611,7 @@ #define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */ #define TICK_TIMER_LIMIT ((100*1000000/4)/100) -__initfunc(void pci_time_init(void)) +void __init pci_time_init(void) { unsigned long v; int timer_irq, irq; @@ -802,7 +802,7 @@ return PCIBIOS_SUCCESSFUL; } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { return str; } @@ -973,7 +973,7 @@ writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); } -__initfunc(void sun4m_pci_init_IRQ(void)) +void __init sun4m_pci_init_IRQ(void) { BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM); @@ -985,7 +985,7 @@ BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM); } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +void __init pcibios_fixup_bus(struct pci_bus *bus) { } diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.3.15/linux/arch/sparc/kernel/process.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/kernel/process.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.138 1999/07/23 01:56:10 davem Exp $ +/* $Id: process.c,v 1.139 1999/08/14 03:51:14 anton Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -51,7 +51,7 @@ /* * the idle loop on a Sparc... ;) */ -asmlinkage int sys_idle(void) +int cpu_idle(void) { int ret = -EPERM; @@ -107,7 +107,7 @@ #else /* This is being executed in task 0 'user space'. */ -int cpu_idle(void *unused) +int cpu_idle(void) { /* endless idle loop with no priority at all */ current->priority = 0; @@ -123,15 +123,6 @@ } } -asmlinkage int sys_idle(void) -{ - if(current->pid != 0) - return -EPERM; - - cpu_idle(NULL); - return 0; -} - #endif extern char reboot_command []; @@ -299,33 +290,33 @@ } #if NOTUSED -void show_thread(struct thread_struct *tss) +void show_thread(struct thread_struct *thread) { int i; - printk("uwinmask: 0x%08lx kregs: 0x%08lx\n", tss->uwinmask, (unsigned long)tss->kregs); - show_regs(tss->kregs); - printk("sig_address: 0x%08lx sig_desc: 0x%08lx\n", tss->sig_address, tss->sig_desc); - printk("ksp: 0x%08lx kpc: 0x%08lx\n", tss->ksp, tss->kpc); - printk("kpsr: 0x%08lx kwim: 0x%08lx\n", tss->kpsr, tss->kwim); - printk("fork_kpsr: 0x%08lx fork_kwim: 0x%08lx\n", tss->fork_kpsr, tss->fork_kwim); + printk("uwinmask: 0x%08lx kregs: 0x%08lx\n", thread->uwinmask, (unsigned long)thread->kregs); + show_regs(thread->kregs); + printk("sig_address: 0x%08lx sig_desc: 0x%08lx\n", thread->sig_address, thread->sig_desc); + printk("ksp: 0x%08lx kpc: 0x%08lx\n", thread->ksp, thread->kpc); + printk("kpsr: 0x%08lx kwim: 0x%08lx\n", thread->kpsr, thread->kwim); + printk("fork_kpsr: 0x%08lx fork_kwim: 0x%08lx\n", thread->fork_kpsr, thread->fork_kwim); for (i = 0; i < NSWINS; i++) { - if (!tss->rwbuf_stkptrs[i]) + if (!thread->rwbuf_stkptrs[i]) continue; printk("reg_window[%d]:\n", i); - printk("stack ptr: 0x%08lx\n", tss->rwbuf_stkptrs[i]); - show_regwindow(&tss->reg_window[i]); + printk("stack ptr: 0x%08lx\n", thread->rwbuf_stkptrs[i]); + show_regwindow(&thread->reg_window[i]); } - printk("w_saved: 0x%08lx\n", tss->w_saved); + printk("w_saved: 0x%08lx\n", thread->w_saved); /* XXX missing: float_regs */ - printk("fsr: 0x%08lx fpqdepth: 0x%08lx\n", tss->fsr, tss->fpqdepth); + printk("fsr: 0x%08lx fpqdepth: 0x%08lx\n", thread->fsr, thread->fpqdepth); /* XXX missing: fpqueue */ - printk("flags: 0x%08lx current_ds: 0x%08lx\n", tss->flags, tss->current_ds.seg); + printk("flags: 0x%08lx current_ds: 0x%08lx\n", thread->flags, thread->current_ds.seg); - show_regwindow((struct reg_window *)tss->ksp); + show_regwindow((struct reg_window *)thread->ksp); /* XXX missing: core_exec */ } @@ -343,8 +334,8 @@ #endif /* Keep process from leaving FPU in a bogon state. */ put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, + ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); #ifndef __SMP__ last_task_used_math = NULL; #else @@ -355,10 +346,10 @@ void flush_thread(void) { - current->tss.w_saved = 0; + current->thread.w_saved = 0; /* No new signal delivery by default */ - current->tss.new_signal = 0; + current->thread.new_signal = 0; #ifndef __SMP__ if(last_task_used_math == current) { #else @@ -366,8 +357,8 @@ #endif /* Clean the fpu. */ put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, + ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); #ifndef __SMP__ last_task_used_math = NULL; #else @@ -376,24 +367,15 @@ } /* Now, this task is no longer a kernel thread. */ - current->tss.current_ds = USER_DS; - if (current->tss.flags & SPARC_FLAG_KTHREAD) { - current->tss.flags &= ~SPARC_FLAG_KTHREAD; + current->thread.current_ds = USER_DS; + if (current->thread.flags & SPARC_FLAG_KTHREAD) { + current->thread.flags &= ~SPARC_FLAG_KTHREAD; /* We must fixup kregs as well. */ - current->tss.kregs = (struct pt_regs *) + current->thread.kregs = (struct pt_regs *) (((unsigned long)current) + (TASK_UNION_SIZE - TRACEREG_SZ)); } - - /* Exec'ing out of a vfork() shared address space is - * tricky on sparc32. exec_mmap will not set the mmu - * context because it sets the new current->mm after - * calling init_new_context and activate_context is - * a nop on sparc32, so we gotta catch it here. And - * clone()'s had the same problem. -DaveM - */ - switch_to_context(current); } static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src) @@ -457,12 +439,10 @@ * temporarily so we can build the child clone stack frame * without deadlocking. */ - up(¤t->mm->mmap_sem); if (copy_to_user(sp, src, size)) sp = (struct sparc_stackf *) 0; else if (put_user(dst, &sp->fp)) sp = (struct sparc_stackf *) 0; - down(¤t->mm->mmap_sem); return sp; } @@ -499,8 +479,8 @@ if(current->flags & PF_USEDFPU) { #endif put_psr(get_psr() | PSR_EF); - fpsave(&p->tss.float_regs[0], &p->tss.fsr, - &p->tss.fpqueue[0], &p->tss.fpqdepth); + fpsave(&p->thread.float_regs[0], &p->thread.fsr, + &p->thread.fpqueue[0], &p->thread.fpqdepth); #ifdef __SMP__ current->flags &= ~PF_USEDFPU; #endif @@ -516,36 +496,36 @@ new_stack = (((struct reg_window *) childregs) - 1); copy_regwin(new_stack, (((struct reg_window *) regs) - 1)); - p->tss.ksp = (unsigned long) new_stack; + p->thread.ksp = (unsigned long) new_stack; #ifdef __SMP__ - p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8); - p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL; + p->thread.kpc = (((unsigned long) ret_from_smpfork) - 0x8); + p->thread.kpsr = current->thread.fork_kpsr | PSR_PIL; #else - p->tss.kpc = (((unsigned long) ret_from_syscall) - 0x8); - p->tss.kpsr = current->tss.fork_kpsr; + p->thread.kpc = (((unsigned long) ret_from_syscall) - 0x8); + p->thread.kpsr = current->thread.fork_kpsr; #endif - p->tss.kwim = current->tss.fork_kwim; + p->thread.kwim = current->thread.fork_kwim; if(regs->psr & PSR_PS) { extern struct pt_regs fake_swapper_regs; - p->tss.kregs = &fake_swapper_regs; + p->thread.kregs = &fake_swapper_regs; new_stack = (struct reg_window *) ((((unsigned long)p) + (TASK_UNION_SIZE)) - (REGWIN_SZ)); childregs->u_regs[UREG_FP] = (unsigned long) new_stack; - p->tss.flags |= SPARC_FLAG_KTHREAD; - p->tss.current_ds = KERNEL_DS; + p->thread.flags |= SPARC_FLAG_KTHREAD; + p->thread.current_ds = KERNEL_DS; memcpy((void *)new_stack, (void *)regs->u_regs[UREG_FP], sizeof(struct reg_window)); childregs->u_regs[UREG_G6] = (unsigned long) p; } else { - p->tss.kregs = childregs; + p->thread.kregs = childregs; childregs->u_regs[UREG_FP] = sp; - p->tss.flags &= ~SPARC_FLAG_KTHREAD; - p->tss.current_ds = USER_DS; + p->thread.flags &= ~SPARC_FLAG_KTHREAD; + p->thread.current_ds = USER_DS; if (sp != regs->u_regs[UREG_FP]) { struct sparc_stackf *childstack; @@ -601,7 +581,7 @@ 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->uexec = current->thread.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))); @@ -609,13 +589,13 @@ dump->u_dsize &= ~(PAGE_SIZE - 1); first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1)); dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1); - memcpy(&dump->fpu.fpstatus.fregs.regs[0], ¤t->tss.float_regs[0], (sizeof(unsigned long) * 32)); - dump->fpu.fpstatus.fsr = current->tss.fsr; + memcpy(&dump->fpu.fpstatus.fregs.regs[0], ¤t->thread.float_regs[0], (sizeof(unsigned long) * 32)); + dump->fpu.fpstatus.fsr = current->thread.fsr; dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0; - dump->fpu.fpstatus.fpq_count = current->tss.fpqdepth; - memcpy(&dump->fpu.fpstatus.fpq[0], ¤t->tss.fpqueue[0], + dump->fpu.fpstatus.fpq_count = current->thread.fpqdepth; + memcpy(&dump->fpu.fpstatus.fpq[0], ¤t->thread.fpqueue[0], ((sizeof(unsigned long) * 2) * 16)); - dump->sigcode = current->tss.sig_desc; + dump->sigcode = current->thread.sig_desc; } /* @@ -631,30 +611,30 @@ #ifdef __SMP__ if (current->flags & PF_USEDFPU) { put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, + ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); regs->psr &= ~(PSR_EF); current->flags &= ~(PF_USEDFPU); } #else if (current == last_task_used_math) { put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, + ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); last_task_used_math = 0; regs->psr &= ~(PSR_EF); } #endif memcpy(&fpregs->pr_fr.pr_regs[0], - ¤t->tss.float_regs[0], + ¤t->thread.float_regs[0], (sizeof(unsigned long) * 32)); - fpregs->pr_fsr = current->tss.fsr; - fpregs->pr_qcnt = current->tss.fpqdepth; + fpregs->pr_fsr = current->thread.fsr; + fpregs->pr_qcnt = current->thread.fpqdepth; fpregs->pr_q_entrysize = 8; fpregs->pr_en = 1; if(fpregs->pr_qcnt != 0) { memcpy(&fpregs->pr_q[0], - ¤t->tss.fpqueue[0], + ¤t->thread.fpqueue[0], sizeof(struct fpq) * fpregs->pr_qcnt); } /* Zero out the rest. */ diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.3.15/linux/arch/sparc/kernel/ptrace.c Mon Jul 5 11:30:11 1999 +++ linux/arch/sparc/kernel/ptrace.c Tue Aug 31 11:23:29 1999 @@ -70,8 +70,8 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, struct task_struct *tsk, long *addr) { - struct pt_regs *cregs = tsk->tss.kregs; - struct thread_struct *t = &tsk->tss; + struct pt_regs *cregs = tsk->thread.kregs; + struct thread_struct *t = &tsk->thread; int v; if(offset >= 1024) @@ -128,7 +128,7 @@ v = cregs->u_regs[UREG_I6]; break; case 924: - if(tsk->tss.flags & MAGIC_CONSTANT) + if(tsk->thread.flags & MAGIC_CONSTANT) v = cregs->u_regs[UREG_G1]; else v = 0; @@ -165,8 +165,8 @@ static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, struct task_struct *tsk) { - struct pt_regs *cregs = tsk->tss.kregs; - struct thread_struct *t = &tsk->tss; + struct pt_regs *cregs = tsk->thread.kregs; + struct thread_struct *t = &tsk->thread; unsigned long value = regs->u_regs[UREG_I3]; if(offset >= 1024) @@ -398,7 +398,7 @@ case PTRACE_GETREGS: { struct pt_regs *pregs = (struct pt_regs *) addr; - struct pt_regs *cregs = child->tss.kregs; + struct pt_regs *cregs = child->thread.kregs; int rval; rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs)); @@ -421,7 +421,7 @@ case PTRACE_SETREGS: { struct pt_regs *pregs = (struct pt_regs *) addr; - struct pt_regs *cregs = child->tss.kregs; + struct pt_regs *cregs = child->thread.kregs; unsigned long psr, pc, npc, y; int i; @@ -471,15 +471,15 @@ goto out; } for(i = 0; i < 32; i++) - __put_user(child->tss.float_regs[i], (&fps->regs[i])); - __put_user(child->tss.fsr, (&fps->fsr)); - __put_user(child->tss.fpqdepth, (&fps->fpqd)); + __put_user(child->thread.float_regs[i], (&fps->regs[i])); + __put_user(child->thread.fsr, (&fps->fsr)); + __put_user(child->thread.fpqdepth, (&fps->fpqd)); __put_user(0, (&fps->flags)); __put_user(0, (&fps->extra)); for(i = 0; i < 16; i++) { - __put_user(child->tss.fpqueue[i].insn_addr, + __put_user(child->thread.fpqueue[i].insn_addr, (&fps->fpq[i].insnaddr)); - __put_user(child->tss.fpqueue[i].insn, (&fps->fpq[i].insn)); + __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); } pt_succ_return(regs, 0); goto out; @@ -504,13 +504,13 @@ pt_error_return(regs, -i); goto out; } - copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); - __get_user(child->tss.fsr, (&fps->fsr)); - __get_user(child->tss.fpqdepth, (&fps->fpqd)); + copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); + __get_user(child->thread.fsr, (&fps->fsr)); + __get_user(child->thread.fpqdepth, (&fps->fpqd)); for(i = 0; i < 16; i++) { - __get_user(child->tss.fpqueue[i].insn_addr, + __get_user(child->thread.fpqueue[i].insn_addr, (&fps->fpq[i].insnaddr)); - __get_user(child->tss.fpqueue[i].insn, (&fps->fpq[i].insn)); + __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); } pt_succ_return(regs, 0); goto out; @@ -560,11 +560,11 @@ goto out; } #ifdef DEBUG_PTRACE - printk ("Original: %08lx %08lx\n", child->tss.kregs->pc, child->tss.kregs->npc); + printk ("Original: %08lx %08lx\n", child->thread.kregs->pc, child->thread.kregs->npc); printk ("Continuing with %08lx %08lx\n", addr, addr+4); #endif - child->tss.kregs->pc = addr; - child->tss.kregs->npc = addr + 4; + child->thread.kregs->pc = addr; + child->thread.kregs->npc = addr + 4; } if (request == PTRACE_SYSCALL) @@ -576,8 +576,8 @@ #ifdef DEBUG_PTRACE printk("CONT: %s [%d]: set exit_code = %x %x %x\n", child->comm, child->pid, child->exit_code, - child->tss.kregs->pc, - child->tss.kregs->npc); + child->thread.kregs->pc, + child->thread.kregs->npc); #endif wake_up_process(child); @@ -639,7 +639,7 @@ return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; - current->tss.flags ^= MAGIC_CONSTANT; + current->thread.flags ^= MAGIC_CONSTANT; notify_parent(current, SIGCHLD); schedule(); /* diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v2.3.15/linux/arch/sparc/kernel/rtrap.S Tue Aug 4 16:03:34 1998 +++ linux/arch/sparc/kernel/rtrap.S Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.51 1998/07/26 03:02:38 davem Exp $ +/* $Id: rtrap.S,v 1.52 1999/08/14 03:51:18 anton Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -95,7 +95,7 @@ wr %t_psr, 0x0, %psr WRITE_PAUSE - ld [%curptr + AOFF_task_tss + AOFF_thread_w_saved], %twin_tmp1 + ld [%curptr + AOFF_task_thread + AOFF_thread_w_saved], %twin_tmp1 orcc %g0, %twin_tmp1, %g0 be ret_trap_nobufwins nop @@ -119,7 +119,7 @@ /* If there are already live user windows in the * set we can return from trap safely. */ - ld [%curptr + AOFF_task_tss + AOFF_thread_uwinmask], %twin_tmp1 + ld [%curptr + AOFF_task_thread + AOFF_thread_uwinmask], %twin_tmp1 orcc %g0, %twin_tmp1, %g0 bne ret_trap_userwins_ok nop diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/semaphore.c linux/arch/sparc/kernel/semaphore.c --- v2.3.15/linux/arch/sparc/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc/kernel/semaphore.c Tue Aug 31 11:23:29 1999 @@ -0,0 +1,129 @@ +/* $Id: semaphore.c,v 1.1 1999/08/31 13:26:15 anton Exp $ + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.3.15/linux/arch/sparc/kernel/setup.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/kernel/setup.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.108 1999/07/30 09:35:03 davem Exp $ +/* $Id: setup.c,v 1.110 1999/08/31 06:54:23 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -153,7 +153,7 @@ * Process kernel command line switches that are specific to the * SPARC or that require special low-level processing. */ -__initfunc(static void process_switch(char c)) +static void __init process_switch(char c) { switch (c) { case 'd': @@ -172,7 +172,7 @@ } } -__initfunc(static void boot_flags_init(char *commands)) +static void __init boot_flags_init(char *commands) { while (*commands) { /* Move to the start of the next "argument". */ @@ -297,8 +297,8 @@ "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)) +void __init setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) { int total, i, packed; @@ -425,6 +425,8 @@ initrd_start -= KERNBASE; initrd_end -= KERNBASE; break; + default: + break; } } } @@ -493,7 +495,7 @@ init_mm.mmap->vm_start = KERNBASE; init_mm.mmap->vm_end = *memory_end_p; init_mm.context = (unsigned long) NO_CONTEXT; - init_task.tss.kregs = &fake_swapper_regs; + init_task.thread.kregs = &fake_swapper_regs; if (serial_console) conswitchp = NULL; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.3.15/linux/arch/sparc/kernel/signal.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/kernel/signal.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.94 1999/07/30 09:35:04 davem Exp $ +/* $Id: signal.c,v 1.95 1999/08/14 03:51:22 anton Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -211,12 +211,12 @@ if (verify_area (VERIFY_READ, fpu, sizeof(*fpu))) return -EFAULT; - err = __copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0], + err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0], (sizeof(unsigned long) * 32)); - err |= __get_user(current->tss.fsr, &fpu->si_fsr); - err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); - if (current->tss.fpqdepth != 0) - err |= __copy_from_user(¤t->tss.fpqueue[0], + err |= __get_user(current->thread.fsr, &fpu->si_fsr); + err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); + if (current->thread.fpqdepth != 0) + err |= __copy_from_user(¤t->thread.fpqueue[0], &fpu->si_fpqueue[0], ((sizeof(unsigned long) + (sizeof(unsigned long *)))*16)); @@ -289,7 +289,7 @@ synchronize_user_stack(); - if (current->tss.new_signal) + if (current->thread.new_signal) return do_new_sigreturn (regs); scptr = (struct sigcontext *) regs->u_regs[UREG_I0]; @@ -459,28 +459,28 @@ err |= __put_user(regs->psr, &sc->sigc_psr); err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); - err |= __put_user(current->tss.w_saved, &sc->sigc_oswins); - if(current->tss.w_saved) - for(window = 0; window < current->tss.w_saved; window++) { + err |= __put_user(current->thread.w_saved, &sc->sigc_oswins); + if(current->thread.w_saved) + for(window = 0; window < current->thread.w_saved; window++) { sc->sigc_spbuf[window] = - (char *)current->tss.rwbuf_stkptrs[window]; + (char *)current->thread.rwbuf_stkptrs[window]; err |= __copy_to_user(&sc->sigc_wbuf[window], - ¤t->tss.reg_window[window], + ¤t->thread.reg_window[window], sizeof(struct reg_window)); } else err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP], sizeof(struct reg_window)); - current->tss.w_saved = 0; /* So process is allowed to execute. */ + current->thread.w_saved = 0; /* So process is allowed to execute. */ err |= __put_user(signr, &sframep->sig_num); if(signr == SIGSEGV || signr == SIGILL || signr == SIGFPE || signr == SIGBUS || signr == SIGEMT) { - err |= __put_user(current->tss.sig_desc, &sframep->sig_code); - err |= __put_user(current->tss.sig_address, &sframep->sig_address); + err |= __put_user(current->thread.sig_desc, &sframep->sig_code); + err |= __put_user(current->thread.sig_address, &sframep->sig_address); } else { err |= __put_user(0, &sframep->sig_code); err |= __put_user(0, &sframep->sig_address); @@ -508,26 +508,26 @@ #ifdef __SMP__ if (current->flags & PF_USEDFPU) { put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, + ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); regs->psr &= ~(PSR_EF); current->flags &= ~(PF_USEDFPU); } #else if (current == last_task_used_math) { put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, + ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); last_task_used_math = 0; regs->psr &= ~(PSR_EF); } #endif - err |= __copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], + err |= __copy_to_user(&fpu->si_float_regs[0], ¤t->thread.float_regs[0], (sizeof(unsigned long) * 32)); - err |= __put_user(current->tss.fsr, &fpu->si_fsr); - err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); - if (current->tss.fpqdepth != 0) - err |= __copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], + err |= __put_user(current->thread.fsr, &fpu->si_fsr); + err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth); + if (current->thread.fpqdepth != 0) + err |= __copy_to_user(&fpu->si_fpqueue[0], ¤t->thread.fpqueue[0], ((sizeof(unsigned long) + (sizeof(unsigned long *)))*16)); current->used_math = 0; @@ -553,7 +553,7 @@ if (invalid_frame_pointer (sf, sigframe_size)) goto sigill_and_return; - if (current->tss.w_saved != 0) { + if (current->thread.w_saved != 0) { #ifdef DEBUG_SIGNALS printk ("%s [%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); @@ -631,7 +631,7 @@ sf = (struct rt_signal_frame *)get_sigframe(&ka->sa, regs, sigframe_size); if(invalid_frame_pointer(sf, sigframe_size)) goto sigill; - if(current->tss.w_saved != 0) + if(current->thread.w_saved != 0) goto sigill; err = __put_user(regs->pc, &sf->regs.pc); @@ -764,7 +764,7 @@ err |= __put_user(gw, &mc->gwin); /* 2. Number of windows to restore at setcontext (): */ - err |= __put_user(current->tss.w_saved, &gw->count); + err |= __put_user(current->thread.w_saved, &gw->count); /* 3. Save each valid window * Currently, it makes a copy of the windows from the kernel copy. @@ -777,21 +777,21 @@ * These windows are just used in case synchronize_user_stack failed * to flush the user windows. */ - for(window = 0; window < current->tss.w_saved; window++) { + for(window = 0; window < current->thread.w_saved; window++) { err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]); err |= __copy_to_user(&gw->win [window], - ¤t->tss.reg_window [window], + ¤t->thread.reg_window [window], sizeof (svr4_rwindow_t)); err |= __put_user(0, gw->winptr [window]); } /* 4. We just pay attention to the gw->count field on setcontext */ - current->tss.w_saved = 0; /* So process is allowed to execute. */ + current->thread.w_saved = 0; /* So process is allowed to execute. */ /* Setup the signal information. Solaris expects a bunch of * information to be passed to the signal handler, we don't provide * that much currently, should use those that David already - * is providing with tss.sig_desc + * is providing with thread.sig_desc */ err |= __put_user(signr, &si->siginfo.signo); err |= __put_user(SVR4_SINOINFO, &si->siginfo.code); @@ -837,7 +837,7 @@ synchronize_user_stack(); - if (current->tss.w_saved) + if (current->thread.w_saved) goto sigsegv_and_return; err = clear_user(uc, sizeof (*uc)); @@ -884,7 +884,7 @@ /* Set the context for a svr4 application, this is Solaris way to sigreturn */ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs) { - struct thread_struct *tp = ¤t->tss; + struct thread_struct *tp = ¤t->thread; svr4_gregset_t *gr; unsigned long pc, npc, psr; sigset_t set; @@ -973,7 +973,7 @@ else { if (ka->sa.sa_flags & SA_SIGINFO) new_setup_rt_frame(ka, regs, signr, oldset, info); - else if (current->tss.new_signal) + else if (current->thread.new_signal) new_setup_frame (ka, regs, signr, oldset); else setup_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.3.15/linux/arch/sparc/kernel/smp.c Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/kernel/smp.c Tue Aug 31 11:23:29 1999 @@ -74,7 +74,7 @@ volatile int smp_commenced = 0; /* Not supported on Sparc yet. */ -__initfunc(void smp_setup(char *str, int *ints)) +void __init smp_setup(char *str, int *ints) { } @@ -83,12 +83,12 @@ * a given CPU */ -__initfunc(void smp_store_cpu_info(int id)) +void __init smp_store_cpu_info(int id) { cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */ } -__initfunc(void smp_commence(void)) +void __init smp_commence(void) { /* * Lets the callin's below out of their loop. @@ -103,17 +103,17 @@ /* Only broken Intel needs this, thus it should not even be referenced * globally... */ -__initfunc(void initialize_secondary(void)) +void __init initialize_secondary(void) { } -extern int cpu_idle(void *unused); +extern int cpu_idle(void); /* Activate a secondary processor. */ int start_secondary(void *unused) { prom_printf("Start secondary called. Should not happen\n"); - return cpu_idle(NULL); + return cpu_idle(); } void cpu_panic(void) @@ -129,7 +129,7 @@ extern struct prom_cpuinfo linux_cpus[NR_CPUS]; struct linux_prom_registers smp_penguin_ctable __initdata = { 0 }; -__initfunc(void smp_boot_cpus(void)) +void __init smp_boot_cpus(void) { extern void smp4m_boot_cpus(void); extern void smp4d_boot_cpus(void); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/solaris.c linux/arch/sparc/kernel/solaris.c --- v2.3.15/linux/arch/sparc/kernel/solaris.c Sun Jan 26 02:07:07 1997 +++ linux/arch/sparc/kernel/solaris.c Tue Aug 31 11:23:29 1999 @@ -13,8 +13,6 @@ #include #include -extern asmlinkage int sys_open(const char *,int,int); - asmlinkage int solaris_open(const char *filename, int flags, int mode) { int newflags; @@ -39,5 +37,3 @@ unlock_kernel(); return ret; } - - diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sun4c_irq.c linux/arch/sparc/kernel/sun4c_irq.c --- v2.3.15/linux/arch/sparc/kernel/sun4c_irq.c Sun Oct 4 10:22:42 1998 +++ linux/arch/sparc/kernel/sun4c_irq.c Thu Aug 26 12:42:32 1999 @@ -138,7 +138,7 @@ /* Errm.. not sure how to do this.. */ } -__initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))) +static void __init sun4c_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)) { int irq; @@ -184,7 +184,7 @@ extern char *sun4m_irq_itoa(unsigned int irq); -__initfunc(void sun4c_init_IRQ(void)) +void __init sun4c_init_IRQ(void) { struct linux_prom_registers int_regs[2]; int ie_node; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c --- v2.3.15/linux/arch/sparc/kernel/sun4d_irq.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/kernel/sun4d_irq.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.18 1999/04/20 13:22:30 anton Exp $ +/* $Id: sun4d_irq.c,v 1.19 1999/08/31 06:54:25 davem Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -366,7 +366,7 @@ } /* Setup IRQ distribution scheme. */ -__initfunc(void sun4d_distribute_irqs(void)) +void __init sun4d_distribute_irqs(void) { #ifdef DISTRIBUTE_IRQS struct linux_sbus *sbus; @@ -431,7 +431,7 @@ bw_set_prof_limit(cpu, limit); } -__initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))) +static void __init sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)) { int irq; extern struct prom_cpuinfo linux_cpus[NR_CPUS]; @@ -492,7 +492,7 @@ #endif } -__initfunc(void sun4d_init_sbi_irq(void)) +void __init sun4d_init_sbi_irq(void) { struct linux_sbus *sbus; unsigned mask; @@ -529,7 +529,7 @@ return buff; } -__initfunc(void sun4d_init_IRQ(void)) +void __init sun4d_init_IRQ(void) { __cli(); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.3.15/linux/arch/sparc/kernel/sun4d_smp.c Fri Jul 23 12:20:23 1999 +++ linux/arch/sparc/kernel/sun4d_smp.c Thu Aug 26 12:42:32 1999 @@ -83,7 +83,7 @@ extern void cpu_probe(void); extern void sun4d_distribute_irqs(void); -__initfunc(void smp4d_callin(void)) +void __init smp4d_callin(void) { int cpuid = hard_smp4d_processor_id(); extern spinlock_t sun4d_imsk_lock; @@ -161,7 +161,7 @@ extern unsigned long trapbase_cpu2[]; extern unsigned long trapbase_cpu3[]; -__initfunc(void smp4d_boot_cpus(void)) +void __init smp4d_boot_cpus(void) { int cpucount = 0; int i = 0; @@ -499,7 +499,7 @@ extern unsigned int lvl14_resolution; -__initfunc(static void smp_setup_percpu_timer(void)) +static void __init smp_setup_percpu_timer(void) { int cpu = hard_smp4d_processor_id(); @@ -507,7 +507,7 @@ load_profile_irq(cpu, lvl14_resolution); } -__initfunc(void smp4d_blackbox_id(unsigned *addr)) +void __init smp4d_blackbox_id(unsigned *addr) { int rd = *addr & 0x3e000000; @@ -516,7 +516,7 @@ addr[2] = 0x01000000; /* nop */ } -__initfunc(void smp4d_blackbox_current(unsigned *addr)) +void __init smp4d_blackbox_current(unsigned *addr) { /* We have a nice Linux current register :) */ int rd = addr[1] & 0x3e000000; @@ -525,7 +525,7 @@ addr[1] = 0xc0800820 | rd; /* lda [%g0] ASI_M_VIKING_TMP2, reg */ } -__initfunc(void sun4d_init_smp(void)) +void __init sun4d_init_smp(void) { int i; extern unsigned int patchme_store_new_current[]; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c --- v2.3.15/linux/arch/sparc/kernel/sun4m_irq.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/kernel/sun4m_irq.c Thu Aug 26 12:42:32 1999 @@ -220,7 +220,7 @@ return buff; } -__initfunc(static void sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))) +static void __init sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)) { int reg_count, irq, cpu; struct linux_prom_registers cnt_regs[PROMREG_MAX]; @@ -303,7 +303,7 @@ #endif } -__initfunc(void sun4m_init_IRQ(void)) +void __init sun4m_init_IRQ(void) { int ie_node,i; struct linux_prom_registers int_regs[PROMREG_MAX]; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.3.15/linux/arch/sparc/kernel/sun4m_smp.c Fri Jul 23 12:20:23 1999 +++ linux/arch/sparc/kernel/sun4m_smp.c Thu Aug 26 12:42:32 1999 @@ -77,7 +77,7 @@ static void smp_setup_percpu_timer(void); extern void cpu_probe(void); -__initfunc(void smp4m_callin(void)) +void __init smp4m_callin(void) { int cpuid = hard_smp_processor_id(); @@ -135,7 +135,7 @@ extern unsigned long trapbase_cpu2[]; extern unsigned long trapbase_cpu3[]; -__initfunc(void smp4m_boot_cpus(void)) +void __init smp4m_boot_cpus(void) { int cpucount = 0; int i = 0; @@ -479,7 +479,7 @@ extern unsigned int lvl14_resolution; -__initfunc(static void smp_setup_percpu_timer(void)) +static void __init smp_setup_percpu_timer(void) { int cpu = smp_processor_id(); @@ -490,7 +490,7 @@ enable_pil_irq(14); } -__initfunc(void smp4m_blackbox_id(unsigned *addr)) +void __init smp4m_blackbox_id(unsigned *addr) { int rd = *addr & 0x3e000000; int rs1 = rd >> 11; @@ -500,7 +500,7 @@ addr[2] = 0x80082003 | rd | rs1; /* and reg, 3, reg */ } -__initfunc(void smp4m_blackbox_current(unsigned *addr)) +void __init smp4m_blackbox_current(unsigned *addr) { int rd = *addr & 0x3e000000; int rs1 = rd >> 11; @@ -510,7 +510,7 @@ addr[4] = 0x8008200c | rd | rs1; /* and reg, 3, reg */ } -__initfunc(void sun4m_init_smp(void)) +void __init sun4m_init_smp(void) { BTFIXUPSET_BLACKBOX(smp_processor_id, smp4m_blackbox_id); BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sun4setup.c linux/arch/sparc/kernel/sun4setup.c --- v2.3.15/linux/arch/sparc/kernel/sun4setup.c Tue Aug 4 23:57:51 1998 +++ linux/arch/sparc/kernel/sun4setup.c Thu Aug 26 12:42:32 1999 @@ -23,7 +23,7 @@ int sun4_esp_physaddr; int sun4_ie_physaddr; -__initfunc(void sun4setup()) +void __init sun4setup(void) { printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). "); /* diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.3.15/linux/arch/sparc/kernel/sys_sparc.c Tue May 11 08:24:31 1999 +++ linux/arch/sparc/kernel/sys_sparc.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $ +/* $Id: sys_sparc.c,v 1.53 1999/08/14 03:51:25 anton Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -263,7 +263,7 @@ int ret; if (sig < 0) { - current->tss.new_signal = 1; + current->thread.new_signal = 1; sig = -sig; } @@ -313,7 +313,7 @@ /* All tasks which use RT signals (effectively) use * new style signals. */ - current->tss.new_signal = 1; + current->thread.new_signal = 1; if (act) { new_ka.ka_restorer = restorer; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.3.15/linux/arch/sparc/kernel/sys_sunos.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/kernel/sys_sunos.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.102 1999/07/23 01:56:19 davem Exp $ +/* $Id: sys_sunos.c,v 1.104 1999/08/31 12:30:50 anton Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -597,9 +597,9 @@ struct pt_regs *regs; lock_kernel(); - regs = current->tss.kregs; - current->tss.sig_address = regs->pc; - current->tss.sig_desc = regs->u_regs[UREG_G1]; + regs = current->thread.kregs; + current->thread.sig_address = regs->pc; + current->thread.sig_desc = regs->u_regs[UREG_G1]; send_sig(SIGSYS, current, 1); printk("Process makes ni_syscall number %d, register dump:\n", (int) regs->u_regs[UREG_G1]); @@ -1009,10 +1009,6 @@ return ret; } -extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); -extern asmlinkage int sys_semget (key_t key, int nsems, int semflg); -extern asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops); - asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2, unsigned long arg3, void *ptr) { @@ -1059,13 +1055,6 @@ return ret; } -extern asmlinkage int sys_msgget (key_t key, int msgflg); -extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, - size_t msgsz, long msgtyp, int msgflg); -extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, - size_t msgsz, int msgflg); -extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); - asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) { @@ -1083,7 +1072,7 @@ (struct msqid_ds *)arg3); break; case 2: - sp = (struct sparc_stackf *)current->tss.kregs->u_regs[UREG_FP]; + sp = (struct sparc_stackf *)current->thread.kregs->u_regs[UREG_FP]; arg5 = sp->xxargs[0]; rval = sys_msgrcv((int)arg1, (struct msgbuf *)arg2, (size_t)arg3, (long)arg4, (int)arg5); @@ -1099,11 +1088,6 @@ unlock_kernel(); return rval; } - -extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); -extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); -extern asmlinkage int sys_shmdt (char *shmaddr); -extern asmlinkage int sys_shmget (key_t key, int size, int shmflg); asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2, unsigned long arg3) diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.3.15/linux/arch/sparc/kernel/systbls.S Wed Jul 28 10:30:10 1999 +++ linux/arch/sparc/kernel/systbls.S Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.83 1999/04/07 17:14:06 davem Exp $ +/* $Id: systbls.S,v 1.84 1999/08/14 03:51:29 anton Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -58,7 +58,7 @@ /*195*/ .long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask /*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir /*205*/ .long sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall -/*210*/ .long sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo +/*210*/ .long sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo /*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex /*220*/ .long sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid /*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/tadpole.c linux/arch/sparc/kernel/tadpole.c --- v2.3.15/linux/arch/sparc/kernel/tadpole.c Tue Apr 14 17:44:19 1998 +++ linux/arch/sparc/kernel/tadpole.c Thu Aug 26 12:42:32 1999 @@ -95,7 +95,7 @@ clk_ctrl[0] = 0; } -__initfunc(void clock_stop_probe(void)) +void __init clock_stop_probe(void) { unsigned int node, clk_nd; char name[20]; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v2.3.15/linux/arch/sparc/kernel/time.c Mon Mar 15 16:10:43 1999 +++ linux/arch/sparc/kernel/time.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.43 1999/03/15 22:13:31 davem Exp $ +/* $Id: time.c,v 1.46 1999/08/31 13:11:26 anton Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -42,8 +42,8 @@ extern rwlock_t xtime_lock; enum sparc_clock_type sp_clock_typ; -struct mostek48t02 *mstk48t02_regs = 0; -struct mostek48t08 *mstk48t08_regs = 0; +unsigned long mstk48t02_regs = 0UL; +static struct mostek48t08 *mstk48t08_regs = 0; static int set_rtc_mmss(unsigned long); static void sbus_do_settimeofday(struct timeval *tv); @@ -140,9 +140,9 @@ } /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ -__initfunc(static void kick_start_clock(void)) +static void __init kick_start_clock(void) { - register struct mostek48t02 *regs = mstk48t02_regs; + struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned char sec; int i, count; @@ -191,7 +191,7 @@ /* Return nonzero if the clock chip battery is low. */ static __inline__ int has_low_battery(void) { - register struct mostek48t02 *regs = mstk48t02_regs; + struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned char data1, data2; data1 = regs->eeprom[0]; /* Read some data. */ @@ -210,15 +210,15 @@ if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) { sp_clock_typ = MSTK48T02; - mstk48t02_regs = (struct mostek48t02 *) + mstk48t02_regs = (unsigned long) sparc_alloc_io(sun4_clock_physaddr, 0, - sizeof(*mstk48t02_regs), + sizeof(struct mostek48t02), "clock", 0x0, 0x0); mstk48t08_regs = 0; /* To catch weirdness */ intersil_clock = 0; /* just in case */ /* Kick start the clock if it is completely stopped. */ - if (mstk48t02_regs->sec & MSTK_STOP) + if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) { /* intersil setup code */ @@ -297,9 +297,9 @@ else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ - mstk48t02_regs = (struct mostek48t02 *) + mstk48t02_regs = (unsigned long) sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t02_regs), + (void *) 0, sizeof(struct mostek48t02), "clock", clk_reg[0].which_io, 0x0); mstk48t08_regs = 0; /* To catch weirdness */ } else if (strcmp(model, "mk48t08") == 0) { @@ -319,7 +319,7 @@ (void *) 0, sizeof(*mstk48t08_regs), "clock", clk_reg[0].which_io, 0x0); - mstk48t02_regs = &mstk48t08_regs->regs; + mstk48t02_regs = (unsigned long)&mstk48t08_regs->regs; } else { prom_printf("CLOCK: Unknown model name '%s'\n",model); prom_halt(); @@ -330,11 +330,11 @@ printk(KERN_CRIT "NVRAM: Low battery voltage!\n"); /* Kick start the clock if it is completely stopped. */ - if (mstk48t02_regs->sec & MSTK_STOP) + if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); } -__initfunc(void sbus_time_init(void)) +void __init sbus_time_init(void) { unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs; @@ -364,7 +364,7 @@ #ifdef CONFIG_SUN4 if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) { #endif - mregs = mstk48t02_regs; + mregs = (struct mostek48t02 *)mstk48t02_regs; if(!mregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); prom_halt(); @@ -416,7 +416,7 @@ __sti(); } -__initfunc(void time_init(void)) +void __init time_init(void) { #ifdef CONFIG_PCI extern void pci_time_init(void); @@ -521,7 +521,7 @@ static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, mostek_minutes; - struct mostek48t02 *regs = mstk48t02_regs; + struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; #ifdef CONFIG_SUN4 struct intersil *iregs = intersil_clock; int temp; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c --- v2.3.15/linux/arch/sparc/kernel/traps.c Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/kernel/traps.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.59 1999/03/06 12:07:31 anton Exp $ +/* $Id: traps.c,v 1.60 1999/08/14 03:51:31 anton Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -132,17 +132,17 @@ if(type < 0x80) { /* Sun OS's puke from bad traps, Linux survives! */ printk("Unimplemented Sparc TRAP, type = %02lx\n", type); - die_if_kernel("Whee... Hello Mr. Penguin", current->tss.kregs); + die_if_kernel("Whee... Hello Mr. Penguin", current->thread.kregs); } if(type == SP_TRAP_SBPT) { send_sig(SIGTRAP, current, 1); } else { if(psr & PSR_PS) - die_if_kernel("Kernel bad trap", current->tss.kregs); + die_if_kernel("Kernel bad trap", current->thread.kregs); - current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80); - current->tss.sig_address = pc; + current->thread.sig_desc = SUBSIG_BADTRAP(type - 0x80); + current->thread.sig_address = pc; send_sig(SIGILL, current, 1); } unlock_kernel(); @@ -163,8 +163,8 @@ if (!do_user_muldiv (regs, pc)) goto out; } - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_ILLINST; + current->thread.sig_address = pc; + current->thread.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); out: unlock_kernel(); @@ -176,8 +176,8 @@ lock_kernel(); if(psr & PSR_PS) die_if_kernel("Penguin instruction from Penguin mode??!?!", regs); - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = pc; + current->thread.sig_desc = SUBSIG_PRIVINST; send_sig(SIGILL, current, 1); unlock_kernel(); } @@ -194,8 +194,8 @@ die_if_kernel("BOGUS", regs); /* die_if_kernel("Kernel MNA access", regs); */ } - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = pc; + current->thread.sig_desc = SUBSIG_PRIVINST; #if 0 show_regs (regs); instruction_dump ((unsigned long *) regs->pc); @@ -232,12 +232,12 @@ if(last_task_used_math) { /* Other processes fpu state, save away */ struct task_struct *fptask = last_task_used_math; - fpsave(&fptask->tss.float_regs[0], &fptask->tss.fsr, - &fptask->tss.fpqueue[0], &fptask->tss.fpqdepth); + fpsave(&fptask->thread.float_regs[0], &fptask->thread.fsr, + &fptask->thread.fpqueue[0], &fptask->thread.fpqdepth); } last_task_used_math = current; if(current->used_math) { - fpload(¤t->tss.float_regs[0], ¤t->tss.fsr); + fpload(¤t->thread.float_regs[0], ¤t->thread.fsr); } else { /* Set initial sane state. */ fpload(&init_fregs[0], &init_fsr); @@ -248,7 +248,7 @@ fpload(&init_fregs[0], &init_fsr); current->used_math = 1; } else { - fpload(¤t->tss.float_regs[0], ¤t->tss.fsr); + fpload(¤t->thread.float_regs[0], ¤t->thread.fsr); } current->flags |= PF_USEDFPU; #endif @@ -290,13 +290,13 @@ regs->psr &= ~PSR_EF; goto out; } - fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr, - &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth); + fpsave(&fpt->thread.float_regs[0], &fpt->thread.fsr, + &fpt->thread.fpqueue[0], &fpt->thread.fpqdepth); #ifdef DEBUG_FPU - printk("Hmm, FP exception, fsr was %016lx\n", fpt->tss.fsr); + printk("Hmm, FP exception, fsr was %016lx\n", fpt->thread.fsr); #endif - switch ((fpt->tss.fsr & 0x1c000)) { + switch ((fpt->thread.fsr & 0x1c000)) { /* switch on the contents of the ftt [floating point trap type] field */ #ifdef DEBUG_FPU case (1 << 14): @@ -321,13 +321,13 @@ } /* If we successfully emulated the FPop, we pretend the trap never happened :-> */ if (ret) { - fpload(¤t->tss.float_regs[0], ¤t->tss.fsr); + fpload(¤t->thread.float_regs[0], ¤t->thread.fsr); return; } /* nope, better SIGFPE the offending process... */ - fpt->tss.sig_address = pc; - fpt->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */ + fpt->thread.sig_address = pc; + fpt->thread.sig_desc = SUBSIG_FPERROR; /* as good as any */ #ifdef __SMP__ fpt->flags &= ~PF_USEDFPU; #endif @@ -362,8 +362,8 @@ lock_kernel(); if(psr & PSR_PS) die_if_kernel("Penguin overflow trap from kernel mode", regs); - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_TAG; /* as good as any */ + current->thread.sig_address = pc; + current->thread.sig_desc = SUBSIG_TAG; /* as good as any */ send_sig(SIGEMT, current, 1); unlock_kernel(); } @@ -436,4 +436,11 @@ void trap_init(void) { + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + + /* NOTE: Other cpus have this done as they are started + * up on SMP. + */ } diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/unaligned.c linux/arch/sparc/kernel/unaligned.c --- v2.3.15/linux/arch/sparc/kernel/unaligned.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/kernel/unaligned.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.18 1999/04/03 11:36:17 anton Exp $ +/* $Id: unaligned.c,v 1.19 1999/08/14 03:51:33 anton Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -61,7 +61,7 @@ return 2; else { printk("Impossible unaligned trap. insn=%08x\n", insn); - die_if_kernel("Byte sized unaligned access?!?!", current->tss.kregs); + die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs); return 4; /* just to keep gcc happy. */ } } @@ -422,8 +422,8 @@ void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) { - current->tss.sig_address = regs->pc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = regs->pc; + current->thread.sig_desc = SUBSIG_PRIVINST; send_sig(SIGBUS, current, 1); } @@ -432,7 +432,7 @@ enum direction dir; lock_kernel(); - if(!(current->tss.flags & SPARC_FLAG_UNALIGNED) || + if(!(current->thread.flags & SPARC_FLAG_UNALIGNED) || (((insn >> 30) & 3) != 3)) goto kill_user; dir = decode_direction(insn); @@ -487,8 +487,8 @@ } kill_user: - current->tss.sig_address = regs->pc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = regs->pc; + current->thread.sig_desc = SUBSIG_PRIVINST; send_sig(SIGBUS, current, 1); out: unlock_kernel(); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/windows.c linux/arch/sparc/kernel/windows.c --- v2.3.15/linux/arch/sparc/kernel/windows.c Mon Apr 14 16:28:07 1997 +++ linux/arch/sparc/kernel/windows.c Tue Aug 31 11:23:29 1999 @@ -32,7 +32,7 @@ restore %%g0, %%g0, %%g0" : "=&r" (ctr) : "0" (ctr), - "i" ((const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))) + "i" ((const unsigned long)(&(((struct task_struct *)0)->thread.uwinmask))) : "g4", "cc"); } @@ -61,7 +61,7 @@ int window; flush_user_windows(); - tp = ¤t->tss; + tp = ¤t->thread; if(!tp->w_saved) return; @@ -115,7 +115,7 @@ lock_kernel(); flush_user_windows(); - tp = ¤t->tss; + tp = ¤t->thread; for(window = 0; window < tp->w_saved; window++) { unsigned long sp = tp->rwbuf_stkptrs[window]; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S --- v2.3.15/linux/arch/sparc/kernel/wof.S Tue Apr 14 17:44:19 1998 +++ linux/arch/sparc/kernel/wof.S Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: wof.S,v 1.38 1998/02/06 14:14:22 jj Exp $ +/* $Id: wof.S,v 1.39 1999/08/14 03:51:35 anton Exp $ * wof.S: Sparc window overflow handler. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -62,7 +62,7 @@ * andcc %l0, PSR_PS, %g0 */ - /* Datum current->tss.uwinmask contains at all times a bitmask + /* Datum current->thread.uwinmask contains at all times a bitmask * where if any user windows are active, at least one bit will * be set in to mask. If no user windows are active, the bitmask * will be all zeroes. @@ -96,7 +96,7 @@ save %g0, %g0, %g0 ! Go where saving will occur /* See if any user windows are active in the set. */ - ld [%curptr + AOFF_task_tss + AOFF_thread_uwinmask], %twin_tmp ! grab win mask + ld [%curptr + AOFF_task_thread + AOFF_thread_uwinmask], %twin_tmp ! grab win mask orcc %g0, %twin_tmp, %g0 ! check for set bits bne spwin_exist_uwins ! yep, there are some andn %twin_tmp, %glob_tmp, %twin_tmp ! compute new umask @@ -139,7 +139,7 @@ * But first, store the new user window mask calculated * above. */ - st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] + st %twin_tmp, [%curptr + AOFF_task_thread + AOFF_thread_uwinmask] save %g0, %g0, %g0 ! Go to where the saving will occur spwin_fromuser: @@ -212,15 +212,15 @@ /* Oh well, throw this one window into the per-task window * buffer, the first one. */ - st %sp, [%curptr + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] - STORE_WINDOW(curptr + AOFF_task_tss + AOFF_thread_reg_window) + st %sp, [%curptr + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs] + STORE_WINDOW(curptr + AOFF_task_thread + AOFF_thread_reg_window) restore %g0, %g0, %g0 /* LOCATION: Trap Window */ /* Back in the trap window, update winbuffer save count. */ mov 1, %glob_tmp - st %glob_tmp, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] + st %glob_tmp, [%curptr + AOFF_task_thread + AOFF_thread_w_saved] /* Compute new user window mask. What we are basically * doing is taking two windows, the invalid one at trap @@ -232,7 +232,7 @@ or %twin_tmp, %t_wim, %twin_tmp not %twin_tmp spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs - st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] + st %twin_tmp, [%curptr + AOFF_task_thread + AOFF_thread_uwinmask] #define STACK_OFFSET (TASK_UNION_SIZE - TRACEREG_SZ - REGWIN_SZ) diff -u --recursive --new-file v2.3.15/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S --- v2.3.15/linux/arch/sparc/kernel/wuf.S Tue Apr 14 17:44:19 1998 +++ linux/arch/sparc/kernel/wuf.S Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.37 1998/02/19 21:25:50 ecd Exp $ +/* $Id: wuf.S,v 1.38 1999/08/14 03:51:36 anton Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller @@ -40,7 +40,7 @@ * andcc %l0, PSR_PS, %g0 */ - /* Datum current->tss.uwinmask contains at all times a bitmask + /* Datum current->thread.uwinmask contains at all times a bitmask * where if any user windows are active, at least one bit will * be set in to mask. If no user windows are active, the bitmask * will be all zeroes. @@ -184,8 +184,8 @@ /* Fix users window mask and buffer save count. */ mov 0x1, %g5 sll %g5, %g3, %g5 - st %g5, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] ! one live user window still - st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] ! no windows in the buffer + st %g5, [%curptr + AOFF_task_thread + AOFF_thread_uwinmask] ! one live user window still + st %g0, [%curptr + AOFF_task_thread + AOFF_thread_w_saved] ! no windows in the buffer wr %t_psr, PSR_ET, %psr ! enable traps nop diff -u --recursive --new-file v2.3.15/linux/arch/sparc/lib/debuglocks.c linux/arch/sparc/lib/debuglocks.c --- v2.3.15/linux/arch/sparc/lib/debuglocks.c Fri Aug 6 11:58:00 1999 +++ linux/arch/sparc/lib/debuglocks.c Tue Aug 31 11:23:29 1999 @@ -1,4 +1,4 @@ -/* $Id: debuglocks.c,v 1.8 1999/08/05 09:49:59 anton Exp $ +/* $Id: debuglocks.c,v 1.9 1999/08/14 03:51:39 anton Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -7,7 +7,7 @@ #include #include -#include /* For NR_CPUS */ +#include /* For NR_CPUS */ #include #include #include diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/Makefile linux/arch/sparc/math-emu/Makefile --- v2.3.15/linux/arch/sparc/math-emu/Makefile Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/Makefile Tue Aug 31 11:23:30 1999 @@ -8,19 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := math-emu.o -O_OBJS := math.o ashldi3.o fabss.o faddd.o faddq.o fadds.o \ - fcmpd.o fcmped.o fcmpeq.o fcmpes.o fcmpq.o fcmps.o \ - fdivd.o fdivq.o fdivs.o fdmulq.o fdtoi.o fdtoq.o \ - fdtos.o fitoq.o fmovs.o fmuld.o fmulq.o fmuls.o \ - fnegs.o fqtod.o fqtoi.o fqtos.o fsmuld.o fsqrtd.o \ - fsqrtq.o fsqrts.o fstod.o fstoi.o fstoq.o fsubd.o \ - fsubq.o fsubs.o - -LINKS := double.h faddd.c faddq.c fadds.c fdivd.c fdivq.c fdivs.c \ - fdtoi.c fitoq.c fmuld.c fmulq.c fmuls.c fqtoi.c \ - fsqrtd.c fsqrtq.c fsqrts.c fstoi.c fsubd.c \ - fsubq.c fsubs.c op-1.h op-2.h op-4.h op-8.h \ - op-common.h quad.h single.h soft-fp.h +O_OBJS := math.o ashldi3.o .S.s: $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s @@ -28,10 +16,6 @@ .S.o: $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o -include $(TOPDIR)/Rules.make - -symlinks: - ln -sf $(patsubst %,../../sparc64/math-emu/%,$(LINKS)) . +CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w -cleansymlinks: - rm -f $(LINKS) +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fabss.c linux/arch/sparc/math-emu/fabss.c --- v2.3.15/linux/arch/sparc/math-emu/fabss.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fabss.c Wed Dec 31 16:00:00 1969 @@ -1,12 +0,0 @@ -/* $Id: fabss.c,v 1.8 1999/05/28 13:41:33 jj Exp $ - * arch/sparc/math-emu/fabss.c - * - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -int FABSS(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0] & 0x7fffffffUL; - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fcmpd.c linux/arch/sparc/math-emu/fcmpd.c --- v2.3.15/linux/arch/sparc/math-emu/fcmpd.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fcmpd.c Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -/* $Id: fcmpd.c,v 1.8 1999/05/28 13:41:36 jj Exp $ - * arch/sparc/math-emu/fcmpd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FCMPD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); - long ret; - unsigned long fsr; - - FP_UNPACK_RAW_DP(A, rs1); - FP_UNPACK_RAW_DP(B, rs2); - FP_CMP_D(ret, B, A, 3); - if (ret == 3 && (FP_ISSIGNAN_D(A) || FP_ISSIGNAN_D(B))) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - if (ret == -1) ret = 2; - fsr = *(long *)rd; - fsr &= ~0xc00; - fsr |= (ret << 10); - *(long *)rd = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fcmped.c linux/arch/sparc/math-emu/fcmped.c --- v2.3.15/linux/arch/sparc/math-emu/fcmped.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fcmped.c Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -/* $Id: fcmped.c,v 1.8 1999/05/28 13:41:38 jj Exp $ - * arch/sparc/math-emu/fcmped.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FCMPED(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); - long ret; - unsigned long fsr; - - FP_UNPACK_RAW_DP(A, rs1); - FP_UNPACK_RAW_DP(B, rs2); - FP_CMP_D(ret, B, A, 3); - if (ret == 3) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - if (ret == -1) ret = 2; - fsr = *(long *)rd; - fsr &= ~0xc00; - fsr |= (ret << 10); - *(long *)rd = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fcmpeq.c linux/arch/sparc/math-emu/fcmpeq.c --- v2.3.15/linux/arch/sparc/math-emu/fcmpeq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fcmpeq.c Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -/* $Id: fcmpeq.c,v 1.8 1999/05/28 13:41:42 jj Exp $ - * arch/sparc/math-emu/fcmpeq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FCMPEQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); - long ret; - unsigned long fsr; - - FP_UNPACK_RAW_QP(A, rs1); - FP_UNPACK_RAW_QP(B, rs2); - FP_CMP_Q(ret, B, A, 3); - if (ret == 3) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - if (ret == -1) ret = 2; - fsr = *(long *)rd; - fsr &= ~0xc00; - fsr |= (ret << 10); - *(long *)rd = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fcmpes.c linux/arch/sparc/math-emu/fcmpes.c --- v2.3.15/linux/arch/sparc/math-emu/fcmpes.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fcmpes.c Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -/* $Id: fcmpes.c,v 1.8 1999/05/28 13:41:45 jj Exp $ - * arch/sparc/math-emu/fcmpes.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FCMPES(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); - long ret; - unsigned long fsr; - - FP_UNPACK_RAW_SP(A, rs1); - FP_UNPACK_RAW_SP(B, rs2); - FP_CMP_S(ret, B, A, 3); - if (ret == 3) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - if (ret == -1) ret = 2; - fsr = *(long *)rd; - fsr &= ~0xc00; - fsr |= (ret << 10); - *(long *)rd = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fcmpq.c linux/arch/sparc/math-emu/fcmpq.c --- v2.3.15/linux/arch/sparc/math-emu/fcmpq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fcmpq.c Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -/* $Id: fcmpq.c,v 1.8 1999/05/28 13:41:48 jj Exp $ - * arch/sparc/math-emu/fcmpq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FCMPQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); - long ret; - unsigned long fsr; - - FP_UNPACK_RAW_QP(A, rs1); - FP_UNPACK_RAW_QP(B, rs2); - FP_CMP_Q(ret, B, A, 3); - if (ret == 3 && (FP_ISSIGNAN_Q(A) || FP_ISSIGNAN_Q(B))) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - if (ret == -1) ret = 2; - fsr = *(long *)rd; - fsr &= ~0xc00; - fsr |= (ret << 10); - *(long *)rd = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fcmps.c linux/arch/sparc/math-emu/fcmps.c --- v2.3.15/linux/arch/sparc/math-emu/fcmps.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fcmps.c Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -/* $Id: fcmps.c,v 1.8 1999/05/28 13:41:51 jj Exp $ - * arch/sparc/math-emu/fcmps.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FCMPS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); - long ret; - unsigned long fsr; - - FP_UNPACK_RAW_SP(A, rs1); - FP_UNPACK_RAW_SP(B, rs2); - FP_CMP_S(ret, B, A, 3); - if (ret == 3 && (FP_ISSIGNAN_S(A) || FP_ISSIGNAN_S(B))) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - if (ret == -1) ret = 2; - fsr = *(long *)rd; - fsr &= ~0xc00; - fsr |= (ret << 10); - *(long *)rd = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fdmulq.c linux/arch/sparc/math-emu/fdmulq.c --- v2.3.15/linux/arch/sparc/math-emu/fdmulq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fdmulq.c Wed Dec 31 16:00:00 1969 @@ -1,26 +0,0 @@ -/* $Id: fdmulq.c,v 1.9 1999/05/28 13:41:56 jj Exp $ - * arch/sparc/math-emu/fdmulq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FDMULQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_DP(IN, rs1); - FP_CONV(Q,D,4,2,A,IN); - FP_UNPACK_DP(IN, rs2); - FP_CONV(Q,D,4,2,B,IN); - FP_MUL_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fdtoq.c linux/arch/sparc/math-emu/fdtoq.c --- v2.3.15/linux/arch/sparc/math-emu/fdtoq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fdtoq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fdtoq.c,v 1.9 1999/05/28 13:42:01 jj Exp $ - * arch/sparc/math-emu/fdtoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FDTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_Q(R); - - FP_UNPACK_DP(A, rs2); - FP_CONV(Q,D,4,2,R,A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fdtos.c linux/arch/sparc/math-emu/fdtos.c --- v2.3.15/linux/arch/sparc/math-emu/fdtos.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fdtos.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fdtos.c,v 1.9 1999/05/28 13:42:03 jj Exp $ - * arch/sparc/math-emu/fdtos.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FDTOS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_S(R); - - FP_UNPACK_DP(A, rs2); - FP_CONV(S,D,1,2,R,A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fmovs.c linux/arch/sparc/math-emu/fmovs.c --- v2.3.15/linux/arch/sparc/math-emu/fmovs.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fmovs.c Wed Dec 31 16:00:00 1969 @@ -1,12 +0,0 @@ -/* $Id: fmovs.c,v 1.7 1999/05/28 13:42:05 jj Exp $ - * arch/sparc/math-emu/fmovs.c - * - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -int FMOVS(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0]; - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fnegs.c linux/arch/sparc/math-emu/fnegs.c --- v2.3.15/linux/arch/sparc/math-emu/fnegs.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fnegs.c Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* $Id: fnegs.c,v 1.9 1999/05/28 13:42:06 jj Exp $ - * arch/sparc/math-emu/fnegs.c - * - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -int FNEGS(unsigned long *rd, unsigned long *rs2) -{ - /* just change the sign bit */ - rd[0] = rs2[0] ^ 0x80000000UL; - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fqtod.c linux/arch/sparc/math-emu/fqtod.c --- v2.3.15/linux/arch/sparc/math-emu/fqtod.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fqtod.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fqtod.c,v 1.9 1999/05/28 13:42:08 jj Exp $ - * arch/sparc/math-emu/fqtod.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FQTOD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_D(R); - - FP_UNPACK_QP(A, rs2); - FP_CONV(D,Q,2,4,R,A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fqtos.c linux/arch/sparc/math-emu/fqtos.c --- v2.3.15/linux/arch/sparc/math-emu/fqtos.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fqtos.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fqtos.c,v 1.9 1999/05/28 13:42:10 jj Exp $ - * arch/sparc/math-emu/fqtos.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "single.h" - -int FQTOS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_S(R); - - FP_UNPACK_QP(A, rs2); - FP_CONV(S,Q,1,4,R,A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fsmuld.c linux/arch/sparc/math-emu/fsmuld.c --- v2.3.15/linux/arch/sparc/math-emu/fsmuld.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fsmuld.c Wed Dec 31 16:00:00 1969 @@ -1,26 +0,0 @@ -/* $Id: fsmuld.c,v 1.9 1999/05/28 13:42:12 jj Exp $ - * arch/sparc/math-emu/fsmuld.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FSMULD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_SP(IN, rs1); - FP_CONV(D,S,2,1,A,IN); - FP_UNPACK_SP(IN, rs2); - FP_CONV(D,S,2,1,B,IN); - FP_MUL_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fstod.c linux/arch/sparc/math-emu/fstod.c --- v2.3.15/linux/arch/sparc/math-emu/fstod.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fstod.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fstod.c,v 1.9 1999/05/28 13:42:14 jj Exp $ - * arch/sparc/math-emu/fstod.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FSTOD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_D(R); - - FP_UNPACK_SP(A, rs2); - FP_CONV(D,S,2,1,R,A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/fstoq.c linux/arch/sparc/math-emu/fstoq.c --- v2.3.15/linux/arch/sparc/math-emu/fstoq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/fstoq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fstoq.c,v 1.9 1999/05/28 13:42:16 jj Exp $ - * arch/sparc/math-emu/fstoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "single.h" - -int FSTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_Q(R); - - FP_UNPACK_SP(A, rs2); - FP_CONV(Q,S,4,1,R,A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/math.c linux/arch/sparc/math-emu/math.c --- v2.3.15/linux/arch/sparc/math-emu/math.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc/math-emu/math.c Tue Aug 31 11:23:30 1999 @@ -71,6 +71,9 @@ #include "sfp-util.h" #include "soft-fp.h" +#include "single.h" +#include "double.h" +#include "quad.h" #define FLOATFUNC(x) extern int x(void *,void *,void *) @@ -78,45 +81,45 @@ * each insn is. This is from the binutils source :-> */ /* quadword instructions */ -FLOATFUNC(FSQRTQ); /* v8 */ -FLOATFUNC(FADDQ); /* v8 */ -FLOATFUNC(FSUBQ); /* v8 */ -FLOATFUNC(FMULQ); /* v8 */ -FLOATFUNC(FDIVQ); /* v8 */ -FLOATFUNC(FDMULQ); /* v8 */ -FLOATFUNC(FQTOS); /* v8 */ -FLOATFUNC(FQTOD); /* v8 */ -FLOATFUNC(FITOQ); /* v8 */ -FLOATFUNC(FSTOQ); /* v8 */ -FLOATFUNC(FDTOQ); /* v8 */ -FLOATFUNC(FQTOI); /* v8 */ -FLOATFUNC(FCMPQ); /* v8 */ -FLOATFUNC(FCMPEQ); /* v8 */ +#define FSQRTQ 0x02b /* v8 */ +#define FADDQ 0x043 /* v8 */ +#define FSUBQ 0x047 /* v8 */ +#define FMULQ 0x04b /* v8 */ +#define FDIVQ 0x04f /* v8 */ +#define FDMULQ 0x06e /* v8 */ +#define FQTOS 0x0c7 /* v8 */ +#define FQTOD 0x0cb /* v8 */ +#define FITOQ 0x0cc /* v8 */ +#define FSTOQ 0x0cd /* v8 */ +#define FDTOQ 0x0ce /* v8 */ +#define FQTOI 0x0d3 /* v8 */ +#define FCMPQ 0x053 /* v8 */ +#define FCMPEQ 0x057 /* v8 */ /* single/double instructions (subnormal): should all work */ -FLOATFUNC(FSQRTS); /* v7 */ -FLOATFUNC(FSQRTD); /* v7 */ -FLOATFUNC(FADDS); /* v6 */ -FLOATFUNC(FADDD); /* v6 */ -FLOATFUNC(FSUBS); /* v6 */ -FLOATFUNC(FSUBD); /* v6 */ -FLOATFUNC(FMULS); /* v6 */ -FLOATFUNC(FMULD); /* v6 */ -FLOATFUNC(FDIVS); /* v6 */ -FLOATFUNC(FDIVD); /* v6 */ -FLOATFUNC(FSMULD); /* v8 */ -FLOATFUNC(FDTOS); /* v6 */ -FLOATFUNC(FSTOD); /* v6 */ -FLOATFUNC(FSTOI); /* v6 */ -FLOATFUNC(FDTOI); /* v6 */ -FLOATFUNC(FABSS); /* v6 */ -FLOATFUNC(FCMPS); /* v6 */ -FLOATFUNC(FCMPES); /* v6 */ -FLOATFUNC(FCMPD); /* v6 */ -FLOATFUNC(FCMPED); /* v6 */ -FLOATFUNC(FMOVS); /* v6 */ -FLOATFUNC(FNEGS); /* v6 */ -FLOATFUNC(FITOS); /* v6 */ -FLOATFUNC(FITOD); /* v6 */ +#define FSQRTS 0x029 /* v7 */ +#define FSQRTD 0x02a /* v7 */ +#define FADDS 0x041 /* v6 */ +#define FADDD 0x042 /* v6 */ +#define FSUBS 0x045 /* v6 */ +#define FSUBD 0x046 /* v6 */ +#define FMULS 0x049 /* v6 */ +#define FMULD 0x04a /* v6 */ +#define FDIVS 0x04d /* v6 */ +#define FDIVD 0x04e /* v6 */ +#define FSMULD 0x069 /* v6 */ +#define FDTOS 0x0c6 /* v6 */ +#define FSTOD 0x0c9 /* v6 */ +#define FSTOI 0x0d1 /* v6 */ +#define FDTOI 0x0d2 /* v6 */ +#define FABSS 0x009 /* v6 */ +#define FCMPS 0x051 /* v6 */ +#define FCMPES 0x055 /* v6 */ +#define FCMPD 0x052 /* v6 */ +#define FCMPED 0x056 /* v6 */ +#define FMOVS 0x001 /* v6 */ +#define FNEGS 0x005 /* v6 */ +#define FITOS 0x0c4 /* v6 */ +#define FITOD 0x0c8 /* v6 */ #define FSR_TEM_SHIFT 23UL #define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT) @@ -162,18 +165,18 @@ #ifdef DEBUG_MATHEMU printk("In do_mathemu()... pc is %08lx\n", regs->pc); - printk("fpqdepth is %ld\n", fpt->tss.fpqdepth); - for (i = 0; i < fpt->tss.fpqdepth; i++) - printk("%d: %08lx at %08lx\n", i, fpt->tss.fpqueue[i].insn, - (unsigned long)fpt->tss.fpqueue[i].insn_addr); + printk("fpqdepth is %ld\n", fpt->thread.fpqdepth); + for (i = 0; i < fpt->thread.fpqdepth; i++) + printk("%d: %08lx at %08lx\n", i, fpt->thread.fpqueue[i].insn, + (unsigned long)fpt->thread.fpqueue[i].insn_addr); #endif - if (fpt->tss.fpqdepth == 0) { /* no queue, guilty insn is at regs->pc */ + if (fpt->thread.fpqdepth == 0) { /* no queue, guilty insn is at regs->pc */ #ifdef DEBUG_MATHEMU printk("precise trap at %08lx\n", regs->pc); #endif if (!get_user(insn, (u32 *)regs->pc)) { - retcode = do_one_mathemu(insn, &fpt->tss.fsr, fpt->tss.float_regs); + retcode = do_one_mathemu(insn, &fpt->thread.fsr, fpt->thread.float_regs); if (retcode) { /* in this case we need to fix up PC & nPC */ regs->pc = regs->npc; @@ -184,17 +187,17 @@ } /* Normal case: need to empty the queue... */ - for (i = 0; i < fpt->tss.fpqdepth; i++) { - retcode = do_one_mathemu(fpt->tss.fpqueue[i].insn, &(fpt->tss.fsr), fpt->tss.float_regs); + for (i = 0; i < fpt->thread.fpqdepth; i++) { + retcode = do_one_mathemu(fpt->thread.fpqueue[i].insn, &(fpt->thread.fsr), fpt->thread.float_regs); if (!retcode) /* insn failed, no point doing any more */ break; } /* Now empty the queue and clear the queue_not_empty flag */ if(retcode) - fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK); + fpt->thread.fsr &= ~(0x3000 | FSR_CEXC_MASK); else - fpt->tss.fsr &= ~0x3000; - fpt->tss.fpqdepth = 0; + fpt->thread.fsr &= ~0x3000; + fpt->thread.fpqdepth = 0; return retcode; } @@ -207,7 +210,7 @@ * * We return 0 if a SIGFPE should be sent, 1 otherwise. */ -static int record_exception(unsigned long *pfsr, int eflag) +static inline int record_exception(unsigned long *pfsr, int eflag) { unsigned long fsr = *pfsr; int would_trap; @@ -259,19 +262,28 @@ return (would_trap ? 0 : 1); } -static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs) +typedef union { + u32 s; + u64 d; + u64 q[2]; +} *argp; + +static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs) { /* Emulate the given insn, updating fsr and fregs appropriately. */ 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 that may happen in - * (this field not used on sparc32 code, as we can't - * extract trap type info for ops on the FP queue) - */ - int freg, eflag; - int (*func)(void *,void *,void *) = NULL; - void *rs1 = NULL, *rs2 = NULL, *rd = NULL; + /* r is rd, b is rs2 and a is rs1. The *u arg tells + whether the argument should be packed/unpacked (0 - do not unpack/pack, 1 - unpack/pack) + non-u args tells the size of the argument (0 - no argument, 1 - single, 2 - double, 3 - quad */ +#define TYPE(dummy, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6) + int freg; + argp rs1 = NULL, rs2 = NULL, rd = NULL; + FP_DECL_EX; + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + int IR; + long fsr; #ifdef DEBUG_MATHEMU printk("In do_mathemu(), emulating %08lx\n", insn); @@ -279,38 +291,38 @@ if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ { switch ((insn >> 5) & 0x1ff) { - /* QUAD - ftt == 3 */ - case 0x001: type = 0x314; func = FMOVS; break; - case 0x005: type = 0x314; func = FNEGS; break; - case 0x009: type = 0x314; func = FABSS; 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 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 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; + case FSQRTQ: TYPE(3,3,1,3,1,0,0); break; + case FADDQ: + case FSUBQ: + case FMULQ: + case FDIVQ: TYPE(3,3,1,3,1,3,1); break; + case FDMULQ: TYPE(3,3,1,2,1,2,1); break; + case FQTOS: TYPE(3,1,1,3,1,0,0); break; + case FQTOD: TYPE(3,2,1,3,1,0,0); break; + case FITOQ: TYPE(3,3,1,1,0,0,0); break; + case FSTOQ: TYPE(3,3,1,1,1,0,0); break; + case FDTOQ: TYPE(3,3,1,2,1,0,0); break; + case FQTOI: TYPE(3,1,0,3,1,0,0); break; + case FSQRTS: TYPE(2,1,1,1,1,0,0); break; + case FSQRTD: TYPE(2,2,1,2,1,0,0); break; + case FADDD: + case FSUBD: + case FMULD: + case FDIVD: TYPE(2,2,1,2,1,2,1); break; + case FADDS: + case FSUBS: + case FMULS: + case FDIVS: TYPE(2,1,1,1,1,1,1); break; + case FSMULD: TYPE(2,2,1,1,1,1,1); break; + case FDTOS: TYPE(2,1,1,2,1,0,0); break; + case FSTOD: TYPE(2,2,1,1,1,0,0); break; + case FSTOI: TYPE(2,1,0,1,1,0,0); break; + case FDTOI: TYPE(2,1,0,2,1,0,0); break; + case FITOS: TYPE(2,1,1,1,0,0,0); break; + case FITOD: TYPE(2,2,1,1,0,0,0); break; + case FMOVS: + case FABSS: + case FNEGS: TYPE(2,1,0,1,0,0,0); break; default: #ifdef DEBUG_MATHEMU printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff); @@ -318,12 +330,12 @@ } } else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ { switch ((insn >> 5) & 0x1ff) { - case 0x051: type = 0x305; func = FCMPS; break; - case 0x052: type = 0x30a; func = FCMPD; break; - case 0x053: type = 0x30f; func = FCMPQ; break; - case 0x055: type = 0x305; func = FCMPES; break; - case 0x056: type = 0x30a; func = FCMPED; break; - case 0x057: type = 0x30f; func = FCMPEQ; break; + case FCMPS: TYPE(3,0,0,1,1,1,1); break; + case FCMPES: TYPE(3,0,0,1,1,1,1); break; + case FCMPD: TYPE(3,0,0,2,1,2,1); break; + case FCMPED: TYPE(3,0,0,2,1,2,1); break; + case FCMPQ: TYPE(3,0,0,3,1,3,1); break; + case FCMPEQ: TYPE(3,0,0,3,1,3,1); break; default: #ifdef DEBUG_MATHEMU printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff); @@ -332,67 +344,78 @@ } if (!type) { /* oops, didn't recognise that FPop */ +#ifdef DEBUG_MATHEMU printk("attempt to emulate unrecognised FPop!\n"); +#endif return 0; } /* Decode the registers to be used */ - freg = (*fsr >> 14) & 0xf; - - *fsr &= ~0x1c000; /* clear the traptype bits */ + freg = (*pfsr >> 14) & 0xf; + *pfsr &= ~0x1c000; /* clear the traptype bits */ + freg = ((insn >> 14) & 0x1f); switch (type & 0x3) { /* is rs1 single, double or quad? */ case 3: if (freg & 3) { /* quadwords must have bits 4&5 of the */ /* encoded reg. number set to zero. */ - *fsr |= (6 << 14); + *pfsr |= (6 << 14); return 0; /* simulate invalid_fp_register exception */ } /* fall through */ case 2: if (freg & 1) { /* doublewords must have bit 5 zeroed */ - *fsr |= (6 << 14); + *pfsr |= (6 << 14); return 0; } } - rs1 = (void *)&fregs[freg]; + rs1 = (argp)&fregs[freg]; + switch (type & 0x7) { + case 7: FP_UNPACK_QP (QA, rs1); break; + case 6: FP_UNPACK_DP (DA, rs1); break; + case 5: FP_UNPACK_SP (SA, rs1); break; + } freg = (insn & 0x1f); - switch ((type >> 2) & 0x3) { /* same again for rs2 */ + switch ((type >> 3) & 0x3) { /* same again for rs2 */ case 3: if (freg & 3) { /* quadwords must have bits 4&5 of the */ /* encoded reg. number set to zero. */ - *fsr |= (6 << 14); + *pfsr |= (6 << 14); return 0; /* simulate invalid_fp_register exception */ } /* fall through */ case 2: if (freg & 1) { /* doublewords must have bit 5 zeroed */ - *fsr |= (6 << 14); + *pfsr |= (6 << 14); return 0; } } - rs2 = (void *)&fregs[freg]; + rs2 = (argp)&fregs[freg]; + switch ((type >> 3) & 0x7) { + case 7: FP_UNPACK_QP (QB, rs2); break; + case 6: FP_UNPACK_DP (DB, rs2); break; + case 5: FP_UNPACK_SP (SB, rs2); break; + } freg = ((insn >> 25) & 0x1f); - switch ((type >> 4) & 0x3) { /* and finally rd. This one's a bit different */ + switch ((type >> 6) & 0x3) { /* and finally rd. This one's a bit different */ case 0: /* dest is fcc. (this must be FCMPQ or FCMPEQ) */ if (freg) { /* V8 has only one set of condition codes, so */ /* anything but 0 in the rd field is an error */ - *fsr |= (6 << 14); /* (should probably flag as invalid opcode */ + *pfsr |= (6 << 14); /* (should probably flag as invalid opcode */ return 0; /* but SIGFPE will do :-> ) */ } - rd = (void *)(fsr); /* FCMPQ and FCMPEQ are special and only */ - break; /* set bits they're supposed to :-> */ + break; case 3: if (freg & 3) { /* quadwords must have bits 4&5 of the */ /* encoded reg. number set to zero. */ - *fsr |= (6 << 14); + *pfsr |= (6 << 14); return 0; /* simulate invalid_fp_register exception */ } /* fall through */ case 2: if (freg & 1) { /* doublewords must have bit 5 zeroed */ - *fsr |= (6 << 14); + *pfsr |= (6 << 14); return 0; } /* fall through */ @@ -403,8 +426,94 @@ #ifdef DEBUG_MATHEMU printk("executing insn...\n"); #endif - eflag = func(rd, rs2, rs1); /* do the Right Thing */ - if(eflag == 0) + /* do the Right Thing */ + switch ((insn >> 5) & 0x1ff) { + /* + */ + case FADDS: FP_ADD_S (SR, SA, SB); break; + case FADDD: FP_ADD_D (DR, DA, DB); break; + case FADDQ: FP_ADD_Q (QR, QA, QB); break; + /* - */ + case FSUBS: FP_SUB_S (SR, SA, SB); break; + case FSUBD: FP_SUB_D (DR, DA, DB); break; + case FSUBQ: FP_SUB_Q (QR, QA, QB); break; + /* * */ + case FMULS: FP_MUL_S (SR, SA, SB); break; + case FSMULD: FP_CONV (D, S, 2, 1, DA, SA); + FP_CONV (D, S, 2, 1, DB, SB); + case FMULD: FP_MUL_D (DR, DA, DB); break; + case FDMULQ: FP_CONV (Q, D, 4, 2, QA, DA); + FP_CONV (Q, D, 4, 2, QB, DB); + case FMULQ: FP_MUL_Q (QR, QA, QB); break; + /* / */ + case FDIVS: FP_DIV_S (SR, SA, SB); break; + case FDIVD: FP_DIV_D (DR, DA, DB); break; + case FDIVQ: FP_DIV_Q (QR, QA, QB); break; + /* sqrt */ + case FSQRTS: FP_SQRT_S (SR, SB); break; + case FSQRTD: FP_SQRT_D (DR, DB); break; + case FSQRTQ: FP_SQRT_Q (QR, QB); break; + /* mov */ + case FMOVS: rd->s = rs2->s; break; + case FABSS: rd->s = rs2->s & 0x7fffffff; break; + case FNEGS: rd->s = rs2->s ^ 0x80000000; break; + /* float to int */ + case FSTOI: FP_TO_INT_S (IR, SB, 32, 1); break; + case FDTOI: FP_TO_INT_D (IR, DB, 32, 1); break; + case FQTOI: FP_TO_INT_Q (IR, QB, 32, 1); break; + /* int to float */ + case FITOS: IR = rs2->s; FP_FROM_INT_S (SR, IR, 32, int); break; + case FITOD: IR = rs2->s; FP_FROM_INT_D (DR, IR, 32, int); break; + case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break; + /* float to float */ + case FSTOD: FP_CONV (D, S, 2, 1, DR, SB); break; + case FSTOQ: FP_CONV (Q, S, 4, 1, QR, SB); break; + case FDTOQ: FP_CONV (Q, D, 4, 2, QR, DB); break; + case FDTOS: FP_CONV (S, D, 1, 2, SR, DB); break; + case FQTOS: FP_CONV (S, Q, 1, 4, SR, QB); break; + case FQTOD: FP_CONV (D, Q, 2, 4, DR, QB); break; + /* comparison */ + case FCMPS: + case FCMPES: + FP_CMP_S(IR, SB, SA, 3); + if (IR == 3 && + (((insn >> 5) & 0x1ff) == FCMPES || + FP_ISSIGNAN_S(SA) || + FP_ISSIGNAN_S(SB))) + FP_SET_EXCEPTION (FP_EX_INVALID); + break; + case FCMPD: + case FCMPED: + FP_CMP_D(IR, DB, DA, 3); + if (IR == 3 && + (((insn >> 5) & 0x1ff) == FCMPED || + FP_ISSIGNAN_D(DA) || + FP_ISSIGNAN_D(DB))) + FP_SET_EXCEPTION (FP_EX_INVALID); + break; + case FCMPQ: + case FCMPEQ: + FP_CMP_Q(IR, QB, QA, 3); + if (IR == 3 && + (((insn >> 5) & 0x1ff) == FCMPEQ || + FP_ISSIGNAN_Q(QA) || + FP_ISSIGNAN_Q(QB))) + FP_SET_EXCEPTION (FP_EX_INVALID); + } + if (!FP_INHIBIT_RESULTS) { + switch ((type >> 6) & 0x7) { + case 0: fsr = *pfsr; + if (IR == -1) IR = 2; + /* fcc is always fcc0 */ + fsr &= ~0xc00; fsr |= (IR << 10); break; + *pfsr = fsr; + break; + case 1: rd->s = IR; break; + case 5: FP_PACK_SP (rd, SR); break; + case 6: FP_PACK_DP (rd, DR); break; + case 7: FP_PACK_QP (rd, QR); break; + } + } + if(_fex == 0) return 1; /* success! */ - return record_exception(fsr, eflag); + return record_exception(pfsr, _fex); } diff -u --recursive --new-file v2.3.15/linux/arch/sparc/math-emu/sfp-machine.h linux/arch/sparc/math-emu/sfp-machine.h --- v2.3.15/linux/arch/sparc/math-emu/sfp-machine.h Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/math-emu/sfp-machine.h Tue Aug 31 11:23:30 1999 @@ -31,7 +31,7 @@ #define _FP_I_TYPE long #define _FP_MUL_MEAT_S(R,X,Y) \ - _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y) + _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) #define _FP_MUL_MEAT_D(R,X,Y) \ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) #define _FP_MUL_MEAT_Q(R,X,Y) \ @@ -181,9 +181,9 @@ /* Obtain the current rounding mode. */ #ifndef FP_ROUNDMODE #ifdef __SMP__ -#define FP_ROUNDMODE ((current->tss.fsr >> 30) & 0x3) +#define FP_ROUNDMODE ((current->thread.fsr >> 30) & 0x3) #else -#define FP_ROUNDMODE ((last_task_used_math->tss.fsr >> 30) & 0x3) +#define FP_ROUNDMODE ((last_task_used_math->thread.fsr >> 30) & 0x3) #endif #endif @@ -197,9 +197,9 @@ #define FP_HANDLE_EXCEPTIONS return _fex #ifdef __SMP__ -#define FP_INHIBIT_RESULTS ((current->tss.fsr >> 23) & _fex) +#define FP_INHIBIT_RESULTS ((current->thread.fsr >> 23) & _fex) #else -#define FP_INHIBIT_RESULTS ((last_task_used_math->tss.fsr >> 23) & _fex) +#define FP_INHIBIT_RESULTS ((last_task_used_math->thread.fsr >> 23) & _fex) #endif #endif diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile --- v2.3.15/linux/arch/sparc/mm/Makefile Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/mm/Makefile Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.33 1999/01/02 16:45:47 davem Exp $ +# $Id: Makefile,v 1.34 1999/08/14 03:51:42 anton Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -8,7 +8,10 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := fault.o init.o loadmmu.o generic.o asyncd.o extable.o btfixup.o +O_OBJS := fault.o init.o loadmmu.o generic.o extable.o btfixup.o +ifeq ($(CONFIG_AP1000),y) +O_OBJS += asyncd.o +endif ifeq ($(CONFIG_SUN4),y) O_OBJS += nosrmmu.o else diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c --- v2.3.15/linux/arch/sparc/mm/asyncd.c Wed Aug 4 15:39:46 1999 +++ linux/arch/sparc/mm/asyncd.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.16 1999/08/04 03:19:16 davem Exp $ +/* $Id: asyncd.c,v 1.17 1999/08/14 03:51:44 anton Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -178,8 +178,8 @@ bad_area: stats.failure++; - tsk->tss.sig_address = address; - tsk->tss.sig_desc = SUBSIG_NOMAPPING; + tsk->thread.sig_address = address; + tsk->thread.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); return 1; } diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/btfixup.c linux/arch/sparc/mm/btfixup.c --- v2.3.15/linux/arch/sparc/mm/btfixup.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/mm/btfixup.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: btfixup.c,v 1.7 1998/03/09 14:03:56 jj Exp $ +/* $Id: btfixup.c,v 1.8 1999/08/31 06:54:31 davem Exp $ * btfixup.c: Boot time code fixup and relocator, so that * we can get rid of most indirect calls to achieve single * image sun4c and srmmu kernel. @@ -48,7 +48,7 @@ static char wrong_setaddr[] __initdata = "Garbled CALL/INT patch at %p[%08x,%08x,%08x]=%08x\n"; #ifdef BTFIXUP_OPTIMIZE_OTHER -__initfunc(static void set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value)) +static void __init set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value) { if (!fmangled) *addr = value; @@ -74,7 +74,7 @@ } #endif -__initfunc(void btfixup(void)) +void __init btfixup(void) { unsigned int *p, *q; int type, count; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.3.15/linux/arch/sparc/mm/fault.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/mm/fault.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.106 1999/07/30 09:35:07 davem Exp $ +/* $Id: fault.c,v 1.107 1999/08/14 03:51:46 anton Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -280,8 +280,8 @@ printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n", tsk->comm, tsk->pid, address, regs->pc); #endif - tsk->tss.sig_address = address; - tsk->tss.sig_desc = SUBSIG_NOMAPPING; + tsk->thread.sig_address = address; + tsk->thread.sig_desc = SUBSIG_NOMAPPING; force_sig(SIGSEGV, tsk); return; } @@ -290,8 +290,8 @@ do_sigbus: up(&mm->mmap_sem); - tsk->tss.sig_address = address; - tsk->tss.sig_desc = SUBSIG_MISCERROR; + tsk->thread.sig_address = address; + tsk->thread.sig_desc = SUBSIG_MISCERROR; force_sig(SIGBUS, tsk); if (! from_user) goto do_kernel_fault; @@ -399,15 +399,15 @@ printk("Window whee %s [%d]: segfaults at %08lx\n", tsk->comm, tsk->pid, address); #endif - tsk->tss.sig_address = address; - tsk->tss.sig_desc = SUBSIG_NOMAPPING; + tsk->thread.sig_address = address; + tsk->thread.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); return; do_sigbus: up(&mm->mmap_sem); - tsk->tss.sig_address = address; - tsk->tss.sig_desc = SUBSIG_MISCERROR; + tsk->thread.sig_address = address; + tsk->thread.sig_desc = SUBSIG_MISCERROR; force_sig(SIGBUS, tsk); } @@ -416,7 +416,7 @@ unsigned long sp; lock_kernel(); - sp = current->tss.rwbuf_stkptrs[0]; + sp = current->thread.rwbuf_stkptrs[0]; if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 1); force_user_fault(sp, 1); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S --- v2.3.15/linux/arch/sparc/mm/hypersparc.S Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/mm/hypersparc.S Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: hypersparc.S,v 1.13 1998/02/13 15:35:09 jj Exp $ +/* $Id: hypersparc.S,v 1.14 1999/08/14 03:51:47 anton Exp $ * hypersparc.S: High speed Hypersparc mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -13,7 +13,7 @@ #define WINDOW_FLUSH(tmp1, tmp2) \ mov 0, tmp1; \ -98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \ +98: ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], tmp2; \ orcc %g0, tmp2, %g0; \ add tmp1, 1, tmp1; \ bne 98b; \ diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.3.15/linux/arch/sparc/mm/init.c Tue Jun 29 09:22:08 1999 +++ linux/arch/sparc/mm/init.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.67 1999/06/29 12:33:59 davem Exp $ +/* $Id: init.c,v 1.68 1999/08/31 06:54:32 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -113,7 +113,7 @@ extern pgprot_t protection_map[16]; -__initfunc(unsigned long sparc_context_init(unsigned long start_mem, int numctx)) +unsigned long __init sparc_context_init(unsigned long start_mem, int numctx) { int ctx; @@ -142,8 +142,8 @@ extern unsigned long srmmu_paging_init(unsigned long, unsigned long); extern unsigned long device_scan(unsigned long); -__initfunc(unsigned long -paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init +paging_init(unsigned long start_mem, unsigned long end_mem) { switch(sparc_cpu_model) { case sun4c: @@ -202,7 +202,7 @@ int physmem_mapped_contig __initdata = 1; -__initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)) +static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem) { unsigned long addr, tmp2 = 0; @@ -234,7 +234,7 @@ } } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { int codepages = 0; int datapages = 0; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c --- v2.3.15/linux/arch/sparc/mm/io-unit.c Sun Jul 25 13:45:25 1999 +++ linux/arch/sparc/mm/io-unit.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.13 1998/11/08 11:13:57 davem Exp $ +/* $Id: io-unit.c,v 1.14 1999/08/31 06:54:33 davem Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -26,8 +26,8 @@ #define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID) #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM) -__initfunc(void -iounit_init(int sbi_node, int io_node, struct linux_sbus *sbus)) +void __init +iounit_init(int sbi_node, int io_node, struct linux_sbus *sbus) { iopte_t *xpt, *xptend; struct iounit_struct *iounit; @@ -217,7 +217,7 @@ /* FIXME: Write this */ } -__initfunc(void ld_mmu_iounit(void)) +void __init ld_mmu_iounit(void) { BTFIXUPSET_CALL(mmu_lockarea, iounit_lockarea, BTFIXUPCALL_RETO0); BTFIXUPSET_CALL(mmu_unlockarea, iounit_unlockarea, BTFIXUPCALL_NOP); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c --- v2.3.15/linux/arch/sparc/mm/iommu.c Sun Jul 25 13:45:25 1999 +++ linux/arch/sparc/mm/iommu.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: iommu.c,v 1.10 1999/05/07 17:03:34 jj Exp $ +/* $Id: iommu.c,v 1.11 1999/08/31 06:54:34 davem Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -44,8 +44,8 @@ } } -__initfunc(void -iommu_init(int iommund, struct linux_sbus *sbus)) +void __init +iommu_init(int iommund, struct linux_sbus *sbus) { unsigned int impl, vers, ptsize; unsigned long tmp; @@ -264,7 +264,7 @@ { } -__initfunc(void ld_mmu_iommu(void)) +void __init ld_mmu_iommu(void) { viking_flush = (BTFIXUPVAL_CALL(flush_page_for_dma) == (unsigned long)viking_flush_page); BTFIXUPSET_CALL(mmu_lockarea, iommu_lockarea, BTFIXUPCALL_RETO0); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c --- v2.3.15/linux/arch/sparc/mm/loadmmu.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/mm/loadmmu.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.50 1998/02/05 14:19:02 jj Exp $ +/* $Id: loadmmu.c,v 1.51 1999/08/31 06:54:35 davem Exp $ * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. @@ -31,7 +31,7 @@ extern void ld_mmu_sun4c(void); extern void ld_mmu_srmmu(void); -__initfunc(void load_mmu(void)) +void __init load_mmu(void) { switch(sparc_cpu_model) { case sun4c: diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/nosrmmu.c linux/arch/sparc/mm/nosrmmu.c --- v2.3.15/linux/arch/sparc/mm/nosrmmu.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/mm/nosrmmu.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: nosrmmu.c,v 1.2 1999/03/30 10:17:39 jj Exp $ +/* $Id: nosrmmu.c,v 1.3 1999/08/31 06:54:35 davem Exp $ * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, * so that it does not need srmmu and avoid ifdefs. * @@ -14,24 +14,24 @@ enum mbus_module srmmu_modtype; -__initfunc(static void should_not_happen(void)) +static void __init should_not_happen(void) { prom_printf(shouldnothappen); prom_halt(); } -__initfunc(void srmmu_frob_mem_map(unsigned long start_mem)) +void __init srmmu_frob_mem_map(unsigned long start_mem) { should_not_happen(); } -__initfunc(unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem) { should_not_happen(); return 0; } -__initfunc(void ld_mmu_srmmu(void)) +void __init ld_mmu_srmmu(void) { should_not_happen(); } @@ -44,7 +44,7 @@ { } -__initfunc(void srmmu_end_memory(unsigned long memory_size, unsigned long *mem_end_p)) +void __init srmmu_end_memory(unsigned long memory_size, unsigned long *mem_end_p) { return 0; } diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/nosun4c.c linux/arch/sparc/mm/nosun4c.c --- v2.3.15/linux/arch/sparc/mm/nosun4c.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/mm/nosun4c.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: nosun4c.c,v 1.1 1998/03/09 14:04:16 jj Exp $ +/* $Id: nosun4c.c,v 1.2 1999/08/31 06:54:36 davem Exp $ * nosun4c.c: This file is a bunch of dummies for SMP compiles, * so that it does not need sun4c and avoid ifdefs. * @@ -23,19 +23,19 @@ unsigned long sun4c_kernel_faults; unsigned long *sun4c_memerr_reg; -__initfunc(static void should_not_happen(void)) +static void __init should_not_happen(void) { prom_printf(shouldnothappen); prom_halt(); } -__initfunc(unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long end_mem) { should_not_happen(); return 0; } -__initfunc(void ld_mmu_sun4c(void)) +void __init ld_mmu_sun4c(void) { should_not_happen(); } @@ -66,12 +66,12 @@ { } -__initfunc(void sun4c_probe_vac(void)) +void __init sun4c_probe_vac(void) { should_not_happen(); } -__initfunc(void sun4c_probe_memerr_reg(void)) +void __init sun4c_probe_memerr_reg(void) { should_not_happen(); } diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.3.15/linux/arch/sparc/mm/srmmu.c Mon Aug 9 11:29:37 1999 +++ linux/arch/sparc/mm/srmmu.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.190 1999/08/07 17:47:01 anton Exp $ +/* $Id: srmmu.c,v 1.191 1999/08/31 06:54:38 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -204,7 +204,7 @@ #define PGSKIP_DEBUG(from,to) do { } while (0) #endif -__initfunc(void srmmu_frob_mem_map(unsigned long start_mem)) +void __init srmmu_frob_mem_map(unsigned long start_mem) { unsigned long bank_start, bank_end = 0; unsigned long addr; @@ -1503,7 +1503,7 @@ * looking at the prom's page table directly which is what most * other OS's do. Yuck... this is much better. */ -__initfunc(void srmmu_inherit_prom_mappings(unsigned long start,unsigned long end)) +void __init srmmu_inherit_prom_mappings(unsigned long start,unsigned long end) { pgd_t *pgdp; pmd_t *pmdp; @@ -1571,7 +1571,7 @@ static int srmmu_low_pa __initdata = 0; static unsigned long end_of_phys_memory __initdata = 0; -__initfunc(void srmmu_end_memory(unsigned long memory_size, unsigned long *end_mem_p)) +void __init srmmu_end_memory(unsigned long memory_size, unsigned long *end_mem_p) { unsigned int sum = 0; unsigned long last = 0xff000000; @@ -1633,7 +1633,7 @@ #define KERNEL_PTE(page_shifted) ((page_shifted)|SRMMU_CACHE|SRMMU_PRIV|SRMMU_VALID) /* Create a third-level SRMMU 16MB page mapping. */ -__initfunc(static void do_large_mapping(unsigned long vaddr, unsigned long phys_base)) +static void __init do_large_mapping(unsigned long vaddr, unsigned long phys_base) { pgd_t *pgdp = srmmu_pgd_offset(&init_mm, vaddr); unsigned long big_pte; @@ -1664,7 +1664,7 @@ * array of char's, each member indicating if that spbank is mapped * yet or not. */ -__initfunc(static int find_free_spbank(char *taken_vector)) +static int __init find_free_spbank(char *taken_vector) { int entry; @@ -1678,7 +1678,7 @@ /* Map sp_bank entry SP_ENTRY, starting at virtual address VBASE. */ -__initfunc(static unsigned long map_spbank(unsigned long vbase, int sp_entry)) +static unsigned long __init map_spbank(unsigned long vbase, int sp_entry) { unsigned long pstart = (sp_banks[sp_entry].base_addr & SRMMU_PGDIR_MASK); unsigned long vstart = (vbase & SRMMU_PGDIR_MASK); @@ -1943,7 +1943,7 @@ void (*poke_srmmu)(void) __initdata = NULL; -__initfunc(unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem) { unsigned long ptables_start; int i, cpunode; @@ -2157,13 +2157,13 @@ } /* Init various srmmu chip types. */ -__initfunc(static void srmmu_is_bad(void)) +static void __init srmmu_is_bad(void) { prom_printf("Could not determine SRMMU chip type.\n"); prom_halt(); } -__initfunc(static void init_vac_layout(void)) +static void __init init_vac_layout(void) { int nd, cache_lines; char node_str[128]; @@ -2217,7 +2217,7 @@ (int)vac_cache_size, (int)vac_line_size); } -__initfunc(static void poke_hypersparc(void)) +static void __init poke_hypersparc(void) { volatile unsigned long clear; unsigned long mreg = srmmu_get_mmureg(); @@ -2240,7 +2240,7 @@ clear = srmmu_get_fstatus(); } -__initfunc(static void init_hypersparc(void)) +static void __init init_hypersparc(void) { srmmu_name = "ROSS HyperSparc"; @@ -2277,7 +2277,7 @@ hypersparc_setup_blockops(); } -__initfunc(static void poke_cypress(void)) +static void __init poke_cypress(void) { unsigned long mreg = srmmu_get_mmureg(); unsigned long faddr, tagval; @@ -2316,7 +2316,7 @@ srmmu_set_mmureg(mreg); } -__initfunc(static void init_cypress_common(void)) +static void __init init_cypress_common(void) { init_vac_layout(); @@ -2345,14 +2345,14 @@ poke_srmmu = poke_cypress; } -__initfunc(static void init_cypress_604(void)) +static void __init init_cypress_604(void) { srmmu_name = "ROSS Cypress-604(UP)"; srmmu_modtype = Cypress; init_cypress_common(); } -__initfunc(static void init_cypress_605(unsigned long mrev)) +static void __init init_cypress_605(unsigned long mrev) { srmmu_name = "ROSS Cypress-605(MP)"; if(mrev == 0xe) { @@ -2369,7 +2369,7 @@ init_cypress_common(); } -__initfunc(static void poke_swift(void)) +static void __init poke_swift(void) { unsigned long mreg = srmmu_get_mmureg(); @@ -2390,7 +2390,7 @@ } #define SWIFT_MASKID_ADDR 0x10003018 -__initfunc(static void init_swift(void)) +static void __init init_swift(void) { unsigned long swift_rev; @@ -2552,7 +2552,7 @@ } -__initfunc(static void poke_turbosparc(void)) +static void __init poke_turbosparc(void) { unsigned long mreg = srmmu_get_mmureg(); unsigned long ccreg; @@ -2592,7 +2592,7 @@ srmmu_set_mmureg(mreg); } -__initfunc(static void init_turbosparc(void)) +static void __init init_turbosparc(void) { srmmu_name = "Fujitsu TurboSparc"; srmmu_modtype = TurboSparc; @@ -2616,7 +2616,7 @@ poke_srmmu = poke_turbosparc; } -__initfunc(static void poke_tsunami(void)) +static void __init poke_tsunami(void) { unsigned long mreg = srmmu_get_mmureg(); @@ -2627,7 +2627,7 @@ srmmu_set_mmureg(mreg); } -__initfunc(static void init_tsunami(void)) +static void __init init_tsunami(void) { /* Tsunami's pretty sane, Sun and TI actually got it * somewhat right this time. Fujitsu should have @@ -2656,7 +2656,7 @@ poke_srmmu = poke_tsunami; } -__initfunc(static void poke_viking(void)) +static void __init poke_viking(void) { unsigned long mreg = srmmu_get_mmureg(); static int smp_catch = 0; @@ -2711,7 +2711,7 @@ #endif } -__initfunc(static void init_viking(void)) +static void __init init_viking(void) { unsigned long mreg = srmmu_get_mmureg(); @@ -2776,7 +2776,7 @@ } /* Probe for the srmmu chip version. */ -__initfunc(static void get_srmmu_type(void)) +static void __init get_srmmu_type(void) { unsigned long mreg, psr; unsigned long mod_typ, mod_rev, psr_typ, psr_vers; @@ -2942,7 +2942,7 @@ *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \ } while(0); -__initfunc(static void patch_window_trap_handlers(void)) +static void __init patch_window_trap_handlers(void) { unsigned long *iaddr, *daddr; @@ -2965,7 +2965,7 @@ #endif /* Load up routines and constants for sun4m and sun4d mmu */ -__initfunc(void ld_mmu_srmmu(void)) +void __init ld_mmu_srmmu(void) { extern void ld_mmu_iommu(void); extern void ld_mmu_iounit(void); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.15/linux/arch/sparc/mm/sun4c.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/mm/sun4c.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.175 1999/07/30 09:35:10 davem Exp $ +/* $Id: sun4c.c,v 1.176 1999/08/31 06:54:42 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -437,7 +437,7 @@ sun4c_set_context(savectx); } -__initfunc(void sun4c_probe_vac(void)) +void __init sun4c_probe_vac(void) { sun4c_disable_vac(); @@ -601,7 +601,7 @@ } } -__initfunc(static void sun4c_probe_mmu(void)) +static void __init sun4c_probe_mmu(void) { if (ARCH_SUN4) { switch(idprom->id_machtype) { @@ -652,7 +652,7 @@ volatile unsigned long *sun4c_memerr_reg = 0; -__initfunc(void sun4c_probe_memerr_reg(void)) +void __init sun4c_probe_memerr_reg(void) { int node; struct linux_prom_registers regs[1]; @@ -730,7 +730,7 @@ static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS]; -__initfunc(static void sun4c_init_mmu_entry_pool(void)) +static void __init sun4c_init_mmu_entry_pool(void) { int i; @@ -788,7 +788,7 @@ } } -__initfunc(static void sun4c_init_lock_area(unsigned long start, unsigned long end)) +static void __init sun4c_init_lock_area(unsigned long start, unsigned long end) { int i, ctx; @@ -897,7 +897,7 @@ add_ring(&sun4c_kfree_ring, entry); } -__initfunc(static void sun4c_init_fill_kernel_ring(int howmany)) +static void __init sun4c_init_fill_kernel_ring(int howmany) { int i; @@ -912,7 +912,7 @@ } } -__initfunc(static void sun4c_init_fill_user_ring(void)) +static void __init sun4c_init_fill_user_ring(void) { int i; @@ -1372,7 +1372,7 @@ garbage_collect(entry); } -__initfunc(static void sun4c_init_buckets(void)) +static void __init sun4c_init_buckets(void) { int entry; @@ -1534,7 +1534,7 @@ struct vm_area_struct sun4c_kstack_vma; -__initfunc(static unsigned long sun4c_init_lock_areas(unsigned long start_mem)) +static unsigned long __init sun4c_init_lock_areas(unsigned long start_mem) { unsigned long sun4c_taskstack_start; unsigned long sun4c_taskstack_end; @@ -2745,7 +2745,7 @@ extern unsigned long sparc_context_init(unsigned long, int); extern unsigned long end; -__initfunc(unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long end_mem) { int i, cnt; unsigned long kernel_end, vaddr; @@ -2798,7 +2798,7 @@ } /* Load up routines and constants for sun4c mmu */ -__initfunc(void ld_mmu_sun4c(void)) +void __init ld_mmu_sun4c(void) { extern void ___xchg32_sun4c(void); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/tsunami.S linux/arch/sparc/mm/tsunami.S --- v2.3.15/linux/arch/sparc/mm/tsunami.S Thu May 15 16:48:02 1997 +++ linux/arch/sparc/mm/tsunami.S Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: tsunami.S,v 1.1 1997/05/03 05:09:09 davem Exp $ +/* $Id: tsunami.S,v 1.2 1999/08/14 03:51:48 anton Exp $ * tsunami.S: High speed MicroSparc-I mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -12,7 +12,7 @@ #define WINDOW_FLUSH(tmp1, tmp2) \ mov 0, tmp1; \ -98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \ +98: ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], tmp2; \ orcc %g0, tmp2, %g0; \ add tmp1, 1, tmp1; \ bne 98b; \ diff -u --recursive --new-file v2.3.15/linux/arch/sparc/mm/viking.S linux/arch/sparc/mm/viking.S --- v2.3.15/linux/arch/sparc/mm/viking.S Thu Mar 25 09:23:33 1999 +++ linux/arch/sparc/mm/viking.S Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: viking.S,v 1.13 1999/03/24 11:42:32 davem Exp $ +/* $Id: viking.S,v 1.14 1999/08/14 03:51:50 anton Exp $ * viking.S: High speed Viking cache/mmu operations * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -144,7 +144,7 @@ #define WINDOW_FLUSH(tmp1, tmp2) \ mov 0, tmp1; \ -98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \ +98: ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], tmp2; \ orcc %g0, tmp2, %g0; \ add tmp1, 1, tmp1; \ bne 98b; \ diff -u --recursive --new-file v2.3.15/linux/arch/sparc/prom/bootstr.c linux/arch/sparc/prom/bootstr.c --- v2.3.15/linux/arch/sparc/prom/bootstr.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/prom/bootstr.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: bootstr.c,v 1.17 1998/02/09 13:26:21 jj Exp $ +/* $Id: bootstr.c,v 1.18 1999/08/31 06:54:45 davem Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -16,8 +16,8 @@ extern linux_sun4_romvec *sun4_romvec; -__initfunc(char * -prom_getbootargs(void)) +char * __init +prom_getbootargs(void) { int iter; char *cp, *arg; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/prom/init.c linux/arch/sparc/prom/init.c --- v2.3.15/linux/arch/sparc/prom/init.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/prom/init.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.12 1998/01/30 10:59:02 jj Exp $ +/* $Id: init.c,v 1.13 1999/08/31 06:54:45 davem Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * @@ -35,7 +35,7 @@ extern void prom_meminit(void); extern void prom_ranges_init(void); -__initfunc(void prom_init(struct linux_romvec *rp)) +void __init prom_init(struct linux_romvec *rp) { #ifdef CONFIG_SUN4 extern struct linux_romvec *sun4_prom_init(void); diff -u --recursive --new-file v2.3.15/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c --- v2.3.15/linux/arch/sparc/prom/memory.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/prom/memory.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.13 1998/01/30 10:59:03 jj Exp $ +/* $Id: memory.c,v 1.14 1999/08/31 06:54:46 davem Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * @@ -39,8 +39,8 @@ /* Internal Prom library routine to sort a linux_mlist_v0 memory * list. Used below in initialization. */ -__initfunc(static void -prom_sortmemlist(struct linux_mlist_v0 *thislist)) +static void __init +prom_sortmemlist(struct linux_mlist_v0 *thislist) { int swapi = 0; int i, mitr, tmpsize; @@ -69,7 +69,7 @@ } /* Initialize the memory lists based upon the prom version. */ -__initfunc(void prom_meminit(void)) +void __init prom_meminit(void) { int node = 0; unsigned int iter, num_regs; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/prom/ranges.c linux/arch/sparc/prom/ranges.c --- v2.3.15/linux/arch/sparc/prom/ranges.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/prom/ranges.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: ranges.c,v 1.11 1998/01/30 10:59:05 jj Exp $ +/* $Id: ranges.c,v 1.12 1999/08/31 06:54:47 davem Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -82,7 +82,7 @@ } } -__initfunc(void prom_ranges_init(void)) +void __init prom_ranges_init(void) { int node, obio_node; int success; @@ -107,7 +107,7 @@ return; } -__initfunc(void prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus)) +void __init prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus) { int success; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/prom/sun4prom.c linux/arch/sparc/prom/sun4prom.c --- v2.3.15/linux/arch/sparc/prom/sun4prom.c Tue Apr 14 17:44:20 1998 +++ linux/arch/sparc/prom/sun4prom.c Thu Aug 26 12:42:32 1999 @@ -114,7 +114,7 @@ static int synch_hook; -__initfunc(struct linux_romvec *sun4_prom_init(void)) +struct linux_romvec * __init sun4_prom_init(void) { int i; unsigned char x; diff -u --recursive --new-file v2.3.15/linux/arch/sparc/vmlinux.lds linux/arch/sparc/vmlinux.lds --- v2.3.15/linux/arch/sparc/vmlinux.lds Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/vmlinux.lds Tue Aug 31 11:23:30 1999 @@ -32,16 +32,23 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - . = ALIGN(4096); __init_begin = .; .text.init : { *(.text.init) } __init_text_end = .; .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup_init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile --- v2.3.15/linux/arch/sparc64/Makefile Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/Makefile Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.38 1999/08/02 12:06:06 jj Exp $ +# $Id: Makefile,v 1.40 1999/08/19 02:31:57 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -15,7 +15,7 @@ CC := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| \)' > /dev/null; then echo y; else echo n; fi) -IS_EGCS := $(shell if $(CC) -c -m64 -mcmodel=medlow -o /dev/null /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) +IS_EGCS := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) ifneq ($(CC_HAS_ARGS),y) diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.15/linux/arch/sparc64/config.in Thu Aug 26 13:05:34 1999 +++ linux/arch/sparc64/config.in Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.73 1999/08/06 12:11:47 davem Exp $ +# $Id: config.in,v 1.77 1999/08/31 12:49:42 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -36,7 +36,7 @@ # Global things across all Sun machines. define_bool CONFIG_SBUS y define_bool CONFIG_SBUSCHAR y -define_bool CONFIG_MOUSE y +define_bool CONFIG_BUSMOUSE y define_bool CONFIG_SUN_MOUSE y define_bool CONFIG_SERIAL y define_bool CONFIG_SUN_SERIAL y @@ -64,10 +64,9 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL fi - +source drivers/parport/Config.in +dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT if [ "$CONFIG_PCI" = "y" ]; then - source drivers/parport/Config.in - dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT tristate 'SUNW,envctrl support' CONFIG_ENVCTRL fi endmenu @@ -205,6 +204,7 @@ if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX + tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.15/linux/arch/sparc64/defconfig Fri Aug 6 11:58:00 1999 +++ linux/arch/sparc64/defconfig Tue Aug 31 11:23:30 1999 @@ -27,6 +27,7 @@ CONFIG_PROM_CONSOLE=y CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_MATROX is not set CONFIG_FB_ATY=y @@ -49,7 +50,7 @@ # CONFIG_FBCON_FONTS is not set CONFIG_SBUS=y CONFIG_SBUSCHAR=y -CONFIG_MOUSE=y +CONFIG_BUSMOUSE=y CONFIG_SUN_MOUSE=y CONFIG_SERIAL=y CONFIG_SUN_SERIAL=y @@ -82,7 +83,6 @@ # CONFIG_SPARCAUDIO_DBRI is not set # CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m -CONFIG_PCI_OLD_PROC=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -99,6 +99,7 @@ # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set # CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set CONFIG_PARPORT_1284=y CONFIG_PRINTER=m @@ -108,11 +109,7 @@ # Floppy, IDE, and other block devices # CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_STRIPED=m -CONFIG_MD_MIRRORING=m -CONFIG_MD_RAID5=m +# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m @@ -134,8 +131,9 @@ # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -151,10 +149,11 @@ # # (it is safe to leave these untouched) # -CONFIG_INET_RARP=m CONFIG_SKB_LARGE=y CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # @@ -175,7 +174,6 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -259,6 +257,7 @@ CONFIG_MYRI_SBUS=m CONFIG_DE4X5=m CONFIG_VORTEX=m +CONFIG_ADAPTEC_STARFIRE=m # # Unix 98 PTY support @@ -322,13 +321,13 @@ # # Partition Types # -CONFIG_BSD_DISKLABEL=y -# CONFIG_MAC_PARTITION is not set -CONFIG_SMD_DISKLABEL=y -CONFIG_SOLARIS_X86_PARTITION=y -# CONFIG_SGI_DISKLABEL is not set +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_AMIGA_PARTITION=y +# CONFIG_SGI_PARTITION is not set +CONFIG_SUN_PARTITION=y CONFIG_NLS=y # @@ -359,6 +358,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.3.15/linux/arch/sparc64/kernel/Makefile Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/Makefile Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.44 1999/08/02 12:05:53 jj Exp $ +# $Id: Makefile,v 1.46 1999/08/31 04:39:34 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -20,7 +20,9 @@ traps.o devices.o auxio.o ioport.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o sys_sunos32.o sunos_ioctl32.o \ - central.o psycho.o starfire.o + central.o pci.o pci_common.o pci_iommu.o \ + pci_psycho.o pci_sabre.o starfire.o semaphore.o \ + power.o OX_OBJS := sparc64_ksyms.o ifdef CONFIG_PCI diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/auxio.c linux/arch/sparc64/kernel/auxio.c --- v2.3.15/linux/arch/sparc64/kernel/auxio.c Tue Aug 4 16:03:35 1998 +++ linux/arch/sparc64/kernel/auxio.c Tue Aug 31 11:23:30 1999 @@ -22,7 +22,7 @@ /* Probe and map in the Auxiliary I/O register */ unsigned char *auxio_register; -__initfunc(void auxio_probe(void)) +void __init auxio_probe(void) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; @@ -51,17 +51,7 @@ ebus_done: if (edev) { - if (check_region(edev->base_address[0], - sizeof(unsigned int))) { - prom_printf("%s: Can't get region %lx, %d\n", - __FUNCTION__, edev->base_address[0], - sizeof(unsigned int)); - prom_halt(); - } - request_region(edev->base_address[0], - sizeof(unsigned int), "LED auxio"); - - led_auxio = edev->base_address[0]; + led_auxio = edev->resource[0].start; outl(0x01, led_auxio); return; } diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.3.15/linux/arch/sparc64/kernel/binfmt_aout32.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Thu Aug 26 12:42:32 1999 @@ -453,7 +453,7 @@ } -__initfunc(int init_aout32_binfmt(void)) +int __init init_aout32_binfmt(void) { return register_binfmt(&aout32_format); } diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c --- v2.3.15/linux/arch/sparc64/kernel/cpu.c Tue May 11 08:24:31 1999 +++ linux/arch/sparc64/kernel/cpu.c Thu Aug 26 12:42:32 1999 @@ -58,7 +58,7 @@ unsigned int fsr_storage; -__initfunc(void cpu_probe(void)) +void __init cpu_probe(void) { int manuf, impl; unsigned i, cpuid; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c --- v2.3.15/linux/arch/sparc64/kernel/devices.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/devices.c Thu Aug 26 12:42:32 1999 @@ -21,8 +21,8 @@ extern void cpu_probe(void); extern unsigned long central_probe(unsigned long); -__initfunc(unsigned long -device_scan(unsigned long mem_start)) +unsigned long __init +device_scan(unsigned long mem_start) { char node_str[128]; int nd, prom_node_cpu, thismid; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c --- v2.3.15/linux/arch/sparc64/kernel/ebus.c Fri Aug 6 11:58:00 1999 +++ linux/arch/sparc64/kernel/ebus.c Tue Aug 31 11:23:30 1999 @@ -1,7 +1,8 @@ -/* $Id: ebus.c,v 1.38 1999/08/06 10:37:32 davem Exp $ +/* $Id: ebus.c,v 1.42 1999/08/31 09:12:31 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ #include @@ -19,15 +20,6 @@ #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 *); @@ -46,11 +38,11 @@ extern int envctrl_init(void); #endif -static inline unsigned long ebus_alloc(size_t size) +static inline void *ebus_alloc(size_t size) { - unsigned long mem; + void *mem; - mem = (unsigned long)kmalloc(size, GFP_ATOMIC); + mem = kmalloc(size, GFP_ATOMIC); if (!mem) panic(__FUNCTION__ ": out of memory"); memset((char *)mem, 0, size); @@ -89,23 +81,26 @@ { int regs[PROMREG_MAX]; int irqs[PROMREG_MAX]; - char lbuf[128]; int i, len; dev->prom_node = node; - prom_getstring(node, "name", lbuf, sizeof(lbuf)); - strcpy(dev->prom_name, lbuf); + prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); + printk("(%s)", dev->prom_name); len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); dev->num_addrs = len / sizeof(regs[0]); for (i = 0; i < dev->num_addrs; i++) { - if (regs[i] >= dev->parent->num_addrs) { + int rnum = regs[i]; + if (rnum >= dev->parent->num_addrs) { prom_printf("UGH: property for %s was %d, need < %d\n", dev->prom_name, len, dev->parent->num_addrs); panic(__FUNCTION__); } - dev->base_address[i] = dev->parent->base_address[regs[i]]; + dev->resource[i].start = dev->parent->resource[i].start; + dev->resource[i].end = dev->parent->resource[i].end; + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dev->prom_name; } len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); @@ -129,25 +124,13 @@ } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + ebus_intmap_match(dev->bus, preg, &irqs[i]); - dev->irqs[i] = psycho_irq_build(dev->bus->parent, - dev->bus->self, irqs[i]); + dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]); } } - -#ifdef DEBUG_FILL_EBUS_DEV - dprintf("child '%s': address%s ", dev->prom_name, - dev->num_addrs > 1 ? "es" : ""); - for (i = 0; i < dev->num_addrs; i++) - dprintf("%016lx ", dev->base_address[i]); - dprintf("\n"); - if (dev->num_irqs) { - dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); - for (i = 0; i < dev->num_irqs; i++) - dprintf(" %s", __irq_itoa(dev->irqs[i])); - dprintf("\n"); - } -#endif } void __init fill_ebus_device(int node, struct linux_ebus_device *dev) @@ -155,27 +138,32 @@ struct linux_prom_registers regs[PROMREG_MAX]; struct linux_ebus_child *child; int irqs[PROMINTR_MAX]; - char lbuf[128]; int i, n, len; dev->prom_node = node; - prom_getstring(node, "name", lbuf, sizeof(lbuf)); - strcpy(dev->prom_name, lbuf); + prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); + printk(" [%s", dev->prom_name); len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); if (len % sizeof(struct linux_prom_registers)) { prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", dev->prom_name, len, (int)sizeof(struct linux_prom_registers)); - panic(__FUNCTION__); + prom_halt(); } dev->num_addrs = len / sizeof(struct linux_prom_registers); for (i = 0; i < dev->num_addrs; i++) { n = (regs[i].which_io - 0x10) >> 2; - dev->base_address[i] = dev->bus->self->resource[n].start; - dev->base_address[i] += (unsigned long)regs[i].phys_addr; + dev->resource[i].start = dev->bus->self->resource[n].start; + dev->resource[i].start += (unsigned long)regs[i].phys_addr; + dev->resource[i].end = + (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL); + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dev->prom_name; + request_resource(&dev->bus->self->resource[n], + &dev->resource[i]); } len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); @@ -184,28 +172,17 @@ } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + ebus_intmap_match(dev->bus, ®s[0], &irqs[i]); - dev->irqs[i] = psycho_irq_build(dev->bus->parent, - dev->bus->self, irqs[i]); + dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]); } } -#ifdef DEBUG_FILL_EBUS_DEV - dprintf("'%s': address%s ", dev->prom_name, - dev->num_addrs > 1 ? "es" : ""); - for (i = 0; i < dev->num_addrs; i++) - dprintf("%016lx ", dev->base_address[i]); - dprintf("\n"); - if (dev->num_irqs) { - dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); - for (i = 0; i < dev->num_irqs; i++) - dprintf(" %s", __irq_itoa(dev->irqs[i])); - dprintf("\n"); - } -#endif if ((node = prom_getchild(node))) { - dev->children = (struct linux_ebus_child *) - ebus_alloc(sizeof(struct linux_ebus_child)); + printk(" ->"); + dev->children = ebus_alloc(sizeof(struct linux_ebus_child)); child = dev->children; child->next = 0; @@ -214,8 +191,7 @@ fill_ebus_child(node, ®s[0], child); while ((node = prom_getsibling(node))) { - child->next = (struct linux_ebus_child *) - ebus_alloc(sizeof(struct linux_ebus_child)); + child->next = ebus_alloc(sizeof(struct linux_ebus_child)); child = child->next; child->next = 0; @@ -224,24 +200,21 @@ fill_ebus_child(node, ®s[0], child); } } + printk("]"); } extern void clock_probe(void); +extern void power_init(void); void __init ebus_init(void) { - struct linux_prom_pci_registers regs[PROMREG_MAX]; - struct linux_pbm_info *pbm; + struct pci_pbm_info *pbm; struct linux_ebus_device *dev; struct linux_ebus *ebus; struct pci_dev *pdev; struct pcidev_cookie *cookie; - char lbuf[128]; - struct resource *base; - unsigned long addr; unsigned short pci_command; - int nd, len, ebusnd; - int reg, rng, nreg; + int nd, ebusnd; int num_ebus = 0; if (!pci_present()) @@ -250,17 +223,13 @@ pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0); if (!pdev) { printk("ebus: No EBus's found.\n"); -#ifdef PROM_DEBUG - dprintf("ebus: No EBus's found.\n"); -#endif return; } cookie = pdev->sysdata; ebusnd = cookie->prom_node; - ebus_chain = ebus = (struct linux_ebus *) - ebus_alloc(sizeof(struct linux_ebus)); + ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = 0; while (ebusnd) { @@ -277,9 +246,6 @@ if (ebus == ebus_chain) { ebus_chain = NULL; printk("ebus: No EBus's found.\n"); -#ifdef PROM_DEBUG - dprintf("ebus: No EBus's found.\n"); -#endif return; } break; @@ -290,14 +256,10 @@ continue; } printk("ebus%d:", num_ebus); -#ifdef PROM_DEBUG - dprintf("ebus%d:", num_ebus); -#endif - prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf)); + prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name)); + ebus->index = num_ebus; ebus->prom_node = ebusnd; - strcpy(ebus->prom_name, lbuf); - ebus->self = pdev; ebus->parent = pbm = cookie->pbm; @@ -310,56 +272,7 @@ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); /* NOTE: Cache line size is in 32-bit word units. */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); - - len = prom_getproperty(ebusnd, "reg", (void *)regs, - sizeof(regs)); - if (len == 0 || len == -1) { - prom_printf("%s: can't find reg property\n", - __FUNCTION__); - prom_halt(); - } - nreg = len / sizeof(struct linux_prom_pci_registers); - - base = &ebus->self->resource[0]; - for (reg = 0; reg < nreg; reg++) { - if (!(regs[reg].phys_hi & 0x03000000)) - continue; - - for (rng = 0; rng < pbm->num_pbm_ranges; rng++) { - struct linux_prom_pci_ranges *rp = - &pbm->pbm_ranges[rng]; - - if ((rp->child_phys_hi ^ regs[reg].phys_hi) - & 0x03000000) - continue; - - addr = (u64)regs[reg].phys_lo; - addr += (u64)regs[reg].phys_mid << 32UL; - addr += (u64)rp->parent_phys_lo; - addr += (u64)rp->parent_phys_hi << 32UL; - - base->name = "EBUS"; - base->start = (unsigned long)__va(addr); - base->end = base->start + regs[reg].size_lo - 1; - base->flags = 0; - request_resource(&ioport_resource, base); - - base += 1; - - 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 + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64/sizeof(u32)); prom_ebus_ranges_init(ebus); prom_ebus_intmap_init(ebus); @@ -368,8 +281,7 @@ if (!nd) goto next_ebus; - ebus->devices = (struct linux_ebus_device *) - ebus_alloc(sizeof(struct linux_ebus_device)); + ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device)); dev = ebus->devices; dev->next = 0; @@ -378,8 +290,7 @@ fill_ebus_device(nd, dev); while ((nd = prom_getsibling(nd))) { - dev->next = (struct linux_ebus_device *) - ebus_alloc(sizeof(struct linux_ebus_device)); + dev->next = ebus_alloc(sizeof(struct linux_ebus_device)); dev = dev->next; dev->next = 0; @@ -389,6 +300,8 @@ } next_ebus: + printk("\n"); + pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, pdev); if (!pdev) @@ -397,8 +310,7 @@ cookie = pdev->sysdata; ebusnd = cookie->prom_node; - ebus->next = (struct linux_ebus *) - ebus_alloc(sizeof(struct linux_ebus)); + ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; ebus->next = 0; ++num_ebus; @@ -420,4 +332,5 @@ flash_init(); #endif clock_probe(); + power_init(); } diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/idprom.c linux/arch/sparc64/kernel/idprom.c --- v2.3.15/linux/arch/sparc64/kernel/idprom.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc64/kernel/idprom.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: idprom.c,v 1.2 1997/04/17 02:28:10 miguel Exp $ +/* $Id: idprom.c,v 1.3 1999/08/31 06:54:53 davem Exp $ * idprom.c: Routines to load the idprom into kernel addresses and * interpret the data contained within. * @@ -16,7 +16,7 @@ static struct idprom idprom_buffer; /* Calculate the IDPROM checksum (xor of the data bytes). */ -__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom)) +static unsigned char __init calc_idprom_cksum(struct idprom *idprom) { unsigned char cksum, i, *ptr = (unsigned char *)idprom; @@ -27,7 +27,7 @@ } /* Create a local IDPROM copy and verify integrity. */ -__initfunc(void idprom_init(void)) +void __init idprom_init(void) { prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer)); diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.15/linux/arch/sparc64/kernel/ioctl32.c Wed Aug 18 11:39:01 1999 +++ linux/arch/sparc64/kernel/ioctl32.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.66 1999/08/08 01:37:06 davem Exp $ +/* $Id: ioctl32.c,v 1.67 1999/08/20 00:27:08 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.3.15/linux/arch/sparc64/kernel/irq.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc64/kernel/irq.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.76 1999/04/02 14:54:30 davem Exp $ +/* $Id: irq.c,v 1.78 1999/08/31 06:54:54 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -31,11 +31,6 @@ #include #include -#ifdef CONFIG_PCI -#include -#include -#endif - /* Internal flag, should not be visible elsewhere at all. */ #define SA_IMAP_MASKED 0x100 #define SA_DMA_SYNC 0x200 @@ -79,15 +74,6 @@ NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; -/* Only 8-bits are available, be careful. -DaveM */ -#define IBF_DMA_SYNC 0x01 /* DMA synchronization behind PCI bridge needed. */ -#define IBF_PCI 0x02 /* Indicates PSYCHO/SCHIZO PCI interrupt. */ -#define IBF_ACTIVE 0x04 /* This interrupt is active and has a handler. */ -#define IBF_MULTI 0x08 /* On PCI, indicates shared bucket. */ - -#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) -#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) - int get_irq_list(char *buf) { int i, len = 0; @@ -183,67 +169,22 @@ /* Convert Interrupt Mapping register pointer to assosciated * Interrupt Clear register pointer, SYSIO specific version. */ -static unsigned int *sysio_imap_to_iclr(unsigned int *imap) +static volatile unsigned int *sysio_imap_to_iclr(volatile unsigned int *imap) { unsigned long diff; diff = offset(iclr_unused0) - offset(imap_slot0); - return (unsigned int *) (((unsigned long)imap) + diff); + return (volatile unsigned int *) (((unsigned long)imap) + diff); } #undef offset -#ifdef CONFIG_PCI -/* PCI PSYCHO INO number to Sparc PIL level. */ -unsigned char psycho_ino_to_pil[] = { - 7, 5, 4, 2, /* PCI A slot 0 Int A, B, C, D */ - 7, 5, 4, 2, /* PCI A slot 1 Int A, B, C, D */ - 7, 5, 4, 2, /* PCI A slot 2 Int A, B, C, D */ - 7, 5, 4, 2, /* PCI A slot 3 Int A, B, C, D */ - 6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */ - 6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */ - 6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */ - 6, 4, 3, 1, /* PCI B slot 3 Int A, B, C, D */ - 3, /* SCSI */ - 5, /* Ethernet */ - 8, /* Parallel Port */ - 13, /* Audio Record */ - 14, /* Audio Playback */ - 15, /* PowerFail */ - 3, /* second SCSI */ - 11, /* Floppy */ - 2, /* Spare Hardware */ - 9, /* Keyboard */ - 4, /* Mouse */ - 12, /* Serial */ - 10, /* Timer 0 */ - 11, /* Timer 1 */ - 15, /* Uncorrectable ECC */ - 15, /* Correctable ECC */ - 15, /* PCI Bus A Error */ - 15, /* PCI Bus B Error */ - 1, /* Power Management */ -}; - -/* INO number to IMAP register offset for PSYCHO external IRQ's. */ -#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x))) - -#define psycho_imap_offset(ino) \ - ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \ - (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1))) - -#define psycho_iclr_offset(ino) \ - ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \ - (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f)<<3))) - -#endif - /* Now these are always passed a true fully specified sun4u INO. */ void enable_irq(unsigned int irq) { extern int this_is_starfire; struct ino_bucket *bucket = __bucket(irq); - unsigned int *imap; + volatile unsigned int *imap; unsigned long tid; imap = bucket->imap; @@ -257,7 +198,7 @@ : "i" (ASI_UPA_CONFIG)); tid = ((tid & UPA_CONFIG_MID) << 9); } else { - extern unsigned int starfire_translate(unsigned int *imap, + extern unsigned int starfire_translate(volatile unsigned int *imap, unsigned int upaid); tid = (starfire_translate(imap, current->processor) << 26); @@ -278,7 +219,7 @@ void disable_irq(unsigned int irq) { struct ino_bucket *bucket = __bucket(irq); - unsigned int *imap; + volatile unsigned int *imap; imap = bucket->imap; if (imap != NULL) { @@ -306,7 +247,7 @@ NULL, /* imap */ }; -unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap) +unsigned int build_irq(int pil, int inofixup, volatile unsigned int *iclr, volatile unsigned int *imap) { struct ino_bucket *bucket; int ino; @@ -365,7 +306,7 @@ struct sysio_regs *sregs = sbus->iommu->sysio_regs; unsigned long offset; int pil; - unsigned int *imap, *iclr; + volatile unsigned int *imap, *iclr; int sbus_level = 0; pil = sysio_ino_to_pil[ino]; @@ -380,7 +321,7 @@ panic("BAD SYSIO IRQ offset..."); } offset += ((unsigned long)sregs); - imap = ((unsigned int *)offset); + imap = ((volatile unsigned int *)offset); /* SYSIO inconsistancy. For external SLOTS, we have to select * the right ICLR register based upon the lower SBUS irq level @@ -412,81 +353,11 @@ iclraddr = (unsigned long) iclr; iclraddr += ((sbus_level - 1) * 8); - iclr = (unsigned int *) iclraddr; + iclr = (volatile unsigned int *) iclraddr; } return build_irq(pil, sbus_level, iclr, imap); } -#ifdef CONFIG_PCI -unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_dma_sync) -{ - struct linux_psycho *psycho = (struct linux_psycho *)buscookie; - struct psycho_regs *pregs = psycho->psycho_regs; - unsigned long addr; - struct ino_bucket *bucket; - int pil; - unsigned int *imap, *iclr; - int inofixup = 0; - - pil = psycho_ino_to_pil[ino & PCI_IRQ_INO]; - - addr = (unsigned long) &pregs->imap_a_slot0; - addr = addr + imap_off; - imap = ((unsigned int *)addr) + 1; - - addr = (unsigned long) pregs; - addr += psycho_iclr_offset(ino & (PCI_IRQ_INO)); - iclr = ((unsigned int *)addr) + 1; - - if(!(ino & 0x20)) - inofixup = ino & 0x03; - - /* First check for sharing. */ - ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup; - if (ino > NUM_IVECS) { - prom_printf("PSYCHO: Invalid INO %04x (%d:%d:%016lx:%016lx)\n", - ino, pil, inofixup, iclr, imap); - prom_halt(); - } - bucket = &ivector_table[ino]; - if(bucket->flags & IBF_ACTIVE) { - void *old_handler = bucket->irq_info; - unsigned long flags; - - if(old_handler == NULL) { - prom_printf("PSYCHO: Active bucket, but no handler.\n"); - prom_halt(); - } - save_and_cli(flags); - if((bucket->flags & IBF_MULTI) == 0) { - void **vector; - - vector = kmalloc(sizeof(void *) * 4, - GFP_KERNEL); - - /* We might have slept. */ - if((bucket->flags & IBF_MULTI) != 0) { - kfree(vector); - } else { - vector[0] = old_handler; - vector[1] = vector[2] = vector[3] = NULL; - bucket->irq_info = vector; - bucket->flags |= IBF_MULTI; - } - } - restore_flags(flags); - } else { - /* Just init the bucket */ - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); - } - if (need_dma_sync) - bucket->flags |= IBF_DMA_SYNC; - - bucket->flags |= IBF_PCI; - return __irq(bucket); -} -#endif - static void atomic_bucket_insert(struct ino_bucket *bucket) { unsigned long pstate; @@ -731,7 +602,7 @@ *(bucket->pil + irq_action) = action->next; if(action->flags & SA_IMAP_MASKED) { - unsigned int *imap = bucket->imap; + volatile unsigned int *imap = bucket->imap; void **vector, *orig; int ent; @@ -1286,7 +1157,7 @@ { extern int this_is_starfire; struct ino_bucket *bucket = __bucket(p->mask); - unsigned int *imap = bucket->imap; + volatile unsigned int *imap = bucket->imap; unsigned int tid; /* Never change this, it causes problems on Ex000 systems. */ @@ -1296,7 +1167,7 @@ if(this_is_starfire == 0) { tid = __cpu_logical_map[goal_cpu] << 26; } else { - extern unsigned int starfire_translate(unsigned int *imap, + extern unsigned int starfire_translate(volatile unsigned int *imap, unsigned int upaid); tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26); @@ -1399,7 +1270,7 @@ prom_timers->count0 = 0; } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { static int called = 0; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.3.15/linux/arch/sparc64/kernel/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/pci.c Tue Aug 31 11:23:30 1999 @@ -0,0 +1,361 @@ +/* $Id: pci.c,v 1.1 1999/08/30 10:00:42 davem Exp $ + * pci.c: UltraSparc PCI controller support. + * + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* This is the base address of IOMMU translated space + * on PCI bus segments. This means that any PCI address + * greater than or equal this value will be translated + * into a physical address and transferred on the system + * bus. Any address less than it will be considered a + * PCI peer-to-peer transaction. For example, given a + * value of 0x80000000: + * + * If a PCI device bus masters the address 0x80001000 + * then then PCI controller's IOMMU will take the offset + * portion (0x1000) and translate that into a physical + * address. The data transfer will be performed to/from + * that physical address on the system bus. + * + * If the PCI device bus masters the address 0x00002000 + * then the PCI controller will not do anything, it will + * proceed as a PCI peer-to-peer transfer. + * + * This all stems from the fact that PCI drivers in Linux are + * not conscious of DMA mappings to the extent they need to + * be for systems like Sparc64 and Alpha which have IOMMU's. + * Plans are already in the works to fix this. So what we do + * at the moment is linearly map all of physical ram with the + * IOMMU in consistant mode, thus providing the illusion of + * a simplistic linear DMA mapping scheme to the drivers. + * This, while it works, is bad for performance (streaming + * DMA is not used) and limits the amount of total memory we + * can support (2GB on Psycho, 512MB on Sabre/APB). + */ +unsigned long pci_dvma_offset = 0x00000000UL; + +/* Given a valid PCI dma address (ie. >= pci_dvma_addset) this + * mask will give you the offset into the DMA space of a + * PCI bus. + */ +unsigned long pci_dvma_mask = 0xffffffffUL; + +unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; +unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; + +#ifndef CONFIG_PCI +/* A "nop" PCI implementation. */ +int pcibios_present(void) { return 0; } +asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + return 0; +} +asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + return 0; +} +#else + +/* List of all PCI controllers found in the system. */ +spinlock_t pci_controller_lock = SPIN_LOCK_UNLOCKED; +struct pci_controller_info *pci_controller_root = NULL; + +/* Each PCI controller found gets a unique index. */ +int pci_num_controllers = 0; + +/* Given an 8-bit PCI bus number, this yields the + * controlling PBM module info. + * + * Some explanation is in order here. The Linux APIs for + * the PCI subsystem require that the configuration space + * types are enough to signify PCI configuration space + * accesses correctly. This gives us 8-bits for the bus + * number, however we have multiple PCI controllers on + * UltraSparc systems. + * + * So what we do is give the PCI busses under each controller + * a unique portion of the 8-bit PCI bus number space. + * Therefore one can obtain the controller from the bus + * number. For example, say PSYCHO PBM-A a subordinate bus + * space of 0 to 4, and PBM-B has a space of 0 to 2. PBM-A + * will use 0 to 4, and PBM-B will use 5 to 7. + */ +struct pci_pbm_info *pci_bus2pbm[256]; +unsigned char pci_highest_busnum = 0; + +/* At boot time the user can give the kernel a command + * line option which controls if and how PCI devices + * are reordered at PCI bus probing time. + */ +int pci_device_reorder = 0; + +spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED; +volatile int pci_poke_in_progress; +volatile int pci_poke_faulted; + +/* Probe for all PCI controllers in the system. */ +extern void sabre_init(int); +extern void psycho_init(int); + +static struct { + char *model_name; + void (*init)(int); +} pci_controller_table[] = { + { "SUNW,sabre", sabre_init }, + { "SUNW,psycho", psycho_init } +}; +#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ + sizeof(pci_controller_table[0])) + +static void pci_controller_init(char *model_name, int namelen, int node) +{ + int i; + + for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) { + if (!strncmp(model_name, + pci_controller_table[i].model_name, + namelen)) { + pci_controller_table[i].init(node); + return; + } + } + printk("PCI: Warning unknown controller, model name [%s]\n", + model_name); + printk("PCI: Ignoring controller...\n"); +} + +/* Find each controller in the system, attach and initialize + * software state structure for each and link into the + * pci_controller_root. Setup the controller enough such + * that bus scanning can be done. + */ +static void pci_controller_probe(void) +{ + char namebuf[16]; + int node; + + printk("PCI: Probing for controllers.\n"); + node = prom_getchild(prom_root_node); + while ((node = prom_searchsiblings(node, "pci")) != 0) { + int len; + + len = prom_getproperty(node, "model", + namebuf, sizeof(namebuf)); + if (len > 0) + pci_controller_init(namebuf, len, node); + node = prom_getsibling(node); + if (!node) + break; + } +} + +static void pci_scan_each_controller_bus(void) +{ + struct pci_controller_info *p; + unsigned long flags; + + spin_lock_irqsave(&pci_controller_lock, flags); + for (p = pci_controller_root; p; p = p->next) + p->scan_bus(p); + spin_unlock_irqrestore(&pci_controller_lock, flags); +} + +/* Reorder the pci_dev chain, so that onboard devices come first + * and then come the pluggable cards. + */ +static void __init pci_reorder_devs(void) +{ + struct pci_dev **pci_onboard = &pci_devices; + struct pci_dev **pci_tail = &pci_devices; + struct pci_dev *pdev = pci_devices, *pci_other = NULL; + + while (pdev) { + if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { + if (pci_other) { + *pci_onboard = pdev; + pci_onboard = &pdev->next; + pdev = pdev->next; + *pci_onboard = pci_other; + *pci_tail = pdev; + continue; + } else + pci_onboard = &pdev->next; + } else if (!pci_other) + pci_other = pdev; + pci_tail = &pdev->next; + pdev = pdev->next; + } +} + +void __init pcibios_init(void) +{ + pci_controller_probe(); + if (pci_controller_root == NULL) + return; + + pci_scan_each_controller_bus(); + + if (pci_device_reorder) + pci_reorder_devs(); + + ebus_init(); +} + +struct pci_fixup pcibios_fixups[] = { + { 0 } +}; + +void pcibios_fixup_bus(struct pci_bus *pbus) +{ +} + +char * __init pcibios_setup(char *str) +{ + if (!strcmp(str, "onboardfirst")) { + pci_device_reorder = 1; + return NULL; + } + if (!strcmp(str, "noreorder")) { + pci_device_reorder = 0; + return NULL; + } + return str; +} + +asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + int err = 0; + + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + + dev = pci_find_slot(bus, dfn); + if (!dev) { + /* Xfree86 is such a turd, it does not check the + * return value and just relies on the buffer being + * set to all 1's to mean "device not present". + */ + switch(len) { + case 1: + put_user(0xff, (unsigned char *)buf); + break; + case 2: + put_user(0xffff, (unsigned short *)buf); + break; + case 4: + put_user(0xffffffff, (unsigned int *)buf); + break; + default: + err = -EINVAL; + break; + }; + goto out; + } + + lock_kernel(); + switch(len) { + case 1: + pci_read_config_byte(dev, off, &byte); + put_user(byte, (unsigned char *)buf); + break; + case 2: + pci_read_config_word(dev, off, &word); + put_user(word, (unsigned short *)buf); + break; + case 4: + pci_read_config_dword(dev, off, &dword); + put_user(dword, (unsigned int *)buf); + break; + + default: + err = -EINVAL; + break; + }; + unlock_kernel(); +out: + return err; +} + +asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + int err = 0; + + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + dev = pci_find_slot(bus, dfn); + if (!dev) { + /* See commentary above about Xfree86 */ + goto out; + } + + lock_kernel(); + switch(len) { + case 1: + err = get_user(byte, (u8 *)buf); + if(err) + break; + pci_write_config_byte(dev, off, byte); + break; + + case 2: + err = get_user(word, (u16 *)buf); + if(err) + break; + pci_write_config_byte(dev, off, word); + break; + + case 4: + err = get_user(dword, (u32 *)buf); + if(err) + break; + pci_write_config_byte(dev, off, dword); + break; + + default: + err = -EINVAL; + break; + + }; + unlock_kernel(); + +out: + return err; +} + +#endif /* !(CONFIG_PCI) */ diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c --- v2.3.15/linux/arch/sparc64/kernel/pci_common.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/pci_common.c Tue Aug 31 11:23:30 1999 @@ -0,0 +1,638 @@ +/* $Id: pci_common.c,v 1.2 1999/08/31 09:12:33 davem Exp $ + * pci_common.c: PCI controller common support. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include + +#include + +/* Find the OBP PROM device tree node for a PCI device. + * Return zero if not found. + */ +static int __init find_device_prom_node(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + int bus_prom_node, + struct linux_prom_pci_registers *pregs, + int *nregs) +{ + int node; + + node = prom_getchild(bus_prom_node); + while (node != 0) { + int err = prom_getproperty(node, "reg", + (char *)pregs, + sizeof(*pregs) * PROMREG_MAX); + if (err == 0 || err == -1) + goto do_next_sibling; + if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) { + *nregs = err / sizeof(*pregs); + return node; + } + + do_next_sibling: + node = prom_getsibling(node); + } + return 0; +} + +/* Remove a PCI device from the device trees, then + * free it up. Note that this must run before + * the device's resources are registered because we + * do not handle unregistering them here. + */ +static void pci_device_delete(struct pci_dev *pdev) +{ + struct pci_dev **dpp; + + /* First, unlink from list of all devices. */ + dpp = &pci_devices; + while (*dpp != NULL) { + if (*dpp == pdev) { + *dpp = pdev->next; + pdev->next = NULL; + break; + } + dpp = &(*dpp)->next; + } + + /* Next, unlink from bus sibling chain. */ + dpp = &pdev->bus->devices; + while (*dpp != NULL) { + if (*dpp == pdev) { + *dpp = pdev->sibling; + pdev->sibling = NULL; + break; + } + dpp = &(*dpp)->sibling; + } + + /* Ok, all references are gone, free it up. */ + kfree(pdev); +} + +/* Fill in the PCI device cookie sysdata for the given + * PCI device. This cookie is the means by which one + * can get to OBP and PCI controller specific information + * for a PCI device. + */ +static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + int bus_prom_node) +{ + struct linux_prom_pci_registers pregs[PROMREG_MAX]; + struct pcidev_cookie *pcp; + int device_prom_node, nregs, err; + + device_prom_node = find_device_prom_node(pbm, pdev, bus_prom_node, + pregs, &nregs); + if (device_prom_node == 0) { + /* If it is not in the OBP device tree then + * there must be a damn good reason for it. + * + * So what we do is delete the device from the + * PCI device tree completely. This scenerio + * is seen, for example, on CP1500 for the + * second EBUS/HappyMeal pair if the external + * connector for it is not present. + */ + pci_device_delete(pdev); + return; + } + + pcp = kmalloc(sizeof(*pcp), GFP_ATOMIC); + if (pcp == NULL) { + prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n"); + prom_halt(); + } + pcp->pbm = pbm; + pcp->prom_node = device_prom_node; + memcpy(pcp->prom_regs, pregs, sizeof(pcp->prom_regs)); + pcp->num_prom_regs = nregs; + err = prom_getproperty(device_prom_node, "name", + pcp->prom_name, sizeof(pcp->prom_name)); + if (err > 0) + pcp->prom_name[err] = 0; + else + pcp->prom_name[0] = 0; + if (strcmp(pcp->prom_name, "ebus") == 0) { + struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX]; + int iter; + + /* EBUS is special... */ + err = prom_getproperty(device_prom_node, "ranges", + (char *)&erng[0], sizeof(erng)); + if (err == 0 || err == -1) { + prom_printf("EBUS: Fatal error, no range property\n"); + prom_halt(); + } + err = (err / sizeof(erng[0])); + for(iter = 0; iter < err; iter++) { + struct linux_prom_ebus_ranges *ep = &erng[iter]; + struct linux_prom_pci_registers *ap; + + ap = &pcp->prom_assignments[iter]; + + ap->phys_hi = ep->parent_phys_hi; + ap->phys_mid = ep->parent_phys_mid; + ap->phys_lo = ep->parent_phys_lo; + ap->size_hi = 0; + ap->size_lo = ep->size; + } + pcp->num_prom_assignments = err; + } else { + err = prom_getproperty(device_prom_node, + "assigned-addresses", + (char *)pcp->prom_assignments, + sizeof(pcp->prom_assignments)); + if (err == 0 || err == -1) + pcp->num_prom_assignments = 0; + else + pcp->num_prom_assignments = + (err / sizeof(pcp->prom_assignments[0])); + } + + pdev->sysdata = pcp; +} + +void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, + struct pci_pbm_info *pbm, + int prom_node) +{ + struct pci_dev *pdev; + + /* This loop is coded like this because the cookie + * fillin routine can delete devices from the tree. + */ + pdev = pbus->devices; + while (pdev != NULL) { + struct pci_dev *next = pdev->sibling; + + pdev_cookie_fillin(pbm, pdev, prom_node); + + pdev = next; + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) { + struct pcidev_cookie *pcp = pbus->self->sysdata; + pci_fill_in_pbm_cookies(pbus, pbm, pcp->prom_node); + } +} + +static void __init bad_assignment(struct linux_prom_pci_registers *ap, + struct resource *res, + int do_prom_halt) +{ + prom_printf("PCI: Bogus PROM assignment.\n"); + if (ap) + prom_printf("PCI: phys[%08x:%08x:%08x] size[%08x:%08x]\n", + ap->phys_hi, ap->phys_mid, ap->phys_lo, + ap->size_hi, ap->size_lo); + if (res) + prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n", + res->start, res->end, res->flags); + prom_printf("Please email this information to davem@redhat.com\n"); + if (do_prom_halt) + prom_halt(); +} + +static struct resource * +__init get_root_resource(struct linux_prom_pci_registers *ap, + struct pci_pbm_info *pbm) +{ + int space = (ap->phys_hi >> 24) & 3; + + switch (space) { + case 0: + /* Configuration space, silently ignore it. */ + return NULL; + + case 1: + /* 16-bit IO space */ + return &pbm->io_space; + + case 2: + /* 32-bit MEM space */ + return &pbm->mem_space; + + case 3: + default: + /* 64-bit MEM space, unsupported. */ + printk("PCI: 64-bit MEM assignment??? " + "Tell davem@redhat.com about it!\n"); + return NULL; + }; +} + +static struct resource * +__init get_device_resource(struct linux_prom_pci_registers *ap, + struct pci_dev *pdev) +{ + int breg = (ap->phys_hi & 0xff); + int space = (ap->phys_hi >> 24) & 3; + + switch (breg) { + case PCI_ROM_ADDRESS: + /* It had better be MEM space. */ + if (space != 2) + bad_assignment(ap, NULL, 0); + + return &pdev->resource[PCI_ROM_RESOURCE]; + + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_1: + case PCI_BASE_ADDRESS_2: + case PCI_BASE_ADDRESS_3: + case PCI_BASE_ADDRESS_4: + case PCI_BASE_ADDRESS_5: + return &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4]; + + default: + bad_assignment(ap, NULL, 0); + return NULL; + }; +} + +static void __init pdev_record_assignments(struct pci_pbm_info *pbm, + struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + int i; + + for (i = 0; i < pcp->num_prom_assignments; i++) { + struct linux_prom_pci_registers *ap; + struct resource *root, *res; + + /* The format of this property is specified in + * the PCI Bus Binding to IEEE1275-1994. + */ + ap = &pcp->prom_assignments[i]; + root = get_root_resource(ap, pbm); + res = get_device_resource(ap, pdev); + if (root == NULL || res == NULL) + continue; + + /* Ok we know which resource this PROM assignment is + * for, sanity check it. + */ + if ((res->start & 0xffffffffUL) != ap->phys_lo) + bad_assignment(ap, res, 1); + + /* Adjust the resource into the physical address space + * of this PBM. + */ + pbm->parent->resource_adjust(pdev, res, root); + + if (request_resource(root, res) < 0) { + /* OK, there is some conflict. But this is fine + * since we'll reassign it in the fixup pass. + * Nevertheless notify the user that OBP made + * an error. + */ + printk(KERN_ERR "PCI: Address space collision on region %ld " + "of device %s\n", + (res - &pdev->resource[0]), pdev->name); + } + } +} + +void __init pci_record_assignments(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) + pdev_record_assignments(pbm, pdev); + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_record_assignments(pbm, pbus); +} + +static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_dev *pdev) +{ + u32 reg; + u16 cmd; + int i, io_seen, mem_seen; + + io_seen = mem_seen = 0; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *root, *res; + unsigned long size, min, max, align; + + res = &pdev->resource[i]; + + if (res->flags & IORESOURCE_IO) + io_seen++; + else if (res->flags & IORESOURCE_MEM) + mem_seen++; + + /* If it is already assigned or the resource does + * not exist, there is nothing to do. + */ + if (res->parent != NULL || res->flags == 0UL) + continue; + + /* Determine the root we allocate from. */ + if (res->flags & IORESOURCE_IO) { + root = &pbm->io_space; + min = root->start + 0x400UL; + max = root->end; + } else { + root = &pbm->mem_space; + min = root->start; + max = min + 0x80000000UL; + } + + size = res->end - res->start; + align = size + 1; + if (allocate_resource(root, res, size + 1, min, max, align) < 0) { + /* uh oh */ + prom_printf("PCI: Failed to allocate resource %d for %s\n", + i, pdev->name); + prom_halt(); + } + + /* Update PCI config space. */ + pbm->parent->base_address_update(pdev, i); + } + + /* Special case, disable the ROM. Several devices + * act funny (ie. do not respond to memory space writes) + * when it is left enabled. A good example are Qlogic,ISP + * adapters. + */ + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, ®); + reg &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, reg); + + /* If we saw I/O or MEM resources, enable appropriate + * bits in PCI command register. + */ + if (io_seen || mem_seen) { + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (io_seen) + cmd |= PCI_COMMAND_IO; + if (mem_seen) + cmd |= PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + } + + /* If this is a PCI bridge or an IDE controller, + * enable bus mastering. In the former case also + * set the cache line size correctly. + */ + if (((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) || + (((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) && + ((pdev->class & 0x80) != 0))) { + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + pci_write_config_byte(pdev, + PCI_CACHE_LINE_SIZE, + (64 / sizeof(u32))); + } +} + +void __init pci_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) + pdev_assign_unassigned(pbm, pdev); + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_assign_unassigned(pbm, pbus); +} + +static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) +{ + struct pcidev_cookie *dev_pcp = pdev->sysdata; + struct pci_pbm_info *pbm = dev_pcp->pbm; + struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs; + unsigned int hi, mid, lo, irq; + int i; + + if (pbm->num_pbm_intmap == 0) + return 0; + + /* If we are underneath a PCI bridge, use PROM register + * property of parent bridge. + */ + if (pdev->bus->number != pbm->pci_first_busno) { + struct pcidev_cookie *bus_pcp; + int offset; + + bus_pcp = pdev->bus->self->sysdata; + pregs = bus_pcp->prom_regs; + offset = prom_getint(bus_pcp->prom_node, + "fcode-rom-offset"); + + /* Did PROM know better and assign an interrupt other + * than #INTA to the device? - We test here for presence of + * FCODE on the card, in this case we assume PROM has set + * correct 'interrupts' property, unless it is quadhme. + */ + if (offset == -1 || + !strcmp(bus_pcp->prom_name, "SUNW,qfe") || + !strcmp(bus_pcp->prom_name, "qfe")) { + /* + * No, use low slot number bits of child as IRQ line. + */ + *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1; + } + } + + hi = pregs->phys_hi & pbm->pbm_intmask.phys_hi; + mid = pregs->phys_mid & pbm->pbm_intmask.phys_mid; + lo = pregs->phys_lo & pbm->pbm_intmask.phys_lo; + irq = *interrupt & pbm->pbm_intmask.interrupt; + + for (i = 0; i < pbm->num_pbm_intmap; i++) { + if (pbm->pbm_intmap[i].phys_hi == hi && + pbm->pbm_intmap[i].phys_mid == mid && + pbm->pbm_intmap[i].phys_lo == lo && + pbm->pbm_intmap[i].interrupt == irq) { + *interrupt = pbm->pbm_intmap[i].cinterrupt; + return 1; + } + } + + prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ", + pdev->bus->number, pdev->devfn); + prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", + pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); + prom_printf("Please email this information to davem@redhat.com\n"); + prom_halt(); +} + +static void __init pdev_fixup_irq(struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct pci_controller_info *p = pbm->parent; + unsigned int portid = p->portid; + unsigned int prom_irq; + int prom_node = pcp->prom_node; + int err; + + err = prom_getproperty(prom_node, "interrupts", + (char *)&prom_irq, sizeof(prom_irq)); + if (err == 0 || err == -1) { + pdev->irq = 0; + return; + } + + /* Fully specified already? */ + if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { + pdev->irq = p->irq_build(p, pdev, prom_irq); + goto have_irq; + } + + /* An onboard device? (bit 5 set) */ + if ((prom_irq & PCI_IRQ_INO) & 0x20) { + pdev->irq = p->irq_build(p, pdev, (portid << 6 | prom_irq)); + goto have_irq; + } + + /* Can we find a matching entry in the interrupt-map? */ + if (pci_intmap_match(pdev, &prom_irq)) { + pdev->irq = p->irq_build(p, pdev, (portid << 6) | prom_irq); + goto have_irq; + } + + /* Ok, we have to do it the hard way. */ + { + unsigned int bus, slot, line; + + bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; + + /* If we have a legal interrupt property, use it as + * the IRQ line. + */ + if (prom_irq > 0 && prom_irq < 5) { + line = ((prom_irq - 1) & 3); + } else { + u8 pci_irq_line; + + /* Else just directly consult PCI config space. */ + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); + line = ((pci_irq_line - 1) & 3); + } + + /* Now figure out the slot. */ + if (pdev->bus->number == pbm->pci_first_busno) { + if (pbm == &pbm->parent->pbm_A) + slot = (pdev->devfn >> 3) - 1; + else + slot = (pdev->devfn >> 3) - 2; + } else { + if (pbm == &pbm->parent->pbm_A) + slot = (pdev->bus->self->devfn >> 3) - 1; + else + slot = (pdev->bus->self->devfn >> 3) - 2; + } + slot = slot << 2; + + pdev->irq = p->irq_build(p, pdev, + ((portid << 6) & PCI_IRQ_IGN) | + (bus | slot | line)); + } + +have_irq: + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, + pdev->irq & PCI_IRQ_INO); +} + +void __init pci_fixup_irq(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) + pdev_fixup_irq(pdev); + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_fixup_irq(pbm, pbus); +} + +/* Generic helper routines for PCI error reporting. */ +void pci_scan_for_target_abort(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + u16 status, error_bits; + + pci_read_config_word(pdev, PCI_STATUS, &status); + error_bits = + (status & (PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT)); + if (error_bits) { + pci_write_config_word(pdev, PCI_STATUS, error_bits); + printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n", + p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'), + pdev->name, status); + } + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_scan_for_target_abort(p, pbm, pbus); +} + +void pci_scan_for_master_abort(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + u16 status, error_bits; + + pci_read_config_word(pdev, PCI_STATUS, &status); + error_bits = + (status & (PCI_STATUS_REC_MASTER_ABORT)); + if (error_bits) { + pci_write_config_word(pdev, PCI_STATUS, error_bits); + printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n", + p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'), + pdev->name, status); + } + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_scan_for_master_abort(p, pbm, pbus); +} + +void pci_scan_for_parity_error(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + u16 status, error_bits; + + pci_read_config_word(pdev, PCI_STATUS, &status); + error_bits = + (status & (PCI_STATUS_PARITY | + PCI_STATUS_DETECTED_PARITY)); + if (error_bits) { + pci_write_config_word(pdev, PCI_STATUS, error_bits); + printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n", + p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'), + pdev->name, status); + } + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_scan_for_parity_error(p, pbm, pbus); +} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/pci_impl.h linux/arch/sparc64/kernel/pci_impl.h --- v2.3.15/linux/arch/sparc64/kernel/pci_impl.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/pci_impl.h Tue Aug 31 11:23:30 1999 @@ -0,0 +1,166 @@ +/* $Id: pci_impl.h,v 1.1 1999/08/30 10:00:44 davem Exp $ + * pci_impl.h: Helper definitions for PCI controller support. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#ifndef PCI_IMPL_H +#define PCI_IMPL_H + +#include +#include +#include + +extern spinlock_t pci_controller_lock; +extern struct pci_controller_info *pci_controller_root; + +extern struct pci_pbm_info *pci_bus2pbm[256]; +extern unsigned char pci_highest_busnum; +extern int pci_num_controllers; + +/* PCI bus scanning and fixup support. */ +extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus, + struct pci_pbm_info *pbm, + int prom_node); +extern void pci_record_assignments(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_fixup_irq(struct pci_pbm_info *pbm, + struct pci_bus *pbus); + +/* Error reporting support. */ +extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); +extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); +extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); + +/* IOMMU/DVMA initialization. */ +extern unsigned long pci_dvma_offset; +extern unsigned long pci_dvma_mask; +#define PCI_DVMA_HASH_NONE ~0UL +static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr) +{ + unsigned long dvma_addr = pci_dvma_offset + daddr; + unsigned long vaddr = (unsigned long)__va(paddr); + + pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr; + pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr; +} + +/* Configuration space access. */ +extern spinlock_t pci_poke_lock; +extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_faulted; + +static __inline__ void pci_config_read8(u8 *addr, u8 *ret) +{ + unsigned long flags; + u8 byte; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduba [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (byte) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + if (!pci_poke_faulted) + *ret = byte; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_read16(u16 *addr, u16 *ret) +{ + unsigned long flags; + u16 word; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduha [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (word) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + if (!pci_poke_faulted) + *ret = word; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_read32(u32 *addr, u32 *ret) +{ + unsigned long flags; + u32 dword; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduwa [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (dword) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + if (!pci_poke_faulted) + *ret = dword; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_write8(u8 *addr, u8 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stba %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_write16(u16 *addr, u16 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stha %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_write32(u32 *addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stwa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +#endif /* !(PCI_IMPL_H) */ diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c --- v2.3.15/linux/arch/sparc64/kernel/pci_iommu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/pci_iommu.c Tue Aug 31 11:23:30 1999 @@ -0,0 +1,510 @@ +/* $Id: pci_iommu.c,v 1.1 1999/08/30 10:00:47 davem Exp $ + * pci_iommu.c: UltraSparc PCI controller IOM/STC support. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include + +#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \ + ((STC)->strbuf_ctxmatch_base + ((CTX) << 3)) + +/* Accessing IOMMU and Streaming Buffer registers. + * REG parameter is a physical address. All registers + * are 64-bits in size. + */ +#define pci_iommu_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define pci_iommu_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* Find a range of iommu mappings of size NPAGES in page + * table PGT. Return pointer to first iopte. + */ +static iopte_t *iommu_find_range(unsigned long npages, iopte_t *pgt, int pgt_size) +{ + int i; + + pgt_size -= npages; + for (i = 0; i < pgt_size; i++) { + if (!iopte_val(pgt[i]) & IOPTE_VALID) { + int scan; + + for (scan = 1; scan < npages; scan++) { + if (iopte_val(pgt[i + scan]) & IOPTE_VALID) { + i += scan; + goto do_next; + } + } + return &pgt[i]; + } + do_next: + } + return NULL; +} + +#define IOPTE_CONSISTANT(CTX, PADDR) \ + (IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | \ + (((CTX) << 47) & IOPTE_CONTEXT) | \ + ((PADDR) & IOPTE_PAGE)) + +#define IOPTE_STREAMING(CTX, PADDR) \ + (IOPTE_CONSISTANT(CTX, PADDR) | IOPTE_STBUF) + +#define IOPTE_INVALID 0UL + +/* Map kernel buffer at ADDR of size SZ using consistant mode + * DMA for PCI device PDEV. Return 32-bit PCI DMA address. + */ +u32 pci_map_consistant(struct pci_dev *pdev, void *addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + iopte_t *base; + unsigned long flags, npages, oaddr; + u32 ret; + + spin_lock_irqsave(&iommu->lock, flags); + oaddr = (unsigned long)addr; + npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu_find_range(npages, + iommu->page_table, iommu->page_table_sz); + ret = 0; + if (base != NULL) { + unsigned long i, base_paddr, ctx; + + ret = (iommu->page_table_map_base + + ((base - iommu->page_table) << PAGE_SHIFT)); + ret |= (oaddr & ~PAGE_MASK); + base_paddr = __pa(oaddr & PAGE_MASK); + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = iommu->iommu_cur_ctx++; + for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr); + } + spin_unlock_irqrestore(&iommu->lock, flags); + + return ret; +} + +/* Unmap a consistant DMA translation. */ +void pci_unmap_consistant(struct pci_dev *pdev, u32 bus_addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + iopte_t *base; + unsigned long flags, npages, i, ctx; + + spin_lock_irqsave(&iommu->lock, flags); + npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT); + + /* Data for consistant mappings cannot enter the streaming + * buffers, so we only need to update the TSB and flush + * those entries from the IOMMU's TLB. + */ + + /* Step 1: Clear out the TSB entries. Save away + * the context if necessary. + */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + for (i = 0; i < npages; i++, base++) + iopte_val(*base) = IOPTE_INVALID; + + /* Step 2: Flush from IOMMU TLB. */ + if (iommu->iommu_has_ctx_flush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + bus_addr &= PAGE_MASK; + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, bus_addr); + } + + /* Step 3: Ensure completion of previous PIO writes. */ + (void) pci_iommu_read(iommu->write_complete_reg); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Map a single buffer at PTR of SZ bytes for PCI DMA + * in streaming mode. + */ +u32 pci_map_single(struct pci_dev *pdev, void *ptr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + iopte_t *base; + unsigned long flags, npages, oaddr; + u32 ret; + + spin_lock_irqsave(&iommu->lock, flags); + oaddr = (unsigned long)ptr; + npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu_find_range(npages, + iommu->page_table, iommu->page_table_sz); + ret = 0; + if (base != NULL) { + unsigned long i, base_paddr, ctx; + + ret = (iommu->page_table_map_base + + ((base - iommu->page_table) << PAGE_SHIFT)); + ret |= (oaddr & ~PAGE_MASK); + base_paddr = __pa(oaddr & PAGE_MASK); + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = iommu->iommu_cur_ctx++; + for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); + } + spin_unlock_irqrestore(&iommu->lock, flags); + + return ret; +} + +/* Unmap a single streaming mode DMA translation. */ +void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + iopte_t *base; + unsigned long flags, npages, i, ctx; + + spin_lock_irqsave(&iommu->lock, flags); + npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT); + bus_addr &= PAGE_MASK; + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + + /* Step 2: Kick data out of streaming buffers if necessary. */ + if (strbuf->strbuf_enabled) { + u32 vaddr = bus_addr; + + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (strbuf->strbuf_has_ctx_flush && + iommu->iommu_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while(((long)pci_iommu_read(matchreg)) < 0L); + } else { + for (i = 0; i < npages; i++, vaddr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, vaddr); + } + + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + } + + /* Step 3: Clear out TSB entries. */ + for (i = 0; i < npages; i++, base++) + iopte_val(*base) = IOPTE_INVALID; + + /* Step 4: Flush the IOMMU TLB. */ + if (iommu->iommu_has_ctx_flush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, bus_addr); + } + + /* Step 5: Ensure completion of previous PIO writes. */ + (void) pci_iommu_read(iommu->write_complete_reg); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Map a set of buffers described by SGLIST with NELEMS array + * elements in streaming mode for PCI DMA. + */ +void pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + unsigned long flags, ctx, i; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Step 1: Choose a context if necessary. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = iommu->iommu_cur_ctx++; + + /* Step 2: Create the mappings. */ + for (i = 0; i < nelems; i++) { + unsigned long oaddr, npages; + iopte_t *base; + + oaddr = (unsigned long)sglist[i].address; + npages = PAGE_ALIGN(oaddr + sglist[i].length) - (oaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu_find_range(npages, + iommu->page_table, iommu->page_table_sz); + if (base != NULL) { + unsigned long j, base_paddr; + u32 dvma_addr; + + dvma_addr = (iommu->page_table_map_base + + ((base - iommu->page_table) << PAGE_SHIFT)); + dvma_addr |= (oaddr & ~PAGE_MASK); + sglist[i].dvma_address = dvma_addr; + sglist[i].dvma_length = sglist[i].length; + base_paddr = __pa(oaddr & PAGE_MASK); + for (j = 0; j < npages; j++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); + } else { + sglist[i].dvma_address = 0; + sglist[i].dvma_length = 0; + } + } + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Unmap a set of streaming mode DMA translations. */ +void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + unsigned long flags, ctx, i; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers if necessary. */ + if (strbuf->strbuf_enabled) { + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (strbuf->strbuf_has_ctx_flush && + iommu->iommu_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while(((long)pci_iommu_read(matchreg)) < 0L); + } else { + for (i = 0; i < nelems; i++) { + unsigned long j, npages; + u32 vaddr; + + j = sglist[i].dvma_length; + if (!j) + break; + vaddr = sglist[i].dvma_address; + npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + vaddr &= PAGE_MASK; + for (j = 0; j < npages; j++, vaddr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, vaddr); + } + + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + } + } + + /* Step 3: Clear out TSB entries. */ + for (i = 0; i < nelems; i++) { + unsigned long j, npages; + iopte_t *base; + u32 vaddr; + + j = sglist[i].dvma_length; + if (!j) + break; + vaddr = sglist[i].dvma_address; + npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu->page_table + + ((vaddr - iommu->page_table_map_base) >> PAGE_SHIFT); + for (j = 0; j < npages; j++, base++) + iopte_val(*base) = IOPTE_INVALID; + } + + /* Step 4: Flush the IOMMU TLB. */ + if (iommu->iommu_has_ctx_flush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + for (i = 0; i < nelems; i++) { + unsigned long j, npages; + u32 vaddr; + + j = sglist[i].dvma_length; + if (!j) + break; + vaddr = sglist[i].dvma_address; + npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + for (j = 0; j < npages; j++, vaddr += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, vaddr); + } + } + + /* Step 5: Ensure completion of previous PIO writes. */ + (void) pci_iommu_read(iommu->write_complete_reg); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Make physical memory consistant for a single + * streaming mode DMA translation after a transfer. + */ +void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + unsigned long flags, ctx, npages; + + if (!strbuf->strbuf_enabled) + return; + + spin_lock_irqsave(&iommu->lock, flags); + + npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + bus_addr &= PAGE_MASK; + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((bus_addr - iommu->page_table_map_base)>>PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers. */ + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while(((long)pci_iommu_read(matchreg)) < 0L); + } else { + unsigned long i; + + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, bus_addr); + } + + /* Step 3: Perform flush synchronization sequence. */ + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Make physical memory consistant for a set of streaming + * mode DMA translations after a transfer. + */ +void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + unsigned long flags, ctx; + + if (!strbuf->strbuf_enabled) + return; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers. */ + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while (((long)pci_iommu_read(matchreg)) < 0L); + } else { + unsigned long i; + + for(i = 0; i < nelems; i++) { + unsigned long bus_addr, npages, j; + + j = sglist[i].dvma_length; + if (!j) + break; + bus_addr = sglist[i].dvma_address; + npages = PAGE_ALIGN(bus_addr + j) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + bus_addr &= PAGE_MASK; + for(j = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, bus_addr); + } + } + + /* Step 3: Perform flush synchronization sequence. */ + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + + spin_unlock_irqrestore(&iommu->lock, flags); +} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.3.15/linux/arch/sparc64/kernel/pci_psycho.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/pci_psycho.c Tue Aug 31 11:23:30 1999 @@ -0,0 +1,1604 @@ +/* $Id: pci_psycho.c,v 1.2 1999/08/31 09:12:34 davem Exp $ + * pci_psycho.c: PSYCHO/U2P specific PCI controller support. + * + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pci_impl.h" + +/* All PSYCHO registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define psycho_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define psycho_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* Misc. PSYCHO PCI controller register offsets and definitions. */ +#define PSYCHO_CONTROL 0x0010UL +#define PSYCHO_CONTROL_IMPL 0xf000000000000000 /* Implementation of this PSYCHO*/ +#define PSYCHO_CONTROL_VER 0x0f00000000000000 /* Version of this PSYCHO */ +#define PSYCHO_CONTROL_MID 0x00f8000000000000 /* UPA Module ID of PSYCHO */ +#define PSYCHO_CONTROL_IGN 0x0007c00000000000 /* Interrupt Group Number */ +#define PSYCHO_CONTROL_RESV 0x00003ffffffffff0 /* Reserved */ +#define PSYCHO_CONTROL_APCKEN 0x0000000000000008 /* Address Parity Check Enable */ +#define PSYCHO_CONTROL_APERR 0x0000000000000004 /* Incoming System Addr Parerr */ +#define PSYCHO_CONTROL_IAP 0x0000000000000002 /* Invert UPA Parity */ +#define PSYCHO_CONTROL_MODE 0x0000000000000001 /* PSYCHO clock mode */ +#define PSYCHO_PCIA_CTRL 0x2000UL +#define PSYCHO_PCIB_CTRL 0x4000UL +#define PSYCHO_PCICTRL_RESV1 0xfffffff000000000 /* Reserved */ +#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000 /* Streaming byte hole error */ +#define PSYCHO_PCICTRL_SERR 0x0000000400000000 /* SERR signal asserted */ +#define PSYCHO_PCICTRL_SPEED 0x0000000200000000 /* PCI speed (1 is U2P clock) */ +#define PSYCHO_PCICTRL_RESV2 0x00000001ffc00000 /* Reserved */ +#define PSYCHO_PCICTRL_ARB_PARK 0x0000000000200000 /* PCI arbitration parking */ +#define PSYCHO_PCICTRL_RESV3 0x00000000001ff800 /* Reserved */ +#define PSYCHO_PCICTRL_SBH_INT 0x0000000000000400 /* Streaming byte hole int enab */ +#define PSYCHO_PCICTRL_WEN 0x0000000000000200 /* Power Mgmt Wake Enable */ +#define PSYCHO_PCICTRL_EEN 0x0000000000000100 /* PCI Error Interrupt Enable */ +#define PSYCHO_PCICTRL_RESV4 0x00000000000000c0 /* Reserved */ +#define PSYCHO_PCICTRL_AEN 0x000000000000003f /* PCI DVMA Arbitration Enable */ + +/* U2P Programmer's Manual, page 13-55, configuration space + * address format: + * + * 32 24 23 16 15 11 10 8 7 2 1 0 + * --------------------------------------------------------- + * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | + * --------------------------------------------------------- + */ +#define PSYCHO_CONFIG_BASE(PBM) \ + ((PBM)->parent->config_space | (1UL << 24)) +#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned int devfn, + int where) +{ + if (!pbm) + return NULL; + return (void *) + (PSYCHO_CONFIG_BASE(pbm) | + PSYCHO_CONFIG_ENCODE(bus, devfn, where)); +} + +static int psycho_out_of_range(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned char devfn) +{ + return ((pbm->parent == 0) || + ((pbm == &pbm->parent->pbm_B) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8) || + ((pbm == &pbm->parent->pbm_A) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8)); +} + +/* PSYCHO PCI configuration space accessors. */ + +static int psycho_read_byte(struct pci_dev *dev, int where, u8 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + *value = 0xff; + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + pci_config_read8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_read_word(struct pci_dev *dev, int where, u16 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + *value = 0xffff; + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_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_config_read16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_read_dword(struct pci_dev *dev, int where, u32 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + *value = 0xffffffff; + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_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_config_read32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_write_byte(struct pci_dev *dev, int where, u8 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + pci_config_write8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_write_word(struct pci_dev *dev, int where, u16 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_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_config_write16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_write_dword(struct pci_dev *dev, int where, u32 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_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_config_write32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops psycho_ops = { + psycho_read_byte, + psycho_read_word, + psycho_read_dword, + psycho_write_byte, + psycho_write_word, + psycho_write_dword +}; + +/* PSYCHO interrupt mapping support. */ +#define PSYCHO_IMAP_A_SLOT0 0x0c00UL +#define PSYCHO_IMAP_B_SLOT0 0x0c20UL +static unsigned long psycho_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return PSYCHO_IMAP_A_SLOT0 + (slot * 8); + else + return PSYCHO_IMAP_B_SLOT0 + (slot * 8); +} + +#define PSYCHO_IMAP_SCSI 0x1000UL +#define PSYCHO_IMAP_ETH 0x1008UL +#define PSYCHO_IMAP_BPP 0x1010UL +#define PSYCHO_IMAP_AU_REC 0x1018UL +#define PSYCHO_IMAP_AU_PLAY 0x1020UL +#define PSYCHO_IMAP_PFAIL 0x1028UL +#define PSYCHO_IMAP_KMS 0x1030UL +#define PSYCHO_IMAP_FLPY 0x1038UL +#define PSYCHO_IMAP_SHW 0x1040UL +#define PSYCHO_IMAP_KBD 0x1048UL +#define PSYCHO_IMAP_MS 0x1050UL +#define PSYCHO_IMAP_SER 0x1058UL +#define PSYCHO_IMAP_TIM0 0x1060UL +#define PSYCHO_IMAP_TIM1 0x1068UL +#define PSYCHO_IMAP_UE 0x1070UL +#define PSYCHO_IMAP_CE 0x1078UL +#define PSYCHO_IMAP_A_ERR 0x1080UL +#define PSYCHO_IMAP_B_ERR 0x1088UL +#define PSYCHO_IMAP_PMGMT 0x1090UL +#define PSYCHO_IMAP_GFX 0x1098UL +#define PSYCHO_IMAP_EUPA 0x10a0UL + +static unsigned long __onboard_imap_off[] = { +/*0x20*/ PSYCHO_IMAP_SCSI, +/*0x21*/ PSYCHO_IMAP_ETH, +/*0x22*/ PSYCHO_IMAP_BPP, +/*0x23*/ PSYCHO_IMAP_AU_REC, +/*0x24*/ PSYCHO_IMAP_AU_PLAY, +/*0x25*/ PSYCHO_IMAP_PFAIL, +/*0x26*/ PSYCHO_IMAP_KMS, +/*0x27*/ PSYCHO_IMAP_FLPY, +/*0x28*/ PSYCHO_IMAP_SHW, +/*0x29*/ PSYCHO_IMAP_KBD, +/*0x2a*/ PSYCHO_IMAP_MS, +/*0x2b*/ PSYCHO_IMAP_SER, +/*0x2c*/ PSYCHO_IMAP_TIM0, +/*0x2d*/ PSYCHO_IMAP_TIM1, +/*0x2e*/ PSYCHO_IMAP_UE, +/*0x2f*/ PSYCHO_IMAP_CE, +/*0x30*/ PSYCHO_IMAP_A_ERR, +/*0x31*/ PSYCHO_IMAP_B_ERR, +/*0x32*/ PSYCHO_IMAP_PMGMT +}; +#define PSYCHO_ONBOARD_IRQ_BASE 0x20 +#define PSYCHO_ONBOARD_IRQ_LAST 0x32 +#define psycho_onboard_imap_offset(__ino) \ + __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] + +#define PSYCHO_ICLR_A_SLOT0 0x1400UL +#define PSYCHO_ICLR_SCSI 0x1800UL + +#define psycho_iclr_offset(ino) \ + ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +/* PCI PSYCHO INO number to Sparc PIL level. */ +static unsigned char psycho_pil_table[] = { +/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ +/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ +/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ +/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ +/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ +/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ +/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ +/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ +/*0x20*/3, /* SCSI */ +/*0x21*/5, /* Ethernet */ +/*0x22*/8, /* Parallel Port */ +/*0x23*/13, /* Audio Record */ +/*0x24*/14, /* Audio Playback */ +/*0x25*/15, /* PowerFail */ +/*0x26*/3, /* second SCSI */ +/*0x27*/11, /* Floppy */ +/*0x28*/2, /* Spare Hardware */ +/*0x29*/9, /* Keyboard */ +/*0x2a*/4, /* Mouse */ +/*0x2b*/12, /* Serial */ +/*0x2c*/10, /* Timer 0 */ +/*0x2d*/11, /* Timer 1 */ +/*0x2e*/15, /* Uncorrectable ECC */ +/*0x2f*/15, /* Correctable ECC */ +/*0x30*/15, /* PCI Bus A Error */ +/*0x31*/15, /* PCI Bus B Error */ +/*0x32*/1, /* Power Management */ +}; + +static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) +{ + int ret; + + ret = psycho_pil_table[ino]; + if (ret == 0 && pdev == NULL) { + ret = 1; + } else if (ret == 0) { + switch ((pdev->class >> 16) & 0x0f) { + case PCI_BASE_CLASS_STORAGE: + ret = 4; + + case PCI_BASE_CLASS_NETWORK: + ret = 6; + + case PCI_BASE_CLASS_DISPLAY: + ret = 9; + + case PCI_BASE_CLASS_MULTIMEDIA: + case PCI_BASE_CLASS_MEMORY: + case PCI_BASE_CLASS_BRIDGE: + ret = 10; + + default: + ret = 1; + }; + } + + return ret; +} + +static unsigned int __init psycho_irq_build(struct pci_controller_info *p, + struct pci_dev *pdev, + unsigned int ino) +{ + struct ino_bucket *bucket; + volatile unsigned int *imap, *iclr; + unsigned long imap_off, iclr_off; + int pil, inofixup = 0; + + ino &= PCI_IRQ_INO; + if (ino < PSYCHO_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = psycho_pcislot_imap_offset(ino); + } else { + /* Onboard device */ + if (ino > PSYCHO_ONBOARD_IRQ_LAST) { + prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = psycho_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + pil = psycho_ino_to_pil(pdev, ino); + imap = (volatile unsigned int *)__va(p->controller_regs + imap_off); + imap += 1; + + iclr_off = psycho_iclr_offset(ino); + iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off); + iclr += 1; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket->flags |= IBF_PCI; + + return __irq(bucket); +} + +/* PSYCHO error handling support. */ +enum psycho_error_type { + UE_ERR, CE_ERR, PCI_ERR +}; + +/* Helper function of IOMMU error checking, which checks out + * the state of the streaming buffers. The IOMMU lock is + * held when this is called. + * + * For the PCI error case we know which PBM (and thus which + * streaming buffer) caused the error, but for the uncorrectable + * error case we do not. So we always check both streaming caches. + */ +#define PSYCHO_STRBUF_CONTROL_A 0x2800UL +#define PSYCHO_STRBUF_CONTROL_B 0x4800UL +#define PSYCHO_STRBUF_CTRL_LPTR 0x00000000000000f0 /* LRU Lock Pointer */ +#define PSYCHO_STRBUF_CTRL_LENAB 0x0000000000000008 /* LRU Lock Enable */ +#define PSYCHO_STRBUF_CTRL_RRDIS 0x0000000000000004 /* Rerun Disable */ +#define PSYCHO_STRBUF_CTRL_DENAB 0x0000000000000002 /* Diagnostic Mode Enable */ +#define PSYCHO_STRBUF_CTRL_ENAB 0x0000000000000001 /* Streaming Buffer Enable */ +#define PSYCHO_STRBUF_FLUSH_A 0x2808UL +#define PSYCHO_STRBUF_FLUSH_B 0x4808UL +#define PSYCHO_STRBUF_FSYNC_A 0x2810UL +#define PSYCHO_STRBUF_FSYNC_B 0x4810UL +#define PSYCHO_STC_DATA_A 0xb000UL +#define PSYCHO_STC_DATA_B 0xc000UL +#define PSYCHO_STC_ERR_A 0xb400UL +#define PSYCHO_STC_ERR_B 0xc400UL +#define PSYCHO_STCERR_WRITE 0x0000000000000002 /* Write Error */ +#define PSYCHO_STCERR_READ 0x0000000000000001 /* Read Error */ +#define PSYCHO_STC_TAG_A 0xb800UL +#define PSYCHO_STC_TAG_B 0xc800UL +#define PSYCHO_STCTAG_PPN 0x0fffffff00000000 /* Physical Page Number */ +#define PSYCHO_STCTAG_VPN 0x00000000ffffe000 /* Virtual Page Number */ +#define PSYCHO_STCTAG_VALID 0x0000000000000002 /* Valid */ +#define PSYCHO_STCTAG_WRITE 0x0000000000000001 /* Writable */ +#define PSYCHO_STC_LINE_A 0xb900UL +#define PSYCHO_STC_LINE_B 0xc900UL +#define PSYCHO_STCLINE_LINDX 0x0000000001e00000 /* LRU Index */ +#define PSYCHO_STCLINE_SPTR 0x00000000001f8000 /* Dirty Data Start Pointer */ +#define PSYCHO_STCLINE_LADDR 0x0000000000007f00 /* Line Address */ +#define PSYCHO_STCLINE_EPTR 0x00000000000000fc /* Dirty Data End Pointer */ +#define PSYCHO_STCLINE_VALID 0x0000000000000002 /* Valid */ +#define PSYCHO_STCLINE_FOFN 0x0000000000000001 /* Fetch Outstanding / Flush Necessary */ + +static spinlock_t stc_buf_lock = SPIN_LOCK_UNLOCKED; +static unsigned long stc_error_buf[128]; +static unsigned long stc_tag_buf[16]; +static unsigned long stc_line_buf[16]; + +static void __psycho_check_one_stc(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + int is_pbm_a) +{ + struct pci_strbuf *strbuf = &pbm->stc; + unsigned long regbase = p->controller_regs; + unsigned long err_base, tag_base, line_base; + u64 control; + int i; + + if (is_pbm_a) { + err_base = regbase + PSYCHO_STC_ERR_A; + tag_base = regbase + PSYCHO_STC_TAG_A; + line_base = regbase + PSYCHO_STC_LINE_A; + } else { + err_base = regbase + PSYCHO_STC_ERR_A; + tag_base = regbase + PSYCHO_STC_TAG_A; + line_base = regbase + PSYCHO_STC_LINE_A; + } + + spin_lock(&stc_buf_lock); + + /* This is __REALLY__ dangerous. When we put the + * streaming buffer into diagnostic mode to probe + * it's tags and error status, we _must_ clear all + * of the line tag valid bits before re-enabling + * the streaming buffer. If any dirty data lives + * in the STC when we do this, we will end up + * invalidating it before it has a chance to reach + * main memory. + */ + control = psycho_read(strbuf->strbuf_control); + psycho_write(strbuf->strbuf_control, + (control | PSYCHO_STRBUF_CTRL_DENAB)); + for (i = 0; i < 128; i++) { + unsigned long val; + + val = psycho_read(err_base + (i * 8UL)); + psycho_write(err_base + (i * 8UL), 0UL); + stc_error_buf[i] = val; + } + for (i = 0; i < 16; i++) { + stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL)); + stc_line_buf[i] = psycho_read(line_base + (i * 8UL)); + psycho_write(tag_base + (i * 8UL), 0UL); + psycho_write(line_base + (i * 8UL), 0UL); + } + + /* OK, state is logged, exit diagnostic mode. */ + psycho_write(strbuf->strbuf_control, control); + + for (i = 0; i < 16; i++) { + int j, saw_error, first, last; + + saw_error = 0; + first = i * 8; + last = first + 8; + for (j = first; j < last; j++) { + unsigned long errval = stc_error_buf[j]; + if (errval != 0) { + saw_error++; + printk("PSYCHO%d(PBM%c): STC_ERR(%d)[wr(%d)rd(%d)]\n", + p->index, + (is_pbm_a ? 'A' : 'B'), + j, + (errval & PSYCHO_STCERR_WRITE) ? 1 : 0, + (errval & PSYCHO_STCERR_READ) ? 1 : 0); + } + } + if (saw_error != 0) { + unsigned long tagval = stc_tag_buf[i]; + unsigned long lineval = stc_line_buf[i]; + printk("PSYCHO%d(PBM%c): STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n", + p->index, + (is_pbm_a ? 'A' : 'B'), + i, + ((tagval & PSYCHO_STCTAG_PPN) >> 19UL), + (tagval & PSYCHO_STCTAG_VPN), + ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0), + ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0)); + printk("PSYCHO%d(PBM%c): STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" + "V(%d)FOFN(%d)]\n", + p->index, + (is_pbm_a ? 'A' : 'B'), + i, + ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL), + ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL), + ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL), + ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL), + ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0), + ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0)); + } + } + + spin_unlock(&stc_buf_lock); +} + +static void __psycho_check_stc_error(struct pci_controller_info *p, + unsigned long afsr, + unsigned long afar, + enum psycho_error_type type) +{ + struct pci_pbm_info *pbm; + + pbm = &p->pbm_A; + if (pbm->stc.strbuf_enabled) + __psycho_check_one_stc(p, pbm, 1); + + pbm = &p->pbm_B; + if (pbm->stc.strbuf_enabled) + __psycho_check_one_stc(p, pbm, 0); +} + +/* When an Uncorrectable Error or a PCI Error happens, we + * interrogate the IOMMU state to see if it is the cause. + */ +#define PSYCHO_IOMMU_CONTROL 0x0200UL +#define PSYCHO_IOMMU_CTRL_RESV 0xfffffffff9000000 /* Reserved */ +#define PSYCHO_IOMMU_CTRL_XLTESTAT 0x0000000006000000 /* Translation Error Status */ +#define PSYCHO_IOMMU_CTRL_XLTEERR 0x0000000001000000 /* Translation Error encountered */ +#define PSYCHO_IOMMU_CTRL_LCKEN 0x0000000000800000 /* Enable translation locking */ +#define PSYCHO_IOMMU_CTRL_LCKPTR 0x0000000000780000 /* Translation lock pointer */ +#define PSYCHO_IOMMU_CTRL_TSBSZ 0x0000000000070000 /* TSB Size */ +#define PSYCHO_IOMMU_TSBSZ_1K 0x0000000000000000 /* TSB Table 1024 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_2K 0x0000000000010000 /* TSB Table 2048 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_4K 0x0000000000020000 /* TSB Table 4096 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_8K 0x0000000000030000 /* TSB Table 8192 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_16K 0x0000000000040000 /* TSB Table 16k 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_32K 0x0000000000050000 /* TSB Table 32k 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_64K 0x0000000000060000 /* TSB Table 64k 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_128K 0x0000000000070000 /* TSB Table 128k 8-byte entries */ +#define PSYCHO_IOMMU_CTRL_RESV2 0x000000000000fff8 /* Reserved */ +#define PSYCHO_IOMMU_CTRL_TBWSZ 0x0000000000000004 /* Assumed page size, 0=8k 1=64k */ +#define PSYCHO_IOMMU_CTRL_DENAB 0x0000000000000002 /* Diagnostic mode enable */ +#define PSYCHO_IOMMU_CTRL_ENAB 0x0000000000000001 /* IOMMU Enable */ +#define PSYCHO_IOMMU_TSBBASE 0x0208UL +#define PSYCHO_IOMMU_FLUSH 0x0210UL +#define PSYCHO_IOMMU_TAG 0xa580UL +#define PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL) +#define PSYCHO_IOMMU_TAG_ERR (0x1UL << 22UL) +#define PSYCHO_IOMMU_TAG_WRITE (0x1UL << 21UL) +#define PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL) +#define PSYCHO_IOMMU_TAG_SIZE (0x1UL << 19UL) +#define PSYCHO_IOMMU_TAG_VPAGE 0x7ffffUL +#define PSYCHO_IOMMU_DATA 0xa600UL +#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL) +#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL) +#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL +static void psycho_check_iommu_error(struct pci_controller_info *p, + unsigned long afsr, + unsigned long afar, + enum psycho_error_type type) +{ + unsigned long iommu_tag[16]; + unsigned long iommu_data[16]; + unsigned long flags; + u64 control; + int i; + + spin_lock_irqsave(&p->iommu.lock, flags); + control = psycho_read(p->iommu.iommu_control); + if (control & PSYCHO_IOMMU_CTRL_XLTEERR) { + char *type_string; + + /* Clear the error encountered bit. */ + control &= ~PSYCHO_IOMMU_CTRL_XLTEERR; + psycho_write(p->iommu.iommu_control, control); + + switch((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("PSYCHO%d: IOMMU Error, type[%s]\n", + p->index, type_string); + + /* Put the IOMMU into diagnostic mode and probe + * it's TLB for entries with error status. + * + * It is very possible for another DVMA to occur + * while we do this probe, and corrupt the system + * further. But we are so screwed at this point + * that we are likely to crash hard anyways, so + * get as much diagnostic information to the + * console as we can. + */ + psycho_write(p->iommu.iommu_control, + control | PSYCHO_IOMMU_CTRL_DENAB); + for (i = 0; i < 16; i++) { + unsigned long base = p->controller_regs; + + iommu_tag[i] = + psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL)); + iommu_data[i] = + psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL)); + + /* Now clear out the entry. */ + psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0); + psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0); + } + + /* Leave diagnostic mode. */ + psycho_write(p->iommu.iommu_control, control); + + for (i = 0; i < 16; i++) { + unsigned long tag, data; + + tag = iommu_tag[i]; + if (!(tag & PSYCHO_IOMMU_TAG_ERR)) + continue; + + data = iommu_data[i]; + switch((tag & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("PSYCHO%d: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n", + p->index, i, type_string, + ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0), + ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0), + ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8), + (tag & PSYCHO_IOMMU_TAG_VPAGE) << PAGE_SHIFT); + printk("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", + p->index, i, + ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0), + ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0), + (data & PSYCHO_IOMMU_DATA_PPAGE) << PAGE_SHIFT); + } + } + __psycho_check_stc_error(p, afsr, afar, type); + spin_unlock_irqrestore(&p->iommu.lock, flags); +} + +/* Uncorrectable Errors. Cause of the error and the address are + * recorded in the UE_AFSR and UE_AFAR of PSYCHO. They are errors + * relating to UPA interface transactions. + */ +#define PSYCHO_UE_AFSR 0x0030UL +#define PSYCHO_UEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define PSYCHO_UEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define PSYCHO_UEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define PSYCHO_UEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define PSYCHO_UEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define PSYCHO_UEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define PSYCHO_UEAFSR_RESV1 0x03ff000000000000 /* Reserved */ +#define PSYCHO_UEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */ +#define PSYCHO_UEAFSR_DOFF 0x00000000e0000000 /* Doubleword Offset */ +#define PSYCHO_UEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */ +#define PSYCHO_UEAFSR_BLK 0x0000000000800000 /* Trans was block operation */ +#define PSYCHO_UEAFSR_RESV2 0x00000000007fffff /* Reserved */ +#define PSYCHO_UE_AFAR 0x0038UL + +static void psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + PSYCHO_UE_AFSR; + unsigned long afar_reg = p->controller_regs + PSYCHO_UE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch uncorrectable error status. */ + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); + + /* Clear the primary/secondary error status bits. */ + error_bits = afsr & + (PSYCHO_UEAFSR_PPIO | PSYCHO_UEAFSR_PDRD | PSYCHO_UEAFSR_PDWR | + PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR); + psycho_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("PSYCHO%d: Uncorrectable Error, primary error type[%s]\n", + p->index, + (((error_bits & PSYCHO_UEAFSR_PPIO) ? + "PIO" : + ((error_bits & PSYCHO_UEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & PSYCHO_UEAFSR_PDWR) ? + "DMA Write" : "???"))))); + printk("PSYCHO%d: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n", + p->index, + (afsr & PSYCHO_UEAFSR_BMSK) >> 32UL, + (afsr & PSYCHO_UEAFSR_DOFF) >> 29UL, + (afsr & PSYCHO_UEAFSR_MID) >> 24UL, + ((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0)); + printk("PSYCHO%d: UE AFAR [%016lx]\n", p->index, afar); + printk("PSYCHO%d: UE Secondary errors [", p->index); + reported = 0; + if (afsr & PSYCHO_UEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & PSYCHO_UEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & PSYCHO_UEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* Interrogate IOMMU for error status. */ + psycho_check_iommu_error(p, afsr, afar, UE_ERR); +} + +/* Correctable Errors. */ +#define PSYCHO_CE_AFSR 0x0040UL +#define PSYCHO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define PSYCHO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define PSYCHO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define PSYCHO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define PSYCHO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define PSYCHO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define PSYCHO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */ +#define PSYCHO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */ +#define PSYCHO_CEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */ +#define PSYCHO_CEAFSR_DOFF 0x00000000e0000000 /* Double Offset */ +#define PSYCHO_CEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */ +#define PSYCHO_CEAFSR_BLK 0x0000000000800000 /* Trans was block operation */ +#define PSYCHO_CEAFSR_RESV2 0x00000000007fffff /* Reserved */ +#define PSYCHO_CE_AFAR 0x0040UL + +static void psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + PSYCHO_CE_AFSR; + unsigned long afar_reg = p->controller_regs + PSYCHO_CE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch error status. */ + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (PSYCHO_CEAFSR_PPIO | PSYCHO_CEAFSR_PDRD | PSYCHO_CEAFSR_PDWR | + PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR); + psycho_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("PSYCHO%d: Correctable Error, primary error type[%s]\n", + p->index, + (((error_bits & PSYCHO_CEAFSR_PPIO) ? + "PIO" : + ((error_bits & PSYCHO_CEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & PSYCHO_CEAFSR_PDWR) ? + "DMA Write" : "???"))))); + printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " + "UPA_MID[%02lx] was_block(%d)\n", + p->index, + (afsr & PSYCHO_CEAFSR_ESYND) >> 48UL, + (afsr & PSYCHO_CEAFSR_BMSK) >> 32UL, + (afsr & PSYCHO_CEAFSR_DOFF) >> 29UL, + (afsr & PSYCHO_CEAFSR_MID) >> 24UL, + ((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0)); + printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar); + printk("PSYCHO%d: CE Secondary errors [", p->index); + reported = 0; + if (afsr & PSYCHO_CEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & PSYCHO_CEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & PSYCHO_CEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); +} + +/* PCI Errors. They are signalled by the PCI bus module since they + * are assosciated with a specific bus segment. + */ +#define PSYCHO_PCI_AFSR_A 0x2010UL +#define PSYCHO_PCI_AFSR_B 0x4010UL +#define PSYCHO_PCIAFSR_PMA 0x8000000000000000 /* Primary Master Abort Error */ +#define PSYCHO_PCIAFSR_PTA 0x4000000000000000 /* Primary Target Abort Error */ +#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000 /* Primary Excessive Retries */ +#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000 /* Primary Parity Error */ +#define PSYCHO_PCIAFSR_SMA 0x0800000000000000 /* Secondary Master Abort Error */ +#define PSYCHO_PCIAFSR_STA 0x0400000000000000 /* Secondary Target Abort Error */ +#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000 /* Secondary Excessive Retries */ +#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000 /* Secondary Parity Error */ +#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000 /* Reserved */ +#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */ +#define PSYCHO_PCIAFSR_BLK 0x0000000080000000 /* Trans was block operation */ +#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000 /* Reserved */ +#define PSYCHO_PCIAFSR_MID 0x000000003e000000 /* MID causing the error */ +#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffff /* Reserved */ +#define PSYCHO_PCI_AFAR_A 0x2018UL +#define PSYCHO_PCI_AFAR_B 0x4018UL + +static void psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int is_pbm_a, reported; + + is_pbm_a = (pbm == &pbm->parent->pbm_A); + if (is_pbm_a) { + afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_A; + afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_A; + } else { + afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_B; + afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_B; + } + + /* Latch error status. */ + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA | + PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR | + PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA | + PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR); + psycho_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n", + p->index, (is_pbm_a ? 'A' : 'B'), + (((error_bits & PSYCHO_PCIAFSR_PMA) ? + "Master Abort" : + ((error_bits & PSYCHO_PCIAFSR_PTA) ? + "Target Abort" : + ((error_bits & PSYCHO_PCIAFSR_PRTRY) ? + "Excessive Retries" : + ((error_bits & PSYCHO_PCIAFSR_PPERR) ? + "Parity Error" : "???")))))); + printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n", + p->index, (is_pbm_a ? 'A' : 'B'), + (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL, + (afsr & PSYCHO_PCIAFSR_MID) >> 25UL, + (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0); + printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n", + p->index, (is_pbm_a ? 'A' : 'B'), afar); + printk("PSYCHO%d(PBM%c): PCI Secondary errors [", + p->index, (is_pbm_a ? 'A' : 'B')); + reported = 0; + if (afsr & PSYCHO_PCIAFSR_SMA) { + reported++; + printk("(Master Abort)"); + } + if (afsr & PSYCHO_PCIAFSR_STA) { + reported++; + printk("(Target Abort)"); + } + if (afsr & PSYCHO_PCIAFSR_SRTRY) { + reported++; + printk("(Excessive Retries)"); + } + if (afsr & PSYCHO_PCIAFSR_SPERR) { + reported++; + printk("(Parity Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* For the error types shown, scan PBM's PCI bus for devices + * which have logged that error type. + */ + + /* If we see a Target Abort, this could be the result of an + * IOMMU translation error of some sort. It is extremely + * useful to log this information as usually it indicates + * a bug in the IOMMU support code or a PCI device driver. + */ + if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) { + psycho_check_iommu_error(p, afsr, afar, PCI_ERR); + pci_scan_for_target_abort(p, pbm, pbm->pci_bus); + } + if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA)) + pci_scan_for_master_abort(p, pbm, pbm->pci_bus); + + /* For excessive retries, PSYCHO/PBM will abort the device + * and there is no way to specifically check for excessive + * retries in the config space status registers. So what + * we hope is that we'll catch it via the master/target + * abort events. + */ + + if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR)) + pci_scan_for_parity_error(p, pbm, pbm->pci_bus); +} + +/* XXX What about PowerFail/PowerManagement??? -DaveM */ +#define PSYCHO_ECC_CTRL 0x0020 +#define PSYCHO_ECCCTRL_EE 0x8000000000000000 /* Enable ECC Checking */ +#define PSYCHO_ECCCTRL_UE 0x4000000000000000 /* Enable UE Interrupts */ +#define PSYCHO_ECCCTRL_CE 0x2000000000000000 /* Enable CE INterrupts */ +#define PSYCHO_UE_INO 0x2e +#define PSYCHO_CE_INO 0x2f +#define PSYCHO_PCIERR_A_INO 0x30 +#define PSYCHO_PCIERR_B_INO 0x31 +static void __init psycho_register_error_handlers(struct pci_controller_info *p) +{ + unsigned long base = p->controller_regs; + unsigned int irq, portid = p->portid; + u64 tmp; + + /* Build IRQs and register handlers. */ + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_UE_INO); + if (request_irq(irq, psycho_ue_intr, + SA_SHIRQ, "PSYCHO UE", p) < 0) { + prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } + + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_CE_INO); + if (request_irq(irq, psycho_ce_intr, + SA_SHIRQ, "PSYCHO CE", p) < 0) { + prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } + + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); + if (request_irq(irq, psycho_pcierr_intr, + SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { + prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); + if (request_irq(irq, psycho_pcierr_intr, + SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { + prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + /* Enable UE and CE interrupts for controller. */ + psycho_write(base + PSYCHO_ECC_CTRL, + (PSYCHO_ECCCTRL_EE | + PSYCHO_ECCCTRL_UE | + PSYCHO_ECCCTRL_CE)); + + /* Enable PCI Error interrupts and clear error + * bits for each PBM. + */ + tmp = psycho_read(base + PSYCHO_PCIA_CTRL); + tmp |= (PSYCHO_PCICTRL_SBH_ERR | + PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_INT | + PSYCHO_PCICTRL_EEN); + psycho_write(base + PSYCHO_PCIA_CTRL, tmp); + + tmp = psycho_read(base + PSYCHO_PCIB_CTRL); + tmp |= (PSYCHO_PCICTRL_SBH_ERR | + PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_INT | + PSYCHO_PCICTRL_EEN); + psycho_write(base + PSYCHO_PCIB_CTRL, tmp); +} + +/* PSYCHO boot time probing and initialization. */ +static void __init psycho_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + res->start += root->start; + res->end += root->start; +} + +static void __init psycho_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct resource *res = &pdev->resource[resource]; + struct resource *root; + u32 reg; + int where, size; + + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else + root = &pbm->mem_space; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - root->start)) & ~size)); + pci_write_config_dword(pdev, where, reg); +} + +/* We have to do the config space accesses by hand, thus... */ +#define PBM_BRIDGE_BUS 0x40 +#define PBM_BRIDGE_SUBORDINATE 0x41 +static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno) +{ + u8 *addr, busno; + int nbus; + + busno = pci_highest_busnum; + nbus = pbm->pci_last_busno - pbm->pci_first_busno; + + addr = psycho_pci_config_mkaddr(pbm, orig_busno, + 0, PBM_BRIDGE_BUS); + pci_config_write8(addr, busno); + addr = psycho_pci_config_mkaddr(pbm, busno, + 0, PBM_BRIDGE_SUBORDINATE); + pci_config_write8(addr, busno + nbus); + + pbm->pci_first_busno = busno; + pbm->pci_last_busno = busno + nbus; + pci_highest_busnum = busno + nbus + 1; + + do { + pci_bus2pbm[busno++] = pbm; + } while (nbus--); +} + +/* We have to do the config space accesses by hand here since + * the pci_bus2pbm array is not ready yet. + */ +static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm, + u8 busno) +{ + u32 devfn, l, class; + u8 hdr_type; + int is_multi = 0; + + for(devfn = 0; devfn < 0xff; ++devfn) { + u32 *dwaddr; + u8 *baddr; + + if (PCI_FUNC(devfn) != 0 && is_multi == 0) + continue; + + /* Anything there? */ + dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID); + l = 0xffffffff; + pci_config_read32(dwaddr, &l); + if (l == 0xffffffff || l == 0x00000000 || + l == 0x0000ffff || l == 0xffff0000) { + is_multi = 0; + continue; + } + + baddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE); + pci_config_read8(baddr, &hdr_type); + if (PCI_FUNC(devfn) == 0) + is_multi = hdr_type & 0x80; + + dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION); + class = 0xffffffff; + pci_config_read32(dwaddr, &class); + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { + u32 buses = 0xffffffff; + + dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, + PCI_PRIMARY_BUS); + pci_config_read32(dwaddr, &buses); + pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff); + buses &= 0xff000000; + pci_config_write32(dwaddr, buses); + } + } +} + +static void __init pbm_bridge_reconfigure(struct pci_controller_info *p) +{ + struct pci_pbm_info *pbm; + u8 *addr; + + /* Clear out primary/secondary/subordinate bus numbers on + * all PCI-to-PCI bridges under each PBM. The generic bus + * probing will fix them up. + */ + pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); + pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno); + + /* Move PBM A out of the way. */ + pbm = &p->pbm_A; + addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno, + 0, PBM_BRIDGE_BUS); + pci_config_write8(addr, 0xff); + addr = psycho_pci_config_mkaddr(pbm, 0xff, + 0, PBM_BRIDGE_SUBORDINATE); + pci_config_write8(addr, 0xff); + + /* Now we can safely renumber both PBMs. */ + pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); + pbm_renumber(&p->pbm_A, 0xff); +} + +static void __init pbm_scan_bus(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, + p->pci_ops, + pbm); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbm->pci_bus); + pci_assign_unassigned(pbm, pbm->pci_bus); + pci_fixup_irq(pbm, pbm->pci_bus); +} + +static void __init psycho_scan_bus(struct pci_controller_info *p) +{ + pbm_bridge_reconfigure(p); + pbm_scan_bus(p, &p->pbm_B); + pbm_scan_bus(p, &p->pbm_A); + + /* After the PCI bus scan is complete, we can register + * the error interrupt handlers. + */ + psycho_register_error_handlers(p); +} + +static void __init psycho_iommu_init(struct pci_controller_info *p, int tsbsize) +{ + extern int this_is_starfire; + extern void *starfire_hookup(int); + struct linux_mlist_p1275 *mlist; + unsigned long tsbbase, i, n, order; + iopte_t *iopte; + u64 control; + + /* Setup initial software IOMMU state. */ + spin_lock_init(&p->iommu.lock); + p->iommu.iommu_cur_ctx = 0; + + /* PSYCHO's IOMMU lacks ctx flushing. */ + p->iommu.iommu_has_ctx_flush = 0; + + /* Register addresses. */ + p->iommu.iommu_control = p->controller_regs + PSYCHO_IOMMU_CONTROL; + p->iommu.iommu_tsbbase = p->controller_regs + PSYCHO_IOMMU_TSBBASE; + p->iommu.iommu_flush = p->controller_regs + PSYCHO_IOMMU_FLUSH; + p->iommu.iommu_ctxflush = 0; + + /* We use the main control register of PSYCHO as the write + * completion register. + */ + p->iommu.write_complete_reg = p->controller_regs + PSYCHO_CONTROL; + + /* + * Invalidate TLB Entries. + */ + control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); + control |= PSYCHO_IOMMU_CTRL_DENAB; + psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + for(i = 0; i < 16; i++) + psycho_write(p->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0); + + control &= ~(PSYCHO_IOMMU_CTRL_DENAB); + psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + + for(order = 0;; order++) + if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) + break; + + tsbbase = __get_free_pages(GFP_DMA, order); + if (!tsbbase) { + prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n"); + prom_halt(); + } + p->iommu.page_table = iopte = (iopte_t *)tsbbase; + p->iommu.page_table_sz = (tsbsize * 1024); + + /* Initialize to "none" settings. */ + for(i = 0; i < PCI_DVMA_HASHSZ; i++) { + pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; + pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; + } + + n = 0; + mlist = *prom_meminfo()->p1275_totphys; + while (mlist) { + unsigned long paddr = mlist->start_adr; + unsigned long num_bytes = mlist->num_bytes; + + if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) + goto next; + + if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) + num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr; + + /* Align base and length so we map whole hash table sized chunks + * at a time (and therefore full 64K IOMMU pages). + */ + paddr &= ~((1UL << 24UL) - 1); + num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); + + /* Move up the base for mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != + PCI_DVMA_HASH_NONE) { + paddr += (1UL << 24UL); + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Move down the size for tail mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != + PCI_DVMA_HASH_NONE) { + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Now map the rest. */ + for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { + iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K | + IOPTE_CACHE | IOPTE_WRITE) | + (paddr & IOPTE_PAGE)); + + if (!(n & 0xff)) + set_dvma_hash(paddr, (n << 16)); + + if (++n > (tsbsize * 1024)) + goto out; + + paddr += (1 << 16); + iopte++; + } + next: + mlist = mlist->theres_more; + } +out: + if (mlist) { + prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); + prom_printf("Try booting with mem=xxxM or similar\n"); + prom_halt(); + } + + psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase)); + + control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); + control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ); + control |= (PSYCHO_IOMMU_CTRL_TBWSZ | PSYCHO_IOMMU_CTRL_ENAB); + switch(tsbsize) { + case 8: + p->iommu.page_table_map_base = 0xe0000000; + pci_dvma_mask = 0x1fffffffUL; + control |= PSYCHO_IOMMU_TSBSZ_8K; + break; + case 16: + p->iommu.page_table_map_base = 0xc0000000; + pci_dvma_mask = 0x3fffffffUL; + control |= PSYCHO_IOMMU_TSBSZ_16K; + break; + case 32: + p->iommu.page_table_map_base = 0x80000000; + pci_dvma_mask = 0x7fffffffUL; + control |= PSYCHO_IOMMU_TSBSZ_32K; + break; + default: + prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); + prom_halt(); + break; + } + psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + + /* If necessary, hook us up for starfire IRQ translations. */ + if(this_is_starfire) + p->starfire_cookie = starfire_hookup(p->portid); + else + p->starfire_cookie = NULL; +} + +#define PSYCHO_IRQ_RETRY 0x1a00UL +#define PSYCHO_PCIA_DIAG 0x2020UL +#define PSYCHO_PCIB_DIAG 0x4020UL +#define PSYCHO_PCIDIAG_RESV 0xffffffffffffff80 /* Reserved */ +#define PSYCHO_PCIDIAG_DRETRY 0x0000000000000040 /* Disable retry limit */ +#define PSYCHO_PCIDIAG_DISYNC 0x0000000000000020 /* Disable DMA wr / irq sync */ +#define PSYCHO_PCIDIAG_DDWSYNC 0x0000000000000010 /* Disable DMA wr / PIO rd sync */ +#define PSYCHO_PCIDIAG_IDDPAR 0x0000000000000008 /* Invert DMA data parity */ +#define PSYCHO_PCIDIAG_IPDPAR 0x0000000000000004 /* Invert PIO data parity */ +#define PSYCHO_PCIDIAG_IPAPAR 0x0000000000000002 /* Invert PIO address parity */ +#define PSYCHO_PCIDIAG_LPBACK 0x0000000000000001 /* Enable loopback mode */ + +static void psycho_controller_hwinit(struct pci_controller_info *p) +{ + u64 tmp; + + /* PROM sets the IRQ retry value too low, increase it. */ + psycho_write(p->controller_regs + PSYCHO_IRQ_RETRY, 0xff); + + /* Enable arbiter for all PCI slots. */ + tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_CTRL); + tmp |= PSYCHO_PCICTRL_AEN; + psycho_write(p->controller_regs + PSYCHO_PCIA_CTRL, tmp); + + tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_CTRL); + tmp |= PSYCHO_PCICTRL_AEN; + psycho_write(p->controller_regs + PSYCHO_PCIB_CTRL, tmp); + + /* Disable DMA write / PIO read synchronization on + * both PCI bus segments. + * [ U2P Erratum 1243770, STP2223BGA data sheet ] + */ + tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_DIAG); + tmp |= PSYCHO_PCIDIAG_DDWSYNC; + psycho_write(p->controller_regs + PSYCHO_PCIA_DIAG, tmp); + + tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_DIAG); + tmp |= PSYCHO_PCIDIAG_DDWSYNC; + psycho_write(p->controller_regs + PSYCHO_PCIB_DIAG, tmp); +} + +static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + char *name = pbm->name; + + sprintf(name, "PSYCHO%d PBM%c", + p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->io_space.name = pbm->mem_space.name = name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); +} + +static void psycho_pbm_strbuf_init(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + int is_pbm_a) +{ + unsigned long base = p->controller_regs; + + /* Currently we don't even use it. */ + pbm->stc.strbuf_enabled = 0; + + /* PSYCHO's streaming buffer lacks ctx flushing. */ + pbm->stc.strbuf_has_ctx_flush = 0; + + if (is_pbm_a) { + pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; + pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; + pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A; + } else { + pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B; + pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; + pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; + } + pbm->stc.strbuf_ctxflush = 0; + pbm->stc.strbuf_ctxmatch_base = 0; + + pbm->stc.strbuf_flushflag = (volatile unsigned long *) + ((((unsigned long)&pbm->stc.__flushflag_buf[0]) + + 63UL) + & ~63UL); + pbm->stc.strbuf_flushflag_pa = (unsigned long) + __pa(pbm->stc.strbuf_flushflag); + +#if 0 + /* And when we do enable it, these are the sorts of things + * we'll do. + */ + control = psycho_read(pbm->stc.strbuf_control); + control |= PSYCHO_SBUFCTRL_SB_EN; + psycho_write(pbm->stc.strbuf_control, control); +#endif +} + +#define PSYCHO_IOSPACE_A 0x002000000UL +#define PSYCHO_IOSPACE_B 0x002010000UL +#define PSYCHO_IOSPACE_SIZE 0x00000ffffUL +#define PSYCHO_MEMSPACE_A 0x100000000UL +#define PSYCHO_MEMSPACE_B 0x180000000UL +#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL + +static void psycho_pbm_init(struct pci_controller_info *p, + int prom_node, int is_pbm_a) +{ + unsigned int busrange[2]; + struct pci_pbm_info *pbm; + int err; + + if (is_pbm_a) { + pbm = &p->pbm_A; + pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_A; + pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A; + } else { + pbm = &p->pbm_B; + pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B; + pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B; + } + pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE; + pbm->io_space.flags = IORESOURCE_IO; + pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE; + pbm->mem_space.flags = IORESOURCE_MEM; + pbm_register_toplevel_resources(p, pbm); + + pbm->parent = p; + pbm->prom_node = prom_node; + prom_getstring(prom_node, "name", + pbm->prom_name, + sizeof(pbm->prom_name)); + + err = prom_getproperty(prom_node, "ranges", + (char *)pbm->pbm_ranges, + sizeof(pbm->pbm_ranges)); + if (err != -1) + pbm->num_pbm_ranges = + (err / sizeof(struct linux_prom_pci_ranges)); + else + pbm->num_pbm_ranges = 0; + + err = prom_getproperty(prom_node, "interrupt-map", + (char *)pbm->pbm_intmap, + sizeof(pbm->pbm_intmap)); + if (err != -1) { + pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); + err = prom_getproperty(prom_node, "interrupt-map-mask", + (char *)&pbm->pbm_intmask, + sizeof(pbm->pbm_intmask)); + if (err == -1) { + prom_printf("PSYCHO-PBM: Fatal error, no " + "interrupt-map-mask.\n"); + prom_halt(); + } + } else { + pbm->num_pbm_intmap = 0; + memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); + } + + err = prom_getproperty(prom_node, "bus-range", + (char *)&busrange[0], + sizeof(busrange)); + if (err == 0 || err == -1) { + prom_printf("PSYCHO-PBM: Fatal error, no bus-range.\n"); + prom_halt(); + } + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + + psycho_pbm_strbuf_init(p, pbm, is_pbm_a); +} + +#define PSYCHO_CONFIGSPACE 0x001000000UL + +void __init psycho_init(int node) +{ + struct linux_prom64_registers pr_regs[3]; + struct pci_controller_info *p; + unsigned long flags; + u32 upa_portid; + int is_pbm_a, err; + + upa_portid = prom_getintdefault(node, "upa-portid", 0xff); + + spin_lock_irqsave(&pci_controller_lock, flags); + for(p = pci_controller_root; p; p = p->next) { + if (p->portid == upa_portid) { + spin_unlock_irqrestore(&pci_controller_lock, flags); + is_pbm_a = (p->pbm_A.prom_node == 0); + psycho_pbm_init(p, node, is_pbm_a); + return; + } + } + spin_unlock_irqrestore(&pci_controller_lock, flags); + + p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + if (!p) { + prom_printf("PSYCHO: Fatal memory allocation error.\n"); + prom_halt(); + } + memset(p, 0, sizeof(*p)); + + spin_lock_irqsave(&pci_controller_lock, flags); + p->next = pci_controller_root; + pci_controller_root = p; + spin_unlock_irqrestore(&pci_controller_lock, flags); + + p->portid = upa_portid; + p->index = pci_num_controllers++; + p->scan_bus = psycho_scan_bus; + p->irq_build = psycho_irq_build; + p->base_address_update = psycho_base_address_update; + p->resource_adjust = psycho_resource_adjust; + p->pci_ops = &psycho_ops; + + err = prom_getproperty(node, "reg", + (char *)&pr_regs[0], + sizeof(pr_regs)); + if (err == 0 || err == -1) { + prom_printf("PSYCHO: Fatal error, no reg property.\n"); + prom_halt(); + } + + p->controller_regs = pr_regs[2].phys_addr; + printk("PCI: Found PSYCHO, control regs at %016lx\n", + p->controller_regs); + + p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE; + printk("PSYCHO: PCI config space at %016lx\n", p->config_space); + + psycho_controller_hwinit(p); + + pci_dvma_offset = 0x80000000UL; + psycho_iommu_init(p, 32); + + is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); + psycho_pbm_init(p, node, is_pbm_a); +} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c --- v2.3.15/linux/arch/sparc64/kernel/pci_sabre.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/pci_sabre.c Tue Aug 31 11:23:30 1999 @@ -0,0 +1,1492 @@ +/* $Id: pci_sabre.c,v 1.1 1999/08/30 10:00:32 davem Exp $ + * pci_sabre.c: Sabre specific PCI controller support. + * + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pci_impl.h" + +/* All SABRE registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define sabre_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define sabre_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* SABRE PCI controller register offsets and definitions. */ +#define SABRE_UE_AFSR 0x0030UL +#define SABRE_UEAFSR_PDRD 0x4000000000000000UL /* Primary PCI DMA Read */ +#define SABRE_UEAFSR_PDWR 0x2000000000000000UL /* Primary PCI DMA Write */ +#define SABRE_UEAFSR_SDRD 0x0800000000000000UL /* Secondary PCI DMA Read */ +#define SABRE_UEAFSR_SDWR 0x0400000000000000UL /* Secondary PCI DMA Write */ +#define SABRE_UEAFSR_SDTE 0x0200000000000000UL /* Secondary DMA Translation Error */ +#define SABRE_UEAFSR_PDTE 0x0100000000000000UL /* Primary DMA Translation Error */ +#define SABRE_UEAFSR_BMSK 0x0000ffff00000000UL /* Bytemask */ +#define SABRE_UEAFSR_OFF 0x00000000e0000000UL /* Offset (AFAR bits [5:3] */ +#define SABRE_UEAFSR_BLK 0x0000000000800000UL /* Was block operation */ +#define SABRE_UECE_AFAR 0x0038UL +#define SABRE_CE_AFSR 0x0040UL +#define SABRE_CEAFSR_PDRD 0x4000000000000000UL /* Primary PCI DMA Read */ +#define SABRE_CEAFSR_PDWR 0x2000000000000000UL /* Primary PCI DMA Write */ +#define SABRE_CEAFSR_SDRD 0x0800000000000000UL /* Secondary PCI DMA Read */ +#define SABRE_CEAFSR_SDWR 0x0400000000000000UL /* Secondary PCI DMA Write */ +#define SABRE_CEAFSR_ESYND 0x00ff000000000000UL /* ECC Syndrome */ +#define SABRE_CEAFSR_BMSK 0x0000ffff00000000UL /* Bytemask */ +#define SABRE_CEAFSR_OFF 0x00000000e0000000UL /* Offset */ +#define SABRE_CEAFSR_BLK 0x0000000000800000UL /* Was block operation */ +#define SABRE_UECE_AFAR_ALIAS 0x0048UL /* Aliases to 0x0038 */ +#define SABRE_IOMMU_CONTROL 0x0200UL +#define SABRE_IOMMUCTRL_ERRSTS 0x0000000006000000UL /* Error status bits */ +#define SABRE_IOMMUCTRL_ERR 0x0000000001000000UL /* Error present in IOTLB */ +#define SABRE_IOMMUCTRL_LCKEN 0x0000000000800000UL /* IOTLB lock enable */ +#define SABRE_IOMMUCTRL_LCKPTR 0x0000000000780000UL /* IOTLB lock pointer */ +#define SABRE_IOMMUCTRL_TSBSZ 0x0000000000070000UL /* TSB Size */ +#define SABRE_IOMMUCTRL_TBWSZ 0x0000000000000004UL /* TSB assumed page size */ +#define SABRE_IOMMUCTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */ +#define SABRE_IOMMUCTRL_ENAB 0x0000000000000001UL /* IOMMU Enable */ +#define SABRE_IOMMU_TSBBASE 0x0208UL +#define SABRE_IOMMU_FLUSH 0x0210UL +#define SABRE_IMAP_A_SLOT0 0x0c00UL +#define SABRE_IMAP_B_SLOT0 0x0c20UL +#define SABRE_IMAP_SCSI 0x1000UL +#define SABRE_IMAP_ETH 0x1008UL +#define SABRE_IMAP_BPP 0x1010UL +#define SABRE_IMAP_AU_REC 0x1018UL +#define SABRE_IMAP_AU_PLAY 0x1020UL +#define SABRE_IMAP_PFAIL 0x1028UL +#define SABRE_IMAP_KMS 0x1030UL +#define SABRE_IMAP_FLPY 0x1038UL +#define SABRE_IMAP_SHW 0x1040UL +#define SABRE_IMAP_KBD 0x1048UL +#define SABRE_IMAP_MS 0x1050UL +#define SABRE_IMAP_SER 0x1058UL +#define SABRE_IMAP_UE 0x1070UL +#define SABRE_IMAP_CE 0x1078UL +#define SABRE_IMAP_PCIERR 0x1080UL +#define SABRE_IMAP_GFX 0x1098UL +#define SABRE_IMAP_EUPA 0x10a0UL +#define SABRE_ICLR_A_SLOT0 0x1400UL +#define SABRE_ICLR_B_SLOT0 0x1480UL +#define SABRE_ICLR_SCSI 0x1800UL +#define SABRE_ICLR_ETH 0x1808UL +#define SABRE_ICLR_BPP 0x1810UL +#define SABRE_ICLR_AU_REC 0x1818UL +#define SABRE_ICLR_AU_PLAY 0x1820UL +#define SABRE_ICLR_PFAIL 0x1828UL +#define SABRE_ICLR_KMS 0x1830UL +#define SABRE_ICLR_FLPY 0x1838UL +#define SABRE_ICLR_SHW 0x1840UL +#define SABRE_ICLR_KBD 0x1848UL +#define SABRE_ICLR_MS 0x1850UL +#define SABRE_ICLR_SER 0x1858UL +#define SABRE_ICLR_UE 0x1870UL +#define SABRE_ICLR_CE 0x1878UL +#define SABRE_ICLR_PCIERR 0x1880UL +#define SABRE_WRSYNC 0x1c20UL +#define SABRE_PCICTRL 0x2000UL +#define SABRE_PCICTRL_MRLEN 0x0000001000000000UL /* Use MemoryReadLine for block loads/stores */ +#define SABRE_PCICTRL_SERR 0x0000000400000000UL /* Set when SERR asserted on PCI bus */ +#define SABRE_PCICTRL_ARBPARK 0x0000000000200000UL /* Bus Parking 0=Ultra-IIi 1=prev-bus-owner */ +#define SABRE_PCICTRL_CPUPRIO 0x0000000000100000UL /* Ultra-IIi granted every other bus cycle */ +#define SABRE_PCICTRL_ARBPRIO 0x00000000000f0000UL /* Slot which is granted every other bus cycle */ +#define SABRE_PCICTRL_ERREN 0x0000000000000100UL /* PCI Error Interrupt Enable */ +#define SABRE_PCICTRL_RTRYWE 0x0000000000000080UL /* DMA Flow Control 0=wait-if-possible 1=retry */ +#define SABRE_PCICTRL_AEN 0x000000000000000fUL /* Slot PCI arbitration enables */ +#define SABRE_PIOAFSR 0x2010UL +#define SABRE_PIOAFSR_PMA 0x8000000000000000UL /* Primary Master Abort */ +#define SABRE_PIOAFSR_PTA 0x4000000000000000UL /* Primary Target Abort */ +#define SABRE_PIOAFSR_PRTRY 0x2000000000000000UL /* Primary Excessive Retries */ +#define SABRE_PIOAFSR_PPERR 0x1000000000000000UL /* Primary Parity Error */ +#define SABRE_PIOAFSR_SMA 0x0800000000000000UL /* Secondary Master Abort */ +#define SABRE_PIOAFSR_STA 0x0400000000000000UL /* Secondary Target Abort */ +#define SABRE_PIOAFSR_SRTRY 0x0200000000000000UL /* Secondary Excessive Retries */ +#define SABRE_PIOAFSR_SPERR 0x0100000000000000UL /* Secondary Parity Error */ +#define SABRE_PIOAFSR_BMSK 0x0000ffff00000000UL /* Byte Mask */ +#define SABRE_PIOAFSR_BLK 0x0000000080000000UL /* Was Block Operation */ +#define SABRE_PIOAFAR 0x2018UL +#define SABRE_PCIDIAG 0x2020UL +#define SABRE_PCIDIAG_DRTRY 0x0000000000000040UL /* Disable PIO Retry Limit */ +#define SABRE_PCIDIAG_IPAPAR 0x0000000000000008UL /* Invert PIO Address Parity */ +#define SABRE_PCIDIAG_IPDPAR 0x0000000000000004UL /* Invert PIO Data Parity */ +#define SABRE_PCIDIAG_IDDPAR 0x0000000000000002UL /* Invert DMA Data Parity */ +#define SABRE_PCIDIAG_ELPBK 0x0000000000000001UL /* Loopback Enable - not supported */ +#define SABRE_PCITASR 0x2028UL +#define SABRE_PCITASR_EF 0x0000000000000080UL /* Respond to 0xe0000000-0xffffffff */ +#define SABRE_PCITASR_CD 0x0000000000000040UL /* Respond to 0xc0000000-0xdfffffff */ +#define SABRE_PCITASR_AB 0x0000000000000020UL /* Respond to 0xa0000000-0xbfffffff */ +#define SABRE_PCITASR_89 0x0000000000000010UL /* Respond to 0x80000000-0x9fffffff */ +#define SABRE_PCITASR_67 0x0000000000000008UL /* Respond to 0x60000000-0x7fffffff */ +#define SABRE_PCITASR_45 0x0000000000000004UL /* Respond to 0x40000000-0x5fffffff */ +#define SABRE_PCITASR_23 0x0000000000000002UL /* Respond to 0x20000000-0x3fffffff */ +#define SABRE_PCITASR_01 0x0000000000000001UL /* Respond to 0x00000000-0x1fffffff */ +#define SABRE_PIOBUF_DIAG 0x5000UL +#define SABRE_DMABUF_DIAGLO 0x5100UL +#define SABRE_DMABUF_DIAGHI 0x51c0UL +#define SABRE_IMAP_GFX_ALIAS 0x6000UL /* Aliases to 0x1098 */ +#define SABRE_IMAP_EUPA_ALIAS 0x8000UL /* Aliases to 0x10a0 */ +#define SABRE_IOMMU_VADIAG 0xa400UL +#define SABRE_IOMMU_TCDIAG 0xa408UL +#define SABRE_IOMMU_TAG 0xa580UL +#define SABRE_IOMMUTAG_ERRSTS 0x0000000001800000UL /* Error status bits */ +#define SABRE_IOMMUTAG_ERR 0x0000000000400000UL /* Error present */ +#define SABRE_IOMMUTAG_WRITE 0x0000000000200000UL /* Page is writable */ +#define SABRE_IOMMUTAG_STREAM 0x0000000000100000UL /* Streamable bit - unused */ +#define SABRE_IOMMUTAG_SIZE 0x0000000000080000UL /* 0=8k 1=16k */ +#define SABRE_IOMMUTAG_VPN 0x000000000007ffffUL /* Virtual Page Number [31:13] */ +#define SABRE_IOMMU_DATA 0xa600UL +#define SABRE_IOMMUDATA_VALID 0x0000000040000000UL /* Valid */ +#define SABRE_IOMMUDATA_USED 0x0000000020000000UL /* Used (for LRU algorithm) */ +#define SABRE_IOMMUDATA_CACHE 0x0000000010000000UL /* Cacheable */ +#define SABRE_IOMMUDATA_PPN 0x00000000001fffffUL /* Physical Page Number [33:13] */ +#define SABRE_PCI_IRQSTATE 0xa800UL +#define SABRE_OBIO_IRQSTATE 0xa808UL +#define SABRE_FFBCFG 0xf000UL +#define SABRE_FFBCFG_SPRQS 0x000000000f000000 /* Slave P_RQST queue size */ +#define SABRE_FFBCFG_ONEREAD 0x0000000000004000 /* Slave supports one outstanding read */ +#define SABRE_MCCTRL0 0xf010UL +#define SABRE_MCCTRL0_RENAB 0x0000000080000000 /* Refresh Enable */ +#define SABRE_MCCTRL0_EENAB 0x0000000010000000 /* Enable all ECC functions */ +#define SABRE_MCCTRL0_11BIT 0x0000000000001000 /* Enable 11-bit column addressing */ +#define SABRE_MCCTRL0_DPP 0x0000000000000f00 /* DIMM Pair Present Bits */ +#define SABRE_MCCTRL0_RINTVL 0x00000000000000ff /* Refresh Interval */ +#define SABRE_MCCTRL1 0xf018UL +#define SABRE_MCCTRL1_AMDC 0x0000000038000000 /* Advance Memdata Clock */ +#define SABRE_MCCTRL1_ARDC 0x0000000007000000 /* Advance DRAM Read Data Clock */ +#define SABRE_MCCTRL1_CSR 0x0000000000e00000 /* CAS to RAS delay for CBR refresh */ +#define SABRE_MCCTRL1_CASRW 0x00000000001c0000 /* CAS length for read/write */ +#define SABRE_MCCTRL1_RCD 0x0000000000038000 /* RAS to CAS delay */ +#define SABRE_MCCTRL1_CP 0x0000000000007000 /* CAS Precharge */ +#define SABRE_MCCTRL1_RP 0x0000000000000e00 /* RAS Precharge */ +#define SABRE_MCCTRL1_RAS 0x00000000000001c0 /* Length of RAS for refresh */ +#define SABRE_MCCTRL1_CASRW2 0x0000000000000038 /* Must be same as CASRW */ +#define SABRE_MCCTRL1_RSC 0x0000000000000007 /* RAS after CAS hold time */ +#define SABRE_RESETCTRL 0xf020UL + +#define SABRE_CONFIGSPACE 0x001000000UL +#define SABRE_IOSPACE 0x002000000UL +#define SABRE_IOSPACE_SIZE 0x00000ffffUL +#define SABRE_MEMSPACE 0x100000000UL +#define SABRE_MEMSPACE_SIZE 0x07fffffffUL + +/* UltraSparc-IIi Programmer's Manual, page 325, PCI + * configuration space address format: + * + * 32 24 23 16 15 11 10 8 7 2 1 0 + * --------------------------------------------------------- + * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | + * --------------------------------------------------------- + */ +#define SABRE_CONFIG_BASE(PBM) \ + ((PBM)->parent->config_space | (1UL << 24)) +#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned int devfn, + int where) +{ + if (!pbm) + return NULL; + return (void *) + (SABRE_CONFIG_BASE(pbm) | + SABRE_CONFIG_ENCODE(bus, devfn, where)); +} + +static int sabre_out_of_range(unsigned char devfn) +{ + return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || + ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) || + (PCI_SLOT(devfn) > 1)); +} + +static int __sabre_out_of_range(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned char devfn) +{ + return ((pbm->parent == 0) || + ((pbm == &pbm->parent->pbm_B) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8) || + ((pbm == &pbm->parent->pbm_A) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8)); +} + +static int __sabre_read_byte(struct pci_dev *dev, int where, u8 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + *value = 0xff; + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + pci_config_read8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_read_word(struct pci_dev *dev, int where, u16 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + *value = 0xffff; + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_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_config_read16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_read_dword(struct pci_dev *dev, int where, u32 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + *value = 0xffffffff; + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_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_config_read32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int sabre_read_byte(struct pci_dev *dev, int where, u8 *value) +{ + if (dev->bus->number) + return __sabre_read_byte(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) { + *value = 0xff; + return PCIBIOS_SUCCESSFUL; + } + + if (where < 8) { + u16 tmp; + + __sabre_read_word(dev, where & ~1, &tmp); + if (where & 1) + *value = tmp >> 8; + else + *value = tmp & 0xff; + return PCIBIOS_SUCCESSFUL; + } else + return __sabre_read_byte(dev, where, value); +} + +static int sabre_read_word(struct pci_dev *dev, int where, u16 *value) +{ + if (dev->bus->number) + return __sabre_read_word(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) { + *value = 0xffff; + return PCIBIOS_SUCCESSFUL; + } + + if (where < 8) + return __sabre_read_word(dev, where, value); + else { + u8 tmp; + + __sabre_read_byte(dev, where, &tmp); + *value = tmp; + __sabre_read_byte(dev, where + 1, &tmp); + *value |= tmp << 8; + return PCIBIOS_SUCCESSFUL; + } +} + +static int sabre_read_dword(struct pci_dev *dev, int where, u32 *value) +{ + u16 tmp; + + if (dev->bus->number) + return __sabre_read_dword(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) { + *value = 0xffffffff; + return PCIBIOS_SUCCESSFUL; + } + + sabre_read_word(dev, where, &tmp); + *value = tmp; + sabre_read_word(dev, where + 2, &tmp); + *value |= tmp << 16; + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_write_byte(struct pci_dev *dev, int where, u8 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + pci_config_write8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_write_word(struct pci_dev *dev, int where, u16 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_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_config_write16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_write_dword(struct pci_dev *dev, int where, u32 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_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_config_write32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int sabre_write_byte(struct pci_dev *dev, int where, u8 value) +{ + if (dev->bus->number) + return __sabre_write_byte(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where < 8) { + u16 tmp; + + __sabre_read_word(dev, where & ~1, &tmp); + if (where & 1) { + value &= 0x00ff; + value |= tmp << 8; + } else { + value &= 0xff00; + value |= tmp; + } + return __sabre_write_word(dev, where & ~1, tmp); + } else + return __sabre_write_byte(dev, where, value); +} + +static int sabre_write_word(struct pci_dev *dev, int where, u16 value) +{ + if (dev->bus->number) + return __sabre_write_word(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where < 8) + return __sabre_write_word(dev, where, value); + else { + __sabre_write_byte(dev, where, value & 0xff); + __sabre_write_byte(dev, where + 1, value >> 8); + return PCIBIOS_SUCCESSFUL; + } +} + +static int sabre_write_dword(struct pci_dev *dev, int where, u32 value) +{ + if (dev->bus->number) + return __sabre_write_dword(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) + return PCIBIOS_SUCCESSFUL; + + sabre_write_word(dev, where, value & 0xffff); + sabre_write_word(dev, where + 2, value >> 16); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops sabre_ops = { + sabre_read_byte, + sabre_read_word, + sabre_read_dword, + sabre_write_byte, + sabre_write_word, + sabre_write_dword +}; + +static unsigned long sabre_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return SABRE_IMAP_A_SLOT0 + (slot * 8); + else + return SABRE_IMAP_B_SLOT0 + (slot * 8); +} + +static unsigned long __onboard_imap_off[] = { +/*0x20*/ SABRE_IMAP_SCSI, +/*0x21*/ SABRE_IMAP_ETH, +/*0x22*/ SABRE_IMAP_BPP, +/*0x23*/ SABRE_IMAP_AU_REC, +/*0x24*/ SABRE_IMAP_AU_PLAY, +/*0x25*/ SABRE_IMAP_PFAIL, +/*0x26*/ SABRE_IMAP_KMS, +/*0x27*/ SABRE_IMAP_FLPY, +/*0x28*/ SABRE_IMAP_SHW, +/*0x29*/ SABRE_IMAP_KBD, +/*0x2a*/ SABRE_IMAP_MS, +/*0x2b*/ SABRE_IMAP_SER, +/*0x2c*/ 0 /* reserved */, +/*0x2d*/ 0 /* reserved */, +/*0x2e*/ SABRE_IMAP_UE, +/*0x2f*/ SABRE_IMAP_CE, +/*0x30*/ SABRE_IMAP_PCIERR, +}; +#define SABRE_ONBOARD_IRQ_BASE 0x20 +#define SABRE_ONBOARD_IRQ_LAST 0x30 +#define sabre_onboard_imap_offset(__ino) \ + __onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] + +#define sabre_iclr_offset(ino) \ + ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +/* PCI SABRE INO number to Sparc PIL level. */ +static unsigned char sabre_pil_table[] = { +/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ +/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ +/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ +/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ +/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ +/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ +/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ +/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ +/*0x20*/3, /* SCSI */ +/*0x21*/5, /* Ethernet */ +/*0x22*/8, /* Parallel Port */ +/*0x23*/13, /* Audio Record */ +/*0x24*/14, /* Audio Playback */ +/*0x25*/15, /* PowerFail */ +/*0x26*/3, /* second SCSI */ +/*0x27*/11, /* Floppy */ +/*0x28*/2, /* Spare Hardware */ +/*0x29*/9, /* Keyboard */ +/*0x2a*/4, /* Mouse */ +/*0x2b*/12, /* Serial */ +/*0x2c*/10, /* Timer 0 */ +/*0x2d*/11, /* Timer 1 */ +/*0x2e*/15, /* Uncorrectable ECC */ +/*0x2f*/15, /* Correctable ECC */ +/*0x30*/15, /* PCI Bus A Error */ +/*0x31*/15, /* PCI Bus B Error */ +/*0x32*/1, /* Power Management */ +}; + +static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) +{ + int ret; + + ret = sabre_pil_table[ino]; + if (ret == 0 && pdev == NULL) { + ret = 1; + } else if (ret == 0) { + switch ((pdev->class >> 16) & 0x0f) { + case PCI_BASE_CLASS_STORAGE: + ret = 4; + + case PCI_BASE_CLASS_NETWORK: + ret = 6; + + case PCI_BASE_CLASS_DISPLAY: + ret = 9; + + case PCI_BASE_CLASS_MULTIMEDIA: + case PCI_BASE_CLASS_MEMORY: + case PCI_BASE_CLASS_BRIDGE: + ret = 10; + + default: + ret = 1; + }; + } + return ret; +} + +static unsigned int __init sabre_irq_build(struct pci_controller_info *p, + struct pci_dev *pdev, + unsigned int ino) +{ + struct ino_bucket *bucket; + volatile unsigned int *imap, *iclr; + unsigned long imap_off, iclr_off; + int pil, inofixup = 0; + + ino &= PCI_IRQ_INO; + if (ino < SABRE_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = sabre_pcislot_imap_offset(ino); + } else { + /* onboard device */ + if (ino > SABRE_ONBOARD_IRQ_LAST) { + prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = sabre_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + pil = sabre_ino_to_pil(pdev, ino); + imap = (volatile unsigned int *)__va(p->controller_regs + imap_off); + imap += 1; + + iclr_off = sabre_iclr_offset(ino); + iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off); + iclr += 1; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket->flags |= IBF_PCI; + + /* XXX We still need to code up support for this in irq.c + * XXX It's easy to code up since only one SIMBA can exist + * XXX in a machine and this is where the sync register is. -DaveM + */ + if (pdev) { + struct pcidev_cookie *pcp = pdev->sysdata; + if (pdev->bus->number != pcp->pbm->pci_first_busno) + bucket->flags |= IBF_DMA_SYNC; + } + return __irq(bucket); +} + +/* SABRE error handling support. */ +static void sabre_check_iommu_error(struct pci_controller_info *p, + unsigned long afsr, + unsigned long afar) +{ + unsigned long iommu_tag[16]; + unsigned long iommu_data[16]; + unsigned long flags; + u64 control; + int i; + + spin_lock_irqsave(&p->iommu.lock, flags); + control = sabre_read(p->iommu.iommu_control); + if (control & SABRE_IOMMUCTRL_ERR) { + char *type_string; + + /* Clear the error encountered bit. + * NOTE: On Sabre this is write 1 to clear, + * which is different from Psycho. + */ + sabre_write(p->iommu.iommu_control, control); + switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) { + case 1: + type_string = "Invalid Error"; + break; + case 3: + type_string = "ECC Error"; + break; + default: + type_string = "Unknown"; + break; + }; + printk("SABRE%d: IOMMU Error, type[%s]\n", + p->index, type_string); + + /* Enter diagnostic mode and probe for error'd + * entries in the IOTLB. + */ + control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR); + sabre_write(p->iommu.iommu_control, + (control | SABRE_IOMMUCTRL_DENAB)); + for (i = 0; i < 16; i++) { + unsigned long base = p->controller_regs; + + iommu_tag[i] = + sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL)); + iommu_data[i] = + sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL)); + sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0); + sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0); + } + sabre_write(p->iommu.iommu_control, control); + + for (i = 0; i < 16; i++) { + unsigned long tag, data; + + tag = iommu_tag[i]; + if (!(tag & SABRE_IOMMUTAG_ERR)) + continue; + + data = iommu_data[i]; + switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) { + case 1: + type_string = "Invalid Error"; + break; + case 3: + type_string = "ECC Error"; + break; + default: + type_string = "Unknown"; + break; + }; + printk("SABRE%d: IOMMU TAG(%d)[error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", + p->index, i, type_string, + ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0), + ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8), + ((tag & SABRE_IOMMUTAG_VPN) << PAGE_SHIFT)); + printk("SABRE%d: IOMMU DATA(%d)[valid(%d)used(%d)cache(%d)ppg(%016lx)\n", + p->index, i, + ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0), + ((data & SABRE_IOMMUDATA_USED) ? 1 : 0), + ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0), + ((data & SABRE_IOMMUDATA_PPN) << PAGE_SHIFT)); + } + } + spin_unlock_irqrestore(&p->iommu.lock, flags); +} + +static void sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + SABRE_UE_AFSR; + unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch uncorrectable error status. */ + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); + + /* Clear the primary/secondary error status bits. */ + error_bits = afsr & + (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | + SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | + SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE); + sabre_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n", + p->index, + ((error_bits & SABRE_UEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & SABRE_UEAFSR_PDWR) ? + "DMA Write" : "???")), + ((error_bits & SABRE_UEAFSR_PDTE) ? + ":Translation Error" : "")); + printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n", + p->index, + (afsr & SABRE_UEAFSR_BMSK) >> 32UL, + (afsr & SABRE_UEAFSR_OFF) >> 29UL, + ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0)); + printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar); + printk("SABRE%d: UE Secondary errors [", p->index); + reported = 0; + if (afsr & SABRE_UEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & SABRE_UEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (afsr & SABRE_UEAFSR_SDTE) { + reported++; + printk("(Translation Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* Interrogate IOMMU for error status. */ + sabre_check_iommu_error(p, afsr, afar); +} + +static void sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + SABRE_CE_AFSR; + unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch error status. */ + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | + SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR); + sabre_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SABRE%d: Correctable Error, primary error type[%s]\n", + p->index, + ((error_bits & SABRE_CEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & SABRE_CEAFSR_PDWR) ? + "DMA Write" : "???"))); + printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " + "was_block(%d)\n", + p->index, + (afsr & SABRE_CEAFSR_ESYND) >> 48UL, + (afsr & SABRE_CEAFSR_BMSK) >> 32UL, + (afsr & SABRE_CEAFSR_OFF) >> 29UL, + ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0)); + printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar); + printk("SABRE%d: CE Secondary errors [", p->index); + reported = 0; + if (afsr & SABRE_CEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & SABRE_CEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); +} + +static void sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int reported; + + afsr_reg = p->controller_regs + SABRE_PIOAFSR; + afar_reg = p->controller_regs + SABRE_PIOAFAR; + + /* Latch error status. */ + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA | + SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR | + SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA | + SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR); + sabre_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SABRE%d: PCI Error, primary error type[%s]\n", + p->index, + (((error_bits & SABRE_PIOAFSR_PMA) ? + "Master Abort" : + ((error_bits & SABRE_PIOAFSR_PTA) ? + "Target Abort" : + ((error_bits & SABRE_PIOAFSR_PRTRY) ? + "Excessive Retries" : + ((error_bits & SABRE_PIOAFSR_PPERR) ? + "Parity Error" : "???")))))); + printk("SABRE%d: bytemask[%04lx] was_block(%d)\n", + p->index, + (afsr & SABRE_PIOAFSR_BMSK) >> 32UL, + (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0); + printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar); + printk("SABRE%d: PCI Secondary errors [", p->index); + reported = 0; + if (afsr & SABRE_PIOAFSR_SMA) { + reported++; + printk("(Master Abort)"); + } + if (afsr & SABRE_PIOAFSR_STA) { + reported++; + printk("(Target Abort)"); + } + if (afsr & SABRE_PIOAFSR_SRTRY) { + reported++; + printk("(Excessive Retries)"); + } + if (afsr & SABRE_PIOAFSR_SPERR) { + reported++; + printk("(Parity Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* For the error types shown, scan both PCI buses for devices + * which have logged that error type. + */ + + /* If we see a Target Abort, this could be the result of an + * IOMMU translation error of some sort. It is extremely + * useful to log this information as usually it indicates + * a bug in the IOMMU support code or a PCI device driver. + */ + if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) { + sabre_check_iommu_error(p, afsr, afar); + pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus); + } + if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) { + pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus); + } + /* For excessive retries, SABRE/PBM will abort the device + * and there is no way to specifically check for excessive + * retries in the config space status registers. So what + * we hope is that we'll catch it via the master/target + * abort events. + */ + + if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) { + pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus); + } +} + +/* XXX What about PowerFail/PowerManagement??? -DaveM */ +#define SABRE_UE_INO 0x2e +#define SABRE_CE_INO 0x2f +#define SABRE_PCIERR_INO 0x30 +static void __init sabre_register_error_handlers(struct pci_controller_info *p) +{ + unsigned long base = p->controller_regs; + unsigned long irq, portid = p->portid; + u64 tmp; + + /* We clear the error bits in the appropriate AFSR before + * registering the handler so that we don't get spurious + * interrupts. + */ + sabre_write(base + SABRE_UE_AFSR, + (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | + SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | + SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); + irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_UE_INO); + if (request_irq(irq, sabre_ue_intr, + SA_SHIRQ, "SABRE UE", p) < 0) { + prom_printf("SABRE%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } + + sabre_write(base + SABRE_CE_AFSR, + (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | + SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); + irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_CE_INO); + if (request_irq(irq, sabre_ce_intr, + SA_SHIRQ, "SABRE CE", p) < 0) { + prom_printf("SABRE%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } + + irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_PCIERR_INO); + if (request_irq(irq, sabre_pcierr_intr, + SA_SHIRQ, "SABRE PCIERR", p) < 0) { + prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + tmp = sabre_read(base + SABRE_PCICTRL); + tmp |= SABRE_PCICTRL_ERREN; + sabre_write(base + SABRE_PCICTRL, tmp); +} + +static void __init sabre_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_controller_info *p = pcp->pbm->parent; + unsigned long base; + + if (res->flags & IORESOURCE_IO) + base = p->controller_regs + SABRE_IOSPACE; + else + base = p->controller_regs + SABRE_MEMSPACE; + + res->start += base; + res->end += base; +} + +static void __init sabre_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct pci_controller_info *p = pbm->parent; + struct resource *res = &pdev->resource[resource]; + unsigned long base; + u32 reg; + int where, size; + + if (res->flags & IORESOURCE_IO) + base = p->controller_regs + SABRE_IOSPACE; + else + base = p->controller_regs + SABRE_MEMSPACE; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - base)) & ~size)); + pci_write_config_dword(pdev, where, reg); +} + +static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) +{ + struct pci_dev *pdev; + u32 dword; + u16 word; + + for(pdev = pci_devices; pdev; pdev = pdev->next) { + if(pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_SABRE) { + sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); + break; + } + } + + for (pdev = sabre_bus->devices; pdev; pdev = pdev->sibling) { + if (pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { + sabre_read_word(pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | + PCI_COMMAND_IO; + sabre_write_word(pdev, PCI_COMMAND, word); + + /* Status register bits are "write 1 to clear". */ + sabre_write_word(pdev, PCI_STATUS, 0xffff); + sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff); + + sabre_read_word(pdev, PCI_BRIDGE_CONTROL, &word); + word = PCI_BRIDGE_CTL_MASTER_ABORT | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_PARITY; + sabre_write_word(pdev, PCI_BRIDGE_CONTROL, word); + + sabre_read_dword(pdev, APB_PCI_CONTROL_HIGH, &dword); + dword = APB_PCI_CTL_HIGH_SERR | + APB_PCI_CTL_HIGH_ARBITER_EN; + sabre_write_dword(pdev, APB_PCI_CONTROL_HIGH, dword); + + /* Systems with SIMBA are usually workstations, so + * we configure to park to SIMBA not to the previous + * bus owner. + */ + sabre_read_dword(pdev, APB_PCI_CONTROL_LOW, &dword); + dword = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; + sabre_write_dword(pdev, APB_PCI_CONTROL_LOW, dword); + + /* Don't mess with the retry limit and PIO/DMA latency + * timer settings. But do set primary and secondary + * latency timers. + */ + sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); + sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); + } + } +} + +static void __init sabre_scan_bus(struct pci_controller_info *p) +{ + static int once = 0; + struct pci_bus *sabre_bus, *pbus; + + /* Unlike for PSYCHO, we can only have one SABRE + * in a system. Having multiple SABREs is thus + * and error, and as a consequence we do not need + * to do any bus renumbering but we do have to have + * the pci_bus2pbm array setup properly. + * + * Also note that the SABRE host bridge is hardwired + * to live at bus 0. + */ + if (once != 0) { + prom_printf("SABRE: Multiple controllers unsupported.\n"); + prom_halt(); + } + once++; + + /* The pci_bus2pbm table has already been setup in sabre_init. */ + sabre_bus = pci_scan_bus(p->pci_first_busno, + p->pci_ops, + &p->pbm_A); + apb_init(p, sabre_bus); + + for (pbus = sabre_bus->children; pbus; pbus = pbus->next) { + struct pci_pbm_info *pbm; + + if (pbus->number == p->pbm_A.pci_first_busno) { + pbm = &p->pbm_A; + } else if (pbus->number == p->pbm_B.pci_first_busno) { + pbm = &p->pbm_B; + } else + continue; + + pbus->sysdata = pbm; + pbm->pci_bus = pbus; + pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbus); + pci_assign_unassigned(pbm, pbus); + pci_fixup_irq(pbm, pbus); + } + + sabre_register_error_handlers(p); +} + +static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize) +{ + struct linux_mlist_p1275 *mlist; + unsigned long tsbbase, i, n, order; + iopte_t *iopte; + u64 control; + + /* Invalidate TLB Entries. */ + control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); + control |= IOMMU_CTRL_DENAB; + sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); + + for(i = 0; i < 16; i++) + sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); + + control &= ~(IOMMU_CTRL_DENAB); + sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); + + for(order = 0;; order++) + if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) + break; + + tsbbase = __get_free_pages(GFP_DMA, order); + if (!tsbbase) { + prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); + prom_halt(); + } + iopte = (iopte_t *)tsbbase; + + /* Initialize to "none" settings. */ + for(i = 0; i < PCI_DVMA_HASHSZ; i++) { + pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; + pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; + } + + n = 0; + mlist = *prom_meminfo()->p1275_totphys; + while (mlist) { + unsigned long paddr = mlist->start_adr; + unsigned long num_bytes = mlist->num_bytes; + + if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) + goto next; + + if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) + num_bytes = + (((unsigned long) high_memory) - + PAGE_OFFSET) - paddr; + + /* Align base and length so we map whole hash table sized chunks + * at a time (and therefore full 64K IOMMU pages). + */ + paddr &= ~((1UL << 24UL) - 1); + num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); + + /* Move up the base for mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != + PCI_DVMA_HASH_NONE) { + paddr += (1UL << 24UL); + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Move down the size for tail mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != + PCI_DVMA_HASH_NONE) { + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Now map the rest. */ + for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { + iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K | + IOPTE_CACHE | IOPTE_WRITE) | + (paddr & IOPTE_PAGE)); + + if (!(n & 0xff)) + set_dvma_hash(paddr, (n << 16)); + + if (++n > (tsbsize * 1024)) + goto out; + + paddr += (1 << 16); + iopte++; + } + next: + mlist = mlist->theres_more; + } +out: + if (mlist) { + prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); + prom_printf("Try booting with mem=xxxM or similar\n"); + prom_halt(); + } + + sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); + + control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); + control &= ~(IOMMU_CTRL_TSBSZ); + control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); + switch(tsbsize) { + case 8: + pci_dvma_mask = 0x1fffffffUL; + control |= IOMMU_TSBSZ_8K; + break; + case 16: + pci_dvma_mask = 0x3fffffffUL; + control |= IOMMU_TSBSZ_16K; + break; + case 32: + pci_dvma_mask = 0x7fffffffUL; + control |= IOMMU_TSBSZ_32K; + break; + default: + prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); + prom_halt(); + break; + } + sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); +} + +static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + char *name = pbm->name; + unsigned long ibase = p->controller_regs + SABRE_IOSPACE; + unsigned long mbase = p->controller_regs + SABRE_MEMSPACE; + unsigned int devfn; + unsigned long first, last, i; + u8 *addr, map; + + sprintf(name, "SABRE%d PBM%c", + p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->io_space.name = pbm->mem_space.name = name; + + devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1); + addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP); + map = 0; + pci_config_read8(addr, &map); + + first = 8; + last = 0; + for (i = 0; i < 8; i++) { + if ((map & (1 << i)) != 0) { + if (first > i) + first = i; + if (last < i) + last = i; + } + } + pbm->io_space.start = ibase + (first << 21UL); + pbm->io_space.end = ibase + (last << 21UL) + ((1 << 21UL) - 1); + pbm->io_space.flags = IORESOURCE_IO; + + addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP); + map = 0; + pci_config_read8(addr, &map); + + first = 8; + last = 0; + for (i = 0; i < 8; i++) { + if ((map & (1 << i)) != 0) { + if (first > i) + first = i; + if (last < i) + last = i; + } + } + pbm->mem_space.start = mbase + (first << 29UL); + pbm->mem_space.end = mbase + (last << 29UL) + ((1 << 29UL) - 1); + pbm->mem_space.flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, &pbm->io_space) < 0) { + prom_printf("Cannot register PBM-%c's IO space.\n", + (pbm == &p->pbm_A ? 'A' : 'B')); + prom_halt(); + } + if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { + prom_printf("Cannot register PBM-%c's MEM space.\n", + (pbm == &p->pbm_A ? 'A' : 'B')); + prom_halt(); + } +} + +static void __init sabre_pbm_init(struct pci_controller_info *p, int sabre_node) +{ + char namebuf[128]; + u32 busrange[2]; + int node; + + node = prom_getchild(sabre_node); + while ((node = prom_searchsiblings(node, "pci")) != 0) { + struct pci_pbm_info *pbm; + int err; + + err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); + if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err)) + goto next_pci; + + err = prom_getproperty(node, "bus-range", + (char *)&busrange[0], sizeof(busrange)); + if (err == 0 || err == -1) { + prom_printf("APB: Error, cannot get PCI bus-range.\n"); + prom_halt(); + } + + if (busrange[0] == 1) + pbm = &p->pbm_B; + else + pbm = &p->pbm_A; + pbm->parent = p; + pbm->prom_node = node; + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + for (err = pbm->pci_first_busno; + err <= pbm->pci_last_busno; + err++) + pci_bus2pbm[err] = pbm; + + + prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name)); + err = prom_getproperty(node, "ranges", + (char *)pbm->pbm_ranges, + sizeof(pbm->pbm_ranges)); + if (err != -1) + pbm->num_pbm_ranges = + (err / sizeof(struct linux_prom_pci_ranges)); + else + pbm->num_pbm_ranges = 0; + + err = prom_getproperty(node, "interrupt-map", + (char *)pbm->pbm_intmap, + sizeof(pbm->pbm_intmap)); + if (err != -1) { + pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); + err = prom_getproperty(node, "interrupt-map-mask", + (char *)&pbm->pbm_intmask, + sizeof(pbm->pbm_intmask)); + if (err == -1) { + prom_printf("APB: Fatal error, no interrupt-map-mask.\n"); + prom_halt(); + } + } else { + pbm->num_pbm_intmap = 0; + memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); + } + + pbm_register_toplevel_resources(p, pbm); + + next_pci: + node = prom_getsibling(node); + if (!node) + break; + } +} + +void __init sabre_init(int pnode) +{ + struct linux_prom64_registers pr_regs[2]; + struct pci_controller_info *p; + unsigned long flags; + int tsbsize, err; + u32 busrange[2]; + u32 vdma[2]; + u32 upa_portid; + int bus; + + p = kmalloc(sizeof(*p), GFP_ATOMIC); + if (!p) { + prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); + prom_halt(); + } + + upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); + + memset(p, 0, sizeof(*p)); + + spin_lock_irqsave(&pci_controller_lock, flags); + p->next = pci_controller_root; + pci_controller_root = p; + spin_unlock_irqrestore(&pci_controller_lock, flags); + + p->portid = upa_portid; + p->index = pci_num_controllers++; + p->scan_bus = sabre_scan_bus; + p->irq_build = sabre_irq_build; + p->base_address_update = sabre_base_address_update; + p->resource_adjust = sabre_resource_adjust; + p->pci_ops = &sabre_ops; + + /* + * Map in SABRE register set and report the presence of this SABRE. + */ + err = prom_getproperty(pnode, "reg", + (char *)&pr_regs[0], sizeof(pr_regs)); + if(err == 0 || err == -1) { + prom_printf("SABRE: Error, cannot get U2P registers " + "from PROM.\n"); + prom_halt(); + } + + /* + * First REG in property is base of entire SABRE register space. + */ + p->controller_regs = pr_regs[0].phys_addr; + printk("PCI: Found SABRE, main regs at %016lx\n", p->controller_regs); + + /* Error interrupts are enabled later after the bus scan. */ + sabre_write(p->controller_regs + SABRE_PCICTRL, + (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR | + SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); + + /* Now map in PCI config space for entire SABRE. */ + p->config_space = p->controller_regs + SABRE_CONFIGSPACE; + printk("SABRE: PCI config space at %016lx\n", p->config_space); + + err = prom_getproperty(pnode, "virtual-dma", + (char *)&vdma[0], sizeof(vdma)); + if(err == 0 || err == -1) { + prom_printf("SABRE: Error, cannot get virtual-dma property " + "from PROM.\n"); + prom_halt(); + } + + switch(vdma[1]) { + case 0x20000000: + tsbsize = 8; + break; + case 0x40000000: + tsbsize = 16; + break; + case 0x80000000: + tsbsize = 32; + break; + default: + prom_printf("SABRE: strange virtual-dma size.\n"); + prom_halt(); + } + + pci_dvma_offset = vdma[0]; + sabre_iommu_init(p, tsbsize); + + printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); + + err = prom_getproperty(pnode, "bus-range", + (char *)&busrange[0], sizeof(busrange)); + if(err == 0 || err == -1) { + prom_printf("SABRE: Error, cannot get PCI bus-range " + " from PROM.\n"); + prom_halt(); + } + + p->pci_first_busno = busrange[0]; + p->pci_last_busno = busrange[1]; + + /* + * Handle config space reads through any Simba on APB. + */ + for (bus = p->pci_first_busno; bus <= p->pci_last_busno; bus++) + pci_bus2pbm[bus] = &p->pbm_A; + + /* + * Look for APB underneath. + */ + sabre_pbm_init(p, pnode); +} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/power.c linux/arch/sparc64/kernel/power.c --- v2.3.15/linux/arch/sparc64/kernel/power.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/power.c Tue Aug 31 11:23:30 1999 @@ -0,0 +1,105 @@ +/* $Id: power.c,v 1.2 1999/08/31 04:39:38 davem Exp $ + * power.c: Power management driver. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define __KERNEL_SYSCALLS__ +#include + +#ifdef CONFIG_PCI +static unsigned long power_reg = 0UL; +#define POWER_SYSTEM_OFF (1 << 0) +#define POWER_COURTESY_OFF (1 << 1) + +static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); +static int button_pressed = 0; + +static void power_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if (button_pressed == 0) { + wake_up(&powerd_wait); + button_pressed = 1; + } +} +#endif /* CONFIG_PCI */ + +extern void machine_halt(void); + +void machine_power_off(void) +{ +#ifdef CONFIG_PCI + if (power_reg != 0UL) { + /* Both register bits seem to have the + * same effect, so until I figure out + * what the difference is... + */ + writel(POWER_COURTESY_OFF | POWER_SYSTEM_OFF, power_reg); + } +#endif /* CONFIG_PCI */ + machine_halt(); +} + +#ifdef CONFIG_PCI +static int powerd(void *__unused) +{ + static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { "/usr/bin/shutdown", "-h", "now", NULL }; + + current->session = 1; + current->pgrp = 1; + sprintf(current->comm, "powerd"); + +again: + while(button_pressed == 0) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + interruptible_sleep_on(&powerd_wait); + } + + /* Ok, down we go... */ + if (execve("/usr/bin/shutdown", argv, envp) < 0) { + printk("powerd: shutdown execution failed\n"); + button_pressed = 0; + goto again; + } + return 0; +} + +void __init power_init(void) +{ + struct linux_ebus *ebus; + struct linux_ebus_device *edev; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "power")) + goto found; + } + } + return; + +found: + power_reg = edev->resource[0].start; + printk("power: Control reg at %016lx ... ", power_reg); + if (kernel_thread(powerd, 0, CLONE_FS) < 0) { + printk("Failed to start power daemon.\n"); + return; + } + printk("powerd running.\n"); + if (request_irq(edev->irqs[0], + power_handler, SA_SHIRQ, "power", + (void *) power_reg) < 0) + printk("power: Error, cannot register IRQ handler.\n"); +} +#endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.3.15/linux/arch/sparc64/kernel/process.c Wed Aug 4 15:39:46 1999 +++ linux/arch/sparc64/kernel/process.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.99 1999/08/04 03:19:20 davem Exp $ +/* $Id: process.c,v 1.100 1999/08/31 04:39:39 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -141,11 +141,6 @@ prom_reboot(reboot_command); prom_reboot(""); panic("Reboot failed!"); -} - -void machine_power_off(void) -{ - machine_halt(); } static void show_regwindow32(struct pt_regs *regs) diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c --- v2.3.15/linux/arch/sparc64/kernel/psycho.c Fri Aug 6 11:58:00 1999 +++ linux/arch/sparc64/kernel/psycho.c Wed Dec 31 16:00:00 1969 @@ -1,2905 +0,0 @@ -/* $Id: psycho.c,v 1.89 1999/08/06 10:37:35 davem 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) - * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) - */ - -#include -#include -#include -#include -#include -#include - -#include -#include /* for sanity check... */ -#include -#include - -#undef PROM_DEBUG -#undef FIXUP_REGS_DEBUG -#undef FIXUP_IRQ_DEBUG -#undef FIXUP_VMA_DEBUG -#undef PCI_COOKIE_DEBUG - -#ifdef PROM_DEBUG -#define dprintf prom_printf -#else -#define dprintf printk -#endif - -unsigned long pci_dvma_offset = 0x00000000UL; -unsigned long pci_dvma_mask = 0xffffffffUL; - -#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL -unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; -unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; - -#ifndef CONFIG_PCI - -int pcibios_present(void) -{ - return 0; -} - -asmlinkage int sys_pciconfig_read(unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf) -{ - return 0; -} - -asmlinkage int sys_pciconfig_write(unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf) -{ - return 0; -} - -#else - -#include -#include -#include - -#include -#include -#include -#include - -#define PSYCHO_REORDER_ONBOARDFIRST 1 - -struct linux_psycho *psycho_root = NULL; -int linux_num_psycho = 0; -static struct linux_pbm_info *bus2pbm[256]; -static int psycho_reorder __initdata = 0; - -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. - * After that we leave it on of course. - */ -static int pci_probe_enable = 0; - -static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr) -{ - unsigned long dvma_addr = pci_dvma_offset + daddr; - unsigned long vaddr = (unsigned long)__va(paddr); - - pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr; - pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr; -} - -static void __init psycho_iommu_init(struct linux_psycho *psycho, int tsbsize) -{ - extern int this_is_starfire; - extern void *starfire_hookup(int); - struct linux_mlist_p1275 *mlist; - unsigned long tsbbase; - unsigned long control, i, n; - unsigned long *iopte; - unsigned long order; - - /* - * 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; - - for(order = 0;; order++) { - if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) - break; - } - tsbbase = __get_free_pages(GFP_DMA, order); - if (!tsbbase) { - prom_printf("IOMMU: Error, kmalloc(tsb) failed.\n"); - prom_halt(); - } - iopte = (unsigned long *)tsbbase; - - /* Initialize to "none" settings. */ - for(i = 0; i < PCI_DVMA_HASHSZ; i++) { - pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; - pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; - } - - n = 0; - mlist = *prom_meminfo()->p1275_totphys; - while (mlist) { - unsigned long paddr = mlist->start_adr; - unsigned long num_bytes = mlist->num_bytes; - - if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) - goto next; - - if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) - num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr; - - /* Align base and length so we map whole hash table sized chunks - * at a time (and therefore full 64K IOMMU pages). - */ - paddr &= ~((1UL << 24UL) - 1); - num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); - - /* Move up the base for mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != - PCI_DVMA_HASH_NONE) { - paddr += (1UL << 24UL); - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Move down the size for tail mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != - PCI_DVMA_HASH_NONE) { - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Now map the rest. */ - for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { - *iopte = (IOPTE_VALID | IOPTE_64K | - IOPTE_CACHE | IOPTE_WRITE); - *iopte |= paddr; - - if (!(n & 0xff)) - set_dvma_hash(paddr, (n << 16)); - - if (++n > (tsbsize * 1024)) - goto out; - - paddr += (1 << 16); - iopte++; - } - next: - mlist = mlist->theres_more; - } -out: - if (mlist) { - prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); - prom_printf("Try booting with mem=xxxM or similar\n"); - prom_halt(); - } - - psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase); - - control = psycho->psycho_regs->iommu_control; - control &= ~(IOMMU_CTRL_TSBSZ); - control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); - switch(tsbsize) { - case 8: - pci_dvma_mask = 0x1fffffffUL; - control |= IOMMU_TSBSZ_8K; - break; - case 16: - pci_dvma_mask = 0x3fffffffUL; - control |= IOMMU_TSBSZ_16K; - break; - case 32: - pci_dvma_mask = 0x7fffffffUL; - control |= IOMMU_TSBSZ_32K; - break; - default: - prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); - prom_halt(); - break; - } - psycho->psycho_regs->iommu_control = control; - - /* If necessary, hook us up for starfire IRQ translations. */ - if(this_is_starfire) - psycho->starfire_cookie = starfire_hookup(psycho->upa_portid); - else - psycho->starfire_cookie = NULL; -} - -extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm); -extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm); - -/* - * Poor man's PCI... - */ -void __init sabre_init(int pnode) -{ - struct linux_prom64_registers pr_regs[2]; - struct linux_psycho *sabre; - unsigned long ctrl; - int tsbsize, node, err; - u32 busrange[2]; - u32 vdma[2]; - u32 portid; - int bus; - - sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); - if (!sabre) { - prom_printf("SABRE: Error, kmalloc(sabre) failed.\n"); - prom_halt(); - } - - portid = prom_getintdefault(pnode, "upa-portid", 0xff); - - memset(sabre, 0, sizeof(*sabre)); - - sabre->next = psycho_root; - psycho_root = sabre; - - sabre->upa_portid = portid; - sabre->index = linux_num_psycho++; - - /* - * Map in SABRE register set and report the presence of this SABRE. - */ - err = prom_getproperty(pnode, "reg", - (char *)&pr_regs[0], sizeof(pr_regs)); - if(err == 0 || err == -1) { - prom_printf("SABRE: Error, cannot get U2P registers " - "from PROM.\n"); - prom_halt(); - } - - /* - * First REG in property is base of entire SABRE register space. - */ - sabre->psycho_regs = - sparc_alloc_io((pr_regs[0].phys_addr & 0xffffffff), - NULL, sizeof(struct psycho_regs), - "SABRE Registers", - (pr_regs[0].phys_addr >> 32), 0); - if(sabre->psycho_regs == NULL) { - prom_printf("SABRE: Error, cannot map SABRE main registers.\n"); - prom_halt(); - } - - printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n", - sabre->psycho_regs, sabre->psycho_regs->control); -#ifdef PROM_DEBUG - dprintf("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n", - sabre->psycho_regs, sabre->psycho_regs->control); -#endif - - ctrl = sabre->psycho_regs->pci_a_control; - ctrl = (1UL << 36) | (1UL << 34) | (1UL << 21) | (1UL << 8) | 0x0fUL; - sabre->psycho_regs->pci_a_control = ctrl; - - /* Now map in PCI config space for entire SABRE. */ - sabre->pci_config_space = - sparc_alloc_io(((pr_regs[0].phys_addr & 0xffffffff) - + 0x01000000), - NULL, 0x01000000, - "PCI Config Space", - (pr_regs[0].phys_addr >> 32), 0); - if(sabre->pci_config_space == NULL) { - prom_printf("SABRE: Error, cannot map PCI config space.\n"); - prom_halt(); - } - - /* Report some more info. */ - printk("SABRE: PCI config space at %p\n", sabre->pci_config_space); -#ifdef PROM_DEBUG - dprintf("SABRE: PCI config space at %p\n", sabre->pci_config_space); -#endif - - err = prom_getproperty(pnode, "virtual-dma", - (char *)&vdma[0], sizeof(vdma)); - if(err == 0 || err == -1) { - prom_printf("SABRE: Error, cannot get virtual-dma property " - "from PROM.\n"); - prom_halt(); - } - - switch(vdma[1]) { - case 0x20000000: - tsbsize = 8; - break; - case 0x40000000: - tsbsize = 16; - break; - case 0x80000000: - tsbsize = 32; - break; - default: - prom_printf("SABRE: strange virtual-dma size.\n"); - prom_halt(); - } - - pci_dvma_offset = vdma[0]; - psycho_iommu_init(sabre, tsbsize); - - printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); -#ifdef PROM_DEBUG - dprintf("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); -#endif - - err = prom_getproperty(pnode, "bus-range", - (char *)&busrange[0], sizeof(busrange)); - if(err == 0 || err == -1) { - prom_printf("SIMBA: Error, cannot get PCI bus-range " - " from PROM.\n"); - prom_halt(); - } - - sabre->pci_first_busno = busrange[0]; - sabre->pci_last_busno = busrange[1]; - sabre->pci_bus = &pci_root; - - /* - * Handle config space reads through any Simba on APB. - */ - for (bus = sabre->pci_first_busno; bus <= sabre->pci_last_busno; bus++) - bus2pbm[bus] = &sabre->pbm_A; - - /* - * Look for APB underneath. - */ - node = prom_getchild(pnode); - while ((node = prom_searchsiblings(node, "pci"))) { - struct linux_pbm_info *pbm; - char namebuf[128]; - - err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); - if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err)) - goto next_pci; - - err = prom_getproperty(node, "bus-range", - (char *)&busrange[0], sizeof(busrange)); - if(err == 0 || err == -1) { - prom_printf("SIMBA: Error, cannot get PCI bus-range " - " from PROM.\n"); - prom_halt(); - } - - if (busrange[0] == 1) - pbm = &sabre->pbm_B; - else - pbm = &sabre->pbm_A; - - pbm->parent = sabre; - pbm->IO_assignments = NULL; - pbm->MEM_assignments = NULL; - pbm->prom_node = node; - - prom_getstring(node, "name", namebuf, sizeof(namebuf)); - strcpy(pbm->prom_name, namebuf); - - /* Now the ranges. */ - prom_pbm_ranges_init(pnode, pbm); - prom_pbm_intmap_init(node, pbm); - - pbm->pci_first_busno = busrange[0]; - pbm->pci_last_busno = busrange[1]; - memset(&pbm->pci_bus, 0, sizeof(struct pci_bus)); - - for (bus = pbm->pci_first_busno; - bus <= pbm->pci_last_busno; bus++) - bus2pbm[bus] = pbm; - - next_pci: - node = prom_getsibling(node); - if (!node) - break; - } -} - -static __inline__ int -apb_present(struct linux_psycho *psycho) -{ - return psycho->pci_bus ? 1 : 0; -} - -void __init pcibios_init(void) -{ - struct linux_prom64_registers pr_regs[3]; - struct linux_psycho *psycho; - char namebuf[128]; - u32 portid; - int node; - - printk("PCI: Probing for controllers.\n"); -#ifdef PROM_DEBUG - dprintf("PCI: Probing for controllers.\n"); -#endif - - node = prom_getchild(prom_root_node); - while((node = prom_searchsiblings(node, "pci")) != 0) { - struct linux_psycho *search; - struct linux_pbm_info *pbm = NULL; - u32 busrange[2]; - int err, is_pbm_a; - - err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); - if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) { - sabre_init(node); - goto next_pci; - } - - portid = prom_getintdefault(node, "upa-portid", 0xff); - for(search = psycho_root; search; search = search->next) { - if(search->upa_portid == portid) { - psycho = search; - - /* This represents _this_ instance, so it's - * which ever one does _not_ have the prom node - * info filled in yet. - */ - is_pbm_a = (psycho->pbm_A.prom_node == 0); - goto other_pbm; - } - } - - psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); - if (!psycho) { - prom_printf("PSYCHO: Error, kmalloc(psycho) failed.\n"); - prom_halt(); - } - memset(psycho, 0, sizeof(*psycho)); - - psycho->next = psycho_root; - psycho_root = psycho; - - psycho->upa_portid = portid; - psycho->index = linux_num_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) { - prom_printf("PSYCHO: Error, cannot get U2P registers " - "from PROM.\n"); - prom_halt(); - } - - /* - * 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", - (pr_regs[2].phys_addr >> 32), 0); - if(psycho->psycho_regs == NULL) { - prom_printf("PSYCHO: Error, cannot map PSYCHO " - "main registers.\n"); - prom_halt(); - } - - printk("PCI: Found PSYCHO, main regs at %p\n", - psycho->psycho_regs); -#ifdef PROM_DEBUG - dprintf("PCI: Found PSYCHO, main regs at %p\n", - psycho->psycho_regs); -#endif - - psycho->psycho_regs->irq_retry = 0xff; - - /* Now map in PCI config space for entire PSYCHO. */ - psycho->pci_config_space = - sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff) - + 0x01000000), - NULL, 0x01000000, - "PCI Config Space", - (pr_regs[2].phys_addr >> 32), 0); - if(psycho->pci_config_space == NULL) { - prom_printf("PSYCHO: Error, cannot map PCI config space.\n"); - prom_halt(); - } - - /* Report some more info. */ - 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 - - pci_dvma_offset = 0x80000000UL; - psycho_iommu_init(psycho, 32); - - is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); - - /* Enable arbitration for all PCI slots. */ - psycho->psycho_regs->pci_a_control |= PSYCHO_PCICTRL_AEN; - psycho->psycho_regs->pci_b_control |= PSYCHO_PCICTRL_AEN; - - /* Disable DMA write / PIO rd synchronization on both - * PCI bus segments. - */ - psycho->psycho_regs->pci_a_diag |= PSYCHO_PCIDIAG_DDWSYNC; - psycho->psycho_regs->pci_b_diag |= PSYCHO_PCIDIAG_DDWSYNC; - - other_pbm: - if(is_pbm_a) - pbm = &psycho->pbm_A; - else - pbm = &psycho->pbm_B; - - pbm->parent = psycho; - pbm->IO_assignments = NULL; - pbm->MEM_assignments = NULL; - pbm->prom_node = node; - - prom_getstring(node, "name", namebuf, sizeof(namebuf)); - strcpy(pbm->prom_name, namebuf); - - /* Now the ranges. */ - prom_pbm_ranges_init(node, pbm); - prom_pbm_intmap_init(node, pbm); - - /* Finally grab the pci bus root array for this pbm after - * having found the bus range existing under it. - */ - err = prom_getproperty(node, "bus-range", - (char *)&busrange[0], sizeof(busrange)); - if(err == 0 || err == -1) { - prom_printf("PSYCHO: Error, cannot get PCI bus range.\n"); - prom_halt(); - } - pbm->pci_first_busno = busrange[0]; - pbm->pci_last_busno = busrange[1]; - memset(&pbm->pci_bus, 0, sizeof(struct pci_bus)); - - next_pci: - node = prom_getsibling(node); - if(!node) - break; - } -} - -int pcibios_present(void) -{ - return psycho_root != NULL; -} - -static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm, - unsigned long start, - unsigned int offset, int io) -{ - struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments); - - while (vp) { - if (offset && (vp->offset != offset)) - goto next; - if (vp->end >= start) - break; - next: - vp = vp->next; - } - return vp; -} - -static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new, int io) -{ - struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments); - - if(!vp) { - new->next = NULL; - if(io) - pbm->IO_assignments = new; - else - pbm->MEM_assignments = new; - } else { - struct pci_vma *prev = NULL; - - while(vp && (vp->end < new->end)) { - prev = vp; - vp = vp->next; - } - new->next = vp; - if(!prev) { - if(io) - pbm->IO_assignments = new; - else - pbm->MEM_assignments = new; - } else { - prev->next = new; - } - - /* Check for programming errors. */ - if(vp && - ((vp->start >= new->start && vp->start < new->end) || - (vp->end >= new->start && vp->end < new->end))) { - prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n", - io ? "IO" : "MEM"); - prom_printf("pci_add_vma: vp[%016lx:%016lx] " - "new[%016lx:%016lx]\n", - vp->start, vp->end, - new->start, new->end); - } - } -} - -static inline struct pci_vma *pci_vma_alloc(void) -{ - return kmalloc(sizeof(struct pci_vma), GFP_ATOMIC); -} - -static inline struct pcidev_cookie *pci_devcookie_alloc(void) -{ - return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC); -} - - -static void __init -pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus) -{ - unsigned int devfn, l, class; - unsigned char hdr_type = 0; - int is_multi = 0; - - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) != 0 && is_multi == 0) { - /* not a multi-function device */ - continue; - } - pbm_read_config_byte(pbm, bus, devfn, - PCI_HEADER_TYPE, &hdr_type); - if (PCI_FUNC(devfn) == 0) - is_multi = hdr_type & 0x80; - - /* Check if there is anything here. */ - pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l); - if (l == 0xffffffff || l == 0x00000000 || - l == 0x0000ffff || l == 0xffff0000) { - is_multi = 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 __init 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 __init apb_init(struct linux_psycho *sabre) -{ - struct pci_dev *pdev; - unsigned short stmp; - unsigned int itmp; - -#if 0 - for(pdev = pci_devices; pdev; pdev = pdev->next) { - if(pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_SABRE) { - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); - break; - } - } -#endif - for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) { - if (pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { - pci_read_config_word(pdev, PCI_COMMAND, &stmp); - stmp |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | - PCI_COMMAND_IO; - pci_write_config_word(pdev, PCI_COMMAND, stmp); - - /* Status register bits are "write 1 to clear". */ - pci_write_config_word(pdev, PCI_STATUS, 0xffff); - pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff); - - pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp); - stmp = PCI_BRIDGE_CTL_MASTER_ABORT | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_PARITY; - pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp); - - pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp); - itmp = APB_PCI_CTL_HIGH_SERR | - APB_PCI_CTL_HIGH_ARBITER_EN; - pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp); - - /* Systems with SIMBA are usually workstations, so - * we configure to park to SIMBA not to the previous - * bus owner. - */ - pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp); - itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; - pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp); -#if 0 - /* Don't mess with the retry limit and PIO/DMA latency - * timer settings. But do set primary and secondary - * latency timers. - */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); - pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); -#endif - } - } -} - -extern struct pci_bus pci_root; -extern struct pci_dev *pci_devices; -static struct pci_dev **pci_last_dev_p = &pci_devices; -extern int pci_reverse; - -extern void pci_namedevice(struct pci_dev *); - -static void __init sparc64_pci_read_bases(struct pci_dev *dev, unsigned int howmany) -{ - unsigned int reg; - u32 l; - - for(reg=0; reg < howmany; reg++) { - struct resource *res = dev->resource + reg; - unsigned long mask; - unsigned int newval, size; - - res->name = dev->name; - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l); - if (l == 0xffffffff) - continue; - - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), 0xffffffff); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &newval); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), l); - - mask = PCI_BASE_ADDRESS_MEM_MASK; - if (l & PCI_BASE_ADDRESS_SPACE_IO) - mask = PCI_BASE_ADDRESS_IO_MASK; - - newval &= mask; - if (!newval) - continue; - - res->start = l & mask; - res->flags = l & ~mask; - - size = 1; - do { - size <<= 1; - } while (!(size & newval)); - - /* 64-bit memory? */ - if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) - == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { - unsigned int high; - reg++; - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &high); - if (high) - res->start |= ((unsigned long) high) << 32; - } - res->end = res->start + size - 1; - } -} - -static unsigned int __init sparc64_pci_scan_bus(struct pci_bus *bus) -{ - unsigned int devfn, l, max, class; - unsigned char cmd, irq, tmp, hdr_type, is_multi = 0; - struct pci_dev *dev, **bus_last; - struct pci_bus *child; - - bus_last = &bus->devices; - max = bus->secondary; - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) && !is_multi) { - /* not a multi-function device */ - continue; - } - if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type)) - continue; - if (!PCI_FUNC(devfn)) - is_multi = hdr_type & 0x80; - - if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) || - /* some broken boards return 0 if a slot is empty: */ - l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) - continue; - - dev = kmalloc(sizeof(*dev), GFP_ATOMIC); - if(dev==NULL) - { - printk(KERN_ERR "pci: out of memory.\n"); - continue; - } - memset(dev, 0, sizeof(*dev)); - dev->bus = bus; - dev->devfn = devfn; - dev->vendor = l & 0xffff; - dev->device = (l >> 16) & 0xffff; - pci_namedevice(dev); - - /* non-destructively determine if device can be a master: */ - pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd); - pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); - pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp); - dev->master = ((tmp & PCI_COMMAND_MASTER) != 0); - pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd); - - pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class); - class >>= 8; /* upper 3 bytes */ - dev->class = class; - class >>= 8; - dev->hdr_type = hdr_type; - - switch (hdr_type & 0x7f) { /* header type */ - case PCI_HEADER_TYPE_NORMAL: /* standard header */ - if (class == PCI_CLASS_BRIDGE_PCI) - goto bad; - /* - * If the card generates interrupts, read IRQ number - * (some architectures change it during pcibios_fixup()) - */ - pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq); - if (irq) - pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq); - dev->irq = irq; - sparc64_pci_read_bases(dev, 6); - pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l); - dev->rom_address = (l == 0xffffffff) ? 0 : l; - break; - case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ - if (class != PCI_CLASS_BRIDGE_PCI) - goto bad; - sparc64_pci_read_bases(dev, 2); - pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l); - dev->rom_address = (l == 0xffffffff) ? 0 : l; - break; - case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ - if (class != PCI_CLASS_BRIDGE_CARDBUS) - goto bad; - sparc64_pci_read_bases(dev, 1); - break; - default: /* unknown header */ - bad: - printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n", - bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type); - continue; - } - - /* - * Put it into the global PCI device chain. It's used to - * find devices once everything is set up. - */ - if (!pci_reverse) { - *pci_last_dev_p = dev; - pci_last_dev_p = &dev->next; - } else { - dev->next = pci_devices; - pci_devices = dev; - } - - /* - * Now insert it into the list of devices held - * by the parent bus. - */ - *bus_last = dev; - bus_last = &dev->sibling; - } - - /* - * After performing arch-dependent fixup of the bus, look behind - * all PCI-to-PCI bridges on this bus. - */ - pcibios_fixup_bus(bus); - for(dev=bus->devices; dev; dev=dev->sibling) - /* - * If it's a bridge, scan the bus behind it. - */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - unsigned int buses; - unsigned int devfn = dev->devfn; - unsigned short cr; - - /* - * Insert it into the tree of buses. - */ - child = kmalloc(sizeof(*child), GFP_ATOMIC); - if(child==NULL) - { - printk(KERN_ERR "pci: out of memory for bridge.\n"); - continue; - } - memset(child, 0, sizeof(*child)); - child->next = bus->children; - bus->children = child; - child->self = dev; - child->parent = bus; - - /* - * Set up the primary, secondary and subordinate - * bus numbers. - */ - child->number = child->secondary = ++max; - child->primary = bus->secondary; - child->subordinate = 0xff; - /* - * Clear all status bits and turn off memory, - * I/O and master enables. - */ - pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr); - pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000); - pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff); - /* - * Read the existing primary/secondary/subordinate bus - * number configuration to determine if the PCI bridge - * has already been configured by the system. If so, - * do not modify the configuration, merely note it. - */ - pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses); - if ((buses & 0xFFFFFF) != 0) - { - unsigned int cmax; - - child->primary = buses & 0xFF; - child->secondary = (buses >> 8) & 0xFF; - child->subordinate = (buses >> 16) & 0xFF; - child->number = child->secondary; - cmax = sparc64_pci_scan_bus(child); - if (cmax > max) max = cmax; - } - else - { - /* - * Configure the bus numbers for this bridge: - */ - buses &= 0xff000000; - buses |= - (((unsigned int)(child->primary) << 0) | - ((unsigned int)(child->secondary) << 8) | - ((unsigned int)(child->subordinate) << 16)); - pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); - /* - * Now we can scan all subordinate buses: - */ - max = sparc64_pci_scan_bus(child); - /* - * Set the subordinate bus number to its real - * value: - */ - child->subordinate = max; - buses = (buses & 0xff00ffff) - | ((unsigned int)(child->subordinate) << 16); - pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); - } - pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr); - } - - /* - * We've scanned the bus and so we know all about what's on - * the other side of any bridges that may be on this bus plus - * any devices. - * - * Return how far we've got finding sub-buses. - */ - return max; -} - -static void __init sabre_probe(struct linux_psycho *sabre) -{ - struct pci_bus *pbus = sabre->pci_bus; - static unsigned char busno = 0; - - pbus->number = pbus->secondary = busno; - pbus->sysdata = sabre; - - pbus->subordinate = sparc64_pci_scan_bus(pbus); - busno = pbus->subordinate + 1; - - for(pbus = pbus->children; pbus; pbus = pbus->next) { - if (pbus->number == sabre->pbm_A.pci_first_busno) - memcpy(&sabre->pbm_A.pci_bus, pbus, sizeof(*pbus)); - if (pbus->number == sabre->pbm_B.pci_first_busno) - memcpy(&sabre->pbm_B.pci_bus, pbus, sizeof(*pbus)); - } - - apb_init(sabre); -} - - -static void __init pbm_probe(struct linux_pbm_info *pbm) -{ - 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 = pbus->secondary = busno; - pbus->sysdata = pbm; - - pbm_fixup_busno(pbm, busno); - - pbus->subordinate = sparc64_pci_scan_bus(pbus); - - /* - * 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 __init pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - int pnode) -{ - struct linux_prom_pci_registers pregs[PROMREG_MAX]; - int node; - int err; - - node = prom_getchild(pnode); - while (node) { - - err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs)); - if(err != 0 && err != -1) { - u32 devfn = (pregs[0].phys_hi >> 8) & 0xff; - - if(devfn == pdev->devfn) - return node; /* Match */ - } - - node = prom_getsibling(node); - } - return 0; -} - -static void __init pdev_cookie_fillin(struct linux_pbm_info *pbm, - struct pci_dev *pdev, int pnode) -{ - struct pcidev_cookie *pcp; - int node; - - node = pdev_to_pnode_sibtraverse(pbm, pdev, pnode); - if(node == 0) - node = -1; - pcp = pci_devcookie_alloc(); - pcp->pbm = pbm; - pcp->prom_node = node; - pdev->sysdata = pcp; -#ifdef PCI_COOKIE_DEBUG - dprintf("pdev_cookie_fillin: pdev [%02x.%02x]: pbm %p, node %x\n", - pdev->bus->number, pdev->devfn, pbm, node); -#endif -} - -static void __init fill_in_pbm_cookies(struct pci_bus *pbus, - struct linux_pbm_info *pbm, - int node) -{ - struct pci_dev *pdev; - - pbus->sysdata = pbm; - -#ifdef PCI_COOKIE_DEBUG - dprintf("fill_in_pbm_cookies: pbus [%02x]: pbm %p\n", - pbus->number, pbm); -#endif - - for(pdev = pbus->devices; pdev; pdev = pdev->sibling) - pdev_cookie_fillin(pbm, pdev, node); - - for(pbus = pbus->children; pbus; pbus = pbus->next) { - struct pcidev_cookie *pcp = pbus->self->sysdata; - fill_in_pbm_cookies(pbus, pbm, pcp->prom_node); - } -} - -static void __init sabre_cookie_fillin(struct linux_psycho *sabre) -{ - struct pci_bus *pbus = sabre->pci_bus; - - for(pbus = pbus->children; pbus; pbus = pbus->next) { - if (pbus->number == sabre->pbm_A.pci_first_busno) - pdev_cookie_fillin(&sabre->pbm_A, pbus->self, - sabre->pbm_A.prom_node); - else if (pbus->number == sabre->pbm_B.pci_first_busno) - pdev_cookie_fillin(&sabre->pbm_B, pbus->self, - sabre->pbm_B.prom_node); - } -} - -/* Walk PROM device tree under PBM, looking for 'assigned-address' - * properties, and recording them in pci_vma's linked in via - * PBM->assignments. - */ -static int __init gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs) -{ - struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX]; - int err, iter; - - err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng)); - if(err == 0 || err == -1) { - prom_printf("EBUS: fatal error, no range property.\n"); - prom_halt(); - } - err = (err / sizeof(struct linux_prom_ebus_ranges)); - for(iter = 0; iter < err; iter++) { - struct linux_prom_ebus_ranges *ep = &erng[iter]; - struct linux_prom_pci_registers *ap = &aregs[iter]; - - ap->phys_hi = ep->parent_phys_hi; - ap->phys_mid = ep->parent_phys_mid; - ap->phys_lo = ep->parent_phys_lo; - - ap->size_hi = 0; - ap->size_lo = ep->size; - } - return err; -} - -static void __init assignment_process(struct linux_pbm_info *pbm, int node) -{ - struct linux_prom_pci_registers aregs[PROMREG_MAX]; - char pname[256]; - int err, iter, numa; - - err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname)); - if (err > 0) - pname[err] = 0; -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: %s\n", __FUNCTION__, err > 0 ? pname : "???"); -#endif - if(strcmp(pname, "ebus") == 0) { - numa = gimme_ebus_assignments(node, &aregs[0]); - } else { - err = prom_getproperty(node, "assigned-addresses", - (char *)&aregs[0], sizeof(aregs)); - - /* No assignments, nothing to do. */ - if(err == 0 || err == -1) - return; - - numa = (err / sizeof(struct linux_prom_pci_registers)); - } - - for(iter = 0; iter < numa; iter++) { - struct linux_prom_pci_registers *ap = &aregs[iter]; - struct pci_vma *vp; - int space, breg, io; - - space = (ap->phys_hi >> 24) & 3; - if(space != 1 && space != 2) - continue; - io = (space == 1); - - breg = (ap->phys_hi & 0xff); - - vp = pci_vma_alloc(); - - /* XXX Means we don't support > 32-bit range of - * XXX PCI MEM space, PSYCHO/PBM does not support it - * XXX either due to it's layout so... - */ - vp->start = ap->phys_lo; - vp->end = vp->start + ap->size_lo - 1; - vp->offset = (ap->phys_hi & 0xffffff); - - pci_add_vma(pbm, vp, io); - -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: BaseReg %02x", pname, breg); - dprintf(" %s vma [%08x,%08x]\n", - io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end); -#endif - } -} - -static void __init assignment_walk_siblings(struct linux_pbm_info *pbm, int node) -{ - while(node) { - int child = prom_getchild(node); - if(child) - assignment_walk_siblings(pbm, child); - - assignment_process(pbm, node); - - node = prom_getsibling(node); - } -} - -static inline void record_assignments(struct linux_pbm_info *pbm) -{ - struct pci_vma *vp; - - if (apb_present(pbm->parent)) { - /* - * Disallow anything that is not in our IO/MEM map on SIMBA. - */ - struct pci_bus *pbus = pbm->parent->pci_bus; - struct pci_dev *pdev; - unsigned char map; - int bit; - - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { - struct pcidev_cookie *pcp = pdev->sysdata; - if (!pcp) - continue; - if (pcp->pbm == pbm) - break; - } - - if (!pdev) { - prom_printf("record_assignments: no pdev for PBM\n"); - prom_halt(); - } - - pci_read_config_byte(pdev, APB_IO_ADDRESS_MAP, &map); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: IO %02x\n", __FUNCTION__, map); -#endif - for (bit = 0; bit < 8; bit++) { - if (!(map & (1 << bit))) { - vp = pci_vma_alloc(); - vp->start = (bit << 21); - vp->end = vp->start + (1 << 21) - 1; - vp->offset = 0; - pci_add_vma(pbm, vp, 1); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: IO prealloc vma [%08x,%08x]\n", - __FUNCTION__, vp->start, vp->end); -#endif - } - } - pci_read_config_byte(pdev, APB_MEM_ADDRESS_MAP, &map); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: MEM %02x\n", __FUNCTION__, map); -#endif - for (bit = 0; bit < 8; bit++) { - if (!(map & (1 << bit))) { - vp = pci_vma_alloc(); - vp->start = (bit << 29); - vp->end = vp->start + (1 << 29) - 1; - vp->offset = 0; - pci_add_vma(pbm, vp, 0); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: MEM prealloc vma [%08x,%08x]\n", - __FUNCTION__, vp->start, vp->end); -#endif - } - } - } - - assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node)); - - /* - * Protect ISA IO space from being used. - */ - vp = pci_find_vma(pbm, 0, 0, 1); - if (!vp || 0x400 <= vp->start) { - vp = pci_vma_alloc(); - vp->start = 0; - vp->end = vp->start + 0x400 - 1; - vp->offset = 0; - pci_add_vma(pbm, vp, 1); - } - -#ifdef FIXUP_VMA_DEBUG - dprintf("PROM IO assignments for PBM %s:\n", - pbm == &pbm->parent->pbm_A ? "A" : "B"); - vp = pbm->IO_assignments; - while (vp) { - dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end, - vp->offset ? "Register" : "Unmapped"); - vp = vp->next; - } - dprintf("PROM MEM assignments for PBM %s:\n", - pbm == &pbm->parent->pbm_A ? "A" : "B"); - vp = pbm->MEM_assignments; - while (vp) { - dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end, - vp->offset ? "Register" : "Unmapped"); - vp = vp->next; - } -#endif -} - -static void __init fixup_regs(struct pci_dev *pdev, - struct linux_pbm_info *pbm, - struct linux_prom_pci_registers *pregs, - int nregs, - struct linux_prom_pci_registers *assigned, - int numaa) -{ - int preg, rng; - int IO_seen = 0; - int MEM_seen = 0; - - for(preg = 0; preg < nregs; preg++) { - struct linux_prom_pci_registers *ap = NULL; - int bustype = (pregs[preg].phys_hi >> 24) & 0x3; - int bsreg, brindex; - unsigned int rtmp; - u64 pci_addr, pci_size; - - if(bustype == 0) { - /* Config space cookie, nothing to do. */ - if(preg != 0) - printk("%s %02x.%02x [%04x,%04x]: " - "strange, config space not 0\n", - __FUNCTION__, - pdev->bus->number, pdev->devfn, - pdev->vendor, pdev->device); - continue; - } else if(bustype == 3) { - /* XXX add support for this... */ - printk("%s %02x.%02x [%04x,%04x]: " - "Warning, ignoring 64-bit PCI memory space, " - "tell Eddie C. Dost (ecd@skynet.be).\n", - __FUNCTION__, - pdev->bus->number, pdev->devfn, - pdev->vendor, pdev->device); - continue; - } - - bsreg = (pregs[preg].phys_hi & 0xff); - - /* Sanity */ - if((bsreg < PCI_BASE_ADDRESS_0) || - ((bsreg > (PCI_BASE_ADDRESS_5 + 4)) && (bsreg != PCI_ROM_ADDRESS)) || - (bsreg & 3)) { - printk("%s %02x.%02x [%04x:%04x]: " - "Warning, ignoring bogus basereg [%x]\n", - __FUNCTION__, pdev->bus->number, pdev->devfn, - 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; - } - - brindex = (bsreg - PCI_BASE_ADDRESS_0) >> 2; - if(numaa) { - int r; - - for(r = 0; r < numaa; r++) { - int abreg; - - abreg = (assigned[r].phys_hi & 0xff); - if(abreg == bsreg) { - ap = &assigned[r]; - break; - } - } - } - - /* Now construct UPA physical address. */ - pci_addr = (((u64)pregs[preg].phys_mid) << 32UL); - pci_addr |= (((u64)pregs[preg].phys_lo)); - pci_size = (((u64)pregs[preg].size_hi) << 32UL); - pci_size |= (((u64)pregs[preg].size_lo)); - - if(ap) { - pci_addr += ((u64)ap->phys_lo); - pci_addr += (((u64)ap->phys_mid) << 32UL); - } - - /* Final step, apply PBM range. */ - for(rng = 0; rng < pbm->num_pbm_ranges; rng++) { - struct linux_prom_pci_ranges *rngp = &pbm->pbm_ranges[rng]; - int space = (rngp->child_phys_hi >> 24) & 3; - - if(space == bustype) { - pci_addr += ((u64)rngp->parent_phys_lo); - pci_addr += (((u64)rngp->parent_phys_hi) << 32UL); - break; - } - } - if(rng == pbm->num_pbm_ranges) { - /* AIEEE */ - prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n"); - } - if (bsreg == PCI_ROM_ADDRESS) { - pdev->rom_address = (unsigned long)__va(pci_addr); - pdev->rom_address &= ~1UL; - - /* - * Disable access to the ROM. - */ - pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp & ~1); - } else { - struct resource *root, *rp; - - rp = &pdev->resource[brindex]; - - pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + (brindex * 4), &rtmp); - if (rtmp & 0x1) - rtmp &= 0x1; - else - rtmp &= 0xf; - - rp->name = pdev->name; - rp->start = (unsigned long)__va(pci_addr); - rp->end = rp->start + pci_size - 1; - - /* Keep track of what we've seen so far. */ - if(rtmp & 0x1) { - IO_seen = 1; - root = &ioport_resource; - } else { - MEM_seen = 1; - root = &iomem_resource; - } - rp->flags = rtmp; - request_resource(root, rp); - } - } - - /* Now handle assignments PROM did not take care of. */ - if(nregs) { - unsigned int rtmp, ridx; - unsigned int offset, base; - struct pci_vma *vp; - u64 pci_addr; - int breg; - - for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) { - struct resource *rp; - int io; - - ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2); - rp = &pdev->resource[ridx]; - base = (unsigned int)rp->start; - - /* Already handled? */ - if(rp->start > PAGE_OFFSET) - continue; - - pci_read_config_dword(pdev, breg, &rtmp); - io = (rtmp & 0x1); - offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg; - vp = pci_find_vma(pbm, base, offset, io); - if(!vp || vp->start > base) { - unsigned int size, new_base; - - pci_write_config_dword(pdev, breg, 0xffffffff); - pci_read_config_dword(pdev, breg, &size); - - if(io) - size &= ~0x1; - else - size &= ~0xf; - - size = (~(size) + 1); - if(!size) - continue; - - new_base = 0; - for(vp = pci_find_vma(pbm, new_base, 0, io); ; - vp = vp->next) { - if(!vp || new_base + size <= vp->start) - break; - new_base = (vp->end + (size - 1)) & ~(size-1); - } - if(vp && (new_base + size > vp->start)) { - prom_printf("PCI: Impossible full %s space.\n", - (io ? "IO" : "MEM")); - prom_halt(); - } - vp = pci_vma_alloc(); - vp->start = new_base; - vp->end = vp->start + size - 1; - vp->offset = offset; - - pci_add_vma(pbm, vp, io); - -#ifdef FIXUP_VMA_DEBUG - dprintf("%02x.%02x.%x: BaseReg %02x", - pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), - breg); - dprintf(" %s vma [%08x,%08x]\n", - io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end); -#endif - rtmp = new_base; - pci_read_config_dword(pdev, breg, &base); - if(io) - rtmp |= (base & ~PCI_BASE_ADDRESS_IO_MASK); - else - rtmp |= (base & ~PCI_BASE_ADDRESS_MEM_MASK); - pci_write_config_dword(pdev, breg, rtmp); - - /* Apply PBM ranges and update pci_dev. */ - pci_addr = new_base; - for(rng = 0; rng < pbm->num_pbm_ranges; rng++) { - struct linux_prom_pci_ranges *rngp; - int rspace; - - rngp = &pbm->pbm_ranges[rng]; - rspace = (rngp->child_phys_hi >> 24) & 3; - if(io && rspace != 1) - continue; - else if(!io && rspace != 2) - continue; - pci_addr += ((u64)rngp->parent_phys_lo); - pci_addr += (((u64)rngp->parent_phys_hi)<<32UL); - break; - } - if(rng == pbm->num_pbm_ranges) { - /* AIEEE */ - prom_printf("fixup_doit: YIEEE, cannot find " - "PBM ranges\n"); - } - rp->name = pdev->name; - rp->start = (unsigned long) __va(pci_addr); - rp->end = rp->start + size - 1; - - /* Keep track of what we've seen so far. */ - if(io) { - IO_seen = 1; - rp->flags = rtmp & 0x1; - request_resource(&ioport_resource, rp); - } else { - MEM_seen = 1; - rp->flags = rtmp & 0xf; - request_resource(&iomem_resource, rp); - } - } - } - - /* - * Handle PCI_ROM_ADDRESS. - */ - breg = PCI_ROM_ADDRESS; - base = (unsigned int)pdev->rom_address; - - if(pdev->rom_address > PAGE_OFFSET) - goto rom_address_done; - - base &= PCI_ROM_ADDRESS_MASK; - offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg; - vp = pci_find_vma(pbm, base, offset, 0); - if(!vp || vp->start > base) { - unsigned int size, new_base; - - pci_read_config_dword(pdev, breg, &rtmp); - pci_write_config_dword(pdev, breg, 0xffffffff); - pci_read_config_dword(pdev, breg, &size); - size &= ~1; - size = (~(size) + 1); - if(!size) - goto rom_address_done; - - new_base = 0; - for(vp = pci_find_vma(pbm, new_base, 0, 0); ; vp = vp->next) { - if(!vp || new_base + size <= vp->start) - break; - new_base = (vp->end + (size - 1)) & ~(size-1); - } - if(vp && (new_base + size > vp->start)) { - prom_printf("PCI: Impossible full MEM space.\n"); - prom_halt(); - } - vp = pci_vma_alloc(); - vp->start = new_base; - vp->end = vp->start + size - 1; - vp->offset = offset; - - pci_add_vma(pbm, vp, 0); - -#ifdef FIXUP_VMA_DEBUG - dprintf("%02x.%02x.%x: BaseReg %02x", - pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), - breg); - dprintf(" %s vma [%08x,%08x]\n", - "ROM", vp->start, vp->end); -#endif - - rtmp = new_base; - pci_read_config_dword(pdev, breg, &base); - rtmp &= ~(base & ~PCI_ROM_ADDRESS_MASK); - pci_write_config_dword(pdev, breg, rtmp); - - /* Apply PBM ranges and update pci_dev. */ - pci_addr = new_base; - for(rng = 0; rng < pbm->num_pbm_ranges; rng++) { - struct linux_prom_pci_ranges *rngp; - int rspace; - - rngp = &pbm->pbm_ranges[rng]; - rspace = (rngp->child_phys_hi >> 24) & 3; - if(rspace != 2) - continue; - pci_addr += ((u64)rngp->parent_phys_lo); - pci_addr += (((u64)rngp->parent_phys_hi)<<32UL); - break; - } - if(rng == pbm->num_pbm_ranges) { - /* AIEEE */ - prom_printf("fixup_doit: YIEEE, cannot find " - "PBM ranges\n"); - } - pdev->rom_address = (unsigned long)__va(pci_addr); - pdev->rom_address &= ~(base & ~PCI_ROM_ADDRESS_MASK); - MEM_seen = 1; - } - rom_address_done: - - } - if(IO_seen || MEM_seen) { - unsigned int l; - - pci_read_config_dword(pdev, PCI_COMMAND, &l); -#ifdef FIXUP_REGS_DEBUG - dprintf("["); -#endif - if(IO_seen) { -#ifdef FIXUP_REGS_DEBUG - dprintf("IO "); -#endif - l |= PCI_COMMAND_IO; - } - if(MEM_seen) { -#ifdef FIXUP_REGS_DEBUG - dprintf("MEM"); -#endif - l |= PCI_COMMAND_MEMORY; - } -#ifdef FIXUP_REGS_DEBUG - dprintf("]"); -#endif - pci_write_config_dword(pdev, PCI_COMMAND, l); - } - -#ifdef FIXUP_REGS_DEBUG - dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device); - for(preg = 0; preg < 6; preg++) { - if(pdev->resource[preg].start != 0) - dprintf("%d[%016lx] ", preg, pdev->resource[preg].start); - } - dprintf("\n"); -#endif -} - -#define imap_offset(__member) \ - ((unsigned long)(&(((struct psycho_regs *)0)->__member))) - -static unsigned long __init psycho_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus, slot; - - bus = (ino & 0x10) >> 4; - slot = (ino & 0x0c) >> 2; - - if(bus == 0) { - switch(slot) { - case 0: - return imap_offset(imap_a_slot0); - case 1: - return imap_offset(imap_a_slot1); - case 2: - return imap_offset(imap_a_slot2); - case 3: - default: - return imap_offset(imap_a_slot3); - } - } else { - switch(slot) { - case 0: - return imap_offset(imap_b_slot0); - case 1: - return imap_offset(imap_b_slot1); - case 2: - return imap_offset(imap_b_slot2); - case 3: - default: - return imap_offset(imap_b_slot3); - } - } -} - -/* Exported for EBUS probing layer. */ -unsigned int __init psycho_irq_build(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap_off; - int need_dma_sync = 0; - - ino &= PSYCHO_IMAP_INO; - - /* Compute IMAP register offset, generic IRQ layer figures out - * the ICLR register address as this is simple given the 32-bit - * irq number and IMAP register address. - */ - if((ino & 0x20) == 0) - imap_off = psycho_pcislot_imap_offset(ino); - else { - switch(ino) { - case 0x20: - /* Onboard SCSI. */ - imap_off = imap_offset(imap_scsi); - break; - - case 0x21: - /* Onboard Ethernet (ie. CheerIO/HME) */ - imap_off = imap_offset(imap_eth); - break; - - case 0x22: - /* Onboard Parallel Port */ - imap_off = imap_offset(imap_bpp); - break; - - case 0x23: - /* Audio Record */ - imap_off = imap_offset(imap_au_rec); - break; - - case 0x24: - /* Audio Play */ - imap_off = imap_offset(imap_au_play); - break; - - case 0x25: - /* Power Fail */ - imap_off = imap_offset(imap_pfail); - break; - - case 0x26: - /* Onboard KBD/MOUSE/SERIAL */ - imap_off = imap_offset(imap_kms); - break; - - case 0x27: - /* Floppy (ie. fdthree) */ - imap_off = imap_offset(imap_flpy); - break; - - case 0x28: - /* Spare HW INT */ - imap_off = imap_offset(imap_shw); - break; - - case 0x29: - /* Onboard Keyboard (only) */ - imap_off = imap_offset(imap_kbd); - break; - - case 0x2a: - /* Onboard Mouse (only) */ - imap_off = imap_offset(imap_ms); - break; - - case 0x2b: - /* Onboard Serial (only) */ - imap_off = imap_offset(imap_ser); - break; - - case 0x2c: - /* Onboard Timer 0 */ - imap_off = imap_offset(imap_tim0); - break; - - case 0x2d: - /* Onboard Timer 1 */ - imap_off = imap_offset(imap_tim1); - break; - - case 0x2e: - /* Psycho UE Interrupt */ - imap_off = imap_offset(imap_ue); - break; - - case 0x2f: - /* Psycho CE Interrupt */ - imap_off = imap_offset(imap_ce); - break; - - case 0x30: - /* Psycho PCI A Error Interrupt */ - imap_off = imap_offset(imap_a_err); - break; - - case 0x31: - /* Psycho PCI B Error Interrupt */ - imap_off = imap_offset(imap_b_err); - break; - - case 0x32: - /* Power Management */ - imap_off = imap_offset(imap_pmgmt); - break; - - default: - /* We don't expect anything else. - */ - prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - }; - } - imap_off -= imap_offset(imap_a_slot0); - - if (apb_present(pbm->parent) && (pdev->bus->number != pbm->pci_first_busno)) { - need_dma_sync = 1; - } - - return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync); -} - -static int __init pbm_intmap_match(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - struct linux_prom_pci_registers *preg, - unsigned int *interrupt) -{ - struct linux_prom_pci_registers ppreg; - unsigned int hi, mid, lo, irq; - int i; - -#ifdef FIXUP_IRQ_DEBUG - dprintf("pbm_intmap_match: "); -#endif - if (!pbm->num_pbm_intmap) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No intmap UPA[%x:%c]\n", - pbm->parent->upa_portid, - (pbm == &pbm->parent->pbm_A) ? 'A' : 'B'); -#endif - return 0; - } - /* - * Underneath a bridge, use register of parent bridge. - */ - if (pdev->bus->number != pbm->pci_first_busno) { - struct pcidev_cookie *pcp; - int node, offset; - char prom_name[64]; - -#ifdef FIXUP_IRQ_DEBUG - dprintf("UnderBridge, "); -#endif - pcp = pdev->bus->self->sysdata; - if (!pcp) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No bus PCP\n"); -#endif - goto out; - } - node = pcp->prom_node; - - i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg)); - if(i == 0 || i == -1) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No reg property.\n"); -#endif - goto out; - } - /* - * Did PROM know better and assign an interrupt different - * to #INTA to the device? - We test here for presence of - * FCODE on the card, in this case we assume PROM has set - * correct 'interrupts' property, unless it is quadhme. - */ - pcp = pdev->sysdata; - if (!pcp) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No dev PCP\n"); -#endif - goto out; - } - node = pcp->prom_node; - - offset = prom_getint(node, "fcode-rom-offset"); - prom_getstring(node, "name", prom_name, sizeof(prom_name)); - if (offset == -1 || - !strcmp(prom_name, "SUNW,qfe") || - !strcmp(prom_name, "qfe")) { - /* - * No, use low slot number bits of child as IRQ line. - */ - *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1; - } - preg = &ppreg; - } - - hi = preg->phys_hi & pbm->pbm_intmask.phys_hi; - mid = preg->phys_mid & pbm->pbm_intmask.phys_mid; - lo = preg->phys_lo & pbm->pbm_intmask.phys_lo; - irq = *interrupt & pbm->pbm_intmask.interrupt; -#ifdef FIXUP_IRQ_DEBUG - dprintf("intmap_match: [%02x.%02x.%x] key: [%08x.%08x.%08x.%08x] ", - pdev->bus->number, pdev->devfn >> 3, pdev->devfn & 7, - hi, mid, lo, irq); -#endif - for (i = 0; i < pbm->num_pbm_intmap; i++) { - if ((pbm->pbm_intmap[i].phys_hi == hi) && - (pbm->pbm_intmap[i].phys_mid == mid) && - (pbm->pbm_intmap[i].phys_lo == lo) && - (pbm->pbm_intmap[i].interrupt == irq)) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("irq: [%08x]", pbm->pbm_intmap[i].cinterrupt); -#endif - *interrupt = pbm->pbm_intmap[i].cinterrupt; - return 1; - } - } - -out: - prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ", - pdev->bus->number, pdev->devfn); - prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", - preg->phys_hi, preg->phys_mid, preg->phys_lo, *interrupt); - prom_halt(); -} - -static void __init fixup_irq(struct pci_dev *pdev, - struct linux_pbm_info *pbm, - struct linux_prom_pci_registers *preg, - int node) -{ - unsigned int prom_irq, portid = pbm->parent->upa_portid; - int err; - -#ifdef FIXUP_IRQ_DEBUG - 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) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No interrupts property.\n"); -#endif - pdev->irq = 0; - return; - } - - /* 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(pbm, pdev, 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, pdev, - (pbm->parent->upa_portid << 6) - | prom_irq); -#ifdef FIXUP_IRQ_DEBUG - dprintf("partially specified prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); -#endif - /* See if we find a matching interrupt-map entry. */ - } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) { - pdev->irq = psycho_irq_build(pbm, pdev, - (pbm->parent->upa_portid << 6) - | prom_irq); -#ifdef FIXUP_IRQ_DEBUG - dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); -#endif - } else { - unsigned int bus, slot, line; - - bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; - - /* Use the given interrupt property value as the line if it - * is non-zero and legal. Legal encodings are INTA=1, INTB=2, - * INTC=3, INTD=4 as per PCI OBP binding spec version 2.1 -DaveM - */ - if(prom_irq > 0 && prom_irq < 5) { - line = ((prom_irq - 1) & 3); - } else { - unsigned char pci_irq_line; - - /* The generic PCI probing layer will read the - * interrupt line into pdev->irq if the interrupt - * pin is non-zero, so we have to explicitly fetch - * the pin here to be certain (the interrupt line is - * typically left at zero by OBP). - */ - pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); - line = ((pci_irq_line - 1) & 3); - } - - /* Slot determination is only slightly complex. Handle - * the easy case first. - */ - if(pdev->bus->number == pbm->pci_first_busno) { - if(pbm == &pbm->parent->pbm_A) - slot = (pdev->devfn >> 3) - 1; - else - slot = (pdev->devfn >> 3) - 2; - } else { - /* Underneath a bridge, use slot number of parent - * bridge. - */ - 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) & 0x03; - } - slot = (slot << 2); - - pdev->irq = psycho_irq_build(pbm, pdev, - (((portid << 6) & PSYCHO_IMAP_IGN) - | (bus | slot | line))); - -#ifdef FIXUP_IRQ_DEBUG - do { - unsigned char iline, ipin; - - pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &ipin); - pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &iline); - 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. - */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - pdev->irq & PCI_IRQ_INO); - -#ifdef FIXUP_IRQ_DEBUG - dprintf("\n"); -#endif -} - -static void __init fixup_doit(struct pci_dev *pdev, - struct linux_pbm_info *pbm, - struct linux_prom_pci_registers *pregs, - int nregs, - int node) -{ - struct linux_prom_pci_registers assigned[PROMREG_MAX]; - int numaa, err; - - /* Get assigned addresses, if any. */ - err = prom_getproperty(node, "assigned-addresses", - (char *)&assigned[0], sizeof(assigned)); - if(err == 0 || err == -1) - numaa = 0; - else - numaa = (err / sizeof(struct linux_prom_pci_registers)); - - /* First, scan and fixup base registers. */ - fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa); - - /* Next, fixup interrupt numbers. */ - fixup_irq(pdev, pbm, &pregs[0], node); -} - -static void __init fixup_pci_dev(struct pci_dev *pdev, - struct pci_bus *pbus, - struct linux_pbm_info *pbm) -{ - struct linux_prom_pci_registers pregs[PROMREG_MAX]; - struct pcidev_cookie *pcp = pdev->sysdata; - int node, nregs, err; - - /* If this is a PCI bridge, we must program it. */ - if(pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) { - unsigned short cmd; - - /* First, enable bus mastering. */ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, cmd); - - /* Now, set cache line size to 64-bytes. - * NOTE: Cache line size is in 32-bit word units. - */ - pci_write_config_byte(pdev, - PCI_CACHE_LINE_SIZE, - (64 / sizeof(u32))); - } - - /* Ignore if this is one of the PBM's, EBUS, or a - * sub-bridge underneath the PBM. We only need to fixup - * true devices. - */ - if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) || - (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) || - (pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) || - (pcp == NULL)) { - /* - * Prevent access to PCI_ROM_ADDRESS, in case present - * as we don't fixup the address. - */ - if (pdev->rom_address) { - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, 0); - pdev->rom_address = 0; - } - return; - } - - node = pcp->prom_node; - - err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs)); - if(err == 0 || err == -1) { - prom_printf("Cannot find REG for pci_dev\n"); - prom_halt(); - } - - nregs = (err / sizeof(pregs[0])); - - fixup_doit(pdev, pbm, &pregs[0], nregs, node); - - /* Enable bus mastering on IDE interfaces. */ - if ((pdev->class >> 8 == PCI_CLASS_STORAGE_IDE) - && (pdev->class & 0x80)) { - unsigned short cmd; - - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, cmd); - } -} - -static void __init fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm) -{ - struct pci_dev *pdev; - - for(pdev = pbus->devices; pdev; pdev = pdev->sibling) - fixup_pci_dev(pdev, pbus, pbm); - - for(pbus = pbus->children; pbus; pbus = pbus->next) - fixup_pci_bus(pbus, pbm); -} - -static void __init fixup_addr_irq(struct linux_pbm_info *pbm) -{ - struct pci_bus *pbus = &pbm->pci_bus; - - /* Work through top level devices (not bridges, those and their - * devices are handled specially in the next loop). - */ - fixup_pci_bus(pbus, pbm); -} - -/* Walk all PCI devices probes, fixing up base registers and IRQ registers. - * We use OBP for most of this work. - */ -static void __init psycho_final_fixup(struct linux_psycho *psycho) -{ - /* Second, fixup base address registers and IRQ lines... */ - if (psycho->pbm_A.parent) - fixup_addr_irq(&psycho->pbm_A); - if (psycho->pbm_B.parent) - fixup_addr_irq(&psycho->pbm_B); -} - -/* Reorder the pci_dev chain, so that onboard devices come first - and then come the pluggable cards. */ -void __init psycho_reorder_devs(void) -{ - struct pci_dev **pci_onboard = &pci_devices; - struct pci_dev **pci_tail = &pci_devices; - struct pci_dev *pdev = pci_devices, *pci_other = NULL; - - while (pdev) { - if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { - if (pci_other) { - *pci_onboard = pdev; - pci_onboard = &pdev->next; - pdev = pdev->next; - *pci_onboard = pci_other; - *pci_tail = pdev; - continue; - } else - pci_onboard = &pdev->next; - } else if (!pci_other) - pci_other = pdev; - pci_tail = &pdev->next; - pdev = pdev->next; - } -} - -void __init pcibios_fixup(void) -{ - struct linux_psycho *psycho; - - pci_probe_enable = 1; - - /* XXX Really this should be per-PSYCHO, but the config space - * XXX reads and writes give us no way to know which PSYCHO - * XXX in which the config space reads should occur. - * XXX - * XXX Further thought says that we cannot change this generic - * XXX interface, else we'd break xfree86 and other parts of the - * XXX kernel (but whats more important is breaking userland for - * XXX the ix86/Alpha/etc. people). So we should define our own - * XXX internal extension initially, we can compile our own user - * XXX apps that need to get at PCI configuration space. - */ - - for (psycho = psycho_root; psycho; psycho = psycho->next) { - /* Probe bus on builtin PCI. */ - if (apb_present(psycho)) { - sabre_probe(psycho); - } else { - /* Probe busses under PBM B. */ - pbm_probe(&psycho->pbm_B); - - /* Probe busses under PBM A. */ - pbm_probe(&psycho->pbm_A); - } - } - - /* Walk all PCI devices found. For each device, and - * PCI bridge which is not one of the PSYCHO PBM's, fill in the - * sysdata with a pointer to the PBM (for pci_bus's) or - * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's). - */ - for (psycho = psycho_root; psycho; psycho = psycho->next) { - if (apb_present(psycho)) - sabre_cookie_fillin(psycho); - - fill_in_pbm_cookies(&psycho->pbm_A.pci_bus, - &psycho->pbm_A, - psycho->pbm_A.prom_node); - fill_in_pbm_cookies(&psycho->pbm_B.pci_bus, - &psycho->pbm_B, - psycho->pbm_B.prom_node); - - /* 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); - } - - if (psycho_reorder & PSYCHO_REORDER_ONBOARDFIRST) - psycho_reorder_devs(); - - return ebus_init(); -} - -/* "PCI: The emerging standard..." 8-( */ -volatile int pci_poke_in_progress = 0; -volatile int pci_poke_faulted = 0; - -/* XXX Current PCI support code is broken, it assumes one master PCI config - * XXX space exists, on Ultra we can have many of them, especially with - * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire. - */ -static void * -pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus, - unsigned char devfn, unsigned char where) -{ - unsigned long ret; - - if (!pbm) - return NULL; - - ret = (unsigned long) pbm->parent->pci_config_space; - - ret |= (1 << 24); - ret |= (bus << 16); - ret |= (devfn << 8); - ret |= where; - - return (void *)ret; -} - -static inline int -out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn) -{ - return ((pbm->parent == 0) || - ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || - ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || - (pci_probe_enable == 0)); -} - -static inline int -sabre_out_of_range(unsigned char devfn) -{ - return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || - ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) || - (PCI_SLOT(devfn) > 1) || - (pci_probe_enable == 0)); -} - -static int -sabre_read_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char *value) -{ - if (bus) - return pbm_read_config_byte(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) { - *value = 0xff; - return PCIBIOS_SUCCESSFUL; - } - - if (where < 8) { - unsigned short tmp; - - pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp); - if (where & 1) - *value = tmp >> 8; - else - *value = tmp & 0xff; - return PCIBIOS_SUCCESSFUL; - } else - return pbm_read_config_byte(pbm, bus, devfn, where, value); -} - -static int -sabre_read_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short *value) -{ - if (bus) - return pbm_read_config_word(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) { - *value = 0xffff; - return PCIBIOS_SUCCESSFUL; - } - - if (where < 8) - return pbm_read_config_word(pbm, bus, devfn, where, value); - else { - unsigned char tmp; - - pbm_read_config_byte(pbm, bus, devfn, where, &tmp); - *value = tmp; - pbm_read_config_byte(pbm, bus, devfn, where + 1, &tmp); - *value |= tmp << 8; - return PCIBIOS_SUCCESSFUL; - } -} - -static int -sabre_read_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int *value) -{ - unsigned short tmp; - - if (bus) - return pbm_read_config_dword(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) { - *value = 0xffffffff; - return PCIBIOS_SUCCESSFUL; - } - - sabre_read_config_word(pbm, bus, devfn, where, &tmp); - *value = tmp; - sabre_read_config_word(pbm, bus, devfn, where + 2, &tmp); - *value |= tmp << 16; - return PCIBIOS_SUCCESSFUL; -} - -static int -sabre_write_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value) -{ - if (bus) - return pbm_write_config_byte(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where < 8) { - unsigned short tmp; - - pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp); - if (where & 1) { - value &= 0x00ff; - value |= tmp << 8; - } else { - value &= 0xff00; - value |= tmp; - } - return pbm_write_config_word(pbm, bus, devfn, where & ~1, tmp); - } else - return pbm_write_config_byte(pbm, bus, devfn, where, value); -} - -static int -sabre_write_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value) -{ - if (bus) - return pbm_write_config_word(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where < 8) - return pbm_write_config_word(pbm, bus, devfn, where, value); - else { - pbm_write_config_byte(pbm, bus, devfn, where, value & 0xff); - pbm_write_config_byte(pbm, bus, devfn, where + 1, value >> 8); - return PCIBIOS_SUCCESSFUL; - } -} - -static int -sabre_write_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int value) -{ - if (bus) - return pbm_write_config_dword(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) - return PCIBIOS_SUCCESSFUL; - - sabre_write_config_word(pbm, bus, devfn, where, value & 0xffff); - sabre_write_config_word(pbm, bus, devfn, where + 2, value >> 16); - return PCIBIOS_SUCCESSFUL; -} - -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 (!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" - "lduba [%1] %2, %0\n\t" - "membar #Sync" - : "=r" (byte) - : "r" (addr), "i" (ASI_PL)); - pci_poke_in_progress = 0; - trapped = pci_poke_faulted; - pci_poke_faulted = 0; - if(!trapped) - *value = byte; - return PCIBIOS_SUCCESSFUL; -} - -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 (!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" - "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) - *value = word; - return PCIBIOS_SUCCESSFUL; -} - -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 = pci_mkaddr(pbm, bus, devfn, where); - unsigned int word, trapped; - - *value = 0xffffffff; - - 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; - __asm__ __volatile__("membar #Sync\n\t" - "lduwa [%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) - *value = word; - return PCIBIOS_SUCCESSFUL; -} - -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(pbm, bus, devfn, where); - - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - pci_poke_in_progress = 1; - - /* Endianness doesn't matter but we have to get the memory - * barriers in there so... - */ - __asm__ __volatile__("membar #Sync\n\t" - "stba %0, [%1] %2\n\t" - "membar #Sync\n\t" - : /* no outputs */ - : "r" (value), "r" (addr), "i" (ASI_PL)); - pci_poke_in_progress = 0; - - return PCIBIOS_SUCCESSFUL; -} - -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 = pci_mkaddr(pbm, bus, devfn, where); - - 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" - "membar #Sync\n\t" - : /* no outputs */ - : "r" (value), "r" (addr), "i" (ASI_PL)); - pci_poke_in_progress = 0; - return PCIBIOS_SUCCESSFUL; -} - -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 = pci_mkaddr(pbm, bus, devfn, where); - - 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" - "membar #Sync" - : /* no outputs */ - : "r" (value), "r" (addr), "i" (ASI_PL)); - pci_poke_in_progress = 0; - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_read_config_byte (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char *value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_read_config_byte(pbm, bus, devfn, where, value); - return pbm_read_config_byte(pbm, bus, devfn, where, value); -} - -int pcibios_read_config_word (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short *value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_read_config_word(pbm, bus, devfn, where, value); - return pbm_read_config_word(pbm, bus, devfn, where, value); -} - -int pcibios_read_config_dword (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int *value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_read_config_dword(pbm, bus, devfn, where, value); - return pbm_read_config_dword(pbm, bus, devfn, where, value); -} - -int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_write_config_byte(pbm, bus, devfn, where, value); - return pbm_write_config_byte(pbm, bus, devfn, where, value); -} - -int pcibios_write_config_word (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_write_config_word(pbm, bus, devfn, where, 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) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_write_config_dword(pbm, bus, devfn, where, 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, - unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - int err = 0; - - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - - lock_kernel(); - switch(len) { - case 1: - pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, (unsigned char *)buf); - break; - case 2: - pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, (unsigned short *)buf); - break; - case 4: - pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, (unsigned int *)buf); - break; - - 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) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - int err = 0; - - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - - lock_kernel(); - switch(len) { - case 1: - err = get_user(ubyte, (unsigned char *)buf); - if(err) - break; - pcibios_write_config_byte(bus, dfn, off, ubyte); - break; - - case 2: - err = get_user(ushort, (unsigned short *)buf); - if(err) - break; - pcibios_write_config_byte(bus, dfn, off, ushort); - break; - - case 4: - err = get_user(uint, (unsigned int *)buf); - if(err) - break; - pcibios_write_config_byte(bus, dfn, off, uint); - break; - - default: - err = -EINVAL; - break; - - }; - unlock_kernel(); - - return err; -} - -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ -} - -char * __init pcibios_setup(char *str) -{ - if (!strcmp(str, "onboardfirst")) { - psycho_reorder |= PSYCHO_REORDER_ONBOARDFIRST; - return NULL; - } - if (!strcmp(str, "noreorder")) { - psycho_reorder = 0; - return NULL; - } - return str; -} - -#endif diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c --- v2.3.15/linux/arch/sparc64/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/semaphore.c Tue Aug 31 11:23:30 1999 @@ -0,0 +1,129 @@ +/* $Id: semaphore.c,v 1.1 1999/08/30 10:00:50 davem Exp $ + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.3.15/linux/arch/sparc64/kernel/setup.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/setup.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.46 1999/08/02 08:39:36 davem Exp $ +/* $Id: setup.c,v 1.47 1999/08/31 06:54:55 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -316,7 +316,7 @@ * Process kernel command line switches that are specific to the * SPARC or that require special low-level processing. */ -__initfunc(static void process_switch(char c)) +static void __init process_switch(char c) { switch (c) { case 'd': @@ -335,7 +335,7 @@ } } -__initfunc(static void boot_flags_init(char *commands)) +static void __init boot_flags_init(char *commands) { while (*commands) { /* Move to the start of the next "argument". */ @@ -438,8 +438,8 @@ extern struct consw sun_serial_con; -__initfunc(void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init 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, end_of_phys_memory = 0; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.3.15/linux/arch/sparc64/kernel/smp.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/smp.c Tue Aug 31 11:23:30 1999 @@ -83,7 +83,7 @@ return len; } -__initfunc(void smp_store_cpu_info(int id)) +void __init smp_store_cpu_info(int id) { int i; @@ -103,7 +103,7 @@ cpu_data[id].irq_worklists[i] = 0; } -__initfunc(void smp_commence(void)) +void __init smp_commence(void) { } @@ -115,7 +115,7 @@ extern void inherit_locked_prom_mappings(int save_p); extern void cpu_probe(void); -__initfunc(void smp_callin(void)) +void __init smp_callin(void) { int cpuid = hard_smp_processor_id(); @@ -192,7 +192,7 @@ */ static struct task_struct *cpu_new_task = NULL; -__initfunc(void smp_boot_cpus(void)) +void __init smp_boot_cpus(void) { int cpucount = 0, i; @@ -547,10 +547,18 @@ atomic_dec(&smp_capture_registry); } -static inline void sparc64_do_profile(unsigned long pc) +static inline void sparc64_do_profile(unsigned long pc, unsigned long g3) { if (prof_buffer && current->pid) { extern int _stext; + extern int rwlock_impl_begin, rwlock_impl_end; + extern int atomic_impl_begin, atomic_impl_end; + + if ((pc >= (unsigned long) &rwlock_impl_begin && + pc < (unsigned long) &rwlock_impl_end) || + (pc >= (unsigned long) &atomic_impl_begin && + pc < (unsigned long) &atomic_impl_end)) + pc = g3; pc -= (unsigned long) &_stext; pc >>= prof_shift; @@ -589,7 +597,7 @@ clear_softint((1UL << 0)); do { if(!user) - sparc64_do_profile(regs->tpc); + sparc64_do_profile(regs->tpc, regs->u_regs[UREG_G3]); if(!--prof_counter(cpu)) { if (cpu == boot_cpu_id) { @@ -647,7 +655,7 @@ } while (tick >= compare); } -__initfunc(static void smp_setup_percpu_timer(void)) +static void __init smp_setup_percpu_timer(void) { int cpu = smp_processor_id(); @@ -661,7 +669,7 @@ : "g1"); } -__initfunc(void smp_tick_init(void)) +void __init smp_tick_init(void) { int i; @@ -707,7 +715,7 @@ cycles_t cacheflush_time; -__initfunc(static void smp_tune_scheduling (void)) +static void __init smp_tune_scheduling (void) { unsigned long flush_base, flags, *p; unsigned int ecache_size; @@ -775,7 +783,8 @@ (int) cacheflush_time); } -int __init setup_profiling_timer(unsigned int multiplier) +/* /proc/profile writes can call this, don't __init it please. */ +int setup_profiling_timer(unsigned int multiplier) { unsigned long flags; int i; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/starfire.c linux/arch/sparc64/kernel/starfire.c --- v2.3.15/linux/arch/sparc64/kernel/starfire.c Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/kernel/starfire.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: starfire.c,v 1.2 1998/12/09 18:53:11 davem Exp $ +/* $Id: starfire.c,v 1.3 1999/08/30 10:01:13 davem Exp $ * starfire.c: Starfire/E10000 support. * * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) @@ -43,7 +43,7 @@ int starfire_hard_smp_processor_id(void) { - return *((unsigned int *) __va(0x1fff40000d0)); + return *((volatile unsigned int *) __va(0x1fff40000d0)); } /* Each Starfire board has 32 registers which perform translation @@ -52,8 +52,8 @@ * bits than in all previous Sun5 systems. */ struct starfire_irqinfo { - unsigned int *imap_slots[32]; - unsigned int *tregs[32]; + volatile unsigned int *imap_slots[32]; + volatile unsigned int *tregs[32]; struct starfire_irqinfo *next; int upaid, hwmid; }; @@ -80,7 +80,7 @@ treg_base += 0x200UL; for(i = 0; i < 32; i++) { p->imap_slots[i] = NULL; - p->tregs[i] = __va(treg_base + (i * 0x10)); + p->tregs[i] = (volatile unsigned int *)__va(treg_base + (i * 0x10)); } p->upaid = upaid; p->next = sflist; @@ -89,7 +89,7 @@ return (void *) p; } -unsigned int starfire_translate(unsigned int *imap, +unsigned int starfire_translate(volatile unsigned int *imap, unsigned int upaid) { struct starfire_irqinfo *p; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.3.15/linux/arch/sparc64/kernel/sys_sparc32.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/sys_sparc32.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.117 1999/08/02 08:39:40 davem Exp $ +/* $Id: sys_sparc32.c,v 1.118 1999/08/30 10:01:15 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -3741,7 +3741,7 @@ } -extern asmlinkage int sys_personality(unsigned long); +extern asmlinkage long sys_personality(unsigned long); asmlinkage int sys32_personality(unsigned long personality) { diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.3.15/linux/arch/sparc64/kernel/sys_sunos32.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/sys_sunos32.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.30 1999/07/30 09:35:31 davem Exp $ +/* $Id: sys_sunos32.c,v 1.31 1999/08/30 10:01:19 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -981,10 +981,6 @@ return ret; } -extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); -extern asmlinkage int sys_semget (key_t key, int nsems, int semflg); -extern asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops); - asmlinkage int sunos_semsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 ptr) { union semun arg4; @@ -1119,13 +1115,6 @@ return 0; } -extern asmlinkage int sys_msgget (key_t key, int msgflg); -extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, - size_t msgsz, long msgtyp, int msgflg); -extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, - size_t msgsz, int msgflg); -extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); - asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { struct sparc_stackf32 *sp; @@ -1241,11 +1230,6 @@ return -EFAULT; return 0; } - -extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); -extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); -extern asmlinkage int sys_shmdt (char *shmaddr); -extern asmlinkage int sys_shmget (key_t key, int size, int shmflg); asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3) { diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c --- v2.3.15/linux/arch/sparc64/kernel/time.c Mon Mar 15 16:10:43 1999 +++ linux/arch/sparc64/kernel/time.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.20 1999/03/15 22:13:40 davem Exp $ +/* $Id: time.c,v 1.22 1999/08/30 10:01:22 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -33,9 +33,9 @@ extern rwlock_t xtime_lock; -struct mostek48t02 *mstk48t02_regs = 0; -static struct mostek48t08 *mstk48t08_regs = 0; -static struct mostek48t59 *mstk48t59_regs = 0; +unsigned long mstk48t02_regs = 0UL; +static unsigned long mstk48t08_regs = 0UL; +static unsigned long mstk48t59_regs = 0UL; static int set_rtc_mmss(unsigned long); @@ -47,7 +47,7 @@ */ unsigned long timer_tick_offset; static unsigned long timer_tick_compare; -static unsigned long timer_ticks_per_usec; +static unsigned long timer_ticks_per_usec_quotient; static __inline__ void timer_check_rtc(void) { @@ -146,17 +146,25 @@ /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { - register struct mostek48t02 *regs = mstk48t02_regs; - unsigned char sec; + unsigned long regs = mstk48t02_regs; + u8 sec, tmp; int i, count; prom_printf("CLOCK: Clock was stopped. Kick start "); /* Turn on the kick start bit to start the oscillator. */ - regs->creg |= MSTK_CREG_WRITE; - regs->sec &= ~MSTK_STOP; - regs->hour |= MSTK_KICK_START; - regs->creg &= ~MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + tmp = mostek_read(regs + MOSTEK_SEC); + tmp &= ~MSTK_STOP; + mostek_write(regs + MOSTEK_SEC, tmp); + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp |= MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); /* Delay to allow the clock oscillator to start. */ sec = MSTK_REG_SEC(regs); @@ -165,13 +173,17 @@ for (count = 0; count < 100000; count++) /* nothing */ ; prom_printf("."); - sec = regs->sec; + sec = MSTK_REG_SEC(regs); } prom_printf("\n"); /* Turn off kick start and set a "valid" time and date. */ - regs->creg |= MSTK_CREG_WRITE; - regs->hour &= ~MSTK_KICK_START; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp &= ~MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); MSTK_SET_REG_SEC(regs,0); MSTK_SET_REG_MIN(regs,0); MSTK_SET_REG_HOUR(regs,0); @@ -179,14 +191,24 @@ MSTK_SET_REG_DOM(regs,1); MSTK_SET_REG_MONTH(regs,8); MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO); - regs->creg &= ~MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); /* Ensure the kick start bit is off. If it isn't, turn it off. */ - while (regs->hour & MSTK_KICK_START) { + while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) { prom_printf("CLOCK: Kick start still on!\n"); - regs->creg |= MSTK_CREG_WRITE; - regs->hour &= ~MSTK_KICK_START; - regs->creg &= ~MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp &= ~MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); } prom_printf("CLOCK: Kick start procedure successful.\n"); @@ -195,13 +217,13 @@ /* Return nonzero if the clock chip battery is low. */ static int __init has_low_battery(void) { - register struct mostek48t02 *regs = mstk48t02_regs; - unsigned char data1, data2; + unsigned long regs = mstk48t02_regs; + u8 data1, data2; - data1 = regs->eeprom[0]; /* Read some data. */ - regs->eeprom[0] = ~data1; /* Write back the complement. */ - data2 = regs->eeprom[0]; /* Read back the complement. */ - regs->eeprom[0] = data1; /* Restore the original value. */ + data1 = mostek_read(regs + MOSTEK_EEPROM); /* Read some data. */ + mostek_write(regs + MOSTEK_EEPROM, ~data1); /* Write back the complement. */ + data2 = mostek_read(regs + MOSTEK_EEPROM); /* Read back the complement. */ + mostek_write(regs + MOSTEK_EEPROM, data1); /* Restore original value. */ return (data1 == data2); /* Was the write blocked? */ } @@ -211,17 +233,20 @@ static void __init set_system_time(void) { unsigned int year, mon, day, hour, min, sec; - struct mostek48t02 *mregs; + unsigned long mregs = mstk48t02_regs; + u8 tmp; do_get_fast_time = do_gettimeofday; - mregs = mstk48t02_regs; if(!mregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); prom_halt(); } - mregs->creg |= MSTK_CREG_READ; + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + sec = MSTK_REG_SEC(mregs); min = MSTK_REG_MIN(mregs); hour = MSTK_REG_HOUR(mregs); @@ -230,7 +255,10 @@ year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_usec = 0; - mregs->creg &= ~MSTK_CREG_READ; + + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); } void __init clock_probe(void) @@ -315,19 +343,8 @@ prom_halt(); } - if (check_region(edev->base_address[0], - sizeof(struct mostek48t59))) { - prom_printf("%s: Can't get region %lx, %d\n", - __FUNCTION__, edev->base_address[0], - sizeof(struct mostek48t59)); - prom_halt(); - } - request_region(edev->base_address[0], - sizeof(struct mostek48t59), "clock"); - - mstk48t59_regs = (struct mostek48t59 *) - edev->base_address[0]; - mstk48t02_regs = &mstk48t59_regs->regs; + mstk48t59_regs = edev->resource[0].start; + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; break; } #endif @@ -338,22 +355,16 @@ } if(model[5] == '0' && model[6] == '2') { - mstk48t02_regs = (struct mostek48t02 *) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t02_regs), - "clock", clk_reg[0].which_io, 0x0); + mstk48t02_regs = (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); } else if(model[5] == '0' && model[6] == '8') { - mstk48t08_regs = (struct mostek48t08 *) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t08_regs), - "clock", clk_reg[0].which_io, 0x0); - mstk48t02_regs = &mstk48t08_regs->regs; + mstk48t08_regs = (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); + mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; } else { - mstk48t59_regs = (struct mostek48t59 *) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t59_regs), - "clock", clk_reg[0].which_io, 0x0); - mstk48t02_regs = &mstk48t59_regs->regs; + mstk48t59_regs = (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } break; } @@ -363,7 +374,7 @@ prom_printf("NVRAM: Low battery voltage!\n"); /* Kick start the clock if it is completely stopped. */ - if (mstk48t02_regs->sec & MSTK_STOP) + if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); set_system_time(); @@ -392,7 +403,7 @@ init_timers(timer_interrupt, &clock); timer_tick_offset = clock / HZ; - timer_ticks_per_usec = clock / 1000000; + timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020)); } static __inline__ unsigned long do_gettimeoffset(void) @@ -408,7 +419,7 @@ : "r" (timer_tick_offset), "r" (timer_tick_compare) : "g1", "g2"); - return ticks / timer_ticks_per_usec; + return (ticks * timer_ticks_per_usec_quotient) >> 32UL; } /* This need not obtain the xtime_lock as it is coded in @@ -431,24 +442,22 @@ or %g2, %lo(xtime), %g2 or %g1, %lo(timer_tick_compare), %g1 1: ldda [%g2] 0x24, %o4 - membar #LoadLoad | #MemIssue rd %tick, %o1 ldx [%g1], %g7 - membar #LoadLoad | #MemIssue ldda [%g2] 0x24, %o2 - membar #LoadLoad xor %o4, %o2, %o2 xor %o5, %o3, %o3 orcc %o2, %o3, %g0 bne,pn %xcc, 1b sethi %hi(lost_ticks), %o2 - sethi %hi(timer_ticks_per_usec), %o3 + sethi %hi(timer_ticks_per_usec_quotient), %o3 ldx [%o2 + %lo(lost_ticks)], %o2 add %g3, %o1, %o1 - ldx [%o3 + %lo(timer_ticks_per_usec)], %o3 + ldx [%o3 + %lo(timer_ticks_per_usec_quotient)], %o3 sub %o1, %g7, %o1 + mulx %o3, %o1, %o1 brz,pt %o2, 1f - udivx %o1, %o3, %o1 + srlx %o1, 32, %o1 sethi %hi(10000), %g2 or %g2, %lo(10000), %g2 add %o1, %g2, %o1 @@ -487,16 +496,23 @@ static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, mostek_minutes; - struct mostek48t02 *regs = mstk48t02_regs; + unsigned long regs = mstk48t02_regs; + u8 tmp; /* Not having a register set can lead to trouble. */ if (!regs) return -1; /* Read the current RTC minutes. */ - regs->creg |= MSTK_CREG_READ; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + mostek_minutes = MSTK_REG_MIN(regs); - regs->creg &= ~MSTK_CREG_READ; + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); /* * since we're only adjusting minutes and seconds, @@ -511,10 +527,16 @@ real_minutes %= 60; if (abs(real_minutes - mostek_minutes) < 30) { - regs->creg |= MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + MSTK_SET_REG_SEC(regs,real_seconds); MSTK_SET_REG_MIN(regs,real_minutes); - regs->creg &= ~MSTK_CREG_WRITE; + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); } else return -1; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/lib/atomic.S linux/arch/sparc64/lib/atomic.S --- v2.3.15/linux/arch/sparc64/lib/atomic.S Sun Jul 4 09:53:12 1999 +++ linux/arch/sparc64/lib/atomic.S Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: atomic.S,v 1.1 1999/07/03 22:11:04 davem Exp $ +/* $Id: atomic.S,v 1.2 1999/08/23 05:15:58 davem Exp $ * atomic.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -9,7 +9,10 @@ .text .align 64 + .globl atomic_impl_begin, atomic_impl_end + .globl __atomic_add +atomic_impl_begin: __atomic_add: lduw [%g1], %g5 add %g5, %g2, %g7 @@ -30,3 +33,4 @@ nop jmpl %g3 + 8, %g0 sub %g7, %g2, %g2 +atomic_impl_end: diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/lib/rwlock.S linux/arch/sparc64/lib/rwlock.S --- v2.3.15/linux/arch/sparc64/lib/rwlock.S Sun Jul 4 09:53:12 1999 +++ linux/arch/sparc64/lib/rwlock.S Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: rwlock.S,v 1.1 1999/07/03 22:11:06 davem Exp $ +/* $Id: rwlock.S,v 1.2 1999/08/23 05:15:58 davem Exp $ * rwlocks.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -7,10 +7,13 @@ .text .align 64 + .globl rwlock_impl_begin, rwlock_impl_end + /* The non-contention read lock usage is 2 cache lines. */ .globl __read_lock, __read_unlock /* g1=lock, g3=retpc, g5/g7=scratch */ +rwlock_impl_begin: __read_lock: ldsw [%g1], %g5 brlz,pn %g5, __read_wait_for_writer @@ -78,4 +81,5 @@ be,pn %icc, 99b membar #LoadLoad b,a,pt %xcc, 99b +rwlock_impl_end: diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/Makefile linux/arch/sparc64/math-emu/Makefile --- v2.3.15/linux/arch/sparc64/math-emu/Makefile Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/Makefile Tue Aug 31 11:23:30 1999 @@ -8,12 +8,7 @@ # 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 \ - 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 +O_OBJS := math.o +CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/double.h linux/arch/sparc64/math-emu/double.h --- v2.3.15/linux/arch/sparc64/math-emu/double.h Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/double.h Wed Dec 31 16:00:00 1969 @@ -1,197 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Double Precision - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel 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_UNPACK_RAW_DP(X,val) _FP_UNPACK_RAW_2_P(D,X,val) -#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_2(D,val,X) -#define FP_PACK_RAW_DP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(D,val,X); \ - } while (0) - -#define FP_UNPACK_D(X,val) \ - do { \ - _FP_UNPACK_RAW_2(D,X,val); \ - _FP_UNPACK_CANONICAL(D,2,X); \ - } while (0) - -#define FP_UNPACK_DP(X,val) \ - do { \ - _FP_UNPACK_RAW_2_P(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_PACK_DP(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,2,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(D,val,X); \ - } while (0) - -#define FP_ISSIGNAN_D(X) _FP_ISSIGNAN(D,2,X) -#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_SQRT_MEAT_D(R,S,T,X,Q) _FP_SQRT_MEAT_2(R,S,T,X,Q) - -#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) - -#define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_2(X) -#define _FP_FRAC_HIGH_RAW_D(X) _FP_FRAC_HIGH_2(X) - -#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_UNPACK_RAW_DP(X,val) _FP_UNPACK_RAW_1_P(D,X,val) -#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_1(D,val,X) -#define FP_PACK_RAW_DP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(D,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_UNPACK_DP(X,val) \ - do { \ - _FP_UNPACK_RAW_1_P(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_PACK_DP(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,1,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(D,val,X); \ - } while (0) - -#define FP_ISSIGNAN_D(X) _FP_ISSIGNAN(D,1,X) -#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) -#define _FP_SQRT_MEAT_D(R,S,T,X,Q) _FP_SQRT_MEAT_1(R,S,T,X,Q) - -/* 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) - -#define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_1(X) -#define _FP_FRAC_HIGH_RAW_D(X) _FP_FRAC_HIGH_1(X) - -#endif /* W_TYPE_SIZE < 64 */ diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/extended.h linux/arch/sparc64/math-emu/extended.h --- v2.3.15/linux/arch/sparc64/math-emu/extended.h Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/extended.h Wed Dec 31 16:00:00 1969 @@ -1,388 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Extended Precision. - Copyright (C) 1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Jakub Jelinek (jj@ultra.linux.cz). - - 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. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel, kid. Go buy yourself a real computer." -#endif - -#if _FP_W_TYPE_SIZE < 64 -#define _FP_FRACTBITS_E (4*_FP_W_TYPE_SIZE) -#else -#define _FP_FRACTBITS_E (2*_FP_W_TYPE_SIZE) -#endif - -#define _FP_FRACBITS_E 64 -#define _FP_FRACXBITS_E (_FP_FRACTBITS_E - _FP_FRACBITS_E) -#define _FP_WFRACBITS_E (_FP_WORKBITS + _FP_FRACBITS_E) -#define _FP_WFRACXBITS_E (_FP_FRACTBITS_E - _FP_WFRACBITS_E) -#define _FP_EXPBITS_E 15 -#define _FP_EXPBIAS_E 16383 -#define _FP_EXPMAX_E 32767 - -#define _FP_QNANBIT_E \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-2) % _FP_W_TYPE_SIZE) -#define _FP_IMPLBIT_E \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-1) % _FP_W_TYPE_SIZE) -#define _FP_OVERFLOW_E \ - ((_FP_W_TYPE)1 << (_FP_WFRACBITS_E % _FP_W_TYPE_SIZE)) - -#if _FP_W_TYPE_SIZE < 64 - -union _FP_UNION_E -{ - long double flt; - struct - { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned long pad1 : _FP_W_TYPE_SIZE; - unsigned long pad2 : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E); - unsigned long sign : 1; - unsigned long exp : _FP_EXPBITS_E; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned long frac0 : _FP_W_TYPE_SIZE; -#else - unsigned long frac0 : _FP_W_TYPE_SIZE; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned exp : _FP_EXPBITS_E; - unsigned sign : 1; -#endif /* not bigendian */ - } bits __attribute__((packed)); -}; - - -#define FP_DECL_E(X) _FP_DECL(4,X) - -#define FP_UNPACK_RAW_E(X, val) \ - do { \ - union _FP_UNION_E _flo; _flo.flt = (val); \ - \ - X##_f[2] = 0; X##_f[3] = 0; \ - X##_f[0] = _flo.bits.frac0; \ - X##_f[1] = _flo.bits.frac1; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - if (!X##_e && (X##_f[1] || X##_f[0]) \ - && !(X##_f[1] & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_UNPACK_RAW_EP(X, val) \ - do { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - X##_f[2] = 0; X##_f[3] = 0; \ - X##_f[0] = _flo->bits.frac0; \ - X##_f[1] = _flo->bits.frac1; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - if (!X##_e && (X##_f[1] || X##_f[0]) \ - && !(X##_f[1] & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_PACK_RAW_E(val, X) \ - do { \ - union _FP_UNION_E _flo; \ - \ - if (X##_e) X##_f[1] |= _FP_IMPLBIT_E; \ - else X##_f[1] &= ~(_FP_IMPLBIT_E); \ - _flo.bits.frac0 = X##_f[0]; \ - _flo.bits.frac1 = X##_f[1]; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - \ - (val) = _flo.flt; \ - } while (0) - -#define FP_PACK_RAW_EP(val, X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - if (X##_e) X##_f[1] |= _FP_IMPLBIT_E; \ - else X##_f[1] &= ~(_FP_IMPLBIT_E); \ - _flo->bits.frac0 = X##_f[0]; \ - _flo->bits.frac1 = X##_f[1]; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } \ - } while (0) - -#define FP_UNPACK_E(X,val) \ - do { \ - FP_UNPACK_RAW_E(X,val); \ - _FP_UNPACK_CANONICAL(E,4,X); \ - } while (0) - -#define FP_UNPACK_EP(X,val) \ - do { \ - FP_UNPACK_RAW_2_P(X,val); \ - _FP_UNPACK_CANONICAL(E,4,X); \ - } while (0) - -#define FP_PACK_E(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,4,X); \ - FP_PACK_RAW_E(val,X); \ - } while (0) - -#define FP_PACK_EP(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,4,X); \ - FP_PACK_RAW_EP(val,X); \ - } while (0) - -#define FP_ISSIGNAN_E(X) _FP_ISSIGNAN(E,4,X) -#define FP_NEG_E(R,X) _FP_NEG(E,4,R,X) -#define FP_ADD_E(R,X,Y) _FP_ADD(E,4,R,X,Y) -#define FP_SUB_E(R,X,Y) _FP_SUB(E,4,R,X,Y) -#define FP_MUL_E(R,X,Y) _FP_MUL(E,4,R,X,Y) -#define FP_DIV_E(R,X,Y) _FP_DIV(E,4,R,X,Y) -#define FP_SQRT_E(R,X) _FP_SQRT(E,4,R,X) - -/* - * Square root algorithms: - * We have just one right now, maybe Newton approximation - * should be added for those machines where division is fast. - * This has special _E version because standard _4 square - * root would not work (it has to start normally with the - * second word and not the first), but as we have to do it - * anyway, we optimize it by doing most of the calculations - * in two UWtype registers instead of four. - */ - -#define _FP_SQRT_MEAT_E(R, S, T, X, q) \ - do { \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - _FP_FRAC_SRL_4(X, (_FP_WORKBITS)); \ - while (q) \ - { \ - T##_f[1] = S##_f[1] + q; \ - if (T##_f[1] <= X##_f[1]) \ - { \ - S##_f[1] = T##_f[1] + q; \ - X##_f[1] -= T##_f[1]; \ - R##_f[1] += q; \ - } \ - _FP_FRAC_SLL_2(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q) \ - { \ - T##_f[0] = S##_f[0] + q; \ - T##_f[1] = S##_f[1]; \ - if (T##_f[1] < X##_f[1] || \ - (T##_f[1] == X##_f[1] && \ - T##_f[0] <= X##_f[0])) \ - { \ - S##_f[0] = T##_f[0] + q; \ - S##_f[1] += (T##_f[0] > S##_f[0]); \ - _FP_FRAC_DEC_2(X, T); \ - R##_f[0] += q; \ - } \ - _FP_FRAC_SLL_2(X, 1); \ - q >>= 1; \ - } \ - _FP_FRAC_SLL_4(R, (_FP_WORKBITS)); \ - if (X##_f[0] | X##_f[1]) \ - { \ - if (S##_f[1] < X##_f[1] || \ - (S##_f[1] == X##_f[1] && \ - S##_f[0] < X##_f[0])) \ - R##_f[0] |= _FP_WORK_ROUND; \ - R##_f[0] |= _FP_WORK_STICKY; \ - } \ - } while (0) - -#define FP_CMP_E(r,X,Y,un) _FP_CMP(E,4,r,X,Y,un) -#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,4,r,X,Y) - -#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,4,r,X,rsz,rsg) -#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,4,X,r,rs,rt) - -#define _FP_FRAC_HIGH_E(X) (X##_f[2]) -#define _FP_FRAC_HIGH_RAW_E(X) (X##_f[1]) - -#else /* not _FP_W_TYPE_SIZE < 64 */ -union _FP_UNION_E -{ - long double flt /* __attribute__((mode(TF))) */ ; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned long pad : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E); - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_E; - unsigned long frac : _FP_W_TYPE_SIZE; -#else - unsigned long frac : _FP_W_TYPE_SIZE; - unsigned exp : _FP_EXPBITS_E; - unsigned sign : 1; -#endif - } bits; -}; - -#define FP_DECL_E(X) _FP_DECL(2,X) - -#define FP_UNPACK_RAW_E(X, val) \ - do { \ - union _FP_UNION_E _flo; _flo.flt = (val); \ - \ - X##_f0 = _flo.bits.frac; \ - X##_f1 = 0; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_UNPACK_RAW_EP(X, val) \ - do { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - X##_f0 = _flo->bits.frac; \ - X##_f1 = 0; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_PACK_RAW_E(val, X) \ - do { \ - union _FP_UNION_E _flo; \ - \ - if (X##_e) X##_f0 |= _FP_IMPLBIT_E; \ - else X##_f0 &= ~(_FP_IMPLBIT_E); \ - _flo.bits.frac = X##_f0; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - \ - (val) = _flo.flt; \ - } while (0) - -#define FP_PACK_RAW_EP(fs, val, X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - if (X##_e) X##_f0 |= _FP_IMPLBIT_E; \ - else X##_f0 &= ~(_FP_IMPLBIT_E); \ - _flo->bits.frac = X##_f0; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } \ - } while (0) - - -#define FP_UNPACK_E(X,val) \ - do { \ - FP_UNPACK_RAW_E(X,val); \ - _FP_UNPACK_CANONICAL(E,2,X); \ - } while (0) - -#define FP_UNPACK_EP(X,val) \ - do { \ - FP_UNPACK_RAW_EP(X,val); \ - _FP_UNPACK_CANONICAL(E,2,X); \ - } while (0) - -#define FP_PACK_E(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,2,X); \ - FP_PACK_RAW_E(val,X); \ - } while (0) - -#define FP_PACK_EP(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,2,X); \ - FP_PACK_RAW_EP(val,X); \ - } while (0) - -#define FP_ISSIGNAN_E(X) _FP_ISSIGNAN(E,2,X) -#define FP_NEG_E(R,X) _FP_NEG(E,2,R,X) -#define FP_ADD_E(R,X,Y) _FP_ADD(E,2,R,X,Y) -#define FP_SUB_E(R,X,Y) _FP_SUB(E,2,R,X,Y) -#define FP_MUL_E(R,X,Y) _FP_MUL(E,2,R,X,Y) -#define FP_DIV_E(R,X,Y) _FP_DIV(E,2,R,X,Y) -#define FP_SQRT_E(R,X) _FP_SQRT(E,2,R,X) - -/* - * Square root algorithms: - * We have just one right now, maybe Newton approximation - * should be added for those machines where division is fast. - * We optimize it by doing most of the calculations - * in one UWtype registers instead of two, although we don't - * have to. - */ -#define _FP_SQRT_MEAT_E(R, S, T, X, q) \ - do { \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - _FP_FRAC_SRL_2(X, (_FP_WORKBITS)); \ - while (q) \ - { \ - T##_f0 = S##_f0 + q; \ - if (T##_f0 <= X##_f0) \ - { \ - S##_f0 = T##_f0 + q; \ - X##_f0 -= T##_f0; \ - R##_f0 += q; \ - } \ - _FP_FRAC_SLL_1(X, 1); \ - q >>= 1; \ - } \ - _FP_FRAC_SLL_2(R, (_FP_WORKBITS)); \ - if (X##_f0) \ - { \ - if (S##_f0 < X##_f0) \ - R##_f0 |= _FP_WORK_ROUND; \ - R##_f0 |= _FP_WORK_STICKY; \ - } \ - } while (0) - -#define FP_CMP_E(r,X,Y,un) _FP_CMP(E,2,r,X,Y,un) -#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,2,r,X,Y) - -#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,2,r,X,rsz,rsg) -#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,2,X,r,rs,rt) - -#define _FP_FRAC_HIGH_E(X) (X##_f1) -#define _FP_FRAC_HIGH_RAW_E(X) (X##_f0) - -#endif /* not _FP_W_TYPE_SIZE < 64 */ diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fabsq.c linux/arch/sparc64/math-emu/fabsq.c --- v2.3.15/linux/arch/sparc64/math-emu/fabsq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fabsq.c Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* $Id: fabsq.c,v 1.5 1999/05/28 13:42:27 jj Exp $ - * arch/sparc64/math-emu/fabsq.c - * - * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz) - * - */ - -int FABSQ(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0] & 0x7fffffffffffffffUL; - rd[1] = rs2[1]; - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/faddd.c linux/arch/sparc64/math-emu/faddd.c --- v2.3.15/linux/arch/sparc64/math-emu/faddd.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/faddd.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: faddd.c,v 1.4 1999/05/28 13:43:17 jj Exp $ - * arch/sparc64/math-emu/faddd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FADDD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - FP_ADD_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/faddq.c linux/arch/sparc64/math-emu/faddq.c --- v2.3.15/linux/arch/sparc64/math-emu/faddq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/faddq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: faddq.c,v 1.4 1999/05/28 13:43:19 jj Exp $ - * arch/sparc64/math-emu/faddq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FADDQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - FP_ADD_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fadds.c linux/arch/sparc64/math-emu/fadds.c --- v2.3.15/linux/arch/sparc64/math-emu/fadds.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fadds.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fadds.c,v 1.4 1999/05/28 13:43:25 jj Exp $ - * arch/sparc64/math-emu/fadds.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FADDS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - FP_ADD_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fcmpeq.c linux/arch/sparc64/math-emu/fcmpeq.c --- v2.3.15/linux/arch/sparc64/math-emu/fcmpeq.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/fcmpeq.c Wed Dec 31 16:00:00 1969 @@ -1,39 +0,0 @@ -/* $Id: fcmpeq.c,v 1.6 1999/07/30 09:35:40 davem Exp $ - * arch/sparc64/math-emu/fcmpeq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FCMPEQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); - long ret; - long fccno = (long)rd; - unsigned long fsr; - - FP_UNPACK_RAW_QP(A, rs1); - FP_UNPACK_RAW_QP(B, rs2); - FP_CMP_Q(ret, B, A, 3); - if (ret == 3) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - rd = (void *)(((long)rd)&~3); - if (ret == -1) ret = 2; - fsr = current->thread.xfsr[0]; - 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; - } - current->thread.xfsr[0] = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fcmpq.c linux/arch/sparc64/math-emu/fcmpq.c --- v2.3.15/linux/arch/sparc64/math-emu/fcmpq.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/fcmpq.c Wed Dec 31 16:00:00 1969 @@ -1,39 +0,0 @@ -/* $Id: fcmpq.c,v 1.6 1999/07/30 09:35:40 davem Exp $ - * arch/sparc64/math-emu/fcmpq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FCMPQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); - long ret; - long fccno = (long)rd; - unsigned long fsr; - - FP_UNPACK_RAW_QP(A, rs1); - FP_UNPACK_RAW_QP(B, rs2); - FP_CMP_Q(ret, B, A, 3); - if (ret == 3 && (FP_ISSIGNAN_Q(A) || FP_ISSIGNAN_Q(B))) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - rd = (void *)(((long)rd)&~3); - if (ret == -1) ret = 2; - fsr = current->thread.xfsr[0]; - 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; - } - current->thread.xfsr[0] = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdivd.c linux/arch/sparc64/math-emu/fdivd.c --- v2.3.15/linux/arch/sparc64/math-emu/fdivd.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdivd.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fdivd.c,v 1.4 1999/05/28 13:43:36 jj Exp $ - * arch/sparc64/math-emu/fdivd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FDIVD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - FP_DIV_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdivq.c linux/arch/sparc64/math-emu/fdivq.c --- v2.3.15/linux/arch/sparc64/math-emu/fdivq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdivq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fdivq.c,v 1.4 1999/05/28 13:43:41 jj Exp $ - * arch/sparc64/math-emu/fdivq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FDIVQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - FP_DIV_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdivs.c linux/arch/sparc64/math-emu/fdivs.c --- v2.3.15/linux/arch/sparc64/math-emu/fdivs.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdivs.c Wed Dec 31 16:00:00 1969 @@ -1,24 +0,0 @@ -/* $Id: fdivs.c,v 1.4 1999/05/28 13:43:45 jj Exp $ - * arch/sparc64/math-emu/fdivs.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FDIVS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - FP_DIV_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} - diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdmulq.c linux/arch/sparc64/math-emu/fdmulq.c --- v2.3.15/linux/arch/sparc64/math-emu/fdmulq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdmulq.c Wed Dec 31 16:00:00 1969 @@ -1,26 +0,0 @@ -/* $Id: fdmulq.c,v 1.4 1999/05/28 13:43:48 jj Exp $ - * arch/sparc64/math-emu/fdmulq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FDMULQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_DP(IN, rs1); - FP_CONV(Q,D,2,1,A,IN); - FP_UNPACK_DP(IN, rs2); - FP_CONV(Q,D,2,1,B,IN); - FP_MUL_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdtoi.c linux/arch/sparc64/math-emu/fdtoi.c --- v2.3.15/linux/arch/sparc64/math-emu/fdtoi.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdtoi.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* $Id: fdtoi.c,v 1.3 1999/05/28 13:43:52 jj Exp $ - * arch/sparc64/math-emu/fdtoi.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FDTOI(int *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); - int r; - - FP_UNPACK_DP(A, rs2); - FP_TO_INT_D(r, A, 32, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdtoq.c linux/arch/sparc64/math-emu/fdtoq.c --- v2.3.15/linux/arch/sparc64/math-emu/fdtoq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdtoq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fdtoq.c,v 1.4 1999/05/28 13:43:56 jj Exp $ - * arch/sparc64/math-emu/fdtoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FDTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_Q(R); - - FP_UNPACK_DP(A, rs2); - FP_CONV(Q,D,2,1,R,A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdtos.c linux/arch/sparc64/math-emu/fdtos.c --- v2.3.15/linux/arch/sparc64/math-emu/fdtos.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdtos.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fdtos.c,v 1.4 1999/05/28 13:43:58 jj Exp $ - * arch/sparc64/math-emu/fdtos.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FDTOS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_S(R); - - FP_UNPACK_DP(A, rs2); - FP_CONV(S,D,1,1,R,A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fdtox.c linux/arch/sparc64/math-emu/fdtox.c --- v2.3.15/linux/arch/sparc64/math-emu/fdtox.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fdtox.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* $Id: fdtox.c,v 1.3 1999/05/28 13:44:02 jj Exp $ - * arch/sparc64/math-emu/fdtox.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FDTOX(long *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); - long r; - - FP_UNPACK_DP(A, rs2); - FP_TO_INT_D(r, A, 64, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fitoq.c linux/arch/sparc64/math-emu/fitoq.c --- v2.3.15/linux/arch/sparc64/math-emu/fitoq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fitoq.c Wed Dec 31 16:00:00 1969 @@ -1,22 +0,0 @@ -/* $Id: fitoq.c,v 1.5 1999/05/28 13:44:06 jj Exp $ - * arch/sparc64/math-emu/fitoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FITOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(R); - int a = *(int *)rs2; - - FP_FROM_INT_Q(R, a, 32, int); - FP_PACK_QP(rd, R); - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fmovq.c linux/arch/sparc64/math-emu/fmovq.c --- v2.3.15/linux/arch/sparc64/math-emu/fmovq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fmovq.c Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* $Id: fmovq.c,v 1.2 1999/05/28 13:44:09 jj Exp $ - * arch/sparc64/math-emu/fmovq.c - * - * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz) - * - */ - -int FMOVQ(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0]; - rd[1] = rs2[1]; - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fmuld.c linux/arch/sparc64/math-emu/fmuld.c --- v2.3.15/linux/arch/sparc64/math-emu/fmuld.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fmuld.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fmuld.c,v 1.4 1999/05/28 13:44:11 jj Exp $ - * arch/sparc64/math-emu/fmuld.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FMULD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - FP_MUL_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fmulq.c linux/arch/sparc64/math-emu/fmulq.c --- v2.3.15/linux/arch/sparc64/math-emu/fmulq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fmulq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fmulq.c,v 1.4 1999/05/28 13:44:14 jj Exp $ - * arch/sparc64/math-emu/fmulq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FMULQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - FP_MUL_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fmuls.c linux/arch/sparc64/math-emu/fmuls.c --- v2.3.15/linux/arch/sparc64/math-emu/fmuls.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fmuls.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fmuls.c,v 1.4 1999/05/28 13:44:18 jj Exp $ - * arch/sparc64/math-emu/fmuls.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FMULS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - FP_MUL_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fnegq.c linux/arch/sparc64/math-emu/fnegq.c --- v2.3.15/linux/arch/sparc64/math-emu/fnegq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fnegq.c Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* $Id: fnegq.c,v 1.6 1999/05/28 13:44:21 jj Exp $ - * arch/sparc64/math-emu/fnegq.c - * - * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz) - * - */ - -int FNEGQ(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0] ^ 0x8000000000000000UL; - rd[1] = rs2[1]; - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fqtod.c linux/arch/sparc64/math-emu/fqtod.c --- v2.3.15/linux/arch/sparc64/math-emu/fqtod.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fqtod.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fqtod.c,v 1.4 1999/05/28 13:44:24 jj Exp $ - * arch/sparc64/math-emu/fqtod.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FQTOD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_D(R); - - FP_UNPACK_QP(A, rs2); - FP_CONV(D,Q,1,2,R,A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fqtoi.c linux/arch/sparc64/math-emu/fqtoi.c --- v2.3.15/linux/arch/sparc64/math-emu/fqtoi.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fqtoi.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* $Id: fqtoi.c,v 1.4 1999/05/28 13:44:26 jj Exp $ - * arch/sparc64/math-emu/fqtoi.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FQTOI(int *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); - int r; - - FP_UNPACK_QP(A, rs2); - FP_TO_INT_Q(r, A, 32, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fqtos.c linux/arch/sparc64/math-emu/fqtos.c --- v2.3.15/linux/arch/sparc64/math-emu/fqtos.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fqtos.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fqtos.c,v 1.4 1999/05/28 13:44:30 jj Exp $ - * arch/sparc64/math-emu/fqtos.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "single.h" - -int FQTOS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_S(R); - - FP_UNPACK_QP(A, rs2); - FP_CONV(S,Q,1,2,R,A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fqtox.c linux/arch/sparc64/math-emu/fqtox.c --- v2.3.15/linux/arch/sparc64/math-emu/fqtox.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fqtox.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* $Id: fqtox.c,v 1.4 1999/05/28 13:44:34 jj Exp $ - * arch/sparc64/math-emu/fqtox.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FQTOX(long *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); - long r; - - FP_UNPACK_QP(A, rs2); - FP_TO_INT_Q(r, A, 64, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fsmuld.c linux/arch/sparc64/math-emu/fsmuld.c --- v2.3.15/linux/arch/sparc64/math-emu/fsmuld.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fsmuld.c Wed Dec 31 16:00:00 1969 @@ -1,26 +0,0 @@ -/* $Id: fsmuld.c,v 1.4 1999/05/28 13:44:37 jj Exp $ - * arch/sparc64/math-emu/fsmuld.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FSMULD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_SP(IN, rs1); - FP_CONV(D,S,1,1,A,IN); - FP_UNPACK_SP(IN, rs2); - FP_CONV(D,S,1,1,B,IN); - FP_MUL_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fsqrtd.c linux/arch/sparc64/math-emu/fsqrtd.c --- v2.3.15/linux/arch/sparc64/math-emu/fsqrtd.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fsqrtd.c Wed Dec 31 16:00:00 1969 @@ -1,22 +0,0 @@ -/* $Id: fsqrtd.c,v 1.4 1999/05/28 13:44:39 jj Exp $ - * arch/sparc64/math-emu/fsqrtd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FSQRTD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs2); - FP_SQRT_D(R, A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fsqrtq.c linux/arch/sparc64/math-emu/fsqrtq.c --- v2.3.15/linux/arch/sparc64/math-emu/fsqrtq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fsqrtq.c Wed Dec 31 16:00:00 1969 @@ -1,22 +0,0 @@ -/* $Id: fsqrtq.c,v 1.5 1999/05/28 13:44:44 jj Exp $ - * arch/sparc64/math-emu/fsqrtq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FSQRTQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs2); - FP_SQRT_Q(R, A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fsqrts.c linux/arch/sparc64/math-emu/fsqrts.c --- v2.3.15/linux/arch/sparc64/math-emu/fsqrts.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fsqrts.c Wed Dec 31 16:00:00 1969 @@ -1,22 +0,0 @@ -/* $Id: fsqrts.c,v 1.4 1999/05/28 13:44:48 jj Exp $ - * arch/sparc64/math-emu/fsqrts.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSQRTS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs2); - FP_SQRT_S(R, A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fstod.c linux/arch/sparc64/math-emu/fstod.c --- v2.3.15/linux/arch/sparc64/math-emu/fstod.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fstod.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fstod.c,v 1.4 1999/05/28 13:44:51 jj Exp $ - * arch/sparc64/math-emu/fstod.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FSTOD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_D(R); - - FP_UNPACK_SP(A, rs2); - FP_CONV(D,S,1,1,R,A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fstoi.c linux/arch/sparc64/math-emu/fstoi.c --- v2.3.15/linux/arch/sparc64/math-emu/fstoi.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fstoi.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* $Id: fstoi.c,v 1.3 1999/05/28 13:44:54 jj Exp $ - * arch/sparc64/math-emu/fstoi.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSTOI(int *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); - int r; - - FP_UNPACK_SP(A, rs2); - FP_TO_INT_S(r, A, 32, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fstoq.c linux/arch/sparc64/math-emu/fstoq.c --- v2.3.15/linux/arch/sparc64/math-emu/fstoq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fstoq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fstoq.c,v 1.4 1999/05/28 13:44:58 jj Exp $ - * arch/sparc64/math-emu/fstoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "single.h" - -int FSTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_Q(R); - - FP_UNPACK_SP(A, rs2); - FP_CONV(Q,S,2,1,R,A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fstox.c linux/arch/sparc64/math-emu/fstox.c --- v2.3.15/linux/arch/sparc64/math-emu/fstox.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fstox.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* $Id: fstox.c,v 1.3 1999/05/28 13:45:01 jj Exp $ - * arch/sparc64/math-emu/fstox.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSTOX(long *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); - long r; - - FP_UNPACK_SP(A, rs2); - FP_TO_INT_S(r, A, 64, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fsubd.c linux/arch/sparc64/math-emu/fsubd.c --- v2.3.15/linux/arch/sparc64/math-emu/fsubd.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/fsubd.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fsubd.c,v 1.5 1999/08/02 14:08:04 jj Exp $ - * arch/sparc64/math-emu/fsubd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FSUBD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - FP_SUB_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fsubq.c linux/arch/sparc64/math-emu/fsubq.c --- v2.3.15/linux/arch/sparc64/math-emu/fsubq.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/fsubq.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fsubq.c,v 1.5 1999/08/02 14:08:06 jj Exp $ - * arch/sparc64/math-emu/fsubq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FSUBQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - FP_SUB_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fsubs.c linux/arch/sparc64/math-emu/fsubs.c --- v2.3.15/linux/arch/sparc64/math-emu/fsubs.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/fsubs.c Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: fsubs.c,v 1.5 1999/08/02 14:08:07 jj Exp $ - * arch/sparc64/math-emu/fsubs.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSUBS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - FP_SUB_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/fxtoq.c linux/arch/sparc64/math-emu/fxtoq.c --- v2.3.15/linux/arch/sparc64/math-emu/fxtoq.c Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/fxtoq.c Wed Dec 31 16:00:00 1969 @@ -1,22 +0,0 @@ -/* $Id: fxtoq.c,v 1.5 1999/05/28 13:45:15 jj Exp $ - * arch/sparc64/math-emu/fxtoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FXTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(R); - long a = *(long *)rs2; - - FP_FROM_INT_Q(R, a, 64, long); - FP_PACK_QP(rd, R); - return 0; -} diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/math.c linux/arch/sparc64/math-emu/math.c --- v2.3.15/linux/arch/sparc64/math-emu/math.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/math.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: math.c,v 1.9 1999/07/30 09:35:41 davem Exp $ +/* $Id: math.c,v 1.10 1999/08/13 16:02:06 jj Exp $ * arch/sparc64/math-emu/math.c * * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz) @@ -17,46 +17,61 @@ #include "sfp-util.h" #include "soft-fp.h" - -#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) +#include "single.h" +#include "double.h" +#include "quad.h" + +/* QUAD - ftt == 3 */ +#define FMOVQ 0x003 +#define FNEGQ 0x007 +#define FABSQ 0x00b +#define FSQRTQ 0x02b +#define FADDQ 0x043 +#define FSUBQ 0x047 +#define FMULQ 0x04b +#define FDIVQ 0x04f +#define FDMULQ 0x06e +#define FQTOX 0x083 +#define FXTOQ 0x08c +#define FQTOS 0x0c7 +#define FQTOD 0x0cb +#define FITOQ 0x0cc +#define FSTOQ 0x0cd +#define FDTOQ 0x0ce +#define FQTOI 0x0d3 +/* SUBNORMAL - ftt == 2 */ +#define FSQRTS 0x029 +#define FSQRTD 0x02a +#define FADDS 0x041 +#define FADDD 0x042 +#define FSUBS 0x045 +#define FSUBD 0x046 +#define FMULS 0x049 +#define FMULD 0x04a +#define FDIVS 0x04d +#define FDIVD 0x04e +#define FSMULD 0x069 +#define FSTOX 0x081 +#define FDTOX 0x082 +#define FDTOS 0x0c6 +#define FSTOD 0x0c9 +#define FSTOI 0x0d1 +#define FDTOI 0x0d2 +/* FPOP2 */ +#define FCMPQ 0x053 +#define FCMPEQ 0x057 +#define FMOVQ0 0x003 +#define FMOVQ1 0x043 +#define FMOVQ2 0x083 +#define FMOVQ3 0x0c3 +#define FMOVQI 0x103 +#define FMOVQX 0x183 +#define FMOVQZ 0x027 +#define FMOVQLE 0x047 +#define FMOVQLZ 0x067 +#define FMOVQNZ 0x0a7 +#define FMOVQGZ 0x0c7 +#define FMOVQGE 0x0e7 #define FSR_TEM_SHIFT 23UL #define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT) @@ -73,7 +88,7 @@ * * We return 0 if a SIGFPE should be sent, 1 otherwise. */ -static int record_exception(struct pt_regs *regs, int eflag) +static inline int record_exception(struct pt_regs *regs, int eflag) { u64 fsr = current->thread.xfsr[0]; int would_trap; @@ -133,18 +148,31 @@ return (would_trap ? 0 : 1); } +typedef union { + u32 s; + u64 d; + u64 q[2]; +} *argp; + 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 type = 0; + /* ftt tells which ftt it may happen in, r is rd, b is rs2 and a is rs1. The *u arg tells + whether the argument should be packed/unpacked (0 - do not unpack/pack, 1 - unpack/pack) + non-u args tells the size of the argument (0 - no argument, 1 - single, 2 - double, 3 - quad */ +#define TYPE(ftt, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6) | (ftt << 9) int freg; static u64 zero[2] = { 0L, 0L }; int flags; - int (*func)(void *,void *,void *) = NULL; + FP_DECL_EX; + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + int IR; + long XR, xfsr; if(tstate & TSTATE_PRIV) die_if_kernel("FPQuad from kernel", regs); @@ -154,55 +182,145 @@ 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; + case FMOVQ: + case FNEGQ: + case FABSQ: TYPE(3,3,0,3,0,0,0); break; + case FSQRTQ: TYPE(3,3,1,3,1,0,0); break; + case FADDQ: + case FSUBQ: + case FMULQ: + case FDIVQ: TYPE(3,3,1,3,1,3,1); break; + case FDMULQ: TYPE(3,3,1,2,1,2,1); break; + case FQTOX: TYPE(3,2,0,3,1,0,0); break; + case FXTOQ: TYPE(3,3,1,2,0,0,0); break; + case FQTOS: TYPE(3,1,1,3,1,0,0); break; + case FQTOD: TYPE(3,2,1,3,1,0,0); break; + case FITOQ: TYPE(3,3,1,1,0,0,0); break; + case FSTOQ: TYPE(3,3,1,1,1,0,0); break; + case FDTOQ: TYPE(3,3,1,2,1,0,0); break; + case FQTOI: TYPE(3,1,0,3,1,0,0); 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; + case FSQRTS: TYPE(2,1,1,1,1,0,0); break; + case FSQRTD: TYPE(2,2,1,2,1,0,0); break; + case FADDD: + case FSUBD: + case FMULD: + case FDIVD: TYPE(2,2,1,2,1,2,1); break; + case FADDS: + case FSUBS: + case FMULS: + case FDIVS: TYPE(2,1,1,1,1,1,1); break; + case FSMULD: TYPE(2,2,1,1,1,1,1); break; + case FSTOX: TYPE(2,2,0,1,1,0,0); break; + case FDTOX: TYPE(2,2,0,2,1,0,0); break; + case FDTOS: TYPE(2,1,1,2,1,0,0); break; + case FSTOD: TYPE(2,2,1,1,1,0,0); break; + case FSTOI: TYPE(2,1,0,1,1,0,0); break; + case FDTOI: TYPE(2,1,0,2,1,0,0); break; } } else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ { + IR = 2; switch ((insn >> 5) & 0x1ff) { - case 0x053: type = 0x30f; func = FCMPQ; break; - case 0x057: type = 0x30f; func = FCMPEQ; break; + case FCMPQ: TYPE(3,0,0,3,1,3,1); break; + case FCMPEQ: TYPE(3,0,0,3,1,3,1); break; + /* Now the conditional fmovq support */ + case FMOVQ0: + case FMOVQ1: + case FMOVQ2: + case FMOVQ3: + /* fmovq %fccX, %fY, %fZ */ + if (!((insn >> 11) & 3)) + XR = current->thread.xfsr[0] >> 10; + else + XR = current->thread.xfsr[0] >> (30 + ((insn >> 10) & 0x6)); + XR &= 3; + IR = 0; + switch ((insn >> 14) & 0x7) { + /* case 0: IR = 0; break; */ /* Never */ + case 1: if (XR) IR = 1; break; /* Not Equal */ + case 2: if (XR == 1 || XR == 2) IR = 1; break; /* Less or Greater */ + case 3: if (XR & 1) IR = 1; break; /* Unordered or Less */ + case 4: if (XR == 1) IR = 1; break; /* Less */ + case 5: if (XR & 2) IR = 1; break; /* Unordered or Greater */ + case 6: if (XR == 2) IR = 1; break; /* Greater */ + case 7: if (XR == 3) IR = 1; break; /* Unordered */ + } + if ((insn >> 14) & 8) + IR ^= 1; + break; + case FMOVQI: + case FMOVQX: + /* fmovq %[ix]cc, %fY, %fZ */ + XR = regs->tstate >> 32; + if ((insn >> 5) & 0x80) + XR >>= 4; + XR &= 0xf; + IR = 0; + freg = ((XR >> 2) ^ XR) & 2; + switch ((insn >> 14) & 0x7) { + /* case 0: IR = 0; break; */ /* Never */ + case 1: if (XR & 4) IR = 1; break; /* Equal */ + case 2: if ((XR & 4) || freg) IR = 1; break; /* Less or Equal */ + case 3: if (freg) IR = 1; break; /* Less */ + case 4: if (XR & 5) IR = 1; break; /* Less or Equal Unsigned */ + case 5: if (XR & 1) IR = 1; break; /* Carry Set */ + case 6: if (XR & 8) IR = 1; break; /* Negative */ + case 7: if (XR & 2) IR = 1; break; /* Overflow Set */ + } + if ((insn >> 14) & 8) + IR ^= 1; + break; + case FMOVQZ: + case FMOVQLE: + case FMOVQLZ: + case FMOVQNZ: + case FMOVQGZ: + case FMOVQGE: + freg = (insn >> 14) & 0x1f; + if (!freg) + XR = 0; + else if (freg < 16) + XR = regs->u_regs[freg]; + else if (current->thread.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + flushw_user (); + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + get_user(XR, &win32->locals[freg - 16]); + } else { + struct reg_window *win; + flushw_user (); + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + get_user(XR, &win->locals[freg - 16]); + } + IR = 0; + switch ((insn >> 10) & 3) { + case 1: if (!XR) IR = 1; break; /* Register Zero */ + case 2: if (XR <= 0) IR = 1; break; /* Register Less Than or Equal to Zero */ + case 3: if (XR < 0) IR = 1; break; /* Register Less Than Zero */ + } + if ((insn >> 10) & 4) + IR ^= 1; + break; + } + if (IR == 0) { + /* The fmov test was false. Do a nop instead */ + current->thread.xfsr[0] &= ~(FSR_CEXC_MASK); + regs->tpc = regs->tnpc; + regs->tnpc += 4; + return 1; + } else if (IR == 1) { + /* Change the instruction into plain fmovq */ + insn = (insn & 0x3e00001f) | 0x81a00060; + TYPE(3,3,0,3,0,0,0); } } } if (type) { - void *rs1 = NULL, *rs2 = NULL, *rd = NULL; + argp rs1 = NULL, rs2 = NULL, rd = NULL; freg = (current->thread.xfsr[0] >> 14) & 0xf; - if (freg != (type >> 8)) + if (freg != (type >> 9)) goto err; current->thread.xfsr[0] &= ~0x1c000; freg = ((insn >> 14) & 0x1f); @@ -212,34 +330,43 @@ goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); - case 1: rs1 = (void *)&f->regs[freg]; + case 1: rs1 = (argp)&f->regs[freg]; flags = (freg < 32) ? FPRS_DL : FPRS_DU; if (!(current->thread.fpsaved[0] & flags)) - rs1 = (void *)&zero; + rs1 = (argp)&zero; break; } + switch (type & 0x7) { + case 7: FP_UNPACK_QP (QA, rs1); break; + case 6: FP_UNPACK_DP (DA, rs1); break; + case 5: FP_UNPACK_SP (SA, rs1); break; + } freg = (insn & 0x1f); - switch ((type >> 2) & 0x3) { + switch ((type >> 3) & 0x3) { case 3: if (freg & 2) { current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); - case 1: rs2 = (void *)&f->regs[freg]; + case 1: rs2 = (argp)&f->regs[freg]; flags = (freg < 32) ? FPRS_DL : FPRS_DU; if (!(current->thread.fpsaved[0] & flags)) - rs2 = (void *)&zero; + rs2 = (argp)&zero; break; } + switch ((type >> 3) & 0x7) { + case 7: FP_UNPACK_QP (QB, rs2); break; + case 6: FP_UNPACK_DP (DB, rs2); break; + case 5: FP_UNPACK_SP (SB, rs2); break; + } freg = ((insn >> 25) & 0x1f); - switch ((type >> 4) & 0x3) { - case 0: rd = (void *)(long)(freg & 3); break; + switch ((type >> 6) & 0x3) { case 3: if (freg & 2) { current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); - case 1: rd = (void *)&f->regs[freg]; + case 1: rd = (argp)&f->regs[freg]; flags = (freg < 32) ? FPRS_DL : FPRS_DU; if (!(current->thread.fpsaved[0] & FPRS_FEF)) { current->thread.fpsaved[0] = FPRS_FEF; @@ -254,9 +381,85 @@ current->thread.fpsaved[0] |= flags; break; } - flags = func(rd, rs2, rs1); - if(flags != 0) - return record_exception(regs, flags); + switch ((insn >> 5) & 0x1ff) { + /* + */ + case FADDS: FP_ADD_S (SR, SA, SB); break; + case FADDD: FP_ADD_D (DR, DA, DB); break; + case FADDQ: FP_ADD_Q (QR, QA, QB); break; + /* - */ + case FSUBS: FP_SUB_S (SR, SA, SB); break; + case FSUBD: FP_SUB_D (DR, DA, DB); break; + case FSUBQ: FP_SUB_Q (QR, QA, QB); break; + /* * */ + case FMULS: FP_MUL_S (SR, SA, SB); break; + case FSMULD: FP_CONV (D, S, 1, 1, DA, SA); + FP_CONV (D, S, 1, 1, DB, SB); + case FMULD: FP_MUL_D (DR, DA, DB); break; + case FDMULQ: FP_CONV (Q, D, 2, 1, QA, DA); + FP_CONV (Q, D, 2, 1, QB, DB); + case FMULQ: FP_MUL_Q (QR, QA, QB); break; + /* / */ + case FDIVS: FP_DIV_S (SR, SA, SB); break; + case FDIVD: FP_DIV_D (DR, DA, DB); break; + case FDIVQ: FP_DIV_Q (QR, QA, QB); break; + /* sqrt */ + case FSQRTS: FP_SQRT_S (SR, SB); break; + case FSQRTD: FP_SQRT_D (DR, DB); break; + case FSQRTQ: FP_SQRT_Q (QR, QB); break; + /* mov */ + case FMOVQ: rd->q[0] = rs2->q[0]; rd->q[1] = rs2->q[1]; break; + case FABSQ: rd->q[0] = rs2->q[0] & 0x7fffffffffffffffUL; rd->q[1] = rs2->q[1]; break; + case FNEGQ: rd->q[0] = rs2->q[0] ^ 0x8000000000000000UL; rd->q[1] = rs2->q[1]; break; + /* float to int */ + case FSTOI: FP_TO_INT_S (IR, SB, 32, 1); break; + case FDTOI: FP_TO_INT_D (IR, DB, 32, 1); break; + case FQTOI: FP_TO_INT_Q (IR, QB, 32, 1); break; + case FSTOX: FP_TO_INT_S (XR, SB, 64, 1); break; + case FDTOX: FP_TO_INT_D (XR, DB, 64, 1); break; + case FQTOX: FP_TO_INT_Q (XR, QB, 64, 1); break; + /* int to float */ + case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break; + case FXTOQ: XR = rs2->d; FP_FROM_INT_Q (QR, XR, 64, long); break; + /* float to float */ + case FSTOD: FP_CONV (D, S, 1, 1, DR, SB); break; + case FSTOQ: FP_CONV (Q, S, 2, 1, QR, SB); break; + case FDTOQ: FP_CONV (Q, D, 2, 1, QR, DB); break; + case FDTOS: FP_CONV (S, D, 1, 1, SR, DB); break; + case FQTOS: FP_CONV (S, Q, 1, 2, SR, QB); break; + case FQTOD: FP_CONV (D, Q, 1, 2, DR, QB); break; + /* comparison */ + case FCMPQ: + case FCMPEQ: + FP_CMP_Q(XR, QB, QA, 3); + if (XR == 3 && + (((insn >> 5) & 0x1ff) == FCMPEQ || + FP_ISSIGNAN_Q(QA) || + FP_ISSIGNAN_Q(QB))) + FP_SET_EXCEPTION (FP_EX_INVALID); + } + if (!FP_INHIBIT_RESULTS) { + switch ((type >> 6) & 0x7) { + case 0: xfsr = current->thread.xfsr[0]; + if (XR == -1) XR = 2; + switch (freg & 3) { + /* fcc0, 1, 2, 3 */ + case 0: xfsr &= ~0xc00; xfsr |= (XR << 10); break; + case 1: xfsr &= ~0x300000000UL; xfsr |= (XR << 32); break; + case 2: xfsr &= ~0xc00000000UL; xfsr |= (XR << 34); break; + case 3: xfsr &= ~0x3000000000UL; xfsr |= (XR << 36); break; + } + current->thread.xfsr[0] = xfsr; + break; + case 1: rd->s = IR; break; + case 2: rd->d = XR; break; + case 5: FP_PACK_SP (rd, SR); break; + case 6: FP_PACK_DP (rd, DR); break; + case 7: FP_PACK_QP (rd, QR); break; + } + } + + if(_fex != 0) + return record_exception(regs, _fex); /* Success and no exceptions detected. */ current->thread.xfsr[0] &= ~(FSR_CEXC_MASK); diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/op-1.h linux/arch/sparc64/math-emu/op-1.h --- v2.3.15/linux/arch/sparc64/math-emu/op-1.h Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/op-1.h Wed Dec 31 16:00:00 1969 @@ -1,297 +0,0 @@ -/* Software floating-point emulation. - Basic one-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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_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_DEC_1(X,Y) (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 -#define _FP_MAXFRAC_1 (~(_FP_WS_TYPE)0) - -/* - * 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) - -#define _FP_UNPACK_RAW_1_P(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) - -/* - * 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) - -#define _FP_PACK_RAW_1_P(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) - - -/* - * Multiplication algorithms: - */ - -/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the - multiplication immediately. */ - -#define _FP_MUL_MEAT_1_imm(wfracbits, 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, wfracbits-1, 2*wfracbits); \ - } while (0) - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ - -#define _FP_MUL_MEAT_1_wide(wfracbits, 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, wfracbits-1, 2*wfracbits); \ - R##_f = _Z_f0; \ - } while (0) - -/* Finally, a simple widening multiply algorithm. What fun! */ - -#define _FP_MUL_MEAT_1_hard(wfracbits, 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, wfracbits - 1, 2*wfracbits); \ - 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 != _FP_WORK_ROUND) \ - { \ - 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; \ - } \ - if (X##_f) \ - { \ - if (S##_f < X##_f) \ - R##_f |= _FP_WORK_ROUND; \ - R##_f |= _FP_WORK_STICKY; \ - } \ - } 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) \ - { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs)); \ - } \ - else \ - D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \ - } while (0) diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/op-2.h linux/arch/sparc64/math-emu/op-2.h --- v2.3.15/linux/arch/sparc64/math-emu/op-2.h Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/op-2.h Wed Dec 31 16:00:00 1969 @@ -1,608 +0,0 @@ -/* Software floating-point emulation. - Basic two-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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_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_DEC_2(X,Y) \ - __FP_FRAC_DEC_2(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) (_FP_FRAC_HIGH_##fs(X) & _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 -#define _FP_MAXFRAC_2 (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0) - -/* - * 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,xh); \ - 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 -#ifndef __FP_FRAC_DEC_2 -#define __FP_FRAC_DEC_2(xh, xl, yh, yl) \ - do { \ - UWtype _t = xl; \ - xh -= yh + ((xl -= yl) > _t); \ - } while (0) -#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 -#undef __FP_FRAC_DEC_2 -#define __FP_FRAC_DEC_2(xh, xl, yh, yl) sub_ddmmss(xh, xl, xh, xl, yh, yl) - -#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) - -#define _FP_UNPACK_RAW_2_P(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) - - -/* - * 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) - -#define _FP_PACK_RAW_2_P(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) - - -/* - * Multiplication algorithms: - */ - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ - -#define _FP_MUL_MEAT_2_wide(wfracbits, 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_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), 0, _b_f1, _b_f0, \ - _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0, \ - _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1)); \ - \ - /* 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, wfracbits-1, 2*wfracbits); \ - R##_f0 = _FP_FRAC_WORD_4(_z,0); \ - R##_f1 = _FP_FRAC_WORD_4(_z,1); \ - } while (0) - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. - Do only 3 multiplications instead of four. This one is for machines - where multiplication is much more expensive than subtraction. */ - -#define _FP_MUL_MEAT_2_wide_3mul(wfracbits, R, X, Y, doit) \ - do { \ - _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ - _FP_W_TYPE _d; \ - int _c1, _c2; \ - \ - _b_f0 = X##_f0 + X##_f1; \ - _c1 = _b_f0 < X##_f0; \ - _b_f1 = Y##_f0 + Y##_f1; \ - _c2 = _b_f1 < Y##_f0; \ - doit(_d, _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \ - doit(_FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1), _b_f0, _b_f1); \ - doit(_c_f1, _c_f0, X##_f1, Y##_f1); \ - \ - _b_f0 &= -_c2; \ - _b_f1 &= -_c1; \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), (_c1 & _c2), 0, _d, \ - 0, _FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1)); \ - __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _b_f0); \ - __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _b_f1); \ - __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), \ - 0, _d, _FP_FRAC_WORD_4(_z,0)); \ - __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0); \ - __FP_FRAC_ADD_2(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), \ - _c_f1, _c_f0, \ - _FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,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, wfracbits-1, 2*wfracbits); \ - R##_f0 = _FP_FRAC_WORD_4(_z,0); \ - R##_f1 = _FP_FRAC_WORD_4(_z,1); \ - } while (0) - -#define _FP_MUL_MEAT_2_gmp(wfracbits, R, X, Y) \ - do { \ - _FP_FRAC_DECL_4(_z); \ - _FP_W_TYPE _x[2], _y[2]; \ - _x[0] = X##_f0; _x[1] = X##_f1; \ - _y[0] = Y##_f0; _y[1] = Y##_f1; \ - \ - mpn_mul_n(_z_f, _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, wfracbits-1, 2*wfracbits); \ - R##_f0 = _z_f[0]; \ - R##_f1 = _z_f[1]; \ - } while (0) - -/* Do at most 120x120=240 bits multiplication using double floating - point multiplication. This is useful if floating point - multiplication has much bigger throughput than integer multiply. - It is supposed to work for _FP_W_TYPE_SIZE 64 and wfracbits - between 106 and 120 only. - Caller guarantees that X and Y has (1LLL << (wfracbits - 1)) set. - SETFETZ is a macro which will disable all FPU exceptions and set rounding - towards zero, RESETFE should optionally reset it back. */ - -#define _FP_MUL_MEAT_2_120_240_double(wfracbits, R, X, Y, setfetz, resetfe) \ - do { \ - static const double _const[] = { \ - /* 2^-24 */ 5.9604644775390625e-08, \ - /* 2^-48 */ 3.5527136788005009e-15, \ - /* 2^-72 */ 2.1175823681357508e-22, \ - /* 2^-96 */ 1.2621774483536189e-29, \ - /* 2^28 */ 2.68435456e+08, \ - /* 2^4 */ 1.600000e+01, \ - /* 2^-20 */ 9.5367431640625e-07, \ - /* 2^-44 */ 5.6843418860808015e-14, \ - /* 2^-68 */ 3.3881317890172014e-21, \ - /* 2^-92 */ 2.0194839173657902e-28, \ - /* 2^-116 */ 1.2037062152420224e-35}; \ - double _a240, _b240, _c240, _d240, _e240, _f240, \ - _g240, _h240, _i240, _j240, _k240; \ - union { double d; UDItype i; } _l240, _m240, _n240, _o240, \ - _p240, _q240, _r240, _s240; \ - UDItype _t240, _u240, _v240, _w240, _x240, _y240 = 0; \ - \ - if (wfracbits < 106 || wfracbits > 120) \ - abort(); \ - \ - setfetz; \ - \ - _e240 = (double)(long)(X##_f0 & 0xffffff); \ - _j240 = (double)(long)(Y##_f0 & 0xffffff); \ - _d240 = (double)(long)((X##_f0 >> 24) & 0xffffff); \ - _i240 = (double)(long)((Y##_f0 >> 24) & 0xffffff); \ - _c240 = (double)(long)(((X##_f1 << 16) & 0xffffff) | (X##_f0 >> 48)); \ - _h240 = (double)(long)(((Y##_f1 << 16) & 0xffffff) | (Y##_f0 >> 48)); \ - _b240 = (double)(long)((X##_f1 >> 8) & 0xffffff); \ - _g240 = (double)(long)((Y##_f1 >> 8) & 0xffffff); \ - _a240 = (double)(long)(X##_f1 >> 32); \ - _f240 = (double)(long)(Y##_f1 >> 32); \ - _e240 *= _const[3]; \ - _j240 *= _const[3]; \ - _d240 *= _const[2]; \ - _i240 *= _const[2]; \ - _c240 *= _const[1]; \ - _h240 *= _const[1]; \ - _b240 *= _const[0]; \ - _g240 *= _const[0]; \ - _s240.d = _e240*_j240;\ - _r240.d = _d240*_j240 + _e240*_i240;\ - _q240.d = _c240*_j240 + _d240*_i240 + _e240*_h240;\ - _p240.d = _b240*_j240 + _c240*_i240 + _d240*_h240 + _e240*_g240;\ - _o240.d = _a240*_j240 + _b240*_i240 + _c240*_h240 + _d240*_g240 + _e240*_f240;\ - _n240.d = _a240*_i240 + _b240*_h240 + _c240*_g240 + _d240*_f240; \ - _m240.d = _a240*_h240 + _b240*_g240 + _c240*_f240; \ - _l240.d = _a240*_g240 + _b240*_f240; \ - _k240 = _a240*_f240; \ - _r240.d += _s240.d; \ - _q240.d += _r240.d; \ - _p240.d += _q240.d; \ - _o240.d += _p240.d; \ - _n240.d += _o240.d; \ - _m240.d += _n240.d; \ - _l240.d += _m240.d; \ - _k240 += _l240.d; \ - _s240.d -= ((_const[10]+_s240.d)-_const[10]); \ - _r240.d -= ((_const[9]+_r240.d)-_const[9]); \ - _q240.d -= ((_const[8]+_q240.d)-_const[8]); \ - _p240.d -= ((_const[7]+_p240.d)-_const[7]); \ - _o240.d += _const[7]; \ - _n240.d += _const[6]; \ - _m240.d += _const[5]; \ - _l240.d += _const[4]; \ - if (_s240.d != 0.0) _y240 = 1; \ - if (_r240.d != 0.0) _y240 = 1; \ - if (_q240.d != 0.0) _y240 = 1; \ - if (_p240.d != 0.0) _y240 = 1; \ - _t240 = (DItype)_k240; \ - _u240 = _l240.i; \ - _v240 = _m240.i; \ - _w240 = _n240.i; \ - _x240 = _o240.i; \ - R##_f1 = (_t240 << (128 - (wfracbits - 1))) \ - | ((_u240 & 0xffffff) >> ((wfracbits - 1) - 104)); \ - R##_f0 = ((_u240 & 0xffffff) << (168 - (wfracbits - 1))) \ - | ((_v240 & 0xffffff) << (144 - (wfracbits - 1))) \ - | ((_w240 & 0xffffff) << (120 - (wfracbits - 1))) \ - | ((_x240 & 0xffffff) >> ((wfracbits - 1) - 96)) \ - | _y240; \ - resetfe; \ - } while (0) - -/* - * Division algorithms: - */ - -#define _FP_DIV_MEAT_2_udiv(fs, R, X, Y) \ - do { \ - _FP_W_TYPE _n_f2, _n_f1, _n_f0, _r_f1, _r_f0, _m_f1, _m_f0; \ - if (_FP_FRAC_GT_2(X, Y)) \ - { \ - _n_f2 = X##_f1 >> 1; \ - _n_f1 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1; \ - _n_f0 = X##_f0 << (_FP_W_TYPE_SIZE - 1); \ - } \ - else \ - { \ - R##_e--; \ - _n_f2 = X##_f1; \ - _n_f1 = X##_f0; \ - _n_f0 = 0; \ - } \ - \ - /* Normalize, i.e. make the most significant bit of the \ - denominator set. */ \ - _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs); \ - \ - udiv_qrnnd(R##_f1, _r_f1, _n_f2, _n_f1, Y##_f1); \ - umul_ppmm(_m_f1, _m_f0, R##_f1, Y##_f0); \ - _r_f0 = _n_f0; \ - if (_FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f1--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f1--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - } \ - } \ - _FP_FRAC_DEC_2(_r, _m); \ - \ - if (_r_f1 == Y##_f1) \ - { \ - /* This is a special case, not an optimization \ - (_r/Y##_f1 would not fit into UWtype). \ - As _r is guaranteed to be < Y, R##_f0 can be either \ - (UWtype)-1 or (UWtype)-2. But as we know what kind \ - of bits it is (sticky, guard, round), we don't care. \ - We also don't care what the reminder is, because the \ - guard bit will be set anyway. -jj */ \ - R##_f0 = -1; \ - } \ - else \ - { \ - udiv_qrnnd(R##_f0, _r_f1, _r_f1, _r_f0, Y##_f1); \ - umul_ppmm(_m_f1, _m_f0, R##_f0, Y##_f0); \ - _r_f0 = 0; \ - if (_FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f0--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f0--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - } \ - } \ - if (!_FP_FRAC_EQ_2(_r, _m)) \ - R##_f0 |= _FP_WORK_STICKY; \ - } \ - } 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_##fs-1 - _FP_W_TYPE_SIZE) | \ - X##_f1 >> (_FP_W_TYPE_SIZE - \ - (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE))); \ - _x[2] = X##_f1 << (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE); \ - } \ - else \ - { \ - _x[1] = (X##_f0 << (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE) | \ - X##_f1 >> (_FP_W_TYPE_SIZE - \ - (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE))); \ - _x[2] = X##_f1 << (_FP_WFRACBITS_##fs - _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 != _FP_WORK_ROUND) \ - { \ - 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; \ - S##_f1 += (T##_f0 > S##_f0); \ - _FP_FRAC_DEC_2(X, T); \ - R##_f0 += q; \ - } \ - _FP_FRAC_SLL_2(X, 1); \ - q >>= 1; \ - } \ - if (X##_f0 | X##_f1) \ - { \ - if (S##_f1 < X##_f1 || \ - (S##_f1 == X##_f1 && S##_f0 < X##_f0)) \ - R##_f0 |= _FP_WORK_ROUND; \ - R##_f0 |= _FP_WORK_STICKY; \ - } \ - } 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 { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \ - 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.3.15/linux/arch/sparc64/math-emu/op-4.h linux/arch/sparc64/math-emu/op-4.h --- v2.3.15/linux/arch/sparc64/math-emu/op-4.h Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/op-4.h Wed Dec 31 16:00:00 1969 @@ -1,661 +0,0 @@ -/* Software floating-point emulation. - Basic four-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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_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; \ - if (!_up) \ - for (_i = 3; _i >= _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip]; \ - else \ - { \ - for (_i = 3; _i > _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip] << _up \ - | X##_f[_i-_skip-1] >> _down; \ - X##_f[_i--] = X##_f[0] << _up; \ - } \ - for (; _i >= 0; --_i) \ - X##_f[_i] = 0; \ - } while (0) - -/* This one was broken too */ -#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; \ - if (!_down) \ - for (_i = 0; _i <= 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[3] >> _down; \ - } \ - for (; _i < 4; ++_i) \ - X##_f[_i] = 0; \ - } while (0) - - -/* Right shift with sticky-lsb. - * What this actually means is that we do a standard right-shift, - * but that if any of the bits that fall off the right hand side - * were one then we always set the LSbit. - */ -#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; \ -/* s is now != 0 if we want to set the LSbit */ \ - if (!_down) \ - for (_i = 0; _i <= 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[3] >> _down; \ - } \ - for (; _i < 4; ++_i) \ - X##_f[_i] = 0; \ - /* don't fix the LSB until the very end when we're sure f[0] is stable */ \ - X##_f[0] |= (_s != 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]) - -#define _FP_FRAC_SUB_4(R,X,Y) \ - __FP_FRAC_SUB_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]) - -#define _FP_FRAC_DEC_4(X,Y) \ - __FP_FRAC_DEC_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ - Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) - -#define _FP_FRAC_ADDI_4(X,I) \ - __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I) - -#define _FP_ZEROFRAC_4 0,0,0,0 -#define _FP_MINFRAC_4 0,0,0,1 -#define _FP_MAXFRAC_4 (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0) - -#define _FP_FRAC_ZEROP_4(X) ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0) -#define _FP_FRAC_NEGP_4(X) ((_FP_WS_TYPE)X##_f[3] < 0) -#define _FP_FRAC_OVERP_4(fs,X) (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs) - -#define _FP_FRAC_EQ_4(X,Y) \ - (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1] \ - && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3]) - -#define _FP_FRAC_GT_4(X,Y) \ - (X##_f[3] > Y##_f[3] || \ - (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ - (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ - (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0]) \ - )) \ - )) \ - ) - -#define _FP_FRAC_GE_4(X,Y) \ - (X##_f[3] > Y##_f[3] || \ - (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ - (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ - (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0]) \ - )) \ - )) \ - ) - - -#define _FP_FRAC_CLZ_4(R,X) \ - do { \ - if (X##_f[3]) \ - { \ - __FP_CLZ(R,X##_f[3]); \ - } \ - else if (X##_f[2]) \ - { \ - __FP_CLZ(R,X##_f[2]); \ - R += _FP_W_TYPE_SIZE; \ - } \ - else if (X##_f[1]) \ - { \ - __FP_CLZ(R,X##_f[2]); \ - R += _FP_W_TYPE_SIZE*2; \ - } \ - else \ - { \ - __FP_CLZ(R,X##_f[0]); \ - R += _FP_W_TYPE_SIZE*3; \ - } \ - } while(0) - - -#define _FP_UNPACK_RAW_4(fs, X, val) \ - do { \ - union _FP_UNION_##fs _flo; _flo.flt = (val); \ - X##_f[0] = _flo.bits.frac0; \ - X##_f[1] = _flo.bits.frac1; \ - X##_f[2] = _flo.bits.frac2; \ - X##_f[3] = _flo.bits.frac3; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - } while (0) - -#define _FP_UNPACK_RAW_4_P(fs, X, val) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - X##_f[0] = _flo->bits.frac0; \ - X##_f[1] = _flo->bits.frac1; \ - X##_f[2] = _flo->bits.frac2; \ - X##_f[3] = _flo->bits.frac3; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - } while (0) - -#define _FP_PACK_RAW_4(fs, val, X) \ - do { \ - union _FP_UNION_##fs _flo; \ - _flo.bits.frac0 = X##_f[0]; \ - _flo.bits.frac1 = X##_f[1]; \ - _flo.bits.frac2 = X##_f[2]; \ - _flo.bits.frac3 = X##_f[3]; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - (val) = _flo.flt; \ - } while (0) - -#define _FP_PACK_RAW_4_P(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - _flo->bits.frac0 = X##_f[0]; \ - _flo->bits.frac1 = X##_f[1]; \ - _flo->bits.frac2 = X##_f[2]; \ - _flo->bits.frac3 = X##_f[3]; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - -/* - * Multiplication algorithms: - */ - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ - -#define _FP_MUL_MEAT_4_wide(wfracbits, R, X, Y, doit) \ - do { \ - _FP_FRAC_DECL_8(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ - _FP_FRAC_DECL_2(_d); _FP_FRAC_DECL_2(_e); _FP_FRAC_DECL_2(_f); \ - \ - doit(_FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0), X##_f[0], Y##_f[0]); \ - doit(_b_f1, _b_f0, X##_f[0], Y##_f[1]); \ - doit(_c_f1, _c_f0, X##_f[1], Y##_f[0]); \ - doit(_d_f1, _d_f0, X##_f[1], Y##_f[1]); \ - doit(_e_f1, _e_f0, X##_f[0], Y##_f[2]); \ - doit(_f_f1, _f_f0, X##_f[2], Y##_f[0]); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), 0,_b_f1,_b_f0, \ - 0,0,_FP_FRAC_WORD_8(_z,1)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), 0,_c_f1,_c_f0, \ - _FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2), 0,_d_f1,_d_f0, \ - 0,_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2), 0,_e_f1,_e_f0, \ - _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2), 0,_f_f1,_f_f0, \ - _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2)); \ - doit(_b_f1, _b_f0, X##_f[0], Y##_f[3]); \ - doit(_c_f1, _c_f0, X##_f[3], Y##_f[0]); \ - doit(_d_f1, _d_f0, X##_f[1], Y##_f[2]); \ - doit(_e_f1, _e_f0, X##_f[2], Y##_f[1]); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_b_f1,_b_f0, \ - 0,_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_c_f1,_c_f0, \ - _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_d_f1,_d_f0, \ - _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_e_f1,_e_f0, \ - _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3)); \ - doit(_b_f1, _b_f0, X##_f[2], Y##_f[2]); \ - doit(_c_f1, _c_f0, X##_f[1], Y##_f[3]); \ - doit(_d_f1, _d_f0, X##_f[3], Y##_f[1]); \ - doit(_e_f1, _e_f0, X##_f[2], Y##_f[3]); \ - doit(_f_f1, _f_f0, X##_f[3], Y##_f[2]); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4), 0,_b_f1,_b_f0, \ - 0,_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4), 0,_c_f1,_c_f0, \ - _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4), 0,_d_f1,_d_f0, \ - _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _FP_FRAC_WORD_8(_z,5), 0,_e_f1,_e_f0, \ - 0,_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _FP_FRAC_WORD_8(_z,5), 0,_f_f1,_f_f0, \ - _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _FP_FRAC_WORD_8(_z,5)); \ - doit(_b_f1, _b_f0, X##_f[3], Y##_f[3]); \ - __FP_FRAC_ADD_2(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _b_f1,_b_f0, \ - _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6)); \ - \ - /* 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_8(_z, wfracbits-1, 2*wfracbits); \ - __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0)); \ - } while (0) - -#define _FP_MUL_MEAT_4_gmp(wfracbits, R, X, Y) \ - do { \ - _FP_FRAC_DECL_8(_z); \ - \ - mpn_mul_n(_z_f, _x_f, _y_f, 4); \ - \ - /* 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_8(_z, wfracbits-1, 2*wfracbits); \ - __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0)); \ - } while (0) - -/* - * Helper utility for _FP_DIV_MEAT_4_udiv: - * pppp = m * nnn - */ -#define umul_ppppmnnn(p3,p2,p1,p0,m,n2,n1,n0) \ - do { \ - UWtype _t; \ - umul_ppmm(p1,p0,m,n0); \ - umul_ppmm(p2,_t,m,n1); \ - __FP_FRAC_ADDI_2(p2,p1,_t); \ - umul_ppmm(p3,_t,m,n2); \ - __FP_FRAC_ADDI_2(p3,p2,_t); \ - } while (0) - -/* - * Division algorithms: - */ - -#define _FP_DIV_MEAT_4_udiv(fs, R, X, Y) \ - do { \ - int _i; \ - _FP_FRAC_DECL_4(_n); _FP_FRAC_DECL_4(_m); \ - _FP_FRAC_SET_4(_n, _FP_ZEROFRAC_4); \ - if (_FP_FRAC_GT_4(X, Y)) \ - { \ - _n_f[3] = X##_f[0] << (_FP_W_TYPE_SIZE - 1); \ - _FP_FRAC_SRL_4(X, 1); \ - } \ - else \ - R##_e--; \ - \ - /* Normalize, i.e. make the most significant bit of the \ - denominator set. */ \ - _FP_FRAC_SLL_4(Y, _FP_WFRACXBITS_##fs); \ - \ - for (_i = 3; ; _i--) \ - { \ - if (X##_f[3] == Y##_f[3]) \ - { \ - /* This is a special case, not an optimization \ - (X##_f[3]/Y##_f[3] would not fit into UWtype). \ - As X## is guaranteed to be < Y, R##_f[_i] can be either \ - (UWtype)-1 or (UWtype)-2. */ \ - R##_f[_i] = -1; \ - if (!_i) \ - break; \ - __FP_FRAC_SUB_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ - Y##_f[2], Y##_f[1], Y##_f[0], 0, \ - X##_f[2], X##_f[1], X##_f[0], _n_f[_i]); \ - _FP_FRAC_SUB_4(X, Y, X); \ - if (X##_f[3] > Y##_f[3]) \ - { \ - R##_f[_i] = -2; \ - _FP_FRAC_ADD_4(X, Y, X); \ - } \ - } \ - else \ - { \ - udiv_qrnnd(R##_f[_i], X##_f[3], X##_f[3], X##_f[2], Y##_f[3]); \ - umul_ppppmnnn(_m_f[3], _m_f[2], _m_f[1], _m_f[0], \ - R##_f[_i], Y##_f[2], Y##_f[1], Y##_f[0]); \ - X##_f[2] = X##_f[1]; \ - X##_f[1] = X##_f[0]; \ - X##_f[0] = _n_f[_i]; \ - if (_FP_FRAC_GT_4(_m, X)) \ - { \ - R##_f[_i]--; \ - _FP_FRAC_ADD_4(X, Y, X); \ - if (_FP_FRAC_GE_4(X, Y) && _FP_FRAC_GT_4(_m, X)) \ - { \ - R##_f[_i]--; \ - _FP_FRAC_ADD_4(X, Y, X); \ - } \ - } \ - _FP_FRAC_DEC_4(X, _m); \ - if (!_i) \ - { \ - if (!_FP_FRAC_EQ_4(X, _m)) \ - R##_f[0] |= _FP_WORK_STICKY; \ - break; \ - } \ - } \ - } \ - } 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_4(R, S, T, X, q) \ - do { \ - while (q) \ - { \ - T##_f[3] = S##_f[3] + q; \ - if (T##_f[3] <= X##_f[3]) \ - { \ - S##_f[3] = T##_f[3] + q; \ - X##_f[3] -= T##_f[3]; \ - R##_f[3] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q) \ - { \ - T##_f[2] = S##_f[2] + q; \ - T##_f[3] = S##_f[3]; \ - if (T##_f[3] < X##_f[3] || \ - (T##_f[3] == X##_f[3] && T##_f[2] <= X##_f[2])) \ - { \ - S##_f[2] = T##_f[2] + q; \ - S##_f[3] += (T##_f[2] > S##_f[2]); \ - __FP_FRAC_DEC_2(X##_f[3], X##_f[2], \ - T##_f[3], T##_f[2]); \ - R##_f[2] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q) \ - { \ - T##_f[1] = S##_f[1] + q; \ - T##_f[2] = S##_f[2]; \ - T##_f[3] = S##_f[3]; \ - if (T##_f[3] < X##_f[3] || \ - (T##_f[3] == X##_f[3] && (T##_f[2] < X##_f[2] || \ - (T##_f[2] == X##_f[2] && T##_f[1] <= X##_f[1])))) \ - { \ - S##_f[1] = T##_f[1] + q; \ - S##_f[2] += (T##_f[1] > S##_f[1]); \ - S##_f[3] += (T##_f[2] > S##_f[2]); \ - __FP_FRAC_DEC_3(X##_f[3], X##_f[2], X##_f[1], \ - T##_f[3], T##_f[2], T##_f[1]); \ - R##_f[1] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q != _FP_WORK_ROUND) \ - { \ - T##_f[0] = S##_f[0] + q; \ - T##_f[1] = S##_f[1]; \ - T##_f[2] = S##_f[2]; \ - T##_f[3] = S##_f[3]; \ - if (_FP_FRAC_GE_4(X,T)) \ - { \ - S##_f[0] = T##_f[0] + q; \ - S##_f[1] += (T##_f[0] > S##_f[0]); \ - S##_f[2] += (T##_f[1] > S##_f[1]); \ - S##_f[3] += (T##_f[2] > S##_f[2]); \ - _FP_FRAC_DEC_4(X, T); \ - R##_f[0] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - if (!_FP_FRAC_ZEROP_4(X)) \ - { \ - if (_FP_FRAC_GT_4(X,S)) \ - R##_f[0] |= _FP_WORK_ROUND; \ - R##_f[0] |= _FP_WORK_STICKY; \ - } \ - } while (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_3 -#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ - (r0 = x0 + y0, \ - r1 = x1 + y1 + (r0 < x0), \ - r2 = x2 + y2 + (r1 < x1)) -#endif - -#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 - -#ifndef __FP_FRAC_SUB_3 -#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ - (r0 = x0 - y0, \ - r1 = x1 - y1 - (r0 > x0), \ - r2 = x2 - y2 - (r1 > x1)) -#endif - -#ifndef __FP_FRAC_SUB_4 -#define __FP_FRAC_SUB_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 - -#ifndef __FP_FRAC_DEC_3 -#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) \ - do { \ - UWtype _t0, _t1; \ - _t0 = x0; \ - x0 -= y0; \ - _t1 = x1; \ - x1 -= y1 + (x0 > _t0); \ - x2 -= y2 + (x1 > _t1); \ - } while (0) -#endif - -#ifndef __FP_FRAC_DEC_4 -#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) \ - do { \ - UWtype _t0, _t1; \ - _t0 = x0; \ - x0 -= y0; \ - _t1 = x1; \ - x1 -= y1 + (x0 > _t0); \ - _t0 = x2; \ - x2 -= y2 + (x1 > _t1); \ - x3 -= y3 + (x2 > _t0); \ - } while (0) -#endif - -#ifndef __FP_FRAC_ADDI_4 -#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \ - do { \ - UWtype _t; \ - _t = ((x0 += i) < i); \ - x1 += _t; _t = (x1 < _t); \ - x2 += _t; _t = (x2 < _t); \ - x3 += _t; \ - } while (0) -#endif - -/* Convert FP values between word sizes. This appears to be more - * complicated than I'd have expected it to be, so these might be - * wrong... These macros are in any case somewhat bogus because they - * use information about what various FRAC_n variables look like - * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do - * the ones in op-2.h and op-1.h. - */ -#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S) \ - do { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \ - D##_f = S##_f[0]; \ - } while (0) - -#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S) \ - do { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \ - D##_f0 = S##_f[0]; \ - D##_f1 = S##_f[1]; \ - } while (0) - -/* Assembly/disassembly for converting to/from integral types. - * No shifting or overflow handled here. - */ -/* Put the FP value X into r, which is an integer of size rsize. */ -#define _FP_FRAC_ASSEMBLE_4(r, X, rsize) \ - do { \ - if (rsize <= _FP_W_TYPE_SIZE) \ - r = X##_f[0]; \ - else if (rsize <= 2*_FP_W_TYPE_SIZE) \ - { \ - r = X##_f[1]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[0]; \ - } \ - else \ - { \ - /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \ - /* and int == 4words as a single case. */ \ - r = X##_f[3]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[2]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[1]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[0]; \ - } \ - } while (0) - -/* "No disassemble Number Five!" */ -/* move an integer of size rsize into X's fractional part. We rely on - * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid - * having to mask the values we store into it. - */ -#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize) \ - do { \ - X##_f[0] = r; \ - X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ - X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \ - X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \ - } while (0); - -#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \ - do { \ - D##_f[0] = S##_f; \ - D##_f[1] = D##_f[2] = D##_f[3] = 0; \ - _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ - } while (0) - -#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S) \ - do { \ - D##_f[0] = S##_f0; \ - D##_f[1] = S##_f1; \ - D##_f[2] = D##_f[3] = 0; \ - _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ - } while (0) - diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/op-8.h linux/arch/sparc64/math-emu/op-8.h --- v2.3.15/linux/arch/sparc64/math-emu/op-8.h Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/op-8.h Wed Dec 31 16:00:00 1969 @@ -1,103 +0,0 @@ -/* Software floating-point emulation. - Basic eight-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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. */ - -/* We need just a few things from here for op-4, if we ever need some - other macros, they can be added. */ -#define _FP_FRAC_DECL_8(X) _FP_W_TYPE X##_f[8] -#define _FP_FRAC_HIGH_8(X) (X##_f[7]) -#define _FP_FRAC_LOW_8(X) (X##_f[0]) -#define _FP_FRAC_WORD_8(X,w) (X##_f[w]) - -#define _FP_FRAC_SLL_8(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; \ - if (!_up) \ - for (_i = 7; _i >= _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip]; \ - else \ - { \ - for (_i = 7; _i > _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip] << _up \ - | X##_f[_i-_skip-1] >> _down; \ - X##_f[_i--] = X##_f[0] << _up; \ - } \ - for (; _i >= 0; --_i) \ - X##_f[_i] = 0; \ - } while (0) - -#define _FP_FRAC_SRL_8(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; \ - if (!_down) \ - for (_i = 0; _i <= 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[7] >> _down; \ - } \ - for (; _i < 8; ++_i) \ - X##_f[_i] = 0; \ - } while (0) - - -/* Right shift with sticky-lsb. - * What this actually means is that we do a standard right-shift, - * but that if any of the bits that fall off the right hand side - * were one then we always set the LSbit. - */ -#define _FP_FRAC_SRS_8(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; \ -/* s is now != 0 if we want to set the LSbit */ \ - if (!_down) \ - for (_i = 0; _i <= 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[7] >> _down; \ - } \ - for (; _i < 8; ++_i) \ - X##_f[_i] = 0; \ - /* don't fix the LSB until the very end when we're sure f[0] is stable */ \ - X##_f[0] |= (_s != 0); \ - } while (0) - diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/op-common.h linux/arch/sparc64/math-emu/op-common.h --- v2.3.15/linux/arch/sparc64/math-emu/op-common.h Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/op-common.h Wed Dec 31 16:00:00 1969 @@ -1,767 +0,0 @@ -/* Software floating-point emulation. Common operations. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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_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_RAW_##fs(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; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - break; \ - \ - case _FP_EXPMAX_##fs: \ - if (_FP_FRAC_ZEROP_##wc(X)) \ - X##_c = FP_CLS_INF; \ - else \ - { \ - X##_c = FP_CLS_NAN; \ - /* Check for signaling NaN */ \ - if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - } \ - 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 */ \ - switch (FP_ROUNDMODE) \ - { \ - case FP_RND_NEAREST: \ - X##_c = FP_CLS_INF; \ - break; \ - case FP_RND_PINF: \ - if (!X##_s) X##_c = FP_CLS_INF; \ - break; \ - case FP_RND_MINF: \ - if (X##_s) X##_c = FP_CLS_INF; \ - break; \ - } \ - if (X##_c == FP_CLS_INF) \ - { \ - /* Overflow to infinity */ \ - X##_e = _FP_EXPMAX_##fs; \ - _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - } \ - else \ - { \ - /* Overflow to maximum normal */ \ - X##_e = _FP_EXPMAX_##fs - 1; \ - _FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc); \ - } \ - FP_SET_EXCEPTION(FP_EX_OVERFLOW); \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - } \ - } \ - 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); \ - if (_FP_FRAC_HIGH_##fs(X) \ - & (_FP_OVERFLOW_##fs >> 1)) \ - { \ - X##_e = 1; \ - _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - } \ - else \ - { \ - X##_e = 0; \ - _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ - FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \ - } \ - } \ - else \ - { \ - /* underflow to zero */ \ - X##_e = 0; \ - if (!_FP_FRAC_ZEROP_##wc(X)) \ - { \ - _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ - _FP_ROUND(wc, X); \ - _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS); \ - } \ - FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \ - } \ - } \ - 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 = _FP_NANSIGN_##fs; \ - } \ - else \ - _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs; \ - break; \ - } \ -} while (0) - -/* This one accepts raw argument and not cooked, returns - * 1 if X is a signaling NaN. - */ -#define _FP_ISSIGNAN(fs, wc, X) \ -({ \ - int __ret = 0; \ - if (X##_e == _FP_EXPMAX_##fs) \ - { \ - if (!_FP_FRAC_ZEROP_##wc(X) \ - && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ - __ret = 1; \ - } \ - __ret; \ -}) - - - - - -/* - * Main addition routine. The input values should be cooked. - */ - -#define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP) \ -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); \ - 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); \ - } \ - 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, OP); \ - 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 = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - 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) - -#define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+') -#define _FP_SUB(fs, wc, R, X, Y) \ - do { \ - if (Y##_c != FP_CLS_NAN) Y##_s ^= 1; \ - _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-'); \ - } 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##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - 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): \ - FP_SET_EXCEPTION(FP_EX_DIVZERO); \ - 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##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - 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 \ - { \ - int __is_zero_x; \ - int __is_zero_y; \ - \ - __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ - __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ - \ - if (__is_zero_x && __is_zero_y) \ - ret = 0; \ - else if (__is_zero_x) \ - ret = Y##_s ? 1 : -1; \ - else if (__is_zero_y) \ - ret = X##_s ? -1 : 1; \ - else 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: \ - _FP_FRAC_COPY_##wc(R, X); \ - R##_s = X##_s; \ - R##_c = FP_CLS_NAN; \ - break; \ - case FP_CLS_INF: \ - if (X##_s) \ - { \ - R##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; /* NAN */ \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - } \ - 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 */ \ - R##_s = _FP_NANSIGN_##fs; \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - 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 >> 1; \ - _FP_SQRT_MEAT_##wc(R, S, T, X, q); \ - } \ - } while (0) - -/* - * Convert from FP to integer - */ - -/* RSIGNED can have following values: - * 0: the number is required to be 0..(2^rsize)-1, if not, NV is set plus - * the result is either 0 or (2^rsize)-1 depending on the sign in such case. - * 1: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is - * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending - * on the sign in such case. - * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is - * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending - * on the sign in such case. - */ -#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ - do { \ - switch (X##_c) \ - { \ - case FP_CLS_NORMAL: \ - if (X##_e < 0) \ - { \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - case FP_CLS_ZERO: \ - r = 0; \ - } \ - else if (X##_e >= rsize - (rsigned > 0 || X##_s) \ - || (!rsigned && X##_s)) \ - { /* overflow */ \ - case FP_CLS_NAN: \ - case FP_CLS_INF: \ - if (rsigned) \ - { \ - r = 1; \ - r <<= rsize - 1; \ - r -= 1 - X##_s; \ - } else { \ - r = 0; \ - if (X##_s) \ - r = ~r; \ - } \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - } \ - 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 if (X##_e < _FP_WFRACBITS_##fs - 1) \ - { \ - _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2), \ - _FP_WFRACBITS_##fs); \ - if (_FP_FRAC_LOW_##wc(X) & 1) \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - _FP_FRAC_SRL_##wc(X, 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; \ - \ - 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 &= ~((rtype)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 -#if _FP_W_TYPE_SIZE < 64 -/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */ -#define __FP_CLZ(r, x) \ - do { \ - _FP_W_TYPE _t = (x); \ - r = _FP_W_TYPE_SIZE - 1; \ - 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) -#else /* not _FP_W_TYPE_SIZE < 64 */ -#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 /* not _FP_W_TYPE_SIZE < 64 */ -#endif /* ndef __FP_CLZ */ - -#define _FP_DIV_HELP_imm(q, r, n, d) \ - do { \ - q = n / d, r = n % d; \ - } while (0) - diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/quad.h linux/arch/sparc64/math-emu/quad.h --- v2.3.15/linux/arch/sparc64/math-emu/quad.h Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/math-emu/quad.h Wed Dec 31 16:00:00 1969 @@ -1,201 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Quad Precision. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel, kid. Go buy yourself a real computer." -#endif - -#if _FP_W_TYPE_SIZE < 64 -#define _FP_FRACTBITS_Q (4*_FP_W_TYPE_SIZE) -#else -#define _FP_FRACTBITS_Q (2*_FP_W_TYPE_SIZE) -#endif - -#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)) - -#if _FP_W_TYPE_SIZE < 64 - -union _FP_UNION_Q -{ - long double flt; - struct - { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_Q; - unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3); - unsigned long frac2 : _FP_W_TYPE_SIZE; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned long frac0 : _FP_W_TYPE_SIZE; -#else - unsigned long frac0 : _FP_W_TYPE_SIZE; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned long frac2 : _FP_W_TYPE_SIZE; - unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3); - unsigned exp : _FP_EXPBITS_Q; - unsigned sign : 1; -#endif /* not bigendian */ - } bits __attribute__((packed)); -}; - - -#define FP_DECL_Q(X) _FP_DECL(4,X) -#define FP_UNPACK_RAW_Q(X,val) _FP_UNPACK_RAW_4(Q,X,val) -#define FP_UNPACK_RAW_QP(X,val) _FP_UNPACK_RAW_4_P(Q,X,val) -#define FP_PACK_RAW_Q(val,X) _FP_PACK_RAW_4(Q,val,X) -#define FP_PACK_RAW_QP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_4_P(Q,val,X); \ - } while (0) - -#define FP_UNPACK_Q(X,val) \ - do { \ - _FP_UNPACK_RAW_4(Q,X,val); \ - _FP_UNPACK_CANONICAL(Q,4,X); \ - } while (0) - -#define FP_UNPACK_QP(X,val) \ - do { \ - _FP_UNPACK_RAW_4_P(Q,X,val); \ - _FP_UNPACK_CANONICAL(Q,4,X); \ - } while (0) - -#define FP_PACK_Q(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,4,X); \ - _FP_PACK_RAW_4(Q,val,X); \ - } while (0) - -#define FP_PACK_QP(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,4,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_4_P(Q,val,X); \ - } while (0) - -#define FP_ISSIGNAN_Q(X) _FP_ISSIGNAN(Q,4,X) -#define FP_NEG_Q(R,X) _FP_NEG(Q,4,R,X) -#define FP_ADD_Q(R,X,Y) _FP_ADD(Q,4,R,X,Y) -#define FP_SUB_Q(R,X,Y) _FP_SUB(Q,4,R,X,Y) -#define FP_MUL_Q(R,X,Y) _FP_MUL(Q,4,R,X,Y) -#define FP_DIV_Q(R,X,Y) _FP_DIV(Q,4,R,X,Y) -#define FP_SQRT_Q(R,X) _FP_SQRT(Q,4,R,X) -#define _FP_SQRT_MEAT_Q(R,S,T,X,Q) _FP_SQRT_MEAT_4(R,S,T,X,Q) - -#define FP_CMP_Q(r,X,Y,un) _FP_CMP(Q,4,r,X,Y,un) -#define FP_CMP_EQ_Q(r,X,Y) _FP_CMP_EQ(Q,4,r,X,Y) - -#define FP_TO_INT_Q(r,X,rsz,rsg) _FP_TO_INT(Q,4,r,X,rsz,rsg) -#define FP_FROM_INT_Q(X,r,rs,rt) _FP_FROM_INT(Q,4,X,r,rs,rt) - -#define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_4(X) -#define _FP_FRAC_HIGH_RAW_Q(X) _FP_FRAC_HIGH_4(X) - -#else /* not _FP_W_TYPE_SIZE < 64 */ -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_UNPACK_RAW_QP(X,val) _FP_UNPACK_RAW_2_P(Q,X,val) -#define FP_PACK_RAW_Q(val,X) _FP_PACK_RAW_2(Q,val,X) -#define FP_PACK_RAW_QP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(Q,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_UNPACK_QP(X,val) \ - do { \ - _FP_UNPACK_RAW_2_P(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_PACK_QP(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,2,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(Q,val,X); \ - } while (0) - -#define FP_ISSIGNAN_Q(X) _FP_ISSIGNAN(Q,2,X) -#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_SQRT_MEAT_Q(R,S,T,X,Q) _FP_SQRT_MEAT_2(R,S,T,X,Q) - -#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) - -#define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_2(X) -#define _FP_FRAC_HIGH_RAW_Q(X) _FP_FRAC_HIGH_2(X) - -#endif /* not _FP_W_TYPE_SIZE < 64 */ diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/single.h linux/arch/sparc64/math-emu/single.h --- v2.3.15/linux/arch/sparc64/math-emu/single.h Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/single.h Wed Dec 31 16:00:00 1969 @@ -1,110 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Single Precision. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel 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_UNPACK_RAW_SP(X,val) _FP_UNPACK_RAW_1_P(S,X,val) -#define FP_PACK_RAW_S(val,X) _FP_PACK_RAW_1(S,val,X) -#define FP_PACK_RAW_SP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(S,val,X); \ - } 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_UNPACK_SP(X,val) \ - do { \ - _FP_UNPACK_RAW_1_P(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_PACK_SP(val,X) \ - do { \ - _FP_PACK_CANONICAL(S,1,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(S,val,X); \ - } while (0) - -#define FP_ISSIGNAN_S(X) _FP_ISSIGNAN(S,1,X) -#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_SQRT_MEAT_S(R,S,T,X,Q) _FP_SQRT_MEAT_1(R,S,T,X,Q) - -#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) - -#define _FP_FRAC_HIGH_S(X) _FP_FRAC_HIGH_1(X) -#define _FP_FRAC_HIGH_RAW_S(X) _FP_FRAC_HIGH_1(X) diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/math-emu/soft-fp.h linux/arch/sparc64/math-emu/soft-fp.h --- v2.3.15/linux/arch/sparc64/math-emu/soft-fp.h Sat May 29 11:09:04 1999 +++ linux/arch/sparc64/math-emu/soft-fp.h Wed Dec 31 16:00:00 1969 @@ -1,176 +0,0 @@ -/* Software floating-point emulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - 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. */ - -#ifndef SOFT_FP_H -#define SOFT_FP_H - -#include "sfp-machine.h" - -/* Allow sfp-machine to have its own byte order definitions. */ -#ifndef __BYTE_ORDER -#include -#endif - -#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 -#ifndef FP_ROUNDMODE -# define FP_ROUNDMODE FP_RND_NEAREST -#endif -#endif - -/* By default don't care about exceptions. */ -#ifndef FP_EX_INVALID -#define FP_EX_INVALID 0 -#endif -#ifndef FP_EX_OVERFLOW -#define FP_EX_OVERFLOW 0 -#endif -#ifndef FP_EX_UNDERFLOW -#define FP_EX_UNDERFLOW -#endif -#ifndef FP_EX_DIVZERO -#define FP_EX_DIVZERO 0 -#endif -#ifndef FP_EX_INEXACT -#define FP_EX_INEXACT 0 -#endif -#ifndef FP_EX_DENORM -#define FP_EX_DENORM 0 -#endif - -#ifdef _FP_DECL_EX -#define FP_DECL_EX \ - int _fex = 0; \ - _FP_DECL_EX -#else -#define FP_DECL_EX int _fex = 0 -#endif - -#ifndef FP_INIT_ROUNDMODE -#define FP_INIT_ROUNDMODE do {} while (0) -#endif - -#ifndef FP_HANDLE_EXCEPTIONS -#define FP_HANDLE_EXCEPTIONS do {} while (0) -#endif - -#ifndef FP_INHIBIT_RESULTS -/* By default we write the results always. - * sfp-machine may override this and e.g. - * check if some exceptions are unmasked - * and inhibit it in such a case. - */ -#define FP_INHIBIT_RESULTS 0 -#endif - -#define FP_SET_EXCEPTION(ex) \ - _fex |= (ex) - -#define FP_UNSET_EXCEPTION(ex) \ - _fex &= ~(ex) - -#define FP_CLEAR_EXCEPTIONS \ - _fex = 0 - -#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) 0 - -#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) \ -do { \ - if (_FP_FRAC_LOW_##wc(X) & 7) \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - 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; \ - } \ -} while (0) - -#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-8.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 - -#ifndef umul_ppmm -#include -#endif - -#endif diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.3.15/linux/arch/sparc64/mm/fault.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/mm/fault.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.38 1999/08/02 08:39:50 davem Exp $ +/* $Id: fault.c,v 1.39 1999/08/30 10:07:09 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -312,6 +312,16 @@ return; } } else { +#if 0 + extern void __show_regs(struct pt_regs *); + printk("SHIT(%s:%d:cpu(%d)): PC[%016lx] ADDR[%016lx]\n", + current->comm, current->pid, smp_processor_id(), + regs->tpc, address); + __show_regs(regs); + __sti(); + while(1) + barrier(); +#endif current->thread.sig_address = address; current->thread.sig_desc = SUBSIG_NOMAPPING; force_sig(SIGSEGV, current); diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.3.15/linux/arch/sparc64/mm/init.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/mm/init.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.131 1999/07/30 09:35:45 davem Exp $ +/* $Id: init.c,v 1.134 1999/08/31 06:54:58 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -166,7 +166,7 @@ static unsigned long dvmaiobase = 0; static unsigned long dvmaiosz __initdata = 0; -__initfunc(void dvmaio_init(void)) +void __init dvmaio_init(void) { long i; @@ -187,7 +187,7 @@ } } -__initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus)) +void __init iommu_init(int iommu_node, struct linux_sbus *sbus) { extern int this_is_starfire; extern void *starfire_hookup(int); @@ -586,7 +586,8 @@ struct linux_sbus *sbus = sdev->my_bus; struct sysio_regs *sregs = sbus->iommu->sysio_regs; int slot = sdev->slot; - u64 *cfg, tmp; + volatile u64 *cfg; + u64 tmp; switch(slot) { case 0: @@ -1044,8 +1045,8 @@ return NULL; } -__initfunc(static void -allocate_ptable_skeleton(unsigned long start, unsigned long end)) +static void __init +allocate_ptable_skeleton(unsigned long start, unsigned long end) { pgd_t *pgdp; pmd_t *pmdp; @@ -1142,8 +1143,8 @@ extern unsigned long free_area_init(unsigned long, unsigned long); extern unsigned long sun_serial_setup(unsigned long); -__initfunc(unsigned long -paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init +paging_init(unsigned long start_mem, unsigned long end_mem) { extern pmd_t swapper_pmd_dir[1024]; extern unsigned int sparc64_vpte_patchme1[1]; @@ -1262,7 +1263,7 @@ return device_scan (PAGE_ALIGN (start_mem)); } -__initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)) +static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem) { unsigned long tmp = 0, paddr, endaddr; unsigned long end = __pa(end_mem); @@ -1308,7 +1309,7 @@ } } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { int codepages = 0; int datapages = 0; @@ -1322,6 +1323,7 @@ max_mapnr = MAP_NR(end_mem); high_memory = (void *) end_mem; + start_mem = ((start_mem + 7UL) & ~7UL); sparc64_valid_addr_bitmap = (unsigned long *)start_mem; i = max_mapnr >> ((22 - PAGE_SHIFT) + 6); i += 1; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/prom/bootstr.c linux/arch/sparc64/prom/bootstr.c --- v2.3.15/linux/arch/sparc64/prom/bootstr.c Tue Apr 14 17:44:21 1998 +++ linux/arch/sparc64/prom/bootstr.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: bootstr.c,v 1.5 1998/01/23 08:51:39 jj Exp $ +/* $Id: bootstr.c,v 1.6 1999/08/31 06:55:01 davem Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -14,8 +14,8 @@ static int bootstr_valid = 0; static char bootstr_buf[BARG_LEN] = { 0 }; -__initfunc(char * -prom_getbootargs(void)) +char * __init +prom_getbootargs(void) { /* This check saves us from a panic when bootfd patches args. */ if (bootstr_valid) return bootstr_buf; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/prom/init.c linux/arch/sparc64/prom/init.c --- v2.3.15/linux/arch/sparc64/prom/init.c Tue Apr 14 17:44:21 1998 +++ linux/arch/sparc64/prom/init.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.8 1998/03/15 10:14:44 ecd Exp $ +/* $Id: init.c,v 1.9 1999/08/31 06:55:03 davem Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * @@ -31,7 +31,7 @@ extern void prom_ranges_init(void); extern void prom_cif_init(void *, void *); -__initfunc(void prom_init(void *cif_handler, void *cif_stack)) +void __init prom_init(void *cif_handler, void *cif_stack) { char buffer[80], *p; int ints[3]; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/prom/memory.c linux/arch/sparc64/prom/memory.c --- v2.3.15/linux/arch/sparc64/prom/memory.c Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/prom/memory.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.4 1998/11/25 10:04:06 jj Exp $ +/* $Id: memory.c,v 1.5 1999/08/31 06:55:04 davem Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * @@ -37,8 +37,8 @@ /* Internal Prom library routine to sort a linux_mlist_p1275 memory * list. Used below in initialization. */ -__initfunc(static void -prom_sortmemlist(struct linux_mlist_p1275 *thislist)) +static void __init +prom_sortmemlist(struct linux_mlist_p1275 *thislist) { int swapi = 0; int i, mitr; @@ -65,7 +65,7 @@ } /* Initialize the memory lists based upon the prom version. */ -__initfunc(void prom_meminit(void)) +void __init prom_meminit(void) { int node = 0; unsigned int iter, num_regs; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/prom/ranges.c linux/arch/sparc64/prom/ranges.c --- v2.3.15/linux/arch/sparc64/prom/ranges.c Tue Apr 14 17:44:21 1998 +++ linux/arch/sparc64/prom/ranges.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: ranges.c,v 1.10 1998/03/24 05:54:29 ecd Exp $ +/* $Id: ranges.c,v 1.12 1999/08/31 06:55:05 davem Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -87,11 +87,11 @@ central->num_central_ranges); } -__initfunc(void prom_ranges_init(void)) +void __init prom_ranges_init(void) { } -__initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus)) +void __init prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus) { int success; @@ -103,7 +103,7 @@ sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); } -__initfunc(void prom_central_ranges_init(int cnode, struct linux_central *central)) +void __init prom_central_ranges_init(int cnode, struct linux_central *central) { int success; @@ -115,7 +115,7 @@ central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); } -__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc)) +void __init prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc) { int success; @@ -128,7 +128,7 @@ } #ifdef CONFIG_PCI -__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus)) +void __init prom_ebus_ranges_init(struct linux_ebus *ebus) { int success; @@ -140,7 +140,7 @@ ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); } -__initfunc(void prom_ebus_intmap_init(struct linux_ebus *ebus)) +void __init prom_ebus_intmap_init(struct linux_ebus *ebus) { int success; @@ -156,40 +156,6 @@ success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", (char *)&ebus->ebus_intmask, sizeof(ebus->ebus_intmask)); - if (success == -1) { - prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); - prom_halt(); - } -} - -__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm)) -{ - int success; - - pbm->num_pbm_ranges = 0; - success = prom_getproperty(pnode, "ranges", - (char *)&pbm->pbm_ranges, - sizeof(pbm->pbm_ranges)); - if(success != -1) - pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges)); -} - -__initfunc(void prom_pbm_intmap_init(int pnode, struct linux_pbm_info *pbm)) -{ - int success; - - pbm->num_pbm_intmap = 0; - success = prom_getproperty(pnode, "interrupt-map", - (char *)pbm->pbm_intmap, - sizeof(pbm->pbm_intmap)); - if (success == -1) - return; - - pbm->num_pbm_intmap = (success/sizeof(struct linux_prom_pci_intmap)); - - success = prom_getproperty(pnode, "interrupt-map-mask", - (char *)&pbm->pbm_intmask, - sizeof(pbm->pbm_intmask)); if (success == -1) { prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); prom_halt(); diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/solaris/ioctl.c linux/arch/sparc64/solaris/ioctl.c --- v2.3.15/linux/arch/sparc64/solaris/ioctl.c Wed Aug 18 11:39:02 1999 +++ linux/arch/sparc64/solaris/ioctl.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: ioctl.c,v 1.12 1999/07/23 01:57:03 davem Exp $ +/* $Id: ioctl.c,v 1.13 1999/08/20 00:27:15 davem Exp $ * ioctl.c: Solaris ioctl emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c --- v2.3.15/linux/arch/sparc64/solaris/socksys.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/solaris/socksys.c Tue Aug 31 11:23:30 1999 @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.9 1999/07/23 01:57:07 davem Exp $ +/* $Id: socksys.c,v 1.10 1999/08/31 06:55:08 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -174,8 +174,8 @@ socksys_release,/* release */ }; -__initfunc(int -init_socksys(void)) +int __init +init_socksys(void) { int ret; struct file * file; diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c --- v2.3.15/linux/arch/sparc64/solaris/timod.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/solaris/timod.c Tue Aug 31 11:30:47 1999 @@ -677,7 +677,7 @@ wait = &wait_table; for(;;) { SOLD("loop"); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ diff -u --recursive --new-file v2.3.15/linux/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c --- v2.3.15/linux/drivers/acorn/char/keyb_arc.c Mon Jul 5 20:35:18 1999 +++ linux/drivers/acorn/char/keyb_arc.c Mon Aug 30 18:15:19 1999 @@ -419,7 +419,7 @@ }; #endif -__initfunc(void a5kkbd_init_hw (void)) +void __init a5kkbd_init_hw (void) { unsigned long flags; diff -u --recursive --new-file v2.3.15/linux/drivers/acorn/char/keyb_ps2.c linux/drivers/acorn/char/keyb_ps2.c --- v2.3.15/linux/drivers/acorn/char/keyb_ps2.c Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/char/keyb_ps2.c Thu Aug 26 12:42:33 1999 @@ -325,7 +325,7 @@ { } -__initfunc(int ps2kbd_init_hw(void)) +int __init ps2kbd_init_hw(void) { unsigned long flags; diff -u --recursive --new-file v2.3.15/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.3.15/linux/drivers/acorn/net/ether1.c Wed Aug 18 11:38:59 1999 +++ linux/drivers/acorn/net/ether1.c Mon Aug 30 18:15:21 1999 @@ -254,8 +254,8 @@ } } -__initfunc(static int -ether1_ramtest (struct net_device *dev, unsigned char byte)) +static int __init +ether1_ramtest (struct net_device *dev, unsigned char byte) { unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); int i, ret = BUFFER_SIZE; @@ -308,8 +308,8 @@ return BUS_16; } -__initfunc(static int -ether1_init_2 (struct net_device *dev)) +static int __init +ether1_init_2 (struct net_device *dev) { int i; dev->mem_start = 0; @@ -612,8 +612,8 @@ return failures ? 1 : 0; } -__initfunc(static int -ether1_probe1 (struct net_device *dev)) +static int __init +ether1_probe1 (struct net_device *dev) { static unsigned int version_printed = 0; struct ether1_priv *priv; @@ -664,8 +664,8 @@ /* ------------------------------------------------------------------------- */ -__initfunc(static void -ether1_addr (struct net_device *dev)) +static void __init +ether1_addr (struct net_device *dev) { int i; @@ -673,8 +673,8 @@ dev->dev_addr[i] = inb (IDPROM_ADDRESS + i); } -__initfunc(int -ether1_probe (struct net_device *dev)) +int __init +ether1_probe (struct net_device *dev) { #ifndef MODULE struct expansion_card *ec; diff -u --recursive --new-file v2.3.15/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c --- v2.3.15/linux/drivers/acorn/net/ether3.c Wed Aug 18 11:38:59 1999 +++ linux/drivers/acorn/net/ether3.c Mon Aug 30 18:15:21 1999 @@ -199,8 +199,8 @@ * Read the ethernet address string from the on board rom. * This is an ascii string!!! */ -__initfunc(static void -ether3_addr(char *addr, struct expansion_card *ec)) +static void __init +ether3_addr(char *addr, struct expansion_card *ec) { struct in_chunk_dir cd; char *s; @@ -224,8 +224,8 @@ /* --------------------------------------------------------------------------- */ -__initfunc(static int -ether3_ramtest(struct net_device *dev, unsigned char byte)) +static int __init +ether3_ramtest(struct net_device *dev, unsigned char byte) { unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); int i,ret = 0; @@ -273,8 +273,8 @@ /* ------------------------------------------------------------------------------- */ -__initfunc(static int -ether3_init_2(struct net_device *dev)) +static int __init +ether3_init_2(struct net_device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; int i; @@ -400,8 +400,8 @@ /* * This is the real probe routine. */ -__initfunc(static int -ether3_probe1(struct net_device *dev)) +static int __init +ether3_probe1(struct net_device *dev) { static unsigned version_printed = 0; struct dev_priv *priv; @@ -478,8 +478,8 @@ return error; } -__initfunc(static void -ether3_get_dev(struct net_device *dev, struct expansion_card *ec)) +static void __init +ether3_get_dev(struct net_device *dev, struct expansion_card *ec) { ecard_claim(ec); @@ -498,8 +498,8 @@ } #ifndef MODULE -__initfunc(int -ether3_probe(struct net_device *dev)) +int __init +ether3_probe(struct net_device *dev) { struct expansion_card *ec; diff -u --recursive --new-file v2.3.15/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c --- v2.3.15/linux/drivers/acorn/net/etherh.c Wed Aug 18 11:38:59 1999 +++ linux/drivers/acorn/net/etherh.c Mon Aug 30 18:15:21 1999 @@ -84,8 +84,8 @@ * Read the ethernet address string from the on board rom. * This is an ascii string... */ -__initfunc(static int -etherh_addr(char *addr, struct expansion_card *ec)) +static int __init +etherh_addr(char *addr, struct expansion_card *ec) { struct in_chunk_dir cd; char *s; @@ -352,8 +352,8 @@ /* * This is the real probe routine. */ -__initfunc(static int -etherh_probe1(struct net_device *dev)) +static int __init +etherh_probe1(struct net_device *dev) { static int version_printed; unsigned int addr, i, reg0, tmp; @@ -463,8 +463,8 @@ NULL }; -__initfunc(static void -etherh_initdev(ecard_t *ec, struct net_device *dev)) +static void __init +etherh_initdev(ecard_t *ec, struct net_device *dev) { ecard_claim (ec); @@ -496,8 +496,8 @@ } #ifndef MODULE -__initfunc(int -etherh_probe(struct net_device *dev)) +int __init +etherh_probe(struct net_device *dev) { if (!dev) return ENODEV; diff -u --recursive --new-file v2.3.15/linux/drivers/acorn/net/net-probe.c linux/drivers/acorn/net/net-probe.c --- v2.3.15/linux/drivers/acorn/net/net-probe.c Wed Aug 18 11:38:59 1999 +++ linux/drivers/acorn/net/net-probe.c Thu Aug 26 12:42:33 1999 @@ -12,7 +12,7 @@ extern int ether3_probe (struct net_device *dev); extern int etherh_probe (struct net_device *dev); -__initfunc(int acorn_ethif_probe(struct net_device *dev)) +int __init acorn_ethif_probe(struct net_device *dev) { if (1 #ifdef CONFIG_ARM_ETHERH diff -u --recursive --new-file v2.3.15/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.3.15/linux/drivers/atm/Makefile Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/Makefile Mon Aug 30 10:18:40 1999 @@ -21,10 +21,10 @@ endif ifeq ($(CONFIG_ATM_ZATM),y) -L_OBJS += zatm.o uPD98402.o +LX_OBJS += zatm.o uPD98402.o else ifeq ($(CONFIG_ATM_ZATM),m) - M_OBJS += zatm.o uPD98402.o + MX_OBJS += zatm.o uPD98402.o endif endif diff -u --recursive --new-file v2.3.15/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c --- v2.3.15/linux/drivers/atm/ambassador.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/ambassador.c Mon Aug 30 10:18:40 1999 @@ -2338,8 +2338,8 @@ // read resources from PCI configuration space u32 * membase = bus_to_virt - (pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK); - u32 iobase = pci_dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + (pci_dev->resource[0].start); + u32 iobase = pci_dev->resource[1].start; u8 irq = pci_dev->irq; // check IO region diff -u --recursive --new-file v2.3.15/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c --- v2.3.15/linux/drivers/atm/atmdev_init.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/atmdev_init.c Thu Aug 26 12:42:33 1999 @@ -30,7 +30,7 @@ #endif -__initfunc(int atmdev_init(void)) +int __init atmdev_init(void) { int devs; diff -u --recursive --new-file v2.3.15/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.3.15/linux/drivers/atm/eni.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/eni.c Mon Aug 30 10:18:40 1999 @@ -1548,7 +1548,7 @@ } }) -__initfunc(static int get_esi_asic(struct atm_dev *dev)) +static int __init get_esi_asic(struct atm_dev *dev) { struct eni_dev *eni_dev; unsigned char tonga; @@ -1640,7 +1640,7 @@ #undef GET_SEPROM -__initfunc(static int get_esi_fpga(struct atm_dev *dev,unsigned long base)) +static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base) { unsigned long mac_base; int i; @@ -1651,7 +1651,7 @@ } -__initfunc(static int eni_init(struct atm_dev *dev)) +static int __init eni_init(struct atm_dev *dev) { struct midway_eprom *eprom; struct eni_dev *eni_dev; @@ -1666,7 +1666,7 @@ dev->link_rate = ATM_OC3_PCR; eni_dev = ENI_DEV(dev); pci_dev = eni_dev->pci_dev; - real_base = pci_dev->base_address[0] & MEM_VALID; /* strip flags */ + real_base = pci_dev->resource[0].start; eni_dev->irq = pci_dev->irq; error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision); if (error) { @@ -1740,7 +1740,7 @@ } -__initfunc(static int eni_start(struct atm_dev *dev)) +static int __init eni_start(struct atm_dev *dev) { struct eni_dev *eni_dev; unsigned long buf,buffer_mem; @@ -2190,7 +2190,7 @@ }; -__initfunc(int eni_detect(void)) +int __init eni_detect(void) { struct atm_dev *dev; struct eni_dev *eni_dev; diff -u --recursive --new-file v2.3.15/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c --- v2.3.15/linux/drivers/atm/horizon.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/horizon.c Mon Aug 30 10:18:40 1999 @@ -2517,7 +2517,7 @@ // clear error and grab cell rate resource lock error = 0; - spin_lock (&dev->rates_lock); + spin_lock (&dev->rate_lock); if (vcc.tx_rate > dev->tx_avail) { PRINTD (DBG_QOS, "not enough TX PCR left"); @@ -2538,7 +2538,7 @@ } // release lock and exit on error - spin_unlock (&dev->rates_lock); + spin_unlock (&dev->rate_lock); if (error) { PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources"); kfree (vccp); @@ -2618,12 +2618,12 @@ } // atomically release our rate reservation - spin_lock (&dev->rates_lock); + spin_lock (&dev->rate_lock); PRINTD (DBG_QOS|DBG_VCC, "releasing %u TX PCR and %u RX PCR", vcc->tx_rate, vcc->rx_rate); dev->tx_avail += vcc->tx_rate; dev->rx_avail += vcc->rx_rate; - spin_unlock (&dev->rates_lock); + spin_unlock (&dev->rate_lock); // free our structure kfree (vcc); @@ -2790,9 +2790,8 @@ hrz_dev * dev; // adapter slot free, read resources from PCI configuration space - u32 iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; - u32 * membase = bus_to_virt - (pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK); + u32 iobase = pci_dev->resource[0].start; + u32 * membase = bus_to_virt(pci_dev->resource[1].start); u8 irq = pci_dev->irq; // check IO region diff -u --recursive --new-file v2.3.15/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c --- v2.3.15/linux/drivers/atm/nicstar.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/nicstar.c Mon Aug 30 10:18:40 1999 @@ -344,7 +344,7 @@ #else -__initfunc(int nicstar_detect(void)) +int __init nicstar_detect(void) { int i; unsigned error = 0; /* Initialized to remove compile warning */ @@ -454,7 +454,7 @@ card->index = i; card->pcidev = pcidev; - card->membase = (u32) (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK); + card->membase = (u32) pcidev->resource[1].start; #ifdef __powerpc__ /* Compensate for different memory map between host CPU and PCI bus. Shouldn't we use a macro for this? */ diff -u --recursive --new-file v2.3.15/linux/drivers/atm/suni.c linux/drivers/atm/suni.c --- v2.3.15/linux/drivers/atm/suni.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/suni.c Thu Aug 26 12:42:33 1999 @@ -264,7 +264,7 @@ }; -__initfunc(int suni_init(struct atm_dev *dev)) +int __init suni_init(struct atm_dev *dev) { unsigned char mri; diff -u --recursive --new-file v2.3.15/linux/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c --- v2.3.15/linux/drivers/atm/uPD98402.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/uPD98402.c Thu Aug 26 12:42:33 1999 @@ -196,7 +196,7 @@ }; -__initfunc(int uPD98402_init(struct atm_dev *dev)) +int __init uPD98402_init(struct atm_dev *dev) { DPRINTK("phy_init\n"); dev->phy = &uPD98402_ops; diff -u --recursive --new-file v2.3.15/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c --- v2.3.15/linux/drivers/atm/zatm.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/zatm.c Mon Aug 30 10:18:40 1999 @@ -460,7 +460,7 @@ } -__initfunc(static void zatm_clock_init(struct zatm_dev *zatm_dev)) +static void __init zatm_clock_init(struct zatm_dev *zatm_dev) { static int start_timer = 1; unsigned long flags; @@ -1289,8 +1289,8 @@ /*----------------------------- (E)EPROM access -----------------------------*/ -__initfunc(static void eprom_set(struct zatm_dev *zatm_dev,unsigned long value, - unsigned short cmd)) +static void __init eprom_set(struct zatm_dev *zatm_dev,unsigned long value, + unsigned short cmd) { int error; @@ -1300,8 +1300,8 @@ } -__initfunc(static unsigned long eprom_get(struct zatm_dev *zatm_dev, - unsigned short cmd)) +static unsigned long __init eprom_get(struct zatm_dev *zatm_dev, + unsigned short cmd) { unsigned int value; int error; @@ -1313,8 +1313,8 @@ } -__initfunc(static void eprom_put_bits(struct zatm_dev *zatm_dev, - unsigned long data,int bits,unsigned short cmd)) +static void __init eprom_put_bits(struct zatm_dev *zatm_dev, + unsigned long data,int bits,unsigned short cmd) { unsigned long value; int i; @@ -1328,8 +1328,8 @@ } -__initfunc(static void eprom_get_byte(struct zatm_dev *zatm_dev, - unsigned char *byte,unsigned short cmd)) +static void __init eprom_get_byte(struct zatm_dev *zatm_dev, + unsigned char *byte,unsigned short cmd) { int i; @@ -1344,8 +1344,8 @@ } -__initfunc(static unsigned char eprom_try_esi(struct atm_dev *dev, - unsigned short cmd,int offset,int swap)) +static unsigned char __init eprom_try_esi(struct atm_dev *dev, + unsigned short cmd,int offset,int swap) { unsigned char buf[ZEPROM_SIZE]; struct zatm_dev *zatm_dev; @@ -1365,7 +1365,7 @@ } -__initfunc(static void eprom_get_esi(struct atm_dev *dev)) +static void __init eprom_get_esi(struct atm_dev *dev) { if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return; (void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0); @@ -1375,7 +1375,7 @@ /*--------------------------------- entries ---------------------------------*/ -__initfunc(static int zatm_init(struct atm_dev *dev)) +static int __init zatm_init(struct atm_dev *dev) { struct zatm_dev *zatm_dev; struct pci_dev *pci_dev; @@ -1387,7 +1387,7 @@ DPRINTK(">zatm_init\n"); zatm_dev = ZATM_DEV(dev); pci_dev = zatm_dev->pci_dev; - zatm_dev->base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + zatm_dev->base = pci_dev->resource[0].start; zatm_dev->irq = pci_dev->irq; if ((error = pci_read_config_word(pci_dev,PCI_COMMAND,&command)) || (error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision))) { @@ -1457,7 +1457,7 @@ } -__initfunc(static int zatm_start(struct atm_dev *dev)) +static int __init zatm_start(struct atm_dev *dev) { struct zatm_dev *zatm_dev; unsigned long curr; @@ -1816,7 +1816,7 @@ }; -__initfunc(int zatm_detect(void)) +int __init zatm_detect(void) { struct atm_dev *dev; struct zatm_dev *zatm_dev; diff -u --recursive --new-file v2.3.15/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.15/linux/drivers/block/Config.in Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/Config.in Thu Aug 26 13:44:03 1999 @@ -51,7 +51,9 @@ bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + if [ "$CONFIG_X86" = "y" ]; then + bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + fi bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 fi @@ -61,10 +63,12 @@ bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA fi bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 - bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX - if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_PIIX" = "y" ]; then - bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + if [ "$CONFIG_X86" = "y" ]; then + bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PIIX" = "y" ]; then + bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + fi fi if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 @@ -80,10 +84,14 @@ bool ' Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE fi fi - bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 + if [ "$CONFIG_X86" = "y" ]; then + bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 + fi if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + if [ "$CONFIG_X86" = "y" ]; then + bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + fi fi fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then diff -u --recursive --new-file v2.3.15/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.3.15/linux/drivers/block/DAC960.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/DAC960.c Mon Aug 30 10:24:14 1999 @@ -0,0 +1,3570 @@ +/* + + Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers + + Copyright 1998-1999 by Leonard N. Zubkoff + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + 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 complete details. + + The author respectfully requests that any modifications to this software be + sent directly to him for evaluation and testing. + +*/ + + +#define DAC960_DriverVersion "2.2.4" +#define DAC960_DriverDate "23 August 1999" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DAC960.h" + + +/* + DAC960_ControllerCount is the number of DAC960 Controllers detected. +*/ + +static int + DAC960_ControllerCount = 0; + + +/* + DAC960_ActiveControllerCount is the number of Active DAC960 Controllers + detected. +*/ + +static int + DAC960_ActiveControllerCount = 0; + + +/* + DAC960_Controllers is an array of pointers to the DAC960 Controller + structures. +*/ + +static DAC960_Controller_T + *DAC960_Controllers[DAC960_MaxControllers] = { NULL }; + + +/* + DAC960_FileOperations is the File Operations structure for DAC960 Logical + Disk Devices. +*/ + +static FileOperations_T + DAC960_FileOperations = + { llseek: NULL, + read: block_read, + write: block_write, + readdir: NULL, + poll: NULL, + ioctl: DAC960_IOCTL, + mmap: NULL, + open: DAC960_Open, + release: DAC960_Release, + fsync: block_fsync, + fasync: NULL, + check_media_change: NULL, + revalidate: NULL }; + + +/* + DAC960_ProcDirectoryEntry is the DAC960 /proc/rd directory entry. +*/ + +static PROC_DirectoryEntry_T + DAC960_ProcDirectoryEntry; + + +/* + DAC960_NotifierBlock is the Notifier Block structure for DAC960 Driver. +*/ + +static NotifierBlock_T + DAC960_NotifierBlock = { DAC960_Finalize, NULL, 0 }; + + +/* + DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name, + Copyright Notice, and Electronic Mail Address. +*/ + +static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller) +{ + DAC960_Announce("***** DAC960 RAID Driver Version " + DAC960_DriverVersion " of " + DAC960_DriverDate " *****\n", Controller); + DAC960_Announce("Copyright 1998-1999 by Leonard N. Zubkoff " + "\n", Controller); +} + + +/* + DAC960_Failure prints a standardized error message, and then returns false. +*/ + +static boolean DAC960_Failure(DAC960_Controller_T *Controller, + char *ErrorMessage) +{ + DAC960_Error("While configuring DAC960 PCI RAID Controller at\n", + Controller); + if (Controller->IO_Address == 0) + DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " + "PCI Address 0x%X\n", Controller, + Controller->Bus, Controller->Device, + Controller->Function, Controller->PCI_Address); + else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " + "0x%X PCI Address 0x%X\n", Controller, + Controller->Bus, Controller->Device, + Controller->Function, Controller->IO_Address, + Controller->PCI_Address); + DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage); + return false; +} + + +/* + DAC960_ClearCommand clears critical fields of Command. +*/ + +static inline void DAC960_ClearCommand(DAC960_Command_T *Command) +{ + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + CommandMailbox->Words[0] = 0; + CommandMailbox->Words[1] = 0; + CommandMailbox->Words[2] = 0; + CommandMailbox->Words[3] = 0; + Command->CommandStatus = 0; +} + + +/* + DAC960_AllocateCommand allocates a Command structure from Controller's + free list. +*/ + +static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T + *Controller) +{ + DAC960_Command_T *Command = Controller->FreeCommands; + if (Command == NULL) return NULL; + Controller->FreeCommands = Command->Next; + Command->Next = NULL; + return Command; +} + + +/* + DAC960_DeallocateCommand deallocates Command, returning it to Controller's + free list. +*/ + +static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + Command->Next = Controller->FreeCommands; + Controller->FreeCommands = Command; +} + + +/* + DAC960_QueueCommand queues Command. +*/ + +static void DAC960_QueueCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_CommandMailbox_T *NextCommandMailbox; + CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands; + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + NextCommandMailbox = Controller->NextCommandMailbox; + DAC960_V5_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); + if (Controller->PreviousCommandMailbox1->Words[0] == 0 || + Controller->PreviousCommandMailbox2->Words[0] == 0) + { + if (Controller->DualModeMemoryMailboxInterface) + DAC960_V5_MemoryMailboxNewCommand(ControllerBaseAddress); + else DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress); + } + Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1; + Controller->PreviousCommandMailbox1 = NextCommandMailbox; + if (++NextCommandMailbox > Controller->LastCommandMailbox) + NextCommandMailbox = Controller->FirstCommandMailbox; + Controller->NextCommandMailbox = NextCommandMailbox; + break; + case DAC960_V4_Controller: + NextCommandMailbox = Controller->NextCommandMailbox; + DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); + if (Controller->PreviousCommandMailbox1->Words[0] == 0 || + Controller->PreviousCommandMailbox2->Words[0] == 0) + { + if (Controller->DualModeMemoryMailboxInterface) + DAC960_V4_MemoryMailboxNewCommand(ControllerBaseAddress); + else DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress); + } + Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1; + Controller->PreviousCommandMailbox1 = NextCommandMailbox; + if (++NextCommandMailbox > Controller->LastCommandMailbox) + NextCommandMailbox = Controller->FirstCommandMailbox; + Controller->NextCommandMailbox = NextCommandMailbox; + break; + case DAC960_V3_Controller: + while (DAC960_V3_MailboxFullP(ControllerBaseAddress)) + udelay(1); + DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox); + DAC960_V3_NewCommand(ControllerBaseAddress); + break; + } +} + + +/* + DAC960_ExecuteCommand executes Command and waits for completion. It + returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + Semaphore_T Semaphore = MUTEX_LOCKED; + unsigned long ProcessorFlags; + Command->Semaphore = &Semaphore; + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (!in_interrupt()) + down(&Semaphore); + return Command->CommandStatus == DAC960_NormalCompletion; +} + + +/* + DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for + completion. It returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller, + DAC960_CommandOpcode_T CommandOpcode, + void *DataPointer) +{ + DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + boolean Result; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3.CommandOpcode = CommandOpcode; + CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer); + Result = DAC960_ExecuteCommand(Command); + DAC960_DeallocateCommand(Command); + return Result; +} + + +/* + DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for + completion. It returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller, + DAC960_CommandOpcode_T CommandOpcode, + unsigned char Channel, + unsigned char TargetID, + void *DataPointer) +{ + DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + boolean Result; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3D.CommandOpcode = CommandOpcode; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer); + Result = DAC960_ExecuteCommand(Command); + DAC960_DeallocateCommand(Command); + return Result; +} + + +/* + DAC960_EnableMemoryMailboxInterface enables the Memory Mailbox Interface. +*/ + +static boolean DAC960_EnableMemoryMailboxInterface(DAC960_Controller_T + *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_CommandMailbox_T *CommandMailboxesMemory; + DAC960_StatusMailbox_T *StatusMailboxesMemory; + DAC960_CommandMailbox_T CommandMailbox; + DAC960_CommandStatus_T CommandStatus; + void *SavedMemoryMailboxesAddress = NULL; + short NextCommandMailboxIndex = 0; + short NextStatusMailboxIndex = 0; + int TimeoutCounter = 1000000, i; + if (Controller->ControllerType == DAC960_V5_Controller) + DAC960_V5_RestoreMemoryMailboxInfo(Controller, + &SavedMemoryMailboxesAddress, + &NextCommandMailboxIndex, + &NextStatusMailboxIndex); + else DAC960_V4_RestoreMemoryMailboxInfo(Controller, + &SavedMemoryMailboxesAddress, + &NextCommandMailboxIndex, + &NextStatusMailboxIndex); + if (SavedMemoryMailboxesAddress == NULL) + CommandMailboxesMemory = + (DAC960_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1); + else CommandMailboxesMemory = SavedMemoryMailboxesAddress; + memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1); + Controller->FirstCommandMailbox = CommandMailboxesMemory; + CommandMailboxesMemory += DAC960_CommandMailboxCount - 1; + Controller->LastCommandMailbox = CommandMailboxesMemory; + Controller->NextCommandMailbox = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + if (--NextCommandMailboxIndex < 0) + NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1; + Controller->PreviousCommandMailbox1 = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + if (--NextCommandMailboxIndex < 0) + NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1; + Controller->PreviousCommandMailbox2 = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + StatusMailboxesMemory = + (DAC960_StatusMailbox_T *) (CommandMailboxesMemory + 1); + Controller->FirstStatusMailbox = StatusMailboxesMemory; + StatusMailboxesMemory += DAC960_StatusMailboxCount - 1; + Controller->LastStatusMailbox = StatusMailboxesMemory; + Controller->NextStatusMailbox = + &Controller->FirstStatusMailbox[NextStatusMailboxIndex]; + if (SavedMemoryMailboxesAddress != NULL) return true; + /* Enable the Memory Mailbox Interface. */ + Controller->DualModeMemoryMailboxInterface = true; + CommandMailbox.TypeX.CommandOpcode = 0x2B; + CommandMailbox.TypeX.CommandIdentifier = 0; + CommandMailbox.TypeX.CommandOpcode2 = 0x14; + CommandMailbox.TypeX.CommandMailboxesBusAddress = + Virtual_to_Bus(Controller->FirstCommandMailbox); + CommandMailbox.TypeX.StatusMailboxesBusAddress = + Virtual_to_Bus(Controller->FirstStatusMailbox); + for (i = 0; i < 2; i++) + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + while (--TimeoutCounter >= 0) + { + if (DAC960_V5_HardwareMailboxEmptyP(ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + DAC960_V5_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress); + while (--TimeoutCounter >= 0) + { + if (DAC960_V5_HardwareMailboxStatusAvailableP( + ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + CommandStatus = DAC960_V5_ReadStatusRegister(ControllerBaseAddress); + DAC960_V5_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); + DAC960_V5_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); + if (CommandStatus == DAC960_NormalCompletion) return true; + Controller->DualModeMemoryMailboxInterface = false; + CommandMailbox.TypeX.CommandOpcode2 = 0x10; + break; + case DAC960_V4_Controller: + while (--TimeoutCounter >= 0) + { + if (!DAC960_V4_HardwareMailboxFullP(ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + DAC960_V4_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress); + while (--TimeoutCounter >= 0) + { + if (DAC960_V4_HardwareMailboxStatusAvailableP( + ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress); + DAC960_V4_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); + DAC960_V4_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); + if (CommandStatus == DAC960_NormalCompletion) return true; + Controller->DualModeMemoryMailboxInterface = false; + CommandMailbox.TypeX.CommandOpcode2 = 0x10; + break; + default: + break; + } + return false; +} + + +/* + DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating + the PCI Configuration Space for Controller Type. +*/ + +static void DAC960_DetectControllers(DAC960_ControllerType_T ControllerType) +{ + unsigned short VendorID = 0, DeviceID = 0; + unsigned int MemoryWindowSize = 0; + PCI_Device_T *PCI_Device = NULL; + switch (ControllerType) + { + case DAC960_V5_Controller: + VendorID = PCI_VENDOR_ID_DEC; + DeviceID = PCI_DEVICE_ID_DEC_21285; + MemoryWindowSize = DAC960_V5_RegisterWindowSize; + break; + case DAC960_V4_Controller: + VendorID = PCI_VENDOR_ID_MYLEX; + DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V4; + MemoryWindowSize = DAC960_V4_RegisterWindowSize; + break; + case DAC960_V3_Controller: + VendorID = PCI_VENDOR_ID_MYLEX; + DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V3; + MemoryWindowSize = DAC960_V3_RegisterWindowSize; + break; + } + while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL) + { + DAC960_Controller_T *Controller = (DAC960_Controller_T *) + kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC); + DAC960_IO_Address_T IO_Address = 0; + DAC960_PCI_Address_T PCI_Address = 0; + unsigned char Bus = PCI_Device->bus->number; + unsigned char DeviceFunction = PCI_Device->devfn; + unsigned char Device = DeviceFunction >> 3; + unsigned char Function = DeviceFunction & 0x7; + unsigned int IRQ_Channel = PCI_Device->irq; + unsigned long BaseAddress0 = PCI_Device->base_address[0]; + unsigned long BaseAddress1 = PCI_Device->base_address[1]; + unsigned short SubsystemVendorID, SubsystemDeviceID; + int CommandIdentifier; + pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID, + &SubsystemVendorID); + pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID, + &SubsystemDeviceID); + switch (ControllerType) + { + case DAC960_V5_Controller: + if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX && + SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960P_V5)) + goto Ignore; + PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK; + break; + case DAC960_V4_Controller: + PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK; + break; + case DAC960_V3_Controller: + IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK; + PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK; + break; + } + if (DAC960_ControllerCount == DAC960_MaxControllers) + { + DAC960_Error("More than %d DAC960 Controllers detected - " + "ignoring from Controller at\n", + NULL, DAC960_MaxControllers); + goto Ignore; + } + if (Controller == NULL) + { + DAC960_Error("Unable to allocate Controller structure for " + "Controller at\n", NULL); + goto Ignore; + } + memset(Controller, 0, sizeof(DAC960_Controller_T)); + init_waitqueue_head(&Controller->CommandWaitQueue); + Controller->ControllerNumber = DAC960_ControllerCount; + DAC960_Controllers[DAC960_ControllerCount++] = Controller; + DAC960_AnnounceDriver(Controller); + Controller->ControllerType = ControllerType; + Controller->IO_Address = IO_Address; + Controller->PCI_Address = PCI_Address; + Controller->Bus = Bus; + Controller->Device = Device; + Controller->Function = Function; + sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); + /* + Acquire shared access to the IRQ Channel. + */ + if (IRQ_Channel == 0) + { + DAC960_Error("IRQ Channel %d illegal for Controller at\n", + Controller, IRQ_Channel); + goto Failure; + } + strcpy(Controller->FullModelName, "DAC960"); + if (request_irq(IRQ_Channel, DAC960_InterruptHandler, + SA_SHIRQ, Controller->FullModelName, Controller) < 0) + { + DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n", + Controller, IRQ_Channel); + goto Failure; + } + Controller->IRQ_Channel = IRQ_Channel; + /* + Map the Controller Register Window. + */ + if (MemoryWindowSize < PAGE_SIZE) + MemoryWindowSize = PAGE_SIZE; + Controller->MemoryMappedAddress = + ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize); + Controller->BaseAddress = + Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK); + if (Controller->MemoryMappedAddress == NULL) + { + DAC960_Error("Unable to map Controller Register Window for " + "Controller at\n", Controller); + goto Failure; + } + switch (ControllerType) + { + case DAC960_V5_Controller: + DAC960_V5_DisableInterrupts(Controller->BaseAddress); + if (!DAC960_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to Enable Memory Mailbox Interface " + "for Controller at\n", Controller); + goto Failure; + } + DAC960_V5_EnableInterrupts(Controller->BaseAddress); + break; + case DAC960_V4_Controller: + DAC960_V4_DisableInterrupts(Controller->BaseAddress); + if (!DAC960_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to Enable Memory Mailbox Interface " + "for Controller at\n", Controller); + goto Failure; + } + DAC960_V4_EnableInterrupts(Controller->BaseAddress); + break; + case DAC960_V3_Controller: + request_region(Controller->IO_Address, 0x80, + Controller->FullModelName); + DAC960_V3_EnableInterrupts(Controller->BaseAddress); + break; + } + DAC960_ActiveControllerCount++; + for (CommandIdentifier = 0; + CommandIdentifier < DAC960_MaxChannels; + CommandIdentifier++) + { + Controller->Commands[CommandIdentifier].Controller = Controller; + Controller->Commands[CommandIdentifier].Next = + Controller->FreeCommands; + Controller->FreeCommands = &Controller->Commands[CommandIdentifier]; + } + continue; + Failure: + if (IO_Address == 0) + DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " + "PCI Address 0x%X\n", Controller, + Bus, Device, Function, PCI_Address); + else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " + "0x%X PCI Address 0x%X\n", Controller, + Bus, Device, Function, IO_Address, PCI_Address); + if (Controller == NULL) break; + if (Controller->IRQ_Channel > 0) + free_irq(IRQ_Channel, Controller); + if (Controller->MemoryMappedAddress != NULL) + iounmap(Controller->MemoryMappedAddress); + DAC960_Controllers[Controller->ControllerNumber] = NULL; + Ignore: + kfree(Controller); + } +} + + +/* + DAC960_ReadControllerConfiguration reads the Configuration Information + from Controller and initializes the Controller structure. +*/ + +static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T + *Controller) +{ + DAC960_Enquiry2_T Enquiry2; + DAC960_Config2_T Config2; + int LogicalDriveNumber, Channel, TargetID; + if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry, + &Controller->Enquiry[0])) + return DAC960_Failure(Controller, "ENQUIRY"); + if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2)) + return DAC960_Failure(Controller, "ENQUIRY2"); + if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2)) + return DAC960_Failure(Controller, "READ CONFIG2"); + if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation, + &Controller->LogicalDriveInformation[0])) + return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION"); + for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState, + Channel, TargetID, + &Controller->DeviceState[0][Channel][TargetID])) + return DAC960_Failure(Controller, "GET DEVICE STATE"); + /* + Initialize the Controller Model Name and Full Model Name fields. + */ + switch (Enquiry2.HardwareID.SubModel) + { + case DAC960_P_PD_PU: + if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra) + strcpy(Controller->ModelName, "DAC960PU"); + else strcpy(Controller->ModelName, "DAC960PD"); + break; + case DAC960_PL: + strcpy(Controller->ModelName, "DAC960PL"); + break; + case DAC960_PG: + strcpy(Controller->ModelName, "DAC960PG"); + break; + case DAC960_PJ: + strcpy(Controller->ModelName, "DAC960PJ"); + break; + case DAC960_PR: + strcpy(Controller->ModelName, "DAC960PR"); + break; + case DAC960_PT: + strcpy(Controller->ModelName, "DAC960PT"); + break; + case DAC960_PTL0: + strcpy(Controller->ModelName, "DAC960PTL0"); + break; + case DAC960_PRL: + strcpy(Controller->ModelName, "DAC960PRL"); + break; + case DAC960_PTL1: + strcpy(Controller->ModelName, "DAC960PTL1"); + break; + case DAC1164_P: + strcpy(Controller->ModelName, "DAC1164P"); + break; + default: + return DAC960_Failure(Controller, "MODEL VERIFICATION"); + } + strcpy(Controller->FullModelName, "Mylex "); + strcat(Controller->FullModelName, Controller->ModelName); + /* + Initialize the Controller Firmware Version field and verify that it + is a supported firmware version. The supported firmware versions are: + + DAC1164P 5.06 and above + DAC960PTL/PRL/PJ/PG 4.06 and above + DAC960PU/PD/PL 3.51 and above + */ + sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d", + Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion, + Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID); + if (!((Controller->FirmwareVersion[0] == '5' && + strcmp(Controller->FirmwareVersion, "5.06") >= 0) || + (Controller->FirmwareVersion[0] == '4' && + strcmp(Controller->FirmwareVersion, "4.06") >= 0) || + (Controller->FirmwareVersion[0] == '3' && + strcmp(Controller->FirmwareVersion, "3.51") >= 0))) + { + DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION"); + DAC960_Error("Firmware Version = '%s'\n", Controller, + Controller->FirmwareVersion); + return false; + } + /* + Initialize the Controller Channels, Memory Size, and SAF-TE Enclosure + Management Enabled fields. + */ + Controller->Channels = Enquiry2.ActualChannels; + Controller->MemorySize = Enquiry2.MemorySize >> 20; + Controller->SAFTE_EnclosureManagementEnabled = + Enquiry2.FaultManagementType == DAC960_SAFTE; + /* + Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive + Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments. + The Driver Queue Depth must be at most one less than the Controller Queue + Depth to allow for an automatic drive rebuild operation. + */ + Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands; + Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1; + Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives; + Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand; + Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries; + /* + Initialize the Stripe Size, Segment Size, and Geometry Translation. + */ + Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor + >> (10 - DAC960_BlockSizeBits); + Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor + >> (10 - DAC960_BlockSizeBits); + switch (Config2.DriveGeometry) + { + case DAC960_Geometry_128_32: + Controller->GeometryTranslationHeads = 128; + Controller->GeometryTranslationSectors = 32; + break; + case DAC960_Geometry_255_63: + Controller->GeometryTranslationHeads = 255; + Controller->GeometryTranslationSectors = 63; + break; + default: + return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY"); + } + /* + Initialize the Logical Drive Initial State. + */ + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + Controller->LogicalDriveInitialState[LogicalDriveNumber] = + Controller->LogicalDriveInformation[0] + [LogicalDriveNumber].LogicalDriveState; + Controller->LastRebuildStatus = DAC960_NoRebuildOrCheckInProgress; + return true; +} + + +/* + DAC960_ReportControllerConfiguration reports the Configuration Information of + Controller. +*/ + +static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T + *Controller) +{ + DAC960_Info("Configuring Mylex %s PCI RAID Controller\n", + Controller, Controller->ModelName); + DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n", + Controller, Controller->FirmwareVersion, + Controller->Channels, Controller->MemorySize); + DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ", + Controller, Controller->Bus, + Controller->Device, Controller->Function); + if (Controller->IO_Address == 0) + DAC960_Info("Unassigned\n", Controller); + else DAC960_Info("0x%X\n", Controller, Controller->IO_Address); + DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n", + Controller, Controller->PCI_Address, + (unsigned long) Controller->BaseAddress, + Controller->IRQ_Channel); + DAC960_Info(" Controller Queue Depth: %d, " + "Maximum Blocks per Command: %d\n", + Controller, Controller->ControllerQueueDepth, + Controller->MaxBlocksPerCommand); + DAC960_Info(" Driver Queue Depth: %d, " + "Maximum Scatter/Gather Segments: %d\n", + Controller, Controller->DriverQueueDepth, + Controller->MaxScatterGatherSegments); + DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, " + "BIOS Geometry: %d/%d\n", Controller, + Controller->StripeSize, + Controller->SegmentSize, + Controller->GeometryTranslationHeads, + Controller->GeometryTranslationSectors); + if (Controller->SAFTE_EnclosureManagementEnabled) + DAC960_Info(" SAF-TE Enclosure Management Enabled\n", Controller); + return true; +} + + +/* + DAC960_ReadDeviceConfiguration reads the Device Configuration Information by + requesting the SCSI Inquiry and SCSI Inquiry Unit Serial Number information + for each device connected to Controller. +*/ + +static boolean DAC960_ReadDeviceConfiguration(DAC960_Controller_T *Controller) +{ + DAC960_DCDB_T DCDBs[DAC960_MaxChannels], *DCDB; + Semaphore_T Semaphores[DAC960_MaxChannels], *Semaphore; + unsigned long ProcessorFlags; + int Channel, TargetID; + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + for (Channel = 0; Channel < Controller->Channels; Channel++) + { + DAC960_Command_T *Command = &Controller->Commands[Channel]; + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->InquiryStandardData[Channel][TargetID]; + InquiryStandardData->PeripheralDeviceType = 0x1F; + Semaphore = &Semaphores[Channel]; + *Semaphore = MUTEX_LOCKED; + DCDB = &DCDBs[Channel]; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + Command->Semaphore = Semaphore; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB; + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + DCDB->Channel = Channel; + DCDB->TargetID = TargetID; + DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem; + DCDB->EarlyStatus = false; + DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds; + DCDB->NoAutomaticRequestSense = false; + DCDB->DisconnectPermitted = true; + DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData); + DCDB->CDBLength = 6; + DCDB->TransferLengthHigh4 = 0; + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 0; /* EVPD = 0 */ + DCDB->CDB[2] = 0; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + for (Channel = 0; Channel < Controller->Channels; Channel++) + { + DAC960_Command_T *Command = &Controller->Commands[Channel]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + &Controller->InquiryUnitSerialNumber[Channel][TargetID]; + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + Semaphore = &Semaphores[Channel]; + down(Semaphore); + if (Command->CommandStatus != DAC960_NormalCompletion) continue; + Command->Semaphore = Semaphore; + DCDB = &DCDBs[Channel]; + DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber); + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 1; /* EVPD = 1 */ + DCDB->CDB[2] = 0x80; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + down(Semaphore); + } + } + return true; +} + + +/* + DAC960_ReportDeviceConfiguration reports the Device Configuration Information + of Controller. +*/ + +static boolean DAC960_ReportDeviceConfiguration(DAC960_Controller_T *Controller) +{ + int LogicalDriveNumber, Channel, TargetID; + DAC960_Info(" Physical Devices:\n", Controller); + for (Channel = 0; Channel < Controller->Channels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->InquiryStandardData[Channel][TargetID]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + &Controller->InquiryUnitSerialNumber[Channel][TargetID]; + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + DAC960_ErrorTable_T *ErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex]; + DAC960_ErrorTableEntry_T *ErrorEntry = + &ErrorTable->ErrorTableEntries[Channel][TargetID]; + char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)]; + char Model[1+sizeof(InquiryStandardData->ProductIdentification)]; + char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)]; + char SerialNumber[1+sizeof(InquiryUnitSerialNumber + ->ProductSerialNumber)]; + int i; + if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue; + for (i = 0; i < sizeof(Vendor)-1; i++) + { + unsigned char VendorCharacter = + InquiryStandardData->VendorIdentification[i]; + Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~' + ? VendorCharacter : ' '); + } + Vendor[sizeof(Vendor)-1] = '\0'; + for (i = 0; i < sizeof(Model)-1; i++) + { + unsigned char ModelCharacter = + InquiryStandardData->ProductIdentification[i]; + Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~' + ? ModelCharacter : ' '); + } + Model[sizeof(Model)-1] = '\0'; + for (i = 0; i < sizeof(Revision)-1; i++) + { + unsigned char RevisionCharacter = + InquiryStandardData->ProductRevisionLevel[i]; + Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~' + ? RevisionCharacter : ' '); + } + Revision[sizeof(Revision)-1] = '\0'; + DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n", + Controller, Channel, TargetID, (TargetID < 10 ? " " : ""), + Vendor, Model, Revision); + if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F) + { + int SerialNumberLength = InquiryUnitSerialNumber->PageLength; + if (SerialNumberLength > + sizeof(InquiryUnitSerialNumber->ProductSerialNumber)) + SerialNumberLength = + sizeof(InquiryUnitSerialNumber->ProductSerialNumber); + for (i = 0; i < SerialNumberLength; i++) + { + unsigned char SerialNumberCharacter = + InquiryUnitSerialNumber->ProductSerialNumber[i]; + SerialNumber[i] = + (SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~' + ? SerialNumberCharacter : ' '); + } + SerialNumber[SerialNumberLength] = '\0'; + DAC960_Info(" Serial Number: %s\n", + Controller, SerialNumber); + } + if (DeviceState->Present && DeviceState->DeviceType == DAC960_DiskType) + { + if (Controller->DeviceResetCount[Channel][TargetID] > 0) + DAC960_Info(" Disk Status: %s, %d blocks, %d resets\n", + Controller, + (DeviceState->DeviceState == DAC960_Device_Dead + ? "Dead" + : DeviceState->DeviceState == DAC960_Device_WriteOnly + ? "Write-Only" + : DeviceState->DeviceState == DAC960_Device_Online + ? "Online" : "Standby"), + DeviceState->DiskSize, + Controller->DeviceResetCount[Channel][TargetID]); + else + DAC960_Info(" Disk Status: %s, %d blocks\n", Controller, + (DeviceState->DeviceState == DAC960_Device_Dead + ? "Dead" + : DeviceState->DeviceState == DAC960_Device_WriteOnly + ? "Write-Only" + : DeviceState->DeviceState == DAC960_Device_Online + ? "Online" : "Standby"), + DeviceState->DiskSize); + } + if (ErrorEntry->ParityErrorCount > 0 || + ErrorEntry->SoftErrorCount > 0 || + ErrorEntry->HardErrorCount > 0 || + ErrorEntry->MiscErrorCount > 0) + DAC960_Info(" Errors - Parity: %d, Soft: %d, " + "Hard: %d, Misc: %d\n", Controller, + ErrorEntry->ParityErrorCount, + ErrorEntry->SoftErrorCount, + ErrorEntry->HardErrorCount, + ErrorEntry->MiscErrorCount); + } + DAC960_Info(" Logical Drives:\n", Controller); + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + { + DAC960_LogicalDriveInformation_T *LogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex][LogicalDriveNumber]; + DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n", + Controller, Controller->ControllerNumber, LogicalDriveNumber, + LogicalDriveInformation->RAIDLevel, + (LogicalDriveInformation->LogicalDriveState == + DAC960_LogicalDrive_Online + ? "Online" + : LogicalDriveInformation->LogicalDriveState == + DAC960_LogicalDrive_Critical + ? "Critical" : "Offline"), + LogicalDriveInformation->LogicalDriveSize, + (LogicalDriveInformation->WriteBack + ? "Write Back" : "Write Thru")); + } + return true; +} + + +/* + DAC960_RegisterBlockDevice registers the Block Device structures + associated with Controller. +*/ + +static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) +{ + static void (*RequestFunctions[DAC960_MaxControllers])(void) = + { DAC960_RequestFunction0, DAC960_RequestFunction1, + DAC960_RequestFunction2, DAC960_RequestFunction3, + DAC960_RequestFunction4, DAC960_RequestFunction5, + DAC960_RequestFunction6, DAC960_RequestFunction7 }; + int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; + GenericDiskInfo_T *GenericDiskInfo; + int MinorNumber; + /* + Register the Block Device Major Number for this DAC960 Controller. + */ + if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0) + { + DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n", + Controller, MajorNumber); + return false; + } + /* + Initialize the I/O Request Function. + */ + blk_dev[MajorNumber].request_fn = + RequestFunctions[Controller->ControllerNumber]; + /* + Initialize the Disk Partitions array, Partition Sizes array, Block Sizes + array, Max Sectors per Request array, and Max Segments per Request array. + */ + for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++) + { + Controller->BlockSizes[MinorNumber] = BLOCK_SIZE; + Controller->MaxSectorsPerRequest[MinorNumber] = + Controller->MaxBlocksPerCommand; + Controller->MaxSegmentsPerRequest[MinorNumber] = + Controller->MaxScatterGatherSegments; + } + Controller->GenericDiskInfo.part = Controller->DiskPartitions; + Controller->GenericDiskInfo.sizes = Controller->PartitionSizes; + blksize_size[MajorNumber] = Controller->BlockSizes; + max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest; + max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest; + /* + Initialize Read Ahead to 128 sectors. + */ + read_ahead[MajorNumber] = 128; + /* + Complete initialization of the Generic Disk Information structure. + */ + Controller->GenericDiskInfo.major = MajorNumber; + Controller->GenericDiskInfo.major_name = "rd"; + Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits; + Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions; + Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives; + Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo; + Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount; + Controller->GenericDiskInfo.real_devices = Controller; + Controller->GenericDiskInfo.next = NULL; + /* + Install the Generic Disk Information structure at the end of the list. + */ + if ((GenericDiskInfo = gendisk_head) != NULL) + { + while (GenericDiskInfo->next != NULL) + GenericDiskInfo = GenericDiskInfo->next; + GenericDiskInfo->next = &Controller->GenericDiskInfo; + } + else gendisk_head = &Controller->GenericDiskInfo; + /* + Indicate the Block Device Registration completed successfully, + */ + return true; +} + + +/* + DAC960_UnregisterBlockDevice unregisters the Block Device structures + associated with Controller. +*/ + +static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller) +{ + int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; + /* + Unregister the Block Device Major Number for this DAC960 Controller. + */ + unregister_blkdev(MajorNumber, "rd"); + /* + Remove the I/O Request Function. + */ + blk_dev[MajorNumber].request_fn = NULL; + /* + Remove the Disk Partitions array, Partition Sizes array, Block Sizes + array, Max Sectors per Request array, and Max Segments per Request array. + */ + Controller->GenericDiskInfo.part = NULL; + Controller->GenericDiskInfo.sizes = NULL; + blk_size[MajorNumber] = NULL; + blksize_size[MajorNumber] = NULL; + max_sectors[MajorNumber] = NULL; + max_segments[MajorNumber] = NULL; + /* + Remove the Generic Disk Information structure from the list. + */ + if (gendisk_head != &Controller->GenericDiskInfo) + { + GenericDiskInfo_T *GenericDiskInfo = gendisk_head; + while (GenericDiskInfo != NULL && + GenericDiskInfo->next != &Controller->GenericDiskInfo) + GenericDiskInfo = GenericDiskInfo->next; + if (GenericDiskInfo != NULL) + GenericDiskInfo->next = GenericDiskInfo->next->next; + } + else gendisk_head = Controller->GenericDiskInfo.next; +} + + +/* + DAC960_InitializeController initializes Controller. +*/ + +static void DAC960_InitializeController(DAC960_Controller_T *Controller) +{ + if (DAC960_ReadControllerConfiguration(Controller) && + DAC960_ReportControllerConfiguration(Controller) && + DAC960_ReadDeviceConfiguration(Controller) && + DAC960_ReportDeviceConfiguration(Controller) && + DAC960_RegisterBlockDevice(Controller)) + { + /* + Initialize the Command structures. + */ + DAC960_Command_T *Commands = Controller->Commands; + int CommandIdentifier; + Controller->FreeCommands = NULL; + for (CommandIdentifier = 0; + CommandIdentifier < Controller->DriverQueueDepth; + CommandIdentifier++) + { + Commands[CommandIdentifier].Controller = Controller; + Commands[CommandIdentifier].Next = Controller->FreeCommands; + Controller->FreeCommands = &Commands[CommandIdentifier]; + } + /* + Initialize the Monitoring Timer. + */ + init_timer(&Controller->MonitoringTimer); + Controller->MonitoringTimer.expires = + jiffies + DAC960_MonitoringTimerInterval; + Controller->MonitoringTimer.data = (unsigned long) Controller; + Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction; + add_timer(&Controller->MonitoringTimer); + Controller->ControllerInitialized = true; + } + else DAC960_FinalizeController(Controller); +} + + +/* + DAC960_FinalizeController finalizes Controller. +*/ + +static void DAC960_FinalizeController(DAC960_Controller_T *Controller) +{ + if (Controller->ControllerInitialized) + { + del_timer(&Controller->MonitoringTimer); + DAC960_Notice("Flushing Cache...", Controller); + DAC960_ExecuteType3(Controller, DAC960_Flush, NULL); + DAC960_Notice("done\n", Controller); + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + if (!Controller->DualModeMemoryMailboxInterface) + DAC960_V5_SaveMemoryMailboxInfo(Controller); + break; + case DAC960_V4_Controller: + if (!Controller->DualModeMemoryMailboxInterface) + DAC960_V4_SaveMemoryMailboxInfo(Controller); + break; + case DAC960_V3_Controller: + break; + } + } + free_irq(Controller->IRQ_Channel, Controller); + iounmap(Controller->MemoryMappedAddress); + if (Controller->IO_Address > 0) + release_region(Controller->IO_Address, 0x80); + DAC960_UnregisterBlockDevice(Controller); + DAC960_Controllers[Controller->ControllerNumber] = NULL; + kfree(Controller); +} + + +/* + DAC960_Initialize initializes the DAC960 Driver. +*/ + +void DAC960_Initialize(void) +{ + int ControllerNumber; + DAC960_DetectControllers(DAC960_V5_Controller); + DAC960_DetectControllers(DAC960_V4_Controller); + DAC960_DetectControllers(DAC960_V3_Controller); + if (DAC960_ActiveControllerCount == 0) return; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + if (DAC960_Controllers[ControllerNumber] != NULL) + DAC960_InitializeController(DAC960_Controllers[ControllerNumber]); + DAC960_CreateProcEntries(); + register_reboot_notifier(&DAC960_NotifierBlock); +} + + +/* + DAC960_Finalize finalizes the DAC960 Driver. +*/ + +static int DAC960_Finalize(NotifierBlock_T *NotifierBlock, + unsigned long Event, + void *Buffer) +{ + int ControllerNumber; + if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF)) + return NOTIFY_DONE; + if (DAC960_ActiveControllerCount == 0) return NOTIFY_OK; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + if (DAC960_Controllers[ControllerNumber] != NULL) + DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]); + DAC960_DestroyProcEntries(); + unregister_reboot_notifier(&DAC960_NotifierBlock); + return NOTIFY_OK; +} + + +/* + DAC960_ProcessRequest attempts to remove one I/O Request from Controller's + I/O Request Queue and queues it to the Controller. WaitForCommand is true if + this function should wait for a Command to become available if necessary. + This function returns true if an I/O Request was queued and false otherwise. +*/ + +static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller, + boolean WaitForCommand) +{ + IO_Request_T **RequestQueuePointer = + &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request; + IO_Request_T *Request; + DAC960_Command_T *Command; + char *RequestBuffer; + while (true) + { + Request = *RequestQueuePointer; + if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false; + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) break; + if (!WaitForCommand) return false; + spin_unlock(&io_request_lock); + sleep_on(&Controller->CommandWaitQueue); + spin_lock_irq(&io_request_lock); + } + DAC960_ClearCommand(Command); + if (Request->cmd == READ) + Command->CommandType = DAC960_ReadCommand; + else Command->CommandType = DAC960_WriteCommand; + Command->Semaphore = Request->sem; + Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev); + Command->BlockNumber = + Request->sector + + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect; + Command->BlockCount = Request->nr_sectors; + Command->SegmentCount = Request->nr_segments; + Command->BufferHeader = Request->bh; + RequestBuffer = Request->buffer; + Request->rq_status = RQ_INACTIVE; + *RequestQueuePointer = Request->next; + wake_up(&wait_for_request); + if (Command->SegmentCount == 1) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + if (Command->CommandType == DAC960_ReadCommand) + CommandMailbox->Type5.CommandOpcode = DAC960_Read; + else CommandMailbox->Type5.CommandOpcode = DAC960_Write; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer); + } + else + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_ScatterGatherSegment_T + *ScatterGatherList = Command->ScatterGatherList; + BufferHeader_T *BufferHeader = Command->BufferHeader; + char *LastDataEndPointer = NULL; + int SegmentNumber = 0; + if (Command->CommandType == DAC960_ReadCommand) + CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather; + else + CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList); + CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount; + while (BufferHeader != NULL) + { + if (BufferHeader->b_data == LastDataEndPointer) + { + ScatterGatherList[SegmentNumber-1].SegmentByteCount += + BufferHeader->b_size; + LastDataEndPointer += BufferHeader->b_size; + } + else + { + ScatterGatherList[SegmentNumber].SegmentDataPointer = + Virtual_to_Bus(BufferHeader->b_data); + ScatterGatherList[SegmentNumber].SegmentByteCount = + BufferHeader->b_size; + LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size; + if (SegmentNumber++ > Controller->MaxScatterGatherSegments) + panic("DAC960: Scatter/Gather Segment Overflow\n"); + } + BufferHeader = BufferHeader->b_reqnext; + } + if (SegmentNumber != Command->SegmentCount) + panic("DAC960: SegmentNumber != SegmentCount\n"); + } + DAC960_QueueCommand(Command); + return true; +} + + +/* + DAC960_ProcessRequests attempts to remove as many I/O Requests as possible + from Controller's I/O Request Queue and queue them to the Controller. +*/ + +static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller) +{ + int Counter = 0; + while (DAC960_ProcessRequest(Controller, Counter++ == 0)) ; +} + + +/* + DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0. +*/ + +static void DAC960_RequestFunction0(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[0]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1. +*/ + +static void DAC960_RequestFunction1(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[1]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2. +*/ + +static void DAC960_RequestFunction2(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[2]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3. +*/ + +static void DAC960_RequestFunction3(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[3]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4. +*/ + +static void DAC960_RequestFunction4(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[4]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5. +*/ + +static void DAC960_RequestFunction5(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[5]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6. +*/ + +static void DAC960_RequestFunction6(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[6]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7. +*/ + +static void DAC960_RequestFunction7(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[7]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_ReadWriteError prints an appropriate error message for Command when + an error occurs on a Read or Write operation. +*/ + +static void DAC960_ReadWriteError(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + char *CommandName = "UNKNOWN"; + switch (Command->CommandType) + { + case DAC960_ReadCommand: + case DAC960_ReadRetryCommand: + CommandName = "READ"; + break; + case DAC960_WriteCommand: + case DAC960_WriteRetryCommand: + CommandName = "WRITE"; + break; + case DAC960_MonitoringCommand: + case DAC960_ImmediateCommand: + case DAC960_QueuedCommand: + break; + } + switch (Command->CommandStatus) + { + case DAC960_IrrecoverableDataError: + DAC960_Error("Irrecoverable Data Error on %s:\n", + Controller, CommandName); + break; + case DAC960_LogicalDriveNonexistentOrOffline: + DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n", + Controller, CommandName); + break; + case DAC960_AccessBeyondEndOfLogicalDrive: + DAC960_Error("Attempt to Access Beyond End of Logical Drive " + "on %s:\n", Controller, CommandName); + break; + case DAC960_BadDataEncountered: + DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName); + break; + default: + DAC960_Error("Unexpected Error Status %04X on %s:\n", + Controller, Command->CommandStatus, CommandName); + break; + } + DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %d..%d\n", + Controller, Controller->ControllerNumber, + Command->LogicalDriveNumber, Command->BlockNumber, + Command->BlockNumber + Command->BlockCount - 1); + if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0) + DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %d..%d\n", + Controller, Controller->ControllerNumber, + Command->LogicalDriveNumber, + DAC960_PartitionNumber(Command->BufferHeader->b_rdev), + Command->BufferHeader->b_rsector, + Command->BufferHeader->b_rsector + Command->BlockCount - 1); +} + + +/* + DAC960_ProcessCompletedBuffer performs completion processing for an + individual Buffer. +*/ + +static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader, + boolean SuccessfulIO) +{ + BufferHeader->b_end_io(BufferHeader, SuccessfulIO); +} + + +/* + DAC960_ProcessCompletedCommand performs completion processing for Command. +*/ + +static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + DAC960_CommandType_T CommandType = Command->CommandType; + DAC960_CommandOpcode_T CommandOpcode = + Command->CommandMailbox.Common.CommandOpcode; + DAC960_CommandStatus_T CommandStatus = Command->CommandStatus; + BufferHeader_T *BufferHeader = Command->BufferHeader; + if (CommandType == DAC960_ReadCommand || + CommandType == DAC960_WriteCommand) + { + if (CommandStatus == DAC960_NormalCompletion) + { + /* + Perform completion processing for all buffers in this I/O Request. + */ + while (BufferHeader != NULL) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + DAC960_ProcessCompletedBuffer(BufferHeader, true); + BufferHeader = NextBufferHeader; + } + /* + Wake up requestor for swap file paging requests. + */ + if (Command->Semaphore != NULL) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + } + add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber); + } + else if ((CommandStatus == DAC960_IrrecoverableDataError || + CommandStatus == DAC960_BadDataEncountered) && + BufferHeader != NULL && + BufferHeader->b_reqnext != NULL) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + if (CommandType == DAC960_ReadCommand) + { + Command->CommandType = DAC960_ReadRetryCommand; + CommandMailbox->Type5.CommandOpcode = DAC960_Read; + } + else + { + Command->CommandType = DAC960_WriteRetryCommand; + CommandMailbox->Type5.CommandOpcode = DAC960_Write; + } + Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.BusAddress = + Virtual_to_Bus(BufferHeader->b_data); + DAC960_QueueCommand(Command); + return; + } + else + { + if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline) + DAC960_ReadWriteError(Command); + /* + Perform completion processing for all buffers in this I/O Request. + */ + while (BufferHeader != NULL) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + DAC960_ProcessCompletedBuffer(BufferHeader, false); + BufferHeader = NextBufferHeader; + } + /* + Wake up requestor for swap file paging requests. + */ + if (Command->Semaphore != NULL) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + } + } + } + else if (CommandType == DAC960_ReadRetryCommand || + CommandType == DAC960_WriteRetryCommand) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + /* + Perform completion processing for this single buffer. + */ + if (CommandStatus == DAC960_NormalCompletion) + DAC960_ProcessCompletedBuffer(BufferHeader, true); + else + { + if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline) + DAC960_ReadWriteError(Command); + DAC960_ProcessCompletedBuffer(BufferHeader, false); + } + if (NextBufferHeader != NULL) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + Command->BlockNumber += + BufferHeader->b_size >> DAC960_BlockSizeBits; + Command->BlockCount = + NextBufferHeader->b_size >> DAC960_BlockSizeBits; + Command->BufferHeader = NextBufferHeader; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = + Virtual_to_Bus(NextBufferHeader->b_data); + DAC960_QueueCommand(Command); + return; + } + } + else if (CommandType == DAC960_MonitoringCommand || + CommandOpcode == DAC960_Enquiry || + CommandOpcode == DAC960_GetRebuildProgress) + { + if (CommandType != DAC960_MonitoringCommand) + { + if (CommandOpcode == DAC960_Enquiry) + memcpy(&Controller->Enquiry[Controller->EnquiryIndex ^ 1], + Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress), + sizeof(DAC960_Enquiry_T)); + else if (CommandOpcode == DAC960_GetRebuildProgress) + memcpy(&Controller->RebuildProgress, + Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress), + sizeof(DAC960_RebuildProgress_T)); + } + if (CommandOpcode == DAC960_Enquiry) + { + DAC960_Enquiry_T *OldEnquiry = + &Controller->Enquiry[Controller->EnquiryIndex]; + DAC960_Enquiry_T *NewEnquiry = + &Controller->Enquiry[Controller->EnquiryIndex ^= 1]; + unsigned int OldCriticalLogicalDriveCount = + OldEnquiry->CriticalLogicalDriveCount; + unsigned int NewCriticalLogicalDriveCount = + NewEnquiry->CriticalLogicalDriveCount; + if (NewEnquiry->StatusFlags.DeferredWriteError != + OldEnquiry->StatusFlags.DeferredWriteError) + DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller, + (NewEnquiry->StatusFlags.DeferredWriteError + ? "TRUE" : "FALSE")); + if ((NewCriticalLogicalDriveCount > 0 || + NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) || + (NewEnquiry->OfflineLogicalDriveCount > 0 || + NewEnquiry->OfflineLogicalDriveCount != + OldEnquiry->OfflineLogicalDriveCount) || + (NewEnquiry->DeadDriveCount > 0 || + NewEnquiry->DeadDriveCount != + OldEnquiry->DeadDriveCount) || + (NewEnquiry->EventLogSequenceNumber != + OldEnquiry->EventLogSequenceNumber) || + Controller->MonitoringTimerCount == 0 || + (jiffies - Controller->SecondaryMonitoringTime + >= DAC960_SecondaryMonitoringInterval)) + { + Controller->NeedLogicalDriveInformation = true; + Controller->NewEventLogSequenceNumber = + NewEnquiry->EventLogSequenceNumber; + Controller->NeedErrorTableInformation = true; + Controller->NeedDeviceStateInformation = true; + Controller->DeviceStateChannel = 0; + Controller->DeviceStateTargetID = -1; + Controller->SecondaryMonitoringTime = jiffies; + } + if (NewEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress || + NewEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress || + OldEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress || + OldEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress) + Controller->NeedRebuildProgress = true; + if (OldEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress) + switch (NewEnquiry->RebuildFlag) + { + case DAC960_NoStandbyRebuildOrCheckInProgress: + DAC960_Progress("Consistency Check Completed Successfully\n", + Controller); + break; + case DAC960_StandbyRebuildInProgress: + case DAC960_BackgroundRebuildInProgress: + break; + case DAC960_BackgroundCheckInProgress: + Controller->NeedConsistencyCheckProgress = true; + break; + case DAC960_StandbyRebuildCompletedWithError: + DAC960_Progress("Consistency Check Completed with Error\n", + Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_DriveFailed: + DAC960_Progress("Consistency Check Failed - " + "Physical Drive Failed\n", Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed: + DAC960_Progress("Consistency Check Failed - " + "Logical Drive Failed\n", Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_OtherCauses: + DAC960_Progress("Consistency Check Failed - Other Causes\n", + Controller); + break; + case DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated: + DAC960_Progress("Consistency Check Successfully Terminated\n", + Controller); + break; + } + else if (NewEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress) + Controller->NeedConsistencyCheckProgress = true; + } + else if (CommandOpcode == DAC960_PerformEventLogOperation) + { + static char + *DAC960_EventMessages[] = + { "killed because write recovery failed", + "killed because of SCSI bus reset failure", + "killed because of double check condition", + "killed because it was removed", + "killed because of gross error on SCSI chip", + "killed because of bad tag returned from drive", + "killed because of timeout on SCSI command", + "killed because of reset SCSI command issued from system", + "killed because busy or parity error count exceeded limit", + "killed because of 'kill drive' command from system", + "killed because of selection timeout", + "killed due to SCSI phase sequence error", + "killed due to unknown status" }; + DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry; + if (EventLogEntry->SequenceNumber == + Controller->OldEventLogSequenceNumber) + { + unsigned char SenseKey = EventLogEntry->SenseKey; + unsigned char AdditionalSenseCode = + EventLogEntry->AdditionalSenseCode; + unsigned char AdditionalSenseCodeQualifier = + EventLogEntry->AdditionalSenseCodeQualifier; + if (SenseKey == 9 && + AdditionalSenseCode == 0x80 && + AdditionalSenseCodeQualifier < + sizeof(DAC960_EventMessages) / sizeof(char *)) + DAC960_Critical("Physical Drive %d:%d %s\n", Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + DAC960_EventMessages[ + AdditionalSenseCodeQualifier]); + else if (SenseKey == 6 && AdditionalSenseCode == 0x29) + { + if (Controller->MonitoringTimerCount > 0) + Controller->DeviceResetCount[EventLogEntry->Channel] + [EventLogEntry->TargetID]++; + } + else if (!(SenseKey == 0 || + (SenseKey == 2 && + AdditionalSenseCode == 0x04 && + (AdditionalSenseCodeQualifier == 0x01 || + AdditionalSenseCodeQualifier == 0x02)))) + { + DAC960_Critical("Physical Drive %d:%d Error Log: " + "Sense Key = %d, ASC = %02X, ASCQ = %02X\n", + Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + SenseKey, + AdditionalSenseCode, + AdditionalSenseCodeQualifier); + DAC960_Critical("Physical Drive %d:%d Error Log: " + "Information = %02X%02X%02X%02X " + "%02X%02X%02X%02X\n", + Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + EventLogEntry->Information[0], + EventLogEntry->Information[1], + EventLogEntry->Information[2], + EventLogEntry->Information[3], + EventLogEntry->CommandSpecificInformation[0], + EventLogEntry->CommandSpecificInformation[1], + EventLogEntry->CommandSpecificInformation[2], + EventLogEntry->CommandSpecificInformation[3]); + } + } + Controller->OldEventLogSequenceNumber++; + } + else if (CommandOpcode == DAC960_GetErrorTable) + { + DAC960_ErrorTable_T *OldErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex]; + DAC960_ErrorTable_T *NewErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex ^= 1]; + int Channel, TargetID; + for (Channel = 0; Channel < Controller->Channels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + DAC960_ErrorTableEntry_T *NewErrorEntry = + &NewErrorTable->ErrorTableEntries[Channel][TargetID]; + DAC960_ErrorTableEntry_T *OldErrorEntry = + &OldErrorTable->ErrorTableEntries[Channel][TargetID]; + if ((NewErrorEntry->ParityErrorCount != + OldErrorEntry->ParityErrorCount) || + (NewErrorEntry->SoftErrorCount != + OldErrorEntry->SoftErrorCount) || + (NewErrorEntry->HardErrorCount != + OldErrorEntry->HardErrorCount) || + (NewErrorEntry->MiscErrorCount != + OldErrorEntry->MiscErrorCount)) + DAC960_Critical("Physical Drive %d:%d Errors: " + "Parity = %d, Soft = %d, " + "Hard = %d, Misc = %d\n", + Controller, Channel, TargetID, + NewErrorEntry->ParityErrorCount, + NewErrorEntry->SoftErrorCount, + NewErrorEntry->HardErrorCount, + NewErrorEntry->MiscErrorCount); + } + } + else if (CommandOpcode == DAC960_GetDeviceState) + { + DAC960_DeviceState_T *OldDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + DAC960_DeviceState_T *NewDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex ^ 1] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + if (NewDeviceState->DeviceState != OldDeviceState->DeviceState) + DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller, + Controller->DeviceStateChannel, + Controller->DeviceStateTargetID, + (NewDeviceState->DeviceState == DAC960_Device_Dead + ? "DEAD" + : NewDeviceState->DeviceState + == DAC960_Device_WriteOnly + ? "WRITE-ONLY" + : NewDeviceState->DeviceState + == DAC960_Device_Online + ? "ONLINE" : "STANDBY")); + if (OldDeviceState->DeviceState == DAC960_Device_Dead && + NewDeviceState->DeviceState != DAC960_Device_Dead) + { + Controller->NeedDeviceInquiryInformation = true; + Controller->NeedDeviceSerialNumberInformation = true; + } + } + else if (CommandOpcode == DAC960_GetLogicalDriveInformation) + { + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + { + DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber]; + DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex ^ 1] + [LogicalDriveNumber]; + if (NewLogicalDriveInformation->LogicalDriveState != + OldLogicalDriveInformation->LogicalDriveState) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "is now %s\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (NewLogicalDriveInformation->LogicalDriveState + == DAC960_LogicalDrive_Online + ? "ONLINE" + : NewLogicalDriveInformation->LogicalDriveState + == DAC960_LogicalDrive_Critical + ? "CRITICAL" : "OFFLINE")); + if (NewLogicalDriveInformation->WriteBack != + OldLogicalDriveInformation->WriteBack) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "is now %s\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (NewLogicalDriveInformation->WriteBack + ? "WRITE BACK" : "WRITE THRU")); + } + Controller->LogicalDriveInformationIndex ^= 1; + } + else if (CommandOpcode == DAC960_GetRebuildProgress) + { + unsigned int LogicalDriveNumber = + Controller->RebuildProgress.LogicalDriveNumber; + unsigned int LogicalDriveSize = + Controller->RebuildProgress.LogicalDriveSize; + unsigned int BlocksCompleted = + LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks; + switch (CommandStatus) + { + case DAC960_NormalCompletion: + Controller->EphemeralProgressMessage = true; + DAC960_Progress("Rebuild in Progress: " + "Logical Drive %d (/dev/rd/c%dd%d) " + "%d%% completed\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (100 * (BlocksCompleted >> 7)) + / (LogicalDriveSize >> 7)); + Controller->EphemeralProgressMessage = false; + break; + case DAC960_RebuildFailed_LogicalDriveFailure: + DAC960_Progress("Rebuild Failed due to " + "Logical Drive Failure\n", Controller); + break; + case DAC960_RebuildFailed_BadBlocksOnOther: + DAC960_Progress("Rebuild Failed due to " + "Bad Blocks on Other Drives\n", Controller); + break; + case DAC960_RebuildFailed_NewDriveFailed: + DAC960_Progress("Rebuild Failed due to " + "Failure of Drive Being Rebuilt\n", Controller); + break; + case DAC960_NoRebuildOrCheckInProgress: + if (Controller->LastRebuildStatus != DAC960_NormalCompletion) + break; + case DAC960_RebuildSuccessful: + DAC960_Progress("Rebuild Completed Successfully\n", Controller); + break; + } + Controller->LastRebuildStatus = CommandStatus; + } + else if (CommandOpcode == DAC960_RebuildStat) + { + unsigned int LogicalDriveNumber = + Controller->RebuildProgress.LogicalDriveNumber; + unsigned int LogicalDriveSize = + Controller->RebuildProgress.LogicalDriveSize; + unsigned int BlocksCompleted = + LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks; + if (CommandStatus == DAC960_NormalCompletion) + { + Controller->EphemeralProgressMessage = true; + DAC960_Progress("Consistency Check in Progress: " + "Logical Drive %d (/dev/rd/c%dd%d) " + "%d%% completed\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (100 * (BlocksCompleted >> 7)) + / (LogicalDriveSize >> 7)); + Controller->EphemeralProgressMessage = false; + } + } + } + if (CommandType == DAC960_MonitoringCommand) + { + if (Controller->NewEventLogSequenceNumber + - Controller->OldEventLogSequenceNumber > 0) + { + Command->CommandMailbox.Type3E.CommandOpcode = + DAC960_PerformEventLogOperation; + Command->CommandMailbox.Type3E.OperationType = + DAC960_GetEventLogEntry; + Command->CommandMailbox.Type3E.OperationQualifier = 1; + Command->CommandMailbox.Type3E.SequenceNumber = + Controller->OldEventLogSequenceNumber; + Command->CommandMailbox.Type3E.BusAddress = + Virtual_to_Bus(&Controller->EventLogEntry); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedErrorTableInformation) + { + Controller->NeedErrorTableInformation = false; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_GetErrorTable; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus( + &Controller->ErrorTable[Controller->ErrorTableIndex ^ 1]); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedRebuildProgress && + Controller->Enquiry[Controller->EnquiryIndex] + .CriticalLogicalDriveCount < + Controller->Enquiry[Controller->EnquiryIndex ^ 1] + .CriticalLogicalDriveCount) + { + Controller->NeedRebuildProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetRebuildProgress; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedDeviceStateInformation) + { + if (Controller->NeedDeviceInquiryInformation) + { + DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB; + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->InquiryStandardData + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + InquiryStandardData->PeripheralDeviceType = 0x1F; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB; + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + DCDB->Channel = Controller->DeviceStateChannel; + DCDB->TargetID = Controller->DeviceStateTargetID; + DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem; + DCDB->EarlyStatus = false; + DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds; + DCDB->NoAutomaticRequestSense = false; + DCDB->DisconnectPermitted = true; + DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData); + DCDB->CDBLength = 6; + DCDB->TransferLengthHigh4 = 0; + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 0; /* EVPD = 0 */ + DCDB->CDB[2] = 0; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_QueueCommand(Command); + Controller->NeedDeviceInquiryInformation = false; + return; + } + if (Controller->NeedDeviceSerialNumberInformation) + { + DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + &Controller->InquiryUnitSerialNumber + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB; + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + DCDB->Channel = Controller->DeviceStateChannel; + DCDB->TargetID = Controller->DeviceStateTargetID; + DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem; + DCDB->EarlyStatus = false; + DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds; + DCDB->NoAutomaticRequestSense = false; + DCDB->DisconnectPermitted = true; + DCDB->TransferLength = + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber); + DCDB->CDBLength = 6; + DCDB->TransferLengthHigh4 = 0; + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 1; /* EVPD = 1 */ + DCDB->CDB[2] = 0x80; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_QueueCommand(Command); + Controller->NeedDeviceSerialNumberInformation = false; + return; + } + if (++Controller->DeviceStateTargetID == DAC960_MaxTargets) + { + Controller->DeviceStateChannel++; + Controller->DeviceStateTargetID = 0; + } + while (Controller->DeviceStateChannel < Controller->Channels) + { + DAC960_DeviceState_T *OldDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + if (OldDeviceState->Present && + OldDeviceState->DeviceType == DAC960_DiskType) + { + Command->CommandMailbox.Type3D.CommandOpcode = + DAC960_GetDeviceState; + Command->CommandMailbox.Type3D.Channel = + Controller->DeviceStateChannel; + Command->CommandMailbox.Type3D.TargetID = + Controller->DeviceStateTargetID; + Command->CommandMailbox.Type3D.BusAddress = + Virtual_to_Bus(&Controller->DeviceState + [Controller->DeviceStateIndex ^ 1] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]); + DAC960_QueueCommand(Command); + return; + } + if (++Controller->DeviceStateTargetID == DAC960_MaxTargets) + { + Controller->DeviceStateChannel++; + Controller->DeviceStateTargetID = 0; + } + } + Controller->NeedDeviceStateInformation = false; + Controller->DeviceStateIndex ^= 1; + } + if (Controller->NeedLogicalDriveInformation) + { + Controller->NeedLogicalDriveInformation = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetLogicalDriveInformation; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus( + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex ^ 1]); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedRebuildProgress) + { + Controller->NeedRebuildProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetRebuildProgress; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedConsistencyCheckProgress) + { + Controller->NeedConsistencyCheckProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_RebuildStat; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + Controller->MonitoringTimerCount++; + Controller->MonitoringTimer.expires = + jiffies + DAC960_MonitoringTimerInterval; + add_timer(&Controller->MonitoringTimer); + } + if (CommandType == DAC960_ImmediateCommand) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + return; + } + if (CommandType == DAC960_QueuedCommand) + { + DAC960_KernelCommand_T *KernelCommand = Command->KernelCommand; + KernelCommand->CommandStatus = CommandStatus; + Command->KernelCommand = NULL; + if (CommandOpcode == DAC960_DCDB) + Controller->DirectCommandActive[KernelCommand->DCDB->Channel] + [KernelCommand->DCDB->TargetID] = false; + DAC960_DeallocateCommand(Command); + KernelCommand->CompletionFunction(KernelCommand); + return; + } + /* + Queue a Status Monitoring Command to the Controller using the just + completed Command if one was deferred previously due to lack of a + free Command when the Monitoring Timer Function was called. + */ + if (Controller->MonitoringCommandDeferred) + { + Controller->MonitoringCommandDeferred = false; + DAC960_QueueMonitoringCommand(Command); + return; + } + /* + Deallocate the Command, and wake up any processes waiting on a free Command. + */ + DAC960_DeallocateCommand(Command); + wake_up(&Controller->CommandWaitQueue); +} + + +/* + DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers. +*/ + +static void DAC960_InterruptHandler(int IRQ_Channel, + void *DeviceIdentifier, + Registers_T *InterruptRegisters) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_StatusMailbox_T *NextStatusMailbox; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags); + /* + Process Hardware Interrupts for Controller. + */ + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + DAC960_V5_AcknowledgeInterrupt(ControllerBaseAddress); + NextStatusMailbox = Controller->NextStatusMailbox; + while (NextStatusMailbox->Fields.Valid) + { + DAC960_CommandIdentifier_T CommandIdentifier = + NextStatusMailbox->Fields.CommandIdentifier; + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus; + NextStatusMailbox->Word = 0; + if (++NextStatusMailbox > Controller->LastStatusMailbox) + NextStatusMailbox = Controller->FirstStatusMailbox; + DAC960_ProcessCompletedCommand(Command); + } + Controller->NextStatusMailbox = NextStatusMailbox; + break; + case DAC960_V4_Controller: + DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress); + NextStatusMailbox = Controller->NextStatusMailbox; + while (NextStatusMailbox->Fields.Valid) + { + DAC960_CommandIdentifier_T CommandIdentifier = + NextStatusMailbox->Fields.CommandIdentifier; + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus; + NextStatusMailbox->Word = 0; + if (++NextStatusMailbox > Controller->LastStatusMailbox) + NextStatusMailbox = Controller->FirstStatusMailbox; + DAC960_ProcessCompletedCommand(Command); + } + Controller->NextStatusMailbox = NextStatusMailbox; + break; + case DAC960_V3_Controller: + while (DAC960_V3_StatusAvailableP(ControllerBaseAddress)) + { + DAC960_CommandIdentifier_T CommandIdentifier = + DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress); + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = + DAC960_V3_ReadStatusRegister(ControllerBaseAddress); + DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress); + DAC960_V3_AcknowledgeStatus(ControllerBaseAddress); + DAC960_ProcessCompletedCommand(Command); + } + break; + } + /* + Attempt to remove additional I/O Requests from the Controller's + I/O Request Queue and queue them to the Controller. + */ + while (DAC960_ProcessRequest(Controller, false)) ; + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags); +} + + +/* + DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller. +*/ + +static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_MonitoringCommand; + CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry; + CommandMailbox->Type3.BusAddress = + Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]); + DAC960_QueueCommand(Command); +} + + +/* + DAC960_MonitoringTimerFunction is the timer function for monitoring + the status of DAC960 Controllers. +*/ + +static void DAC960_MonitoringTimerFunction(unsigned long TimerData) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData; + DAC960_Command_T *Command; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + /* + Queue a Status Monitoring Command to Controller. + */ + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) + DAC960_QueueMonitoringCommand(Command); + else Controller->MonitoringCommandDeferred = true; + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); +} + + +/* + DAC960_Open is the Device Open Function for the DAC960 Driver. +*/ + +static int DAC960_Open(Inode_T *Inode, File_T *File) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DAC960_Controller_T *Controller; + if (ControllerNumber == 0 && LogicalDriveNumber == 0 && + (File->f_flags & O_NONBLOCK)) + goto ModuleOnly; + if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL || + LogicalDriveNumber > Controller->LogicalDriveCount - 1) + return -ENXIO; + if (Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber].LogicalDriveState + == DAC960_LogicalDrive_Offline) + return -ENXIO; + if (Controller->LogicalDriveInitialState[LogicalDriveNumber] + == DAC960_LogicalDrive_Offline) + { + Controller->LogicalDriveInitialState[LogicalDriveNumber] = + DAC960_LogicalDrive_Online; + DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + } + if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0) + return -ENXIO; + /* + Increment Controller and Logical Drive Usage Counts. + */ + Controller->ControllerUsageCount++; + Controller->LogicalDriveUsageCount[LogicalDriveNumber]++; + ModuleOnly: + MOD_INC_USE_COUNT; + return 0; +} + + +/* + DAC960_Release is the Device Release Function for the DAC960 Driver. +*/ + +static int DAC960_Release(Inode_T *Inode, File_T *File) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + if (ControllerNumber == 0 && LogicalDriveNumber == 0 && + File != NULL && (File->f_flags & O_NONBLOCK)) + goto ModuleOnly; + /* + Force any buffered data to be written. + */ + fsync_dev(Inode->i_rdev); + /* + Decrement the Logical Drive and Controller Usage Counts. + */ + Controller->LogicalDriveUsageCount[LogicalDriveNumber]--; + Controller->ControllerUsageCount--; + ModuleOnly: + MOD_DEC_USE_COUNT; + return 0; +} + + +/* + DAC960_IOCTL is the Device IOCTL Function for the DAC960 Driver. +*/ + +static int DAC960_IOCTL(Inode_T *Inode, File_T *File, + unsigned int Request, unsigned long Argument) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DiskGeometry_T Geometry, *UserGeometry; + DAC960_Controller_T *Controller; + int PartitionNumber; + if (File->f_flags & O_NONBLOCK) + return DAC960_UserIOCTL(Inode, File, Request, Argument); + if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL || + LogicalDriveNumber > Controller->LogicalDriveCount - 1) + return -ENXIO; + switch (Request) + { + case HDIO_GETGEO: + /* Get BIOS Disk Geometry. */ + UserGeometry = (DiskGeometry_T *) Argument; + if (UserGeometry == NULL) return -EINVAL; + Geometry.heads = Controller->GeometryTranslationHeads; + Geometry.sectors = Controller->GeometryTranslationSectors; + Geometry.cylinders = + Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber].LogicalDriveSize + / (Controller->GeometryTranslationHeads * + Controller->GeometryTranslationSectors); + Geometry.start = Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)] + .start_sect; + return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T)); + case BLKGETSIZE: + /* Get Device Size. */ + if ((long *) Argument == NULL) return -EINVAL; + return put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)] + .nr_sects, + (long *) Argument); + case BLKRAGET: + /* Get Read-Ahead. */ + if ((int *) Argument == NULL) return -EINVAL; + return put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument); + case BLKRASET: + /* Set Read-Ahead. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (Argument > 256) return -EINVAL; + read_ahead[MAJOR(Inode->i_rdev)] = Argument; + return 0; + case BLKFLSBUF: + /* Flush Buffers. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + fsync_dev(Inode->i_rdev); + invalidate_buffers(Inode->i_rdev); + return 0; + case BLKRRPART: + /* Re-Read Partition Table. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1) + return -EBUSY; + for (PartitionNumber = 0; + PartitionNumber < DAC960_MaxPartitions; + PartitionNumber++) + { + KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber, + LogicalDriveNumber, + PartitionNumber); + int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, + PartitionNumber); + SuperBlock_T *SuperBlock = get_super(Device); + if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0) + continue; + /* + Flush all changes and invalidate buffered state. + */ + sync_dev(Device); + if (SuperBlock != NULL) + invalidate_inodes(SuperBlock); + invalidate_buffers(Device); + /* + Clear existing partition sizes. + */ + if (PartitionNumber > 0) + { + Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0; + Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0; + } + /* + Reset the Block Size so that the partition table can be read. + */ + set_blocksize(Device, BLOCK_SIZE); + } + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + return 0; + } + return -EINVAL; +} + + +/* + DAC960_UserIOCTL is the User IOCTL Function for the DAC960 Driver. +*/ + +static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File, + unsigned int Request, unsigned long Argument) +{ + int ErrorCode; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + switch (Request) + { + case DAC960_IOCTL_GET_CONTROLLER_COUNT: + return DAC960_ControllerCount; + case DAC960_IOCTL_GET_CONTROLLER_INFO: + { + DAC960_ControllerInfo_T *UserSpaceControllerInfo = + (DAC960_ControllerInfo_T *) Argument; + DAC960_ControllerInfo_T ControllerInfo; + DAC960_Controller_T *Controller; + int ControllerNumber; + if (UserSpaceControllerInfo == NULL) return -EINVAL; + ErrorCode = get_user(ControllerNumber, + &UserSpaceControllerInfo->ControllerNumber); + if (ErrorCode != 0) return ErrorCode; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); + ControllerInfo.ControllerNumber = ControllerNumber; + ControllerInfo.PCI_Bus = Controller->Bus; + ControllerInfo.PCI_Device = Controller->Device; + ControllerInfo.PCI_Function = Controller->Function; + ControllerInfo.IRQ_Channel = Controller->IRQ_Channel; + ControllerInfo.Channels = Controller->Channels; + ControllerInfo.PCI_Address = Controller->PCI_Address; + strcpy(ControllerInfo.ModelName, Controller->ModelName); + strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); + return copy_to_user(UserSpaceControllerInfo, &ControllerInfo, + sizeof(DAC960_ControllerInfo_T)); + } + case DAC960_IOCTL_EXECUTE_COMMAND: + { + DAC960_UserCommand_T *UserSpaceUserCommand = + (DAC960_UserCommand_T *) Argument; + DAC960_UserCommand_T UserCommand; + DAC960_Controller_T *Controller; + DAC960_Command_T *Command = NULL; + DAC960_CommandOpcode_T CommandOpcode; + DAC960_CommandStatus_T CommandStatus; + DAC960_DCDB_T DCDB; + ProcessorFlags_T ProcessorFlags; + int ControllerNumber, DataTransferLength; + unsigned char *DataTransferBuffer = NULL; + if (UserSpaceUserCommand == NULL) return -EINVAL; + ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand, + sizeof(DAC960_UserCommand_T)); + if (ErrorCode != 0) goto Failure; + ControllerNumber = UserCommand.ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; + DataTransferLength = UserCommand.DataTransferLength; + if (CommandOpcode & 0x80) return -EINVAL; + if (CommandOpcode == DAC960_DCDB) + { + ErrorCode = + copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_DCDB_T)); + if (ErrorCode != 0) goto Failure; + if (!((DataTransferLength == 0 && + DCDB.Direction == DAC960_DCDB_NoDataTransfer) || + (DataTransferLength > 0 && + DCDB.Direction == DAC960_DCDB_DataTransferDeviceToSystem) || + (DataTransferLength < 0 && + DCDB.Direction == DAC960_DCDB_DataTransferSystemToDevice))) + return -EINVAL; + if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) + != abs(DataTransferLength)) + return -EINVAL; + } + if (DataTransferLength > 0) + { + DataTransferBuffer = kmalloc(DataTransferLength, GFP_KERNEL); + if (DataTransferBuffer == NULL) return -ENOMEM; + memset(DataTransferBuffer, 0, DataTransferLength); + } + else if (DataTransferLength < 0) + { + DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL); + if (DataTransferBuffer == NULL) return -ENOMEM; + ErrorCode = copy_from_user(DataTransferBuffer, + UserCommand.DataTransferBuffer, + -DataTransferLength); + if (ErrorCode != 0) goto Failure; + } + if (CommandOpcode == DAC960_DCDB) + { + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + if (!Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID]) + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) + Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID] = true; + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(&DCDB); + DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer); + } + else + { + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + if (DataTransferBuffer != NULL) + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(DataTransferBuffer); + } + DAC960_ExecuteCommand(Command); + CommandStatus = Command->CommandStatus; + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_DeallocateCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (CommandStatus == DAC960_NormalCompletion && + DataTransferLength > 0) + { + ErrorCode = copy_to_user(UserCommand.DataTransferBuffer, + DataTransferBuffer, DataTransferLength); + if (ErrorCode != 0) goto Failure; + } + if (CommandOpcode == DAC960_DCDB) + { + Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID] = false; + ErrorCode = + copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_DCDB_T)); + if (ErrorCode != 0) goto Failure; + } + ErrorCode = CommandStatus; + Failure: + if (DataTransferBuffer != NULL) + kfree(DataTransferBuffer); + return ErrorCode; + } + } + return -EINVAL; +} + + +/* + DAC960_KernelIOCTL is the Kernel IOCTL Function for the DAC960 Driver. +*/ + +int DAC960_KernelIOCTL(unsigned int Request, void *Argument) +{ + switch (Request) + { + case DAC960_IOCTL_GET_CONTROLLER_COUNT: + return DAC960_ControllerCount; + case DAC960_IOCTL_GET_CONTROLLER_INFO: + { + DAC960_ControllerInfo_T *ControllerInfo = + (DAC960_ControllerInfo_T *) Argument; + DAC960_Controller_T *Controller; + int ControllerNumber; + if (ControllerInfo == NULL) return -EINVAL; + ControllerNumber = ControllerInfo->ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + memset(ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); + ControllerInfo->ControllerNumber = ControllerNumber; + ControllerInfo->PCI_Bus = Controller->Bus; + ControllerInfo->PCI_Device = Controller->Device; + ControllerInfo->PCI_Function = Controller->Function; + ControllerInfo->IRQ_Channel = Controller->IRQ_Channel; + ControllerInfo->Channels = Controller->Channels; + ControllerInfo->PCI_Address = Controller->PCI_Address; + strcpy(ControllerInfo->ModelName, Controller->ModelName); + strcpy(ControllerInfo->FirmwareVersion, Controller->FirmwareVersion); + return 0; + } + case DAC960_IOCTL_EXECUTE_COMMAND: + { + DAC960_KernelCommand_T *KernelCommand = + (DAC960_KernelCommand_T *) Argument; + DAC960_Controller_T *Controller; + DAC960_Command_T *Command = NULL; + DAC960_CommandOpcode_T CommandOpcode; + DAC960_DCDB_T *DCDB = NULL; + ProcessorFlags_T ProcessorFlags; + int ControllerNumber, DataTransferLength; + unsigned char *DataTransferBuffer = NULL; + if (KernelCommand == NULL) return -EINVAL; + ControllerNumber = KernelCommand->ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + CommandOpcode = KernelCommand->CommandMailbox.Common.CommandOpcode; + DataTransferLength = KernelCommand->DataTransferLength; + DataTransferBuffer = KernelCommand->DataTransferBuffer; + if (CommandOpcode & 0x80) return -EINVAL; + if (CommandOpcode == DAC960_DCDB) + { + DCDB = KernelCommand->DCDB; + if (!((DataTransferLength == 0 && + DCDB->Direction == DAC960_DCDB_NoDataTransfer) || + (DataTransferLength > 0 && + DCDB->Direction == DAC960_DCDB_DataTransferDeviceToSystem) || + (DataTransferLength < 0 && + DCDB->Direction == DAC960_DCDB_DataTransferSystemToDevice))) + return -EINVAL; + if (((DCDB->TransferLengthHigh4 << 16) | DCDB->TransferLength) + != abs(DataTransferLength)) + return -EINVAL; + } + if (DataTransferLength != 0 && DataTransferBuffer == NULL) + return -EINVAL; + if (DataTransferLength > 0) + memset(DataTransferBuffer, 0, DataTransferLength); + if (CommandOpcode == DAC960_DCDB) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + if (!Controller->DirectCommandActive[DCDB->Channel] + [DCDB->TargetID]) + Command = DAC960_AllocateCommand(Controller); + if (Command == NULL) + { + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return -EBUSY; + } + else Controller->DirectCommandActive[DCDB->Channel] + [DCDB->TargetID] = true; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_QueuedCommand; + memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + Command->KernelCommand = KernelCommand; + DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + else + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + if (Command == NULL) + { + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return -EBUSY; + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_QueuedCommand; + memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + if (DataTransferBuffer != NULL) + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(DataTransferBuffer); + Command->KernelCommand = KernelCommand; + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + return 0; + } + } + return -EINVAL; +} + + +/* + DAC960_GenericDiskInit is the Generic Disk Information Initialization + Function for the DAC960 Driver. +*/ + +static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo) +{ + DAC960_Controller_T *Controller = + (DAC960_Controller_T *) GenericDiskInfo->real_devices; + DAC960_LogicalDriveInformation_T *LogicalDriveInformation = + Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex]; + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects = + LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize; +} + + +/* + DAC960_Message prints Driver Messages. +*/ + +static void DAC960_Message(DAC960_MessageLevel_T MessageLevel, + char *Format, + DAC960_Controller_T *Controller, + ...) +{ + static char Buffer[DAC960_LineBufferSize]; + static boolean BeginningOfLine = true; + va_list Arguments; + int Length = 0; + va_start(Arguments, Controller); + Length = vsprintf(Buffer, Format, Arguments); + va_end(Arguments); + if (Controller == NULL) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + DAC960_ControllerCount, Buffer); + else if (MessageLevel == DAC960_AnnounceLevel || + MessageLevel == DAC960_InfoLevel) + { + if (!Controller->ControllerInitialized) + { + strcpy(&Controller->InitialStatusBuffer[ + Controller->InitialStatusLength], Buffer); + Controller->InitialStatusLength += Length; + if (MessageLevel == DAC960_AnnounceLevel) + { + static int AnnouncementLines = 0; + if (++AnnouncementLines <= 2) + printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], + Buffer); + } + else + { + if (BeginningOfLine) + { + if (Buffer[0] != '\n' || Length > 1) + printk("%sDAC960#%d: %s", + DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else printk("%s", Buffer); + } + } + else + { + strcpy(&Controller->CurrentStatusBuffer[ + Controller->CurrentStatusLength], Buffer); + Controller->CurrentStatusLength += Length; + } + } + else if (MessageLevel == DAC960_ProgressLevel) + { + strcpy(Controller->RebuildProgressBuffer, Buffer); + Controller->RebuildProgressLength = Length; + if (Controller->EphemeralProgressMessage) + { + if (jiffies - Controller->LastProgressReportTime + >= DAC960_ProgressReportingInterval) + { + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + Controller->LastProgressReportTime = jiffies; + } + } + else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else if (MessageLevel == DAC960_UserCriticalLevel) + { + strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength], + Buffer); + Controller->UserStatusLength += Length; + if (Buffer[0] != '\n' || Length > 1) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else + { + if (BeginningOfLine) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + else printk("%s", Buffer); + } + BeginningOfLine = (Buffer[Length-1] == '\n'); +} + + +/* + DAC960_ParsePhysicalDrive parses spaces followed by a Physical Drive + Channel:TargetID specification from a User Command string. It updates + Channel and TargetID and returns true on success and returns false otherwise. +*/ + +static boolean DAC960_ParsePhysicalDrive(DAC960_Controller_T *Controller, + char *UserCommandString, + unsigned char *Channel, + unsigned char *TargetID) +{ + char *NewUserCommandString = UserCommandString; + unsigned long XChannel, XTargetID; + while (*UserCommandString == ' ') UserCommandString++; + if (UserCommandString == NewUserCommandString) + return false; + XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != ':' || + XChannel >= Controller->Channels) + return false; + UserCommandString = ++NewUserCommandString; + XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != '\0' || + XTargetID >= DAC960_MaxTargets) + return false; + *Channel = XChannel; + *TargetID = XTargetID; + return true; +} + + +/* + DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number + specification from a User Command string. It updates LogicalDriveNumber and + returns true on success and returns false otherwise. +*/ + +static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller, + char *UserCommandString, + unsigned char *LogicalDriveNumber) +{ + char *NewUserCommandString = UserCommandString; + unsigned long XLogicalDriveNumber; + while (*UserCommandString == ' ') UserCommandString++; + if (UserCommandString == NewUserCommandString) + return false; + XLogicalDriveNumber = + simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != '\0' || + XLogicalDriveNumber >= Controller->LogicalDriveCount) + return false; + *LogicalDriveNumber = XLogicalDriveNumber; + return true; +} + + +/* + DAC960_SetDeviceState sets the Device State for a Physical Drive. +*/ + +static void DAC960_SetDeviceState(DAC960_Controller_T *Controller, + DAC960_Command_T *Command, + unsigned char Channel, + unsigned char TargetID, + DAC960_PhysicalDeviceState_T DeviceState, + const char *DeviceStateString) +{ + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + CommandMailbox->Type3D.CommandOpcode = DAC960_StartDevice; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + CommandMailbox->Type3D.DeviceState = DeviceState; + CommandMailbox->Type3D.Modifier = 0; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("%s of Physical Drive %d:%d Succeeded\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_UnableToStartDevice: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Unable to Start Device\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_NoDeviceAtAddress: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "No Device at Address\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_InvalidChannelOrTargetOrModifier: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Invalid Channel or Target or Modifier\n", + Controller, DeviceStateString, Channel, TargetID); + break; + case DAC960_ChannelBusy: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Channel Busy\n", Controller, + DeviceStateString, Channel, TargetID); + break; + default: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Unexpected Status %04X\n", Controller, + DeviceStateString, Channel, TargetID, + Command->CommandStatus); + break; + } +} + + +/* + DAC960_ExecuteUserCommand executes a User Command. +*/ + +static boolean DAC960_ExecuteUserCommand(DAC960_Controller_T *Controller, + char *UserCommand) +{ + DAC960_Command_T *Command; + DAC960_CommandMailbox_T *CommandMailbox; + ProcessorFlags_T ProcessorFlags; + unsigned char Channel, TargetID, LogicalDriveNumber; + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + Controller->UserStatusLength = 0; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox = &Command->CommandMailbox; + if (strcmp(UserCommand, "flush-cache") == 0) + { + CommandMailbox->Type3.CommandOpcode = DAC960_Flush; + DAC960_ExecuteCommand(Command); + DAC960_UserCritical("Cache Flush Completed\n", Controller); + } + else if (strncmp(UserCommand, "kill", 4) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[4], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState != DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Dead, "Kill"); + else DAC960_UserCritical("Kill of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + } + else if (strncmp(UserCommand, "make-online", 11) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[11], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState == DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Online, "Make Online"); + else DAC960_UserCritical("Make Online of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + + } + else if (strncmp(UserCommand, "make-standby", 12) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[12], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState == DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Standby, "Make Standby"); + else DAC960_UserCritical("Make Standby of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + } + else if (strncmp(UserCommand, "rebuild", 7) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[7], + &Channel, &TargetID)) + { + CommandMailbox->Type3D.CommandOpcode = DAC960_RebuildAsync; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Initiated\n", + Controller, Channel, TargetID); + break; + case DAC960_AttemptToRebuildOnlineDrive: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Attempt to Rebuild Online or " + "Unresponsive Drive\n", + Controller, Channel, TargetID); + break; + case DAC960_NewDiskFailedDuringRebuild: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "New Disk Failed During Rebuild\n", + Controller, Channel, TargetID); + break; + case DAC960_InvalidDeviceAddress: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Invalid Device Address\n", + Controller, Channel, TargetID); + break; + case DAC960_RebuildOrCheckAlreadyInProgress: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Rebuild or Consistency Check Already " + "in Progress\n", Controller, Channel, TargetID); + break; + default: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Unexpected Status %04X\n", Controller, + Channel, TargetID, Command->CommandStatus); + break; + } + } + else if (strncmp(UserCommand, "check-consistency", 17) == 0 && + DAC960_ParseLogicalDrive(Controller, &UserCommand[17], + &LogicalDriveNumber)) + { + CommandMailbox->Type3C.CommandOpcode = DAC960_CheckConsistencyAsync; + CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber; + CommandMailbox->Type3C.AutoRestore = true; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Initiated\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_DependentDiskIsDead: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Dependent Physical Drive is DEAD\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_InvalidOrNonredundantLogicalDrive: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Invalid or Nonredundant Logical Drive\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_RebuildOrCheckAlreadyInProgress: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - Rebuild or " + "Consistency Check Already in Progress\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + default: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Unexpected Status %04X\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, Command->CommandStatus); + break; + } + } + else if (strcmp(UserCommand, "cancel-rebuild") == 0 || + strcmp(UserCommand, "cancel-consistency-check") == 0) + { + unsigned char OldRebuildRateConstant; + CommandMailbox->Type3R.CommandOpcode = DAC960_RebuildControl; + CommandMailbox->Type3R.RebuildRateConstant = 0xFF; + CommandMailbox->Type3R.BusAddress = + Virtual_to_Bus(&OldRebuildRateConstant); + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n", + Controller); + break; + default: + DAC960_UserCritical("Cancellation of Rebuild or " + "Consistency Check Failed - " + "Unexpected Status %04X\n", + Controller, Command->CommandStatus); + break; + } + } + else DAC960_UserCritical("Illegal User Command: '%s'\n", + Controller, UserCommand); + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_DeallocateCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return true; +} + + +/* + DAC960_ProcReadStatus implements reading /proc/rd/status. +*/ + +static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + char *StatusMessage = "OK\n"; + int ControllerNumber, BytesAvailable; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + DAC960_Enquiry_T *Enquiry; + if (Controller == NULL) continue; + Enquiry = &Controller->Enquiry[Controller->EnquiryIndex]; + if (Enquiry->CriticalLogicalDriveCount > 0 || + Enquiry->OfflineLogicalDriveCount > 0 || + Enquiry->DeadDriveCount > 0) + { + StatusMessage = "ALERT\n"; + break; + } + } + BytesAvailable = strlen(StatusMessage) - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &StatusMessage[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status. +*/ + +static int DAC960_ProcReadInitialStatus(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable = Controller->InitialStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &Controller->InitialStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status. +*/ + +static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable; + if (jiffies != Controller->LastCurrentStatusTime) + { + Controller->CurrentStatusLength = 0; + DAC960_AnnounceDriver(Controller); + DAC960_ReportControllerConfiguration(Controller); + DAC960_ReportDeviceConfiguration(Controller); + Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; + Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; + if (Controller->RebuildProgressLength > 0) + { + strcpy(&Controller->CurrentStatusBuffer + [Controller->CurrentStatusLength], + Controller->RebuildProgressBuffer); + Controller->CurrentStatusLength += Controller->RebuildProgressLength; + } + else + { + char *StatusMessage = "No Rebuild or Consistency Check in Progress\n"; + strcpy(&Controller->CurrentStatusBuffer + [Controller->CurrentStatusLength], + StatusMessage); + Controller->CurrentStatusLength += strlen(StatusMessage); + } + Controller->LastCurrentStatusTime = jiffies; + } + BytesAvailable = Controller->CurrentStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &Controller->CurrentStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command. +*/ + +static int DAC960_ProcReadUserCommand(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable = Controller->UserStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &Controller->UserStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command. +*/ + +static int DAC960_ProcWriteUserCommand(File_T *File, const char *Buffer, + unsigned long Count, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + char CommandBuffer[80]; + int Length; + if (Count > sizeof(CommandBuffer)-1) return -EINVAL; + copy_from_user(CommandBuffer, Buffer, Count); + CommandBuffer[Count] = '\0'; + Length = strlen(CommandBuffer); + if (CommandBuffer[Length-1] == '\n') + CommandBuffer[--Length] = '\0'; + return (DAC960_ExecuteUserCommand(Controller, CommandBuffer) + ? Count : -EBUSY); +} + + +/* + DAC960_CreateProcEntries creates the /proc/rd/... entries for the DAC960 + Driver. +*/ + +static void DAC960_CreateProcEntries(void) +{ + static PROC_DirectoryEntry_T StatusProcEntry; + int ControllerNumber; + DAC960_ProcDirectoryEntry.name = "rd"; + DAC960_ProcDirectoryEntry.namelen = strlen(DAC960_ProcDirectoryEntry.name); + DAC960_ProcDirectoryEntry.mode = S_IFDIR | S_IRUGO | S_IXUGO; + proc_register(&proc_root, &DAC960_ProcDirectoryEntry); + StatusProcEntry.name = "status"; + StatusProcEntry.namelen = strlen(StatusProcEntry.name); + StatusProcEntry.mode = S_IFREG | S_IRUGO; + StatusProcEntry.read_proc = DAC960_ProcReadStatus; + proc_register(&DAC960_ProcDirectoryEntry, &StatusProcEntry); + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry; + PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry; + if (Controller == NULL) continue; + ControllerProcEntry = &Controller->ControllerProcEntry; + ControllerProcEntry->name = Controller->ControllerName; + ControllerProcEntry->namelen = strlen(ControllerProcEntry->name); + ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO; + proc_register(&DAC960_ProcDirectoryEntry, ControllerProcEntry); + InitialStatusProcEntry = &Controller->InitialStatusProcEntry; + InitialStatusProcEntry->name = "initial_status"; + InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name); + InitialStatusProcEntry->mode = S_IFREG | S_IRUGO; + InitialStatusProcEntry->data = Controller; + InitialStatusProcEntry->read_proc = DAC960_ProcReadInitialStatus; + proc_register(ControllerProcEntry, InitialStatusProcEntry); + CurrentStatusProcEntry = &Controller->CurrentStatusProcEntry; + CurrentStatusProcEntry->name = "current_status"; + CurrentStatusProcEntry->namelen = strlen(CurrentStatusProcEntry->name); + CurrentStatusProcEntry->mode = S_IFREG | S_IRUGO; + CurrentStatusProcEntry->data = Controller; + CurrentStatusProcEntry->read_proc = DAC960_ProcReadCurrentStatus; + proc_register(ControllerProcEntry, CurrentStatusProcEntry); + UserCommandProcEntry = &Controller->UserCommandProcEntry; + UserCommandProcEntry->name = "user_command"; + UserCommandProcEntry->namelen = strlen(UserCommandProcEntry->name); + UserCommandProcEntry->mode = S_IFREG | S_IWUSR | S_IRUSR; + UserCommandProcEntry->data = Controller; + UserCommandProcEntry->read_proc = DAC960_ProcReadUserCommand; + UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand; + proc_register(ControllerProcEntry, UserCommandProcEntry); + } +} + + +/* + DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the DAC960 + Driver. +*/ + +static void DAC960_DestroyProcEntries(void) +{ + proc_unregister(&proc_root, DAC960_ProcDirectoryEntry.low_ino); +} + + +/* + Include Module support if requested. +*/ + +#ifdef MODULE + + +int init_module(void) +{ + int ControllerNumber, LogicalDriveNumber; + DAC960_Initialize(); + if (DAC960_ActiveControllerCount == 0) return -1; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) continue; + DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + } + return 0; +} + + +void cleanup_module(void) +{ + DAC960_Finalize(&DAC960_NotifierBlock, SYS_RESTART, NULL); +} + + +#endif diff -u --recursive --new-file v2.3.15/linux/drivers/block/DAC960.h linux/drivers/block/DAC960.h --- v2.3.15/linux/drivers/block/DAC960.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/DAC960.h Mon Aug 30 10:24:14 1999 @@ -0,0 +1,2244 @@ +/* + + Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers + + Copyright 1998-1999 by Leonard N. Zubkoff + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + 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 complete details. + + The author respectfully requests that any modifications to this software be + sent directly to him for evaluation and testing. + +*/ + + +/* + Define the maximum number of DAC960 Controllers supported by this driver. +*/ + +#define DAC960_MaxControllers 8 + + +/* + Define the maximum number of Controller Channels supported by this driver. +*/ + +#define DAC960_MaxChannels 3 + + +/* + Define the maximum number of Targets per Channel supported by this driver. +*/ + +#define DAC960_MaxTargets 16 + + +/* + Define the maximum number of Logical Drives supported by any DAC960 model. +*/ + +#define DAC960_MaxLogicalDrives 32 + + +/* + Define a Boolean data type. +*/ + +typedef enum { false, true } __attribute__ ((packed)) boolean; + + +/* + Define a 32 bit I/O Address data type. +*/ + +typedef unsigned int DAC960_IO_Address_T; + + +/* + Define a 32 bit PCI Bus Address data type. +*/ + +typedef unsigned int DAC960_PCI_Address_T; + + +/* + Define a 32 bit Bus Address data type. +*/ + +typedef unsigned int DAC960_BusAddress_T; + + +/* + Define a 32 bit Byte Count data type. +*/ + +typedef unsigned int DAC960_ByteCount_T; + + +/* + Define the DAC960 Command Opcodes. +*/ + +typedef enum +{ + /* I/O Commands */ + DAC960_ReadExtended = 0x33, + DAC960_WriteExtended = 0x34, + DAC960_ReadAheadExtended = 0x35, + DAC960_ReadExtendedWithScatterGather = 0xB3, + DAC960_WriteExtendedWithScatterGather = 0xB4, + DAC960_Read = 0x36, + DAC960_ReadWithOldScatterGather = 0xB6, + DAC960_Write = 0x37, + DAC960_WriteWithOldScatterGather = 0xB7, + DAC960_DCDB = 0x04, + DAC960_DCDBWithScatterGather = 0x84, + DAC960_Flush = 0x0A, + /* Controller Status Related Commands */ + DAC960_Enquiry = 0x53, + DAC960_Enquiry2 = 0x1C, + DAC960_GetLogicalDriveElement = 0x55, + DAC960_GetLogicalDriveInformation = 0x19, + DAC960_IOPortRead = 0x39, + DAC960_IOPortWrite = 0x3A, + DAC960_GetSDStats = 0x3E, + DAC960_GetPDStats = 0x3F, + DAC960_PerformEventLogOperation = 0x72, + /* Device Related Commands */ + DAC960_StartDevice = 0x10, + DAC960_GetDeviceState = 0x50, + DAC960_StopChannel = 0x13, + DAC960_StartChannel = 0x12, + DAC960_ResetChannel = 0x1A, + /* Commands Associated with Data Consistency and Errors */ + DAC960_Rebuild = 0x09, + DAC960_RebuildAsync = 0x16, + DAC960_CheckConsistency = 0x0F, + DAC960_CheckConsistencyAsync = 0x1E, + DAC960_RebuildStat = 0x0C, + DAC960_GetRebuildProgress = 0x27, + DAC960_RebuildControl = 0x1F, + DAC960_ReadBadBlockTable = 0x0B, + DAC960_ReadBadDataTable = 0x25, + DAC960_ClearBadDataTable = 0x26, + DAC960_GetErrorTable = 0x17, + DAC960_AddCapacityAsync = 0x2A, + /* Configuration Related Commands */ + DAC960_ReadConfig2 = 0x3D, + DAC960_WriteConfig2 = 0x3C, + DAC960_ReadConfigurationOnDisk = 0x4A, + DAC960_WriteConfigurationOnDisk = 0x4B, + DAC960_ReadConfiguration = 0x4E, + DAC960_ReadBackupConfiguration = 0x4D, + DAC960_WriteConfiguration = 0x4F, + DAC960_AddConfiguration = 0x4C, + DAC960_ReadConfigurationLabel = 0x48, + DAC960_WriteConfigurationLabel = 0x49, + /* Firmware Upgrade Related Commands */ + DAC960_LoadImage = 0x20, + DAC960_StoreImage = 0x21, + DAC960_ProgramImage = 0x22, + /* Diagnostic Commands */ + DAC960_SetDiagnosticMode = 0x31, + DAC960_RunDiagnostic = 0x32, + /* Subsystem Service Commands */ + DAC960_GetSubsystemData = 0x70, + DAC960_SetSubsystemParameters = 0x71 +} +__attribute__ ((packed)) +DAC960_CommandOpcode_T; + + +/* + Define the DAC960 Command Identifier type. +*/ + +typedef unsigned char DAC960_CommandIdentifier_T; + + +/* + Define the DAC960 Command Status Codes. +*/ + +#define DAC960_NormalCompletion 0x0000 /* Common */ +#define DAC960_CheckConditionReceived 0x0002 /* Common */ +#define DAC960_NoDeviceAtAddress 0x0102 /* Common */ +#define DAC960_InvalidDeviceAddress 0x0105 /* Common */ +#define DAC960_InvalidParameter 0x0105 /* Common */ +#define DAC960_IrrecoverableDataError 0x0001 /* I/O */ +#define DAC960_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */ +#define DAC960_AccessBeyondEndOfLogicalDrive 0x0105 /* I/O */ +#define DAC960_BadDataEncountered 0x010C /* I/O */ +#define DAC960_DeviceBusy 0x0008 /* DCDB */ +#define DAC960_DeviceNonresponsive 0x000E /* DCDB */ +#define DAC960_CommandTerminatedAbnormally 0x000F /* DCDB */ +#define DAC960_UnableToStartDevice 0x0002 /* Device */ +#define DAC960_InvalidChannelOrTargetOrModifier 0x0105 /* Device */ +#define DAC960_ChannelBusy 0x0106 /* Device */ +#define DAC960_ChannelNotStopped 0x0002 /* Device */ +#define DAC960_AttemptToRebuildOnlineDrive 0x0002 /* Consistency */ +#define DAC960_RebuildBadBlocksEncountered 0x0003 /* Consistency */ +#define DAC960_NewDiskFailedDuringRebuild 0x0004 /* Consistency */ +#define DAC960_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */ +#define DAC960_DependentDiskIsDead 0x0002 /* Consistency */ +#define DAC960_InconsistentBlocksFound 0x0003 /* Consistency */ +#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */ +#define DAC960_NoRebuildOrCheckInProgress 0x0105 /* Consistency */ +#define DAC960_RebuildInProgress_DataValid 0x0000 /* Consistency */ +#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */ +#define DAC960_RebuildFailed_BadBlocksOnOther 0x0003 /* Consistency */ +#define DAC960_RebuildFailed_NewDriveFailed 0x0004 /* Consistency */ +#define DAC960_RebuildSuccessful 0x0100 /* Consistency */ +#define DAC960_AddCapacityInProgress 0x0004 /* Consistency */ +#define DAC960_AddCapacityFailedOrSuspended 0x00F4 /* Consistency */ +#define DAC960_Config2ChecksumError 0x0002 /* Configuration */ +#define DAC960_ConfigurationSuspended 0x0106 /* Configuration */ +#define DAC960_FailedToConfigureNVRAM 0x0105 /* Configuration */ +#define DAC960_ConfigurationNotSavedStateChange 0x0106 /* Configuration */ +#define DAC960_SubsystemNotInstalled 0x0001 /* Subsystem */ +#define DAC960_SubsystemFailed 0x0002 /* Subsystem */ +#define DAC960_SubsystemBusy 0x0106 /* Subsystem */ + +typedef unsigned short DAC960_CommandStatus_T; + + +/* + Define the Enquiry reply structure. +*/ + +typedef struct DAC960_Enquiry +{ + unsigned char NumberOfLogicalDrives; /* Byte 0 */ + unsigned int :24; /* Bytes 1-3 */ + unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */ + unsigned short FlashAge; /* Bytes 132-133 */ + struct { + boolean DeferredWriteError:1; /* Byte 134 Bit 0 */ + boolean BatteryLow:1; /* Byte 134 Bit 1 */ + unsigned char :6; /* Byte 134 Bits 2-7 */ + } StatusFlags; + unsigned char :8; /* Byte 135 */ + unsigned char MinorFirmwareVersion; /* Byte 136 */ + unsigned char MajorFirmwareVersion; /* Byte 137 */ + enum { + DAC960_NoStandbyRebuildOrCheckInProgress = 0x00, + DAC960_StandbyRebuildInProgress = 0x01, + DAC960_BackgroundRebuildInProgress = 0x02, + DAC960_BackgroundCheckInProgress = 0x03, + DAC960_StandbyRebuildCompletedWithError = 0xFF, + DAC960_BackgroundRebuildOrCheckFailed_DriveFailed = 0xF0, + DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed = 0xF1, + DAC960_BackgroundRebuildOrCheckFailed_OtherCauses = 0xF2, + DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated = 0xF3 + } __attribute__ ((packed)) RebuildFlag; /* Byte 138 */ + unsigned char MaxCommands; /* Byte 139 */ + unsigned char OfflineLogicalDriveCount; /* Byte 140 */ + unsigned char :8; /* Byte 141 */ + unsigned short EventLogSequenceNumber; /* Bytes 142-143 */ + unsigned char CriticalLogicalDriveCount; /* Byte 144 */ + unsigned int :24; /* Bytes 145-147 */ + unsigned char DeadDriveCount; /* Byte 148 */ + unsigned char :8; /* Byte 149 */ + unsigned char RebuildCount; /* Byte 150 */ + struct { + unsigned char :3; /* Byte 151 Bits 0-2 */ + boolean BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */ + unsigned char :3; /* Byte 151 Bits 4-6 */ + unsigned char :1; /* Byte 151 Bit 7 */ + } MiscFlags; + struct { + unsigned char TargetID; + unsigned char Channel; + } DeadDrives[21]; /* Bytes 152-194 */ + unsigned char Reserved[62]; /* Bytes 195-255 */ +} +__attribute__ ((packed)) +DAC960_Enquiry_T; + + +/* + Define the Enquiry2 reply structure. +*/ + +typedef struct DAC960_Enquiry2 +{ + struct { + enum { + DAC960_P_PD_PU = 0x01, + DAC960_PL = 0x02, + DAC960_PG = 0x10, + DAC960_PJ = 0x11, + DAC960_PR = 0x12, + DAC960_PT = 0x13, + DAC960_PTL0 = 0x14, + DAC960_PRL = 0x15, + DAC960_PTL1 = 0x16, + DAC1164_P = 0x20 + } __attribute__ ((packed)) SubModel; /* Byte 0 */ + unsigned char ActualChannels; /* Byte 1 */ + enum { + DAC960_FiveChannelBoard = 0x01, + DAC960_ThreeChannelBoard = 0x02, + DAC960_TwoChannelBoard = 0x03, + DAC960_ThreeChannelASIC_DAC = 0x04 + } __attribute__ ((packed)) Model; /* Byte 2 */ + enum { + DAC960_EISA_Controller = 0x01, + DAC960_MicroChannel_Controller = 0x02, + DAC960_PCI_Controller = 0x03, + DAC960_SCSItoSCSI_Controller = 0x08 + } __attribute__ ((packed)) ProductFamily; /* Byte 3 */ + } HardwareID; /* Bytes 0-3 */ + /* MajorVersion.MinorVersion-FirmwareType-TurnID */ + struct { + unsigned char MajorVersion; /* Byte 4 */ + unsigned char MinorVersion; /* Byte 5 */ + unsigned char TurnID; /* Byte 6 */ + char FirmwareType; /* Byte 7 */ + } FirmwareID; /* Bytes 4-7 */ + unsigned char :8; /* Byte 8 */ + unsigned int :24; /* Bytes 9-11 */ + unsigned char ConfiguredChannels; /* Byte 12 */ + unsigned char ActualChannels; /* Byte 13 */ + unsigned char MaxTargets; /* Byte 14 */ + unsigned char MaxTags; /* Byte 15 */ + unsigned char MaxLogicalDrives; /* Byte 16 */ + unsigned char MaxArms; /* Byte 17 */ + unsigned char MaxSpans; /* Byte 18 */ + unsigned char :8; /* Byte 19 */ + unsigned int :32; /* Bytes 20-23 */ + unsigned int MemorySize; /* Bytes 24-27 */ + unsigned int CacheSize; /* Bytes 28-31 */ + unsigned int FlashMemorySize; /* Bytes 32-35 */ + unsigned int NonVolatileMemorySize; /* Bytes 36-39 */ + struct { + enum { + DAC960_DRAM = 0x00, + DAC960_EDO = 0x01, + DAC960_SDRAM = 0x02 + } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */ + enum { + DAC960_None = 0x00, + DAC960_Parity = 0x01, + DAC960_ECC = 0x02 + } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */ + boolean FastPageMode:1; /* Byte 40 Bit 6 */ + boolean LowPowerMemory:1; /* Byte 40 Bit 7 */ + unsigned char :8; /* Bytes 41 */ + } MemoryType; + unsigned short ClockSpeed; /* Bytes 42-43 */ + unsigned short MemorySpeed; /* Bytes 44-45 */ + unsigned short HardwareSpeed; /* Bytes 46-47 */ + unsigned int :32; /* Bytes 48-51 */ + unsigned int :32; /* Bytes 52-55 */ + unsigned char :8; /* Byte 56 */ + unsigned char :8; /* Byte 57 */ + unsigned short :16; /* Bytes 58-59 */ + unsigned short MaxCommands; /* Bytes 60-61 */ + unsigned short MaxScatterGatherEntries; /* Bytes 62-63 */ + unsigned short MaxDriveCommands; /* Bytes 64-65 */ + unsigned short MaxIODescriptors; /* Bytes 66-67 */ + unsigned short MaxCombinedSectors; /* Bytes 68-69 */ + unsigned char Latency; /* Byte 70 */ + unsigned char :8; /* Byte 71 */ + unsigned char SCSITimeout; /* Byte 72 */ + unsigned char :8; /* Byte 73 */ + unsigned short MinFreeLines; /* Bytes 74-75 */ + unsigned int :32; /* Bytes 76-79 */ + unsigned int :32; /* Bytes 80-83 */ + unsigned char RebuildRateConstant; /* Byte 84 */ + unsigned char :8; /* Byte 85 */ + unsigned char :8; /* Byte 86 */ + unsigned char :8; /* Byte 87 */ + unsigned int :32; /* Bytes 88-91 */ + unsigned int :32; /* Bytes 92-95 */ + unsigned short PhysicalDriveBlockSize; /* Bytes 96-97 */ + unsigned short LogicalDriveBlockSize; /* Bytes 98-99 */ + unsigned short MaxBlocksPerCommand; /* Bytes 100-101 */ + unsigned short BlockFactor; /* Bytes 102-103 */ + unsigned short CacheLineSize; /* Bytes 104-105 */ + struct { + enum { + DAC960_Narrow_8bit = 0x00, + DAC960_Wide_16bit = 0x01, + DAC960_Wide_32bit = 0x02 + } __attribute__ ((packed)) BusWidth:2; /* Byte 106 Bits 0-1 */ + enum { + DAC960_Fast = 0x00, + DAC960_Ultra = 0x01, + DAC960_Ultra2 = 0x02 + } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */ + boolean Differential:1; /* Byte 106 Bit 4 */ + unsigned char :3; /* Byte 106 Bits 5-7 */ + } SCSICapability; + unsigned char :8; /* Byte 107 */ + unsigned int :32; /* Bytes 108-111 */ + unsigned short FirmwareBuildNumber; /* Bytes 112-113 */ + enum { + DAC960_AEMI = 0x01, + DAC960_OEM1 = 0x02, + DAC960_OEM2 = 0x04, + DAC960_OEM3 = 0x08, + DAC960_Conner = 0x10, + DAC960_SAFTE = 0x20 + } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */ + unsigned char :8; /* Byte 115 */ + struct { + boolean Clustering:1; /* Byte 116 Bit 0 */ + boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */ + unsigned int :30; /* Bytes 116-119 */ + } FirmwareFeatures; + unsigned int :32; /* Bytes 120-123 */ + unsigned int :32; /* Bytes 124-127 */ +} +DAC960_Enquiry2_T; + + +/* + Define the Logical Drive State type. +*/ + +typedef enum +{ + DAC960_LogicalDrive_Online = 0x03, + DAC960_LogicalDrive_Critical = 0x04, + DAC960_LogicalDrive_Offline = 0xFF +} +__attribute__ ((packed)) +DAC960_LogicalDriveState_T; + + +/* + Define the Get Logical Drive Information reply structure. +*/ + +typedef struct DAC960_LogicalDriveInformation +{ + unsigned int LogicalDriveSize; /* Bytes 0-3 */ + DAC960_LogicalDriveState_T LogicalDriveState; /* Byte 4 */ + unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */ + boolean WriteBack:1; /* Byte 5 Bit 7 */ + unsigned int :16; /* Bytes 6-7 */ +} +DAC960_LogicalDriveInformation_T; + + +/* + Define the Perform Event Log Operation Types. +*/ + +typedef enum +{ + DAC960_GetEventLogEntry = 0x00 +} +__attribute__ ((packed)) +DAC960_PerformEventLogOpType_T; + + +/* + Define the Get Event Log Entry reply structure. +*/ + +typedef struct DAC960_EventLogEntry +{ + unsigned char MessageType; /* Byte 0 */ + unsigned char MessageLength; /* Byte 1 */ + unsigned char TargetID:5; /* Byte 2 Bits 0-4 */ + unsigned char Channel:3; /* Byte 2 Bits 5-7 */ + unsigned char LogicalUnit:6; /* Byte 3 Bits 0-5 */ + unsigned char :2; /* Byte 3 Bits 6-7 */ + unsigned short SequenceNumber; /* Bytes 4-5 */ + unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */ + boolean Valid:1; /* Byte 6 Bit 7 */ + unsigned char SegmentNumber; /* Byte 7 */ + unsigned char SenseKey:4; /* Byte 8 Bits 0-3 */ + unsigned char :1; /* Byte 8 Bit 4 */ + boolean ILI:1; /* Byte 8 Bit 5 */ + boolean EOM:1; /* Byte 8 Bit 6 */ + boolean Filemark:1; /* Byte 8 Bit 7 */ + unsigned char Information[4]; /* Bytes 9-12 */ + unsigned char AdditionalSenseLength; /* Byte 13 */ + unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */ + unsigned char AdditionalSenseCode; /* Byte 18 */ + unsigned char AdditionalSenseCodeQualifier; /* Byte 19 */ + unsigned char Dummy[12]; /* Bytes 20-31 */ +} +DAC960_EventLogEntry_T; + + +/* + Define the Physical Device State type. +*/ + +typedef enum +{ + DAC960_Device_Dead = 0x00, + DAC960_Device_WriteOnly = 0x02, + DAC960_Device_Online = 0x03, + DAC960_Device_Standby = 0x10 +} +__attribute__ ((packed)) +DAC960_PhysicalDeviceState_T; + + +/* + Define the Get Device State reply structure. +*/ + +typedef struct DAC960_DeviceState +{ + boolean Present:1; /* Byte 0 Bit 0 */ + unsigned char :7; /* Byte 0 Bits 1-7 */ + enum { + DAC960_OtherType = 0x00, + DAC960_DiskType = 0x01, + DAC960_SequentialType = 0x02, + DAC960_CDROM_or_WORM_Type = 0x03 + } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */ + boolean :1; /* Byte 1 Bit 2 */ + boolean Fast20:1; /* Byte 1 Bit 3 */ + boolean Sync:1; /* Byte 1 Bit 4 */ + boolean Fast:1; /* Byte 1 Bit 5 */ + boolean Wide:1; /* Byte 1 Bit 6 */ + boolean TaggedQueuingSupported:1; /* Byte 1 Bit 7 */ + DAC960_PhysicalDeviceState_T DeviceState; /* Byte 2 */ + unsigned char :8; /* Byte 3 */ + unsigned char SynchronousMultiplier; /* Byte 4 */ + unsigned char SynchronousOffset:5; /* Byte 5 Bits 0-4 */ + unsigned char :3; /* Byte 5 Bits 5-7 */ + unsigned long DiskSize __attribute__ ((packed)); /* Bytes 6-9 */ +} +DAC960_DeviceState_T; + + +/* + Define the Get Rebuild Progress reply structure. +*/ + +typedef struct DAC960_RebuildProgress +{ + unsigned int LogicalDriveNumber; /* Bytes 0-3 */ + unsigned int LogicalDriveSize; /* Bytes 4-7 */ + unsigned int RemainingBlocks; /* Bytes 8-11 */ +} +DAC960_RebuildProgress_T; + + +/* + Define the Error Table Entry and Get Error Table reply structure. +*/ + +typedef struct DAC960_ErrorTableEntry +{ + unsigned char ParityErrorCount; /* Byte 0 */ + unsigned char SoftErrorCount; /* Byte 1 */ + unsigned char HardErrorCount; /* Byte 2 */ + unsigned char MiscErrorCount; /* Byte 3 */ +} +DAC960_ErrorTableEntry_T; + + +/* + Define the Get Error Table reply structure. +*/ + +typedef struct DAC960_ErrorTable +{ + DAC960_ErrorTableEntry_T + ErrorTableEntries[DAC960_MaxChannels][DAC960_MaxTargets]; +} +DAC960_ErrorTable_T; + + +/* + Define the Config2 reply structure. +*/ + +typedef struct DAC960_Config2 +{ + unsigned char :1; /* Byte 0 Bit 0 */ + boolean ActiveNegationEnabled:1; /* Byte 0 Bit 1 */ + unsigned char :5; /* Byte 0 Bits 2-6 */ + boolean NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */ + boolean StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */ + boolean HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */ + boolean NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */ + unsigned char :2; /* Byte 1 Bits 3-4 */ + boolean AEMI_ARM:1; /* Byte 1 Bit 5 */ + boolean AEMI_OFM:1; /* Byte 1 Bit 6 */ + unsigned char :1; /* Byte 1 Bit 7 */ + enum { + DAC960_OEMID_Mylex = 0x00, + DAC960_OEMID_IBM = 0x08, + DAC960_OEMID_HP = 0x0A, + DAC960_OEMID_DEC = 0x0C, + DAC960_OEMID_Siemens = 0x10, + DAC960_OEMID_Intel = 0x12 + } __attribute__ ((packed)) OEMID; /* Byte 2 */ + unsigned char OEMModelNumber; /* Byte 3 */ + unsigned char PhysicalSector; /* Byte 4 */ + unsigned char LogicalSector; /* Byte 5 */ + unsigned char BlockFactor; /* Byte 6 */ + boolean ReadAheadEnabled:1; /* Byte 7 Bit 0 */ + boolean LowBIOSDelay:1; /* Byte 7 Bit 1 */ + unsigned char :2; /* Byte 7 Bits 2-3 */ + boolean ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */ + unsigned char :1; /* Byte 7 Bit 5 */ + boolean ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */ + boolean EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */ + unsigned char DefaultRebuildRate; /* Byte 8 */ + unsigned char :8; /* Byte 9 */ + unsigned char BlocksPerCacheLine; /* Byte 10 */ + unsigned char BlocksPerStripe; /* Byte 11 */ + struct { + enum { + DAC960_Async = 0x00, + DAC960_Sync_8MHz = 0x01, + DAC960_Sync_5MHz = 0x02, + DAC960_Sync_10or20MHz = 0x03 /* Bits 0-1 */ + } __attribute__ ((packed)) Speed:2; + boolean Force8Bit:1; /* Bit 2 */ + boolean DisableFast20:1; /* Bit 3 */ + unsigned char :3; /* Bits 4-6 */ + boolean EnableTaggedQueuing:1; /* Bit 7 */ + } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */ + unsigned char SCSIInitiatorID; /* Byte 18 */ + unsigned char :8; /* Byte 19 */ + enum { + DAC960_StartupMode_ControllerSpinUp = 0x00, + DAC960_StartupMode_PowerOnSpinUp = 0x01 + } __attribute__ ((packed)) StartupMode; /* Byte 20 */ + unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */ + unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */ + unsigned char Reserved1[29]; /* Bytes 23-51 */ + boolean BIOSDisabled:1; /* Byte 52 Bit 0 */ + boolean CDROMBootEnabled:1; /* Byte 52 Bit 1 */ + unsigned char :3; /* Byte 52 Bits 2-4 */ + enum { + DAC960_Geometry_128_32 = 0x00, + DAC960_Geometry_255_63 = 0x01, + DAC960_Geometry_Reserved1 = 0x02, + DAC960_Geometry_Reserved2 = 0x03 + } __attribute__ ((packed)) DriveGeometry:2; /* Byte 52 Bits 5-6 */ + unsigned char :1; /* Byte 52 Bit 7 */ + unsigned char Reserved2[9]; /* Bytes 53-61 */ + unsigned short Checksum; /* Bytes 62-63 */ +} +DAC960_Config2_T; + + +/* + Define the DCDB request structure. +*/ + +typedef struct DAC960_DCDB +{ + unsigned char TargetID:4; /* Byte 0 Bits 0-3 */ + unsigned char Channel:4; /* Byte 0 Bits 4-7 */ + enum { + DAC960_DCDB_NoDataTransfer = 0, + DAC960_DCDB_DataTransferDeviceToSystem = 1, + DAC960_DCDB_DataTransferSystemToDevice = 2, + DAC960_DCDB_IllegalDataTransfer = 3 + } __attribute__ ((packed)) Direction:2; /* Byte 1 Bits 0-1 */ + boolean EarlyStatus:1; /* Byte 1 Bit 2 */ + unsigned char :1; /* Byte 1 Bit 3 */ + enum { + DAC960_DCDB_Timeout_24_hours = 0, + DAC960_DCDB_Timeout_10_seconds = 1, + DAC960_DCDB_Timeout_60_seconds = 2, + DAC960_DCDB_Timeout_10_minutes = 3 + } __attribute__ ((packed)) Timeout:2; /* Byte 1 Bits 4-5 */ + boolean NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */ + boolean DisconnectPermitted:1; /* Byte 1 Bit 7 */ + unsigned short TransferLength; /* Bytes 2-3 */ + DAC960_BusAddress_T BusAddress; /* Bytes 4-7 */ + unsigned char CDBLength:4; /* Byte 8 Bits 0-3 */ + unsigned char TransferLengthHigh4:4; /* Byte 8 Bits 4-7 */ + unsigned char SenseLength; /* Byte 9 */ + unsigned char CDB[12]; /* Bytes 10-21 */ + unsigned char SenseData[64]; /* Bytes 22-85 */ + unsigned char Status; /* Byte 86 */ + unsigned char :8; /* Byte 87 */ +} +DAC960_DCDB_T; + + +/* + Define the SCSI INQUIRY Standard Data reply structure. +*/ + +typedef struct DAC960_SCSI_Inquiry +{ + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ + unsigned char :2; /* Byte 3 Bits 4-5 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + boolean AENC:1; /* Byte 3 Bit 7 */ + unsigned char AdditionalLength; /* Byte 4 */ + unsigned char :8; /* Byte 5 */ + unsigned char :8; /* Byte 6 */ + boolean SftRe:1; /* Byte 7 Bit 0 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean :1; /* Byte 7 Bit 2 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean RelAdr:1; /* Byte 7 Bit 7 */ + unsigned char VendorIdentification[8]; /* Bytes 8-15 */ + unsigned char ProductIdentification[16]; /* Bytes 16-31 */ + unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ +} +DAC960_SCSI_Inquiry_T; + + +/* + Define the SCSI INQUIRY Unit Serial Number reply structure. +*/ + +typedef struct DAC960_SCSI_Inquiry_UnitSerialNumber +{ + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char PageCode; /* Byte 1 */ + unsigned char :8; /* Byte 2 */ + unsigned char PageLength; /* Byte 3 */ + unsigned char ProductSerialNumber[28]; /* Bytes 4 - 31 */ +} +DAC960_SCSI_Inquiry_UnitSerialNumber_T; + + +/* + Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count + structure. +*/ + +typedef struct DAC960_ScatterGatherSegment +{ + DAC960_BusAddress_T SegmentDataPointer; /* Bytes 0-3 */ + DAC960_ByteCount_T SegmentByteCount; /* Bytes 4-7 */ +} +DAC960_ScatterGatherSegment_T; + + +/* + Define the 13 Byte DAC960 Command Mailbox structure. Bytes 13-15 are + not used. The Command Mailbox structure is padded to 16 bytes for + efficient access. +*/ + +typedef union DAC960_CommandMailbox +{ + unsigned int Words[4]; /* Words 0-3 */ + unsigned char Bytes[16]; /* Bytes 0-15 */ + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy[14]; /* Bytes 2-15 */ + } __attribute__ ((packed)) Common; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[6]; /* Bytes 2-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[5]; /* Bytes 2-6 */ + unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */ + boolean AutoRestore:1; /* Byte 7 Bit 7 */ + unsigned char Dummy2[8]; /* Bytes 8-15 */ + } __attribute__ ((packed)) Type3C; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Channel; /* Byte 2 */ + unsigned char TargetID; /* Byte 3 */ + DAC960_PhysicalDeviceState_T DeviceState:5; /* Byte 4 Bits 0-4 */ + unsigned char Modifier:3; /* Byte 4 Bits 5-7 */ + unsigned char Dummy1[3]; /* Bytes 5-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3D; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + DAC960_PerformEventLogOpType_T OperationType; /* Byte 2 */ + unsigned char OperationQualifier; /* Byte 3 */ + unsigned short SequenceNumber; /* Bytes 4-5 */ + unsigned char Dummy1[2]; /* Bytes 6-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3E; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[2]; /* Bytes 2-3 */ + unsigned char RebuildRateConstant; /* Byte 4 */ + unsigned char Dummy2[3]; /* Bytes 5-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy3[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3R; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned short TransferLength; /* Bytes 2-3 */ + unsigned int LogicalBlockAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char LogicalDriveNumber; /* Byte 12 */ + unsigned char Dummy[3]; /* Bytes 13-15 */ + } __attribute__ ((packed)) Type4; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + struct { + unsigned short TransferLength:11; /* Bytes 2-3 */ + unsigned char LogicalDriveNumber:5; /* Byte 3 Bits 3-7 */ + } __attribute__ ((packed)) LD; + unsigned int LogicalBlockAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char ScatterGatherCount:6; /* Byte 12 Bits 0-5 */ + enum { + DAC960_ScatterGather_32BitAddress_32BitByteCount = 0x0, + DAC960_ScatterGather_32BitAddress_16BitByteCount = 0x1, + DAC960_ScatterGather_32BitByteCount_32BitAddress = 0x2, + DAC960_ScatterGather_16BitByteCount_32BitAddress = 0x3 + } __attribute__ ((packed)) ScatterGatherType:2; /* Byte 12 Bits 6-7 */ + unsigned char Dummy[3]; /* Bytes 13-15 */ + } __attribute__ ((packed)) Type5; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char CommandOpcode2; /* Byte 2 */ + unsigned char :8; /* Byte 3 */ + DAC960_BusAddress_T CommandMailboxesBusAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T StatusMailboxesBusAddress; /* Bytes 8-11 */ + unsigned char Dummy[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) TypeX; +} +DAC960_CommandMailbox_T; + + +/* + Define the DAC960 Driver IOCTL requests. +*/ + +#define DAC960_IOCTL_GET_CONTROLLER_COUNT 0xDAC001 +#define DAC960_IOCTL_GET_CONTROLLER_INFO 0xDAC002 +#define DAC960_IOCTL_EXECUTE_COMMAND 0xDAC003 + + +/* + Define the DAC960_IOCTL_GET_CONTROLLER_INFO reply structure. +*/ + +typedef struct DAC960_ControllerInfo +{ + unsigned char ControllerNumber; + unsigned char PCI_Bus; + unsigned char PCI_Device; + unsigned char PCI_Function; + unsigned char IRQ_Channel; + unsigned char Channels; + DAC960_PCI_Address_T PCI_Address; + unsigned char ModelName[16]; + unsigned char FirmwareVersion[16]; +} +DAC960_ControllerInfo_T; + + +/* + Define the User Mode DAC960_IOCTL_EXECUTE_COMMAND request structure. +*/ + +typedef struct DAC960_UserCommand +{ + unsigned char ControllerNumber; + DAC960_CommandMailbox_T CommandMailbox; + int DataTransferLength; + void *DataTransferBuffer; + DAC960_DCDB_T *DCDB; +} +DAC960_UserCommand_T; + + +/* + Define the Kernel Mode DAC960_IOCTL_EXECUTE_COMMAND request structure. +*/ + +typedef struct DAC960_KernelCommand +{ + unsigned char ControllerNumber; + DAC960_CommandMailbox_T CommandMailbox; + int DataTransferLength; + void *DataTransferBuffer; + DAC960_DCDB_T *DCDB; + DAC960_CommandStatus_T CommandStatus; + void (*CompletionFunction)(struct DAC960_KernelCommand *); + void *CompletionData; +} +DAC960_KernelCommand_T; + + +/* + Import the Kernel Mode IOCTL interface. +*/ + +extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument); + + +/* + Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. +*/ + +static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress) +{ + return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress); +} + + +/* + Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. +*/ + +static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress) +{ + return (void *) bus_to_virt(BusAddress); +} + + +/* + DAC960_DriverVersion protects the private portion of this file. +*/ + +#ifdef DAC960_DriverVersion + + +/* + Define the maximum Driver Queue Depth and Controller Queue Depth supported + by any DAC960 model. +*/ + +#define DAC960_MaxDriverQueueDepth 127 +#define DAC960_MaxControllerQueueDepth 128 + + +/* + Define the maximum number of Scatter/Gather Segments supported by any + DAC960 model. +*/ + +#define DAC960_MaxScatterGatherSegments 33 + + +/* + Define the number of Command Mailboxes and Status Mailboxes used by the + Memory Mailbox Interface. +*/ + +#define DAC960_CommandMailboxCount 256 +#define DAC960_StatusMailboxCount 1024 + + +/* + Define the DAC960 Controller Monitoring Timer Interval. +*/ + +#define DAC960_MonitoringTimerInterval (10 * HZ) + + +/* + Define the DAC960 Controller Secondary Monitoring Interval. +*/ + +#define DAC960_SecondaryMonitoringInterval (60 * HZ) + + +/* + Define the DAC960 Controller Progress Reporting Interval. +*/ + +#define DAC960_ProgressReportingInterval (60 * HZ) + + +/* + Define the maximum number of Partitions allowed for each Logical Drive. +*/ + +#define DAC960_MaxPartitions 8 +#define DAC960_MaxPartitionsBits 3 + + +/* + Define macros to extract the Controller Number, Logical Drive Number, and + Partition Number from a Kernel Device, and to construct a Major Number, Minor + Number, and Kernel Device from the Controller Number, Logical Drive Number, + and Partition Number. There is one Major Number assigned to each Controller. + The associated Minor Number is divided into the Logical Drive Number and + Partition Number. +*/ + +#define DAC960_ControllerNumber(Device) \ + (MAJOR(Device) - DAC960_MAJOR) + +#define DAC960_LogicalDriveNumber(Device) \ + (MINOR(Device) >> DAC960_MaxPartitionsBits) + +#define DAC960_PartitionNumber(Device) \ + (MINOR(Device) & (DAC960_MaxPartitions - 1)) + +#define DAC960_MajorNumber(ControllerNumber) \ + (DAC960_MAJOR + (ControllerNumber)) + +#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \ + (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber)) + +#define DAC960_MinorCount (DAC960_MaxLogicalDrives \ + * DAC960_MaxPartitions) + +#define DAC960_KernelDevice(ControllerNumber, \ + LogicalDriveNumber, \ + PartitionNumber) \ + MKDEV(DAC960_MajorNumber(ControllerNumber), \ + DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber)) + + +/* + Define the DAC960 Controller fixed Block Size and Block Size Bits. +*/ + +#define DAC960_BlockSize 512 +#define DAC960_BlockSizeBits 9 + + +/* + Define the Controller Line Buffer, Status Buffer, Rebuild Progress, + and User Message Sizes. +*/ + +#define DAC960_LineBufferSize 100 +#define DAC960_StatusBufferSize 16384 +#define DAC960_RebuildProgressSize 200 +#define DAC960_UserMessageSize 200 + + +/* + Define the types of DAC960 Controllers that are supported. +*/ + +typedef enum +{ + DAC960_V5_Controller = 1, /* DAC1164P */ + DAC960_V4_Controller = 2, /* DAC960PTL/PJ/PG */ + DAC960_V3_Controller = 3 /* DAC960PU/PD/PL */ +} +DAC960_ControllerType_T; + + +/* + Define the Driver Message Levels. +*/ + +typedef enum DAC960_MessageLevel +{ + DAC960_AnnounceLevel = 0, + DAC960_InfoLevel = 1, + DAC960_NoticeLevel = 2, + DAC960_WarningLevel = 3, + DAC960_ErrorLevel = 4, + DAC960_ProgressLevel = 5, + DAC960_CriticalLevel = 6, + DAC960_UserCriticalLevel = 7 +} +DAC960_MessageLevel_T; + +static char + *DAC960_MessageLevelMap[] = + { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, + KERN_ERR, KERN_CRIT, KERN_CRIT, KERN_CRIT }; + + +/* + Define Driver Message macros. +*/ + +#define DAC960_Announce(Format, Arguments...) \ + DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments) + +#define DAC960_Info(Format, Arguments...) \ + DAC960_Message(DAC960_InfoLevel, Format, ##Arguments) + +#define DAC960_Notice(Format, Arguments...) \ + DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments) + +#define DAC960_Warning(Format, Arguments...) \ + DAC960_Message(DAC960_WarningLevel, Format, ##Arguments) + +#define DAC960_Error(Format, Arguments...) \ + DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments) + +#define DAC960_Progress(Format, Arguments...) \ + DAC960_Message(DAC960_ProgressLevel, Format, ##Arguments) + +#define DAC960_Critical(Format, Arguments...) \ + DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments) + +#define DAC960_UserCritical(Format, Arguments...) \ + DAC960_Message(DAC960_UserCriticalLevel, Format, ##Arguments) + + +/* + Define types for some of the structures that interface with the rest + of the Linux Kernel and I/O Subsystem. +*/ + +typedef struct buffer_head BufferHeader_T; +typedef struct file File_T; +typedef struct file_operations FileOperations_T; +typedef struct gendisk GenericDiskInfo_T; +typedef struct hd_geometry DiskGeometry_T; +typedef struct hd_struct DiskPartition_T; +typedef struct inode Inode_T; +typedef struct inode_operations InodeOperations_T; +typedef kdev_t KernelDevice_T; +typedef struct notifier_block NotifierBlock_T; +typedef struct pci_dev PCI_Device_T; +typedef struct proc_dir_entry PROC_DirectoryEntry_T; +typedef unsigned long ProcessorFlags_T; +typedef struct pt_regs Registers_T; +typedef struct request IO_Request_T; +typedef struct semaphore Semaphore_T; +typedef struct super_block SuperBlock_T; +typedef struct timer_list Timer_T; +typedef wait_queue_head_t WaitQueue_T; + + +/* + Define the DAC960 Controller Status Mailbox structure. +*/ + +typedef union DAC960_StatusMailbox +{ + unsigned int Word; /* Bytes 0-3 */ + struct { + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 0 */ + unsigned char :7; /* Byte 1 Bits 0-6 */ + boolean Valid:1; /* Byte 1 Bit 7 */ + DAC960_CommandStatus_T CommandStatus; /* Bytes 2-3 */ + } Fields; +} +DAC960_StatusMailbox_T; + + +/* + Define the DAC960 Driver Command Types. +*/ + +typedef enum +{ + DAC960_ReadCommand = 1, + DAC960_WriteCommand = 2, + DAC960_ReadRetryCommand = 3, + DAC960_WriteRetryCommand = 4, + DAC960_MonitoringCommand = 5, + DAC960_ImmediateCommand = 6, + DAC960_QueuedCommand = 7 +} +DAC960_CommandType_T; + + +/* + Define the DAC960 Driver Command structure. +*/ + +typedef struct DAC960_Command +{ + DAC960_CommandType_T CommandType; + DAC960_CommandMailbox_T CommandMailbox; + DAC960_CommandStatus_T CommandStatus; + struct DAC960_Controller *Controller; + struct DAC960_Command *Next; + Semaphore_T *Semaphore; + unsigned int LogicalDriveNumber; + unsigned int BlockNumber; + unsigned int BlockCount; + unsigned int SegmentCount; + BufferHeader_T *BufferHeader; + DAC960_KernelCommand_T *KernelCommand; + DAC960_ScatterGatherSegment_T + ScatterGatherList[DAC960_MaxScatterGatherSegments]; +} +DAC960_Command_T; + + +/* + Define the DAC960 Driver Controller structure. +*/ + +typedef struct DAC960_Controller +{ + void *BaseAddress; + void *MemoryMappedAddress; + DAC960_ControllerType_T ControllerType; + DAC960_IO_Address_T IO_Address; + DAC960_PCI_Address_T PCI_Address; + unsigned char ControllerNumber; + unsigned char ControllerName[4]; + unsigned char ModelName[12]; + unsigned char FullModelName[18]; + unsigned char FirmwareVersion[14]; + unsigned char Bus; + unsigned char Device; + unsigned char Function; + unsigned char IRQ_Channel; + unsigned char Channels; + unsigned char MemorySize; + unsigned char LogicalDriveCount; + unsigned char GeometryTranslationHeads; + unsigned char GeometryTranslationSectors; + unsigned short ControllerQueueDepth; + unsigned short DriverQueueDepth; + unsigned short MaxBlocksPerCommand; + unsigned short MaxScatterGatherSegments; + unsigned short StripeSize; + unsigned short SegmentSize; + unsigned short NewEventLogSequenceNumber; + unsigned short OldEventLogSequenceNumber; + unsigned short InitialStatusLength; + unsigned short CurrentStatusLength; + unsigned short UserStatusLength; + unsigned short RebuildProgressLength; + unsigned int ControllerUsageCount; + unsigned int EnquiryIndex; + unsigned int LogicalDriveInformationIndex; + unsigned int ErrorTableIndex; + unsigned int DeviceStateIndex; + unsigned int DeviceStateChannel; + unsigned int DeviceStateTargetID; + unsigned long MonitoringTimerCount; + unsigned long SecondaryMonitoringTime; + unsigned long LastProgressReportTime; + unsigned long LastCurrentStatusTime; + boolean DualModeMemoryMailboxInterface; + boolean SAFTE_EnclosureManagementEnabled; + boolean ControllerInitialized; + boolean MonitoringCommandDeferred; + boolean NeedLogicalDriveInformation; + boolean NeedErrorTableInformation; + boolean NeedDeviceStateInformation; + boolean NeedDeviceInquiryInformation; + boolean NeedDeviceSerialNumberInformation; + boolean NeedRebuildProgress; + boolean NeedConsistencyCheckProgress; + boolean EphemeralProgressMessage; + Timer_T MonitoringTimer; + GenericDiskInfo_T GenericDiskInfo; + DAC960_Command_T *FreeCommands; + DAC960_CommandMailbox_T *FirstCommandMailbox; + DAC960_CommandMailbox_T *LastCommandMailbox; + DAC960_CommandMailbox_T *NextCommandMailbox; + DAC960_CommandMailbox_T *PreviousCommandMailbox1; + DAC960_CommandMailbox_T *PreviousCommandMailbox2; + DAC960_StatusMailbox_T *FirstStatusMailbox; + DAC960_StatusMailbox_T *LastStatusMailbox; + DAC960_StatusMailbox_T *NextStatusMailbox; + PROC_DirectoryEntry_T ControllerProcEntry; + PROC_DirectoryEntry_T InitialStatusProcEntry; + PROC_DirectoryEntry_T CurrentStatusProcEntry; + PROC_DirectoryEntry_T UserCommandProcEntry; + WaitQueue_T CommandWaitQueue; + DAC960_DCDB_T MonitoringDCDB; + DAC960_Enquiry_T Enquiry[2]; + DAC960_ErrorTable_T ErrorTable[2]; + DAC960_EventLogEntry_T EventLogEntry; + DAC960_RebuildProgress_T RebuildProgress; + DAC960_CommandStatus_T LastRebuildStatus; + DAC960_LogicalDriveInformation_T + LogicalDriveInformation[2][DAC960_MaxLogicalDrives]; + DAC960_LogicalDriveState_T LogicalDriveInitialState[DAC960_MaxLogicalDrives]; + DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets]; + DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth]; + DAC960_SCSI_Inquiry_T + InquiryStandardData[DAC960_MaxChannels][DAC960_MaxTargets]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T + InquiryUnitSerialNumber[DAC960_MaxChannels][DAC960_MaxTargets]; + DiskPartition_T DiskPartitions[DAC960_MinorCount]; + int LogicalDriveUsageCount[DAC960_MaxLogicalDrives]; + int PartitionSizes[DAC960_MinorCount]; + int BlockSizes[DAC960_MinorCount]; + int MaxSectorsPerRequest[DAC960_MinorCount]; + int MaxSegmentsPerRequest[DAC960_MinorCount]; + int DeviceResetCount[DAC960_MaxChannels][DAC960_MaxTargets]; + boolean DirectCommandActive[DAC960_MaxChannels][DAC960_MaxTargets]; + char InitialStatusBuffer[DAC960_StatusBufferSize]; + char CurrentStatusBuffer[DAC960_StatusBufferSize]; + char UserStatusBuffer[DAC960_UserMessageSize]; + char RebuildProgressBuffer[DAC960_RebuildProgressSize]; +} +DAC960_Controller_T; + + +/* + DAC960_AcquireControllerLock acquires exclusive access to Controller. +*/ + +static inline +void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_lock_irqsave(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_ReleaseControllerLock releases exclusive access to Controller. +*/ + +static inline +void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_AcquireControllerLockRF acquires exclusive access to Controller, + but is only called from the request function with the io_request_lock held. +*/ + +static inline +void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ +} + + +/* + DAC960_ReleaseControllerLockRF releases exclusive access to Controller, + but is only called from the request function with the io_request_lock held. +*/ + +static inline +void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ +} + + +/* + DAC960_AcquireControllerLockIH acquires exclusive access to Controller, + but is only called from the interrupt handler. +*/ + +static inline +void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_lock_irqsave(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_ReleaseControllerLockIH releases exclusive access to Controller, + but is only called from the interrupt handler. +*/ + +static inline +void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); +} + + +/* + Define the DAC960 V5 Controller Interface Register Offsets. +*/ + +#define DAC960_V5_RegisterWindowSize 0x80 + +typedef enum +{ + DAC960_V5_InboundDoorBellRegisterOffset = 0x60, + DAC960_V5_OutboundDoorBellRegisterOffset = 0x61, + DAC960_V5_InterruptMaskRegisterOffset = 0x34, + DAC960_V5_CommandOpcodeRegisterOffset = 0x50, + DAC960_V5_CommandIdentifierRegisterOffset = 0x51, + DAC960_V5_MailboxRegister2Offset = 0x52, + DAC960_V5_MailboxRegister3Offset = 0x53, + DAC960_V5_MailboxRegister4Offset = 0x54, + DAC960_V5_MailboxRegister5Offset = 0x55, + DAC960_V5_MailboxRegister6Offset = 0x56, + DAC960_V5_MailboxRegister7Offset = 0x57, + DAC960_V5_MailboxRegister8Offset = 0x58, + DAC960_V5_MailboxRegister9Offset = 0x59, + DAC960_V5_MailboxRegister10Offset = 0x5A, + DAC960_V5_MailboxRegister11Offset = 0x5B, + DAC960_V5_MailboxRegister12Offset = 0x5C, + DAC960_V5_StatusCommandIdentifierRegOffset = 0x5D, + DAC960_V5_StatusRegisterOffset = 0x5E +} +DAC960_V5_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V5 Inbound Door Bell Register. +*/ + +typedef union DAC960_V5_InboundDoorBellRegister +{ + unsigned char All; + struct { + boolean HardwareMailboxNewCommand:1; /* Bit 0 */ + boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + unsigned char :3; /* Bits 5-7 */ + } Write; + struct { + boolean HardwareMailboxEmpty:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V5_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V5 Outbound Door Bell Register. +*/ + +typedef union DAC960_V5_OutboundDoorBellRegister +{ + unsigned char All; + struct { + boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + unsigned char :6; /* Bits 2-7 */ + } Write; + struct { + boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ + boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + unsigned char :6; /* Bits 2-7 */ + } Read; +} +DAC960_V5_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V5 Interrupt Mask Register. +*/ + +typedef union DAC960_V5_InterruptMaskRegister +{ + unsigned char All; + struct { + unsigned char :2; /* Bits 0-1 */ + boolean DisableInterrupts:1; /* Bit 2 */ + unsigned char :5; /* Bits 3-7 */ + } Bits; +} +DAC960_V5_InterruptMaskRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V5 Controller Interface Registers. +*/ + +static inline +void DAC960_V5_HardwareMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_MemoryMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V5_HardwareMailboxEmptyP(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.HardwareMailboxEmpty; +} + +static inline +void DAC960_V5_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V5_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; +} + +static inline +boolean DAC960_V5_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; +} + +static inline +void DAC960_V5_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.DisableInterrupts = false; + writeb(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); +} + +static inline +void DAC960_V5_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.DisableInterrupts = true; + writeb(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); +} + +static inline +boolean DAC960_V5_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = + readb(ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); + return !InterruptMaskRegister.Bits.DisableInterrupts; +} + +static inline +void DAC960_V5_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox, + DAC960_CommandMailbox_T *CommandMailbox) +{ + NextCommandMailbox->Words[1] = CommandMailbox->Words[1]; + NextCommandMailbox->Words[2] = CommandMailbox->Words[2]; + NextCommandMailbox->Words[3] = CommandMailbox->Words[3]; + NextCommandMailbox->Words[0] = CommandMailbox->Words[0]; +} + +static inline +void DAC960_V5_WriteHardwareMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V5_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V5_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V5_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V5_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V5_StatusRegisterOffset); +} + +static inline +void DAC960_V5_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + writel(0x743C485E, + ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset); + writel((unsigned long) Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset); +} + +static inline +void DAC960_V5_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, + void **MemoryMailboxAddress, + short *NextCommandMailboxIndex, + short *NextStatusMailboxIndex) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + if (readl(ControllerBaseAddress + + DAC960_V5_CommandOpcodeRegisterOffset) != 0x743C485E) + return; + *MemoryMailboxAddress = + (void *) readl(ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + *NextCommandMailboxIndex = + readw(ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + *NextStatusMailboxIndex = + readw(ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset); +} + + +/* + Define the DAC960 V4 Controller Interface Register Offsets. +*/ + +#define DAC960_V4_RegisterWindowSize 0x2000 + +typedef enum +{ + DAC960_V4_InboundDoorBellRegisterOffset = 0x0020, + DAC960_V4_OutboundDoorBellRegisterOffset = 0x002C, + DAC960_V4_InterruptMaskRegisterOffset = 0x0034, + DAC960_V4_CommandOpcodeRegisterOffset = 0x1000, + DAC960_V4_CommandIdentifierRegisterOffset = 0x1001, + DAC960_V4_MailboxRegister2Offset = 0x1002, + DAC960_V4_MailboxRegister3Offset = 0x1003, + DAC960_V4_MailboxRegister4Offset = 0x1004, + DAC960_V4_MailboxRegister5Offset = 0x1005, + DAC960_V4_MailboxRegister6Offset = 0x1006, + DAC960_V4_MailboxRegister7Offset = 0x1007, + DAC960_V4_MailboxRegister8Offset = 0x1008, + DAC960_V4_MailboxRegister9Offset = 0x1009, + DAC960_V4_MailboxRegister10Offset = 0x100A, + DAC960_V4_MailboxRegister11Offset = 0x100B, + DAC960_V4_MailboxRegister12Offset = 0x100C, + DAC960_V4_StatusCommandIdentifierRegOffset = 0x1018, + DAC960_V4_StatusRegisterOffset = 0x101A +} +DAC960_V4_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V4 Inbound Door Bell Register. +*/ + +typedef union DAC960_V4_InboundDoorBellRegister +{ + unsigned int All; + struct { + boolean HardwareMailboxNewCommand:1; /* Bit 0 */ + boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + unsigned int :27; /* Bits 5-31 */ + } Write; + struct { + boolean HardwareMailboxFull:1; /* Bit 0 */ + unsigned int :31; /* Bits 1-31 */ + } Read; +} +DAC960_V4_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V4 Outbound Door Bell Register. +*/ + +typedef union DAC960_V4_OutboundDoorBellRegister +{ + unsigned int All; + struct { + boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + unsigned int :30; /* Bits 2-31 */ + } Write; + struct { + boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ + boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + unsigned int :30; /* Bits 2-31 */ + } Read; +} +DAC960_V4_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V4 Interrupt Mask Register. +*/ + +typedef union DAC960_V4_InterruptMaskRegister +{ + unsigned int All; + struct { + unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */ + boolean DisableInterrupts:1; /* Bit 2 */ + unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */ + unsigned int Reserved0:24; /* Bits 8-31 */ + } Bits; +} +DAC960_V4_InterruptMaskRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V4 Controller Interface Registers. +*/ + +static inline +void DAC960_V4_HardwareMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_MemoryMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V4_HardwareMailboxFullP(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.HardwareMailboxFull; +} + +static inline +void DAC960_V4_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V4_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; +} + +static inline +boolean DAC960_V4_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; +} + +static inline +void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; + InterruptMaskRegister.Bits.DisableInterrupts = false; + InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; + writel(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); +} + +static inline +void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; + InterruptMaskRegister.Bits.DisableInterrupts = true; + InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; + writel(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); +} + +static inline +boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = + readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); + return !InterruptMaskRegister.Bits.DisableInterrupts; +} + +static inline +void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox, + DAC960_CommandMailbox_T *CommandMailbox) +{ + NextCommandMailbox->Words[1] = CommandMailbox->Words[1]; + NextCommandMailbox->Words[2] = CommandMailbox->Words[2]; + NextCommandMailbox->Words[3] = CommandMailbox->Words[3]; + NextCommandMailbox->Words[0] = CommandMailbox->Words[0]; +} + +static inline +void DAC960_V4_WriteHardwareMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V4_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset); +} + +static inline +void DAC960_V4_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + writel(0xAABBFFFF, + ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset); + writel((unsigned long) Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset); +} + +static inline +void DAC960_V4_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, + void **MemoryMailboxAddress, + short *NextCommandMailboxIndex, + short *NextStatusMailboxIndex) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + if (readl(ControllerBaseAddress + + DAC960_V4_CommandOpcodeRegisterOffset) != 0xAABBFFFF) + return; + *MemoryMailboxAddress = + (void *) readl(ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + *NextCommandMailboxIndex = + readw(ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + *NextStatusMailboxIndex = + readw(ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset); +} + + +/* + Define the DAC960 V3 Controller Interface Register Offsets. +*/ + +#define DAC960_V3_RegisterWindowSize 0x80 + +typedef enum +{ + DAC960_V3_CommandOpcodeRegisterOffset = 0x00, + DAC960_V3_CommandIdentifierRegisterOffset = 0x01, + DAC960_V3_MailboxRegister2Offset = 0x02, + DAC960_V3_MailboxRegister3Offset = 0x03, + DAC960_V3_MailboxRegister4Offset = 0x04, + DAC960_V3_MailboxRegister5Offset = 0x05, + DAC960_V3_MailboxRegister6Offset = 0x06, + DAC960_V3_MailboxRegister7Offset = 0x07, + DAC960_V3_MailboxRegister8Offset = 0x08, + DAC960_V3_MailboxRegister9Offset = 0x09, + DAC960_V3_MailboxRegister10Offset = 0x0A, + DAC960_V3_MailboxRegister11Offset = 0x0B, + DAC960_V3_MailboxRegister12Offset = 0x0C, + DAC960_V3_StatusCommandIdentifierRegOffset = 0x0D, + DAC960_V3_StatusRegisterOffset = 0x0E, + DAC960_V3_InboundDoorBellRegisterOffset = 0x40, + DAC960_V3_OutboundDoorBellRegisterOffset = 0x41, + DAC960_V3_InterruptEnableRegisterOffset = 0x43 +} +DAC960_V3_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V3 Inbound Door Bell Register. +*/ + +typedef union DAC960_V3_InboundDoorBellRegister +{ + unsigned char All; + struct { + boolean NewCommand:1; /* Bit 0 */ + boolean AcknowledgeStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + unsigned char :4; /* Bits 4-7 */ + } Write; + struct { + boolean MailboxFull:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V3_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V3 Outbound Door Bell Register. +*/ + +typedef union DAC960_V3_OutboundDoorBellRegister +{ + unsigned char All; + struct { + boolean AcknowledgeInterrupt:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Write; + struct { + boolean StatusAvailable:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V3_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V3 Interrupt Enable Register. +*/ + +typedef union DAC960_V3_InterruptEnableRegister +{ + unsigned char All; + struct { + boolean EnableInterrupts:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Bits; +} +DAC960_V3_InterruptEnableRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V3 Controller Interface Registers. +*/ + +static inline +void DAC960_V3_NewCommand(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.NewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeStatus = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.MailboxFull; +} + +static inline +void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.StatusAvailable; +} + +static inline +void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = 0; + InterruptEnableRegister.Bits.EnableInterrupts = true; + writeb(InterruptEnableRegister.All, + ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); +} + +static inline +void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = 0; + InterruptEnableRegister.Bits.EnableInterrupts = false; + writeb(InterruptEnableRegister.All, + ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); +} + +static inline +boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = + readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); + return InterruptEnableRegister.Bits.EnableInterrupts; +} + +static inline +void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V3_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset); +} + + +/* + Define compatibility macros between Linux 2.0 and Linux 2.1. +*/ + +#if LINUX_VERSION_CODE < 0x20100 + +#define MODULE_PARM(Variable, Type) +#define ioremap_nocache(Offset, Size) vremap(Offset, Size) +#define iounmap(Address) vfree(Address) + +#endif + + +/* + Define prototypes for the forward referenced DAC960 Driver Internal Functions. +*/ + +static void DAC960_FinalizeController(DAC960_Controller_T *); +static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *); +static void DAC960_RequestFunction0(void); +static void DAC960_RequestFunction1(void); +static void DAC960_RequestFunction2(void); +static void DAC960_RequestFunction3(void); +static void DAC960_RequestFunction4(void); +static void DAC960_RequestFunction5(void); +static void DAC960_RequestFunction6(void); +static void DAC960_RequestFunction7(void); +static void DAC960_InterruptHandler(int, void *, Registers_T *); +static void DAC960_QueueMonitoringCommand(DAC960_Command_T *); +static void DAC960_MonitoringTimerFunction(unsigned long); +static int DAC960_Open(Inode_T *, File_T *); +static int DAC960_Release(Inode_T *, File_T *); +static int DAC960_IOCTL(Inode_T *, File_T *, unsigned int, unsigned long); +static int DAC960_UserIOCTL(Inode_T *, File_T *, unsigned int, unsigned long); +static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *); +static void DAC960_Message(DAC960_MessageLevel_T, char *, + DAC960_Controller_T *, ...); +static void DAC960_CreateProcEntries(void); +static void DAC960_DestroyProcEntries(void); + + +/* + Export the Kernel Mode IOCTL interface. +*/ + +EXPORT_SYMBOL(DAC960_KernelIOCTL); + + +#endif /* DAC960_DriverVersion */ diff -u --recursive --new-file v2.3.15/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.15/linux/drivers/block/Makefile Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/Makefile Mon Aug 30 10:24:14 1999 @@ -20,7 +20,7 @@ L_TARGET := block.a -L_OBJS := genhd.o +L_OBJS := genhd.o cmos-probe.o M_OBJS := MOD_LIST_NAME := BLOCK_MODULES LX_OBJS := ll_rw_blk.o blkpg.o @@ -154,6 +154,10 @@ IDE_OBJS += ht6560b.o endif +ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y) +IDE_OBJS += icside.o +endif + ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) IDE_OBJS += ide-dma.o endif @@ -194,6 +198,10 @@ IDE_OBJS += qd6580.o endif +ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y) +IDE_OBJS += rapide.o +endif + ifeq ($(CONFIG_BLK_DEV_RZ1000),y) IDE_OBJS += rz1000.o endif @@ -218,14 +226,6 @@ IDE_OBJS += via82c586.o endif -ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y) -IDE_OBJS += icside.o -endif - -ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y) -IDE_OBJS += rapide.o -endif - ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored ifeq ($(CONFIG_PROC_FS),y) @@ -299,6 +299,14 @@ else ifeq ($(CONFIG_BLK_CPQ_DA),m) M_OBJS += cpqarray.o + endif +endif + +ifeq ($(CONFIG_BLK_DEV_DAC960),y) +LX_OBJS += DAC960.o +else + ifeq ($(CONFIG_BLK_DEV_DAC960),m) + MX_OBJS += DAC960.o endif endif diff -u --recursive --new-file v2.3.15/linux/drivers/block/aec6210.c linux/drivers/block/aec6210.c --- v2.3.15/linux/drivers/block/aec6210.c Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/aec6210.c Mon Aug 30 10:18:40 1999 @@ -50,11 +50,11 @@ #include #include -__initfunc(unsigned int pci_init_aec6210 (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) { - if (dev->rom_address) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address); + if (dev->resource[PCI_ROM_RESOURCE].start) { + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } return dev->irq; } diff -u --recursive --new-file v2.3.15/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c --- v2.3.15/linux/drivers/block/alim15x3.c Thu Jul 1 10:25:38 1999 +++ linux/drivers/block/alim15x3.c Thu Aug 26 13:55:41 1999 @@ -110,7 +110,7 @@ } -__initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) { byte confreg0 = 0, confreg1 =0, progif = 0; int errors = 0; @@ -194,7 +194,7 @@ return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -__initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif)) +void __init ide_init_ali15x3 (ide_hwif_t *hwif) { struct pci_dev *dev; byte ideic, inmir, iderev; diff -u --recursive --new-file v2.3.15/linux/drivers/block/cmos-probe.c linux/drivers/block/cmos-probe.c --- v2.3.15/linux/drivers/block/cmos-probe.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cmos-probe.c Thu Aug 26 13:44:03 1999 @@ -0,0 +1,78 @@ +/* + * linux/drivers/block/cmos-probe.c Version 1.00 August 16, 1999 + * + * Copyright (C) 1994-1999 Linus Torvalds & authors (see below) + */ + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include + +/* + * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc + * controller that is BIOS compatible with ST-506, and thus showing up in our + * BIOS table, but not register compatible, and therefore not present in CMOS. + * + * Furthermore, we will assume that our ST-506 drives are the primary + * drives in the system -- the ones reflected as drive 1 or 2. The first + * drive is stored in the high nibble of CMOS byte 0x12, the second in the low + * nibble. This will be either a 4 bit drive type or 0xf indicating use byte + * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value + * means we have an AT controller hard disk for that drive. + * + * Of course, there is no guarantee that either drive is actually on the + * "primary" IDE interface, but we don't bother trying to sort that out here. + * If a drive is not actually on the primary interface, then these parameters + * will be ignored. This results in the user having to supply the logical + * drive geometry as a boot parameter for each drive not on the primary i/f. + * + * The only "perfect" way to handle this would be to modify the setup.[cS] code + * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info + * for us during initialization. I have the necessary docs -- any takers? -ml + */ +void probe_cmos_for_drives (ide_hwif_t *hwif) +{ +#ifdef __i386__ + extern struct drive_info_struct drive_info; + byte cmos_disks, *BIOS = (byte *) &drive_info; + int unit; + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) + return; +#endif /* CONFIG_BLK_DEV_PDC4030 */ + outb_p(0x12,0x70); /* specify CMOS address 0x12 */ + cmos_disks = inb_p(0x71); /* read the data from 0x12 */ + /* Extract drive geometry from CMOS+BIOS if not already setup */ + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) { + drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; + drive->head = drive->bios_head = *(BIOS+2); + drive->sect = drive->bios_sect = *(BIOS+14); + drive->ctl = *(BIOS+8); + drive->present = 1; + } + BIOS += 16; + } +#endif +} diff -u --recursive --new-file v2.3.15/linux/drivers/block/cy82c693.c linux/drivers/block/cy82c693.c --- v2.3.15/linux/drivers/block/cy82c693.c Wed Jun 2 22:21:51 1999 +++ linux/drivers/block/cy82c693.c Thu Aug 26 13:55:57 1999 @@ -369,6 +369,17 @@ /* * this function is called during init and is used to setup the cy82c693 chip */ +/* + * FIXME! "pci_init_cy82c693" really should replace + * the "init_cy82c693_chip", it is the correct location to tinker/setup + * the device prior to INIT. + */ + +unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name) +{ + return 0; +} + static void init_cy82c693_chip (struct pci_dev *dev) { static int initDone = 0; @@ -420,7 +431,7 @@ /* * the init function - called for each ide channel once */ -__initfunc(void ide_init_cy82c693(ide_hwif_t *hwif)) +void __init ide_init_cy82c693(ide_hwif_t *hwif) { hwif->chipset = ide_cy82c693; if (hwif->dma_base) diff -u --recursive --new-file v2.3.15/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.3.15/linux/drivers/block/genhd.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/block/genhd.c Mon Aug 30 10:24:14 1999 @@ -18,6 +18,9 @@ extern int parport_init(void); extern int chr_dev_init(void); extern int blk_dev_init(void); +#ifdef CONFIG_BLK_DEV_DAC960 +extern void DAC960_Initialize(void); +#endif extern int scsi_dev_init(void); extern int net_dev_init(void); extern void console_map_init(void); @@ -39,6 +42,9 @@ chr_dev_init(); blk_dev_init(); sti(); +#ifdef CONFIG_BLK_DEV_DAC960 + DAC960_Initialize(); +#endif #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ soc_probe(); @@ -49,7 +55,7 @@ #ifdef CONFIG_BLK_CPQ_DA cpqarray_init(); #endif -#ifdef CONFIG_INET +#ifdef CONFIG_NET net_dev_init(); #endif #ifdef CONFIG_ATM diff -u --recursive --new-file v2.3.15/linux/drivers/block/hpt34x.c linux/drivers/block/hpt34x.c --- v2.3.15/linux/drivers/block/hpt34x.c Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/hpt34x.c Mon Aug 30 10:18:40 1999 @@ -340,16 +340,16 @@ */ #define HPT34X_PCI_INIT_REG 0x80 -__initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) { unsigned short cmd; pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); pci_read_config_word(dev, PCI_COMMAND, &cmd); if (cmd & PCI_COMMAND_MEMORY) { - if (dev->rom_address) { - pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address); + if (dev->resource[PCI_ROM_RESOURCE].start) { + pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start); } pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } else { @@ -377,7 +377,7 @@ return dev->irq; } -__initfunc(void ide_init_hpt34x (ide_hwif_t *hwif)) +void __init ide_init_hpt34x (ide_hwif_t *hwif) { hwif->tuneproc = &hpt34x_tune_drive; if (hwif->dma_base) { @@ -385,7 +385,9 @@ pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); #ifdef CONFIG_BLK_DEV_HPT34X_DMA +#if 0 hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; +#endif #endif /* CONFIG_BLK_DEV_HPT34X_DMA */ hwif->dmaproc = &hpt34x_dmaproc; } else { diff -u --recursive --new-file v2.3.15/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c --- v2.3.15/linux/drivers/block/hpt366.c Fri Aug 6 11:16:54 1999 +++ linux/drivers/block/hpt366.c Thu Aug 26 13:56:31 1999 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/hpt366.c Version 0.11 August 04, 1999 + * linux/drivers/block/hpt366.c Version 0.12 August 16, 1999 * - * Copyright (C) 1999 Andre Hedrick + * Copyright (C) 1999 Andre Hedrick * * drive_number * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); @@ -29,7 +29,6 @@ const char *bad_ata66_4[] = { "WDC AC310200R", - "QUANTUM FIREBALLP KA13.6", NULL }; @@ -115,7 +114,7 @@ }; #define HPT366_DEBUG_DRIVE_INFO 0 -#define HPT366_ALLOW_ATA66_4 1 +#define HPT366_ALLOW_ATA66_4 0 #define HPT366_ALLOW_ATA66_3 1 #define HPT366_ALLOW_ATA33_2 1 #define HPT366_ALLOW_ATA33_1 1 @@ -421,10 +420,9 @@ } /* - * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. * - * This is specific to the HPT343 UDMA bios-less chipset - * and HPT345 UDMA bios chipset (stamped HPT363) + * This is specific to the HPT366 UDMA bios chipset * by HighPoint|Triones Technologies, Inc. */ @@ -463,7 +461,7 @@ return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -__initfunc(unsigned int pci_init_hpt366 (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) { byte ata66 = 0; @@ -474,7 +472,7 @@ return dev->irq; } -__initfunc(void ide_init_hpt366 (ide_hwif_t *hwif)) +void __init ide_init_hpt366 (ide_hwif_t *hwif) { hwif->tuneproc = &hpt366_tune_drive; if (hwif->dma_base) { diff -u --recursive --new-file v2.3.15/linux/drivers/block/icside.c linux/drivers/block/icside.c --- v2.3.15/linux/drivers/block/icside.c Thu Jul 1 10:25:38 1999 +++ linux/drivers/block/icside.c Thu Aug 26 13:44:03 1999 @@ -299,24 +299,7 @@ drive->drive_data = 250; } -#if 1 err = ide_config_drive_speed(drive, (byte) speed); -#else - /* - * Don't use ide_wait_cmd here - it will - * attempt to set_geometry and recalibrate, - * but for some reason these don't work at - * this point (lost interrupt). - */ - SELECT_DRIVE(hwif, drive); - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); - OUT_BYTE(speed, IDE_NSECTOR_REG); - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - - err = ide_wait_stat(drive, DRIVE_READY, - BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); -#endif if (err == 0) { drive->id->dma_mword &= 0x00ff; diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.3.15/linux/drivers/block/ide-cd.c Mon Aug 9 12:34:22 1999 +++ linux/drivers/block/ide-cd.c Tue Aug 31 16:05:22 1999 @@ -12,11 +12,13 @@ * * Suggestions are welcome. Patches that work are more welcome though. ;-) * For those wishing to work on this driver, please be sure you download - * and comply with the latest ATAPI standard. This document can be - * obtained by anonymous ftp from: - * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps + * and comply with the latest Mt. Fuji (SFF8090 version 3) and ATAPI + * (SFF-8020i rev 2.6) standards. These documents can be obtained by + * anonymous ftp from: + * ftp://fission.dt.wdc.com/pub/standards/SFF/specs/INF-8020.PDF + * ftp://fission.dt.wdc.com/pub/standards/SFF/specs/INF-8090.PDF * - * Drives that deviate from the ATAPI standard will be accomodated as much + * Drives that deviate from these standards will be accomodated as much * as possible via compile time or command-line options. Since I only have * a few drives, you generally need to send me patches... * @@ -255,11 +257,26 @@ * cd-rom drivers. don't report select disc for * non-changers as well. * - mask out audio playing, if the device can't do it. - * + * + * 4.55 Sep 1, 1999 - Eliminated the rest of the audio ioctls, except + * for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers + * use this independently of the actual audio handling. + * They will disappear later when I get the time to + * do it cleanly. + * - Minimize the TOC reading - only do it when we + * know a media change has occured. + * - Moved all the CDROMREADx ioctls to the Uniform layer. + * - Heiko Eissfeldt supplied + * some fixes for CDI. + * - CD-ROM leaving door locked fix from Andries + * Brouwer + * - Erik Andersen unified + * commands across the various drivers and how + * sense errors are handled. * *************************************************************************/ -#define IDECD_VERSION "4.54" +#define IDECD_VERSION "4.55" #include #include @@ -316,12 +333,12 @@ uses this command to poll the drive, and we don't want to fill the syslog with useless errors. */ if (failed_command && - failed_command->c[0] == SCMD_READ_SUBCHANNEL) + failed_command->c[0] == GPCMD_READ_SUBCHANNEL) return; } if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 - && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || - (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) + && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || + (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) { /* * Suppress the following errors: @@ -358,15 +375,16 @@ s = buf; } else { int lo=0, mid, hi=ARY_LEN (sense_data_texts); - unsigned short key = (reqbuf->asc << 8); + unsigned long key = (reqbuf->sense_key << 16); + key |= (reqbuf->asc << 8); if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) key |= reqbuf->ascq; - s = NULL; while (hi > lo) { mid = (lo + hi) / 2; - if (sense_data_texts[mid].asc_ascq == key) { + if (sense_data_texts[mid].asc_ascq == key || + sense_data_texts[mid].asc_ascq == (0xff0000|key)) { s = sense_data_texts[mid].text; break; } @@ -487,7 +505,7 @@ len = sizeof (*reqbuf) / 4; len *= 4; - pc->c[0] = REQUEST_SENSE; + pc->c[0] = GPCMD_REQUEST_SENSE; pc->c[4] = (unsigned char) len; pc->buffer = (char *)reqbuf; pc->buflen = len; @@ -577,7 +595,7 @@ because workman constantly polls the drive with this command, and we don't want to uselessly fill up the syslog. */ - if (pc->c[0] != SCMD_READ_SUBCHANNEL) + if (pc->c[0] != GPCMD_READ_SUBCHANNEL) printk ("%s: tray open or drive not ready\n", drive->name); #endif } else if (sense_key == UNIT_ATTENTION) { @@ -1073,7 +1091,7 @@ /* Set up the command */ memset (&pc.c, 0, sizeof (pc.c)); - pc.c[0] = READ_10; + pc.c[0] = GPCMD_READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); @@ -1118,7 +1136,7 @@ frame = sector / SECTORS_PER_FRAME; memset (&pc.c, 0, sizeof (pc.c)); - pc.c[0] = SEEK; + pc.c[0] = GPCMD_SEEK; put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr); } @@ -1202,7 +1220,7 @@ if ((stat & DRQ_STAT) == 0) { /* Some of the trailing request sense fields are optional, and some drives don't send them. Sigh. */ - if (pc->c[0] == REQUEST_SENSE && + if (pc->c[0] == GPCMD_REQUEST_SENSE && pc->buflen > 0 && pc->buflen <= 5) { while (pc->buflen > 0) { @@ -1372,10 +1390,10 @@ a disk. Retry, but wait a little to give the drive time to complete the load. */ cdrom_sleep (HZ); - } else + } else { /* Otherwise, don't retry. */ retries = 0; - + } --retries; } @@ -1392,12 +1410,13 @@ and we think that the door is presently, lock it again. (The door was probably unlocked via an explicit CDROMEJECT ioctl.) */ - if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && drive->usage && - (pc->c[0] != REQUEST_SENSE && - pc->c[0] != ALLOW_MEDIUM_REMOVAL && - pc->c[0] != START_STOP && - pc->c[0] != MODE_SENSE_10 && - pc->c[0] != MODE_SELECT_10)) { + if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && + (pc->c[0] != GPCMD_TEST_UNIT_READY && + pc->c[0] != GPCMD_REQUEST_SENSE && + pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && + pc->c[0] != GPCMD_START_STOP_UNIT && + pc->c[0] != GPCMD_MODE_SENSE_10 && + pc->c[0] != GPCMD_MODE_SELECT_10)) { (void) cdrom_lockdoor (drive, 1, NULL); } return 0; @@ -1508,7 +1527,7 @@ memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = TEST_UNIT_READY; + pc.c[0] = GPCMD_TEST_UNIT_READY; #if ! STANDARD_ATAPI /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to @@ -1540,7 +1559,7 @@ memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = ALLOW_MEDIUM_REMOVAL; + pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); stat = cdrom_queue_packet_command (drive, &pc); } @@ -1585,7 +1604,7 @@ memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = START_STOP; + pc.c[0] = GPCMD_START_STOP_UNIT; pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc); } @@ -1605,7 +1624,7 @@ memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = READ_CAPACITY; + pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; pc.buflen = sizeof (capbuf); @@ -1629,7 +1648,7 @@ pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = SCMD_READ_TOC; + pc.c[0] = GPCMD_READ_TOC_PMA_ATIP; pc.c[6] = trackno; pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); @@ -1657,11 +1676,10 @@ toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), GFP_KERNEL); info->toc = toc; - } - - if (toc == NULL) { - printk ("%s: No cdrom TOC buffer!\n", drive->name); - return -EIO; + if (toc == NULL) { + printk ("%s: No cdrom TOC buffer!\n", drive->name); + return -ENOMEM; + } } /* Check to see if the existing data is still valid. @@ -1673,9 +1691,7 @@ /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header) + - sizeof (struct atapi_toc_entry), - reqbuf); + sizeof (struct atapi_toc_header), reqbuf); if (stat) return stat; #if ! STANDARD_ATAPI @@ -1690,12 +1706,46 @@ if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; /* Now read the whole schmeer. */ - stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, + stat = cdrom_read_tocentry (drive, toc->hdr.first_track-1, 1, 0, + (char *)&toc->hdr, sizeof (struct atapi_toc_header) + (ntracks+1) * - sizeof (struct atapi_toc_entry), - reqbuf); - if (stat) return stat; + sizeof (struct atapi_toc_entry), reqbuf); + + if (stat && toc->hdr.first_track > 1) { + /* Cds with CDI tracks only don't have any TOC entries, + despite of this the returned values are + first_track == last_track = number of CDI tracks + 1, + so that this case is indistinguishable from the same + layout plus an additional audio track. + If we get an error for the regular case, we assume + a CDI without additional audio tracks. In this case + the readable TOC is empty (CDI tracks are not included) + and only holds the Leadout entry. Heiko Eißfeldt */ + ntracks = 0; + stat = cdrom_read_tocentry (drive, CDROM_LEADOUT, 1, + 0, (char *)&toc->hdr, + sizeof (struct atapi_toc_header) + + (ntracks+1) * + sizeof (struct atapi_toc_entry), + reqbuf); + if (stat) { + return stat; + } +#if ! STANDARD_ATAPI + if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) { + toc->hdr.first_track = bin2bcd(CDROM_LEADOUT); + toc->hdr.last_track = bin2bcd(CDROM_LEADOUT); + } else +#endif /* not STANDARD_ATAPI */ + { + toc->hdr.first_track = CDROM_LEADOUT; + toc->hdr.last_track = CDROM_LEADOUT; + } + } else if (stat) { + return stat; + } + toc->hdr.toc_length = ntohs (toc->hdr.toc_length); #if ! STANDARD_ATAPI @@ -1719,10 +1769,18 @@ } /* Read the multisession information. */ - stat = cdrom_read_tocentry (drive, 0, 1, 1, - (char *)&ms_tmp, sizeof (ms_tmp), - reqbuf); - if (stat) return stat; + if (toc->hdr.first_track != CDROM_LEADOUT) { + /* Read the multisession information. */ + stat = cdrom_read_tocentry (drive, toc->hdr.first_track-1, 1, 1, + (char *)&ms_tmp, sizeof (ms_tmp), + reqbuf); + if (stat) return stat; + } else { + ms_tmp.ent.addr.msf.minute = 0; + ms_tmp.ent.addr.msf.second = 2; + ms_tmp.ent.addr.msf.frame = 0; + ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT; + } #if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) @@ -1736,7 +1794,10 @@ toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); /* Now try to get the total cdrom capacity. */ - stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); + stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major, + drive->select.b.unit << PARTN_BITS), + (long *)&toc->capacity); + if (stat) stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); if (stat) toc->capacity = 0x1fffff; HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] @@ -1762,7 +1823,7 @@ pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = SCMD_READ_SUBCHANNEL; + pc.c[0] = GPCMD_READ_SUBCHANNEL; pc.c[1] = 2; /* MSF addressing */ pc.c[2] = 0x40; /* request subQ data */ pc.c[3] = format; @@ -1785,7 +1846,7 @@ pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = MODE_SENSE_10; + pc.c[0] = GPCMD_MODE_SENSE_10; pc.c[2] = pageno | (modeflag << 6); pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); @@ -1803,7 +1864,7 @@ pc.buffer = buf; pc.buflen = - buflen; - pc.c[0] = MODE_SELECT_10; + pc.c[0] = GPCMD_MODE_SELECT_10; pc.c[1] = 0x10; pc.c[2] = pageno; pc.c[7] = (buflen >> 8); @@ -1826,7 +1887,7 @@ else speed *= 177; /* Nx to kbytes/s */ - pc.c[0] = SET_CD_SPEED; + pc.c[0] = GPCMD_SET_SPEED; /* Read Drive speed in kbytes/second MSB */ pc.c[2] = (speed >> 8) & 0xff; /* Read Drive speed in kbytes/second LSB */ @@ -1842,67 +1903,6 @@ return cdrom_queue_packet_command (drive, &pc); } -static int -cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = SCMD_PLAYAUDIO_MSF; - lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); - lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]); - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd) { - pc.c[3] = bin2bcd (pc.c[3]); - pc.c[4] = bin2bcd (pc.c[4]); - pc.c[5] = bin2bcd (pc.c[5]); - pc.c[6] = bin2bcd (pc.c[6]); - pc.c[7] = bin2bcd (pc.c[7]); - pc.c[8] = bin2bcd (pc.c[8]); - } -#endif /* not STANDARD_ATAPI */ - - return cdrom_queue_packet_command (drive, &pc); -} - - -/* Play audio starting at LBA LBA_START and finishing with the - LBA before LBA_END. */ -static int -cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - int i, stat = 0; - struct atapi_request_sense my_reqbuf; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - /* Some drives, will, for certain audio cds, - give an error if you ask them to play the entire cd using the - values which are returned in the TOC. The play will succeed, - however, if the ending address is adjusted downwards - by a few frames. */ - for (i=0; i<75; i++) { - stat = cdrom_play_lba_range_1 (drive, lba_start, lba_end, - reqbuf); - - if (stat == 0 || - !(reqbuf->sense_key == ILLEGAL_REQUEST && - reqbuf->asc == 0x24)) - return stat; - - --lba_end; - if (lba_end <= lba_start) break; - } - - return stat; -} - static int cdrom_get_toc_entry (ide_drive_t *drive, int track, @@ -1910,17 +1910,12 @@ struct atapi_request_sense *reqbuf) { struct cdrom_info *info = drive->driver_data; - int stat, ntracks; - struct atapi_toc *toc; - - /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc (drive, reqbuf); - if (stat) return stat; - - toc = info->toc; + struct atapi_toc *toc = info->toc; + int ntracks; /* Check validity of requested track number. */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; + if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0; if (track == CDROM_LEADOUT) *ent = &toc->ent[ntracks]; else if (track < toc->hdr.first_track || @@ -1933,44 +1928,6 @@ } -static int -cdrom_read_block (ide_drive_t *drive, int format, int lba, int nblocks, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - struct atapi_request_sense my_reqbuf; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->nec260) - pc.c[0] = 0xd4; - else -#endif /* not STANDARD_ATAPI */ - pc.c[0] = READ_CD; - - pc.c[1] = (format << 2); - put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]); - pc.c[8] = (nblocks & 0xff); - pc.c[7] = ((nblocks>>8) & 0xff); - pc.c[6] = ((nblocks>>16) & 0xff); - if (format <= 1) - pc.c[9] = 0xf8; /* returns 2352 for any format */ - else - pc.c[9] = 0x10; - - return cdrom_queue_packet_command (drive, &pc); -} - - /* If SLOT<0, unload the current slot. Otherwise, try to load SLOT. */ static int cdrom_load_unload (ide_drive_t *drive, int slot, @@ -2005,7 +1962,7 @@ memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = LOAD_UNLOAD; + pc.c[0] = GPCMD_LOAD_UNLOAD; pc.c[4] = 2 + (slot >= 0); pc.c[8] = slot; return cdrom_queue_packet_command (drive, &pc); @@ -2026,7 +1983,7 @@ pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = MECHANISM_STATUS; + pc.c[0] = GPCMD_MECHANISM_STATUS; pc.c[8] = (buflen >> 8); pc.c[9] = (buflen & 0xff); return cdrom_queue_packet_command (drive, &pc); @@ -2098,124 +2055,8 @@ { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; - switch (cmd) { - case CDROMREADRAW: - case CDROMREADMODE1: - case CDROMREADMODE2: { - struct cdrom_msf msf; - int blocksize, format, stat, lba; - struct atapi_toc *toc; - char *buf; - - if (cmd == CDROMREADMODE1) { - blocksize = CD_FRAMESIZE; - format = 2; - } else { /* for RAW and MODE2. */ - blocksize = CD_FRAMESIZE_RAW; - format = 0; - } - - copy_from_user_ret(&msf, (void *)arg, sizeof (msf), -EFAULT); - - lba = msf_to_lba(msf.cdmsf_min0, - msf.cdmsf_sec0, - msf.cdmsf_frame0); - - /* Make sure the TOC is up to date. */ - if (cmd != CDROMREADRAW) { - stat = cdrom_read_toc (drive, NULL); - if (stat) - return stat; - - toc = info->toc; - - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; - } - - buf = (char *) kmalloc (blocksize, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - stat = cdrom_read_block (drive, format, lba, 1, buf, - blocksize, NULL); - - if (stat == 0) { - if (cmd == CDROMREADMODE2) { - /* For Mode2, skip the Sync, Header, and Subheader */ - copy_to_user_ret((char *)arg, buf+16, CD_FRAMESIZE_RAW0, -EFAULT); - } else { - copy_to_user_ret((char *)arg, buf, blocksize, -EFAULT); - } - } - - kfree (buf); - return stat; - } - - /* Read 2352 byte blocks from audio tracks. */ - case CDROMREADAUDIO: { - int stat, lba; - struct atapi_toc *toc; - struct cdrom_read_audio ra; - char *buf; - - /* Make sure the TOC is up to date. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - - toc = info->toc; - - if (copy_from_user(&ra, (void *)arg, sizeof (ra))) - return -EFAULT; - - if (ra.nframes < 0 || ra.nframes > toc->capacity) - return -EINVAL; - else if (ra.nframes == 0) - return 0; - - if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes * CD_FRAMESIZE_RAW)) - return -EFAULT; - - if (ra.addr_format == CDROM_MSF) - lba = msf_to_lba (ra.addr.msf.minute, - ra.addr.msf.second, - ra.addr.msf.frame); - else if (ra.addr_format == CDROM_LBA) - lba = ra.addr.lba; - else - return -EINVAL; - - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; - - buf = (char *) kmalloc (CDROM_NBLOCKS_BUFFER*CD_FRAMESIZE_RAW, - GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - while (ra.nframes > 0) { - int this_nblocks = ra.nframes; - if (this_nblocks > CDROM_NBLOCKS_BUFFER) - this_nblocks = CDROM_NBLOCKS_BUFFER; - stat = cdrom_read_block - (drive, 1, lba, this_nblocks, - buf, this_nblocks * CD_FRAMESIZE_RAW, NULL); - if (stat) break; - - __copy_to_user(ra.buf, buf,this_nblocks * CD_FRAMESIZE_RAW); - ra.buf += this_nblocks * CD_FRAMESIZE_RAW; - ra.nframes -= this_nblocks; - lba += this_nblocks; - } - - kfree (buf); - return stat; - } - case CDROMSETSPINDOWN: { char spindown; char buffer[16]; @@ -2224,13 +2065,13 @@ if (copy_from_user(&spindown, (void *) arg, sizeof(char))) return -EFAULT; - stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, + stat = cdrom_mode_sense (drive, GPMODE_CDROM_PAGE, 0, buffer, sizeof (buffer), NULL); if (stat) return stat; buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f); - return cdrom_mode_select (drive, PAGE_CDROM, buffer, + return cdrom_mode_select (drive, GPMODE_CDROM_PAGE, buffer, sizeof (buffer), NULL); } @@ -2239,7 +2080,7 @@ char buffer[16]; int stat; - stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, + stat = cdrom_mode_sense (drive, GPMODE_CDROM_PAGE, 0, buffer, sizeof (buffer), NULL); if (stat) return stat; @@ -2251,64 +2092,12 @@ return 0; } -#ifdef ALLOW_TEST_PACKETS - case 0x1234: { - int stat; - struct packet_command pc; - int len, lena; - - memset (&pc, 0, sizeof (pc)); - - if (copy_from_user(&pc.c, (void *) arg, sizeof (pc.c))) - return -EFAULT; - - arg += sizeof (pc.c); - - if (copy_from_user (&len, (void *) arg , sizeof (len))) - return -EFAULT; - - arg += sizeof (len); - - lena = len; - if (lena < 0) lena = -lena; - - { - char buf[lena]; - if (len > 0) { - stat = verify_area (VERIFY_WRITE, - (void *) arg, len); - if (stat) return stat; - } - else if (len < 0) { - stat = verify_area (VERIFY_READ, - (void *) arg, -len); - if (stat) return stat; - copy_from_user (buf, (void*)arg, -len); - } - - if (len != 0) { - pc.buflen = len; - pc.buffer = buf; - } - - stat = cdrom_queue_packet_command (drive, &pc); - - if (len > 0) - copy_to_user ((void *)arg, buf, len); - } - - return stat; - } -#endif - default: return -EINVAL; } } - - static int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, unsigned int cmd, void *arg) @@ -2318,47 +2107,6 @@ struct cdrom_info *info = drive->driver_data; switch (cmd) { - case CDROMSUBCHNL: { - struct atapi_cdrom_subchnl scbuf; - int stat; - struct cdrom_subchnl *subchnl = (struct cdrom_subchnl *)arg; - - stat = cdrom_read_subchannel (drive, 1, /* current position */ - (char *)&scbuf, sizeof (scbuf), - NULL); - if (stat) return stat; - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd) { - msf_from_bcd (&scbuf.acdsc_absaddr.msf); - msf_from_bcd (&scbuf.acdsc_reladdr.msf); - } - if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) - scbuf.acdsc_trk = bcd2bin (scbuf.acdsc_trk); -#endif /* not STANDARD_ATAPI */ - - subchnl->cdsc_absaddr.msf.minute = - scbuf.acdsc_absaddr.msf.minute; - subchnl->cdsc_absaddr.msf.second = - scbuf.acdsc_absaddr.msf.second; - subchnl->cdsc_absaddr.msf.frame = - scbuf.acdsc_absaddr.msf.frame; - - subchnl->cdsc_reladdr.msf.minute = - scbuf.acdsc_reladdr.msf.minute; - subchnl->cdsc_reladdr.msf.second = - scbuf.acdsc_reladdr.msf.second; - subchnl->cdsc_reladdr.msf.frame = - scbuf.acdsc_reladdr.msf.frame; - - subchnl->cdsc_audiostatus = scbuf.acdsc_audiostatus; - subchnl->cdsc_ctrl = scbuf.acdsc_ctrl; - subchnl->cdsc_trk = scbuf.acdsc_trk; - subchnl->cdsc_ind = scbuf.acdsc_ind; - - return 0; - } - case CDROMREADTOCHDR: { int stat; struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; @@ -2386,55 +2134,22 @@ tocentry->cdte_ctrl = toce->control; tocentry->cdte_adr = toce->adr; - tocentry->cdte_format = CDROM_LBA; - tocentry->cdte_addr.lba = toce->addr.lba; + if (tocentry->cdte_format == CDROM_MSF) { + lba_to_msf (toce->addr.lba, + &tocentry->cdte_addr.msf.minute, + &tocentry->cdte_addr.msf.second, + &tocentry->cdte_addr.msf.frame); + } else + tocentry->cdte_addr.lba = toce->addr.lba; return 0; } - case CDROMPLAYMSF: { - struct cdrom_msf *msf = (struct cdrom_msf *) arg; - int lba_start, lba_end; - - lba_start = msf_to_lba (msf->cdmsf_min0, msf->cdmsf_sec0, - msf->cdmsf_frame0); - lba_end = msf_to_lba (msf->cdmsf_min1, msf->cdmsf_sec1, - msf->cdmsf_frame1) + 1; - - if (lba_end <= lba_start) return -EINVAL; - - return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); - } - - /* Like just about every other Linux cdrom driver, we ignore the - index part of the request here. */ - case CDROMPLAYTRKIND: { - int stat, lba_start, lba_end; - struct cdrom_ti *ti = (struct cdrom_ti *)arg; - struct atapi_toc_entry *first_toc, *last_toc; - - stat = cdrom_get_toc_entry (drive, ti->cdti_trk0, &first_toc, - NULL); - if (stat) return stat; - stat = cdrom_get_toc_entry (drive, ti->cdti_trk1, &last_toc, - NULL); - if (stat) return stat; - - if (ti->cdti_trk1 != CDROM_LEADOUT) ++last_toc; - lba_start = first_toc->addr.lba; - lba_end = last_toc->addr.lba; - - if (lba_end <= lba_start) return -EINVAL; - - return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); - } - default: return -EINVAL; } } - static int ide_cdrom_reset (struct cdrom_device_info *cdi) { @@ -2486,7 +2201,7 @@ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ if (attempts-- <= 0) return 0; - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, + stat = cdrom_mode_sense (drive, GPMODE_CAPABILITIES_PAGE, 0, (char *)&buf, sizeof (buf), NULL); } while (stat); @@ -2579,12 +2294,6 @@ if (stat && my_reqbuf.sense_key == NOT_READY) return -ENOENT; - if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) { - stat = cdrom_read_toc (drive, &my_reqbuf); - if (stat) - return stat; - } - if (was_locked) (void) cdrom_lockdoor (drive, 1, NULL); @@ -2639,15 +2348,10 @@ int ide_cdrom_get_last_session (struct cdrom_device_info *cdi, struct cdrom_multisession *ms_info) { - int stat; struct atapi_toc *toc; ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct cdrom_info *info = drive->driver_data; - /* Make sure the TOC information is valid. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - toc = info->toc; ms_info->addr.lba = toc->last_session_lba; ms_info->xa_flag = toc->xa_flag; @@ -2655,7 +2359,6 @@ return 0; } - static int ide_cdrom_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn_info) @@ -2689,9 +2392,9 @@ { ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct cdrom_info *info = drive->driver_data; - + struct atapi_request_sense reqbuf; int retval; - + if (slot_nr == CDSL_CURRENT) { (void) cdrom_check_status (drive, NULL); retval = CDROM_STATE_FLAGS (drive)->media_changed; @@ -2717,7 +2420,17 @@ retval = ci->slots[slot_nr].change; } - + + /* if the media has changed, check if a disc is in the drive + and read the toc info. */ + if (retval || !CDROM_STATE_FLAGS (drive)->toc_valid) { + /* if cdrom_read_toc fails, return 1 to indicate + that a disc change has occured. there might not + be a disc in the drive. */ + if ((retval = cdrom_read_toc (drive, &reqbuf))) + return 1; + } + return retval; } @@ -2819,7 +2532,7 @@ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ if (attempts-- <= 0) return 0; - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, + stat = cdrom_mode_sense (drive, GPMODE_CAPABILITIES_PAGE, 0, (char *)&buf, sizeof (buf), NULL); } while (stat); @@ -2989,7 +2702,7 @@ drive->special.all = 0; drive->ready_stat = 0; - CDROM_STATE_FLAGS (drive)->media_changed = 0; + CDROM_STATE_FLAGS (drive)->media_changed = 1; CDROM_STATE_FLAGS (drive)->toc_valid = 0; CDROM_STATE_FLAGS (drive)->door_locked = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h --- v2.3.15/linux/drivers/block/ide-cd.h Wed Aug 18 16:43:30 1999 +++ linux/drivers/block/ide-cd.h Tue Aug 31 16:11:58 1999 @@ -1,9 +1,9 @@ #ifndef _IDE_CD_H #define _IDE_CD_H /* - * linux/drivers/block/ide_modes.h + * linux/drivers/block/ide_cd.h * - * Copyright (C) 1996 Erik Andersen + * Copyright (C) 1996, 1997, 1998 Erik Andersen * Copyright (C) 1998, 1999 Jens Axboe */ @@ -55,65 +55,6 @@ #define REQUEST_SENSE_COMMAND 4316 #define RESET_DRIVE_COMMAND 4317 -/* - * For controlling drive spindown time. - */ -#define CDROMGETSPINDOWN 0x531d -#define CDROMSETSPINDOWN 0x531e - - -/* Some ATAPI command opcodes (just like SCSI). - (Some other cdrom-specific codes are in cdrom.h.) */ -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define INQUIRY 0x12 -#define START_STOP 0x1b -#define ALLOW_MEDIUM_REMOVAL 0x1e -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define SEEK 0x2b -#define READ_HEADER 0x44 -#define STOP_PLAY_SCAN 0x4e -#define MODE_SELECT_10 0x55 -#define MODE_SENSE_10 0x5a -#define LOAD_UNLOAD 0xa6 -#define READ_12 0xa8 -#define READ_CD_MSF 0xb9 -#define SCAN 0xba -#define SET_CD_SPEED 0xbb -#define PLAY_CD 0xbc -#define MECHANISM_STATUS 0xbd -#define READ_CD 0xbe - -/* MMC2/MTFuji Opcodes */ -#define BLANK 0xa1 -#define CLOSE_TRACK 0x5b -#define ERASE 0x2c -#define FORMAT_UNIT 0x04 -#define GET_CONFIGURATION 0x46 -#define GET_EVENT 0xa4 -#define GET_PERFORMANCE 0xac -#define READ_BUFFER 0x3c -#define READ_DISC_INFO 0x51 - -/* Page codes for mode sense/set */ -#define PAGE_READERR 0x01 -#define PAGE_CDROM 0x0d -#define PAGE_AUDIO 0x0e -#define PAGE_CAPABILITIES 0x2a -#define PAGE_ALL 0x3f - -/* ATAPI sense keys (from table 140 of ATAPI 2.6) */ -#define NO_SENSE 0x00 -#define RECOVERED_ERROR 0x01 -#define NOT_READY 0x02 -#define MEDIUM_ERROR 0x03 -#define HARDWARE_ERROR 0x04 -#define ILLEGAL_REQUEST 0x05 -#define UNIT_ATTENTION 0x06 -#define DATA_PROTECT 0x07 -#define ABORTED_COMMAND 0x0b -#define MISCOMPARE 0x0e /* Configuration flags. These describe the capabilities of the drive. They generally do not change after initialization, unless we learn @@ -287,6 +228,9 @@ } mechtype_t; +/* This should probably go into cdrom.h along with the other + * generic stuff now in the Mt. Fuji spec. + */ struct atapi_capabilities_page { #if defined(__BIG_ENDIAN_BITFIELD) __u8 parameters_saveable : 1; @@ -608,11 +552,85 @@ #define ARY_LEN(a) ((sizeof(a) / sizeof(a[0]))) +/* This stuff should be in cdrom.h, since it is now generic... */ + +/* ATAPI sense keys (from table 140 of ATAPI 2.6) */ +#define NO_SENSE 0x00 +#define RECOVERED_ERROR 0x01 +#define NOT_READY 0x02 +#define MEDIUM_ERROR 0x03 +#define HARDWARE_ERROR 0x04 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define DATA_PROTECT 0x07 +#define ABORTED_COMMAND 0x0b +#define MISCOMPARE 0x0e + + + +/* This stuff should be in cdrom.h, since it is now generic... */ #if VERBOSE_IDE_CD_ERRORS -/* From Table 124 of the ATAPI 1.2 spec. - Unchanged in Table 140 of the ATAPI 2.6 draft standard. */ + /* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +const struct { + unsigned short packet_command; + const char * const text; +} packet_command_texts[] = { + { GPCMD_TEST_UNIT_READY, "Test Unit Ready" }, + { GPCMD_REQUEST_SENSE, "Request Sense" }, + { GPCMD_FORMAT_UNIT, "Format Unit" }, + { GPCMD_INQUIRY, "Inquiry" }, + { GPCMD_START_STOP_UNIT, "Start/Stop Unit" }, + { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, + { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" }, + { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" }, + { GPCMD_READ_10, "Read 10" }, + { GPCMD_WRITE_10, "Write 10" }, + { GPCMD_SEEK, "Seek" }, + { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" }, + { GPCMD_VERIFY_10, "Verify 10" }, + { GPCMD_FLUSH_CACHE, "Flush Cache" }, + { GPCMD_READ_SUBCHANNEL, "Read Subchannel" }, + { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" }, + { GPCMD_READ_HEADER, "Read Header" }, + { GPCMD_PLAY_AUDIO_10, "Play Audio 10" }, + { GPCMD_GET_CONFIGURATION, "Get Configuration" }, + { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" }, + { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" }, + { GPCMD_GET_EVENT_STATUS_NOTIFICATION, "Get Event Status Notification" }, + { GPCMD_PAUSE_RESUME, "Pause/Resume" }, + { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" }, + { GPCMD_READ_DISC_INFO, "Read Disc Info" }, + { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" }, + { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" }, + { GPCMD_SEND_OPC, "Send OPC" }, + { GPCMD_MODE_SELECT_10, "Mode Select 10" }, + { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" }, + { GPCMD_MODE_SENSE_10, "Mode Sense 10" }, + { GPCMD_CLOSE_TRACK, "Close Track" }, + { GPCMD_BLANK, "Blank" }, + { GPCMD_SEND_EVENT, "Send Event" }, + { GPCMD_SEND_KEY, "Send Key" }, + { GPCMD_REPORT_KEY, "Report Key" }, + { GPCMD_LOAD_UNLOAD, "Load/Unload" }, + { GPCMD_SET_READ_AHEAD, "Set Read-ahead" }, + { GPCMD_READ_12, "Read 12" }, + { GPCMD_GET_PERFORMANCE, "Get Performance" }, + { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" }, + { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" }, + { GPCMD_SET_STREAMING, "Set Streaming" }, + { GPCMD_READ_CD_MSF, "Read CD MSF" }, + { GPCMD_SCAN, "Scan" }, + { GPCMD_SET_SPEED, "Set Speed" }, + { GPCMD_PLAY_CD, "Play CD" }, + { GPCMD_MECHANISM_STATUS, "Mechanism Status" }, + { GPCMD_READ_CD, "Read CD" }, +}; + + +/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ const char * const sense_key_texts[16] = { "No sense data", "Recovered error", @@ -632,162 +650,108 @@ "(reserved)", }; - -/* From Table 37 of the ATAPI 2.6 draft standard. */ -const struct { - unsigned short packet_command; - const char * const text; -} packet_command_texts[] = { - { TEST_UNIT_READY, "Test Unit Ready" }, - { REQUEST_SENSE, "Request Sense" }, - { INQUIRY, "Inquiry" }, - { START_STOP, "Start Stop Unit" }, - { ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, - { READ_CAPACITY, "Read CD-ROM Capacity" }, - { READ_10, "Read(10)" }, - { SEEK, "Seek" }, - { SCMD_READ_TOC, "Read TOC" }, - { SCMD_READ_SUBCHANNEL, "Read Sub-Channel" }, - { READ_HEADER, "Read Header" }, - { STOP_PLAY_SCAN, "Stop Play/Scan" }, - { SCMD_PLAYAUDIO10, "Play Audio" }, - { SCMD_PLAYAUDIO_MSF, "Play Audio MSF" }, - { SCMD_PAUSE_RESUME, "Pause/Resume" }, - { MODE_SELECT_10, "Mode Select" }, - { MODE_SENSE_10, "Mode Sense" }, - { LOAD_UNLOAD, "Load/Unload CD" }, - { READ_12, "Read(12)" }, - { GET_PERFORMANCE, "Get Performance" }, - { READ_CD_MSF, "Read CD MSF" }, - { SCAN, "Scan" }, - { SET_CD_SPEED, "Set CD Speed" }, - { PLAY_CD, "Play CD" }, - { MECHANISM_STATUS, "Mechanism Status" }, - { READ_CD, "Read CD" }, -}; - - -/* From Table 125 of the ATAPI 1.2 spec., - with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */ - +/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ const struct { - unsigned short asc_ascq; + unsigned long asc_ascq; const char * const text; } sense_data_texts[] = { - { 0x0000, "No additional sense information" }, - - { 0x0011, "Audio play operation in progress" }, - { 0x0012, "Audio play operation paused" }, - { 0x0013, "Audio play operation successfully completed" }, - { 0x0014, "Audio play operation stopped due to error" }, - { 0x0015, "No current audio status to return" }, - - { 0x0100, "Mechanical positioning or changer error" }, - - { 0x0200, "No seek complete" }, - - { 0x0400, "Logical unit not ready - cause not reportable" }, - { 0x0401, - "Logical unit not ready - in progress (sic) of becoming ready" }, - { 0x0402, "Logical unit not ready - initializing command required" }, - { 0x0403, "Logical unit not ready - manual intervention required" }, - - { 0x0501, "Media load - eject failed" }, - - { 0x0600, "No reference position found" }, - - { 0x0900, "Track following error" }, - { 0x0901, "Tracking servo failure" }, - { 0x0902, "Focus servo failure" }, - { 0x0903, "Spindle servo failure" }, - - { 0x1100, "Unrecovered read error" }, - { 0x1106, "CIRC unrecovered error" }, - - { 0x1500, "Random positioning error" }, - { 0x1501, "Mechanical positioning or changer error" }, - { 0x1502, "Positioning error detected by read of medium" }, - - { 0x1700, "Recovered data with no error correction applied" }, - { 0x1701, "Recovered data with retries" }, - { 0x1702, "Recovered data with positive head offset" }, - { 0x1703, "Recovered data with negative head offset" }, - { 0x1704, "Recovered data with retries and/or CIRC applied" }, - { 0x1705, "Recovered data using previous sector ID" }, - - { 0x1800, "Recovered data with error correction applied" }, - { 0x1801, "Recovered data with error correction and retries applied" }, - { 0x1802, "Recovered data - the data was auto-reallocated" }, - { 0x1803, "Recovered data with CIRC" }, - { 0x1804, "Recovered data with L-EC" }, - /* Following two not in 2.6. */ - { 0x1805, "Recovered data - recommend reassignment" }, - { 0x1806, "Recovered data - recommend rewrite" }, - - { 0x1a00, "Parameter list length error" }, - - { 0x2000, "Invalid command operation code" }, - - { 0x2100, "Logical block address out of range" }, - - { 0x2400, "Invalid field in command packet" }, - - { 0x2600, "Invalid field in parameter list" }, - { 0x2601, "Parameter not supported" }, - { 0x2602, "Parameter value invalid" }, - /* Following code not in 2.6. */ - { 0x2603, "Threshold parameters not supported" }, - - { 0x2800, "Not ready to ready transition, medium may have changed" }, - - { 0x2900, "Power on, reset or bus device reset occurred" }, - - { 0x2a00, "Parameters changed" }, - { 0x2a01, "Mode parameters changed" }, - - { 0x3000, "Incompatible medium installed" }, - { 0x3001, "Cannot read medium - unknown format" }, - { 0x3002, "Cannot read medium - incompatible format" }, - - /* Following code not in 2.6. */ - { 0x3700, "Rounded parameter" }, - - { 0x3900, "Saving parameters not supported" }, - - { 0x3a00, "Medium not present" }, - - { 0x3f00, "ATAPI CD-ROM drive operating conditions have changed" }, - { 0x3f01, "Microcode has been changed" }, - /* Following two not in 2.6. */ - { 0x3f02, "Changed operating definition" }, - { 0x3f03, "Inquiry data has changed" }, - - { 0x4000, "Diagnostic failure on component (ASCQ)" }, - - { 0x4400, "Internal ATAPI CD-ROM drive failure" }, - - { 0x4e00, "Overlapped commands attempted" }, - - { 0x5300, "Media load or eject failed" }, - { 0x5302, "Medium removal prevented" }, - - { 0x5700, "Unable to recover table of contents" }, - - { 0x5a00, "Operator request or state change input (unspecified)" }, - { 0x5a01, "Operator medium removal request" }, - - /* Following two not in 2.6. */ - { 0x5b00, "Threshold condition met" }, - { 0x5c00, "Status change" }, - - { 0x6300, "End of user area encountered on this track" }, - - { 0x6400, "Illegal mode for this track or incompatible medium" }, - - /* Following error is misspelled in ATAPI 2.6 */ - { 0xb900, "Play operation oborted [sic]" }, - - { 0xbf00, "Loss of streaming" }, + { 0x000000, "No additional sense information" }, + { 0x000011, "Play operation in progress" }, + { 0x000012, "Play operation paused" }, + { 0x000013, "Play operation successfully completed" }, + { 0x000014, "Play operation stopped due to error" }, + { 0x000015, "No current audio status to return" }, + { 0x011700, "Recovered data with no error correction applied" }, + { 0x011701, "Recovered data with retries" }, + { 0x011702, "Recovered data with positive head offset" }, + { 0x011703, "Recovered data with negative head offset" }, + { 0x011704, "Recovered data with retries and/or CIRC applied" }, + { 0x011705, "Recovered data using previous sector ID" }, + { 0x011800, "Recovered data with error correction applied" }, + { 0x011801, "Recovered data with error correction and retries applied"}, + { 0x011802, "Recovered data - the data was auto-reallocated" }, + { 0x011803, "Recovered data with CIRC" }, + { 0x011804, "Recovered data with L-EC" }, + { 0x015d00, + "Failure prediction threshold exceeded - Predicted logical unit failure" }, + { 0x015d01, + "Failure prediction threshold exceeded - Predicted media failure" }, + { 0x015dff, "Failure prediction threshold exceeded - False" }, + { 0x020400, "Logical unit not ready - cause not reportable" }, + /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ + { 0x020401, + "Logical unit not ready - in progress [sic] of becoming ready" }, + { 0x020402, "Logical unit not ready - initializing command required" }, + { 0x020403, "Logical unit not ready - manual intervention required" }, + { 0x020404, "In process of becoming ready - writing" }, + { 0x020600, "No reference position found (media may be upside down)" }, + { 0x023000, "Incompatible medium installed" }, + { 0x023a00, "Medium not present" }, + { 0x025300, "Media load or eject failed" }, + { 0x025700, "Unable to recover table of contents" }, + { 0x031100, "Unrecovered read error" }, + { 0x031106, "CIRC unrecovered error" }, + { 0x033101, "Format command failed" }, + { 0x040200, "No seek complete" }, + { 0x040300, "Write fault" }, + { 0x040900, "Track following error" }, + { 0x040901, "Tracking servo failure" }, + { 0x040902, "Focus servo failure" }, + { 0x040903, "Spindle servo failure" }, + { 0x041500, "Random positioning error" }, + { 0x041501, "Mechanical positioning or changer error" }, + { 0x041502, "Positioning error detected by read of medium" }, + { 0x043c00, "Mechanical positioning or changer error" }, + { 0x044000, "Diagnostic failure on component (ASCQ)" }, + { 0x044400, "Internal CD/DVD logical unit failure" }, + { 0x04b600, "Media load mechanism failed" }, + { 0x051a00, "Parameter list length error" }, + { 0x052000, "Invalid command operation code" }, + { 0x052c00, "Command sequence error" }, + { 0x052100, "Logical block address out of range" }, + { 0x052400, "Invalid field in command packet" }, + { 0x052600, "Invalid field in parameter list" }, + { 0x052601, "Parameter not supported" }, + { 0x052602, "Parameter value invalid" }, + { 0x052700, "Write protected media" }, + { 0x053001, "Cannot read medium - unknown format" }, + { 0x053002, "Cannot read medium - incompatible format" }, + { 0x053900, "Saving parameters not supported" }, + { 0x054e00, "Overlapped commands attempted" }, + { 0x055302, "Medium removal prevented" }, + { 0x055500, "System resource failure" }, + { 0x056300, "End of user area encountered on this track" }, + { 0x056400, "Illegal mode for this track or incompatible medium" }, + { 0x056f00, + "Copy protection key exchange failure - Authentication failure" }, + { 0x056f01, "Copy protection key exchange failure - Key not present" }, + { 0x056f02, + "Copy protection key exchange failure - Key not established" }, + { 0x05bf00, "Loss of streaming" }, + { 0x062800, "Not ready to ready transition, medium may have changed" }, + { 0x062900, "Power on, reset or hardware reset occurred" }, + { 0x062a00, "Parameters changed" }, + { 0x062a01, "Mode parameters changed" }, + { 0x062e00, "Insufficient time for operation" }, + { 0x063f00, "Logical unit operating conditions have changed" }, + { 0x063f01, "Microcode has been changed" }, + { 0x065a00, "Operator request or state change input (unspecified)" }, + { 0x065a01, "Operator medium removal request" }, + { 0x0bb900, "Play operation aborted" }, + + /* Here we use 0xff for the key (not a valid key) to signify + * that these can have _any_ key value associated with them... */ + { 0xff0401, "Logical unit is in process of becoming ready" }, + { 0xff0400, "Logical unit not ready, cause not reportable" }, + { 0xff0402, "Logical unit not ready, initializing command required" }, + { 0xff0403, "Logical unit not ready, manual intervention required" }, + { 0xff0500, "Logical unit does not respond to selection" }, + { 0xff0800, "Logical unit communication failure" }, + { 0xff0802, "Logical unit communication parity error" }, + { 0xff0801, "Logical unit communication time-out" }, + { 0xff2500, "Logical unit not supported" }, + { 0xff4c00, "Logical unit failed self-configuration" }, + { 0xff3e00, "Logical unit has not self-configured yet" }, }; #endif diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.3.15/linux/drivers/block/ide-dma.c Fri Aug 6 10:41:47 1999 +++ linux/drivers/block/ide-dma.c Tue Aug 31 11:23:03 1999 @@ -470,7 +470,7 @@ } /* - * This can be called for a dynamically installed interface. Don't initfunc it + * This can be called for a dynamically installed interface. Don't __init it */ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports) diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.3.15/linux/drivers/block/ide-pci.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/block/ide-pci.c Thu Aug 26 13:54:23 1999 @@ -130,9 +130,12 @@ #endif #ifdef CONFIG_BLK_DEV_CY82C693 +extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *); extern void ide_init_cy82c693(ide_hwif_t *); +#define PCI_CY82C693 &pci_init_cy82c693 #define INIT_CY82C693 &ide_init_cy82c693 #else +#define PCI_CY82C693 NULL #define INIT_CY82C693 NULL #endif @@ -240,7 +243,7 @@ {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, 16 }, {DEVID_HPT366, "HPT366", PCI_HPT366, INIT_HPT366, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 1, 256 }, {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0, 0 }, - {DEVID_CY82C693,"CY82C693", NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_CY82C693,"CY82C693", PCI_CY82C693, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }}; @@ -262,15 +265,6 @@ pci_write_config_byte(dev, 0x80, 0x00); pci_read_config_word(dev, PCI_COMMAND, &pcicmd); if (!(pcicmd & PCI_COMMAND_MEMORY)) { - /* - * FIXME - this is too ugly, and looks senseless. - * Why not just use resource[4]? - * - * This was a cleaner/quicker way to get the ioports - * that the are not decode do to a flaw in the chipset - * design. - */ - int i; unsigned long hpt34xIoBase = dev->resource[4].start; @@ -491,9 +485,16 @@ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port)) return; if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { - /* FIXME! This really should check that it really gets the IO/MEM part right! */ ctl = dev->resource[(2*port)+1].start; base = dev->resource[2*port].start; + if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || + !(base & PCI_BASE_ADDRESS_IO_MASK)) { + printk("%s: IO baseregs (BIOS) are reported as MEM, report to .\n", d->name); +#if 0 + /* FIXME! This really should check that it really gets the IO/MEM part right! */ + continue; +#endif + } } if ((ctl && !base) || (base && !ctl)) { printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port); @@ -579,7 +580,7 @@ printk("%s: neither IDE port enabled (BIOS)\n", d->name); } -__initfunc(static void hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)) +static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) { struct pci_dev *dev2; ide_pci_device_t *d2; @@ -610,7 +611,7 @@ d->name, dev->bus->number, dev->devfn); ide_setup_pci_device(dev, d); - if (dev2) { + if (dev2 && !hpt363_shared_irq) { printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); ide_setup_pci_device(dev2, d2); diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.3.15/linux/drivers/block/ide-pmac.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/block/ide-pmac.c Tue Aug 31 11:23:03 1999 @@ -57,7 +57,7 @@ #endif /* CONFIG_PMAC_PBOOK */ /* - * N.B. this can't be an initfunc, because the media-bay task can + * N.B. this can't be an __init, because the media-bay task can * call ide_[un]register at any time. */ void pmac_ide_init_hwif_ports(hw_regs_t *hw, @@ -117,7 +117,7 @@ } } -__initfunc(void pmac_ide_probe(void)) +void __init pmac_ide_probe(void) { struct device_node *np; int i; diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.3.15/linux/drivers/block/ide-probe.c Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/ide-probe.c Thu Aug 26 13:44:03 1999 @@ -352,56 +352,6 @@ } /* - * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc - * controller that is BIOS compatible with ST-506, and thus showing up in our - * BIOS table, but not register compatible, and therefore not present in CMOS. - * - * Furthermore, we will assume that our ST-506 drives are the primary - * drives in the system -- the ones reflected as drive 1 or 2. The first - * drive is stored in the high nibble of CMOS byte 0x12, the second in the low - * nibble. This will be either a 4 bit drive type or 0xf indicating use byte - * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value - * means we have an AT controller hard disk for that drive. - * - * Of course, there is no guarantee that either drive is actually on the - * "primary" IDE interface, but we don't bother trying to sort that out here. - * If a drive is not actually on the primary interface, then these parameters - * will be ignored. This results in the user having to supply the logical - * drive geometry as a boot parameter for each drive not on the primary i/f. - * - * The only "perfect" way to handle this would be to modify the setup.[cS] code - * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info - * for us during initialization. I have the necessary docs -- any takers? -ml - */ -static void probe_cmos_for_drives (ide_hwif_t *hwif) -{ -#ifdef __i386__ - extern struct drive_info_struct drive_info; - byte cmos_disks, *BIOS = (byte *) &drive_info; - int unit; - -#ifdef CONFIG_BLK_DEV_PDC4030 - if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) - return; -#endif /* CONFIG_BLK_DEV_PDC4030 */ - outb_p(0x12,0x70); /* specify CMOS address 0x12 */ - cmos_disks = inb_p(0x71); /* read the data from 0x12 */ - /* Extract drive geometry from CMOS+BIOS if not already setup */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) { - drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; - drive->head = drive->bios_head = *(BIOS+2); - drive->sect = drive->bios_sect = *(BIOS+14); - drive->ctl = *(BIOS+8); - drive->present = 1; - } - BIOS += 16; - } -#endif -} - -/* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. */ @@ -418,8 +368,11 @@ if (hwif->noprobe) return; - if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) + if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) { + extern void probe_cmos_for_drives(ide_hwif_t *hwif); + probe_cmos_for_drives (hwif); + } /* * Calculate the region that this interface occupies, diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.3.15/linux/drivers/block/ide-proc.c Sat Jul 3 10:46:04 1999 +++ linux/drivers/block/ide-proc.c Thu Aug 26 13:44:03 1999 @@ -243,6 +243,7 @@ } #endif /* CONFIG_BLK_DEV_IDEPCI */ } else { /* not pci */ +#ifndef CONFIG_Q40 switch (digits) { case 2: outb(val, reg); break; @@ -251,6 +252,7 @@ case 8: outl(val, reg); break; } +#endif /* CONFIG_Q40 */ } } } diff -u --recursive --new-file v2.3.15/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.3.15/linux/drivers/block/ide.c Wed Aug 18 16:14:46 1999 +++ linux/drivers/block/ide.c Thu Aug 26 13:44:03 1999 @@ -1200,7 +1200,9 @@ return; } hwif = HWIF(drive); - if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) /* set nIEN for previous hwif */ + if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && + hwif->io_ports[IDE_CONTROL_OFFSET]) + /* set nIEN for previous hwif */ OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]); hwgroup->hwif = hwif; hwgroup->drive = drive; @@ -2277,7 +2279,8 @@ * this point (lost interrupt). */ SELECT_DRIVE(HWIF(drive), drive); - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(speed, IDE_NSECTOR_REG); OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); diff -u --recursive --new-file v2.3.15/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.15/linux/drivers/block/ll_rw_blk.c Mon Aug 9 11:49:24 1999 +++ linux/drivers/block/ll_rw_blk.c Mon Aug 30 18:12:12 1999 @@ -109,6 +109,11 @@ */ int * max_sectors[MAX_BLKDEV] = { NULL, NULL, }; +/* + * Max number of segments per request + */ +int * max_segments[MAX_BLKDEV] = { NULL, NULL, }; + static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -116,6 +121,13 @@ return max_sectors[MAJOR(dev)][MINOR(dev)]; } +static inline int get_max_segments(kdev_t dev) +{ + if (!max_segments[MAJOR(dev)]) + return MAX_SEGMENTS; + return max_segments[MAJOR(dev)][MINOR(dev)]; +} + /* * Is called with the request spinlock aquired. * NOTE: the device-specific queue() functions @@ -292,24 +304,31 @@ void add_request(struct blk_dev_struct * dev, struct request * req) { + int major = MAJOR(req->rq_dev); + int minor = MINOR(req->rq_dev); struct request * tmp, **current_request; short disk_index; unsigned long flags; int queue_new_request = 0; - switch (MAJOR(req->rq_dev)) { + switch (major) { + case DAC960_MAJOR+0: + disk_index = (minor & 0x00f8) >> 3; + if (disk_index < 4) + drive_stat_acct(req->cmd, req->nr_sectors, disk_index); + break; case SCSI_DISK0_MAJOR: - disk_index = (MINOR(req->rq_dev) & 0x00f0) >> 4; + disk_index = (minor & 0x00f0) >> 4; if (disk_index < 4) drive_stat_acct(req->cmd, req->nr_sectors, disk_index); break; case IDE0_MAJOR: /* same as HD_MAJOR */ case XT_DISK_MAJOR: - disk_index = (MINOR(req->rq_dev) & 0x0040) >> 6; + disk_index = (minor & 0x0040) >> 6; drive_stat_acct(req->cmd, req->nr_sectors, disk_index); break; case IDE1_MAJOR: - disk_index = ((MINOR(req->rq_dev) & 0x0040) >> 6) + 2; + disk_index = ((minor & 0x0040) >> 6) + 2; drive_stat_acct(req->cmd, req->nr_sectors, disk_index); default: break; @@ -345,10 +364,12 @@ tmp->next = req; /* for SCSI devices, call request_fn unconditionally */ - if (scsi_blk_major(MAJOR(req->rq_dev))) + if (scsi_blk_major(major)) + queue_new_request = 1; + if (major >= COMPAQ_SMART2_MAJOR+0 && + major <= COMPAQ_SMART2_MAJOR+7) queue_new_request = 1; - if (MAJOR(req->rq_dev) >= COMPAQ_SMART2_MAJOR+0 && - MAJOR(req->rq_dev) <= COMPAQ_SMART2_MAJOR+7) + if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) queue_new_request = 1; out: if (queue_new_request) @@ -511,6 +532,14 @@ case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR: case SCSI_CDROM_MAJOR: + case DAC960_MAJOR+0: + case DAC960_MAJOR+1: + case DAC960_MAJOR+2: + case DAC960_MAJOR+3: + case DAC960_MAJOR+4: + case DAC960_MAJOR+5: + case DAC960_MAJOR+6: + case DAC960_MAJOR+7: case I2O_MAJOR: case COMPAQ_SMART2_MAJOR+0: case COMPAQ_SMART2_MAJOR+1: @@ -791,7 +820,7 @@ floppy_init(); #else #if !defined (__mc68000__) && !defined(CONFIG_PMAC) && !defined(__sparc__)\ - && !defined(CONFIG_APUS) + && !defined(CONFIG_APUS) && !defined(__sh__) outb_p(0xc, 0x3f2); #endif #endif diff -u --recursive --new-file v2.3.15/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c --- v2.3.15/linux/drivers/block/paride/pcd.c Wed Nov 4 10:03:01 1998 +++ linux/drivers/block/paride/pcd.c Tue Aug 31 16:03:17 1999 @@ -838,21 +838,21 @@ case CDROMPAUSE: - { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO; } case CDROMRESUME: - { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0}; + { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO; } case CDROMPLAYMSF: - { char cmd[12]={SCMD_PLAYAUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PLAY_AUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0}; struct cdrom_msf* msf = (struct cdrom_msf*)arg; cmd[3] = msf->cdmsf_min0; @@ -867,7 +867,7 @@ case CDROMPLAYBLK: - { char cmd[12]={SCMD_PLAYAUDIO10,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PLAY_AUDIO_10,0,0,0,0,0,0,0,0,0,0,0}; struct cdrom_blk* blk = (struct cdrom_blk*)arg; cmd[2] = blk->from >> 24; @@ -882,7 +882,7 @@ case CDROMPLAYTRKIND: - { char cmd[12]={SCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0}; struct cdrom_ti* ti = (struct cdrom_ti*)arg; cmd[4] = ti->cdti_trk0; @@ -895,7 +895,7 @@ case CDROMREADTOCHDR: - { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0}; + { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0}; struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg; char buffer[32]; int r; @@ -910,7 +910,7 @@ case CDROMREADTOCENTRY: - { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0}; + { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0}; struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg; unsigned char buffer[32]; @@ -938,21 +938,21 @@ case CDROMSTOP: - { char cmd[12]={0x1b,1,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,0,0,0,0,0,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO; } case CDROMSTART: - { char cmd[12]={0x1b,1,0,0,1,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,1,0,0,0,0,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO; } case CDROMVOLCTRL: - { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0}; char buffer[32]; char mask[32]; struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; @@ -983,7 +983,7 @@ case CDROMVOLREAD: - { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0}; char buffer[32]; struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; int r; @@ -1004,7 +1004,7 @@ case CDROMSUBCHNL: - { char cmd[12]={SCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0}; + { char cmd[12]={GPCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0}; struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; char buffer[32]; @@ -1035,7 +1035,7 @@ static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) -{ char cmd[12]={SCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0}; +{ char cmd[12]={GPCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0}; char buffer[32]; int k; int unit = DEVICE_NR(cdi->dev); diff -u --recursive --new-file v2.3.15/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c --- v2.3.15/linux/drivers/block/pdc202xx.c Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/pdc202xx.c Mon Aug 30 10:18:40 1999 @@ -491,16 +491,16 @@ return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -__initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) { unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; byte udma_speed_flag = inb(high_16 + 0x001f); byte primary_mode = inb(high_16 + 0x001a); byte secondary_mode = inb(high_16 + 0x001b); - if (dev->rom_address) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address); + if (dev->resource[PCI_ROM_RESOURCE].start) { + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { @@ -547,7 +547,7 @@ return dev->irq; } -__initfunc(void ide_init_pdc202xx (ide_hwif_t *hwif)) +void __init ide_init_pdc202xx (ide_hwif_t *hwif) { if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; diff -u --recursive --new-file v2.3.15/linux/drivers/block/raid5.c linux/drivers/block/raid5.c --- v2.3.15/linux/drivers/block/raid5.c Thu Aug 12 10:16:28 1999 +++ linux/drivers/block/raid5.c Tue Aug 31 11:30:47 1999 @@ -97,7 +97,7 @@ sh->count++; add_wait_queue(&sh->wait, &wait); repeat: - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); if (stripe_locked(sh)) { schedule(); goto repeat; diff -u --recursive --new-file v2.3.15/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.3.15/linux/drivers/block/rd.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/block/rd.c Thu Aug 26 12:48:27 1999 @@ -74,15 +74,6 @@ #include #include -/* - * We use a block size of 512 bytes in comparision to BLOCK_SIZE - * defined in include/linux/blk.h. This because of the finer - * granularity for filling up a RAM disk. - */ -#define RDBLK_SIZE_BITS 9 -#define RDBLK_SIZE (1<rq_dev); @@ -196,8 +196,8 @@ goto repeat; } - offset = CURRENT->sector << RDBLK_SIZE_BITS; - len = CURRENT->current_nr_sectors << RDBLK_SIZE_BITS; + offset = CURRENT->sector << 9; + len = CURRENT->current_nr_sectors << 9; if ((offset + len) > rd_length[minor]) { end_request(0); @@ -243,7 +243,7 @@ case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg); + return put_user(rd_kbsize[minor] << 1, (long *) arg); case BLKROSET: case BLKROGET: @@ -347,6 +347,14 @@ { int i; + if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 || + (rd_blocksize & (rd_blocksize-1))) + { + printk("RAMDISK: wrong blocksize %d, reverting to defaults\n", + rd_blocksize); + rd_blocksize = BLOCK_SIZE; + } + if (register_blkdev(MAJOR_NR, "ramdisk", &fd_fops)) { printk("RAMDISK: Could not get major %d", MAJOR_NR); return -EIO; @@ -356,18 +364,19 @@ for (i = 0; i < NUM_RAMDISKS; i++) { /* rd_size is given in kB */ - rd_length[i] = (rd_size << BLOCK_SIZE_BITS); - rd_hardsec[i] = RDBLK_SIZE; - rd_blocksizes[i] = BLOCK_SIZE; - rd_kbsize[i] = (rd_length[i] >> BLOCK_SIZE_BITS); + rd_length[i] = rd_size << 10; + rd_hardsec[i] = rd_blocksize; + rd_blocksizes[i] = rd_blocksize; + rd_kbsize[i] = rd_size; } hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */ blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */ blk_size[MAJOR_NR] = rd_kbsize; /* Size of the RAM disk in kB */ - printk("RAM disk driver initialized: %d RAM disks of %dK size\n", - NUM_RAMDISKS, rd_size); + printk("RAMDISK driver initialized: " + "%d RAM disks of %dK size %d blocksize\n", + NUM_RAMDISKS, rd_size, rd_blocksize); return 0; } @@ -377,7 +386,9 @@ #ifdef MODULE MODULE_PARM (rd_size, "1i"); -MODULE_PARM_DESC(rd_size, "Size of each RAM disk."); +MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); +MODULE_PARM (rd_blocksize, "i"); +MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes."); int init_module(void) { @@ -564,9 +575,15 @@ goto done; } - if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) { + /* + * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so + * rd_load_image will work only with filesystem BLOCK_SIZE wide! + * So make sure to use 1k blocksize while generating ext2fs + * ramdisk-images. + */ + if (nblocks > (rd_length[unit] >> BLOCK_SIZE_BITS)) { printk("RAMDISK: image too big! (%d/%ld blocks)\n", - nblocks, rd_length[unit] >> RDBLK_SIZE_BITS); + nblocks, rd_length[unit] >> BLOCK_SIZE_BITS); goto done; } diff -u --recursive --new-file v2.3.15/linux/drivers/block/sis5513.c linux/drivers/block/sis5513.c --- v2.3.15/linux/drivers/block/sis5513.c Fri Aug 6 11:16:54 1999 +++ linux/drivers/block/sis5513.c Thu Aug 26 13:55:08 1999 @@ -330,7 +330,7 @@ return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -__initfunc(unsigned int pci_init_sis5513 (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) { struct pci_dev *host; byte latency = 0, reg48h = 0; @@ -383,7 +383,7 @@ return 0; } -__initfunc(void ide_init_sis5513 (ide_hwif_t *hwif)) +void __init ide_init_sis5513 (ide_hwif_t *hwif) { byte reg48h = 0; byte mask = hwif->channel ? 0x20 : 0x10; diff -u --recursive --new-file v2.3.15/linux/drivers/block/sl82c105.c linux/drivers/block/sl82c105.c --- v2.3.15/linux/drivers/block/sl82c105.c Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/sl82c105.c Thu Aug 26 13:44:03 1999 @@ -68,7 +68,8 @@ * the correct drive has been selected. */ SELECT_DRIVE(hwif, drive); - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(0x08 | pio, IDE_NSECTOR_REG); OUT_BYTE(0x03, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); @@ -79,8 +80,8 @@ drive->name); return 1; } - - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); } return 0; diff -u --recursive --new-file v2.3.15/linux/drivers/block/trm290.c linux/drivers/block/trm290.c --- v2.3.15/linux/drivers/block/trm290.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/block/trm290.c Thu Aug 26 13:44:03 1999 @@ -263,7 +263,16 @@ old = inw(hwif->config_data) & ~1; if (old != compat && inb(old+2) == 0xff) { compat += (next_offset += 0x400); /* leave lower 10 bits untouched */ - hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; /* FIXME: should do a check_region */ +#if 1 + if (ide_check_region(compat + 2, 1)) + printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2)); + /* + * The region check is not needed; however......... + * Since this is the checked in ide-probe.c, + * this is only an assignment. + */ +#endif + hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; outw(compat|1, hwif->config_data); printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1); } diff -u --recursive --new-file v2.3.15/linux/drivers/block/via82c586.c linux/drivers/block/via82c586.c --- v2.3.15/linux/drivers/block/via82c586.c Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/via82c586.c Thu Aug 26 13:55:23 1999 @@ -441,7 +441,7 @@ return 0; } -__initfunc(unsigned int pci_init_via82c568 (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_via82c568 (struct pci_dev *dev, const char *name) { struct pci_dev *host; struct pci_dev *isa; @@ -567,7 +567,7 @@ return 0; } -__initfunc(void ide_init_via82c586 (ide_hwif_t *hwif)) +void __init ide_init_via82c586 (ide_hwif_t *hwif) { set_via_timings(hwif); } diff -u --recursive --new-file v2.3.15/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.3.15/linux/drivers/block/xd.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/block/xd.c Thu Aug 26 12:50:51 1999 @@ -194,7 +194,7 @@ } /* xd_detect: scan the possible BIOS ROM locations for the signature strings */ -static __init u_char xd_detect (u_char *controller, unsigned int *address) +static u_char __init xd_detect (u_char *controller, unsigned int *address) { u_char i,j,found = 0; @@ -1204,5 +1204,10 @@ xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200); } } +#else + +__setup ("xd=", xd_setup); +__setup ("xd_geo=", xd_manual_geo_init); + #endif /* MODULE */ diff -u --recursive --new-file v2.3.15/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.3.15/linux/drivers/cdrom/cdrom.c Mon Aug 9 12:34:22 1999 +++ linux/drivers/cdrom/cdrom.c Tue Aug 31 16:03:17 1999 @@ -22,12 +22,6 @@ based tunable parameters such as whether the tray should auto-close for that drive. Suggestions (or patches) for this welcome! - -- Change the CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, and - CDROMREADRAW ioctls so they go through the Uniform CD-ROM driver. - - -- Sync options and capability flags. - - Revision History ---------------------------------- @@ -158,11 +152,22 @@ DVD structures and ioctls in the first place! He designed the original DVD patches for ide-cd and while I rearranged and unified them, the interface is still the same. + + 3.03 Sep 1, 1999 - Jens Axboe + -- Moved the rest of the audio ioctls from the CD-ROM drivers here. Only + CDROMREADTOCENTRY and CDROMREADTOCHDR are left. + -- Moved the CDROMREADxxx ioctls in here. + -- Defined the cdrom_get_last_written and cdrom_get_next_block as ioctls + and exported functions. + -- Erik Andersen modified all SCMD_ commands + to now read GPCMD_ for the new generic packet interface. All low level + drivers are updated as well. + -- Various other cleanups. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.02" -#define VERSION "Id: cdrom.c 3.02 1999/08/08" +#define REVISION "Revision: 3.03" +#define VERSION "Id: cdrom.c 3.03 1999/09/01" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -247,6 +252,10 @@ u_char * curr, u_char requested); static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg); + +int cdrom_get_last_written(kdev_t dev, long *last_written); +int cdrom_get_next_writable(kdev_t dev, long *next_writable); + #ifdef CONFIG_SYSCTL static void cdrom_sysctl_register(void); #endif /* CONFIG_SYSCTL */ @@ -463,8 +472,8 @@ if (cdi->options & CDO_CHECK_TYPE) { /* give people a warning shot, now that CDO_CHECK_TYPE is the default case! */ - printk("cdrom: pid %d is buggy!\n", (unsigned int)current->pid); cdinfo(CD_OPEN, "bummer. wrong media type.\n"); + cdinfo(CD_WARNING, "pid %d is buggy!\n", (unsigned int)current->pid); ret=-EMEDIUMTYPE; goto clean_up_and_return; } @@ -731,19 +740,19 @@ static void setup_report_key (struct cdrom_generic_command *cgc, unsigned agid, unsigned type) { - cgc->cmd[0] = DVD_REPORT_KEY; + cgc->cmd[0] = GPCMD_REPORT_KEY; cgc->cmd[10] = type | (agid << 6); } static void setup_send_key (struct cdrom_generic_command *cgc, unsigned agid, unsigned type) { - cgc->cmd[0] = DVD_SEND_KEY; + cgc->cmd[0] = GPCMD_SEND_KEY; cgc->cmd[10] = type | (agid << 6); } static int dvd_do_auth (struct cdrom_device_info *cdi, dvd_authinfo *ai) { - int rv; + int ret; u_char buf[20]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; @@ -759,9 +768,9 @@ setup_report_key (&cgc, 0, 0); cgc.buflen = cgc.cmd[9] = 8; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) + return ret; ai->lsa.agid = buf[7] >> 6; /* Returning data, let host change state */ @@ -772,9 +781,8 @@ setup_report_key (&cgc, ai->lsk.agid, 2); cgc.buflen = cgc.cmd[9] = 12; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; copy_key(ai->lsk.key, &buf[4]); /* Returning data, let host change state */ @@ -785,9 +793,8 @@ setup_report_key (&cgc, ai->lsc.agid, 1); cgc.buflen = cgc.cmd[9] = 16; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; copy_chal(ai->lsc.chal, &buf[4]); /* Returning data, let host change state */ @@ -803,9 +810,8 @@ cgc.cmd[2] = ai->lstk.lba >> 24; cgc.buflen = cgc.cmd[9] = 12; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; ai->lstk.cpm = (buf[4] >> 7) & 1; ai->lstk.cp_sec = (buf[4] >> 6) & 1; @@ -819,9 +825,8 @@ setup_report_key (&cgc, ai->lsasf.asf, 5); cgc.buflen = cgc.cmd[9] = 8; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; ai->lsasf.asf = buf[7] & 1; break; @@ -834,9 +839,8 @@ buf[1] = 14; copy_chal (&buf[4], ai->hsc.chal); - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; ai->type = DVD_LU_SEND_KEY1; break; @@ -848,10 +852,10 @@ buf[1] = 10; copy_key (&buf[4], ai->hsk.key); - rv = cdo->generic_packet(cdi, &cgc); - if (rv) { + ret = cdo->generic_packet(cdi, &cgc); + if (ret) { ai->type = DVD_AUTH_FAILURE; - return rv; + return ret; } ai->type = DVD_AUTH_ESTABLISHED; break; @@ -860,10 +864,8 @@ case DVD_INVALIDATE_AGID: cdinfo(CD_DO_IOCTL, "entering DVD_INVALIDATE_AGID\n"); setup_report_key (&cgc, ai->lsa.agid, 0x3f); - - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; break; default: @@ -876,7 +878,7 @@ static int dvd_read_physical (struct cdrom_device_info *cdi, dvd_struct *s) { - int rv, i; + int ret, i; u_char buf[4 + 4 * 20], *base; struct dvd_layer *layer; struct cdrom_generic_command cgc; @@ -886,14 +888,13 @@ memset(&cgc, 0, sizeof(cgc)); cgc.buffer = buf; cgc.buflen = sizeof(buf); - cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->physical.layer_num; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen & 0xff; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; base = &buf[4]; layer = &s->physical.layer[0]; @@ -922,7 +923,7 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) { - int rv; + int ret; u_char buf[8]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; @@ -931,15 +932,15 @@ memset(&cgc, 0, sizeof(cgc)); cgc.buffer = buf; cgc.buflen = sizeof(buf); - cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->copyright.layer_num; cgc.cmd[7] = s->type; cgc.cmd[8] = cgc.buflen >> 8; cgc.cmd[9] = cgc.buflen & 0xff; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) + return ret; s->copyright.cpst = buf[4]; s->copyright.rmi = buf[5]; @@ -949,7 +950,7 @@ static int dvd_read_disckey (struct cdrom_device_info *cdi, dvd_struct *s) { - int rv; + int ret; u_char buf[4 + 2048]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; @@ -959,15 +960,14 @@ cgc.buffer = buf; cgc.buflen = sizeof(buf); - cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[8] = sizeof(buf) >> 8; cgc.cmd[9] = cgc.buflen & 0xff; cgc.cmd[10] = s->disckey.agid << 6; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; memcpy (s->disckey.value, &buf[4], 2048); @@ -976,7 +976,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) { - int rv; + int ret; u_char buf[4 + 188]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; @@ -985,13 +985,12 @@ memset(&cgc, 0, sizeof (cgc)); cgc.buffer = buf; cgc.buflen = sizeof(buf); - cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen = 0xff; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; s->bca.len = buf[0] << 8 | buf[1]; if (s->bca.len < 12 || s->bca.len > 188) { @@ -1005,7 +1004,7 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) { - int rv; + int ret; u_char buf[4 + 2048]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; @@ -1013,15 +1012,14 @@ memset(buf, 0, sizeof(buf)); memset(&cgc, 0, sizeof(cgc)); cgc.buffer = buf; - cgc.cmd[0] = DVD_READ_STRUCTURE; + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.buflen = sizeof(buf); cgc.cmd[8] = sizeof(buf) >> 8; cgc.cmd[9] = cgc.buflen & 0xff; - rv = cdo->generic_packet(cdi, &cgc); - if (rv) - return rv; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; s->manufact.len = buf[0] << 8 | buf[1]; if (s->manufact.len < 0 || s->manufact.len > 2048) { @@ -1066,7 +1064,7 @@ memset(cgc->cmd, 0, sizeof(cgc->cmd)); - cgc->cmd[0] = 0x5a; /* MODE_SENSE_10 */ + cgc->cmd[0] = GPCMD_MODE_SENSE_10; cgc->cmd[2] = page_code | (page_control << 6); cgc->cmd[7] = cgc->buflen >> 8; cgc->cmd[8] = cgc->buflen & 0xff; @@ -1080,7 +1078,7 @@ memset(cgc->cmd, 0, sizeof(cgc->cmd)); - cgc->cmd[0] = 0x55; /* MODE_SELECT_10 */ + cgc->cmd[0] = GPCMD_MODE_SELECT_10; cgc->cmd[1] = 0x10; /* PF */ /* generic_packet() wants the length as seen from the drive, i.e. @@ -1092,6 +1090,70 @@ return cdo->generic_packet(cdi, cgc); } +static int cdrom_read_subchannel(struct cdrom_device_info *cdi, + struct cdrom_subchnl *subchnl, int mcn) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + char buffer[32]; + int ret; + + memset(&cgc, 0, sizeof(cgc)); + cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; + cgc.cmd[1] = 2; /* MSF addressing */ + cgc.cmd[2] = 0x40; /* request subQ data */ + cgc.cmd[3] = mcn ? 2 : 1; + cgc.cmd[8] = cgc.buflen = 16; + cgc.buffer = buffer; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + subchnl->cdsc_audiostatus = cgc.buffer[1]; + subchnl->cdsc_format = CDROM_MSF; + subchnl->cdsc_ctrl = cgc.buffer[5] & 0xf; + subchnl->cdsc_trk = cgc.buffer[6]; + subchnl->cdsc_ind = cgc.buffer[7]; + + subchnl->cdsc_reladdr.msf.minute = cgc.buffer[13]; + subchnl->cdsc_reladdr.msf.second = cgc.buffer[14]; + subchnl->cdsc_reladdr.msf.frame = cgc.buffer[15]; + subchnl->cdsc_absaddr.msf.minute = cgc.buffer[9]; + subchnl->cdsc_absaddr.msf.second = cgc.buffer[10]; + subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11]; + + return 0; +} + +/* very generic interface for reading the various types of blocks */ +static int cdrom_read_block(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int lba, int nblocks, int format, int blksize) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(&cgc->cmd, 0, sizeof(cgc->cmd)); + cgc->cmd[0] = GPCMD_READ_CD; + /* expected sector size - cdda,mode1,etc. */ + cgc->cmd[1] = format << 2; + /* starting address */ + cgc->cmd[2] = (lba >> 24) & 0xff; + cgc->cmd[3] = (lba >> 16) & 0xff; + cgc->cmd[4] = (lba >> 8) & 0xff; + cgc->cmd[5] = lba & 0xff; + /* number of blocks */ + cgc->cmd[8] = nblocks; + cgc->buflen = blksize * nblocks; + switch (blksize) { + case CD_FRAMESIZE_RAW0 : cgc->cmd[9] = 0x58; + case CD_FRAMESIZE_RAW1 : cgc->cmd[9] = 0x78; + case CD_FRAMESIZE_RAW : cgc->cmd[9] = 0xf8; + default : cgc->cmd[9] = 0x10; + } + + return cdo->generic_packet(cdi, cgc); +} + /* Some of the cdrom ioctls are not implemented here, because these * appear to be either too device-specific, or it is not clear to me * what use they are. These are (number of drivers that support them @@ -1231,7 +1293,7 @@ if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) return cdo->select_disc(cdi, arg); if ((int)arg >= cdi->capacity) - return -EDRIVE_CANT_DO_THIS; + return -EINVAL; return cdo->select_disc(cdi, arg); } @@ -1264,7 +1326,7 @@ case CDROM_GET_CAPABILITY: { cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); - return cdo->capability; + return (cdo->capability & ~cdi->mask); } /* The following function is implemented, although very few audio @@ -1288,9 +1350,11 @@ cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); if (!(cdo->capability & CDC_DRIVE_STATUS)) return -ENOSYS; + if (!CDROM_CAN(CDC_SELECT_DISC)) + return cdo->drive_status(cdi, CDSL_CURRENT); if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) - return cdo->drive_status(cdi, arg); - if (((int)arg > cdi->capacity)) + return cdo->drive_status(cdi, CDSL_CURRENT); + if (((int)arg >= cdi->capacity)) return -EINVAL; return cdo->drive_status(cdi, arg); } @@ -1415,7 +1479,6 @@ return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); IOCTL_IN(arg, struct cdrom_msf, msf); - CHECKAUDIO; return cdo->audio_ioctl(cdi, cmd, &msf); } case CDROMPLAYTRKIND: { @@ -1464,22 +1527,164 @@ return -ENOSYS; } +static inline +int msf_to_lba (char m, char s, char f) +{ + return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; +} + static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) { struct cdrom_device_ops *cdo = cdi->ops; + kdev_t dev = cdi->dev; struct cdrom_generic_command cgc; - int rv; + char buffer[32]; + int ret = 0; memset(&cgc, 0, sizeof(cgc)); /* build a unified command and queue it through cdo->generic_packet() */ switch (cmd) { + case CDROMREADRAW: + case CDROMREADMODE1: + case CDROMREADMODE2: { + struct cdrom_msf msf; + int blocksize = 0, format = 0, lba; + + switch (cmd) { + case CDROMREADRAW: + blocksize = CD_FRAMESIZE_RAW; + format = 0; + break; + case CDROMREADMODE1: + blocksize = CD_FRAMESIZE; break; + format = 2; + break; + case CDROMREADMODE2: + blocksize = CD_FRAMESIZE_RAW0; break; + format = 0; + break; + } + IOCTL_IN(arg, struct cdrom_msf, msf); + lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0); + /* FIXME: we need upper bound checking, too!! */ + if (lba < 0) + return -EINVAL; + cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL); + if (cgc.buffer == NULL) + return -ENOMEM; + ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); + if (!ret) + if (copy_to_user((char *)arg, cgc.buffer, blocksize)) + return -EFAULT; + kfree(cgc.buffer); + return ret; + } + case CDROMREADAUDIO: { + struct cdrom_read_audio ra; + int lba; + + IOCTL_IN(arg, struct cdrom_read_audio, ra); + + if (ra.addr_format == CDROM_MSF) + lba = msf_to_lba(ra.addr.msf.minute, + ra.addr.msf.second, + ra.addr.msf.frame); + else if (ra.addr_format == CDROM_LBA) + lba = ra.addr.lba; + else + return -EINVAL; + + /* FIXME: we need upper bound checking, too!! */ + if (lba < 0) + return -EINVAL; + + /* do between 1 and 8 frames at the time */ + if (ra.nframes > 8 || ra.nframes < 1) + return -EINVAL; + + /* just a nice round figure */ + if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW*ra.nframes, + GFP_KERNEL)) == NULL) + return -ENOMEM; + + if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) + return -EFAULT; + + while (ra.nframes > 0) { + ret = cdrom_read_block(cdi, &cgc, lba, ra.nframes, 1, + CD_FRAMESIZE_RAW); + if (ret) break; + __copy_to_user(ra.buf, cgc.buffer, + CD_FRAMESIZE_RAW*ra.nframes); + ra.buf += (CD_FRAMESIZE_RAW * ra.nframes); + ra.nframes -= ra.nframes; + lba += ra.nframes; + } + kfree(cgc.buffer); + return ret; + } + case CDROMSUBCHNL: { + struct cdrom_subchnl q; + u_char requested, back; + IOCTL_IN(arg, struct cdrom_subchnl, q); + requested = q.cdsc_format; + if (!((requested == CDROM_MSF) || + (requested == CDROM_LBA))) + return -EINVAL; + q.cdsc_format = CDROM_MSF; + if ((ret = cdrom_read_subchannel(cdi, &q, 0))) + return ret; + back = q.cdsc_format; /* local copy */ + sanitize_format(&q.cdsc_absaddr, &back, requested); + sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); + IOCTL_OUT(arg, struct cdrom_subchnl, q); + /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ + return 0; + } + case CDROMPLAYTRKIND: { + struct cdrom_ti ti; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); + IOCTL_IN(arg, struct cdrom_ti, ti); + cgc.cmd[0] = GPCMD_PLAYAUDIO_TI; + cgc.cmd[4] = ti.cdti_trk0; + cgc.cmd[5] = ti.cdti_ind0; + cgc.cmd[7] = ti.cdti_trk1; + cgc.cmd[8] = ti.cdti_ind1; + return cdo->generic_packet(cdi, &cgc); + } + case CDROMPLAYMSF: { + struct cdrom_msf msf; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); + IOCTL_IN(arg, struct cdrom_msf, msf); + cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + cgc.cmd[3] = msf.cdmsf_min0; + cgc.cmd[4] = msf.cdmsf_sec0; + cgc.cmd[5] = msf.cdmsf_frame0; + cgc.cmd[6] = msf.cdmsf_min1; + cgc.cmd[7] = msf.cdmsf_sec1; + cgc.cmd[8] = msf.cdmsf_frame1; + return cdo->generic_packet(cdi, &cgc); + } + case CDROMPLAYBLK: { + struct cdrom_blk blk; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); + IOCTL_IN(arg, struct cdrom_blk, blk); + cgc.cmd[0] = GPCMD_PLAY_AUDIO_10; + cgc.cmd[2] = blk.from >> 24; + cgc.cmd[3] = blk.from >> 16; + cgc.cmd[4] = blk.from >> 8; + cgc.cmd[5] = blk.from; + cgc.cmd[7] = blk.len >> 8; + cgc.cmd[8] = blk.len; + return cdo->generic_packet(cdi, &cgc); + } case CDROMVOLCTRL: case CDROMVOLREAD: { struct cdrom_volctrl volctrl; - char buffer[32], mask[32]; + char mask[32]; unsigned short offset; cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); @@ -1487,14 +1692,16 @@ cgc.buffer = buffer; cgc.buflen = 24; - rv = cdrom_mode_sense(cdi, &cgc, 0xe, 0); - if (rv) return rv; + if ((ret = cdrom_mode_sense(cdi, &cgc, + GPMODE_AUDIO_CTL_PAGE, 0))) + return ret; /* some drives have longer pages, adjust and reread. */ if (buffer[1] > cgc.buflen) { cgc.buflen = buffer[1] + 2; - rv = cdrom_mode_sense(cdi, &cgc, 0xe, 0); - if (rv) return rv; + if ((ret = cdrom_mode_sense(cdi, &cgc, + GPMODE_AUDIO_CTL_PAGE, 0))) + return ret; } /* get the offset from the length of the page. length @@ -1514,8 +1721,9 @@ /* get the volume mask */ cgc.buffer = mask; - rv = cdrom_mode_sense(cdi, &cgc, 0xe, 1); - if (rv) return rv; + if ((ret = cdrom_mode_sense(cdi, &cgc, + GPMODE_AUDIO_CTL_PAGE, 1))) + return ret; buffer[offset+9] = volctrl.channel0 & mask[offset+9]; buffer[offset+11] = volctrl.channel1 & mask[offset+11]; @@ -1534,7 +1742,7 @@ case CDROMSTART: case CDROMSTOP: { cdinfo(CD_DO_IOCTL, "entering audio ioctl (start/stop)\n"); - cgc.cmd[0] = 0x1b; + cgc.cmd[0] = GPCMD_START_STOP_UNIT; cgc.cmd[1] = 1; cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; return cdo->generic_packet(cdi, &cgc); @@ -1543,7 +1751,7 @@ case CDROMPAUSE: case CDROMRESUME: { cdinfo(CD_DO_IOCTL, "entering audio ioctl (pause/resume)\n"); - cgc.cmd[0] = 0x4b; + cgc.cmd[0] = GPCMD_PAUSE_RESUME; cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; return cdo->generic_packet(cdi, &cgc); } @@ -1554,11 +1762,11 @@ return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering dvd_read_struct\n"); IOCTL_IN(arg, dvd_struct, s); - if ((rv = dvd_read_struct(cdi, &s)) == 0) { + if ((ret = dvd_read_struct(cdi, &s)) == 0) { IOCTL_OUT(arg, dvd_struct, s); return 0; } - return rv; + return ret; } case DVD_AUTH: { @@ -1567,8 +1775,8 @@ return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering dvd_auth\n"); IOCTL_IN(arg, dvd_authinfo, ai); - if ((rv = dvd_do_auth (cdi, &ai))) - return rv; + if ((ret = dvd_do_auth (cdi, &ai))) + return ret; IOCTL_OUT(arg, dvd_authinfo, ai); return 0; } @@ -1579,20 +1787,173 @@ cdinfo(CD_DO_IOCTL, "entering send_packet\n"); IOCTL_IN(arg, struct cdrom_generic_command, cgc); cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL); - rv = cdo->generic_packet(cdi, &cgc); + ret = cdo->generic_packet(cdi, &cgc); if (copy_to_user((void*)arg, cgc.buffer, cgc.buflen)) { kfree(cgc.buffer); return -EFAULT; } kfree(cgc.buffer); - return rv; + return ret; + } + case CDROM_NEXT_WRITABLE: { + long next; + if ((ret = cdrom_get_next_writable(dev, &next))) + return ret; + IOCTL_OUT(arg, long, next); + return 0; + } + case CDROM_LAST_WRITTEN: { + long last; + if ((ret = cdrom_get_last_written(dev, &last))) + return ret; + IOCTL_OUT(arg, long, last); + return 0; } - } /* switch */ return -ENOTTY; } +static int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type, + track_information *ti) +{ + struct cdrom_device_info *cdi = cdrom_find_device (dev); + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + int ret; + + memset(&cgc, 0, sizeof(cgc)); + cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; + cgc.cmd[1] = type & 3; + cgc.cmd[4] = (track & 0xff00) >> 8; + cgc.cmd[5] = track & 0xff; + cgc.cmd[8] = cgc.buflen = 8; + cgc.buffer = (char *)ti; + + ret = cdo->generic_packet(cdi, &cgc); + if (ret) return ret; + + cgc.cmd[8] = cgc.buflen = be16_to_cpu(ti->track_information_length) + + sizeof(ti->track_information_length); + return cdo->generic_packet(cdi, &cgc); +} + +static int cdrom_get_disc_info(kdev_t dev, disc_information *di) +{ + struct cdrom_device_info *cdi = cdrom_find_device (dev); + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + + /* set up command and get the disc info */ + memset(&cgc, 0, sizeof(cgc)); + memset(di, 0, sizeof(disc_information)); + cgc.cmd[0] = GPCMD_READ_DISC_INFO; + cgc.cmd[8] = cgc.buflen = sizeof(*di); + cgc.buffer = (char *)di; + + return cdo->generic_packet(cdi, &cgc); +} + + +/* return the last written block on the CD-R media. this is for the udf + file system. */ +int cdrom_get_last_written(kdev_t dev, long *last_written) +{ + struct cdrom_device_info *cdi = cdrom_find_device (dev); + struct cdrom_tocentry toc; + disc_information di; + track_information ti; + __u32 last_track; + int ret = -1; + + if (!CDROM_CAN(CDC_GENERIC_PACKET)) + goto use_toc; + + if ((ret = cdrom_get_disc_info(dev, &di))) + goto use_toc; + + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_toc; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + last_track--; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_toc; + } + + /* if last recorded field is valid, return it. */ + if (ti.lra_v) { + *last_written = be32_to_cpu(ti.last_rec_address); + } else { + /* make it up instead */ + *last_written = be32_to_cpu(ti.track_start) + + be32_to_cpu(ti.track_size); + if (ti.free_blocks) + *last_written -= (be32_to_cpu(ti.free_blocks) + 7); + } + return 0; + + /* this is where we end up if the drive either can't do a + GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if + it fails. then we return the toc contents. */ +use_toc: + toc.cdte_format = CDROM_MSF; + toc.cdte_track = CDROM_LEADOUT; + if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)) + return ret; + sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); + *last_written = toc.cdte_addr.lba; + return 0; +} + +/* return the next writable block. also for udf file system. */ +int cdrom_get_next_writable(kdev_t dev, long *next_writable) +{ + struct cdrom_device_info *cdi = cdrom_find_device (dev); + disc_information di; + track_information ti; + __u16 last_track; + int ret = -1; + + if (!CDROM_CAN(CDC_GENERIC_PACKET)) + goto use_last_written; + + if ((ret = cdrom_get_disc_info(dev, &di))) + goto use_last_written; + + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_last_written; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + last_track--; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_last_written; + } + + /* if next recordable address field is valid, use it. */ + if (ti.nwa_v) + *next_writable = be32_to_cpu(ti.next_writable); + else + goto use_last_written; + + return 0; + +use_last_written: + if ((ret = cdrom_get_last_written(dev, next_writable))) { + *next_writable = 0; + return ret; + } else { + *next_writable += 7; + return 0; + } +} + +EXPORT_SYMBOL(cdrom_get_next_writable); +EXPORT_SYMBOL(cdrom_get_last_written); EXPORT_SYMBOL(cdrom_count_tracks); EXPORT_SYMBOL(register_cdrom); EXPORT_SYMBOL(unregister_cdrom); diff -u --recursive --new-file v2.3.15/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v2.3.15/linux/drivers/cdrom/sonycd535.c Tue Jul 6 19:05:48 1999 +++ linux/drivers/cdrom/sonycd535.c Fri Aug 27 11:56:04 1999 @@ -1524,9 +1524,11 @@ printk(CDU535_MESSAGE_NAME ": my base address is not free!\n"); return -EIO; } + /* look for the CD-ROM, follows the procedure in the DOS driver */ inb(select_unit_reg); /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ + current->state = TASK_INTERRUPTIBLE; schedule_timeout((HZ+17)*40/18); inb(result_reg); diff -u --recursive --new-file v2.3.15/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.15/linux/drivers/char/Config.in Thu Aug 26 13:05:34 1999 +++ linux/drivers/char/Config.in Tue Aug 31 11:35:59 1999 @@ -69,6 +69,7 @@ dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE + dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE fi tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE @@ -195,6 +196,9 @@ endmenu tristate 'Double Talk PC internal speech card support' CONFIG_DTLK + +tristate 'Siemens R3964 line discipline' CONFIG_R3964 +tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' diff -u --recursive --new-file v2.3.15/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.15/linux/drivers/char/Makefile Thu Aug 26 13:05:34 1999 +++ linux/drivers/char/Makefile Mon Aug 30 18:05:57 1999 @@ -206,11 +206,11 @@ endif endif -ifeq ($(CONFIG_MOUSE),y) +ifeq ($(CONFIG_BUSMOUSE),y) M = y OX_OBJS += busmouse.o else - ifeq ($(CONFIG_MOUSE),m) + ifeq ($(CONFIG_BUSMOUSE),m) MM = m MX_OBJS += busmouse.o endif @@ -224,6 +224,22 @@ endif endif +ifeq ($(CONFIG_R3964),y) +O_OBJS += n_r3964.o +else + ifeq ($(CONFIG_R3964),m) + M_OBJS += n_r3964.o + endif +endif + +ifeq ($(CONFIG_APPLICOM),y) +O_OBJS += applicom.o +else + ifeq ($(CONFIG_APPLICOM),m) + M_OBJS += applicom.o + endif +endif + ifeq ($(CONFIG_MS_BUSMOUSE),y) O_OBJS += msbusmouse.o else @@ -385,7 +401,7 @@ ifeq ($(CONFIG_VIDEO_ZORAN),y) O_OBJS += buz.o else - ifeq ($(CONFIG_VIDEO_LML33),m) + ifeq ($(CONFIG_VIDEO_ZORAN),m) M_OBJS += buz.o endif endif diff -u --recursive --new-file v2.3.15/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c --- v2.3.15/linux/drivers/char/adbmouse.c Thu Aug 12 11:50:14 1999 +++ linux/drivers/char/adbmouse.c Tue Aug 31 11:35:59 1999 @@ -145,10 +145,10 @@ static struct busmouse adb_mouse = { - ADB_MOUSE_MINOR, "adbmouse", open_mouse, close_mouse, 7 + ADB_MOUSE_MINOR, "adbmouse", open_mouse, release_mouse, 7 }; -__initfunc(int adb_mouse_init(void)) +int __init adb_mouse_init(void) { #ifdef __powerpc__ if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac)) @@ -174,7 +174,7 @@ * option, which is about using ADB keyboard buttons to emulate * mouse buttons. -- paulus */ -__initfunc(void adb_mouse_setup(char *str, int *ints)) +void __init adb_mouse_setup(char *str, int *ints) { if (ints[0] >= 1) { adb_emulate_buttons = ints[1] > 0; diff -u --recursive --new-file v2.3.15/linux/drivers/char/applicom.c linux/drivers/char/applicom.c --- v2.3.15/linux/drivers/char/applicom.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/applicom.c Mon Aug 30 18:05:57 1999 @@ -0,0 +1,842 @@ +/* Derived from Applicom driver ac.c for SCO Unix */ +/* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */ +/* Dave@mvhi.com 30/8/98 */ +/* $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $ */ +/* This module is for Linux 2.1 and 2.2 series kernels. */ +/*****************************************************************************/ +/* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt */ +/* ceci pour reseter correctement apres une sortie sauvage */ +/* J PAGET 02/05/94 passage V2.4.3 dans le traitement de d'interruption, */ +/* LoopCount n'etait pas initialise a 0. */ +/* F LAFORSE 04/07/95 version V2.6.0 lecture bidon apres acces a une carte */ +/* pour liberer le bus */ +/* J.PAGET 19/11/95 version V2.6.1 Nombre, addresse,irq n'est plus configure */ +/* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */ +/* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */ +/* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */ +/* adresses de base des cartes, IOCTL 6 plus complet */ +/* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */ +/* de code autre que le texte V2.6.1 en V2.8.0 */ +/*****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "applicom.h" +#ifndef LINUX_VERSION_CODE +#include +#endif + +#undef DEBUG +#define DEVPRIO PZERO+8 +#define FALSE 0 +#define TRUE ~FALSE +#define MAX_BOARD 8 /* maximum of pc board possible */ +#define MAX_ISA_BOARD 4 +#define LEN_RAM_IO 0x800 +#define AC_MINOR 157 + +#ifndef PCI_VENDOR_ID_APPLICOM +#define PCI_VENDOR_ID_APPLICOM 0x1389 +#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 +#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 +#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 +#define MAX_PCI_DEVICE_NUM 3 +#endif + +static char *applicom_pci_devnames[]={ + "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"}; + +MODULE_AUTHOR("David Woodhouse & Applicom International"); +MODULE_DESCRIPTION("Driver for Applicom Profibus card"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ of the Applicom board"); +MODULE_PARM(mem,"i"); +MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board"); + +MODULE_SUPPORTED_DEVICE("ac"); + + +struct applicom_board { + unsigned long PhysIO; + unsigned long RamIO; +#if LINUX_VERSION_CODE > 0x20300 + wait_queue_head_t FlagSleepSend; +#else + struct wait_queue *FlagSleepSend; +#endif + long irq; +} apbs[MAX_BOARD]; + +static unsigned int irq=0; /* interrupt number IRQ */ +static unsigned long mem=0; /* physical segment of board */ + +static unsigned int numboards; /* number of installed boards */ +static volatile unsigned char Dummy; +#if LINUX_VERSION_CODE > 0x20300 +static DECLARE_WAIT_QUEUE_HEAD (FlagSleepRec); +#else +static struct wait_queue *FlagSleepRec; +#endif +static unsigned int WriteErrorCount; /* number of write error */ +static unsigned int ReadErrorCount; /* number of read error */ +static unsigned int DeviceErrorCount; /* number of device error */ + +static loff_t ac_llseek(struct file *file, loff_t offset, int origin); +static int ac_open(struct inode *inode, struct file *filp); +static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr); +static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos); +static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int ac_release(struct inode *inode, struct file *file); +static void ac_interrupt(int irq, void *dev_instance, struct pt_regs *regs); + +struct file_operations ac_fops={ + ac_llseek, /* llseek */ + ac_read, /* read */ + ac_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + ac_ioctl, /* ioctl */ + NULL, /* mmap */ + ac_open, /* open */ + NULL, /* flush */ + ac_release, /* release */ + NULL /* fsync */ +}; + +struct miscdevice ac_miscdev={ + AC_MINOR, + "ac", + &ac_fops +}; + +int ac_register_board(unsigned long physloc, unsigned long loc, + unsigned char boardno) +{ + volatile unsigned char byte_reset_it; + + if((readb(loc + CONF_END_TEST) != 0x00) || + (readb(loc + CONF_END_TEST + 1) != 0x55) || + (readb(loc + CONF_END_TEST + 2) != 0xAA) || + (readb(loc + CONF_END_TEST + 3) != 0xFF)) + return 0; + + + if (!boardno) + boardno = readb(loc + NUMCARD_OWNER_TO_PC); + + if (!boardno && boardno > MAX_BOARD) + { + printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",boardno, physloc, MAX_BOARD); + return 0; + } + + if (apbs[boardno-1].RamIO) + { + printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", + boardno, physloc, boardno, apbs[boardno-1].PhysIO); + return 0; + } + + boardno--; + + apbs[boardno].PhysIO = physloc; + apbs[boardno].RamIO = loc; +#if LINUX_VERSION_CODE > 0x20300 + init_waitqueue_head(&apbs[boardno].FlagSleepSend); +#else + apbs[boardno].FlagSleepSend = NULL; +#endif + byte_reset_it = readb(loc + RAM_IT_TO_PC); + + numboards++; + return boardno+1; +} + +#ifdef MODULE + +#define applicom_init init_module + +void cleanup_module(void) +{ + int i; + + misc_deregister(&ac_miscdev); + for (i=0; i< MAX_BOARD; i++) + { + if (!apbs[i].RamIO) + continue; + iounmap((void *)apbs[i].RamIO); + if (apbs[i].irq) + free_irq(apbs[i].irq,&ac_open); + } + // printk("Removing Applicom module\n"); +} + +#endif /* MODULE */ + +__initfunc(int applicom_init(void)) +{ + int i, numisa=0; + struct pci_dev *dev = NULL; + void *RamIO; + int boardno; +#if LINUX_VERSION_CODE > 0x20300 +#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start) +#else +#define PCI_BASE_ADDRESS(dev) (dev->base_address[0]) +#endif + + printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $\n"); + + /* No mem and irq given - check for a PCI card */ + + while ( (dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev))) + { + // mem = dev->base_address[0]; + // irq = dev->irq; + + RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO); + + if (!RamIO) { + printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev)); + return -EIO; + } + + printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n", + applicom_pci_devnames[dev->device-1], PCI_BASE_ADDRESS(dev), + dev->irq); + + if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev), + (unsigned long)RamIO,0))) + { + printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); + iounmap(RamIO); + continue; + } + + if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) + { + printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); + iounmap(RamIO); + apbs[boardno-1].RamIO = 0; + continue; + } + + /* Enable interrupts. */ + + writeb(0x40, apbs[boardno-1].RamIO + RAM_IT_FROM_PC); + + apbs[boardno-1].irq = dev->irq; + } + + /* Finished with PCI cards. If none registered, + * and there was no mem/irq specified, exit */ + + if (!mem || !irq) + { + if (numboards) + goto fin; + else + { + printk(KERN_INFO "ac.o: No PCI boards found.\n"); + printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n"); + return -ENXIO; + } + } + + /* Now try the specified ISA cards */ + + RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD); + + if (!RamIO) { + printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n",mem); + } + + for (i=0; i< MAX_ISA_BOARD; i++) + { + RamIO = ioremap(mem+ (LEN_RAM_IO*i), LEN_RAM_IO); + + if (!RamIO) { + printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n",i+1); + continue; + } + + if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i), + (unsigned long)RamIO,i+1))) { + iounmap(RamIO); + continue; + } + + printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq); + + if (!numisa) + { + if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open)) + { + printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq); + iounmap((void *)RamIO); + apbs[boardno-1].RamIO = 0; + } + apbs[boardno-1].irq=irq; + } + else + apbs[boardno-1].irq=0; + + numisa++; + } + + if (!numisa) + printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem); + +#if LINUX_VERSION_CODE > 0x20300 + init_waitqueue_head(&FlagSleepRec); +#else + FlagSleepRec = NULL; +#endif + WriteErrorCount = 0; + ReadErrorCount = 0; + DeviceErrorCount = 0; + +fin: + if (numboards) + { + misc_register (&ac_miscdev); + for (i=0; i> 4), + (int)(readb(apbs[i].RamIO + VERS) & 0xF)); + + serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); + + if (serial != 0) + printk (" S/N %d\n", serial); + else + printk("\n"); + } + return 0; + } + + else + return -ENXIO; +} + + +#ifndef MODULE +__initcall (applicom_init); +#endif + +static loff_t ac_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static int ac_open(struct inode *inode, struct file *filp) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int ac_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + + +static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + unsigned int NumCard; /* Board number 1 -> 8 */ + unsigned int IndexCard; /* Index board number 0 -> 7 */ + unsigned char TicCard; /* Board TIC to send */ + unsigned long flags; /* Current priority */ + struct st_ram_io st_loc; + struct mailbox tmpmailbox; + + if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { + printk("Hmmm. write() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); + return -EINVAL; + } + + if(copy_from_user (&st_loc, buf, sizeof(struct st_ram_io))) { + return -EFAULT; + } + if(copy_from_user (&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) { + return -EFAULT; + } + + NumCard = st_loc.num_card; /* board number to send */ + TicCard = st_loc.tic_des_from_pc; /* tic number to send */ + IndexCard = NumCard -1; + if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) + { /* User board number not OK */ + // printk("Write to invalid Applicom board %d\n", NumCard); + return -EINVAL; /* Return error code user buffer */ + } + +#ifdef DEBUG + { + int c; + + printk("Write to applicom card #%d. struct st_ram_io follows:",NumCard); + + + + for (c=0; c< sizeof(struct st_ram_io);) + { + printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]); + + for (c++ ; c%8 && c 2) /* Test octet ready correct */ + { + Dummy = readb(apbs[IndexCard].RamIO + VERS); + restore_flags(flags); + printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n", + IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY)); + DeviceErrorCount++; + return -EIO; + } + while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) + { + Dummy = readb(apbs[IndexCard].RamIO + VERS); + restore_flags(flags); + interruptible_sleep_on (&apbs[IndexCard].FlagSleepSend); + if (signal_pending(current)) + return -EINTR; + save_flags(flags); + cli(); + } + writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); + + // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox)); + { + unsigned char *from = (unsigned char *)&tmpmailbox; + unsigned long to = (unsigned long)apbs[IndexCard].RamIO + RAM_FROM_PC; + int c; + + for (c=0; c 8 */ + unsigned int IndexCard; /* index board number 0 -> 7 */ + unsigned long flags; + unsigned int i; + unsigned char tmp=0; + struct st_ram_io st_loc; + struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */ + + + if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { + printk("Hmmm. read() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); + return -EINVAL; + } + + save_flags(flags); + cli(); + + i = 0; + + while (tmp != 2) + { + for (i=0; i < MAX_BOARD; i++) + { + if (!apbs[i].RamIO) + continue; + + tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); + + if (tmp == 2) + break; + + if (tmp > 2) /* Test octet ready correct */ + { + Dummy = readb(apbs[i].RamIO + VERS); + restore_flags(flags); + printk("APPLICOM driver read error board %d, DataToPcReady = %d\n", + i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); + DeviceErrorCount++; + return -EIO; + } + Dummy = readb(apbs[i].RamIO + VERS); + + } + if (tmp != 2) + { + restore_flags(flags); + interruptible_sleep_on (&FlagSleepRec); + if (signal_pending(current)) + return -EINTR; + save_flags(flags); + cli(); + } + } + + IndexCard = i; + NumCard = i+1; + st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); + st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); + + + // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox)); + { + unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC; + unsigned char *to = (unsigned char *)&tmpmailbox; + int c; + + for (c=0; c 2) + { + printk("APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", + i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); + DeviceErrorCount++; + } + if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && + (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) + { + printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", + i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY)); + DeviceErrorCount++; + } + if(readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) /* mailbox sent by the card ? */ + { + wake_up_interruptible(&FlagSleepRec); + } + if(readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) /* ram i/o free for write by pc ? */ + { + if(waitqueue_active(&apbs[i].FlagSleepSend)) /* process sleep during read ? */ + { + wake_up_interruptible(&apbs[i].FlagSleepSend); + } + } + Dummy = readb(apbs[i].RamIO + VERS); + + if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) + i--; /* There's another int waiting on this card */ + } + if(FlagInt) LoopCount = 0; + else LoopCount++; + } + while(LoopCount < 2); +} + + +static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) + +{ /* @ ADG ou ATO selon le cas */ + int i; + unsigned char IndexCard; + unsigned long pmem ; + volatile unsigned char byte_reset_it; + struct st_ram_io adgl ; + unsigned char TmpRamIo[sizeof(struct st_ram_io)]; + + + if (copy_from_user (&adgl, (void *)arg,sizeof(struct st_ram_io))) + return -EFAULT; + + IndexCard = adgl.num_card-1; + if(cmd != 0 && cmd != 6 && + ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) + { + printk("APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); + printk("apbs[%d].RamIO = %lx\n",IndexCard, apbs[IndexCard].RamIO); + return -EINVAL; + } + + switch( cmd ) + { + case 0 : + pmem = apbs[IndexCard].RamIO; + for(i=0;i 0x20300 + init_waitqueue_head (&FlagSleepRec); +#else + FlagSleepRec = NULL; +#endif + for (i=0;i 0x20300 + init_waitqueue_head (&apbs[i].FlagSleepSend); +#else + apbs[i].FlagSleepSend = NULL; +#endif + byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC); + } + } + break ; + case 3 : + pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC; + writeb(adgl.tic_des_from_pc, pmem); + break; + case 4 : + pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC; + adgl.tic_owner_to_pc = readb(pmem++); + adgl.numcard_owner_to_pc = readb(pmem); + if (copy_to_user ((void *)arg, &adgl,sizeof(struct st_ram_io))) + return -EFAULT; + break; + case 5 : + writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); + writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); + writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); + writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); + writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); + break ; + case 6 : + printk("APPLICOM driver release .... V2.8.0\n"); + printk("Number of installed boards . %d\n",(int)numboards); + printk("Segment of board ........... %X\n",(int)mem); + printk("Interrupt IRQ number ....... %d\n",(int)irq); + for(i=0;i> 4), + (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF), + boardname); + + + serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); + + if (serial != 0) + printk (" S/N %d\n", serial); + else + printk("\n"); + } + if(DeviceErrorCount != 0) + printk("DeviceErrorCount ........... %d\n",DeviceErrorCount); + if(ReadErrorCount != 0) + printk("ReadErrorCount ............. %d\n",ReadErrorCount); + if(WriteErrorCount != 0) + printk("WriteErrorCount ............ %d\n",WriteErrorCount); + if(waitqueue_active(&FlagSleepRec)) + printk("Process in read pending\n"); + for(i=0;i 2) { + printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n"); + } + + if (ints[0] < 2) { + printk("applicom numargs: %d\n", ints[0]); + return 0; + } + + mem=ints[1]; + irq=ints[2]; + return 1; +} +#if LINUX_VERSION_CODE > 0x20300 +__setup("applicom=", applicom_setup); +#endif +#endif /* MODULE */ + diff -u --recursive --new-file v2.3.15/linux/drivers/char/applicom.h linux/drivers/char/applicom.h --- v2.3.15/linux/drivers/char/applicom.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/applicom.h Mon Aug 30 18:05:57 1999 @@ -0,0 +1,85 @@ +/* $Id: applicom.h,v 1.2 1999/08/28 15:09:49 dwmw2 Exp $ */ + + +#ifndef __LINUX_APPLICOM_H__ +#define __LINUX_APPLICOM_H__ + + +#define DATA_TO_PC_READY 0x00 +#define TIC_OWNER_TO_PC 0x01 +#define NUMCARD_OWNER_TO_PC 0x02 +#define TIC_DES_TO_PC 0x03 +#define NUMCARD_DES_TO_PC 0x04 +#define DATA_FROM_PC_READY 0x05 +#define TIC_OWNER_FROM_PC 0x06 +#define NUMCARD_OWNER_FROM_PC 0x07 +#define TIC_DES_FROM_PC 0x08 +#define NUMCARD_DES_FROM_PC 0x09 +#define ACK_FROM_PC_READY 0x0E +#define TIC_ACK_FROM_PC 0x0F +#define NUMCARD_ACK_FROM_PC 0x010 +#define TYP_ACK_FROM_PC 0x011 +#define CONF_END_TEST 0x012 +#define ERROR_CODE 0x016 +#define PARAMETER_ERROR 0x018 +#define VERS 0x01E +#define RAM_TO_PC 0x040 +#define RAM_FROM_PC 0x0170 +#define TYPE_CARD 0x03C0 +#define SERIAL_NUMBER 0x03DA +#define RAM_IT_FROM_PC 0x03FE +#define RAM_IT_TO_PC 0x03FF + +struct mailbox{ + u16 stjb_codef; /* offset 00 */ + s16 stjb_status; /* offset 02 */ + u16 stjb_ticuser_root; /* offset 04 */ + u8 stjb_piduser[4]; /* offset 06 */ + u16 stjb_mode; /* offset 0A */ + u16 stjb_time; /* offset 0C */ + u16 stjb_stop; /* offset 0E */ + u16 stjb_nfonc; /* offset 10 */ + u16 stjb_ncard; /* offset 12 */ + u16 stjb_nchan; /* offset 14 */ + u16 stjb_nes; /* offset 16 */ + u16 stjb_nb; /* offset 18 */ + u16 stjb_typvar; /* offset 1A */ + u32 stjb_adr; /* offset 1C */ + u16 stjb_ticuser_dispcyc; /* offset 20 */ + u16 stjb_ticuser_protocol; /* offset 22 */ + u8 stjb_filler[12]; /* offset 24 */ + u8 stjb_data[256]; /* offset 30 */ + }; + +struct st_ram_io +{ + unsigned char data_to_pc_ready; + unsigned char tic_owner_to_pc; + unsigned char numcard_owner_to_pc; + unsigned char tic_des_to_pc; + unsigned char numcard_des_to_pc; + unsigned char data_from_pc_ready; + unsigned char tic_owner_from_pc; + unsigned char numcard_owner_from_pc; + unsigned char tic_des_from_pc; + unsigned char numcard_des_from_pc; + unsigned char ack_to_pc_ready; + unsigned char tic_ack_to_pc; + unsigned char numcard_ack_to_pc; + unsigned char typ_ack_to_pc; + unsigned char ack_from_pc_ready; + unsigned char tic_ack_from_pc; + unsigned char numcard_ack_from_pc; + unsigned char typ_ack_from_pc; + unsigned char conf_end_test[4]; + unsigned char error_code[2]; + unsigned char parameter_error[4]; + unsigned char time_base; + unsigned char nul_inc; + unsigned char vers; + unsigned char num_card; + unsigned char reserv1[32]; +}; + + +#endif /* __LINUX_APPLICOM_H__ */ diff -u --recursive --new-file v2.3.15/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.15/linux/drivers/char/bttv.c Thu Aug 26 13:05:34 1999 +++ linux/drivers/char/bttv.c Tue Aug 31 11:25:33 1999 @@ -1288,7 +1288,7 @@ } -static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt) +static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int pllset) { u16 vscale, hscale; u32 xsf, sr; @@ -1297,9 +1297,13 @@ u16 inter; u8 crop, vtc; struct tvnorm *tvn; + unsigned long flags; if (!width || !height) return; + + save_flags(flags); + cli(); tvn=&tvnorms[btv->win.norm]; @@ -1324,7 +1328,8 @@ btwrite(1, BT848_VBI_PACK_DEL); btv->pll.pll_ofreq = tvn->Fsc; - set_pll(btv); + if(pllset) + set_pll(btv); btwrite(fmt, BT848_COLOR_FMT); #ifdef __sparc__ @@ -1372,6 +1377,8 @@ hdelay, vdelay, crop); bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop); + + restore_flags(flags); } @@ -1400,7 +1407,7 @@ else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - bt848_set_geo(btv, btv->win.width, btv->win.height, format); + bt848_set_geo(btv, btv->win.width, btv->win.height, format, 1); } /* @@ -1976,7 +1983,8 @@ { struct video_buffer v; #if LINUX_VERSION_CODE >= 0x020100 - if(!capable(CAP_SYS_ADMIN)) + if(!capable(CAP_SYS_ADMIN) + && !capable(CAP_SYS_RAWIO)) #else if(!suser()) #endif @@ -2161,7 +2169,8 @@ case BTTV_WRITEE: #if LINUX_VERSION_CODE >= 0x020100 - if(!capable(CAP_SYS_ADMIN)) + if(!capable(CAP_SYS_ADMIN) + || !capable(CAP_SYS_RAWIO)) #else if(!suser()) #endif @@ -3432,14 +3441,14 @@ btv->risc_jmp[11]=cpu_to_le32(btv->gre); bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt); + btv->gfmt, 0); } else { bt848_set_risc_jmps(btv); btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI); bt848_set_geo(btv, btv->win.width, btv->win.height, - btv->win.color_fmt); + btv->win.color_fmt, 0); } wake_up_interruptible(&btv->capq); break; @@ -3450,7 +3459,7 @@ btv->risc_jmp[11]=cpu_to_le32(btv->gre); btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt); + btv->gfmt, 0); } } if (astat&BT848_INT_OCERR) @@ -3586,11 +3595,7 @@ } } -#ifdef __sparc__ - btv->bt848_mem=(unsigned char *)btv->bt848_adr; -#else - btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); -#endif + btv->bt848_mem = ioremap(btv->bt848_adr, 0x1000); /* clear interrupt mask */ btwrite(0, BT848_INT_MASK); diff -u --recursive --new-file v2.3.15/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.3.15/linux/drivers/char/busmouse.c Sun Aug 15 11:48:40 1999 +++ linux/drivers/char/busmouse.c Tue Aug 31 11:30:47 1999 @@ -49,7 +49,7 @@ /*#define BROKEN_MOUSE*/ extern int adb_mouse_init(void); -extern int bus_mouse_init(void); +extern int logi_busmouse_init(void); extern int ms_bus_mouse_init(void); extern int atixl_busmouse_init(void); extern int amiga_mouse_init(void); @@ -273,7 +273,7 @@ add_wait_queue(&mse->wait, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (!mse->ready && !signal_pending(current)) { spin_unlock_irqrestore(&mse->lock, flags); schedule(); @@ -432,11 +432,11 @@ return 0; } -__initfunc(int -bus_mouse_init(void)) +int __init +bus_mouse_init(void) { -#ifdef CONFIG_BUSMOUSE - bus_mouse_init(); +#ifdef CONFIG_LOGIBUSMOUSE + logi_busmouse_init(); #endif #ifdef CONFIG_MS_BUSMOUSE ms_bus_mouse_init(); diff -u --recursive --new-file v2.3.15/linux/drivers/char/buz.c linux/drivers/char/buz.c --- v2.3.15/linux/drivers/char/buz.c Thu Aug 5 15:04:52 1999 +++ linux/drivers/char/buz.c Thu Aug 26 12:48:49 1999 @@ -2650,7 +2650,8 @@ { struct video_buffer v; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) + || !capable(CAP_SYS_RAWIO)) return -EPERM; if (copy_from_user(&v, arg, sizeof(v))) diff -u --recursive --new-file v2.3.15/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.3.15/linux/drivers/char/cyclades.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/char/cyclades.c Tue Aug 31 11:30:48 1999 @@ -179,7 +179,7 @@ * Change queue_task_irq_off to queue_task_irq. * The inline function queue_task_irq_off (tqueue.h) * was removed from latest releases of 2.1.x kernel. - * Use of macro __initfunc to mark the initialization + * Use of macro __init to mark the initialization * routines, so memory can be reused. * Also incorporate implementation of critical region * in function cleanup_module() created by anonymous @@ -2554,7 +2554,7 @@ } CY_UNLOCK(info, flags); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ){ return ((info->flags & ASYNC_HUP_NOTIFY) ? @@ -2615,7 +2615,7 @@ printk("cyc:block_til_ready raising Z DTR\n"); #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ){ return ((info->flags & ASYNC_HUP_NOTIFY) ? @@ -2851,7 +2851,6 @@ printk("Not clean (jiff=%lu)...", jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -2864,7 +2863,6 @@ } /* Run one more char cycle */ current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time * 5); current->state = TASK_RUNNING; #ifdef CY_DEBUG_WAIT_UNTIL_SENT @@ -3752,7 +3750,7 @@ } } - return cy_put_user(result,(unsigned long *) value); + return cy_put_user(result,(unsigned int *) value); } /* get_modem_info */ @@ -4627,8 +4625,8 @@ /* initialize chips on Cyclom-Y card -- return number of valid chips (which is number of ports/4) */ -__initfunc(static unsigned short -cyy_init_card(volatile ucchar *true_base_addr,int index)) +static unsigned short __init +cyy_init_card(volatile ucchar *true_base_addr,int index) { unsigned int chip_number; volatile ucchar* base_addr; @@ -4713,8 +4711,8 @@ * sets global variables and return the number of ISA boards found. * --------------------------------------------------------------------- */ -__initfunc(static int -cy_detect_isa(void)) +static int __init +cy_detect_isa(void) { unsigned short cy_isa_irq,nboard; volatile ucchar *cy_isa_address; @@ -4841,8 +4839,8 @@ * sets global variables and return the number of PCI boards found. * --------------------------------------------------------------------- */ -__initfunc(static int -cy_detect_pci(void)) +static int __init +cy_detect_pci(void) { #ifdef CONFIG_PCI @@ -5357,8 +5355,8 @@ extra ports are ignored. */ -__initfunc(int -cy_init(void)) +int __init +cy_init(void) { struct cyclades_port *info; struct cyclades_card *cinfo; diff -u --recursive --new-file v2.3.15/linux/drivers/char/dz.c linux/drivers/char/dz.c --- v2.3.15/linux/drivers/char/dz.c Mon Jul 5 20:35:18 1999 +++ linux/drivers/char/dz.c Tue Aug 31 11:30:48 1999 @@ -902,7 +902,7 @@ dz_out (info, DZ_TCR, tmp); - schedule_timeout(jiffies + duration); + schedule_timeout(duration); tmp &= ~mask; dz_out (info, DZ_TCR, tmp); @@ -1093,7 +1093,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - schedule_timeout(jiffies + info->close_delay); + schedule_timeout(info->close_delay); } wake_up_interruptible (&info->open_wait); } @@ -1194,7 +1194,7 @@ info->count--; info->blocked_open++; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p (filp) || !(info->is_initialized)) { retval = -EAGAIN; break; @@ -1281,7 +1281,7 @@ } -__initfunc(int dz_init(void)) +int __init dz_init(void) { int i, flags; struct dz_serial *info; @@ -1454,7 +1454,7 @@ return MKDEV(TTY_MAJOR, 64 + c->index); } -__initfunc(static int dz_console_setup(struct console *co, char *options)) +static int __init dz_console_setup(struct console *co, char *options) { int baud = 9600; int bits = 8; @@ -1590,7 +1590,7 @@ NULL }; -__initfunc (long dz_serial_console_init(long kmem_start, long kmem_end)) +long __init dz_serial_console_init(long kmem_start, long kmem_end) { register_console(&dz_sercons); diff -u --recursive --new-file v2.3.15/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.3.15/linux/drivers/char/epca.c Thu Aug 5 15:04:52 1999 +++ linux/drivers/char/epca.c Tue Aug 31 11:30:48 1999 @@ -1367,7 +1367,7 @@ while(1) { /* Begin forever while */ - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(ch->asyncflags & ASYNC_INITIALIZED)) @@ -3233,7 +3233,7 @@ if (error) return error; - putUser(mflag, (unsigned long *) arg); + putUser(mflag, (unsigned int *) arg); break; diff -u --recursive --new-file v2.3.15/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.3.15/linux/drivers/char/esp.c Tue Jul 6 19:16:55 1999 +++ linux/drivers/char/esp.c Tue Aug 31 11:30:48 1999 @@ -2317,7 +2317,7 @@ scratch | UART_MCR_DTR | UART_MCR_RTS); } sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART diff -u --recursive --new-file v2.3.15/linux/drivers/char/ftape/lowlevel/ftape-io.c linux/drivers/char/ftape/lowlevel/ftape-io.c --- v2.3.15/linux/drivers/char/ftape/lowlevel/ftape-io.c Wed Nov 4 09:57:43 1998 +++ linux/drivers/char/ftape/lowlevel/ftape-io.c Tue Aug 31 11:30:48 1999 @@ -95,19 +95,19 @@ TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks); timeout = ticks; - current->state = TASK_INTERRUPTIBLE; save_flags(flags); sti(); + set_current_state(TASK_INTERRUPTIBLE); do { - while (current->state != TASK_RUNNING) { - timeout = schedule_timeout(timeout); - } /* Mmm. Isn't current->blocked == 0xffffffff ? */ if (signal_pending(current)) { TRACE(ft_t_err, "awoken by non-blocked signal :-("); break; /* exit on signal */ + } + while (current->state != TASK_RUNNING) { + timeout = schedule_timeout(timeout); } } while (timeout); restore_flags(flags); diff -u --recursive --new-file v2.3.15/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c --- v2.3.15/linux/drivers/char/generic_serial.c Thu Aug 5 14:47:44 1999 +++ linux/drivers/char/generic_serial.c Tue Aug 31 11:30:48 1999 @@ -94,7 +94,7 @@ #ifndef TWO_THREE /* These are new in 2.3. The source now uses 2.3 syntax, and here is the compatibility define... */ -#define waitq_head_t struct wait_queue * +#define wait_queue_head_t struct wait_queue * #define DECLARE_MUTEX(name) struct semaphore name = MUTEX #define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } @@ -698,7 +698,7 @@ while (1) { CD = port->rd->get_CD (port); gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) diff -u --recursive --new-file v2.3.15/linux/drivers/char/ip2/i2lib.c linux/drivers/char/ip2/i2lib.c --- v2.3.15/linux/drivers/char/ip2/i2lib.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2/i2lib.c Tue Aug 31 11:30:48 1999 @@ -640,7 +640,6 @@ if (!in_interrupt()) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; schedule_timeout(1); // short nap } else { // we cannot sched/sleep in interrrupt silly @@ -1135,7 +1134,6 @@ ip2trace (CHANN, ITRC_OUTPUT, 61, 0 ); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; schedule_timeout(2); if (signal_pending(current)) { break; diff -u --recursive --new-file v2.3.15/linux/drivers/char/ip2.c linux/drivers/char/ip2.c --- v2.3.15/linux/drivers/char/ip2.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2.c Mon Aug 30 10:18:40 1999 @@ -9,6 +9,7 @@ #include #include #include +#include #include "./ip2/ip2types.h" #include "./ip2/fip_firm.h" // the meat diff -u --recursive --new-file v2.3.15/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c --- v2.3.15/linux/drivers/char/ip2main.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2main.c Tue Aug 31 11:30:48 1999 @@ -304,8 +304,8 @@ // Some functions to keep track of what irq's we have -__initfunc(static int -is_valid_irq(int irq) ) +static int __init +is_valid_irq(int irq) { int *i = Valid_Irqs; @@ -315,14 +315,14 @@ return (*i); } -__initfunc( static void -mark_requested_irq( char irq )) +static void __init +mark_requested_irq( char irq ) { rirqs[iindx++] = irq; } -__initfunc( static int -clear_requested_irq( char irq )) +static int __init +clear_requested_irq( char irq ) { int i; for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { @@ -334,8 +334,8 @@ return 0; } -__initfunc( static int -have_requested_irq( char irq )) +static int __init +have_requested_irq( char irq ) { // array init to zeros so 0 irq will not be requested as a side effect int i; @@ -470,8 +470,8 @@ /* SA_RANDOM - can be source for cert. random number generators */ #define IP2_SA_FLAGS 0 -__initfunc( int -old_ip2_init(void)) +int __init +old_ip2_init(void) { int i; int err; @@ -738,8 +738,8 @@ /* the board, the channel structures are initialized, and the board details */ /* are reported on the console. */ /******************************************************************************/ -__initfunc( static void -ip2_init_board( int boardnum )) +static void __init +ip2_init_board( int boardnum ) { int i,rc; int nports = 0, nboxes = 0; @@ -864,8 +864,8 @@ /* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */ /* it returns the base address of the controller. */ /******************************************************************************/ -__initfunc( static unsigned short -find_eisa_board( int start_slot )) +static unsigned short __init +find_eisa_board( int start_slot ) { int i, j; unsigned int idm = 0; @@ -1573,7 +1573,6 @@ if (pCh->wopen) { if (pCh->ClosingDelay) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; schedule_timeout(pCh->ClosingDelay); } wake_up_interruptible(&pCh->open_wait); diff -u --recursive --new-file v2.3.15/linux/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.3.15/linux/drivers/char/isicom.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/isicom.c Tue Aug 31 11:30:48 1999 @@ -995,7 +995,7 @@ raise_dtr_rts(port); sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; @@ -1405,7 +1405,7 @@ ((status & ISI_DSR) ? TIOCM_DSR : 0) | ((status & ISI_CTS) ? TIOCM_CTS : 0) | ((status & ISI_RI ) ? TIOCM_RI : 0); - put_user(info, (unsigned long *) value); + put_user(info, (unsigned int *) value); return 0; } diff -u --recursive --new-file v2.3.15/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c --- v2.3.15/linux/drivers/char/joystick/joystick.c Wed May 12 13:27:37 1999 +++ linux/drivers/char/joystick/joystick.c Tue Aug 31 11:30:48 1999 @@ -525,8 +525,8 @@ if (GOF(curl->tail) == jd->bhead && curl->startup == jd->num_axes + jd->num_buttons) { + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&jd->wait, &wait); - current->state = TASK_INTERRUPTIBLE; while (GOF(curl->tail) == jd->bhead) { diff -u --recursive --new-file v2.3.15/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.3.15/linux/drivers/char/keyboard.c Thu Aug 5 14:43:32 1999 +++ linux/drivers/char/keyboard.c Thu Aug 26 13:50:37 1999 @@ -901,7 +901,7 @@ } } -__initfunc(int kbd_init(void)) +int __init kbd_init(void) { int i; struct kbd_struct kbd0; diff -u --recursive --new-file v2.3.15/linux/drivers/char/logibusmouse.c linux/drivers/char/logibusmouse.c --- v2.3.15/linux/drivers/char/logibusmouse.c Mon Aug 2 09:54:29 1999 +++ linux/drivers/char/logibusmouse.c Mon Aug 30 10:21:03 1999 @@ -118,7 +118,7 @@ LOGITECH_BUSMOUSE, "busmouse", open_mouse, close_mouse, 7 }; -int __init bus_mouse_init(void) +int __init logi_busmouse_init(void) { if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) return -EIO; @@ -146,7 +146,7 @@ int init_module(void) { - return bus_mouse_init(); + return logi_busmouse_init(); } void cleanup_module(void) diff -u --recursive --new-file v2.3.15/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.3.15/linux/drivers/char/misc.c Mon Aug 9 12:14:28 1999 +++ linux/drivers/char/misc.c Mon Aug 30 10:21:03 1999 @@ -187,7 +187,7 @@ proc_misc = create_proc_entry("misc", 0, 0); if (proc_misc) proc_misc->read_proc = misc_read_proc; -#ifdef CONFIG_MOUSE +#ifdef CONFIG_BUSMOUSE bus_mouse_init(); #endif #if defined CONFIG_82C710_MOUSE diff -u --recursive --new-file v2.3.15/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c --- v2.3.15/linux/drivers/char/msbusmouse.c Tue Aug 3 10:04:42 1999 +++ linux/drivers/char/msbusmouse.c Thu Aug 26 13:50:57 1999 @@ -60,7 +60,7 @@ MODULE_PARM(mouse_irq, "i"); #endif -__initfunc(void msmouse_setup(char *str, int *ints)) +void __init msmouse_setup(char *str, int *ints) { if (ints[0] > 0) mouse_irq=ints[1]; @@ -117,7 +117,7 @@ MICROSOFT_BUSMOUSE, "msbusmouse", open_mouse, release_mouse, 0 }; -__initfunc(int ms_bus_mouse_init(void)) +int __init ms_bus_mouse_init(void) { int present = 0; int mse_byte, i; diff -u --recursive --new-file v2.3.15/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.3.15/linux/drivers/char/msp3400.c Wed May 12 08:41:07 1999 +++ linux/drivers/char/msp3400.c Tue Aug 31 11:30:48 1999 @@ -795,9 +795,8 @@ UNLOCK_I2C_BUS(msp->bus); /* wait 1 sec */ - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ; - schedule(); + __set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); if (signal_pending(current)) goto done; if (msp->restart) { @@ -992,16 +991,16 @@ } static /*const*/ struct file_operations msp3400c_mixer_fops = { - &msp3400c_mixer_llseek, + msp3400c_mixer_llseek, NULL, /* read */ NULL, /* write */ NULL, /* readdir */ NULL, /* poll */ - &msp3400c_mixer_ioctl, + msp3400c_mixer_ioctl, NULL, /* mmap */ - &msp3400c_mixer_open, + msp3400c_mixer_open, NULL, - &msp3400c_mixer_release, + msp3400c_mixer_release, NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ diff -u --recursive --new-file v2.3.15/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c --- v2.3.15/linux/drivers/char/n_r3964.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/n_r3964.c Mon Aug 30 18:05:19 1999 @@ -0,0 +1,1489 @@ +/* r3964 linediscipline for linux + * + * ----------------------------------------------------------- + * Copyright by + * Philips Automation Projects + * Kassel (Germany) + * http://www.pap-philips.de + * ----------------------------------------------------------- + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + * + * Author: + * L. Haag + * + * $Log: r3964.c,v $ + * Revision 1.7 1999/28/08 11:41:50 dwmw2 + * Port to 2.3 kernel + * + * Revision 1.6 1998/09/30 00:40:40 dwmw2 + * Fixed compilation on 2.0.x kernels + * Updated to newly registered tty-ldisc number 9 + * + * Revision 1.5 1998/09/04 21:57:36 dwmw2 + * Signal handling bug fixes, port to 2.1.x. + * + * Revision 1.4 1998/04/02 20:26:59 lhaag + * select, blocking, ... + * + * Revision 1.3 1998/02/12 18:58:43 root + * fixed some memory leaks + * calculation of checksum characters + * + * Revision 1.2 1998/02/07 13:03:34 root + * ioctl read_telegram + * + * Revision 1.1 1998/02/06 19:21:03 root + * Initial revision + * + * + */ +#define R3964_VERSION "1.7" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* to get the struct task_struct */ +#include /* used in new tty drivers */ +#include /* used in new tty drivers */ +#include +#include +#include +#include +#include + + +//#define DEBUG_QUEUE + +/* Log successfull handshake and protocol operations */ +//#define DEBUG_PROTO_S + +/* Log handshake and protocol errors: */ +//#define DEBUG_PROTO_E + +/* Log Linediscipline operations (open, close, read, write...): */ +//#define DEBUG_LDISC + +/* Log module and memory operations (init, cleanup; kmalloc, kfree): */ +//#define DEBUG_MODUL + +/* Macro helpers for debug output: */ +#define TRACE(format, args...) printk("r3964: " format "\n" , ## args); + +#ifdef DEBUG_MODUL +#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args); +#else +#define TRACE_M(fmt, arg...) /**/ +#endif + +#ifdef DEBUG_PROTO_S +#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args); +#else +#define TRACE_PS(fmt, arg...) /**/ +#endif + +#ifdef DEBUG_PROTO_E +#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args); +#else +#define TRACE_PE(fmt, arg...) /**/ +#endif + +#ifdef DEBUG_LDISC +#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args); +#else +#define TRACE_L(fmt, arg...) /**/ +#endif + +#ifdef DEBUG_QUEUE +#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args); +#else +#define TRACE_Q(fmt, arg...) /**/ +#endif + +void cleanup_module(void); + +static void on_timer_1(void*); +static void on_timer_2(void*); +static void add_tx_queue(struct r3964_info *, struct r3964_block_header *); +static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code); +static void put_char(struct r3964_info *pInfo, unsigned char ch); +static void trigger_transmit(struct r3964_info *pInfo); +static void retry_transmit(struct r3964_info *pInfo); +static void transmit_block(struct r3964_info *pInfo); +static void receive_char(struct r3964_info *pInfo, const unsigned char c); +static void receive_error(struct r3964_info *pInfo, const char flag); +static void on_timeout(struct r3964_info *pInfo); +static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg); +static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char *buf); +static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + int error_code, struct r3964_block_header *pBlock); +static struct r3964_message* remove_msg(struct r3964_info *pInfo, + struct r3964_client_info *pClient); +static void remove_client_block(struct r3964_info *pInfo, + struct r3964_client_info *pClient); + +static int r3964_open(struct tty_struct *tty); +static void r3964_close(struct tty_struct *tty); +static int r3964_read(struct tty_struct *tty, struct file *file, + unsigned char *buf, unsigned int nr); +static int r3964_write(struct tty_struct * tty, struct file * file, + const unsigned char * buf, unsigned int nr); +static int r3964_ioctl(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg); +static void r3964_set_termios(struct tty_struct *tty, struct termios * old); +static unsigned int r3964_poll(struct tty_struct * tty, struct file * file, + struct poll_table_struct *wait); +static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count); +static int r3964_receive_room(struct tty_struct *tty); + +static struct tty_ldisc tty_ldisc_N_R3964 = { + TTY_LDISC_MAGIC, /* magic */ + "R3964", /* name */ + 0, /* num */ + 0, /* flags */ + r3964_open, /* open */ + r3964_close, /* close */ + 0, /* flush_buffer */ + 0, /* chars_in_buffer */ + r3964_read, /* read */ + r3964_write, /* write */ + r3964_ioctl, /* ioctl */ + r3964_set_termios, /* set_termios */ + r3964_poll, /* poll */ + r3964_receive_buf, /* receive_buf */ + r3964_receive_room, /* receive_room */ + 0 /* write_wakeup */ +}; + + + +static void dump_block(const unsigned char *block, unsigned int length) +{ + unsigned int i,j; + char linebuf[16*3+1]; + + for(i=0;icount_down) + { + if(!--pInfo->count_down) + { + on_timeout(pInfo); + } + } + queue_task(&pInfo->bh_2, &tq_timer); +} + +static void on_timer_2(void *arg) +{ + struct r3964_info *pInfo = (struct r3964_info *)arg; + + if(pInfo->count_down) + { + if(!--pInfo->count_down) + { + on_timeout(pInfo); + } + } + queue_task(&pInfo->bh_1, &tq_timer); +} + +static void add_tx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + pHeader->next = NULL; + + if(pInfo->tx_last == NULL) + { + pInfo->tx_first = pInfo->tx_last = pHeader; + } + else + { + pInfo->tx_last->next = pHeader; + pInfo->tx_last = pHeader; + } + + restore_flags(flags); + + TRACE_Q("add_tx_queue %x, length %d, tx_first = %x", + (int)pHeader, pHeader->length, (int)pInfo->tx_first ); +} + +static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) +{ + struct r3964_block_header *pHeader; + unsigned long flags; +#ifdef DEBUG_QUEUE + struct r3964_block_header *pDump; +#endif + + pHeader = pInfo->tx_first; + + if(pHeader==NULL) + return; + +#ifdef DEBUG_QUEUE + printk("r3964: remove_from_tx_queue: %x, length %d - ", + (int)pHeader, (int)pHeader->length ); + for(pDump=pHeader;pDump;pDump=pDump->next) + printk("%x ", (int)pDump); + printk("\n"); +#endif + + + if(pHeader->owner) + { + if(error_code) + { + add_msg(pHeader->owner, R3964_MSG_ACK, 0, + error_code, NULL); + } + else + { + add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, + error_code, NULL); + } + wake_up_interruptible (&pInfo->read_wait); + } + + save_flags(flags); + cli(); + + pInfo->tx_first = pHeader->next; + if(pInfo->tx_first==NULL) + { + pInfo->tx_last = NULL; + } + + restore_flags(flags); + + kfree(pHeader); + TRACE_M("remove_from_tx_queue - kfree %x",(int)pHeader); + + TRACE_Q("remove_from_tx_queue: tx_first = %x, tx_last = %x", + (int)pInfo->tx_first, (int)pInfo->tx_last ); +} + +static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + pHeader->next = NULL; + + if(pInfo->rx_last == NULL) + { + pInfo->rx_first = pInfo->rx_last = pHeader; + } + else + { + pInfo->rx_last->next = pHeader; + pInfo->rx_last = pHeader; + } + pInfo->blocks_in_rx_queue++; + + restore_flags(flags); + + TRACE_Q("add_rx_queue: %x, length = %d, rx_first = %x, count = %d", + (int)pHeader, pHeader->length, + (int)pInfo->rx_first, pInfo->blocks_in_rx_queue); +} + +static void remove_from_rx_queue(struct r3964_info *pInfo, + struct r3964_block_header *pHeader) +{ + unsigned long flags; + struct r3964_block_header *pFind; + + if(pHeader==NULL) + return; + + TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d", + (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue ); + TRACE_Q("remove_from_rx_queue: %x, length %d", + (int)pHeader, (int)pHeader->length ); + + save_flags(flags); + cli(); + + if(pInfo->rx_first == pHeader) + { + /* Remove the first block in the linked list: */ + pInfo->rx_first = pHeader->next; + + if(pInfo->rx_first==NULL) + { + pInfo->rx_last = NULL; + } + pInfo->blocks_in_rx_queue--; + } + else + { + /* Find block to remove: */ + for(pFind=pInfo->rx_first; pFind; pFind=pFind->next) + { + if(pFind->next == pHeader) + { + /* Got it. */ + pFind->next = pHeader->next; + pInfo->blocks_in_rx_queue--; + if(pFind->next==NULL) + { + /* Oh, removed the last one! */ + pInfo->rx_last = pFind; + } + break; + } + } + } + + restore_flags(flags); + + kfree(pHeader); + TRACE_M("remove_from_rx_queue - kfree %x",(int)pHeader); + + TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d", + (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue ); +} + +static void put_char(struct r3964_info *pInfo, unsigned char ch) +{ + struct tty_struct *tty = pInfo->tty; + + if(tty==NULL) + return; + + if(tty->driver.put_char) + { + tty->driver.put_char(tty, ch); + } + pInfo->bcc ^= ch; +} + +static void flush(struct r3964_info *pInfo) +{ + struct tty_struct *tty = pInfo->tty; + + if(tty==NULL) + return; + + if(tty->driver.flush_chars) + { + tty->driver.flush_chars(tty); + } +} + +static void trigger_transmit(struct r3964_info *pInfo) +{ + unsigned long flags; + + + save_flags(flags); + cli(); + + if((pInfo->state == R3964_IDLE) && (pInfo->tx_first!=NULL)) + { + pInfo->state = R3964_TX_REQUEST; + pInfo->count_down = R3964_TO_QVZ; + pInfo->nRetry=0; + pInfo->flags &= ~R3964_ERROR; + + restore_flags(flags); + + TRACE_PS("trigger_transmit - sent STX"); + + put_char(pInfo, STX); + flush(pInfo); + + pInfo->bcc = 0; + } + else + { + restore_flags(flags); + } +} + +static void retry_transmit(struct r3964_info *pInfo) +{ + if(pInfo->nRetrynRetry); + pInfo->bcc = 0; + put_char(pInfo, STX); + flush(pInfo); + pInfo->state = R3964_TX_REQUEST; + pInfo->count_down = R3964_TO_QVZ; + pInfo->nRetry++; + } + else + { + TRACE_PE("transmission failed after %d retries", + R3964_MAX_RETRIES); + + remove_from_tx_queue(pInfo, R3964_TX_FAIL); + + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state = R3964_IDLE; + + trigger_transmit(pInfo); + } +} + + +static void transmit_block(struct r3964_info *pInfo) +{ + struct tty_struct *tty = pInfo->tty; + struct r3964_block_header *pBlock = pInfo->tx_first; + int room=0; + + if((tty==NULL) || (pBlock==NULL)) + { + return; + } + + if(tty->driver.write_room) + room=tty->driver.write_room(tty); + + TRACE_PS("transmit_block %x, room %d, length %d", + (int)pBlock, room, pBlock->length); + + while(pInfo->tx_position < pBlock->length) + { + if(room<2) + break; + + if(pBlock->data[pInfo->tx_position]==DLE) + { + /* send additional DLE char: */ + put_char(pInfo, DLE); + } + put_char(pInfo, pBlock->data[pInfo->tx_position++]); + + room--; + } + + if((pInfo->tx_position == pBlock->length) && (room>=3)) + { + put_char(pInfo, DLE); + put_char(pInfo, ETX); + if(pInfo->flags & R3964_BCC) + { + put_char(pInfo, pInfo->bcc); + } + pInfo->state = R3964_WAIT_FOR_TX_ACK; + pInfo->count_down = R3964_TO_QVZ; + } + flush(pInfo); +} + +static void on_receive_block(struct r3964_info *pInfo) +{ + unsigned int length; + struct r3964_client_info *pClient; + struct r3964_block_header *pBlock; + + length=pInfo->rx_position; + + /* compare byte checksum characters: */ + if(pInfo->flags & R3964_BCC) + { + if(pInfo->bcc!=pInfo->last_rx) + { + TRACE_PE("checksum error - got %x but expected %x", + pInfo->last_rx, pInfo->bcc); + pInfo->flags |= R3964_CHECKSUM; + } + } + + /* check for errors (parity, overrun,...): */ + if(pInfo->flags & R3964_ERROR) + { + TRACE_PE("on_receive_block - transmission failed error %x", + pInfo->flags & R3964_ERROR); + + put_char(pInfo, NAK); + flush(pInfo); + if(pInfo->nRetrystate=R3964_WAIT_FOR_RX_REPEAT; + pInfo->count_down = R3964_TO_RX_PANIC; + pInfo->nRetry++; + } + else + { + TRACE_PE("on_receive_block - failed after max retries"); + pInfo->state=R3964_IDLE; + } + return; + } + + + /* received block; submit DLE: */ + put_char(pInfo, DLE); + flush(pInfo); + pInfo->count_down=0; + TRACE_PS(" rx success: got %d chars", length); + + /* prepare struct r3964_block_header: */ + pBlock = kmalloc(length+sizeof(struct r3964_block_header), GFP_KERNEL); + TRACE_M("on_receive_block - kmalloc %x",(int)pBlock); + + if(pBlock==NULL) + return; + + pBlock->length = length; + pBlock->data = ((unsigned char*)pBlock)+sizeof(struct r3964_block_header); + pBlock->locks = 0; + pBlock->next = NULL; + pBlock->owner = NULL; + + memcpy(pBlock->data, pInfo->rx_buf, length); + + /* queue block into rx_queue: */ + add_rx_queue(pInfo, pBlock); + + /* notify attached client processes: */ + for(pClient=pInfo->firstClient; pClient; pClient=pClient->next) + { + if(pClient->sig_flags & R3964_SIG_DATA) + { + add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, pBlock); + } + } + wake_up_interruptible (&pInfo->read_wait); + + pInfo->state = R3964_IDLE; + + trigger_transmit(pInfo); +} + + +static void receive_char(struct r3964_info *pInfo, const unsigned char c) +{ + switch(pInfo->state) + { + case R3964_TX_REQUEST: + if(c==DLE) + { + TRACE_PS("TX_REQUEST - got DLE"); + + pInfo->state = R3964_TRANSMITTING; + pInfo->tx_position = 0; + + transmit_block(pInfo); + } + else if(c==STX) + { + if(pInfo->nRetry==0) + { + TRACE_PE("TX_REQUEST - init conflict"); + if(pInfo->priority == R3964_SLAVE) + { + goto start_receiving; + } + } + else + { + TRACE_PE("TX_REQUEST - secondary init conflict!?" + " Switching to SLAVE mode for next rx."); + goto start_receiving; + } + } + else + { + TRACE_PE("TX_REQUEST - char != DLE: %x", c); + retry_transmit(pInfo); + } + break; + case R3964_TRANSMITTING: + if(c==NAK) + { + TRACE_PE("TRANSMITTING - got NAK"); + retry_transmit(pInfo); + } + else + { + TRACE_PE("TRANSMITTING - got illegal char"); + + pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY; + pInfo->count_down = R3964_TO_ZVZ; + } + break; + case R3964_WAIT_FOR_TX_ACK: + if(c==DLE) + { + TRACE_PS("WAIT_FOR_TX_ACK - got DLE"); + remove_from_tx_queue(pInfo, R3964_OK); + + pInfo->state = R3964_IDLE; + trigger_transmit(pInfo); + } + else + { + retry_transmit(pInfo); + } + break; + case R3964_WAIT_FOR_RX_REPEAT: + /* FALLTROUGH */ + case R3964_IDLE: + if(c==STX) + { + /* Prevent rx_queue from overflow: */ + if(pInfo->blocks_in_rx_queue >= R3964_MAX_BLOCKS_IN_RX_QUEUE) + { + TRACE_PE("IDLE - got STX but no space in rx_queue!"); + pInfo->state=R3964_WAIT_FOR_RX_BUF; + pInfo->count_down = R3964_TO_NO_BUF; + break; + } +start_receiving: + /* Ok, start receiving: */ + TRACE_PS("IDLE - got STX"); + pInfo->rx_position = 0; + pInfo->last_rx = 0; + pInfo->flags &= ~R3964_ERROR; + pInfo->state=R3964_RECEIVING; + pInfo->count_down = R3964_TO_ZVZ; + pInfo->nRetry = 0; + put_char(pInfo, DLE); + flush(pInfo); + pInfo->bcc = 0; + } + break; + case R3964_RECEIVING: + if(pInfo->rx_position < RX_BUF_SIZE) + { + pInfo->bcc ^= c; + + if(c==DLE) + { + if(pInfo->last_rx==DLE) + { + pInfo->last_rx = 0; + goto char_to_buf; + } + pInfo->last_rx = DLE; + break; + } + else if((c==ETX) && (pInfo->last_rx==DLE)) + { + if(pInfo->flags & R3964_BCC) + { + pInfo->state = R3964_WAIT_FOR_BCC; + pInfo->count_down = R3964_TO_ZVZ; + } + else + { + on_receive_block(pInfo); + } + } + else + { + pInfo->last_rx = c; +char_to_buf: + pInfo->rx_buf[pInfo->rx_position++] = c; + pInfo->count_down = R3964_TO_ZVZ; + } + } + /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */ + break; + case R3964_WAIT_FOR_BCC: + pInfo->last_rx = c; + on_receive_block(pInfo); + break; + } +} + +static void receive_error(struct r3964_info *pInfo, const char flag) +{ + switch (flag) + { + case TTY_NORMAL: + break; + case TTY_BREAK: + TRACE_PE("received break") + pInfo->flags |= R3964_BREAK; + break; + case TTY_PARITY: + TRACE_PE("parity error") + pInfo->flags |= R3964_PARITY; + break; + case TTY_FRAME: + TRACE_PE("frame error") + pInfo->flags |= R3964_FRAME; + break; + case TTY_OVERRUN: + TRACE_PE("frame overrun") + pInfo->flags |= R3964_OVERRUN; + break; + default: + TRACE_PE("receive_error - unknown flag %d", flag); + pInfo->flags |= R3964_UNKNOWN; + break; + } +} + +static void on_timeout(struct r3964_info *pInfo) +{ + switch(pInfo->state) + { + case R3964_TX_REQUEST: + TRACE_PE("TX_REQUEST - timeout"); + retry_transmit(pInfo); + break; + case R3964_WAIT_ZVZ_BEFORE_TX_RETRY: + put_char(pInfo, NAK); + flush(pInfo); + retry_transmit(pInfo); + break; + case R3964_WAIT_FOR_TX_ACK: + TRACE_PE("WAIT_FOR_TX_ACK - timeout"); + retry_transmit(pInfo); + break; + case R3964_WAIT_FOR_RX_BUF: + TRACE_PE("WAIT_FOR_RX_BUF - timeout"); + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state=R3964_IDLE; + break; + case R3964_RECEIVING: + TRACE_PE("RECEIVING - timeout after %d chars", + pInfo->rx_position); + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state=R3964_IDLE; + break; + case R3964_WAIT_FOR_RX_REPEAT: + TRACE_PE("WAIT_FOR_RX_REPEAT - timeout"); + pInfo->state=R3964_IDLE; + break; + case R3964_WAIT_FOR_BCC: + TRACE_PE("WAIT_FOR_BCC - timeout"); + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state=R3964_IDLE; + break; + } +} + +static struct r3964_client_info *findClient( + struct r3964_info *pInfo, pid_t pid) +{ + struct r3964_client_info *pClient; + + for(pClient=pInfo->firstClient; pClient; pClient=pClient->next) + { + if(pClient->pid == pid) + { + return pClient; + } + } + return NULL; +} + +static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg) +{ + struct r3964_client_info *pClient; + struct r3964_client_info **ppClient; + struct r3964_message *pMsg; + + if((arg & R3964_SIG_ALL)==0) + { + /* Remove client from client list */ + for(ppClient=&pInfo->firstClient; *ppClient; ppClient=&(*ppClient)->next) + { + pClient = *ppClient; + + if(pClient->pid == pid) + { + TRACE_PS("removing client %d from client list", pid); + *ppClient = pClient->next; + while(pClient->msg_count) + { + pMsg=remove_msg(pInfo, pClient); + if(pMsg) + { + kfree(pMsg); + TRACE_M("enable_signals - msg kfree %x",(int)pMsg); + } + } + kfree(pClient); + TRACE_M("enable_signals - kfree %x",(int)pClient); + return 0; + } + } + return -EINVAL; + } + else + { + pClient=findClient(pInfo, pid); + if(pClient) + { + /* update signal options */ + pClient->sig_flags=arg; + } + else + { + /* add client to client list */ + pClient=kmalloc(sizeof(struct r3964_client_info), GFP_KERNEL); + TRACE_M("enable_signals - kmalloc %x",(int)pClient); + if(pClient==NULL) + return -ENOMEM; + + TRACE_PS("add client %d to client list", pid); + pClient->sig_flags=arg; + pClient->pid = pid; + pClient->next=pInfo->firstClient; + pClient->first_msg = NULL; + pClient->last_msg = NULL; + pClient->next_block_to_read = NULL; + pClient->msg_count = 0; + pInfo->firstClient=pClient; + } + } + + return 0; +} + +static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char *buf) +{ + struct r3964_client_info *pClient; + struct r3964_block_header *block; + + if(!buf) + { + return -EINVAL; + } + + pClient=findClient(pInfo,pid); + if(pClient==NULL) + { + return -EINVAL; + } + + block=pClient->next_block_to_read; + if(!block) + { + return 0; + } + else + { + if (copy_to_user (buf, block->data, block->length)) + return -EFAULT; + + remove_client_block(pInfo, pClient); + return block->length; + } + + return -EINVAL; +} + +static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + int error_code, struct r3964_block_header *pBlock) +{ + struct r3964_message *pMsg; + unsigned long flags; + + if(pClient->msg_countmsg_id = msg_id; + pMsg->arg = arg; + pMsg->error_code = error_code; + pMsg->block = pBlock; + pMsg->next = NULL; + + if(pClient->last_msg==NULL) + { + pClient->first_msg=pClient->last_msg=pMsg; + } + else + { + pClient->last_msg->next = pMsg; + pClient->last_msg=pMsg; + } + + pClient->msg_count++; + + if(pBlock!=NULL) + { + pBlock->locks++; + } + restore_flags(flags); + } + else + { + if((pClient->last_msg->msg_id == R3964_MSG_ACK) + && (pClient->last_msg->error_code==R3964_OVERFLOW)) + { + pClient->last_msg->arg++; + TRACE_PE("add_msg - inc prev OVERFLOW-msg"); + } + else + { + msg_id = R3964_MSG_ACK; + arg = 0; + error_code = R3964_OVERFLOW; + pBlock = NULL; + TRACE_PE("add_msg - queue OVERFLOW-msg"); + goto queue_the_message; + } + } + /* Send SIGIO signal to client process: */ + if(pClient->sig_flags & R3964_USE_SIGIO) + { + kill_proc(pClient->pid, SIGIO, 1); + } +} + +static struct r3964_message *remove_msg(struct r3964_info *pInfo, + struct r3964_client_info *pClient) +{ + struct r3964_message *pMsg=NULL; + unsigned long flags; + + if(pClient->first_msg) + { + save_flags(flags); + cli(); + + pMsg = pClient->first_msg; + pClient->first_msg = pMsg->next; + if(pClient->first_msg==NULL) + { + pClient->last_msg = NULL; + } + + pClient->msg_count--; + if(pMsg->block) + { + remove_client_block(pInfo, pClient); + pClient->next_block_to_read = pMsg->block; + } + restore_flags(flags); + } + return pMsg; +} + +static void remove_client_block(struct r3964_info *pInfo, + struct r3964_client_info *pClient) +{ + struct r3964_block_header *block; + + TRACE_PS("remove_client_block PID %d", pClient->pid); + + block=pClient->next_block_to_read; + if(block) + { + block->locks--; + if(block->locks==0) + { + remove_from_rx_queue(pInfo, block); + } + } + pClient->next_block_to_read = NULL; +} + + +/************************************************************* + * Line discipline routines + *************************************************************/ + +static int r3964_open(struct tty_struct *tty) +{ + struct r3964_info *pInfo; + + MOD_INC_USE_COUNT; + + TRACE_L("open"); + TRACE_L("tty=%x, PID=%d, disc_data=%x", + (int)tty, current->pid, (int)tty->disc_data); + + pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL); + TRACE_M("r3964_open - info kmalloc %x",(int)pInfo); + + if(!pInfo) + { + printk(KERN_ERR "r3964: failed to alloc info structure\n"); + return -ENOMEM; + } + + pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); + TRACE_M("r3964_open - rx_buf kmalloc %x",(int)pInfo->rx_buf); + + if(!pInfo->rx_buf) + { + printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); + kfree(pInfo); + TRACE_M("r3964_open - info kfree %x",(int)pInfo); + return -ENOMEM; + } + + pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); + TRACE_M("r3964_open - tx_buf kmalloc %x",(int)pInfo->tx_buf); + + if(!pInfo->tx_buf) + { + printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); + kfree(pInfo->rx_buf); + TRACE_M("r3964_open - rx_buf kfree %x",(int)pInfo->rx_buf); + kfree(pInfo); + TRACE_M("r3964_open - info kfree %x",(int)pInfo); + return -ENOMEM; + } + + pInfo->tty = tty; + init_waitqueue_head (&pInfo->read_wait); + pInfo->priority = R3964_MASTER; + pInfo->rx_first = pInfo->rx_last = NULL; + pInfo->tx_first = pInfo->tx_last = NULL; + pInfo->rx_position = 0; + pInfo->tx_position = 0; + pInfo->last_rx = 0; + pInfo->blocks_in_rx_queue = 0; + pInfo->firstClient=NULL; + pInfo->state=R3964_IDLE; + pInfo->flags = R3964_DEBUG; + pInfo->count_down = 0; + pInfo->nRetry = 0; + + tty->disc_data = pInfo; + + /* + * Add 'on_timer' to timer task queue + * (will be called from timer bh) + */ + pInfo->bh_1.next = NULL; + pInfo->bh_1.sync = 0; + pInfo->bh_1.routine = &on_timer_1; + pInfo->bh_1.data = pInfo; + + pInfo->bh_2.next = NULL; + pInfo->bh_2.sync = 0; + pInfo->bh_2.routine = &on_timer_2; + pInfo->bh_2.data = pInfo; + + queue_task(&pInfo->bh_1, &tq_timer); + + return 0; +} + +static void r3964_close(struct tty_struct *tty) +{ + struct tq_struct *tq, *prev; + struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; + struct r3964_client_info *pClient, *pNext; + struct r3964_message *pMsg; + struct r3964_block_header *pHeader, *pNextHeader; + unsigned long flags; + + TRACE_L("close"); + + /* + * Make sure that our task queue isn't activated. If it + * is, take it out of the linked list. + */ + save_flags(flags); + cli(); + + for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { + if ((tq == &pInfo->bh_1) || (tq==&pInfo->bh_2)) { + if (prev) + prev->next = tq->next; + else + tq_timer = tq->next; + break; + } + } + restore_flags(flags); + + /* Remove client-structs and message queues: */ + pClient=pInfo->firstClient; + while(pClient) + { + pNext=pClient->next; + while(pClient->msg_count) + { + pMsg=remove_msg(pInfo, pClient); + if(pMsg) + { + kfree(pMsg); + TRACE_M("r3964_close - msg kfree %x",(int)pMsg); + } + } + kfree(pClient); + TRACE_M("r3964_close - client kfree %x",(int)pClient); + pClient=pNext; + } + /* Remove jobs from tx_queue: */ + save_flags(flags); + cli(); + pHeader=pInfo->tx_first; + pInfo->tx_first=pInfo->tx_last=NULL; + restore_flags(flags); + + while(pHeader) + { + pNextHeader=pHeader->next; + kfree(pHeader); + pHeader=pNextHeader; + } + + /* Free buffers: */ + wake_up_interruptible(&pInfo->read_wait); + kfree(pInfo->rx_buf); + TRACE_M("r3964_close - rx_buf kfree %x",(int)pInfo->rx_buf); + kfree(pInfo->tx_buf); + TRACE_M("r3964_close - tx_buf kfree %x",(int)pInfo->tx_buf); + kfree(pInfo); + TRACE_M("r3964_close - info kfree %x",(int)pInfo); + + MOD_DEC_USE_COUNT; +} + +static int r3964_read(struct tty_struct *tty, struct file *file, + unsigned char *buf, unsigned int nr) +{ + struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; + struct r3964_client_info *pClient; + struct r3964_message *pMsg; + struct r3964_client_message theMsg; + DECLARE_WAITQUEUE (wait, current); + + int pid = current->pid; + int count; + + TRACE_L("read()"); + + pClient=findClient(pInfo, pid); + if(pClient) + { + pMsg = remove_msg(pInfo, pClient); + if(pMsg==NULL) + { + /* no messages available. */ + if (file->f_flags & O_NONBLOCK) + { + return -EAGAIN; + } + /* block until there is a message: */ + add_wait_queue(&pInfo->read_wait, &wait); +repeat: + pMsg = remove_msg(pInfo, pClient); + current->state = TASK_INTERRUPTIBLE; + if (!pMsg && !signal_pending(current)) + { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&pInfo->read_wait, &wait); + } + + /* If we still haven't got a message, we must have been signalled */ + + if (!pMsg) return -EINTR; + + /* deliver msg to client process: */ + theMsg.msg_id = pMsg->msg_id; + theMsg.arg = pMsg->arg; + theMsg.error_code = pMsg->error_code; + count = sizeof(struct r3964_client_message); + + kfree(pMsg); + TRACE_M("r3964_read - msg kfree %x",(int)pMsg); + + if (copy_to_user(buf,&theMsg, count)) + return -EFAULT; + + TRACE_PS("read - return %d", count); + return count; + } + return -EPERM; +} + +static int r3964_write(struct tty_struct * tty, struct file * file, + const unsigned char *data, unsigned int count) +{ + struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; + struct r3964_block_header *pHeader; + struct r3964_client_info *pClient; + unsigned char *new_data; + int status; + int pid; + + TRACE_L("write request, %d characters", count); +/* + * Verify the pointers + */ + + if(!pInfo) + return -EIO; + + status = verify_area (VERIFY_READ, data, count); + if (status != 0) + { + return status; + } + +/* + * Ensure that the caller does not wish to send too much. + */ + if (count > R3964_MTU) + { + if (pInfo->flags & R3964_DEBUG) + { + TRACE_L (KERN_WARNING + "r3964_write: truncating user packet " + "from %u to mtu %d", count, R3964_MTU); + } + count = R3964_MTU; + } +/* + * Allocate a buffer for the data and fetch it from the user space. + */ + new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL); + TRACE_M("r3964_write - kmalloc %x",(int)new_data); + if (new_data == NULL) { + if (pInfo->flags & R3964_DEBUG) + { + printk (KERN_ERR + "r3964_write: no memory\n"); + } + return -ENOSPC; + } + + pHeader = (struct r3964_block_header *)new_data; + pHeader->data = new_data + sizeof(struct r3964_block_header); + pHeader->length = count; + pHeader->locks = 0; + pHeader->owner = NULL; + + pid=current->pid; + + pClient=findClient(pInfo, pid); + if(pClient) + { + pHeader->owner = pClient; + } + + copy_from_user (pHeader->data, data, count); /* We already verified this */ + + if(pInfo->flags & R3964_DEBUG) + { + dump_block(pHeader->data, count); + } + +/* + * Add buffer to transmit-queue: + */ + add_tx_queue(pInfo, pHeader); + trigger_transmit(pInfo); + + return 0; +} + +static int r3964_ioctl(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; + if(pInfo==NULL) + return -EINVAL; + switch(cmd) + { + case R3964_ENABLE_SIGNALS: + return enable_signals(pInfo, current->pid, arg); + case R3964_SETPRIORITY: + if(argR3964_SLAVE) + return -EINVAL; + pInfo->priority = arg & 0xff; + return 0; + case R3964_USE_BCC: + if(arg) + pInfo->flags |= R3964_BCC; + else + pInfo->flags &= ~R3964_BCC; + return 0; + case R3964_READ_TELEGRAM: + return read_telegram(pInfo, current->pid, (unsigned char *)arg); + default: + return -ENOIOCTLCMD; + } +} + +static void r3964_set_termios(struct tty_struct *tty, struct termios * old) +{ + TRACE_L("set_termios"); +} + +static unsigned int r3964_poll(struct tty_struct * tty, struct file * file, + struct poll_table_struct *wait) +{ + struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; + int pid=current->pid; + struct r3964_client_info *pClient; + struct r3964_message *pMsg=NULL; + unsigned int flags; + int result = POLLOUT; + + TRACE_L("POLL"); + + pClient=findClient(pInfo,pid); + if(pClient) + { + poll_wait(file, &pInfo->read_wait, wait); + save_flags(flags); + cli(); + pMsg=pClient->first_msg; + restore_flags(flags); + if(pMsg) + result |= POLLIN | POLLRDNORM; + } + else + { + result = -EINVAL; + } + return result; +} + +static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) +{ + struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; + const unsigned char *p; + char *f, flags = 0; + int i; + + for (i=count, p = cp, f = fp; i; i--, p++) { + if (f) + flags = *f++; + if(flags==TTY_NORMAL) + { + receive_char(pInfo, *p); + } + else + { + receive_error(pInfo, flags); + } + + } +} + +static int r3964_receive_room(struct tty_struct *tty) +{ + TRACE_L("receive_room"); + return -1; +} + diff -u --recursive --new-file v2.3.15/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.3.15/linux/drivers/char/n_tty.c Tue May 11 14:37:40 1999 +++ linux/drivers/char/n_tty.c Tue Aug 31 11:30:48 1999 @@ -948,7 +948,7 @@ /* This statement must be first before checking for input so that any interrupt will set the state back to TASK_RUNNING. */ - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (((minimum - (b - buf)) < tty->minimum_to_wake) && ((minimum - (b - buf)) >= 1)) @@ -1073,7 +1073,7 @@ add_wait_queue(&tty->write_wait, &wait); while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { retval = -ERESTARTSYS; break; diff -u --recursive --new-file v2.3.15/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.3.15/linux/drivers/char/pc_keyb.c Mon Aug 2 16:40:36 1999 +++ linux/drivers/char/pc_keyb.c Tue Aug 31 11:30:48 1999 @@ -872,7 +872,7 @@ return -EAGAIN; add_wait_queue(&queue->proc_list, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (queue_empty() && !signal_pending(current)) { schedule(); goto repeat; diff -u --recursive --new-file v2.3.15/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.3.15/linux/drivers/char/pcxx.c Thu Aug 5 14:34:01 1999 +++ linux/drivers/char/pcxx.c Tue Aug 31 11:30:48 1999 @@ -356,7 +356,7 @@ memoff(info); } sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) { if(info->asyncflags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; diff -u --recursive --new-file v2.3.15/linux/drivers/char/planb.c linux/drivers/char/planb.c --- v2.3.15/linux/drivers/char/planb.c Thu Aug 5 14:34:01 1999 +++ linux/drivers/char/planb.c Tue Aug 31 11:30:48 1999 @@ -383,7 +383,7 @@ add_wait_queue(&pb->lockq, &wait); repeat: - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); if (pb->lock) { schedule(); goto repeat; @@ -1533,7 +1533,8 @@ DEBUG("PlanB: IOCTL VIDIOCSFBUF\n"); - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) + || !capable(CAP_SYS_RAWIO)) return -EPERM; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; diff -u --recursive --new-file v2.3.15/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.3.15/linux/drivers/char/ppdev.c Fri Jul 30 12:28:26 1999 +++ linux/drivers/char/ppdev.c Fri Aug 27 12:24:35 1999 @@ -502,8 +502,8 @@ } if (pp->pdev) { - kfree (pp->pdev->name); parport_unregister_device (pp->pdev); + kfree (pp->pdev->name); pp->pdev = NULL; printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n", minor); diff -u --recursive --new-file v2.3.15/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.3.15/linux/drivers/char/qpmouse.c Tue May 11 14:37:40 1999 +++ linux/drivers/char/qpmouse.c Tue Aug 31 11:30:48 1999 @@ -267,7 +267,7 @@ return -EAGAIN; add_wait_queue(&queue->proc_list, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (queue_empty() && !signal_pending(current)) { schedule(); goto repeat; diff -u --recursive --new-file v2.3.15/linux/drivers/char/radio-terratec.c linux/drivers/char/radio-terratec.c --- v2.3.15/linux/drivers/char/radio-terratec.c Mon Jul 5 20:07:02 1999 +++ linux/drivers/char/radio-terratec.c Thu Aug 26 13:53:10 1999 @@ -299,7 +299,7 @@ NULL }; -__initfunc(int terratec_init(struct video_init *v)) +int __init terratec_init(struct video_init *v) { if (check_region(io, 2)) { diff -u --recursive --new-file v2.3.15/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.3.15/linux/drivers/char/random.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/random.c Tue Aug 31 12:37:39 1999 @@ -1,10 +1,10 @@ /* * random.c -- A strong random number generator * - * Version 1.04, last modified 26-Apr-98 + * Version 1.88, last modified 30-Aug-99 * - * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998. All rights - * reserved. + * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All + * rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,15 +27,16 @@ * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. */ /* @@ -223,8 +224,8 @@ * The code for SHA transform was taken from Peter Gutmann's * implementation, which has been placed in the public domain. * The code for MD5 transform was taken from Colin Plumb's - * implementation, which has been placed in the public domain. The - * MD5 cryptographic checksum was devised by Ronald Rivest, and is + * implementation, which has been placed in the public domain. + * The MD5 cryptographic checksum was devised by Ronald Rivest, and is * documented in RFC 1321, "The MD5 Message Digest Algorithm". * * Further background information on this topic may be obtained from @@ -232,11 +233,6 @@ * Eastlake, Steve Crocker, and Jeff Schiller. */ -/* - * Added a check for signal pending in the extract_entropy() loop to allow - * the read(2) syscall to be interrupted. Copyright (C) 1998 Andrea Arcangeli - */ - #include #include #include @@ -256,72 +252,77 @@ /* * Configuration information */ -#undef RANDOM_BENCHMARK -#undef BENCHMARK_NOINT -#define ROTATE_PARANOIA - -#define POOLWORDS 128 /* Power of 2 - note that this is 32-bit words */ -#define POOLBITS (POOLWORDS*32) -/* - * The pool is stirred with a primitive polynomial of degree POOLWORDS - * over GF(2). The taps for various sizes are defined below. They are - * chosen to be evenly spaced (minimum RMS distance from evenly spaced; - * the numbers in the comments are a scaled squared error sum) except - * for the last tap, which is 1 to get the twisting happening as fast - * as possible. - */ -#if POOLWORDS == 2048 /* 115 x^2048+x^1638+x^1231+x^819+x^411+x^1+1 */ -#define TAP1 1638 -#define TAP2 1231 -#define TAP3 819 -#define TAP4 411 -#define TAP5 1 -#elif POOLWORDS == 1024 /* 290 x^1024+x^817+x^615+x^412+x^204+x^1+1 */ -/* Alt: 115 x^1024+x^819+x^616+x^410+x^207+x^2+1 */ -#define TAP1 817 -#define TAP2 615 -#define TAP3 412 -#define TAP4 204 -#define TAP5 1 -#elif POOLWORDS == 512 /* 225 x^512+x^411+x^308+x^208+x^104+x+1 */ -/* Alt: 95 x^512+x^409+x^307+x^206+x^102+x^2+1 - * 95 x^512+x^409+x^309+x^205+x^103+x^2+1 */ -#define TAP1 411 -#define TAP2 308 -#define TAP3 208 -#define TAP4 104 -#define TAP5 1 -#elif POOLWORDS == 256 /* 125 x^256+x^205+x^155+x^101+x^52+x+1 */ -#define TAP1 205 -#define TAP2 155 -#define TAP3 101 -#define TAP4 52 -#define TAP5 1 -#elif POOLWORDS == 128 /* 105 x^128+x^103+x^76+x^51+x^25+x+1 */ -/* Alt: 70 x^128+x^103+x^78+x^51+x^27+x^2+1 */ -#define TAP1 103 -#define TAP2 76 -#define TAP3 51 -#define TAP4 25 -#define TAP5 1 -#elif POOLWORDS == 64 /* 15 x^64+x^52+x^39+x^26+x^14+x+1 */ -#define TAP1 52 -#define TAP2 39 -#define TAP3 26 -#define TAP4 14 -#define TAP5 1 -#elif POOLWORDS == 32 /* 15 x^32+x^26+x^20+x^14+x^7+x^1+1 */ -#define TAP1 26 -#define TAP2 20 -#define TAP3 14 -#define TAP4 7 -#define TAP5 1 -#elif POOLWORDS & (POOLWORDS-1) -#error POOLWORDS must be a power of 2 -#else -#error No primitive polynomial available for chosen POOLWORDS +#define DEFAULT_POOL_SIZE 512 +#define SECONDARY_POOL_SIZE 128 +#define BATCH_ENTROPY_SIZE 256 +#define USE_SHA + +/* + * The minimum number of bits of entropy before we wake up a read on + * /dev/random. Should always be at least 8, or at least 1 byte. + */ +static int random_read_wakeup_thresh = 8; + +/* + * If the entropy count falls under this number of bits, then we + * should wake up processes which are selecting or polling on write + * access to /dev/random. + */ +static int random_write_wakeup_thresh = 128; + +/* + * A pool of size POOLWORDS is stirred with a primitive polynomial + * of degree POOLWORDS over GF(2). The taps for various sizes are + * defined below. They are chosen to be evenly spaced (minimum RMS + * distance from evenly spaced; the numbers in the comments are a + * scaled squared error sum) except for the last tap, which is 1 to + * get the twisting happening as fast as possible. + */ +static struct poolinfo { + int poolwords; + int tap1, tap2, tap3, tap4, tap5; +} poolinfo_table[] = { + /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ + { 2048, 1638, 1231, 819, 411, 1 }, + + /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ + { 1024, 817, 615, 412, 204, 1 }, + +#if 0 /* Alternate polynomial */ + /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ + { 1024, 819, 616, 410, 207, 2 }, +#endif + + /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ + { 512, 411, 308, 208, 104, 1 }, + +#if 0 /* Alternates */ + /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ + { 512, 409, 307, 206, 102, 2 }, + /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ + { 512, 409, 309, 205, 103, 2 }, +#endif + + /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ + { 256, 205, 155, 101, 52, 1 }, + + /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ + { 128, 103, 76, 51, 25, 1 }, + +#if 0 /* Alternate polynomial */ + /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ + { 128, 103, 78, 51, 27, 2 }, #endif + /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ + { 64, 52, 39, 26, 14, 1 }, + + /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ + { 32, 26, 20, 14, 7, 1 }, + + { 0, 0, 0, 0, 0, 0 }, +}; + /* * For the purposes of better mixing, we use the CRC-32 polynomial as * well to make a twisted Generalized Feedback Shift Reigster @@ -332,25 +333,26 @@ * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) * * Thanks to Colin Plumb for suggesting this. + * * We have not analyzed the resultant polynomial to prove it primitive; * in fact it almost certainly isn't. Nonetheless, the irreducible factors * of a random large-degree polynomial over GF(2) are more than large enough * that periodicity is not a concern. - * - * The input hash is much less sensitive than the output hash. All that - * we want of it is that it be a good non-cryptographic hash; i.e. it - * not produce collisions when fed "random" data of the sort we expect - * to see. As long as the pool state differs for different inputs, we - * have preserved the input entropy and done a good job. The fact that an - * intelligent attacker can construct inputs that will produce controlled - * alterations to the pool's state is not important because we don't - * consider such inputs to contribute any randomness. - * The only property we need with respect to them is - * that the attacker can't increase his/her knowledge of the pool's state. + * + * The input hash is much less sensitive than the output hash. All + * that we want of it is that it be a good non-cryptographic hash; + * i.e. it not produce collisions when fed "random" data of the sort + * we expect to see. As long as the pool state differs for different + * inputs, we have preserved the input entropy and done a good job. + * The fact that an intelligent attacker can construct inputs that + * will produce controlled alterations to the pool's state is not + * important because we don't consider such inputs to contribute any + * randomness. The only property we need with respect to them is that + * the attacker can't increase his/her knowledge of the pool's state. * Since all additions are reversible (knowing the final state and the * input, you can reconstruct the initial state), if an attacker has - * any uncertainty about the initial state, he/she can only shuffle that - * uncertainty about, but never cause any collisions (which would + * any uncertainty about the initial state, he/she can only shuffle + * that uncertainty about, but never cause any collisions (which would * decrease the uncertainty). * * The chosen system lets the state of the pool be (essentially) the input @@ -365,82 +367,36 @@ */ /* - * The minimum number of bits to release a "wait on input". Should - * probably always be 8, since a /dev/random read can return a single - * byte. - */ -#define WAIT_INPUT_BITS 8 -/* - * The limit number of bits under which to release a "wait on - * output". Should probably always be the same as WAIT_INPUT_BITS, so - * that an output wait releases when and only when a wait on input - * would block. - */ -#define WAIT_OUTPUT_BITS WAIT_INPUT_BITS - -/* There is actually only one of these, globally. */ -struct random_bucket { - unsigned add_ptr; - unsigned entropy_count; -#ifdef ROTATE_PARANOIA - int input_rotate; + * Linux 2.2 compatibility + */ +#ifndef DECLARE_WAITQUEUE +#define DECLARE_WAITQUEUE(WAIT, PTR) struct wait_queue WAIT = { PTR, NULL } #endif - __u32 pool[POOLWORDS]; -}; - -#ifdef RANDOM_BENCHMARK -/* For benchmarking only */ -struct random_benchmark { - unsigned long long start_time; - int times; /* # of samples */ - unsigned long min; - unsigned long max; - unsigned long accum; /* accumulator for average */ - const char *descr; - int unit; - unsigned long flags; -}; - -#define BENCHMARK_INTERVAL 500 - -static void initialize_benchmark(struct random_benchmark *bench, - const char *descr, int unit); -static void begin_benchmark(struct random_benchmark *bench); -static void end_benchmark(struct random_benchmark *bench); - -struct random_benchmark timer_benchmark; +#ifndef DECLARE_WAIT_QUEUE_HEAD +#define DECLARE_WAIT_QUEUE_HEAD(WAIT) struct wait_queue *WAIT #endif -/* There is one of these per entropy source */ -struct timer_rand_state { - __u32 last_time; - __s32 last_delta,last_delta2; - int dont_count_entropy:1; -}; - -static struct random_bucket random_state; -static struct timer_rand_state keyboard_timer_state; -static struct timer_rand_state mouse_timer_state; -static struct timer_rand_state extract_timer_state; -static struct timer_rand_state *irq_timer_state[NR_IRQS]; -static struct timer_rand_state *blkdev_timer_state[MAX_BLKDEV]; +/* + * Static global variables + */ +static struct entropy_store *random_state; /* The default global store */ +static struct entropy_store *sec_random_state; /* secondary store */ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); -static ssize_t random_read(struct file * file, char * buf, - size_t nbytes, loff_t *ppos); -static ssize_t random_read_unlimited(struct file * file, char * buf, - size_t nbytes, loff_t *ppos); -static unsigned int random_poll(struct file *file, poll_table * wait); -static ssize_t random_write(struct file * file, const char * buffer, - size_t count, loff_t *ppos); -static int random_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg); - -static inline void fast_add_entropy_words(struct random_bucket *r, - __u32 x, __u32 y); +/* + * Forward procedure declarations + */ +#ifdef CONFIG_SYSCTL +static void sysctl_init_random(struct entropy_store *random_state); +#endif -static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y); +/***************************************************************** + * + * Utility functions, with some ASM defined functions for speed + * purposes + * + *****************************************************************/ #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -504,185 +460,236 @@ } #endif - -/* - * Initialize the random pool with standard stuff. +/********************************************************************** * - * NOTE: This is an OS-dependent function. + * OS independent entropy store. Here are the functions which handle + * storing entropy in an entropy pool. + * + **********************************************************************/ + +struct entropy_store { + unsigned add_ptr; + int entropy_count; + int input_rotate; + int extract_count; + struct poolinfo poolinfo; + __u32 *pool; +}; + +/* + * Initialize the entropy store. The input argument is the size of + * the random pool. + * + * Returns an negative error if there is a problem. */ -static void init_std_data(struct random_bucket *r) +static int create_entropy_store(int size, struct entropy_store **ret_bucket) { - __u32 words[2], *p; - int i; - struct timeval tv; + struct entropy_store *r; + struct poolinfo *p; + int poolwords; - do_gettimeofday(&tv); - add_entropy_words(r, tv.tv_sec, tv.tv_usec); + poolwords = (size + 3) / 4; /* Convert bytes->words */ + /* The pool size must be a multiple of 16 32-bit words */ + poolwords = ((poolwords + 15) / 16) * 16; - /* - * This doesnt lock system.utsname. Howeve we are generating - * entropy so a race with a name set here is fine. - */ - p = (__u32 *)&system_utsname; - for (i = sizeof(system_utsname) / sizeof(words); i; i--) { - memcpy(words, p, sizeof(words)); - add_entropy_words(r, words[0], words[1]); - p += sizeof(words)/sizeof(*words); + for (p = poolinfo_table; p->poolwords; p++) { + if (poolwords == p->poolwords) + break; } - + if (p->poolwords == 0) + return -EINVAL; + + r = kmalloc(sizeof(struct entropy_store), GFP_KERNEL); + if (!r) + return -ENOMEM; + + memset (r, 0, sizeof(struct entropy_store)); + r->poolinfo = *p; + + r->pool = kmalloc(poolwords*4, GFP_KERNEL); + if (!r->pool) { + kfree_s(r, sizeof(struct entropy_store)); + return -ENOMEM; + } + memset(r->pool, 0, poolwords*4); + *ret_bucket = r; + return 0; } /* Clear the entropy pool and associated counters. */ -static void rand_clear_pool(void) +static void clear_entropy_store(struct entropy_store *r) { - memset(&random_state, 0, sizeof(random_state)); - init_std_data(&random_state); + r->add_ptr = 0; + r->entropy_count = 0; + r->input_rotate = 0; + r->extract_count = 0; + memset(r->pool, 0, r->poolinfo.poolwords*4); } -void __init rand_initialize(void) +static void free_entropy_store(struct entropy_store *r) { - int i; - - rand_clear_pool(); - for (i = 0; i < NR_IRQS; i++) - irq_timer_state[i] = NULL; - for (i = 0; i < MAX_BLKDEV; i++) - blkdev_timer_state[i] = NULL; - memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state)); - memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state)); - memset(&extract_timer_state, 0, sizeof(struct timer_rand_state)); -#ifdef RANDOM_BENCHMARK - initialize_benchmark(&timer_benchmark, "timer", 0); -#endif - extract_timer_state.dont_count_entropy = 1; + if (r->pool) + kfree(r->pool); + kfree_s(r, sizeof(struct entropy_store)); } -void rand_initialize_irq(int irq) +/* + * This function adds a byte into the entropy "pool". It does not + * update the entropy estimate. The caller should call + * credit_entropy_store if this is appropriate. + * + * The pool is stirred with a primitive polynomial of the appropriate + * degree, and then twisted. We twist by three bits at a time because + * it's cheap to do so and helps slightly in the expected case where + * the entropy is concentrated in the low-order bits. + */ +static void add_entropy_words(struct entropy_store *r, const __u32 *in, + int num) { - struct timer_rand_state *state; - - if (irq >= NR_IRQS || irq_timer_state[irq]) - return; - - /* - * If kmalloc returns null, we just won't use that entropy - * source. - */ - state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) { - irq_timer_state[irq] = state; - memset(state, 0, sizeof(struct timer_rand_state)); + static __u32 const twist_table[8] = { + 0, 0x3b6e20c8, 0x76dc4190, 0x4db26158, + 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; + unsigned i; + int new_rotate; + __u32 w; + + while (num--) { + w = rotate_left(r->input_rotate, *in); + i = r->add_ptr = (r->add_ptr - 1) & (r->poolinfo.poolwords-1); + /* + * Normally, we add 7 bits of rotation to the pool. + * At the beginning of the pool, add an extra 7 bits + * rotation, so that successive passes spread the + * input bits across the pool evenly. + */ + new_rotate = r->input_rotate + 14; + if (i) + new_rotate = r->input_rotate + 7; + r->input_rotate = new_rotate & 31; + + /* XOR in the various taps */ + w ^= r->pool[(i+r->poolinfo.tap1)&(r->poolinfo.poolwords-1)]; + w ^= r->pool[(i+r->poolinfo.tap2)&(r->poolinfo.poolwords-1)]; + w ^= r->pool[(i+r->poolinfo.tap3)&(r->poolinfo.poolwords-1)]; + w ^= r->pool[(i+r->poolinfo.tap4)&(r->poolinfo.poolwords-1)]; + w ^= r->pool[(i+r->poolinfo.tap5)&(r->poolinfo.poolwords-1)]; + w ^= r->pool[i]; + r->pool[i] = (w >> 3) ^ twist_table[w & 7]; } } -void rand_initialize_blkdev(int major, int mode) +/* + * Credit (or debit) the entropy store with n bits of entropy + */ +static void credit_entropy_store(struct entropy_store *r, int num) { - struct timer_rand_state *state; - - if (major >= MAX_BLKDEV || blkdev_timer_state[major]) - return; + int max_entropy = r->poolinfo.poolwords*32; - /* - * If kmalloc returns null, we just won't use that entropy - * source. - */ - state = kmalloc(sizeof(struct timer_rand_state), mode); - if (state) { - blkdev_timer_state[major] = state; - memset(state, 0, sizeof(struct timer_rand_state)); - } + if (r->entropy_count + num < 0) + r->entropy_count = 0; + else if (r->entropy_count + num > max_entropy) + r->entropy_count = max_entropy; + else + r->entropy_count = r->entropy_count + num; } -/* - * This function adds a byte into the entropy "pool". It does not - * update the entropy estimate. The caller must do this if appropriate. +/********************************************************************** * - * This function is tuned for speed above most other considerations. + * Entropy batch input management * - * The pool is stirred with a primitive polynomial of the appropriate degree, - * and then twisted. We twist by three bits at a time because it's - * cheap to do so and helps slightly in the expected case where the - * entropy is concentrated in the low-order bits. - */ -#define MASK(x) ((x) & (POOLWORDS-1)) /* Convenient abreviation */ -static inline void fast_add_entropy_words(struct random_bucket *r, - __u32 x, __u32 y) -{ - static __u32 const twist_table[8] = { - 0, 0x3b6e20c8, 0x76dc4190, 0x4db26158, - 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - unsigned i, j; + * We batch entropy to be added to avoid increasing interrupt latency + * + **********************************************************************/ - i = MASK(r->add_ptr - 2); /* i is always even */ - r->add_ptr = i; +static __u32 *batch_entropy_pool; +static int *batch_entropy_credit; +static int batch_max; +static int batch_head, batch_tail; +static struct tq_struct batch_tqueue; +static void batch_entropy_process(void *private_); -#ifdef ROTATE_PARANOIA - j = r->input_rotate + 14; - if (i) - j -= 7; - r->input_rotate = j & 31; +/* note: the size must be a power of 2 */ +static int batch_entropy_init(int size, struct entropy_store *r) +{ + batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL); + if (!batch_entropy_pool) + return -1; + batch_entropy_credit =kmalloc(size*sizeof(int), GFP_KERNEL); + if (!batch_entropy_credit) { + kfree(batch_entropy_pool); + return -1; + } + batch_head = batch_tail = 0; + batch_max = size; + batch_tqueue.routine = batch_entropy_process; + batch_tqueue.data = r; + return 0; +} - x = rotate_left(r->input_rotate, x); - y = rotate_left(r->input_rotate, y); -#endif +static void batch_entropy_store(__u32 a, __u32 b, int num) +{ + int new; - /* - * XOR in the various taps. Even though logically, we compute - * x and then compute y, we read in y then x order because most - * caches work slightly better with increasing read addresses. - * If a tap is even then we can use the fact that i is even to - * avoid a masking operation. Every polynomial has at least one - * even tap, so j is always used. - * (Is there a nicer way to arrange this code?) - */ -#if TAP1 & 1 - y ^= r->pool[MASK(i+TAP1)]; x ^= r->pool[MASK(i+TAP1+1)]; -#else - j = MASK(i+TAP1); y ^= r->pool[j]; x ^= r->pool[j+1]; -#endif -#if TAP2 & 1 - y ^= r->pool[MASK(i+TAP2)]; x ^= r->pool[MASK(i+TAP2+1)]; -#else - j = MASK(i+TAP2); y ^= r->pool[j]; x ^= r->pool[j+1]; -#endif -#if TAP3 & 1 - y ^= r->pool[MASK(i+TAP3)]; x ^= r->pool[MASK(i+TAP3+1)]; -#else - j = MASK(i+TAP3); y ^= r->pool[j]; x ^= r->pool[j+1]; -#endif -#if TAP4 & 1 - y ^= r->pool[MASK(i+TAP4)]; x ^= r->pool[MASK(i+TAP4+1)]; -#else - j = MASK(i+TAP4); y ^= r->pool[j]; x ^= r->pool[j+1]; -#endif -#if TAP5 == 1 - /* We need to pretend to write pool[i+1] before computing y */ - y ^= r->pool[i]; - x ^= r->pool[i+1]; - x ^= r->pool[MASK(i+TAP5+1)]; - y ^= r->pool[i+1] = x = (x >> 3) ^ twist_table[x & 7]; - r->pool[i] = (y >> 3) ^ twist_table[y & 7]; -#else -# if TAP5 & 1 - y ^= r->pool[MASK(i+TAP5)]; x ^= r->pool[MASK(i+TAP5+1)]; -# else - j = MASK(i+TAP5); y ^= r->pool[j]; x ^= r->pool[j+1]; -# endif - y ^= r->pool[i]; - x ^= r->pool[i+1]; - r->pool[i] = (y >> 3) ^ twist_table[y & 7]; - r->pool[i+1] = (x >> 3) ^ twist_table[x & 7]; + if (!batch_max) + return; + + batch_entropy_pool[2*batch_head] = a; + batch_entropy_pool[(2*batch_head) + 1] = b; + batch_entropy_credit[batch_head] = num; + + new = (batch_head+1) & (batch_max-1); + if (new != batch_tail) { + queue_task(&batch_tqueue, &tq_timer); + batch_head = new; + } else { +#if 0 + printk(KERN_NOTICE "random: batch entropy buffer full\n"); #endif + } } -/* - * For places where we don't need the inlined version - */ -static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y) +static void batch_entropy_process(void *private_) { - fast_add_entropy_words(r, x, y); + int num = 0; + int max_entropy; + struct entropy_store *r = (struct entropy_store *) private_, *p; + + if (!batch_max) + return; + + max_entropy = r->poolinfo.poolwords*32; + while (batch_head != batch_tail) { + add_entropy_words(r, batch_entropy_pool + 2*batch_tail, 2); + p = r; + if (r->entropy_count > max_entropy && (num & 1)) + r = sec_random_state; + credit_entropy_store(r, batch_entropy_credit[batch_tail]); + batch_tail = (batch_tail+1) & (batch_max-1); + num++; + } + if (r->entropy_count >= random_read_wakeup_thresh) + wake_up_interruptible(&random_read_wait); } +/********************************************************************* + * + * Entropy input management + * + *********************************************************************/ + +/* There is one of these per entropy source */ +struct timer_rand_state { + __u32 last_time; + __s32 last_delta,last_delta2; + int dont_count_entropy:1; +}; + +static struct timer_rand_state keyboard_timer_state; +static struct timer_rand_state mouse_timer_state; +static struct timer_rand_state extract_timer_state; +static struct timer_rand_state *irq_timer_state[NR_IRQS]; +static struct timer_rand_state *blkdev_timer_state[MAX_BLKDEV]; + /* * This function adds entropy to the entropy "pool" by using timing * delays. It uses the timer_rand_state structure to make an estimate @@ -695,15 +702,12 @@ * are used for a high-resolution timer. * */ -static void add_timer_randomness(struct random_bucket *r, - struct timer_rand_state *state, unsigned num) +static void add_timer_randomness(struct timer_rand_state *state, unsigned num) { __u32 time; __s32 delta, delta2, delta3; + int entropy = 0; -#ifdef RANDOM_BENCHMARK - begin_benchmark(&timer_benchmark); -#endif #if defined (__i386__) if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { __u32 high; @@ -717,14 +721,12 @@ time = jiffies; #endif - fast_add_entropy_words(r, (__u32)num, time); - /* * Calculate number of bits of randomness we probably added. * We take into account the first, second and third-order deltas * in order to make our estimate. */ - if ((r->entropy_count < POOLBITS) && !state->dont_count_entropy) { + if (!state->dont_count_entropy) { delta = time - state->last_time; state->last_time = time; @@ -753,30 +755,19 @@ delta >>= 1; delta &= (1 << 12) - 1; - r->entropy_count += int_ln_12bits(delta); - - /* Prevent overflow */ - if (r->entropy_count > POOLBITS) - r->entropy_count = POOLBITS; - - /* Wake up waiting processes, if we have enough entropy. */ - if (r->entropy_count >= WAIT_INPUT_BITS) - wake_up_interruptible(&random_read_wait); + entropy = int_ln_12bits(delta); } - -#ifdef RANDOM_BENCHMARK - end_benchmark(&timer_benchmark); -#endif + batch_entropy_store(num, time, entropy); } void add_keyboard_randomness(unsigned char scancode) { - add_timer_randomness(&random_state, &keyboard_timer_state, scancode); + add_timer_randomness(&keyboard_timer_state, scancode); } void add_mouse_randomness(__u32 mouse_data) { - add_timer_randomness(&random_state, &mouse_timer_state, mouse_data); + add_timer_randomness(&mouse_timer_state, mouse_data); } void add_interrupt_randomness(int irq) @@ -784,7 +775,7 @@ if (irq >= NR_IRQS || irq_timer_state[irq] == 0) return; - add_timer_randomness(&random_state, irq_timer_state[irq], 0x100+irq); + add_timer_randomness(irq_timer_state[irq], 0x100+irq); } void add_blkdev_randomness(int major) @@ -798,10 +789,15 @@ return; } - add_timer_randomness(&random_state, blkdev_timer_state[major], - 0x200+major); + add_timer_randomness(blkdev_timer_state[major], 0x200+major); } +/****************************************************************** + * + * Hash function definition + * + *******************************************************************/ + /* * This chunk of code defines a function * void HASH_TRANSFORM(__u32 digest[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE], @@ -821,12 +817,11 @@ * 3) 0x98badcfe * 4) 0x10325476 * 5) 0xc3d2e1f0 (SHA only) - * + * * For /dev/random purposes, the length of the data being hashed is - * fixed in length (at POOLWORDS words), so appending a bit count in - * the usual way is not cryptographically necessary. + * fixed in length, so appending a bit count in the usual way is not + * cryptographically necessary. */ -#define USE_SHA #ifdef USE_SHA @@ -1074,9 +1069,6 @@ /* * MD5 transform algorithm, taken from code written by Colin Plumb, * and put into the public domain - * - * QUESTION: Replace this with SHA, which as generally received better - * reviews from the cryptographic community? */ /* The four core functions - F1 is optimized somewhat */ @@ -1187,39 +1179,94 @@ #endif /* !USE_SHA */ +/********************************************************************* + * + * Entropy extraction routines + * + *********************************************************************/ + +#define EXTRACT_ENTROPY_USER 1 +#define EXTRACT_ENTROPY_SECONDARY 2 +#define TMP_BUF_SIZE (HASH_BUFFER_SIZE + HASH_EXTRA_SIZE) +#define SEC_XFER_SIZE (TMP_BUF_SIZE*4) + +static ssize_t extract_entropy(struct entropy_store *r, void * buf, + size_t nbytes, int flags); + +/* + * This utility inline function is responsible for transfering entropy + * from the primary pool to the secondary extraction pool. We pull + * randomness under two conditions; one is if there isn't enough entropy + * in the secondary pool. The other is after we have extract 1024 bytes, + * at which point we do a "catastrophic reseeding". + */ +static inline void xfer_secondary_pool(struct entropy_store *r, + size_t nbytes) +{ + __u32 tmp[TMP_BUF_SIZE]; + + if (r->entropy_count < nbytes*8) { + extract_entropy(random_state, tmp, sizeof(tmp), 0); + add_entropy_words(r, tmp, TMP_BUF_SIZE); + credit_entropy_store(r, TMP_BUF_SIZE*8); + } + if (r->extract_count > 1024) { + extract_entropy(random_state, tmp, sizeof(tmp), 0); + add_entropy_words(r, tmp, TMP_BUF_SIZE); + r->extract_count = 0; + } +} -#if POOLWORDS % 16 != 0 -#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words. -#endif /* * This function extracts randomness from the "entropy pool", and * returns it in a buffer. This function computes how many remaining * bits of entropy are left in the pool, but it does not restrict the - * number of bytes that are actually obtained. + * number of bytes that are actually obtained. If the EXTRACT_ENTROPY_USER + * flag is given, then the buf pointer is assumed to be in user space. + * If the EXTRACT_ENTROPY_SECONDARY flag is given, then this function will + * + * Note: extract_entropy() assumes that POOLWORDS is a multiple of 16 words. */ -static ssize_t extract_entropy(struct random_bucket *r, char * buf, - size_t nbytes, int to_user) +static ssize_t extract_entropy(struct entropy_store *r, void * buf, + size_t nbytes, int flags) { ssize_t ret, i; - __u32 tmp[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE]; + __u32 tmp[TMP_BUF_SIZE]; __u32 x; - add_timer_randomness(r, &extract_timer_state, nbytes); + add_timer_randomness(&extract_timer_state, nbytes); /* Redundant, but just in case... */ - if (r->entropy_count > POOLBITS) - r->entropy_count = POOLBITS; + if (r->entropy_count > r->poolinfo.poolwords) + r->entropy_count = r->poolinfo.poolwords; + + if (flags & EXTRACT_ENTROPY_SECONDARY) + xfer_secondary_pool(r, nbytes); - ret = nbytes; if (r->entropy_count / 8 >= nbytes) r->entropy_count -= nbytes*8; else r->entropy_count = 0; - if (r->entropy_count < WAIT_OUTPUT_BITS) + if (r->entropy_count < random_write_wakeup_thresh) wake_up_interruptible(&random_write_wait); + + r->extract_count += nbytes; + ret = 0; while (nbytes) { + /* + * Check if we need to break out or reschedule.... + */ + if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) { + if (signal_pending(current)) { + if (ret == 0) + ret = -ERESTARTSYS; + break; + } + schedule(); + } + /* Hash the pool to get the output */ tmp[0] = 0x67452301; tmp[1] = 0xefcdab89; @@ -1228,39 +1275,34 @@ #ifdef USE_SHA tmp[4] = 0xc3d2e1f0; #endif - for (i = 0; i < POOLWORDS; i += 16) - HASH_TRANSFORM(tmp, r->pool+i); - /* - * The following code does two separate things that happen - * to both work two words at a time, so are convenient - * to do together. - * - * First, this feeds the output back into the pool so - * that the next call will return different results. - * Any perturbation of the pool's state would do, even - * changing one bit, but this mixes the pool nicely. - * - * Second, this folds the output in half to hide the data - * fed back into the pool from the user and further mask - * any patterns in the hash output. (The exact folding - * pattern is not important; the one used here is quick.) + * As we hash the pool, we mix intermediate values of + * the hash back into the pool. This eliminates + * backtracking attacks (where the attacker knows + * the state of the pool plus the current outputs, and + * attempts to find previous ouputs), unless the hash + * function can be inverted. */ - for (i = 0; i < HASH_BUFFER_SIZE/2; i++) { - x = tmp[i + (HASH_BUFFER_SIZE+1)/2]; - add_entropy_words(r, tmp[i], x); - tmp[i] ^= x; + for (i = 0, x = 0; i < r->poolinfo.poolwords; i += 16, x+=2) { + HASH_TRANSFORM(tmp, r->pool+i); + add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1); } + + /* + * In case the hash function has some recognizable + * output pattern, we fold it in half. + */ + for (i = 0; i < HASH_BUFFER_SIZE/2; i++) + tmp[i] ^= tmp[i + (HASH_BUFFER_SIZE+1)/2]; #if HASH_BUFFER_SIZE & 1 /* There's a middle word to deal with */ x = tmp[HASH_BUFFER_SIZE/2]; - add_entropy_words(r, x, (__u32)((unsigned long)buf)); x ^= (x >> 16); /* Fold it in half */ ((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x; #endif /* Copy data to destination buffer */ i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2); - if (to_user) { + if (flags & EXTRACT_ENTROPY_USER) { i -= copy_to_user(buf, (__u8 const *)tmp, i); if (!i) { ret = -EFAULT; @@ -1270,16 +1312,8 @@ memcpy(buf, (__u8 const *)tmp, i); nbytes -= i; buf += i; - add_timer_randomness(r, &extract_timer_state, nbytes); - if (to_user && current->need_resched) - { - if (signal_pending(current)) - { - ret = -EINTR; - break; - } - schedule(); - } + ret += i; + add_timer_randomness(&extract_timer_state, nbytes); } /* Wipe data just returned from memory */ @@ -1295,9 +1329,108 @@ */ void get_random_bytes(void *buf, int nbytes) { - extract_entropy(&random_state, (char *) buf, nbytes, 0); + extract_entropy(sec_random_state, (char *) buf, nbytes, + EXTRACT_ENTROPY_SECONDARY); +} + +/********************************************************************* + * + * Functions to interface with Linux + * + *********************************************************************/ + +/* + * Initialize the random pool with standard stuff. + * + * NOTE: This is an OS-dependent function. + */ +static void init_std_data(struct entropy_store *r) +{ + struct timeval tv; + __u32 words[2]; + char *p; + int i; + + do_gettimeofday(&tv); + words[0] = tv.tv_sec; + words[1] = tv.tv_usec; + add_entropy_words(r, words, 2); + + /* + * This doesn't lock system.utsname. However, we are generating + * entropy so a race with a name set here is fine. + */ + p = (char *) &system_utsname; + for (i = sizeof(system_utsname) / sizeof(words); i; i--) { + memcpy(words, p, sizeof(words)); + add_entropy_words(r, words, sizeof(words)/4); + p += sizeof(words); + } +} + +void __init rand_initialize(void) +{ + int i; + + if (create_entropy_store(DEFAULT_POOL_SIZE, &random_state)) + return; /* Error, return */ + if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state)) + return; /* Error, return */ + if (create_entropy_store(SECONDARY_POOL_SIZE, &sec_random_state)) + return; /* Error, return */ + clear_entropy_store(random_state); + clear_entropy_store(sec_random_state); + init_std_data(random_state); +#ifdef CONFIG_SYSCTL + sysctl_init_random(random_state); +#endif + for (i = 0; i < NR_IRQS; i++) + irq_timer_state[i] = NULL; + for (i = 0; i < MAX_BLKDEV; i++) + blkdev_timer_state[i] = NULL; + memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state)); + memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state)); + memset(&extract_timer_state, 0, sizeof(struct timer_rand_state)); + extract_timer_state.dont_count_entropy = 1; +} + +void rand_initialize_irq(int irq) +{ + struct timer_rand_state *state; + + if (irq >= NR_IRQS || irq_timer_state[irq]) + return; + + /* + * If kmalloc returns null, we just won't use that entropy + * source. + */ + state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) { + memset(state, 0, sizeof(struct timer_rand_state)); + irq_timer_state[irq] = state; + } +} + +void rand_initialize_blkdev(int major, int mode) +{ + struct timer_rand_state *state; + + if (major >= MAX_BLKDEV || blkdev_timer_state[major]) + return; + + /* + * If kmalloc returns null, we just won't use that entropy + * source. + */ + state = kmalloc(sizeof(struct timer_rand_state), mode); + if (state) { + memset(state, 0, sizeof(struct timer_rand_state)); + blkdev_timer_state[major] = state; + } } + static ssize_t random_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { @@ -1309,11 +1442,13 @@ add_wait_queue(&random_read_wait, &wait); while (nbytes > 0) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); n = nbytes; - if (n > random_state.entropy_count / 8) - n = random_state.entropy_count / 8; + if (n > SEC_XFER_SIZE) + n = SEC_XFER_SIZE; + if (n > random_state->entropy_count / 8) + n = random_state->entropy_count / 8; if (n == 0) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; @@ -1326,7 +1461,9 @@ schedule(); continue; } - n = extract_entropy(&random_state, buf, n, 1); + n = extract_entropy(sec_random_state, buf, n, + EXTRACT_ENTROPY_USER | + EXTRACT_ENTROPY_SECONDARY); if (n < 0) { retval = n; break; @@ -1351,10 +1488,12 @@ } static ssize_t -random_read_unlimited(struct file * file, char * buf, +urandom_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { - return extract_entropy(&random_state, buf, nbytes, 1); + return extract_entropy(sec_random_state, buf, nbytes, + EXTRACT_ENTROPY_USER | + EXTRACT_ENTROPY_SECONDARY); } static unsigned int @@ -1365,9 +1504,9 @@ poll_wait(file, &random_read_wait, wait); poll_wait(file, &random_write_wait, wait); mask = 0; - if (random_state.entropy_count >= WAIT_INPUT_BITS) + if (random_state->entropy_count >= random_read_wakeup_thresh) mask |= POLLIN | POLLRDNORM; - if (random_state.entropy_count < WAIT_OUTPUT_BITS) + if (random_state->entropy_count < random_write_wakeup_thresh) mask |= POLLOUT | POLLWRNORM; return mask; } @@ -1378,7 +1517,6 @@ { int ret = 0; size_t bytes; - unsigned i; __u32 buf[16]; const char *p = buffer; size_t c = count; @@ -1393,11 +1531,10 @@ } c -= bytes; p += bytes; - - i = (unsigned)((bytes-1) / (2 * sizeof(__u32))); - do { - add_entropy_words(&random_state, buf[2*i], buf[2*i+1]); - } while (i--); + + /* Convert bytes to words */ + bytes = (bytes + 3) / sizeof(__u32); + add_entropy_words(random_state, buf, bytes); } if (p == buffer) { return (ssize_t)ret; @@ -1417,7 +1554,7 @@ switch (cmd) { case RNDGETENTCNT: - ent_count = random_state.entropy_count; + ent_count = random_state->entropy_count; if (put_user(ent_count, (int *) arg)) return -EFAULT; return 0; @@ -1426,45 +1563,31 @@ return -EPERM; if (get_user(ent_count, (int *) arg)) return -EFAULT; - /* - * Add i to entropy_count, limiting the result to be - * between 0 and POOLBITS. - */ - if (ent_count < -random_state.entropy_count) - random_state.entropy_count = 0; - else if (ent_count > POOLBITS) - random_state.entropy_count = POOLBITS; - else { - random_state.entropy_count += ent_count; - if (random_state.entropy_count > POOLBITS) - random_state.entropy_count = POOLBITS; - if (random_state.entropy_count < 0) - random_state.entropy_count = 0; - } + credit_entropy_store(random_state, ent_count); /* * Wake up waiting processes if we have enough * entropy. */ - if (random_state.entropy_count >= WAIT_INPUT_BITS) + if (random_state->entropy_count >= random_read_wakeup_thresh) wake_up_interruptible(&random_read_wait); return 0; case RNDGETPOOL: if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; - ent_count = random_state.entropy_count; + ent_count = random_state->entropy_count; if (put_user(ent_count, p++)) return -EFAULT; if (get_user(size, p)) return -EFAULT; - if (put_user(POOLWORDS, p++)) + if (put_user(random_state->poolinfo.poolwords, p++)) return -EFAULT; if (size < 0) return -EINVAL; - if (size > POOLWORDS) - size = POOLWORDS; - if (copy_to_user(p, random_state.pool, size*sizeof(__u32))) + if (size > random_state->poolinfo.poolwords) + size = random_state->poolinfo.poolwords; + if (copy_to_user(p, random_state->pool, size*sizeof(__u32))) return -EFAULT; return 0; case RNDADDENTROPY: @@ -1481,36 +1604,25 @@ size, &file->f_pos); if (retval < 0) return retval; - /* - * Add ent_count to entropy_count, limiting the result to be - * between 0 and POOLBITS. - */ - if (ent_count > POOLBITS) - random_state.entropy_count = POOLBITS; - else { - random_state.entropy_count += ent_count; - if (random_state.entropy_count > POOLBITS) - random_state.entropy_count = POOLBITS; - if (random_state.entropy_count < 0) - random_state.entropy_count = 0; - } + credit_entropy_store(random_state, ent_count); /* * Wake up waiting processes if we have enough * entropy. */ - if (random_state.entropy_count >= WAIT_INPUT_BITS) + if (random_state->entropy_count >= random_read_wakeup_thresh) wake_up_interruptible(&random_read_wait); return 0; case RNDZAPENTCNT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - random_state.entropy_count = 0; + random_state->entropy_count = 0; return 0; case RNDCLEARPOOL: /* Clear the entropy pool and associated counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - rand_clear_pool(); + clear_entropy_store(random_state); + init_std_data(random_state); return 0; default: return -EINVAL; @@ -1532,7 +1644,7 @@ struct file_operations urandom_fops = { NULL, /* unrandom_lseek */ - random_read_unlimited, + urandom_read, random_write, NULL, /* urandom_readdir */ NULL, /* urandom_poll */ @@ -1543,6 +1655,210 @@ NULL /* no special release code */ }; +/*************************************************************** + * Random UUID interface + * + * Used here for a Boot ID, but can be useful for other kernel + * drivers. + ***************************************************************/ + +/* + * Generate random UUID + */ +void generate_random_uuid(unsigned char uuid_out[16]) +{ + get_random_bytes(uuid_out, 16); + /* Set UUID version to 4 --- truely random generation */ + uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40; + /* Set the UUID variant to DCE */ + uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; +} + +/******************************************************************** + * + * Sysctl interface + * + ********************************************************************/ + +#ifdef CONFIG_SYSCTL + +#include + +static int sysctl_poolsize; +static int min_read_thresh, max_read_thresh; +static int min_write_thresh, max_write_thresh; +static char sysctl_bootid[16]; + +/* + * This function handles a request from the user to change the pool size + * of the primary entropy store. + */ +static int change_poolsize(int poolsize) +{ + struct entropy_store *new_store, *old_store; + int ret; + + if ((ret = create_entropy_store(poolsize, &new_store))) + return ret; + + add_entropy_words(new_store, random_state->pool, + random_state->poolinfo.poolwords); + credit_entropy_store(new_store, random_state->entropy_count); + + sysctl_init_random(new_store); + old_store = random_state; + random_state = batch_tqueue.data = new_store; + free_entropy_store(old_store); + return 0; +} + +static int proc_do_poolsize(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int ret; + + sysctl_poolsize = random_state->poolinfo.poolwords * 4; + + ret = proc_dointvec(table, write, filp, buffer, lenp); + if (ret || !write || + (sysctl_poolsize == random_state->poolinfo.poolwords * 4)) + return ret; + + return change_poolsize(sysctl_poolsize); +} + +static int poolsize_strategy(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + int len; + + sysctl_poolsize = random_state->poolinfo.poolwords * 4; + + /* + * We only handle the write case, since the read case gets + * handled by the default handler (and we don't care if the + * write case happens twice; it's harmless). + */ + if (newval && newlen) { + len = newlen; + if (len > table->maxlen) + len = table->maxlen; + if (copy_from_user(table->data, newval, len)) + return -EFAULT; + } + + if (sysctl_poolsize != random_state->poolinfo.poolwords * 4) + return change_poolsize(sysctl_poolsize); + + return 0; +} + +/* + * These functions is used to return both the bootid UUID, and random + * UUID. The difference is in whether table->data is NULL; if it is, + * then a new UUID is generated and returned to the user. + * + * If the user accesses this via the proc interface, it will be returned + * as an ASCII string in the standard UUID format. If accesses via the + * sysctl system call, it is returned as 16 bytes of binary data. + */ +static int proc_do_uuid(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + ctl_table fake_table; + unsigned char buf[64], tmp_uuid[16], *uuid; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + uuid[8] = 0; + } + if (uuid[8] == 0) + generate_random_uuid(uuid); + + sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + fake_table.data = buf; + fake_table.maxlen = sizeof(buf); + + return proc_dostring(&fake_table, write, filp, buffer, lenp); +} + +static int uuid_strategy(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + unsigned char tmp_uuid[16], *uuid; + int len; + + if (!oldval || !oldlenp) + return 1; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + uuid[8] = 0; + } + if (uuid[8] == 0) + generate_random_uuid(uuid); + + get_user(len, oldlenp); + if (len) { + if (len > 16) + len = 16; + if (copy_to_user(oldval, table->data, len)) + return -EFAULT; + if (put_user(len, oldlenp)) + return -EFAULT; + } + return 1; +} + +ctl_table random_table[] = { + {RANDOM_POOLSIZE, "poolsize", + &sysctl_poolsize, sizeof(int), 0644, NULL, + &proc_do_poolsize, &poolsize_strategy}, + {RANDOM_ENTROPY_COUNT, "entropy_avail", + NULL, sizeof(int), 0444, NULL, + &proc_dointvec}, + {RANDOM_READ_THRESH, "read_wakeup_threshold", + &random_read_wakeup_thresh, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, 0, + &min_read_thresh, &max_read_thresh}, + {RANDOM_WRITE_THRESH, "write_wakeup_threshold", + &random_write_wakeup_thresh, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, 0, + &min_write_thresh, &max_write_thresh}, + {RANDOM_BOOT_ID, "boot_id", + &sysctl_bootid, 16, 0444, NULL, + &proc_do_uuid, &uuid_strategy}, + {RANDOM_UUID, "uuid", + NULL, 16, 0444, NULL, + &proc_do_uuid, &uuid_strategy}, + {0} +}; + +static void sysctl_init_random(struct entropy_store *random_state) +{ + min_read_thresh = 8; + min_write_thresh = 0; + max_read_thresh = max_write_thresh = + random_state->poolinfo.poolwords * 32; + random_table[1].data = &random_state->entropy_count; +} +#endif /* CONFIG_SYSCTL */ + +/******************************************************************** + * + * Random funtions for networking + * + ********************************************************************/ + /* * TCP initial sequence number picking. This uses the random number * generator to pick an initial secret value. This value is hashed @@ -1831,71 +2147,3 @@ return (cookie - tmp[17]) & COOKIEMASK; /* Leaving the data behind */ } #endif - - -#ifdef RANDOM_BENCHMARK -/* - * This is so we can do some benchmarking of the random driver, to see - * how much overhead add_timer_randomness really takes. This only - * works on a Pentium, since it depends on the timer clock... - * - * Note: the results of this benchmark as of this writing (5/27/96) - * - * On a Pentium, add_timer_randomness() takes between 150 and 1000 - * clock cycles, with an average of around 600 clock cycles. On a 75 - * MHz Pentium, this translates to 2 to 13 microseconds, with an - * average time of 8 microseconds. This should be fast enough so we - * can use add_timer_randomness() even with the fastest of interrupts... - */ -static inline unsigned long long get_clock_cnt(void) -{ - unsigned long low, high; - __asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high)); - return (((unsigned long long) high << 32) | low); -} - -static void __init -initialize_benchmark(struct random_benchmark *bench, - const char *descr, int unit) -{ - bench->times = 0; - bench->accum = 0; - bench->max = 0; - bench->min = 1 << 31; - bench->descr = descr; - bench->unit = unit; -} - -static void begin_benchmark(struct random_benchmark *bench) -{ -#ifdef BENCHMARK_NOINT - save_flags(bench->flags); cli(); -#endif - bench->start_time = get_clock_cnt(); -} - -static void end_benchmark(struct random_benchmark *bench) -{ - unsigned long ticks; - - ticks = (unsigned long) (get_clock_cnt() - bench->start_time); -#ifdef BENCHMARK_NOINT - restore_flags(bench->flags); -#endif - if (ticks < bench->min) - bench->min = ticks; - if (ticks > bench->max) - bench->max = ticks; - bench->accum += ticks; - bench->times++; - if (bench->times == BENCHMARK_INTERVAL) { - printk("Random benchmark: %s %d: %lu min, %lu avg, " - "%lu max\n", bench->descr, bench->unit, bench->min, - bench->accum / BENCHMARK_INTERVAL, bench->max); - bench->times = 0; - bench->accum = 0; - bench->max = 0; - bench->min = 1 << 31; - } -} -#endif /* RANDOM_BENCHMARK */ diff -u --recursive --new-file v2.3.15/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v2.3.15/linux/drivers/char/riscom8.c Thu Aug 5 14:34:01 1999 +++ linux/drivers/char/riscom8.c Tue Aug 31 11:30:48 1999 @@ -1027,7 +1027,7 @@ rc_out(bp, RC_DTR, bp->DTR); } sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) diff -u --recursive --new-file v2.3.15/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.3.15/linux/drivers/char/rocket.c Thu Aug 5 15:04:52 1999 +++ linux/drivers/char/rocket.c Tue Aug 31 11:30:48 1999 @@ -88,8 +88,6 @@ #endif #if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */ #include -#else -#define __initfunc(x) x #endif #include "rocket_int.h" @@ -890,7 +888,7 @@ sSetDTR(&info->channel); sSetRTS(&info->channel); } - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) { if (info->flags & ROCKET_HUP_NOTIFY) diff -u --recursive --new-file v2.3.15/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.3.15/linux/drivers/char/rtc.c Thu Aug 5 14:34:02 1999 +++ linux/drivers/char/rtc.c Tue Aug 31 11:25:33 1999 @@ -551,7 +551,7 @@ return -EIO; found: - rtc_port = edev->base_address[0]; + rtc_port = edev->resource[0].start; rtc_irq = edev->irqs[0]; /* * XXX Interrupt pin #7 in Espresso is shared between RTC and diff -u --recursive --new-file v2.3.15/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.3.15/linux/drivers/char/selection.c Tue May 11 14:37:40 1999 +++ linux/drivers/char/selection.c Tue Aug 31 11:30:48 1999 @@ -301,7 +301,7 @@ poke_blanked_console(); add_wait_queue(&vt->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (test_bit(TTY_THROTTLED, &tty->flags)) { schedule(); continue; diff -u --recursive --new-file v2.3.15/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.3.15/linux/drivers/char/serial.c Thu Jul 1 15:09:01 1999 +++ linux/drivers/char/serial.c Tue Aug 31 12:59:27 1999 @@ -2,6 +2,8 @@ * linux/drivers/char/serial.c * * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, + * 1998, 1999 Theodore Ts'o * * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now * much more extensible to support other serial cards based on the @@ -32,6 +34,11 @@ * 4/98: Added changes to support the ARM architecture proposed by * Russell King * + * 5/99: Updated to include support for the XR16C850 and ST16C654 + * uarts. Stuart MacDonald + * + * 8/99: Generalized PCI support added. Theodore Ts'o + * * This module exports the following rs232 io functions: * * int rs_init(void); @@ -62,13 +69,16 @@ * ever possible. */ +#include +#include + #undef SERIAL_PARANOIA_CHECK #define CONFIG_SERIAL_NOPAUSE_IO #define SERIAL_DO_RESTART +#define CONFIG_SERIAL_PCI_MEMMAPPED #if 0 -/* Normally these defines are controlled by the autoconf.h */ - +/* These defines are normally controlled by the autoconf.h */ #define CONFIG_SERIAL_MANY_PORTS #define CONFIG_SERIAL_SHARE_IRQ #define CONFIG_SERIAL_DETECT_IRQ @@ -76,6 +86,19 @@ #define CONFIG_HUB6 #endif +#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072)) +#define ENABLE_SERIAL_PCI +#define CONFIG_SERIAL_SHARE_IRQ +#endif + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_PCI + /* Sanity checks */ #ifdef CONFIG_SERIAL_MULTIPORT @@ -93,18 +116,11 @@ #endif #endif -/* Set of debugging defines */ - -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 256 #define IRQ_T(state) \ - ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) #define SERIAL_INLINE @@ -119,8 +135,34 @@ * End of serial driver configuration section. */ -#include +#if (LINUX_VERSION_CODE > 66304) +#define NEW_MODULES +#ifdef LOCAL_HEADERS /* We're building standalone */ +#define MODULE +#endif +#endif + +#ifdef NEW_MODULES +#ifdef MODVERSIONS +#include +#endif +#include +#else /* !NEW_MODULES */ +#ifdef MODVERSIONS +#define MODULE +#endif #include +#endif /* NEW_MODULES */ + +#ifdef LOCAL_HEADERS +#include "serial_local.h" +#else +#include +#include +#include +static char *serial_version = "4.30"; +#endif + #include #include #include @@ -128,8 +170,6 @@ #include #include #include -#include -#include #include #include #include @@ -137,31 +177,47 @@ #include #include #include +#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */ #include +#else +#define __initfunc(x) x +#endif #include #ifdef CONFIG_SERIAL_CONSOLE #include #endif +#ifdef ENABLE_SERIAL_PCI +#include +#endif #include #include #include -#include #include -#include + +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 2 +#else +#define SERIAL_DEV_OFFSET 0 +#endif #ifdef SERIAL_INLINE #define _INLINE_ inline #endif static char *serial_name = "Serial driver"; -static char *serial_version = "4.27"; static DECLARE_TASK_QUEUE(tq_serial); static struct tty_driver serial_driver, callout_driver; static int serial_refcount; +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -194,20 +250,33 @@ { "16450", 1, 0 }, { "16550", 1, 0 }, { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "cirrus", 1, 0 }, - { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, + { "cirrus", 1, 0 }, /* usurped by cyclades.c */ + { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, + { "Startech", 1, 0}, /* usurped by cyclades.c */ + { "16C950", 128, UART_CLEAR_FIFO | UART_USE_FIFO}, + { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, { 0, 0} }; -static struct serial_state rs_table[] = { +static struct serial_state rs_table[RS_TABLE_SIZE] = { SERIAL_PORT_DFNS /* Defined in serial.h */ }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) +#ifdef ENABLE_SERIAL_PCI +#define NR_PCI_BOARDS 8 +static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; +static int serial_pci_board_idx = 0; +#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) +#endif /* ENABLE_SERIAL_PCI */ + static struct tty_struct *serial_table[NR_PORTS]; static struct termios *serial_termios[NR_PORTS]; static struct termios *serial_termios_locked[NR_PORTS]; @@ -226,7 +295,93 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + +/* + * Provide backwards compatibility for kernels prior to 2.1.XX. + */ +#if (LINUX_VERSION_CODE < 0x20000) +typedef dev_t kdev_t; +#endif + +#if (LINUX_VERSION_CODE < 0x02017E) +static signed long schedule_timeout(signed long timeout) +{ + unsigned long expire; + + expire = timeout + jiffies; + + current->timeout = jiffies + timeout; + schedule(); + + timeout = expire - jiffies; + return timeout < 0 ? 0 : timeout; +} +#endif + +#ifndef time_after +#define time_after(a,b) ((long)(b) - (long)(a) < 0) +#endif + +#if (LINUX_VERSION_CODE < 0x020100) +static inline int irq_cannonicalize(int irq) +{ + return ((irq == 2) ? 9 : irq); +} +#endif + +#if (LINUX_VERSION_CODE < 131336) +static int copy_from_user(void *to, const void *from_user, unsigned long len) +{ + int error; + + error = verify_area(VERIFY_READ, from_user, len); + if (error) + return len; + memcpy_fromfs(to, from_user, len); + return 0; +} + +static int copy_to_user(void *to_user, const void *from, unsigned long len) +{ + int error; + + error = verify_area(VERIFY_WRITE, to_user, len); + if (error) + return len; + memcpy_tofs(to_user, from, len); + return 0; +} + +static inline int signal_pending(struct task_struct *p) +{ + return (p->signal & (~p->blocked != 0)); +} + +#else +#include +#endif + +#ifdef CAP_SYS_ADMIN +#define serial_isroot() (capable(CAP_SYS_ADMIN)) +#else +#define serial_isroot() (suser()) +#endif + +#if (LINUX_VERSION_CODE < 131394) /* 2.1.66 */ +#define test_and_clear_bit(x,y) clear_bit(x,y) + +static inline void remove_bh(int nr) +{ + bh_base[nr] = NULL; + bh_mask &= ~(1 << nr); +} +#endif + static inline int serial_paranoia_check(struct async_struct *info, kdev_t device, const char *routine) @@ -257,6 +412,11 @@ return inb(info->port+1); } else #endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + if (info->iomem_base) + return readb(info->iomem_base + (offset<iomem_reg_shift)); + else +#endif return inb(info->port + offset); } @@ -268,6 +428,11 @@ return inb_p(info->port+1); } else #endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + if (info->iomem_base) + return readb(info->iomem_base + (offset<iomem_reg_shift)); + else +#endif #ifdef CONFIG_SERIAL_NOPAUSE_IO return inb(info->port + offset); #else @@ -283,6 +448,11 @@ outb(value, info->port+1); } else #endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + if (info->iomem_base) + writeb(value, info->iomem_base + (offset<iomem_reg_shift)); + else +#endif outb(value, info->port+offset); } @@ -295,6 +465,11 @@ outb_p(value, info->port+1); } else #endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + if (info->iomem_base) + writeb(value, info->iomem_base + (offset<iomem_reg_shift)); + else +#endif #ifdef CONFIG_SERIAL_NOPAUSE_IO outb(value, info->port+offset); #else @@ -303,6 +478,26 @@ } /* + * For the 16C950 + */ +void serial_icr_write(struct async_struct *info, int offset, int value) +{ + serial_out(info, UART_SCR, offset); + serial_out(info, UART_ICR, value); +} + +unsigned int serial_icr_read(struct async_struct *info, int offset) +{ + int value; + + serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD); + serial_out(info, UART_SCR, offset); + value = serial_in(info, UART_ICR); + serial_icr_write(info, UART_ACR, info->ACR); + return value; +} + +/* * ------------------------------------------------------------ * rs_stop() and rs_start() * @@ -323,6 +518,10 @@ info->IER &= ~UART_IER_THRI; serial_out(info, UART_IER, info->IER); } + if (info->state->type == PORT_16C950) { + info->ACR |= UART_ACR_TXDIS; + serial_icr_write(info, UART_ACR, info->ACR); + } restore_flags(flags); } @@ -339,6 +538,10 @@ info->IER |= UART_IER_THRI; serial_out(info, UART_IER, info->IER); } + if (info->state->type == PORT_16C950) { + info->ACR &= ~UART_ACR_TXDIS; + serial_icr_write(info, UART_ACR, info->ACR); + } restore_flags(flags); } @@ -453,7 +656,11 @@ ignore_char: *status = serial_inp(info, UART_LSR); } while (*status & UART_LSR_DR); +#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ tty_flip_buffer_push(tty); +#else + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +#endif } static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) @@ -932,7 +1139,7 @@ goto errout; } - if (!state->port || !state->type) { + if (!CONFIGURED_SERIAL_PORT(state) || !state->type) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); free_page(page); @@ -951,8 +1158,28 @@ /* Wake up UART */ serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, UART_EFR_ECB); + /* + * Turn off LCR == 0xBF so we actually set the IER + * register on the XR16C850 + */ + serial_outp(info, UART_LCR, 0); serial_outp(info, UART_IER, 0); + /* + * Now reset LCR so we can turn off the ECB bit + */ + serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, 0); + /* + * For a XR16C850, we need to set the trigger levels + */ + if (info->state->type == PORT_16850) { + serial_outp(info, UART_FCTR, UART_FCTR_TRGD | + UART_FCTR_RX); + serial_outp(info, UART_TRG, UART_TRG_96); + serial_outp(info, UART_FCTR, UART_FCTR_TRGD | + UART_FCTR_TX); + serial_outp(info, UART_TRG, UART_TRG_96); + } serial_outp(info, UART_LCR, 0); } @@ -961,13 +1188,38 @@ serial_outp(info, UART_IER, 0); } + if (info->state->type == PORT_16C950) { + /* Wake up and initialize UART */ + info->ACR = 0; + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_IER, 0); + serial_outp(info, UART_LCR, 0); + serial_icr_write(info, UART_CSR, 0); /* Reset the UART */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_LCR, 0); + } + /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) */ - if (uart_config[state->type].flags & UART_CLEAR_FIFO) - serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + if (uart_config[state->type].flags & UART_CLEAR_FIFO) { + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + } + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(info, UART_LSR); + (void) serial_inp(info, UART_RX); + (void) serial_inp(info, UART_IIR); + (void) serial_inp(info, UART_MSR); /* * At this point there's no way the LSR could still be 0xFF; @@ -975,7 +1227,8 @@ * here. */ if (serial_inp(info, UART_LSR) == 0xff) { - if (capable(CAP_SYS_ADMIN)) { + printk("LSR safety check engaged!\n"); + if (serial_isroot()) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); } else @@ -1007,7 +1260,7 @@ retval = request_irq(state->irq, handler, IRQ_T(state), "serial", NULL); if (retval) { - if (capable(CAP_SYS_ADMIN)) { + if (serial_isroot()) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1028,14 +1281,6 @@ figure_IRQ_timeout(state->irq); /* - * Clear the interrupt registers. - */ - /* (void) serial_inp(info, UART_LSR); */ /* (see above) */ - (void) serial_inp(info, UART_RX); - (void) serial_inp(info, UART_IIR); - (void) serial_inp(info, UART_MSR); - - /* * Now, initialize the UART */ serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ @@ -1053,12 +1298,7 @@ if (state->irq != 0) info->MCR |= UART_MCR_OUT2; } -#if defined(__alpha__) && !defined(CONFIG_PCI) - /* - * DEC did something gratutiously wrong.... - */ - info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2; -#endif + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ serial_outp(info, UART_MCR, info->MCR); /* @@ -1097,6 +1337,7 @@ /* * Set up the tty->alt_speed kludge */ +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ if (info->tty) { if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; @@ -1107,6 +1348,7 @@ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } +#endif /* * and set the speed of the serial port @@ -1193,12 +1435,7 @@ } else #endif info->MCR &= ~UART_MCR_OUT2; -#if defined(__alpha__) && !defined(CONFIG_PCI) - /* - * DEC did something gratutiously wrong.... - */ - info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2; -#endif + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ /* disable break condition */ serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); @@ -1230,6 +1467,37 @@ restore_flags(flags); } +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, + 600, 1200, 1800, 2400, 4800, 9600, 19200, + 38400, 57600, 115200, 230400, 460800, 0 }; + +static int tty_get_baud_rate(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned int cflag, i; + + cflag = tty->termios->c_cflag; + + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 2) + tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 2; + } + return baud_table[i]; +} +#endif + /* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. @@ -1237,7 +1505,6 @@ static void change_speed(struct async_struct *info, struct termios *old_termios) { - unsigned short port; int quot = 0, baud_base, baud; unsigned cflag, cval, fcr = 0; int bits; @@ -1246,7 +1513,7 @@ if (!info->tty || !info->tty->termios) return; cflag = info->tty->termios->c_cflag; - if (!(port = info->port)) + if (!CONFIGURED_SERIAL_PORT(info)) return; /* byte size and parity */ @@ -1278,6 +1545,18 @@ if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ baud_base = info->state->baud_base; + if (info->state->type == PORT_16C950) { + if (baud <= baud_base) + serial_icr_write(info, UART_TCR, 0); + else if (baud <= 2*baud_base) { + serial_icr_write(info, UART_TCR, 0x8); + baud_base = baud_base * 2; + } else if (baud <= 4*baud_base) { + serial_icr_write(info, UART_TCR, 0x4); + baud_base = baud_base * 4; + } else + serial_icr_write(info, UART_TCR, 0); + } if (baud == 38400 && ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) quot = info->state->custom_divisor; @@ -1383,6 +1662,7 @@ if (info->state->type == PORT_16750) serial_outp(info, UART_FCR, fcr); /* set fcr */ serial_outp(info, UART_LCR, cval); /* reset DLAB */ + info->LCR = cval; /* Save LCR */ if (info->state->type != PORT_16750) serial_outp(info, UART_FCR, fcr); /* set fcr */ restore_flags(flags); @@ -1664,7 +1944,7 @@ change_port = (new_serial.port != state->port) || (new_serial.hub6 != state->hub6); - if (!capable(CAP_SYS_ADMIN)) { + if (!serial_isroot()) { if (change_irq || change_port || (new_serial.baud_base != state->baud_base) || (new_serial.type != state->type) || @@ -1721,11 +2001,14 @@ state->type = new_serial.type; state->close_delay = new_serial.close_delay * HZ/100; state->closing_wait = new_serial.closing_wait * HZ/100; +#if (LINUX_VERSION_CODE > 0x200100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif info->xmit_fifo_size = state->xmit_fifo_size = new_serial.xmit_fifo_size; - release_region(state->port,8); + if (state->port) + release_region(state->port,8); if (change_port || change_irq) { /* * We need to shutdown the serial port at the old @@ -1736,7 +2019,7 @@ info->port = state->port = new_serial.port; info->hub6 = state->hub6 = new_serial.hub6; } - if (state->type != PORT_UNKNOWN) + if ((state->type != PORT_UNKNOWN) && state->port) request_region(state->port,8,"serial(set)"); @@ -1747,6 +2030,7 @@ if (((old_state.flags & ASYNC_SPD_MASK) != (state->flags & ASYNC_SPD_MASK)) || (old_state.custom_divisor != state->custom_divisor)) { +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) @@ -1755,6 +2039,7 @@ info->tty->alt_speed = 230400; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; +#endif change_speed(info, 0); } } else @@ -1783,7 +2068,9 @@ status = serial_in(info, UART_LSR); restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result,value); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; } @@ -1807,19 +2094,21 @@ | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - return put_user(result,value); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; } static int set_modem_info(struct async_struct * info, unsigned int cmd, unsigned int *value) { - int error; unsigned int arg; unsigned long flags; - error = get_user(arg, value); - if (error) - return error; + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) @@ -1863,6 +2152,7 @@ return -EINVAL; } save_flags(flags); cli(); + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ serial_out(info, UART_MCR, info->MCR); restore_flags(flags); return 0; @@ -1872,7 +2162,7 @@ { int retval; - if (!capable(CAP_SYS_ADMIN)) + if (!serial_isroot()) return -EPERM; if (info->state->count > 1) @@ -1895,6 +2185,22 @@ /* * rs_break() --- routine which turns the break handling on or off */ +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static void send_break( struct async_struct * info, int duration) +{ + if (!CONFIGURED_SERIAL_PORT(info)) + return; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + duration; + cli(); + info->LCR |= UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + schedule(); + info->LCR &= ~UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + sti(); +} +#else static void rs_break(struct tty_struct *tty, int break_state) { struct async_struct * info = (struct async_struct *)tty->driver_data; @@ -1903,17 +2209,17 @@ if (serial_paranoia_check(info, tty->device, "rs_break")) return; - if (!info->port) + if (!CONFIGURED_SERIAL_PORT(info)) return; save_flags(flags); cli(); if (break_state == -1) - serial_out(info, UART_LCR, - serial_inp(info, UART_LCR) | UART_LCR_SBC); + info->LCR |= UART_LCR_SBC; else - serial_out(info, UART_LCR, - serial_inp(info, UART_LCR) & ~UART_LCR_SBC); + info->LCR &= ~UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); restore_flags(flags); } +#endif #ifdef CONFIG_SERIAL_MULTIPORT static int get_multiport_struct(struct async_struct * info, @@ -1959,7 +2265,7 @@ int retval; void (*handler)(int, void *, struct pt_regs *); - if (!capable(CAP_SYS_ADMIN)) + if (!serial_isroot()) return -EPERM; state = info->state; @@ -2032,11 +2338,13 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct async_struct * info = (struct async_struct *)tty->driver_data; struct async_icount cprev, cnow; /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ + struct serial_icounter_struct icount; unsigned long flags; +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + int retval, tmp; +#endif if (serial_paranoia_check(info, tty->device, "rs_ioctl")) return -ENODEV; @@ -2049,6 +2357,45 @@ } switch (cmd) { +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + 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 (signal_pending(current)) + return -EINTR; + if (!arg) { + send_break(info, HZ/4); /* 1/4 second */ + if (signal_pending(current)) + return -EINTR; + } + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + send_break(info, arg ? arg*(HZ/10) : HZ/4); + if (signal_pending(current)) + return -EINTR; + return 0; + case TIOCGSOFTCAR: + tmp = C_CLOCAL(tty) ? 1 : 0; + if (copy_to_user((void *)arg, &tmp, sizeof(int))) + return -EFAULT; + return 0; + case TIOCSSOFTCAR: + if (copy_from_user(&tmp, (void *)arg, sizeof(int))) + return -EFAULT; + + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (tmp ? CLOCAL : 0)); + return 0; +#endif case TIOCMGET: return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: @@ -2124,31 +2471,21 @@ save_flags(flags); cli(); cnow = info->state->icount; restore_flags(flags); - p_cuser = (struct serial_icounter_struct *) arg; - error = put_user(cnow.cts, &p_cuser->cts); - if (error) return error; - error = put_user(cnow.dsr, &p_cuser->dsr); - if (error) return error; - error = put_user(cnow.rng, &p_cuser->rng); - if (error) return error; - error = put_user(cnow.dcd, &p_cuser->dcd); - if (error) return error; - error = put_user(cnow.rx, &p_cuser->rx); - if (error) return error; - error = put_user(cnow.tx, &p_cuser->tx); - if (error) return error; - error = put_user(cnow.frame, &p_cuser->frame); - if (error) return error; - error = put_user(cnow.overrun, &p_cuser->overrun); - if (error) return error; - error = put_user(cnow.parity, &p_cuser->parity); - if (error) return error; - error = put_user(cnow.brk, &p_cuser->brk); - if (error) return error; - error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); - if (error) return error; + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + if (copy_to_user((void *)arg, &icount, sizeof(icount))) + return -EFAULT; return 0; - case TIOCSERGWILD: case TIOCSERSWILD: /* "setserial -W" is called in Debian boot */ @@ -2422,7 +2759,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct async_struct *info) { +#ifdef DECLARE_WAITQUEUE DECLARE_WAITQUEUE(wait, current); +#else + struct wait_queue wait = { current, NULL }; +#endif struct serial_state *state = info->state; int retval; int do_clocal = 0, extra_count = 0; @@ -2511,7 +2852,7 @@ serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); restore_flags(flags); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -2571,12 +2912,18 @@ return -ENOMEM; } memset(info, 0, sizeof(struct async_struct)); +#ifdef DECLARE_WAITQUEUE init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); +#endif info->magic = SERIAL_MAGIC; info->port = sstate->port; info->flags = sstate->flags; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = sstate->iomem_base; + info->iomem_reg_shift = sstate->iomem_reg_shift; +#endif info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; info->tqueue.routine = do_softint; @@ -2616,21 +2963,20 @@ } tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) { - /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ + if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; - } #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->state->count); #endif +#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) { - /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ return -ENOMEM; } if (tmp_buf) @@ -2646,7 +2992,6 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); - /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -2660,13 +3005,11 @@ */ retval = startup(info); if (retval) { - /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ return retval; } retval = block_til_ready(tty, filp, info); if (retval) { - /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ #ifdef SERIAL_DEBUG_OPEN printk("rs_open returning after block_til_ready with %d\n", retval); @@ -2838,6 +3181,13 @@ printk(" DETECT_IRQ"); #define SERIAL_OPT #endif +#ifdef ENABLE_SERIAL_PCI + printk(" SERIAL_PCI"); +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + printk(" PCI_IOMEM"); +#endif +#define SERIAL_OPT +#endif #ifdef SERIAL_OPT printk(" enabled\n"); #else @@ -2913,51 +3263,155 @@ } /* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct async_struct *info) +{ + unsigned char old_fcr, old_mcr, old_dll, old_dlm; + int count; + + old_fcr = serial_inp(info, UART_FCR); + old_mcr = serial_inp(info, UART_MCR); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(info, UART_MCR, UART_MCR_LOOP); + serial_outp(info, UART_LCR, UART_LCR_DLAB); + old_dll = serial_inp(info, UART_DLL); + old_dlm = serial_inp(info, UART_DLM); + serial_outp(info, UART_DLL, 0x01); + serial_outp(info, UART_DLM, 0x00); + serial_outp(info, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_outp(info, UART_TX, count); + mdelay(20); + for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_inp(info, UART_RX); + serial_outp(info, UART_FCR, old_fcr); + serial_outp(info, UART_MCR, old_mcr); + serial_outp(info, UART_LCR, UART_LCR_DLAB); + serial_outp(info, UART_DLL, old_dll); + serial_outp(info, UART_DLM, old_dlm); + + return count; +} + +/* + * This is a helper routine to autodetect StarTech/Exar UART's. When + * this function is called we know it is at least a StarTech 16650 V2, + * but it might be one of several StarTech UARTs, or one of its + * clones. (We treat the broken original StarTech 16650 V1 as a + * 16550A, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void autoconfig_startech_uarts(struct async_struct *info, + struct serial_state *state, + unsigned long flags) +{ + unsigned char scratch, status1, status2, old_fctr, old_emsr; + + /* + * Here we check for the XR16C85x family. We do this by + * checking for to see if we can replace the scratch register + * with the receive FIFO count register. + * + * XXX I don't have one of these chips, but it should also be + * possible to check for them by setting DLL and DLM to 0, and + * then reading back DLL and DLM. If the DLM reads back as + * 0x10, then the UART is a XR16C850 and the DLL contains the + * chip revision. + */ + old_fctr = serial_inp(info, UART_FCTR); + serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP); + old_emsr = serial_inp(info, UART_EMSR); + serial_outp(info, UART_EMSR, 0x00); + serial_outp(info, UART_LCR, 0x00); + scratch = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0xa5); + status1 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0x5a); + status2 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, scratch); + if ((status1 != 0xa5) || (status2 != 0x5a)) { + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP); + serial_outp(info, UART_EMSR, old_emsr); + serial_outp(info, UART_FCTR, old_fctr); + state->type = PORT_16850; + return; + } + serial_outp(info, UART_IER, old_fctr); + + /* + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(info) == 64) + state->type = PORT_16654; + else + state->type = PORT_16650V2; +} + +/* * This routine is called by rs_init() to initialize a specific serial * port. It determines what type of UART chip this serial port is * using: 8250, 16450, 16550, 16550A. The important question is - * whether or not this UART is a 16550A, since this will determine - * whether or not we can use its FIFO features. + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. */ static void autoconfig(struct serial_state * state) { - unsigned char status1, status2, scratch, scratch2; + unsigned char status1, status2, scratch, scratch2, scratch3; struct async_struct *info, scr_info; unsigned long flags; state->type = PORT_UNKNOWN; - if (!state->port) + if (!CONFIGURED_SERIAL_PORT(state)) return; info = &scr_info; /* This is just for serial_{in,out} */ info->magic = SERIAL_MAGIC; + info->state = state; info->port = state->port; info->flags = state->flags; #ifdef CONFIG_HUB6 info->hub6 = state->hub6; #endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; +#endif save_flags(flags); cli(); - /* - * Do a simple existence test first; if we fail this, there's - * no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against false - * positives due to ISA bus float. The assumption is that - * 0x80 is a non-existent port; which should be safe since - * include/asm/io.h also makes this assumption. - */ - scratch = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, 0); - outb(0xff, 0x080); - scratch2 = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, scratch); - if (scratch2) { - restore_flags(flags); - return; /* We failed; there's nothing here */ + if (!state->iomem_base) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + */ + scratch = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0); + outb(0xff, 0x080); + scratch2 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, scratch); + if (scratch2) { + restore_flags(flags); + return; /* We failed; there's nothing here */ + } } /* @@ -2980,7 +3434,7 @@ return; } } - + scratch2 = serial_in(info, UART_LCR); serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ @@ -3002,14 +3456,27 @@ break; } if (state->type == PORT_16550A) { + /* Check for Oxford Semiconductor 16C950 */ + scratch = serial_icr_read(info, UART_ID1); + scratch2 = serial_icr_read(info, UART_ID2); + scratch3 = serial_icr_read(info, UART_ID3); + + if (scratch == 0x16 && scratch2 == 0xC9 && + (scratch3 == 0x50 || scratch3 == 0x52 || + scratch3 == 0x54)) { + state->type = PORT_16C950; + state->revision = serial_icr_read(info, UART_REV); + } + } + if (state->type == PORT_16550A) { /* Check for Startech UART's */ - serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB); + serial_outp(info, UART_LCR, UART_LCR_DLAB); if (serial_in(info, UART_EFR) == 0) { state->type = PORT_16650; } else { serial_outp(info, UART_LCR, 0xBF); if (serial_in(info, UART_EFR) == 0) - state->type = PORT_16650V2; + autoconfig_startech_uarts(info, state, flags); } } if (state->type == PORT_16550A) { @@ -3019,7 +3486,16 @@ UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); scratch = serial_in(info, UART_IIR) >> 5; if (scratch == 7) { + /* + * If this is a 16750, and not a cheap UART + * clone, then it should only go into 64 byte + * mode if the UART_FCR7_64BYTE bit was set + * while UART_LCR_DLAB was latched. + */ + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); scratch = serial_in(info, UART_IIR) >> 5; if (scratch == 6) state->type = PORT_16750; @@ -3045,20 +3521,13 @@ return; } - request_region(info->port,8,"serial(auto)"); + if (info->port) + request_region(info->port,8,"serial(auto)"); /* * Reset the UART. */ -#if defined(__alpha__) && !defined(CONFIG_PCI) - /* - * I wonder what DEC did to the OUT1 and OUT2 lines? - * clearing them results in endless interrupts. - */ - serial_outp(info, UART_MCR, 0x0c); -#else - serial_outp(info, UART_MCR, 0x00); -#endif + serial_outp(info, UART_MCR, 0x00 | ALPHA_KLUDGE_MCR); /* Don't ask */ serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); (void)serial_in(info, UART_RX); @@ -3070,13 +3539,321 @@ int register_serial(struct serial_struct *req); void unregister_serial(int line); +#if (LINUX_VERSION_CODE > 0x20100) EXPORT_SYMBOL(register_serial); EXPORT_SYMBOL(unregister_serial); +#else +static struct symbol_table serial_syms = { +#include + X(register_serial), + X(unregister_serial), +#include +}; +#endif + +#ifdef ENABLE_SERIAL_PCI +/* + * Some PCI serial cards using the PLX 9050 PCI interface chip require + * that the card interrupt be explicitly enabled or disabled. This + * seems to be mainly needed on card using the PLX which also use I/O + * mapped memory. + * + * Note that __init is a no-op if MODULE is defined; we depend on this. + */ +static void __init pci_plx9050_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u8 data, *p; + + pci_read_config_byte(dev, PCI_COMMAND, &data); + + if (enable) + pci_write_config_byte(dev, PCI_COMMAND, + data | PCI_COMMAND_MEMORY); + + /* enable/disable interrupts */ + p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + writel(enable ? 0x41 : 0x00, p + 0x4c); + iounmap(p); + + if (!enable) + pci_write_config_byte(dev, PCI_COMMAND, + data & ~PCI_COMMAND_MEMORY); +} + +/* + * This is the configuration table for all of the PCI serial boards + * which we support. + */ +static struct pci_board pci_boards[] = { + /* + * Vendor ID, Device ID, + * Subvendor ID, Subdevice ID, + * Number of Ports, Base (Maximum) Baud Rate, + * Offset of register holding Uart register offset + * Mask to apply to above register's value + */ + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, + SPCI_FL_BASE1, 8, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, + SPCI_FL_BASE1, 4, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, + SPCI_FL_BASE1, 2, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, + SPCI_FL_BASE1, 8, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, + SPCI_FL_BASE1, 4, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, + SPCI_FL_BASE1, 2, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, + SPCI_FL_BASE1, 2, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, + SPCI_FL_BASE1, 2, 921600 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 8, 115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_KEYSPAN, + PCI_SUBDEVICE_ID_KEYSPAN_SX2, + SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_IOMEM, 4, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600, + 0x400, 7, pci_plx9050_fn }, + { 0, } +}; + +/* + * Query PCI space for known serial boards + * If found, add them to the PCI device space in rs_table[] + * + * Accept a maximum of eight boards + * + */ +static void probe_serial_pci(void) +{ + u16 subvendor, subdevice; + int k, line; + struct pci_dev *dev = NULL; + struct pci_board *board; + struct serial_struct fake_state; + int uart_offset, base_baud, base_idx; + unsigned long port; + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Entered probe_serial_pci()\n"); +#endif + + if (!pcibios_present()) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n"); +#endif + return; + } + + for(dev=pci_devices; dev; dev=dev->next) { + pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, + &subvendor); + pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice); + + for (board = pci_boards; board->vendor; board++) { + if (board->vendor != (unsigned short) PCI_ANY_ID && + dev->vendor != board->vendor) + continue; + if (board->device != (unsigned short) PCI_ANY_ID && + dev->device != board->device) + continue; + if (board->subvendor != (unsigned short) PCI_ANY_ID && + subvendor != board->subvendor) + continue; + if (board->subdevice != (unsigned short) PCI_ANY_ID && + subdevice != board->subdevice) + continue; + break; + } + + if (board->vendor == 0) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Found unknown serial board: %x:%x, %x:%x, %x\n", + dev->vendor, dev->device, subvendor, subdevice, + dev->class); + printk(KERN_DEBUG + " Addresses: %lx, %lx, %lx, %lx\n", + PCI_BASE_ADDRESS(dev, 0), PCI_BASE_ADDRESS(dev, 1), + PCI_BASE_ADDRESS(dev, 2), PCI_BASE_ADDRESS(dev, 3)); +#endif + continue; + } + + /* + * Run the initialization function, if any + */ + if (board->init_fn) + (board->init_fn)(dev, board, 1); + + /* + * Register the serial board in the array so we can + * shutdown the board later, if necessary. + */ + serial_pci_board[serial_pci_board_idx].board = board; + serial_pci_board[serial_pci_board_idx].dev = dev; + serial_pci_board_idx++; + + base_idx = board->flags & SPCI_FL_BASE_MASK; + port = PCI_BASE_ADDRESS(dev, base_idx); + if (board->flags & SPCI_FL_IOMEM) + port &= PCI_BASE_ADDRESS_MEM_MASK; + else + port &= PCI_BASE_ADDRESS_IO_MASK; + + /* + * Set some defaults for the loop below, which + * actually registers each serial port belonging to + * the card. + */ + uart_offset = board->uart_offset; + if (!uart_offset) + uart_offset = 8; + base_baud = board->base_baud; + if (!base_baud) + base_baud = BASE_BAUD; +#ifndef CONFIG_SERIAL_PCI_MEMMAPPED + if (board->flags & SPCI_FL_IOMEM) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Can't support memory mapped PCI serial device\n"); +#endif + continue; + } +#endif + memset(&fake_state, 0, sizeof(fake_state)); + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Found Serial PCI device: %x:%x, %x:%x, %x\n", + dev->vendor, dev->device, subvendor, subdevice, + dev->class); + printk(KERN_DEBUG + " IRQ: %d, base: %lx (%s), num_ports: %d\n", + dev->irq, port, board->flags & SPCI_FL_IOMEM ? + "iomem" : "port", board->num_ports); +#endif + + for (k=0; k < board->num_ports; k++) { + if (board->flags & SPCI_FL_BASE_TABLE) { + port = PCI_BASE_ADDRESS(dev, base_idx++); + if (board->flags & SPCI_FL_IOMEM) + port &= PCI_BASE_ADDRESS_MEM_MASK; + else + port &= PCI_BASE_ADDRESS_IO_MASK; + } + fake_state.irq = dev->irq; + fake_state.port = port; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + if (board->flags & SPCI_FL_IOMEM) { + fake_state.iomem_base = + ioremap(port, board->uart_offset); + fake_state.iomem_reg_shift = board->reg_shift; + fake_state.port = 0; + } +#endif + port += uart_offset; + fake_state.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; + line = register_serial(&fake_state); + if (line < 0) + break; + rs_table[line].baud_base = base_baud; + } + } + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); +#endif + return; +} + +#endif /* ENABLE_SERIAL_PCI */ /* * The serial driver boot-time initialization code! */ -__initfunc(int rs_init(void)) +int __init rs_init(void) { int i; struct serial_state * state; @@ -3120,10 +3897,12 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; +#if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "serial"; +#endif serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; - serial_driver.minor_start = 64; + serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; @@ -3147,14 +3926,18 @@ serial_driver.ioctl = rs_ioctl; serial_driver.throttle = rs_throttle; serial_driver.unthrottle = rs_unthrottle; - serial_driver.send_xchar = rs_send_xchar; serial_driver.set_termios = rs_set_termios; serial_driver.stop = rs_stop; serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ serial_driver.break_ctl = rs_break; +#endif +#if (LINUX_VERSION_CODE >= 131343) + serial_driver.send_xchar = rs_send_xchar; serial_driver.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = rs_read_proc; +#endif /* * The callout device is just like normal device except for @@ -3164,8 +3947,10 @@ callout_driver.name = "cua"; callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; +#if (LINUX_VERSION_CODE >= 131343) callout_driver.read_proc = 0; callout_driver.proc_entry = 0; +#endif if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); @@ -3187,15 +3972,11 @@ state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; state->irq = irq_cannonicalize(state->irq); - if (check_region(state->port,8)) + if (state->port && check_region(state->port,8)) continue; if (state->flags & ASYNC_BOOT_AUTOCONF) autoconfig(state); } - /* - * Detect the IRQ only once every port is initialised, - * because some 16450 do not reset to 0 the MCR register. - */ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { if (state->type == PORT_UNKNOWN) continue; @@ -3204,11 +3985,14 @@ && (state->port != 0)) state->irq = detect_uart_irq(state); printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n", - state->line, + state->line + SERIAL_DEV_OFFSET, (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", state->port, state->irq, uart_config[state->type].name); } +#ifdef ENABLE_SERIAL_PCI + probe_serial_pci(); +#endif return 0; } @@ -3225,7 +4009,8 @@ save_flags(flags); cli(); for (i = 0; i < NR_PORTS; i++) { - if (rs_table[i].port == req->port) + if ((rs_table[i].port == req->port) && + (rs_table[i].iomem_base == req->iomem_base)) break; } if (i == NR_PORTS) { @@ -3248,6 +4033,10 @@ state->irq = req->irq; state->port = req->port; state->flags = req->flags; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + state->iomem_base = req->iomem_base; + state->iomem_reg_shift = req->iomem_reg_shift; +#endif autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -3257,13 +4046,16 @@ } restore_flags(flags); - if ((state->flags & ASYNC_AUTO_IRQ) && (state->port != 0)) + if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state)) state->irq = detect_uart_irq(state); - printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n", - state->line, state->port, state->irq, - uart_config[state->type].name); - return state->line; + printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + state->iomem_base ? "iomem" : "port", + state->iomem_base ? (unsigned long)state->iomem_base : + (unsigned long)state->port, + state->irq, uart_config[state->type].name); + return state->line + SERIAL_DEV_OFFSET; } void unregister_serial(int line) @@ -3308,9 +4100,21 @@ restore_flags(flags); for (i = 0; i < NR_PORTS; i++) { - if (rs_table[i].type != PORT_UNKNOWN) + if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) release_region(rs_table[i].port, 8); +#if defined(ENABLE_SERIAL_PCI) && defined (CONFIG_SERIAL_PCI_MEMMAPPED) + if (rs_table[i].iomem_base) + iounmap(rs_table[i].iomem_base); +#endif + } +#ifdef ENABLE_SERIAL_PCI + for (i=0; i < serial_pci_board_idx; i++) { + struct pci_board_inst *brd = &serial_pci_board[i]; + + if (brd->board->init_fn) + (brd->board->init_fn)(brd->dev, brd->board, 0); } +#endif if (tmp_buf) { free_page((unsigned long) tmp_buf); tmp_buf = NULL; @@ -3429,7 +4233,7 @@ * - initialize the serial port * Return non-zero if we didn't find a serial port. */ -__initfunc(static int serial_console_setup(struct console *co, char *options)) +static int __init serial_console_setup(struct console *co, char *options) { struct serial_state *ser; unsigned cval; @@ -3550,9 +4354,15 @@ /* * Register console. */ -__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +long __init serial_console_init(long kmem_start, long kmem_end) { register_console(&sercons); return kmem_start; } #endif + +/* + Local variables: + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + End: +*/ diff -u --recursive --new-file v2.3.15/linux/drivers/char/serial167.c linux/drivers/char/serial167.c --- v2.3.15/linux/drivers/char/serial167.c Sat May 15 15:05:36 1999 +++ linux/drivers/char/serial167.c Tue Aug 31 11:30:48 1999 @@ -1500,7 +1500,7 @@ | ((status & CyDCD) ? TIOCM_CAR : 0) | ((status & CyDSR) ? TIOCM_DSR : 0) | ((status & CyCTS) ? TIOCM_CTS : 0); - cy_put_user(result,(unsigned long *) value); + cy_put_user(result,(unsigned int *) value); return 0; } /* get_modem_info */ @@ -2094,7 +2094,7 @@ #endif } restore_flags(flags); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ){ if (info->flags & ASYNC_HUP_NOTIFY) { diff -u --recursive --new-file v2.3.15/linux/drivers/char/specialix.c linux/drivers/char/specialix.c --- v2.3.15/linux/drivers/char/specialix.c Wed May 12 13:27:37 1999 +++ linux/drivers/char/specialix.c Tue Aug 31 11:30:48 1999 @@ -1398,7 +1398,7 @@ } } sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) @@ -1755,7 +1755,7 @@ |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */ | ((status & MSVR_CTS) ? TIOCM_CTS : 0); } - put_user(result,(unsigned long *) value); + put_user(result,(unsigned int *) value); return 0; } diff -u --recursive --new-file v2.3.15/linux/drivers/char/synclink.c linux/drivers/char/synclink.c --- v2.3.15/linux/drivers/char/synclink.c Wed Jun 16 19:26:27 1999 +++ linux/drivers/char/synclink.c Tue Aug 31 11:30:48 1999 @@ -3413,7 +3413,6 @@ if ( info->params.mode == MGSL_MODE_HDLC ) { while (info->tx_active) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -3424,7 +3423,6 @@ while (!(usc_InReg(info,TCSR) & TXSTATUS_ALL_SENT) && info->tx_enabled) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -3561,7 +3559,7 @@ spin_unlock_irqrestore(&info->irq_spinlock,flags); } - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ retval = (info->flags & ASYNC_HUP_NOTIFY) ? diff -u --recursive --new-file v2.3.15/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.15/linux/drivers/char/tty_io.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/tty_io.c Tue Aug 31 11:31:35 1999 @@ -1499,10 +1499,11 @@ return 0; } -static int tioccons(struct tty_struct *tty, struct tty_struct *real_tty) +static int tioccons(struct inode *inode, + struct tty_struct *tty, struct tty_struct *real_tty) { - if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE || - tty->driver.type == TTY_DRIVER_TYPE_SYSCONS) { + if (inode->i_rdev == SYSCONS_DEV || + inode->i_rdev == CONSOLE_DEV) { if (!suser()) return -EPERM; redirect = NULL; @@ -1631,7 +1632,7 @@ static int send_break(struct tty_struct *tty, int duration) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); tty->driver.break_ctl(tty, -1); if (!signal_pending(current)) @@ -1712,7 +1713,7 @@ case TIOCSWINSZ: return tiocswinsz(tty, real_tty, (struct winsize *) arg); case TIOCCONS: - return tioccons(tty, real_tty); + return tioccons(inode, tty, real_tty); case FIONBIO: return fionbio(file, (int *) arg); case TIOCEXCL: diff -u --recursive --new-file v2.3.15/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c --- v2.3.15/linux/drivers/char/tty_ioctl.c Tue May 11 14:37:40 1999 +++ linux/drivers/char/tty_ioctl.c Tue Aug 31 11:30:48 1999 @@ -59,7 +59,7 @@ printk("waiting %s...(%d)\n", tty_name(tty, buf), tty->driver.chars_in_buffer(tty)); #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) goto stop_waiting; if (!tty->driver.chars_in_buffer(tty)) diff -u --recursive --new-file v2.3.15/linux/drivers/char/vino.c linux/drivers/char/vino.c --- v2.3.15/linux/drivers/char/vino.c Wed Jun 30 11:24:54 1999 +++ linux/drivers/char/vino.c Thu Aug 26 13:54:01 1999 @@ -240,7 +240,7 @@ 0 }; -__initfunc(int init_vino(struct video_device *dev)) +int __init init_vino(struct video_device *dev) { int err; diff -u --recursive --new-file v2.3.15/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.3.15/linux/drivers/char/vt.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/vt.c Tue Aug 31 11:30:48 1999 @@ -1113,7 +1113,7 @@ add_wait_queue(&vt_activate_queue, &wait); for (;;) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); retval = 0; if (vt == fg_console) break; diff -u --recursive --new-file v2.3.15/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.3.15/linux/drivers/char/wdt.c Wed Jun 2 11:29:13 1999 +++ linux/drivers/char/wdt.c Thu Aug 26 13:53:47 1999 @@ -64,7 +64,7 @@ * Setup options */ -__initfunc(void wdt_setup(char *str, int *ints)) +void __init wdt_setup(char *str, int *ints) { if(ints[0]>0) { @@ -365,7 +365,7 @@ #endif -__initfunc(int wdt_init(void)) +int __init wdt_init(void) { printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL)) diff -u --recursive --new-file v2.3.15/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.3.15/linux/drivers/i2o/i2o_core.c Thu Aug 5 15:04:52 1999 +++ linux/drivers/i2o/i2o_core.c Mon Aug 30 10:23:14 1999 @@ -310,7 +310,7 @@ *p=c->next; spin_unlock(&i2o_configuration_lock); - if(c->page_frame); + if(c->page_frame) kfree(c->page_frame); if(c->hrt) kfree(c->hrt); diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.3.15/linux/drivers/isdn/eicon/eicon.h Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/eicon/eicon.h Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.10 1999/08/22 20:26:41 calle Exp $ +/* $Id: eicon.h,v 1.11 1999/08/29 17:23:44 armin Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * @@ -21,6 +21,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon.h,v $ + * Revision 1.11 1999/08/29 17:23:44 armin + * New setup compat. + * Bugfix if compile as not module. + * * Revision 1.10 1999/08/22 20:26:41 calle * backported changes from kernel 2.3.14: * - several #include "config.h" gone, others come. @@ -221,6 +225,8 @@ #include #include + +#include typedef struct { __u16 length __attribute__ ((packed)); /* length of data/parameter field */ diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.3.15/linux/drivers/isdn/eicon/eicon_idi.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/eicon/eicon_idi.c Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.13 1999/08/22 20:26:44 calle Exp $ +/* $Id: eicon_idi.c,v 1.15 1999/08/28 21:32:50 armin Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * IDI interface @@ -21,6 +21,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.15 1999/08/28 21:32:50 armin + * Prepared for fax related functions. + * Now compilable without errors/warnings. + * + * Revision 1.14 1999/08/28 20:24:40 armin + * Corrected octet 3/3a in CPN/OAD information element. + * Thanks to John Simpson + * * Revision 1.13 1999/08/22 20:26:44 calle * backported changes from kernel 2.3.14: * - several #include "config.h" gone, others come. @@ -88,7 +96,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.13 $"; +char *eicon_idi_revision = "$Revision: 1.15 $"; eicon_manifbuf *manbuf; @@ -469,14 +477,14 @@ reqbuf->XBuffer.P[l++] = CPN; reqbuf->XBuffer.P[l++] = strlen(phone) + 1; - reqbuf->XBuffer.P[l++] = 0xc1; + reqbuf->XBuffer.P[l++] = 0x81; for(i=0; iXBuffer.P[l++] = phone[i]; reqbuf->XBuffer.P[l++] = OAD; reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2; reqbuf->XBuffer.P[l++] = 0x01; - reqbuf->XBuffer.P[l++] = 0x81; + reqbuf->XBuffer.P[l++] = 0x80; for(i=0; iXBuffer.P[l++] = eazmsn[i]; @@ -893,6 +901,120 @@ } } +/********************* FAX stuff ***************************/ + +#ifdef CONFIG_ISDN_TTY_FAX + +int +idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer) +{ + + /* TODO , code follows */ + + return(0); +} + +/* send fax struct */ +int +idi_send_edata(eicon_card *card, eicon_chan *chan) +{ + + /* TODO , code follows */ + + return (0); +} + +void +idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len) +{ + + /* TODO , code follows */ + +} + +void +idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header) +{ + + /* TODO , code follows */ + +} + +void +idi_fax_cmd(eicon_card *card, eicon_chan *chan) +{ + + /* TODO , code follows */ + +} + +void +idi_edata_rcveop(eicon_card *card, eicon_chan *chan) +{ + + /* TODO , code follows */ + +} + +void +idi_reset_fax_stat(eicon_chan *chan) +{ + + /* TODO , code follows */ + +} + +void +idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) +{ + + /* TODO , code follows */ + +} + +void +fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len) +{ + + /* TODO , code follows */ + +} + +void +idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb) +{ + + /* TODO , code follows */ + +} + +int +idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf) +{ + + /* TODO , code follows */ + + return(0); +} + +int +idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb) +{ + + /* TODO , code follows */ + + return(0); +} + +void +idi_fax_hangup(eicon_card *ccard, eicon_chan *chan) +{ + + /* TODO , code follows */ + +} + +#endif /******** FAX ********/ int idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int len) diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.3.15/linux/drivers/isdn/eicon/eicon_mod.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/eicon/eicon_mod.c Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.9 1999/08/18 20:17:02 armin Exp $ +/* $Id: eicon_mod.c,v 1.11 1999/08/29 17:23:45 armin Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * @@ -26,6 +26,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.11 1999/08/29 17:23:45 armin + * New setup compat. + * Bugfix if compile as not module. + * + * Revision 1.10 1999/08/28 21:32:53 armin + * Prepared for fax related functions. + * Now compilable without errors/warnings. + * * Revision 1.9 1999/08/18 20:17:02 armin * Added XLOG function for all cards. * Bugfix of alloc_skb NULL pointer. @@ -83,7 +91,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.9 $"; +static char *eicon_revision = "$Revision: 1.11 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -1006,7 +1014,7 @@ ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038 | ISDN_FEATURE_L2_MODEM | - ISDN_FEATURE_L2_FAX | + /* ISDN_FEATURE_L2_FAX | */ ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FAX; card->hwif.pci.card = (void *)card; @@ -1030,7 +1038,7 @@ ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038 | ISDN_FEATURE_L2_MODEM | - ISDN_FEATURE_L2_FAX | + /* ISDN_FEATURE_L2_FAX | */ ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FAX; card->hwif.pci.card = (void *)card; @@ -1335,7 +1343,7 @@ #else printk(KERN_INFO "Eicon: No PCI-cards found, driver not loaded !\n"); #endif -#endif +#endif /* MODULE */ return -ENODEV; } else @@ -1373,13 +1381,26 @@ } #else /* no module */ + +#ifdef COMPAT_HAS_NEW_SETUP +static int __init +eicon_setup(char *line) +{ + int i, argc; + int ints[5]; + char *str; + + str = get_options(line, 4, ints); +#else __initfunc(void eicon_setup(char *str, int *ints)) { int i, argc; +#endif argc = ints[0]; i = 1; +#ifdef CONFIG_ISDN_DRV_EICON_ISA if (argc) { membase = irq = -1; if (argc) { @@ -1397,10 +1418,20 @@ } else { strcpy(id, "eicon"); } - /* eicon_addcard(0, membase, irq, id); */ - printk(KERN_INFO "eicon: membase=0x%x irq=%d id=%s\n", membase, irq, id); + printk(KERN_INFO "Eicon ISDN active driver setup (id=%s membase=0x%x irq=%d)\n", + id, membase, irq); } +#else + printk(KERN_INFO "Eicon ISDN active driver setup\n"); +#endif +#ifdef COMPAT_HAS_NEW_SETUP + return(1); } +__setup("eicon=", eicon_setup); +#else +} +#endif + #endif /* MODULE */ #ifdef CONFIG_ISDN_DRV_EICON_ISA diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.3.15/linux/drivers/isdn/hisax/callc.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/hisax/callc.c Thu Aug 26 09:48:40 1999 @@ -140,7 +140,6 @@ * */ -#include #define __NO_VERSION__ #include "hisax.h" #include "../avmb1/capicmd.h" /* this should be moved in a common place */ diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.3.15/linux/drivers/isdn/hisax/config.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/hisax/config.c Mon Aug 30 16:27:43 1999 @@ -1,10 +1,16 @@ -/* $Id: config.c,v 2.31 1999/08/25 16:47:43 keil Exp $ +/* $Id: config.c,v 2.33 1999/08/30 11:57:52 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.33 1999/08/30 11:57:52 keil + * Fix broken avm pcmcia + * + * Revision 2.32 1999/08/28 22:11:10 keil + * __setup function should be static + * * Revision 2.31 1999/08/25 16:47:43 keil * Support new __setup; allow to add FEATURES after register_isdn * @@ -224,6 +230,7 @@ int avm_a1_init_pcmcia(void*, int, int*, int); #ifdef COMPAT_HAS_NEW_SYMTAB EXPORT_SYMBOL(avm_a1_init_pcmcia); +EXPORT_SYMBOL(HiSax_closecard); #else static struct symbol_table hisax_syms_avm_a1= { #include @@ -521,9 +528,9 @@ printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3 (module)\n"); + printk(KERN_INFO "HiSax: Version 3.3a (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3 (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.3a (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); @@ -555,8 +562,8 @@ #else #ifdef COMPAT_HAS_NEW_SETUP #define MAX_ARG (HISAX_MAX_CARDS*5) -__initfunc(int -HiSax_setup(char *line)) +static int __init +HiSax_setup(char *line) { int i, j, argc; int ints[MAX_ARG + 1]; diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.3.15/linux/drivers/isdn/hisax/hfc_pci.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/hisax/hfc_pci.c Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.16 1999/08/25 17:01:27 keil Exp $ +/* $Id: hfc_pci.c,v 1.18 1999/08/29 17:05:44 werner Exp $ * hfc_pci.c low level driver for CCD“s hfc-pci based cards * @@ -23,6 +23,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.c,v $ + * Revision 1.18 1999/08/29 17:05:44 werner + * corrected tx_lo line setup. Datasheet is not correct. + * + * Revision 1.17 1999/08/28 21:04:27 werner + * Implemented full audio support (transparent mode) + * * Revision 1.16 1999/08/25 17:01:27 keil * Use new LL->HL auxcmd call * @@ -92,7 +98,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.16 $"; +static const char *hfcpci_revision = "$Revision: 1.18 $"; /* table entry in the PCI devices list */ typedef struct { @@ -181,7 +187,7 @@ cs->hw.hfcpci.fifo_en = 0x30; /* only D fifos enabled */ Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - cs->hw.hfcpci.trm = 0; /* no echo connect */ + cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ @@ -207,7 +213,7 @@ cs->hw.hfcpci.mst_m = HFCPCI_MASTER; /* HFC Master Mode */ Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - cs->hw.hfcpci.sctrl = 0; + cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); cs->hw.hfcpci.sctrl_r = 0; Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); @@ -406,6 +412,59 @@ return (1); } +/*******************************************************************************/ +/* check for transparent receive data and read max one threshold size if avail */ +/*******************************************************************************/ +int hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata) +{ unsigned short *z1r, *z2r; + int new_z2, fcnt, maxlen; + struct sk_buff *skb; + u_char *ptr, *ptr1; + + z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ + z2r = z1r + 1; + + if (!(fcnt = *z1r - *z2r)) + return(0); /* no data avail */ + + if (fcnt <= 0) + fcnt += B_FIFO_SIZE; /* bytes actually buffered */ + if (fcnt > HFCPCI_BTRANS_THRESHOLD) + fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ + + new_z2 = *z2r + fcnt; /* new position in fifo */ + if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z2 -= B_FIFO_SIZE; /* buffer wrap */ + + if (!(skb = dev_alloc_skb(fcnt))) + printk(KERN_WARNING "HFCPCI: receive out of memory\n"); + else { + SET_SKB_FREE(skb); + ptr = skb_put(skb, fcnt); + if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL) + maxlen = fcnt; /* complete transfer */ + else + maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */ + + ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */ + memcpy(ptr, ptr1, maxlen); /* copy data */ + fcnt -= maxlen; + + if (fcnt) { /* rest remaining */ + ptr += maxlen; + ptr1 = bdata; /* start of buffer */ + memcpy(ptr, ptr1, fcnt); /* rest */ + } + cli(); + skb_queue_tail(&bcs->rqueue, skb); + sti(); + hfcpci_sched_event(bcs, B_RCVBUFREADY); + } + + *z2r = new_z2; /* new position */ + return(1); +} /* hfcpci_empty_fifo_trans */ + /**********************************/ /* B-channel main receive routine */ /**********************************/ @@ -465,8 +524,11 @@ receive = 1; else receive = 0; - } else - receive = 0; + } else + if (bcs->mode == L1_MODE_TRANS) + receive = hfcpci_empty_fifo_trans(bcs, bz, bdata); + else + receive = 0; test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); if (count && receive) goto Begin; @@ -558,6 +620,7 @@ bzfifo_type *bz; u_char *bdata; u_char new_f1, *src, *dst; + unsigned short *z1t, *z2t; if (!bcs->tx_skb) return; @@ -575,8 +638,60 @@ bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b1; } + if (bcs->mode == L1_MODE_TRANS) { + z1t = &bz->za[MAX_B_FRAMES].z1; + z2t = z1t + 1; + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)", + bcs->channel, *z1t, *z2t); + fcnt = *z2t - *z1t; + if (fcnt <= 0) + fcnt += B_FIFO_SIZE; /* fcnt contains available bytes in fifo */ + fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */ + + while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) { + if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) { + /* data is suitable for fifo */ + count = bcs->tx_skb->len; + + new_z1 = *z1t + count; /* new buffer Position */ + if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z1 -= B_FIFO_SIZE; /* buffer wrap */ + src = bcs->tx_skb->data; /* source pointer */ + dst = bdata + (*z1t - B_SUB_VAL); + maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */ + if (maxlen > count) + maxlen = count; /* limit size */ + memcpy(dst, src, maxlen); /* first copy */ + + count -= maxlen; /* remaining bytes */ + if (count) { + dst = bdata; /* start of buffer */ + src += maxlen; /* new position */ + memcpy(dst, src, count); + } + bcs->tx_cnt -= bcs->tx_skb->len; + fcnt += bcs->tx_skb->len; + *z1t = new_z1; /* now send data */ + } + else + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", + bcs->channel, bcs->tx_skb->len); + + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + cli(); + bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ + sti(); + } + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + restore_flags(flags); + return; + } + + if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo %d f1(%d) f2(%d) z1(f1)(%x)", + debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)", bcs->channel, bz->f1, bz->f2, bz->za[bz->f1].z1); @@ -1125,6 +1240,7 @@ mode_hfcpci(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; + bzfifo_type *bzr, *bzt; int flags; if (cs->debug & L1_DEB_HSCX) @@ -1171,6 +1287,8 @@ cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC); + bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; + bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; } else { cs->hw.hfcpci.ctmt |= 1; cs->hw.hfcpci.conn &= ~0x03; @@ -1178,7 +1296,17 @@ cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC); + bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; + bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; } + bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; + bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; + bzr->f1 = MAX_B_FRAMES; + bzr->f2 = bzr->f1; /* init F pointers to remain constant */ + bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; + bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; + bzt->f1 = MAX_B_FRAMES; + bzt->f2 = bzt->f1; /* init F pointers to remain constant */ break; case (L1_MODE_HDLC): if (bc) { diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/hisax/hfc_pci.h linux/drivers/isdn/hisax/hfc_pci.h --- v2.3.15/linux/drivers/isdn/hisax/hfc_pci.h Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/hfc_pci.h Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.h,v 1.5 1999/08/09 19:13:34 werner Exp $ +/* $Id: hfc_pci.h,v 1.6 1999/08/28 21:04:29 werner Exp $ * specific defines for CCD's HFC 2BDS0 PCI chips * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.h,v $ + * Revision 1.6 1999/08/28 21:04:29 werner + * Implemented full audio support (transparent mode) + * * Revision 1.5 1999/08/09 19:13:34 werner * moved constant pci ids to pci id table * @@ -36,6 +39,14 @@ * * */ + +/*********************************************/ +/* thresholds for transparent B-channel mode */ +/* change mask and threshold simultaneously */ +/*********************************************/ +#define HFCPCI_BTRANS_THRESHOLD 128 +#define HFCPCI_BTRANS_THRESMASK 0x00 + /* defines for PCI config */ diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.3.15/linux/drivers/isdn/hisax/sedlbauer.c Thu Aug 26 13:05:37 1999 +++ linux/drivers/isdn/hisax/sedlbauer.c Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.15 1999/08/25 17:00:00 keil Exp $ +/* $Id: sedlbauer.c,v 1.16 1999/08/29 18:23:01 niemann Exp $ * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -17,6 +17,9 @@ * Edgar Toernig * * $Log: sedlbauer.c,v $ + * Revision 1.16 1999/08/29 18:23:01 niemann + * Fixed typo in errormsg + * * Revision 1.15 1999/08/25 17:00:00 keil * Make ISAR V32bis modem running * Make LL->HL interface open for additional commands @@ -103,7 +106,7 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.15 $"; +const char *Sedlbauer_revision = "$Revision: 1.16 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", @@ -584,7 +587,7 @@ #if CONFIG_PCI #ifdef COMPAT_HAS_NEW_PCI if (!pci_present()) { - printk(KERN_ERR "FritzPCI: no PCI bus present\n"); + printk(KERN_ERR "Sedlbauer: no PCI bus present\n"); return(0); } if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER, diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.3.15/linux/drivers/isdn/hisax/teles3.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/teles3.c Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: teles3.c,v 2.12 1999/07/12 21:05:32 keil Exp $ +/* $Id: teles3.c,v 2.13 1999/08/30 12:01:28 keil Exp $ * teles3.c low level stuff for Teles 16.3 & PNP isdn cards * @@ -11,6 +11,9 @@ * Beat Doebeli * * $Log: teles3.c,v $ + * Revision 2.13 1999/08/30 12:01:28 keil + * HW version v1.3 support + * * Revision 2.12 1999/07/12 21:05:32 keil * fix race in IRQ handling * added watchdog for lost IRQs @@ -85,7 +88,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.12 $"; +const char *teles3_revision = "$Revision: 2.13 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -464,9 +467,10 @@ * 0x1f=with AB * 0x1c 16.3 ??? * 0x39 16.3 1.1 + * 0x38 16.3 1.3 * 0x46 16.3 with AB + Video (Teles-Vision) */ - if (val != 0x46 && val != 0x39 && val != 0x1c && val != 0x1e && val != 0x1f) { + if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) { printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", cs->hw.teles3.cfg_reg + 2, val); release_io_teles3(cs); diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.3.15/linux/drivers/isdn/icn/icn.c Thu Aug 26 13:05:37 1999 +++ linux/drivers/isdn/icn/icn.c Mon Aug 30 16:27:43 1999 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.58 1999/08/25 16:44:17 keil Exp $ +/* $Id: icn.c,v 1.59 1999/08/28 22:10:55 keil Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.59 1999/08/28 22:10:55 keil + * __setup function should be static + * * Revision 1.58 1999/08/25 16:44:17 keil * Support for new __setup function * @@ -235,7 +238,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.58 $"; +*revision = "$Revision: 1.59 $"; static int icn_addcard(int, char *, char *); @@ -1851,7 +1854,7 @@ #else #ifdef COMPAT_HAS_NEW_SETUP #include -int +static int __init icn_setup(char *line) { char *p, *str; diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.3.15/linux/drivers/isdn/isdn_tty.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/isdn_tty.c Tue Aug 31 11:30:48 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.72 1999/07/31 12:59:45 armin Exp $ +/* $Id: isdn_tty.c,v 1.73 1999/08/28 21:56:27 keil Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.73 1999/08/28 21:56:27 keil + * misplaced #endif caused ttyI crash in 2.3.X + * * Revision 1.72 1999/07/31 12:59:45 armin * Added tty fax capabilities. * @@ -345,7 +348,7 @@ static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.72 $"; +char *isdn_tty_revision = "$Revision: 1.73 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -1981,7 +1984,7 @@ restore_flags(flags); info->blocked_open++; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ISDN_ASYNC_INITIALIZED)) { #ifdef MODEM_DO_RESTART @@ -2399,8 +2402,8 @@ #else info->open_wait = 0; info->close_wait = 0; - info->isdn_driver = -1; #endif + info->isdn_driver = -1; info->isdn_channel = -1; info->drv_index = -1; info->xmit_size = ISDN_SERIAL_XMIT_SIZE; diff -u --recursive --new-file v2.3.15/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c --- v2.3.15/linux/drivers/isdn/pcbit/module.c Thu Aug 26 13:05:37 1999 +++ linux/drivers/isdn/pcbit/module.c Mon Aug 30 16:27:43 1999 @@ -105,7 +105,7 @@ #ifdef COMPAT_HAS_NEW_SETUP #define MAX_PARA (MAX_PCBIT_CARDS * 2) #include -int pcbit_setup(char *line) +static int __init pcbit_setup(char *line) { int i, j, argc; char *str; diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.3.15/linux/drivers/macintosh/mac_keyb.c Thu Aug 12 11:50:14 1999 +++ linux/drivers/macintosh/mac_keyb.c Tue Aug 31 11:35:59 1999 @@ -269,8 +269,6 @@ static int adb_mouse_kinds[16]; -__openfirmware - int mackbd_setkeycode(unsigned int scancode, unsigned int keycode) { return -EINVAL; diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c --- v2.3.15/linux/drivers/macintosh/macio-adb.c Wed Aug 4 16:36:41 1999 +++ linux/drivers/macintosh/macio-adb.c Tue Aug 31 11:35:59 1999 @@ -74,8 +74,6 @@ macio_adb_poll }; -__openfirmware - void macio_adb_init(void) { struct device_node *adbs; diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.3.15/linux/drivers/macintosh/macserial.c Thu Aug 12 11:50:14 1999 +++ linux/drivers/macintosh/macserial.c Tue Aug 31 11:35:59 1999 @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #endif +#include #include #include #include @@ -135,13 +137,13 @@ * buffer across all the serial ports, since it significantly saves * memory if large numbers of serial ports are open. */ -static unsigned char tmp_buf[4096]; /* This is cheating */ -DECLARE_MUTEX(tmp_buf_sem); +static unsigned char *tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); static inline int __pmac serial_paranoia_check(struct mac_serial *info, - dev_t device, const char *routine) + dev_t device, const char *routine) { #ifdef SERIAL_PARANOIA_CHECK static const char *badmagic = @@ -165,7 +167,7 @@ * Reading and writing Z8530 registers. */ static inline unsigned char __pmac read_zsreg(struct mac_zschannel *channel, - unsigned char reg) + unsigned char reg) { unsigned char retval; unsigned long flags; @@ -185,7 +187,7 @@ } static inline void __pmac write_zsreg(struct mac_zschannel *channel, - unsigned char reg, unsigned char value) + unsigned char reg, unsigned char value) { unsigned long flags; @@ -357,8 +359,12 @@ static void transmit_chars(struct mac_serial *info) { + unsigned long flags; + + save_flags(flags); + cli(); if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) - return; + goto out; info->tx_active = 0; if (info->x_char) { @@ -366,12 +372,12 @@ write_zsdata(info->zs_channel, info->x_char); info->x_char = 0; info->tx_active = 1; - return; + goto out; } if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) { write_zsreg(info->zs_channel, 0, RES_Tx_P); - return; + goto out; } /* Send char */ @@ -382,6 +388,9 @@ if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + + out: + restore_flags(flags); } static _INLINE_ void status_handle(struct mac_serial *info) @@ -764,8 +773,10 @@ */ mdelay(250); } +#ifdef CONFIG_PMAC_PBOOK if (info->is_pwbk_ir) pmu_enable_irled(1); +#endif /* CONFIG_PMAC_PBOOK */ } else { #ifdef SERIAL_DEBUG_POWER printk(KERN_INFO "ttyS%02d: shutting down hardware\n", info->line); @@ -795,8 +806,10 @@ feature_clear(info->dev_node, FEATURE_Modem_Reset); mdelay(25); } +#ifdef CONFIG_PMAC_PBOOK if (info->is_pwbk_ir) pmu_enable_irled(0); +#endif /* CONFIG_PMAC_PBOOK */ if (info->zs_chan_a == info->zs_channel) { #ifdef SERIAL_DEBUG_POWER @@ -987,7 +1000,6 @@ static void rs_flush_chars(struct tty_struct *tty) { struct mac_serial *info = (struct mac_serial *)tty->driver_data; - unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) return; @@ -997,53 +1009,76 @@ return; /* Enable transmitter */ - save_flags(flags); cli(); transmit_chars(info); - restore_flags(flags); } static int rs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - int c, total = 0; + int c, ret = 0; struct mac_serial *info = (struct mac_serial *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_write")) return 0; - if (!tty || !info->xmit_buf) + if (!tty || !info->xmit_buf || !tmp_buf) return 0; save_flags(flags); - while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - if (from_user) { - down(&tmp_buf_sem); - copy_from_user(tmp_buf, buf, c); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - up(&tmp_buf_sem); - } else + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } } if (info->xmit_cnt && !tty->stopped && !info->tx_stopped && !info->tx_active) transmit_chars(info); restore_flags(flags); - return total; + return ret; } static int rs_write_room(struct tty_struct *tty) @@ -1186,7 +1221,9 @@ tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; - return copy_to_user(retinfo,&tmp,sizeof(*retinfo)); + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; } static int set_serial_info(struct mac_serial * info, @@ -1196,9 +1233,8 @@ struct mac_serial old_info; int retval = 0; - if (!new_info) + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; - copy_from_user(&new_serial,new_info,sizeof(new_serial)); old_info = *info; if (!capable(CAP_SYS_ADMIN)) { @@ -1248,29 +1284,30 @@ static int get_lsr_info(struct mac_serial * info, unsigned int *value) { unsigned char status; + unsigned long flags; - cli(); + save_flags(flags); cli(); status = read_zsreg(info->zs_channel, 0); - sti(); - put_user(status,value); - return 0; + restore_flags(flags); + status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0; + return put_user(status,value); } static int get_modem_info(struct mac_serial *info, unsigned int *value) { unsigned char control, status; unsigned int result; + unsigned long flags; - cli(); + save_flags(flags); cli(); control = info->curregs[5]; status = read_zsreg(info->zs_channel, 0); - sti(); + restore_flags(flags); result = ((control & RTS) ? TIOCM_RTS: 0) | ((control & DTR) ? TIOCM_DTR: 0) | ((status & DCD) ? TIOCM_CAR: 0) | ((status & CTS) ? 0: TIOCM_CTS); - put_user(result,value); - return 0; + return put_user(result,value); } static int set_modem_info(struct mac_serial *info, unsigned int cmd, @@ -1278,13 +1315,13 @@ { int error; unsigned int arg, bits; + unsigned long flags; - error = verify_area(VERIFY_READ, value, sizeof(int)); + error = get_user(arg, value); if (error) return error; - get_user(arg, value); bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0); - cli(); + save_flags(flags); cli(); switch (cmd) { case TIOCMBIS: info->curregs[5] |= bits; @@ -1296,12 +1333,12 @@ info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits; break; default: - sti(); + restore_flags(flags); return -EINVAL; } info->pendregs[5] = info->curregs[5]; write_zsreg(info->zs_channel, 5, info->curregs[5]); - sti(); + restore_flags(flags); return 0; } @@ -1330,7 +1367,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct mac_serial * info = (struct mac_serial *)tty->driver_data; #ifdef CONFIG_KGDB @@ -1341,48 +1377,31 @@ return -ENODEV; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case TIOCMGET: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int)); - if (error) - return error; return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return set_modem_info(info, cmd, (unsigned int *) arg); case TIOCGSERIAL: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct)); - if (error) - return error; return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int)); - if (error) - return error; - else - return get_lsr_info(info, (unsigned int *) arg); + return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct mac_serial)); - if (error) - return error; - copy_from_user((struct mac_serial *) arg, - info, sizeof(struct mac_serial)); + if (copy_to_user((struct mac_serial *) arg, + info, sizeof(struct mac_serial))) + return -EFAULT; return 0; default: @@ -1674,7 +1693,7 @@ (tty->termios->c_cflag & CBAUD)) zs_rtsdtr(info, 1); sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -1726,6 +1745,7 @@ { struct mac_serial *info; int retval, line; + unsigned long page; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= zs_channels_found)) @@ -1747,6 +1767,16 @@ tty->driver_data = info; info->tty = tty; + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + /* * If the port is the middle of closing, bail out now */ @@ -1817,6 +1847,7 @@ struct device_node *dev, *ch; struct mac_serial **pp; int n, lenp; + char *conn; n = 0; pp = &zs_chain; @@ -1842,9 +1873,11 @@ zs_soft[n].zs_channel->parent = &zs_soft[n]; zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt"); - /* XXX tested only with wallstreet PowerBook, should do no harm anyway */ - zs_soft[n].is_pwbk_ir = (strcmp(get_property(ch, "AAPL,connector", - &lenp), "infrared") == 0); + /* XXX tested only with wallstreet PowerBook, + should do no harm anyway */ + conn = get_property(ch, "AAPL,connector", &lenp); + zs_soft[n].is_pwbk_ir = + conn && (strcmp(conn, "infrared") == 0); /* XXX this assumes the prom puts chan A before B */ if (n & 1) @@ -2024,6 +2057,30 @@ return 0; } + +#ifdef MODULE +int init_module(void) +{ + macserial_init(); + return 0; +} + +void cleanup_module(void) +{ + int i; + unsigned long flags; + struct mac_serial *info; + + for (info = zs_chain, i = 0; info; info = info->zs_next, i++) + set_scc_power(info, 0); + save_flags(flags); cli(); + for (i = 0; i < zs_channels_found; ++i) + free_irq(zs_soft[i].irq, &zs_soft[i]); + restore_flags(flags); + tty_unregister_driver(&callout_driver); + tty_unregister_driver(&serial_driver); +} +#endif /* MODULE */ #if 0 /* diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c --- v2.3.15/linux/drivers/macintosh/mediabay.c Wed Aug 4 16:36:41 1999 +++ linux/drivers/macintosh/mediabay.c Tue Aug 31 11:35:59 1999 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #undef MB_USE_INTERRUPTS @@ -64,8 +64,7 @@ #ifdef CONFIG_BLK_DEV_IDE /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ -#define MB_IDE_READY(i) ((in_8((volatile unsigned char *) \ - (media_bays[i].cd_base + 0x70)) & 0x80) == 0) +#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0) #endif /* diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c --- v2.3.15/linux/drivers/macintosh/nvram.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/macintosh/nvram.c Tue Aug 31 11:35:59 1999 @@ -17,12 +17,6 @@ #define NVRAM_SIZE 8192 -/* when building as a module, __openfirmware is both unavailable - * and unnecessary. */ -#ifndef MODULE -__openfirmware -#endif - static long long nvram_llseek(struct file *file, loff_t offset, int origin) { switch (origin) { diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c --- v2.3.15/linux/drivers/macintosh/via-cuda.c Wed Aug 4 16:36:41 1999 +++ linux/drivers/macintosh/via-cuda.c Tue Aug 31 11:35:59 1999 @@ -94,8 +94,6 @@ cuda_poll }; -__openfirmware - void find_via_cuda() { @@ -340,10 +338,11 @@ { int ie; - ie = _disable_interrupts(); + __save_flags(ie); + __cli(); if (via[IFR] & SR_INT) via_interrupt(0, 0, 0); - _enable_interrupts(ie); + __restore_flags(ie); } static void @@ -496,4 +495,4 @@ cuda_present(void) { return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via); -} \ No newline at end of file +} diff -u --recursive --new-file v2.3.15/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c --- v2.3.15/linux/drivers/macintosh/via-pmu.c Wed Aug 4 16:36:41 1999 +++ linux/drivers/macintosh/via-pmu.c Tue Aug 31 11:35:59 1999 @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -556,10 +556,11 @@ { int ie; - ie = _disable_interrupts(); + __save_flags(ie); + __cli(); if (via[IFR] & (SR_INT | CB1_INT)) via_pmu_interrupt(0, 0, 0); - _enable_interrupts(ie); + __restore_flags(ie); } static void __openfirmware @@ -846,7 +847,7 @@ { struct adb_request req; - _disable_interrupts(); + __cli(); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | PMU_INT_TICK ); @@ -865,7 +866,7 @@ { struct adb_request req; - _disable_interrupts(); + __cli(); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | PMU_INT_TICK ); @@ -945,9 +946,9 @@ for (j = 0; j < 6; ++j) pci_write_config_dword(pd, PCI_BASE_ADDRESS_0 + j*4, - pd->base_address[j]); + pd->resource[j].start); pci_write_config_dword(pd, PCI_ROM_ADDRESS, - pd->rom_address); + pd->resource[PCI_ROM_RESOURCE].start); pci_write_config_word(pd, PCI_CACHE_LINE_SIZE, ps->cache_lat); pci_write_config_word(pd, PCI_INTERRUPT_LINE, diff -u --recursive --new-file v2.3.15/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.3.15/linux/drivers/net/8390.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/8390.c Thu Aug 26 14:24:44 1999 @@ -983,7 +983,7 @@ } /* - * Initialize the rest of the 8390 device structure. Do NOT __initfunc + * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ diff -u --recursive --new-file v2.3.15/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.3.15/linux/drivers/net/arcnet.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/arcnet.c Mon Aug 30 10:29:44 1999 @@ -472,7 +472,7 @@ #ifdef CONFIG_ARCNET_1051 /* Initialize the RFC1051-encap protocol driver */ lp->sdev=(struct net_device *)kmalloc(sizeof(struct net_device)+10,GFP_KERNEL); - if(lp->sdev = NULL) + if(lp->sdev == NULL) { if(lp->edev) kfree(lp->edev); diff -u --recursive --new-file v2.3.15/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.3.15/linux/drivers/net/arlan.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/arlan.c Thu Aug 26 14:25:39 1999 @@ -72,11 +72,9 @@ // #warning kernel 2.1.110 tested #define myATOMIC_INIT(a,b) atomic_set(&(a),b) -#define __initfunctio(a) __initfunc(a) #else #define test_and_set_bit set_bit -#define __initfunctio(a) a #if LINUX_VERSION_CODE != 0x20024 // #warning kernel 2.0.36 tested #endif @@ -1034,7 +1032,7 @@ * verifies that the correct device exists and functions. */ -__initfunctio(static int arlan_check_fingerprint(int memaddr)) +static int __init arlan_check_fingerprint(int memaddr) { static char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; char tempBuf[49]; @@ -1056,7 +1054,7 @@ } -__initfunctio(int arlan_probe_everywhere(struct net_device *dev)) +int __init arlan_probe_everywhere(struct net_device *dev) { int m; int probed = 0; @@ -1094,7 +1092,7 @@ return ENODEV; } -__initfunctio(int arlan_find_devices(void)) +int __init arlan_find_devices(void) { int m; int found = 0; @@ -1153,8 +1151,8 @@ -__initfunctio(static int - arlan_allocate_device(int num, struct net_device *devs)) +static int __init + arlan_allocate_device(int num, struct net_device *devs) { struct net_device *dev; @@ -1214,7 +1212,7 @@ } -__initfunctio(int arlan_probe_here(struct net_device *dev, int memaddr)) +int __init arlan_probe_here(struct net_device *dev, int memaddr) { volatile struct arlan_shmem *arlan; @@ -1992,7 +1990,7 @@ } -__initfunctio(int arlan_probe(struct net_device *dev)) +int __init arlan_probe(struct net_device *dev) { printk("Arlan driver %s\n", arlan_version); diff -u --recursive --new-file v2.3.15/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c --- v2.3.15/linux/drivers/net/bagetlance.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/bagetlance.c Thu Aug 26 14:26:09 1999 @@ -469,7 +469,7 @@ } -__initfunc(int bagetlance_probe( struct net_device *dev )) +int __init bagetlance_probe( struct net_device *dev ) { int i; static int found = 0; @@ -493,9 +493,9 @@ /* Derived from hwreg_present() in vme/config.c: */ -__initfunc(static int addr_accessible( volatile void *regp, - int wordflag, - int writeflag )) +static int __init addr_accessible( volatile void *regp, + int wordflag, + int writeflag ) { /* We have a fine function to do it */ extern int try_read(unsigned long, int); @@ -508,8 +508,8 @@ #define IRQ_TYPE_PRIO SA_INTERRUPT #define IRQ_SOURCE_TO_VECTOR(x) (x) -__initfunc(static unsigned long lance_probe1( struct net_device *dev, - struct lance_addr *init_rec )) +static unsigned long __init lance_probe1( struct net_device *dev, + struct lance_addr *init_rec ) { volatile unsigned short *memaddr = (volatile unsigned short *)init_rec->memaddr; diff -u --recursive --new-file v2.3.15/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.3.15/linux/drivers/net/bmac.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/bmac.c Tue Aug 31 11:35:59 1999 @@ -297,7 +297,6 @@ val = bmac_mif_readbits(dev, 17); bmwrite(dev, MIFCSR, 4); MIFDELAY; - /* printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val); */ return val; } @@ -431,18 +430,26 @@ static int bmac_init_chip(struct net_device *dev) { - if (is_bmac_plus && bmac_mif_read(dev, 2) == 0x7810) { - if (bmac_mif_read(dev, 4) == 0xa1) { - bmac_mif_write(dev, 0, 0x1000); - } else { - bmac_mif_write(dev, 4, 0xa1); + unsigned int addr; + + printk(KERN_DEBUG "phy registers:"); + for (addr = 0; addr < 32; ++addr) { + if ((addr & 7) == 0) + printk("\n" KERN_DEBUG); + printk(" %.4x", bmac_mif_read(dev, addr)); + } + printk("\n"); + if (is_bmac_plus) { + unsigned int capable, ctrl; + + ctrl = bmac_mif_read(dev, 0); + capable = ((bmac_mif_read(dev, 1) & 0xf800) >> 6) | 1; + if (bmac_mif_read(dev, 4) != capable + || (ctrl & 0x1000) == 0) { + bmac_mif_write(dev, 4, capable); bmac_mif_write(dev, 0, 0x1200); - } -#if 0 - /* XXX debugging */ - bmac_mif_read(dev, 0); - bmac_mif_read(dev, 4); -#endif + } else + bmac_mif_write(dev, 0, 0x1000); } bmac_init_registers(dev); return 1; @@ -1330,6 +1337,7 @@ dev->flags |= IFF_UP | IFF_RUNNING; + MOD_INC_USE_COUNT; return 0; } @@ -1374,6 +1382,8 @@ } bp->reset_and_enabled = 0; XXDEBUG(("bmac: all bufs freed\n")); + + MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.3.15/linux/drivers/net/cosa.c linux/drivers/net/cosa.c --- v2.3.15/linux/drivers/net/cosa.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/cosa.c Tue Aug 31 11:30:48 1999 @@ -1560,7 +1560,6 @@ /* sleep if not ready to read */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); - current->state = TASK_RUNNING; } printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n", cosa_getstatus(cosa)); @@ -1588,7 +1587,6 @@ /* sleep if not ready to read */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); - current->state = TASK_RUNNING; #endif } printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n", diff -u --recursive --new-file v2.3.15/linux/drivers/net/cycx_drv.c linux/drivers/net/cycx_drv.c --- v2.3.15/linux/drivers/net/cycx_drv.c Thu Aug 12 09:46:13 1999 +++ linux/drivers/net/cycx_drv.c Tue Aug 31 11:30:48 1999 @@ -638,7 +638,6 @@ know it all the contexts where this routine is used are interruptible... */ current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(sec*HZ); } diff -u --recursive --new-file v2.3.15/linux/drivers/net/cycx_main.c linux/drivers/net/cycx_main.c --- v2.3.15/linux/drivers/net/cycx_main.c Thu Aug 12 09:46:13 1999 +++ linux/drivers/net/cycx_main.c Thu Aug 26 14:28:20 1999 @@ -36,7 +36,7 @@ #include /* WAN router definitions */ #include /* cyclomx common user API definitions */ #include /* kernel <-> user copy */ -#include /* __initfunc (when not using as a module) */ +#include /* __init (when not using as a module) */ #ifdef MODULE MODULE_AUTHOR("Arnaldo Carvalho de Melo"); @@ -95,7 +95,7 @@ #ifdef MODULE int init_module (void) #else -__initfunc(int cyclomx_init (void)) +int __init cyclomx_init (void) #endif { int cnt, err = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/net/declance.c linux/drivers/net/declance.c --- v2.3.15/linux/drivers/net/declance.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/declance.c Thu Aug 26 14:28:48 1999 @@ -1000,7 +1000,7 @@ dev->tbusy = 0; } -__initfunc(static int dec_lance_init(struct net_device *dev, const int type)) +static int __init dec_lance_init(struct net_device *dev, const int type) { static unsigned version_printed = 0; struct lance_private *lp; @@ -1194,7 +1194,7 @@ /* Find all the lance cards on the system and initialize them */ -__initfunc(int dec_lance_probe(struct net_device *dev)) +int __init dec_lance_probe(struct net_device *dev) { static int called = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.3.15/linux/drivers/net/defxx.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/defxx.c Mon Aug 30 10:23:14 1999 @@ -549,11 +549,12 @@ /* Get I/O base address from PCI Configuration Space */ - port = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + port = pdev->resource[1].start /* Verify port address range is not already being used */ port_len = PFI_K_CSR_IO_LEN; + if (check_region(port, port_len) == 0) { /* Allocate a new device structure for this adapter */ diff -u --recursive --new-file v2.3.15/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.3.15/linux/drivers/net/eepro.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/eepro.c Thu Aug 26 14:26:40 1999 @@ -23,7 +23,7 @@ This is a compatibility hardware problem. Versions: - 0.11d added __initdata, __initfunc stuff; call spin_lock_init + 0.11d added __initdata, __init stuff; call spin_lock_init in eepro_probe1. Replaced "eepro" by dev->name. Augmented the code protected by spin_lock in interrupt routine (PdP, 12/12/1998) @@ -157,7 +157,6 @@ /* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */ #define SLOW_DOWN inb(0x80) /* udelay(2) */ -#define compat_init_func(X) __initfunc(X) #define compat_init_data __initdata #else @@ -166,7 +165,6 @@ #define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb), (mode) ) #define test_and_set_bit(a,b) set_bit((a),(b)) #define SLOW_DOWN SLOW_DOWN_IO -#define compat_init_func(X) X #define compat_init_data #endif @@ -461,7 +459,7 @@ struct netdev_entry netcard_drv = {"eepro", eepro_probe1, EEPRO_IO_EXTENT, eepro_portlist}; #else -compat_init_func(int eepro_probe(struct net_device *dev)) +int __init eepro_probe(struct net_device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; diff -u --recursive --new-file v2.3.15/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.3.15/linux/drivers/net/eth16i.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/eth16i.c Thu Aug 26 14:28:58 1999 @@ -171,7 +171,6 @@ #else #define __init #define __initdata -#define __initfunc(x) x #endif #if LINUX_VERSION_CODE < 0x20138 diff -u --recursive --new-file v2.3.15/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.3.15/linux/drivers/net/ewrk3.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ewrk3.c Mon Aug 30 10:23:14 1999 @@ -1414,7 +1414,7 @@ ** If at end of eth device list and can't use current entry, malloc ** one up. If memory could not be allocated, print an error message. */ -static __init struct net_device * +static struct net_device * __init insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *)) { struct net_device *new; diff -u --recursive --new-file v2.3.15/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c --- v2.3.15/linux/drivers/net/fc/iph5526.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/fc/iph5526.c Tue Aug 31 11:23:03 1999 @@ -224,7 +224,7 @@ #endif -__initfunc(int iph5526_probe(struct net_device *dev)) +int __init iph5526_probe(struct net_device *dev) { #ifdef CONFIG_PCI if (pci_present() && (iph5526_probe_pci(dev) == 0)) @@ -234,7 +234,7 @@ } #ifdef CONFIG_PCI -__initfunc(static int iph5526_probe_pci(struct net_device *dev)) +static int __init iph5526_probe_pci(struct net_device *dev) { #ifndef MODULE struct fc_info *fi; @@ -278,7 +278,7 @@ } #endif /* CONFIG_PCI */ -__initfunc(static int fcdev_init(struct net_device *dev)) +static int __init fcdev_init(struct net_device *dev) { dev->open = iph5526_open; dev->stop = iph5526_close; diff -u --recursive --new-file v2.3.15/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.3.15/linux/drivers/net/hp100.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/hp100.c Thu Aug 26 14:27:43 1999 @@ -119,10 +119,6 @@ typedef struct enet_statistics hp100_stats_t; #endif -#ifndef __initfunc -#define __initfunc(__initarg) __initarg -#endif - #include "hp100.h" /* diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in --- v2.3.15/linux/drivers/net/irda/Config.in Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/Config.in Mon Aug 30 10:23:14 1999 @@ -20,6 +20,7 @@ dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA + dep_tristate ' Adaptec Airport 1000/2000 dongle' CONFIG_AIRPORT_DONGLE $CONFIG_IRDA fi endmenu diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile --- v2.3.15/linux/drivers/net/irda/Makefile Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/Makefile Mon Aug 30 10:23:14 1999 @@ -156,6 +156,14 @@ endif endif +ifeq ($(CONFIG_AIRPORT_DONGLE),y) +L_OBJS += airport.o +else + ifeq ($(CONFIG_AIRPORT_DONGLE),m) + M_OBJS += airport.o + endif +endif + include $(TOPDIR)/Rules.make clean: diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/actisys.c linux/drivers/net/irda/actisys.c --- v2.3.15/linux/drivers/net/irda/actisys.c Tue Jul 6 19:05:49 1999 +++ linux/drivers/net/irda/actisys.c Mon Aug 30 10:23:14 1999 @@ -7,7 +7,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Sun May 16 14:35:11 1999 + * Modified at: Sat Jun 26 16:57:57 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. @@ -37,11 +37,11 @@ static void actisys_reset(struct irda_device *dev); static void actisys_open(struct irda_device *idev, int type); static void actisys_close(struct irda_device *dev); -static void actisys_change_speed( struct irda_device *dev, int baudrate); +static void actisys_change_speed( struct irda_device *dev, __u32 speed); static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos); /* These are the baudrates supported */ -static int baud_rates[] = { 9600, 19200, 57600, 115200, 38400}; +static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400}; static struct dongle dongle = { ACTISYS_DONGLE, @@ -107,9 +107,9 @@ * To cycle through the available baud rates, pulse RTS low for a few * ms. */ -static void actisys_change_speed(struct irda_device *idev, int baudrate) +static void actisys_change_speed(struct irda_device *idev, __u32 speed) { - int current_baudrate; + __u32 current_baudrate; int index = 0; DEBUG(4, __FUNCTION__ "()\n"); @@ -126,7 +126,7 @@ DEBUG( 4, __FUNCTION__ "(), index=%d\n", index); /* Cycle through avaiable baudrates until we reach the correct one */ - while (current_baudrate != baudrate) { + while (current_baudrate != speed) { DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", baud_rates[index]); @@ -152,7 +152,7 @@ current_baudrate = baud_rates[index]; } - DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n",baud_rates[index]); + DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", baud_rates[index]); } /* diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/airport.c linux/drivers/net/irda/airport.c --- v2.3.15/linux/drivers/net/irda/airport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/irda/airport.c Tue Aug 31 11:23:03 1999 @@ -0,0 +1,374 @@ +/********************************************************************* + * + * Filename: airport.c + * Version: 0.2 + * Description: Implementation for the Adaptec Airport 1000 and 2000 + * dongles + * Status: Experimental. + * Author: Fons Botman + * Created at: Wed May 19 23:14:34 CEST 1999 + * Based on: actisys.c + * By: Dag Brattli + * + * Copyright (c) 1998-1999 Fons Botman, All Rights Reserved. + * + * 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. + * + * Neither Fons Botman nor anyone else admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +static void airport_reset(struct irda_device *dev); +static void airport_open(struct irda_device *idev, int type); +static void airport_close(struct irda_device *dev); +static void airport_change_speed( struct irda_device *dev, __u32 speed); +static void airport_init_qos(struct irda_device *idev, struct qos_info *qos); + + +static struct dongle dongle = { + AIRPORT_DONGLE, + airport_open, + airport_close, + airport_reset, + airport_change_speed, + airport_init_qos, +}; + + +int __init airport_init(void) +{ + int ret; + + DEBUG(2, __FUNCTION__ "()\n"); + ret = irda_device_register_dongle(&dongle); + if (ret < 0) + return ret; + return 0; +} + +void airport_cleanup(void) +{ + DEBUG(2, __FUNCTION__ "()\n"); + irda_device_unregister_dongle(&dongle); +} + +static void airport_open(struct irda_device *idev, int type) +{ + DEBUG(2, __FUNCTION__ "(,%d)\n", type); + if (strlen(idev->description) < sizeof(idev->description) - 13) + strcat(idev->description, " <-> airport"); + else + DEBUG(0, __FUNCTION__ " description too long: %s\n", + idev->description); + + idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; + + MOD_INC_USE_COUNT; +} + +static void airport_close(struct irda_device *idev) +{ + DEBUG(2, __FUNCTION__ "()\n"); + /* Power off dongle */ + irda_device_set_dtr_rts(idev, FALSE, FALSE); + + MOD_DEC_USE_COUNT; +} + +static void airport_set_command_mode(struct irda_device *idev) +{ + DEBUG(2, __FUNCTION__ "()\n"); + irda_device_set_dtr_rts(idev, FALSE, TRUE); +} + +static void airport_set_normal_mode(struct irda_device *idev) +{ + DEBUG(2, __FUNCTION__ "()\n"); + irda_device_set_dtr_rts(idev, TRUE, TRUE); +} + + +void airport_write_char(struct irda_device *idev, unsigned char c) +{ + int actual; + DEBUG(2, __FUNCTION__ "(,0x%x)\n", c & 0xff); + actual = idev->raw_write(idev, &c, 1); + ASSERT(actual == 1, return;); +} + +#define JIFFIES_TO_MSECS(j) ((j)*1000/HZ) + +static int airport_waitfor_char(struct irda_device *idev, unsigned char c) +{ + int i, found = FALSE; + int before; + DEBUG(2, __FUNCTION__ "(,0x%x)\n", c); + + /* Sleep approx. 10 ms */ + before = jiffies; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(MSECS_TO_JIFFIES(20)); + DEBUG(4, __FUNCTION__ " waited %ldms\n", + JIFFIES_TO_MSECS(jiffies - before)); + + for ( i = 0 ; !found && i < idev->rx_buff.len ; i++ ) { + /* DEBUG(6, __FUNCTION__ " 0x02x\n", idev->rx_buff.data[i]); */ + found = c == idev->rx_buff.data[i]; + } + idev->rx_buff.len = 0; + + DEBUG(2, __FUNCTION__ " returns %s\n", (found ? "true" : "false")); + return found; +} + +static int airport_check_command_mode(struct irda_device *idev) +{ + int i; + int found = FALSE; + + DEBUG(2, __FUNCTION__ "()\n"); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(MSECS_TO_JIFFIES(20)); + airport_set_command_mode(idev); + + /* Loop until the time expires (200ms) or we get the magic char. */ + + for ( i = 0 ; i < 25 ; i++ ) { + airport_write_char(idev, 0xff); + if (airport_waitfor_char(idev, 0xc3)) { + found = TRUE; + break; + } + } + + if (found) { + DEBUG(2, __FUNCTION__ " OK. (%d)\n", i); + } else { + DEBUG(0, __FUNCTION__ " FAILED!\n"); + } + return found; +} + + +static int airport_write_register(struct irda_device *idev, unsigned char reg) +{ + int ok = FALSE; + int i; + + DEBUG(4, __FUNCTION__ "(,0x%x)\n", reg); + airport_check_command_mode(idev); + + for ( i = 0 ; i < 6 ; i++ ) { + airport_write_char(idev, reg); + if (!airport_waitfor_char(idev, reg)) + continue; + + /* Now read it back */ + airport_write_char(idev, (reg << 4) | 0x0f); + if (airport_waitfor_char(idev, reg)) { + ok = TRUE; + break; + } + } + + airport_set_normal_mode(idev); + if (ok) { + DEBUG(4, __FUNCTION__ "(,0x%x) returns OK\n", reg); + } else { + DEBUG(0, __FUNCTION__ "(,0x%x) returns False!\n", reg); + } + return ok; +} + + +/* + * Function airport_change_speed (tty, baud) + * + * Change speed of the Airport type IrDA dongles. + */ +static void airport_change_speed(struct irda_device *idev, __u32 speed) +{ + __u32 current_baudrate; + int baudcode; + + DEBUG(4, __FUNCTION__ "(,%d)\n", speed); + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + /* Find the correct baudrate code for the required baudrate */ + switch (speed) { + case 2400: baudcode = 0x10; break; + case 4800: baudcode = 0x20; break; + case 9600: baudcode = 0x30; break; + case 19200: baudcode = 0x40; break; + case 38400: baudcode = 0x50; break; + case 57600: baudcode = 0x60; break; + case 115200: baudcode = 0x70; break; + default: + DEBUG(0, __FUNCTION__ " bad baud rate: %d\n", speed); + return; + } + + current_baudrate = idev->qos.baud_rate.value; + DEBUG(4, __FUNCTION__ " current baudrate: %d\n", current_baudrate); + + /* The dongle falls back to 9600 baud */ + if (current_baudrate != 9600) { + DEBUG(4, __FUNCTION__ " resetting speed to 9600 baud\n"); + ASSERT(idev->change_speed , return;); + idev->change_speed(idev, 9600); + idev->qos.baud_rate.value = 9600; + } + + if (idev->set_raw_mode) + idev->set_raw_mode(idev, TRUE); + + /* Set the new speed in both registers */ + if (airport_write_register(idev, baudcode)) { + if (airport_write_register(idev, baudcode|0x01)) { + /* ok */ + } else { + DEBUG(0, __FUNCTION__ + " Cannot set new speed in second register\n"); + } + } else { + DEBUG(0, __FUNCTION__ + " Cannot set new speed in first register\n"); + } + + if (idev->set_raw_mode) + idev->set_raw_mode(idev, FALSE); + + /* How do I signal an error in these functions? */ + + DEBUG(4, __FUNCTION__ " returning\n"); +} + + +/* + * Function airport_reset (idev) + * + * Reset the Airport type dongle. Warning, this function must only be + * called with a process context! + * + */ +static void airport_reset(struct irda_device *idev) +{ + int ok; + + DEBUG(2, __FUNCTION__ "()\n"); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev->set_raw_mode /* The airport needs this */, return;); + + if (idev->set_raw_mode) + idev->set_raw_mode(idev, TRUE); + + airport_set_normal_mode(idev); + + /* Sleep 2000 ms */ + DEBUG(2, __FUNCTION__ " waiting for powerup\n"); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(MSECS_TO_JIFFIES(2000)); + DEBUG(2, __FUNCTION__ " finished waiting for powerup\n"); + + /* set dongle speed to 9600 */ + ok = TRUE; + + if (ok) + ok = airport_write_register(idev, 0x30); + if (!ok) + MESSAGE(__FUNCTION__ "() dongle not connected?\n"); + if (ok) + ok = airport_write_register(idev, 0x31); + + if (ok) + ok = airport_write_register(idev, 0x02); + if (ok) + ok = airport_write_register(idev, 0x03); + + if (ok) { + ok = airport_check_command_mode(idev); + + if (ok) { + airport_write_char(idev, 0x04); + ok = airport_waitfor_char(idev, 0x04); + } + airport_set_normal_mode(idev); + } + + if (idev->set_raw_mode) + idev->set_raw_mode(idev, FALSE); + + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(MSECS_TO_JIFFIES(20)); + DEBUG(4, __FUNCTION__ " waited 20ms\n"); + + idev->qos.baud_rate.value = 9600; + if (!ok) + MESSAGE(__FUNCTION__ "() failed.\n"); + DEBUG(2, __FUNCTION__ " returning.\n"); +} + +/* + * Function airport_init_qos (qos) + * + * Initialize QoS capabilities + * + */ +static void airport_init_qos(struct irda_device *idev, struct qos_info *qos) +{ + qos->baud_rate.bits &= + IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + /* May need 1ms */ + qos->min_turn_time.bits &= 0x07; +} + +#ifdef MODULE + +MODULE_AUTHOR("Fons Botman "); +MODULE_DESCRIPTION("Adaptec Airport 1000 and 2000 dongle driver"); + +/* + * Function init_module (void) + * + * Initialize Airport module + * + */ +int init_module(void) +{ + return airport_init(); +} + +/* + * Function cleanup_module (void) + * + * Cleanup Airport module + * + */ +void cleanup_module(void) +{ + airport_cleanup(); +} + +#endif diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/esi.c linux/drivers/net/irda/esi.c --- v2.3.15/linux/drivers/net/irda/esi.c Tue Jul 6 19:05:49 1999 +++ linux/drivers/net/irda/esi.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Thomas Davis, * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Sun May 16 14:35:21 1999 + * Modified at: Sat Jun 26 16:50:17 1999 * Modified by: Dag Brattli * Sources: esi.c * @@ -39,7 +39,7 @@ static void esi_open(struct irda_device *idev, int type); static void esi_close(struct irda_device *driver); -static void esi_change_speed(struct irda_device *idev, int baud); +static void esi_change_speed(struct irda_device *idev, __u32 speed); static void esi_reset(struct irda_device *idev); static void esi_qos_init(struct irda_device *idev, struct qos_info *qos); @@ -81,19 +81,19 @@ } /* - * Function esi_change_speed (tty, baud) + * Function esi_change_speed (idev, speed) * * Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle * */ -static void esi_change_speed(struct irda_device *idev, int baud) +static void esi_change_speed(struct irda_device *idev, __u32 speed) { int dtr, rts; ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - switch (baud) { + switch (speed) { case 19200: dtr = TRUE; rts = FALSE; diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/girbil.c linux/drivers/net/irda/girbil.c --- v2.3.15/linux/drivers/net/irda/girbil.c Tue Jul 6 19:05:49 1999 +++ linux/drivers/net/irda/girbil.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Feb 6 21:02:33 1999 - * Modified at: Tue Jun 1 08:47:41 1999 + * Modified at: Sun Jul 18 12:09:26 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -37,7 +37,7 @@ static void girbil_reset(struct irda_device *dev); static void girbil_open(struct irda_device *dev, int type); static void girbil_close(struct irda_device *dev); -static void girbil_change_speed(struct irda_device *dev, int baud); +static void girbil_change_speed(struct irda_device *dev, __u32 speed); static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos); /* Control register 1 */ @@ -111,7 +111,7 @@ * function must be called with a process context! * */ -static void girbil_change_speed(struct irda_device *idev, int speed) +static void girbil_change_speed(struct irda_device *idev, __u32 speed) { __u8 control[2]; @@ -138,6 +138,9 @@ } control[1] = GIRBIL_LOAD; + /* Need to reset the dongle and go to 9600 bps before programming */ + girbil_reset(idev); + /* Set DTR and Clear RTS to enter command mode */ irda_device_set_dtr_rts(idev, FALSE, TRUE); @@ -145,7 +148,7 @@ irda_device_raw_write(idev, control, 2); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); + schedule_timeout(MSECS_TO_JIFFIES(100)); /* Go back to normal mode */ irda_device_set_dtr_rts(idev, TRUE, TRUE); @@ -168,18 +171,22 @@ ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + /* Make sure the IrDA chip also goes to defalt speed */ + if (idev->change_speed) + idev->change_speed(idev, 9600); + /* Reset dongle */ irda_device_set_dtr_rts(idev, TRUE, FALSE); /* Sleep at least 5 ms */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); + schedule_timeout(MSECS_TO_JIFFIES(10)); /* Set DTR and clear RTS to enter command mode */ irda_device_set_dtr_rts(idev, FALSE, TRUE); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); + schedule_timeout(MSECS_TO_JIFFIES(10)); /* Write control byte */ irda_device_raw_write(idev, &control, 1); @@ -189,10 +196,6 @@ /* Go back to normal mode */ irda_device_set_dtr_rts(idev, TRUE, TRUE); - - /* Make sure the IrDA chip also goes to defalt speed */ - if (idev->change_speed) - idev->change_speed(idev, 9600); } /* diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c --- v2.3.15/linux/drivers/net/irda/irport.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/irda/irport.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 3 13:49:59 1997 - * Modified at: Tue Jun 1 10:02:42 1999 + * Modified at: Wed Aug 11 09:24:46 1999 * Modified by: Dag Brattli * Sources: serial.c by Linus Torvalds * @@ -272,7 +272,7 @@ * Set speed of IrDA port to specified baudrate * */ -void irport_change_speed(struct irda_device *idev, int speed) +void irport_change_speed(struct irda_device *idev, __u32 speed) { unsigned long flags; int iobase; @@ -319,7 +319,7 @@ outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ /* Turn on interrups */ - outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER); + outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); spin_unlock_irqrestore(&idev->lock, flags); } @@ -375,7 +375,7 @@ outb(fcr, iobase+UART_FCR); /* Turn on receive interrupts */ - outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); + outb(/* UART_IER_RLSI| */UART_IER_RDI, iobase+UART_IER); } } @@ -432,7 +432,7 @@ /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) { int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) + if ((tickssofar < 5) || !dev->start) return -EBUSY; WARNING("%s: transmit timed out\n", dev->name); @@ -443,7 +443,7 @@ } spin_lock_irqsave(&idev->lock, flags); - + /* Init tx buffer */ idev->tx_buff.data = idev->tx_buff.head; @@ -465,7 +465,7 @@ } /* - * Function irport_receive (void) + * Function irport_receive (idev) * * Receive one frame from the infrared port * @@ -527,10 +527,10 @@ switch (iir) { case UART_IIR_RLSI: - DEBUG(0, __FUNCTION__ "(), RLSI\n"); + DEBUG(2, __FUNCTION__ "(), RLSI\n"); break; case UART_IIR_RDI: - if (lsr & UART_LSR_DR) + //if (lsr & UART_LSR_DR) /* Receive interrupt */ irport_receive(idev); break; @@ -545,7 +545,7 @@ } /* Make sure we don't stay here to long */ - if (boguscount++ > 32) + if (boguscount++ > 100) break; iir = inb(iobase + UART_IIR) & UART_IIR_ID; @@ -586,18 +586,14 @@ return -EAGAIN; irport_start(idev, iobase); - - MOD_INC_USE_COUNT; - - /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + irda_device_net_open(dev); /* Change speed to make sure dongles follow us again */ if (idev->change_speed) idev->change_speed(idev, 9600); + MOD_INC_USE_COUNT; + return 0; } @@ -612,17 +608,17 @@ struct irda_device *idev; int iobase; + DEBUG(4, __FUNCTION__ "()\n"); + ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; - DEBUG(4, __FUNCTION__ "()\n"); + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;) iobase = idev->io.iobase2; - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; - + irda_device_net_close(dev); irport_stop(idev, iobase); free_irq(idev->io.irq2, idev); @@ -664,7 +660,7 @@ } /* - * Function irtty_set_dtr_rts (tty, dtr, rts) + * Function irport_set_dtr_rts (tty, dtr, rts) * * This function can be used by dongles etc. to set or reset the status * of the dtr and rts lines diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c --- v2.3.15/linux/drivers/net/irda/irtty.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/irda/irtty.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Mon May 10 15:45:50 1999 + * Modified at: Tue Aug 24 13:32:24 1999 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, @@ -49,6 +49,9 @@ static int irtty_is_receiving(struct irda_device *idev); static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts); static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len); +static int irtty_raw_read(struct irda_device *idev, __u8 *buf, int len, + int timeout); +static void irtty_set_raw_mode(struct irda_device *dev, int mode); static int irtty_net_init(struct net_device *dev); static int irtty_net_open(struct net_device *dev); static int irtty_net_close(struct net_device *dev); @@ -57,7 +60,7 @@ static void irtty_close(struct tty_struct *tty); static int irtty_ioctl(struct tty_struct *, void *, int, void *); static int irtty_receive_room(struct tty_struct *tty); -static void irtty_change_speed(struct irda_device *dev, int baud); +static void irtty_change_speed(struct irda_device *dev, __u32 speed); static void irtty_write_wakeup(struct tty_struct *tty); static void irtty_receive_buf(struct tty_struct *, const unsigned char *, @@ -91,10 +94,9 @@ irda_ldisc.receive_room = irtty_receive_room; irda_ldisc.write_wakeup = irtty_write_wakeup; - if (( status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) { - printk(KERN_ERR - "IrDA: can't register line discipline (err = %d)\n", - status); + if ((status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) { + ERROR("IrDA: can't register line discipline (err = %d)\n", + status); } return status; @@ -111,9 +113,7 @@ { int ret; - /* - * Unregister tty line-discipline - */ + /* Unregister tty line-discipline */ if ((ret = tty_register_ldisc(N_IRDA, NULL))) { ERROR(__FUNCTION__ "(), can't unregister line discipline (err = %d)\n", @@ -209,9 +209,11 @@ /* Initialize callbacks */ self->idev.change_speed = irtty_change_speed; self->idev.is_receiving = irtty_is_receiving; + self->idev.wait_until_sent = irtty_wait_until_sent; self->idev.set_dtr_rts = irtty_set_dtr_rts; + self->idev.set_raw_mode = irtty_set_raw_mode; self->idev.raw_write = irtty_raw_write; - self->idev.wait_until_sent = irtty_wait_until_sent; + self->idev.raw_read = irtty_raw_read; /* Override the network functions we need to use */ self->idev.netdev.init = irtty_net_init; @@ -287,19 +289,19 @@ } /* - * Function irtty_change_speed (self, baud) + * Function irtty_change_speed (self, speed) * * Change the speed of the serial port. The driver layer must check that * all transmission has finished using the irtty_wait_until_sent() * function. */ -static void irtty_change_speed(struct irda_device *idev, int baud) +static void irtty_change_speed(struct irda_device *idev, __u32 speed) { struct termios old_termios; struct irtty_cb *self; int cflag; - DEBUG(4,__FUNCTION__ "(), <%ld>\n", jiffies); + DEBUG(4, __FUNCTION__ "(), <%ld>\n", jiffies); ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -314,9 +316,9 @@ cflag &= ~CBAUD; - DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", baud); + DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", speed); - switch (baud) { + switch (speed) { case 1200: cflag |= B1200; break; @@ -401,9 +403,7 @@ { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRTTY_MAGIC, return;); - + DEBUG(5, __FUNCTION__ "(,,,count=%d)\n", count); /* Read the characters out of the buffer */ while (count--) { /* @@ -411,13 +411,25 @@ */ if (fp && *fp++) { DEBUG( 0, "Framing or parity error!\n"); - irda_device_set_media_busy( &self->idev, TRUE); + irda_device_set_media_busy(&self->idev, TRUE); cp++; continue; } - /* Unwrap and destuff one byte */ - async_unwrap_char(&self->idev, *cp++); + + DEBUG(6, __FUNCTION__ " char=0x%02x\n", *cp); + if (self->idev.raw_mode) { + struct irda_device *idev = &self->idev; + + /* What should we do when the buffer is full? */ + if (idev->rx_buff.len == idev->rx_buff.truesize) + idev->rx_buff.len = 0; + + idev->rx_buff.data[idev->rx_buff.len++] = *cp++; + } else { + /* Unwrap and destuff one byte */ + async_unwrap_char(&self->idev, *cp++); + } } } @@ -615,6 +627,72 @@ set_fs(fs); } +/* + * Function irtty_set_raw_mode (idev, status) + * + * For the airport dongle, we need support for reading raw characters + * from the IrDA device. This function switches between those modes. + * FALSE is the default mode, and will then treat incoming data as IrDA + * packets. + */ +void irtty_set_raw_mode(struct irda_device *idev, int status) +{ + struct irtty_cb *self; + + DEBUG(2, __FUNCTION__ "(), status=%s\n", status ? "TRUE" : "FALSE"); + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = (struct irtty_cb *) idev->priv; + + /* save status for driver */ + self->idev.raw_mode = status; + + /* reset the buffer state */ + idev->rx_buff.data = idev->rx_buff.head; + idev->rx_buff.len = 0; + idev->rx_buff.state = OUTSIDE_FRAME; +} + +/* + * Function irtty_raw_read (idev, buf, len) + * + * Receive incomming data. This function sleeps, so it must only be + * called with a process context. Timeout is currently defined to be + * a multiple of 10 ms. + */ +static int irtty_raw_read(struct irda_device *idev, __u8 *buf, int len, + int timeout) +{ + int count; + + buf = idev->rx_buff.data; + + /* Wait for the requested amount of data to arrive */ + while (len < idev->rx_buff.len) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(MSECS_TO_JIFFIES(10)); + + if (!timeout--) + break; + } + + count = idev->rx_buff.len < len ? idev->rx_buff.len : len; + + /* + * Reset the state, this mean that a raw read is sort of a + * datagram read, and _not_ a stream style read. Be aware of the + * difference. Implementing it the other way will just be painful ;-) + */ + idev->rx_buff.data = idev->rx_buff.head; + idev->rx_buff.len = 0; + idev->rx_buff.state = OUTSIDE_FRAME; + + /* Return the amount we were able to get */ + return count; +} + static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len) { struct irtty_cb *self; @@ -634,6 +712,8 @@ return actual; } + + static int irtty_net_init(struct net_device *dev) { /* Set up to be a normal IrDA network device driver */ @@ -646,12 +726,7 @@ static int irtty_net_open(struct net_device *dev) { - ASSERT(dev != NULL, return -1;); - - /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + irda_device_net_open(dev); MOD_INC_USE_COUNT; @@ -660,11 +735,7 @@ static int irtty_net_close(struct net_device *dev) { - ASSERT(dev != NULL, return -1;); - - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; + irda_device_net_close(dev); MOD_DEC_USE_COUNT; @@ -701,10 +772,3 @@ } #endif /* MODULE */ - - - - - - - diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/litelink.c linux/drivers/net/irda/litelink.c --- v2.3.15/linux/drivers/net/irda/litelink.c Tue Jul 6 19:05:49 1999 +++ linux/drivers/net/irda/litelink.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Stable * Author: Dag Brattli * Created at: Fri May 7 12:50:33 1999 - * Modified at: Wed May 19 07:25:15 1999 + * Modified at: Sat Jun 26 17:01:05 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -44,12 +44,12 @@ static void litelink_open(struct irda_device *idev, int type); static void litelink_close(struct irda_device *dev); -static void litelink_change_speed(struct irda_device *dev, int baudrate); +static void litelink_change_speed(struct irda_device *dev, __u32); static void litelink_reset(struct irda_device *dev); static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos); /* These are the baudrates supported */ -static int baud_rates[] = { 115200, 57600, 38400, 19200, 9600 }; +static __u32 baud_rates[] = { 115200, 57600, 38400, 19200, 9600 }; static struct dongle dongle = { LITELINK_DONGLE, @@ -89,12 +89,12 @@ } /* - * Function litelink_change_speed (tty, baud) + * Function litelink_change_speed (idev, speed) * * Change speed of the Litelink dongle. To cycle through the available * baud rates, pulse RTS low for a few ms. */ -static void litelink_change_speed(struct irda_device *idev, int baudrate) +static void litelink_change_speed(struct irda_device *idev, __u32 speed) { int i; @@ -114,7 +114,7 @@ udelay(MIN_DELAY); /* Cycle through avaiable baudrates until we reach the correct one */ - for (i=0; i<5 && baud_rates[i] != baudrate; i++) { + for (i=0; i<5 && baud_rates[i] != speed; i++) { /* Set DTR, clear RTS */ irda_device_set_dtr_rts(idev, FALSE, TRUE); diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/pc87108.c linux/drivers/net/irda/pc87108.c --- v2.3.15/linux/drivers/net/irda/pc87108.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/irda/pc87108.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Mon May 24 15:19:21 1999 + * Modified at: Wed Aug 11 09:26:26 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli @@ -110,7 +110,7 @@ static int pc87108_hard_xmit(struct sk_buff *skb, struct net_device *dev); static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void pc87108_dma_write(struct irda_device *idev, int iobase); -static void pc87108_change_speed(struct irda_device *idev, int baud); +static void pc87108_change_speed(struct irda_device *idev, __u32 baud); static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void pc87108_wait_until_sent(struct irda_device *idev); static int pc87108_is_receiving(struct irda_device *idev); @@ -615,7 +615,7 @@ * Change the speed of the device * */ -static void pc87108_change_speed( struct irda_device *idev, int speed) +static void pc87108_change_speed(struct irda_device *idev, __u32 speed) { __u8 mcr = MCR_SIR; __u8 bank; @@ -1391,12 +1391,7 @@ free_irq( idev->io.irq, idev); return -EAGAIN; } - - /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - + /* Save current bank */ bank = inb( iobase+BSR); @@ -1407,6 +1402,8 @@ /* Restore bank register */ outb( bank, iobase+BSR); + irda_device_net_open(dev); + MOD_INC_USE_COUNT; return 0; @@ -1424,34 +1421,32 @@ int iobase; __u8 bank; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; + irda_device_net_close(dev); - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; - disable_dma( idev->io.dma); + disable_dma(idev->io.dma); /* Save current bank */ - bank = inb( iobase+BSR); + bank = inb(iobase+BSR); /* Disable interrupts */ - switch_bank( iobase, BANK0); - outb( 0, iobase+IER); + switch_bank(iobase, BANK0); + outb(0, iobase+IER); - free_irq( idev->io.irq, idev); - free_dma( idev->io.dma); + free_irq(idev->io.irq, idev); + free_dma(idev->io.dma); /* Restore bank register */ - outb( bank, iobase+BSR); + outb(bank, iobase+BSR); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c --- v2.3.15/linux/drivers/net/irda/smc-ircc.c Wed Aug 18 11:38:52 1999 +++ linux/drivers/net/irda/smc-ircc.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Thomas Davis (tadavis@jps.net) * Created at: - * Modified at: Wed May 19 15:30:08 1999 + * Modified at: Tue Aug 24 13:33:22 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Thomas Davis, All Rights Reserved. @@ -65,7 +65,7 @@ static int ircc_dma_receive_complete(struct irda_device *idev, int iobase); static int ircc_hard_xmit( struct sk_buff *skb, struct net_device *dev); static void ircc_dma_write( struct irda_device *idev, int iobase); -static void ircc_change_speed( struct irda_device *idev, int baud); +static void ircc_change_speed( struct irda_device *idev, __u32 speed); static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void ircc_wait_until_sent( struct irda_device *idev); static int ircc_is_receiving( struct irda_device *idev); @@ -348,7 +348,7 @@ * Change the speed of the device * */ -static void ircc_change_speed( struct irda_device *idev, int speed) +static void ircc_change_speed( struct irda_device *idev, __u32 speed) { struct ircc_cb *self; int iobase, ir_mode, select, fast; @@ -884,9 +884,7 @@ } /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + irda_device_net_open(dev); /* turn on interrupts */ @@ -909,10 +907,6 @@ DEBUG(ircc_debug, __FUNCTION__ " -->\n"); - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; - ASSERT( dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; @@ -920,6 +914,8 @@ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; + + irda_device_net_close(dev); disable_dma( idev->io.dma); diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/tekram.c linux/drivers/net/irda/tekram.c --- v2.3.15/linux/drivers/net/irda/tekram.c Tue Jul 6 19:05:49 1999 +++ linux/drivers/net/irda/tekram.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Sun May 16 14:33:42 1999 + * Modified at: Thu Jul 15 01:17:53 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. @@ -36,7 +36,7 @@ static void tekram_reset(struct irda_device *dev); static void tekram_open(struct irda_device *dev, int type); static void tekram_close(struct irda_device *dev); -static void tekram_change_speed(struct irda_device *dev, int baud); +static void tekram_change_speed(struct irda_device *dev, __u32 speed); static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos); #define TEKRAM_115200 0x00 @@ -85,7 +85,7 @@ } /* - * Function tekram_change_speed (tty, baud) + * Function tekram_change_speed (tty, speed) * * Set the speed for the Tekram IRMate 210 type dongle. Warning, this * function must be called with a process context! @@ -100,7 +100,7 @@ * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here * after */ -static void tekram_change_speed(struct irda_device *idev, int baud) +static void tekram_change_speed(struct irda_device *idev, __u32 speed) { __u8 byte; @@ -109,7 +109,7 @@ ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - switch (baud) { + switch (speed) { default: case 9600: byte = TEKRAM_PW|TEKRAM_9600; @@ -135,7 +135,7 @@ irda_device_set_dtr_rts(idev, TRUE, FALSE); /* Wait at least 7us */ - udelay(7); + udelay(10); /* Write control byte */ irda_device_raw_write(idev, &byte, 1); diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.3.15/linux/drivers/net/irda/toshoboe.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/irda/toshoboe.c Mon Aug 30 10:23:14 1999 @@ -460,7 +460,7 @@ /* Change the baud rate */ static void -toshoboe_change_speed (struct irda_device *idev, int speed) +toshoboe_change_speed (struct irda_device *idev, __u32 speed) { struct toshoboe_cb *self; DEBUG (4, __FUNCTION__ "()\n"); @@ -582,10 +582,7 @@ sti (); - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + irda_device_net_open(dev); MOD_INC_USE_COUNT; @@ -607,9 +604,7 @@ ASSERT (idev != NULL, return 0;); ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;); - dev->tbusy = 1; - dev->start = 0; - + irda_device_net_close(dev); self = idev->priv; @@ -849,7 +844,7 @@ PCI_DEVICE_ID_FIR701, pci_dev); if (pci_dev) { - printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n", + printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %ld\n", pci_dev->resource[0], pci_dev->irq); diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/uircc.c linux/drivers/net/irda/uircc.c --- v2.3.15/linux/drivers/net/irda/uircc.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/irda/uircc.c Mon Aug 30 10:23:14 1999 @@ -7,7 +7,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Dec 26 10:59:03 1998 - * Modified at: Wed May 19 15:29:56 1999 + * Modified at: Tue Aug 24 13:33:57 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. @@ -73,11 +73,11 @@ static int uircc_dma_receive_complete(struct irda_device *idev, int iobase); static int uircc_hard_xmit(struct sk_buff *skb, struct net_device *dev); static void uircc_dma_write(struct irda_device *idev, int iobase); -static void uircc_change_speed(struct irda_device *idev, int baud); +static void uircc_change_speed(struct irda_device *idev, __u32 baud); static void uircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void uircc_wait_until_sent(struct irda_device *idev); static int uircc_is_receiving(struct irda_device *idev); -static int uircc_toshiba_cmd(int *retval, int arg0, int arg1, int arg2); +static int uircc_toshiba_cmd(int *retval, int arg0, int arg1, int arg2); static int uircc_net_init(struct net_device *dev); static int uircc_net_open(struct net_device *dev); static int uircc_net_close(struct net_device *dev); @@ -318,7 +318,7 @@ * Change the speed of the device * */ -static void uircc_change_speed(struct irda_device *idev, int speed) +static void uircc_change_speed(struct irda_device *idev, __u32 speed) { struct uircc_cb *self; int iobase; @@ -846,9 +846,7 @@ } /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + irda_device_net_open(dev); /* turn on interrupts */ @@ -870,10 +868,6 @@ DEBUG(4, __FUNCTION__ "()\n"); - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; - ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; @@ -881,6 +875,8 @@ ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; + + irda_device_net_close(dev); disable_dma(idev->io.dma); diff -u --recursive --new-file v2.3.15/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c --- v2.3.15/linux/drivers/net/irda/w83977af_ir.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/irda/w83977af_ir.c Mon Aug 30 10:23:14 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Fri May 21 22:18:19 1999 + * Modified at: Wed Aug 11 09:27:54 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli @@ -90,7 +90,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev); static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void w83977af_dma_write(struct irda_device *idev, int iobase); -static void w83977af_change_speed(struct irda_device *idev, int baud); +static void w83977af_change_speed(struct irda_device *idev, __u32 speed); static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void w83977af_wait_until_sent(struct irda_device *idev); static int w83977af_is_receiving(struct irda_device *idev); @@ -376,7 +376,7 @@ * Change the speed of the device * */ -void w83977af_change_speed(struct irda_device *idev, int speed) +void w83977af_change_speed(struct irda_device *idev, __u32 speed) { int ir_mode = HCR_SIR; int iobase; @@ -1203,11 +1203,6 @@ return -EAGAIN; } - /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - /* Save current set */ set = inb(iobase+SSR); @@ -1222,6 +1217,9 @@ /* Restore bank register */ outb(set, iobase+SSR); + /* Ready to play! */ + irda_device_net_open(dev); + MOD_INC_USE_COUNT; return 0; @@ -1240,18 +1238,18 @@ __u8 set; DEBUG(0, __FUNCTION__ "()\n"); - - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; ASSERT(dev != NULL, return -1;); + idev = (struct irda_device *) dev->priv; ASSERT(idev != NULL, return 0;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; + + /* Stop device */ + irda_device_net_close(dev); disable_dma(idev->io.dma); diff -u --recursive --new-file v2.3.15/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c --- v2.3.15/linux/drivers/net/jazzsonic.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/jazzsonic.c Thu Aug 26 14:28:05 1999 @@ -90,7 +90,7 @@ * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */ -__initfunc(int sonic_probe(struct net_device *dev)) +int __init sonic_probe(struct net_device *dev) { unsigned int base_addr = dev ? dev->base_addr : 0; int i; @@ -115,8 +115,8 @@ return -ENODEV; } -__initfunc(static int sonic_probe1(struct net_device *dev, - unsigned int base_addr, unsigned int irq)) +static int __init sonic_probe1(struct net_device *dev, + unsigned int base_addr, unsigned int irq) { static unsigned version_printed = 0; unsigned int silicon_revision; diff -u --recursive --new-file v2.3.15/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c --- v2.3.15/linux/drivers/net/macsonic.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/macsonic.c Thu Aug 26 14:29:08 1999 @@ -174,7 +174,7 @@ static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; -__initfunc(int mac_onboard_sonic_probe(void)) +int __init mac_onboard_sonic_probe(void) { struct net_device *dev; unsigned int silicon_revision; diff -u --recursive --new-file v2.3.15/linux/drivers/net/mvme147.c linux/drivers/net/mvme147.c --- v2.3.15/linux/drivers/net/mvme147.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/mvme147.c Thu Aug 26 14:28:33 1999 @@ -70,7 +70,7 @@ #endif /* Initialise the one and only on-board 7990 */ -__initfunc(int mvme147lance_probe(struct net_device *dev)) +int __init mvme147lance_probe(struct net_device *dev) { static int called = 0; static const char name[] = "MVME147 LANCE"; diff -u --recursive --new-file v2.3.15/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.3.15/linux/drivers/net/ne2k-pci.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ne2k-pci.c Mon Aug 30 18:09:00 1999 @@ -86,7 +86,7 @@ {0x4a14, 0x5000, "NetVin NV5000SC", 0}, {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO}, {0x10bd, 0x0e34, "SureCom NE34", 0}, - {0x1050, 0x5a5a, "Winbond", 0}, + {0x1050, 0x5a5a, "Winbond W89C940F", 0}, {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, {0x12c3, 0x5598, "Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, diff -u --recursive --new-file v2.3.15/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.3.15/linux/drivers/net/net_init.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/net_init.c Tue Aug 31 11:23:03 1999 @@ -135,9 +135,11 @@ ether_setup(dev); /* Hmmm, should this be called here? */ - if (new_device) + if (new_device) { + rtnl_lock(); register_netdevice(dev); - + rtnl_unlock(); + } return dev; } @@ -259,9 +261,11 @@ hippi_setup(dev); - if (new_device) + if (new_device) { + rtnl_lock(); register_netdevice(dev); - + rtnl_unlock(); + } return dev; } @@ -601,9 +605,11 @@ /* New-style flags. */ dev->flags = IFF_BROADCAST; - if (new_device) + if (new_device) { + rtnl_lock(); register_netdevice(dev); - + rtnl_unlock(); + } return dev; } @@ -744,9 +750,11 @@ } fc_setup(dev); - if (new_device) + if (new_device) { + rtnl_lock(); register_netdevice(dev); - + rtnl_unlock(); + } return dev; } @@ -775,7 +783,7 @@ void unregister_fcdev(struct net_device *dev) { rtnl_lock(); - unregister_netdevice(dev); + unregister_netdevice(dev); rtnl_unlock(); fc_freedev(dev); } diff -u --recursive --new-file v2.3.15/linux/drivers/net/olympic.c linux/drivers/net/olympic.c --- v2.3.15/linux/drivers/net/olympic.c Wed Aug 18 16:24:11 1999 +++ linux/drivers/net/olympic.c Thu Aug 26 14:27:11 1999 @@ -150,7 +150,7 @@ #endif #endif -__initfunc(int olympic_probe(struct net_device *dev)) +int __init olympic_probe(struct net_device *dev) { int cards_found; @@ -158,7 +158,7 @@ return cards_found ? 0 : -ENODEV; } -__initfunc(static int olympic_scan(struct net_device *dev)) +static int __init olympic_scan(struct net_device *dev) { struct pci_dev *pci_device = NULL ; struct olympic_private *olympic_priv; @@ -226,7 +226,7 @@ } -__initfunc(static int olympic_init(struct net_device *dev)) +static int __init olympic_init(struct net_device *dev) { struct olympic_private *olympic_priv; __u8 *olympic_mmio, *init_srb,*adapter_addr; diff -u --recursive --new-file v2.3.15/linux/drivers/net/ptifddi.c linux/drivers/net/ptifddi.c --- v2.3.15/linux/drivers/net/ptifddi.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ptifddi.c Tue Aug 31 11:25:33 1999 @@ -1,4 +1,4 @@ -/* $Id: ptifddi.c,v 1.8 1999/08/08 01:35:56 davem Exp $ +/* $Id: ptifddi.c,v 1.9 1999/08/20 00:31:07 davem Exp $ * ptifddi.c: Network driver for Performance Technologies single-attach * and dual-attach FDDI sbus cards. * diff -u --recursive --new-file v2.3.15/linux/drivers/net/ptifddi.h linux/drivers/net/ptifddi.h --- v2.3.15/linux/drivers/net/ptifddi.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/ptifddi.h Tue Aug 31 11:25:33 1999 @@ -1,4 +1,4 @@ -/* $Id: ptifddi.h,v 1.2 1996/12/16 06:15:15 davem Exp $ +/* $Id: ptifddi.h,v 1.3 1999/08/20 00:31:08 davem Exp $ * ptifddi.c: Defines for Performance Technologies FDDI sbus cards. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.3.15/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c --- v2.3.15/linux/drivers/net/sdlamain.c Wed Jun 2 14:40:22 1999 +++ linux/drivers/net/sdlamain.c Thu Aug 26 14:27:28 1999 @@ -11,7 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* May 19, 1999 Arnaldo Melo __initfunc for wanpipe_init +* May 19, 1999 Arnaldo Melo __init for wanpipe_init * 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 @@ -43,7 +43,7 @@ #include /* WANPIPE common user API definitions */ #include /* kernel <-> user copy */ #include /* phys_to_virt() */ -#include /* __initfunc (when not using as a module) */ +#include /* __init (when not using as a module) */ /****** Defines & Macros ****************************************************/ @@ -124,7 +124,7 @@ #ifdef MODULE int init_module (void) #else -__initfunc(int wanpipe_init(void)) +int __init wanpipe_init(void) #endif { int cnt, err = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.3.15/linux/drivers/net/sunhme.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/sunhme.c Tue Aug 31 11:25:33 1999 @@ -3325,7 +3325,7 @@ } hpreg_base = pdev->resource[0].start; - if ((pdev->resource[0].flags & IORESOURCE_IOPORT) != 0) { + if ((pdev->resource[0].flags & IORESOURCE_IO) != 0) { printk("happymeal(PCI): Cannot find proper PCI device base address.\n"); return ENODEV; } diff -u --recursive --new-file v2.3.15/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.3.15/linux/drivers/net/sunlance.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/sunlance.c Tue Aug 31 11:25:33 1999 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.87 1999/08/08 01:36:14 davem Exp $ +/* $Id: sunlance.c,v 1.88 1999/08/20 00:31:45 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza diff -u --recursive --new-file v2.3.15/linux/drivers/parport/Config.in linux/drivers/parport/Config.in --- v2.3.15/linux/drivers/parport/Config.in Tue Aug 3 15:30:44 1999 +++ linux/drivers/parport/Config.in Tue Aug 31 11:25:33 1999 @@ -33,6 +33,11 @@ else define_bool CONFIG_PARPORT_ATARI n fi + if [ "$CONFIG_SBUS" = "y" ]; then + dep_tristate ' Sparc hardware (EXPERIMENTAL)' CONFIG_PARPORT_SUNBPP $CONFIG_PARPORT + else + define_bool CONFIG_PARPORT_SUNBPP n + fi # If exactly one hardware type is selected then parport will optimise away # support for loading any others. Defeat this if the user is keen. diff -u --recursive --new-file v2.3.15/linux/drivers/parport/Makefile linux/drivers/parport/Makefile --- v2.3.15/linux/drivers/parport/Makefile Mon Aug 2 11:16:02 1999 +++ linux/drivers/parport/Makefile Tue Aug 31 11:25:33 1999 @@ -57,6 +57,13 @@ M_OBJS += parport_atari.o endif endif + ifeq ($(CONFIG_PARPORT_SUNBPP),y) + LX_OBJS += parport_sunbpp.o + else + ifeq ($(CONFIG_PARPORT_SUNBPP),m) + MX_OBJS += parport_sunbpp.o + endif + endif LX_OBJS += init.o else ifeq ($(CONFIG_PARPORT),m) @@ -81,6 +88,9 @@ endif ifeq ($(CONFIG_PARPORT_ATARI),m) M_OBJS += parport_atari.o + endif + ifeq ($(CONFIG_PARPORT_SUNBPP),m) + M_OBJS += parport_sunbpp.o endif endif diff -u --recursive --new-file v2.3.15/linux/drivers/parport/parport_amiga.c linux/drivers/parport/parport_amiga.c --- v2.3.15/linux/drivers/parport/parport_amiga.c Mon Aug 9 12:32:28 1999 +++ linux/drivers/parport/parport_amiga.c Thu Aug 26 14:29:50 1999 @@ -221,7 +221,7 @@ /* ----------- Initialisation code --------------------------------- */ -__initfunc(int parport_amiga_init(void)) +int __init parport_amiga_init(void) { struct parport *p; diff -u --recursive --new-file v2.3.15/linux/drivers/parport/parport_mfc3.c linux/drivers/parport/parport_mfc3.c --- v2.3.15/linux/drivers/parport/parport_mfc3.c Sun Aug 15 11:48:32 1999 +++ linux/drivers/parport/parport_mfc3.c Thu Aug 26 12:42:33 1999 @@ -313,7 +313,7 @@ /* ----------- Initialisation code --------------------------------- */ -__initfunc(int parport_mfc3_init(void)) +int __init parport_mfc3_init(void) { struct parport *p; int pias = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/parport/parport_sunbpp.c linux/drivers/parport/parport_sunbpp.c --- v2.3.15/linux/drivers/parport/parport_sunbpp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/parport_sunbpp.c Tue Aug 31 11:25:33 1999 @@ -0,0 +1,398 @@ +/* $Id: parport_sunbpp.c,v 1.6 1999/08/31 06:57:22 davem Exp $ + * Parallel-port routines for Sun architecture + * + * Author: Derrick J. Brashear + * + * based on work by: + * Phil Blundell + * Tim Waugh + * Jose Renau + * David Campbell + * Grant Guenther + * Eddie C. Dost + * Stephen Williams (steve@icarus.com) + * Gus Baldauf (gbaldauf@ix.netcom.com) + * Peter Zaitcev + * Tom Dyas + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include /* OpenProm Library */ +#include /* struct linux_sbus *SBus_chain */ +#include /* BPP uses LSI 64854 for DMA */ +#include +#include + +#undef __SUNBPP_DEBUG +#ifdef __SUNBPP_DEBUG +#define dprintk(x) printk x +#else +#define dprintk(x) +#endif + +static void parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); +} + +void +parport_sunbpp_disable_irq(struct parport *p) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + + regs->p_csr &= ~(DMA_INT_ENAB); +} + +void +parport_sunbpp_enable_irq(struct parport *p) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + + regs->p_csr |= DMA_INT_ENAB; +} + +void +parport_sunbpp_write_data(struct parport *p, unsigned char d) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + + regs->p_dr = d; + dprintk(("wrote 0x%x\n", d)); +} + +unsigned char +parport_sunbpp_read_data(struct parport *p) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + + return regs->p_dr; +} + +static void +control_pc_to_sunbpp(struct parport *p, unsigned char status) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_or = regs->p_or; + + if (status & PARPORT_CONTROL_STROBE) + value_tcr |= P_TCR_DS; + if (status & PARPORT_CONTROL_AUTOFD) + value_or |= P_OR_AFXN; + if (status & PARPORT_CONTROL_INIT) + value_or |= P_OR_INIT; + if (status & PARPORT_CONTROL_SELECT) + value_or |= P_OR_SLCT_IN; + + regs->p_or = value_or; + regs->p_tcr = value_tcr; +} + +static unsigned char +status_sunbpp_to_pc(struct parport *p) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char bits = 0; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_ir = regs->p_ir; + + if (!(value_ir & P_IR_ERR)) bits |= PARPORT_STATUS_ERROR; + if (!(value_ir & P_IR_SLCT)) bits |= PARPORT_STATUS_SELECT; + if (!(value_ir & P_IR_PE)) bits |= PARPORT_STATUS_PAPEROUT; + if (value_tcr & P_TCR_ACK) bits |= PARPORT_STATUS_ACK; + if (!(value_tcr & P_TCR_BUSY)) bits |= PARPORT_STATUS_BUSY; + + dprintk(("tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir)); + dprintk(("read status 0x%x\n", bits)); + return bits; +} + +static unsigned char +control_sunbpp_to_pc(struct parport *p) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char bits = 0; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_or = regs->p_or; + + if (!(value_tcr & P_TCR_DS)) bits |= PARPORT_CONTROL_STROBE; + if (!(value_or & P_OR_AFXN)) bits |= PARPORT_CONTROL_AUTOFD; + if (!(value_or & P_OR_INIT)) bits |= PARPORT_CONTROL_INIT; + if (value_or & P_OR_SLCT_IN) bits |= PARPORT_CONTROL_SELECT; + + dprintk(("tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + dprintk(("read control 0x%x\n", bits)); + return bits; +} + +unsigned char +parport_sunbpp_read_control(struct parport *p) +{ + return control_sunbpp_to_pc(p); +} + +unsigned char +parport_sunbpp_frob_control(struct parport *p, unsigned char mask, + unsigned char val) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_or = regs->p_or; + + dprintk(("frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + if (mask & PARPORT_CONTROL_STROBE) { + if (val & PARPORT_CONTROL_STROBE) + value_tcr &= ~P_TCR_DS; + else + value_tcr |= P_TCR_DS; + } + if (mask & PARPORT_CONTROL_AUTOFD) { + if (val & PARPORT_CONTROL_AUTOFD) + value_or &= ~P_OR_AFXN; + else + value_or |= P_OR_AFXN; + } + if (mask & PARPORT_CONTROL_INIT) { + if (val & PARPORT_CONTROL_INIT) + value_or &= ~P_OR_INIT; + else + value_or |= P_OR_INIT; + } + if (mask & PARPORT_CONTROL_SELECT) { + if (val & PARPORT_CONTROL_SELECT) + value_or |= P_OR_SLCT_IN; + else + value_or &= ~P_OR_SLCT_IN; + } + regs->p_or = value_or; + regs->p_tcr = value_tcr; + dprintk(("frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + return parport_sunbpp_read_control(p); +} + +void +parport_sunbpp_write_control(struct parport *p, unsigned char d) +{ + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); + + parport_sunbpp_frob_control (p, wm, d & wm); + return; +} + +unsigned char +parport_sunbpp_read_status(struct parport *p) +{ + return status_sunbpp_to_pc(p); +} + +void parport_sunbpp_data_forward (struct parport *p) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char value_tcr = regs->p_tcr; + + dprintk(("forward\n")); + value_tcr = regs->p_tcr; + value_tcr &= ~P_TCR_DIR; + regs->p_tcr = value_tcr; +} + +void parport_sunbpp_data_reverse (struct parport *p) +{ + struct bpp_regs *regs = (struct bpp_regs *)p->base; + + dprintk(("reverse\n")); + regs->p_tcr |= P_TCR_DIR; +} + +void +parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s) +{ + s->u.pc.ctr = 0xc; + s->u.pc.ecr = 0x0; +} + +void +parport_sunbpp_save_state(struct parport *p, struct parport_state *s) +{ + s->u.pc.ctr = parport_sunbpp_read_control(p); +} + +void +parport_sunbpp_restore_state(struct parport *p, struct parport_state *s) +{ + parport_sunbpp_write_control(p, s->u.pc.ctr); +} + +void +parport_sunbpp_inc_use_count(void) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +void +parport_sunbpp_dec_use_count(void) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static struct parport_operations parport_sunbpp_ops = +{ + parport_sunbpp_write_data, + parport_sunbpp_read_data, + + parport_sunbpp_write_control, + parport_sunbpp_read_control, + parport_sunbpp_frob_control, + + parport_sunbpp_read_status, + + parport_sunbpp_enable_irq, + parport_sunbpp_disable_irq, + + parport_sunbpp_data_forward, + parport_sunbpp_data_reverse, + + parport_sunbpp_init_state, + parport_sunbpp_save_state, + parport_sunbpp_restore_state, + + parport_sunbpp_inc_use_count, + parport_sunbpp_dec_use_count, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, +}; + + +int +init_one_port(struct linux_sbus_device *sdev) +{ + struct parport *p; + /* at least in theory there may be a "we don't dma" case */ + struct parport_operations *ops; + char *base; + int irq, dma, err, size; + struct bpp_regs *regs; + unsigned char value_tcr; + + irq = sdev->irqs[0]; + prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, 1, sdev); + base = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, + "sunbpp", sdev->reg_addrs[0].which_io, 0); + size = sdev->reg_addrs[0].reg_size; + dma = PARPORT_DMA_NONE; + + ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); + if (!ops) { + sparc_free_io(base, size); + return 0; + } + memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); + + if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) { + kfree(ops); + sparc_free_io(base, size); + return 0; + } + + if ((err = request_irq(p->irq, parport_sunbpp_interrupt, + 0, p->name, p)) != 0) { + parport_unregister_port(p); + kfree(ops); + sparc_free_io(base, size); + return err; + } else + parport_sunbpp_enable_irq(p); + + regs = (struct bpp_regs *)p->base; + dprintk(("forward\n")); + value_tcr = regs->p_tcr; + value_tcr &= ~P_TCR_DIR; + regs->p_tcr = value_tcr; + + printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); + parport_proc_register(p); + parport_announce_port (p); + + return 1; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int __init parport_sunbpp_init(void) +#endif +{ + struct linux_sbus *sbus; + struct linux_sbus_device *sdev; + int count = 0; + + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "SUNW,bpp")) + count += init_one_port(sdev); + } + } + return count ? 0 : -ENODEV; +} + +#ifdef MODULE +MODULE_AUTHOR("Derrick J Brashear"); +MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port"); +MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port"); + +void +cleanup_module(void) +{ + struct parport *p = parport_enumerate(), *tmp; + while (p) { + tmp = p->next; + if (1/*p->modes & PARPORT_MODE_PCSPP*/) { + struct parport_operations *ops = p->ops; + if (p->irq != PARPORT_IRQ_NONE) { + parport_sunbpp_disable_irq(p); + free_irq(p->irq, p); + } + sparc_free_io((char *)p->base, p->size); + parport_proc_unregister(p); + parport_unregister_port(p); + kfree (ops); + } + p = tmp; + } +} +#endif diff -u --recursive --new-file v2.3.15/linux/drivers/pci/devlist.h linux/drivers/pci/devlist.h --- v2.3.15/linux/drivers/pci/devlist.h Thu Aug 5 18:44:28 1999 +++ linux/drivers/pci/devlist.h Tue Aug 31 10:53:32 1999 @@ -101,8 +101,9 @@ DEVICE( CIRRUS, CIRRUS_5436, "GD 5436") DEVICE( CIRRUS, CIRRUS_5446, "GD 5446") DEVICE( CIRRUS, CIRRUS_5480, "GD 5480") - DEVICE( CIRRUS, CIRRUS_5464, "GD 5464") - DEVICE( CIRRUS, CIRRUS_5465, "GD 5465") + DEVICE( CIRRUS, CIRRUS_5462, "Laguna") + DEVICE( CIRRUS, CIRRUS_5464, "Laguna 3D") + DEVICE( CIRRUS, CIRRUS_5465, "Laguna 3DA") DEVICE( CIRRUS, CIRRUS_6729, "CL 6729") DEVICE( CIRRUS, CIRRUS_6832, "PD 6832") DEVICE( CIRRUS, CIRRUS_7542, "CL 7542") @@ -134,11 +135,21 @@ ENDVENDOR() VENDOR( TRIDENT, "Trident" ) + DEVICE( TRIDENT, TRIDENT_9320, "Cyber9320") + DEVICE( TRIDENT, TRIDENT_9388, "Cyber9388") DEVICE( TRIDENT, TRIDENT_9397, "Cyber9397") - DEVICE( TRIDENT, TRIDENT_9420, "TG 9420") - DEVICE( TRIDENT, TRIDENT_9440, "TG 9440") - DEVICE( TRIDENT, TRIDENT_9660, "TG 9660 / Cyber9385") - DEVICE( TRIDENT, TRIDENT_9750, "Image 975") + DEVICE( TRIDENT, TRIDENT_939A, "Cyber939a") + DEVICE( TRIDENT, TRIDENT_9520, "Cyber9520") + DEVICE( TRIDENT, TRIDENT_9525, "Cyber9525") + DEVICE( TRIDENT, TRIDENT_9420, "TGUI 9420") + DEVICE( TRIDENT, TRIDENT_9440, "TGUI 9440") + DEVICE( TRIDENT, TRIDENT_9660, "TGUI 9660 / Cyber9385") + DEVICE( TRIDENT, TRIDENT_9750, "3DImage 975") + DEVICE( TRIDENT, TRIDENT_9850, "3DImage 985") + DEVICE( TRIDENT, TRIDENT_9880, "Blade 3D") + DEVICE( TRIDENT, TRIDENT_8400, "CyberBlade/i7") + DEVICE( TRIDENT, TRIDENT_8420, "CyberBlade/i7d") + DEVICE( TRIDENT, TRIDENT_8500, "CyberBlade/i1") ENDVENDOR() VENDOR( AI, "Acer Incorporated" ) @@ -151,11 +162,13 @@ DEVICE( MATROX, MATROX_MYS, "Mystique") DEVICE( MATROX, MATROX_MIL_2, "Millennium II") DEVICE( MATROX, MATROX_MIL_2_AGP,"Millennium II AGP") - DEVICE( MATROX, MATROX_G200_PCI,"G200 PCI") - DEVICE( MATROX, MATROX_G200_AGP,"G200 AGP") DEVICE( MATROX, MATROX_MGA_IMP, "MGA Impression") DEVICE( MATROX, MATROX_G100_MM, "G100 multi monitor") DEVICE( MATROX, MATROX_G100_AGP,"G100 AGP") + DEVICE( MATROX, MATROX_G200_PCI,"G200 PCI") + DEVICE( MATROX, MATROX_G200_AGP,"G200 AGP") + DEVICE( MATROX, MATROX_G400, "G400") + DEVICE( MATROX, MATROX_VIA, "Corona / Meteor-II") ENDVENDOR() VENDOR( CT, "Chips & Technologies" ) @@ -185,15 +198,20 @@ DEVICE( SI, SI_ACPI, "ACPI") DEVICE( SI, SI_5597_VGA, "5597/5598 VGA") DEVICE( SI, SI_6205, "6205") - DEVICE( SI, SI_501, "85C501") DEVICE( SI, SI_496, "85C496") + DEVICE( SI, SI_501, "85C501") + DEVICE( SI, SI_530, "530 Host") DEVICE( SI, SI_601, "85C601") + DEVICE( SI, SI_620, "620 Host") DEVICE( SI, SI_5107, "5107") DEVICE( SI, SI_5511, "85C5511") - DEVICE( SI, SI_5513, "85C5513") + DEVICE( SI, SI_5513, "85C5513 IDE") DEVICE( SI, SI_5571, "5571") DEVICE( SI, SI_5591, "5591/5592 Host") DEVICE( SI, SI_5597, "5597/5598 Host") + DEVICE( SI, SI_5600, "5600 Host") + DEVICE( SI, SI_6306, "3D-AGP 6306 VGA") + DEVICE( SI, SI_6326, "3D-AGP 6326 VGA") DEVICE( SI, SI_7001, "7001 USB") ENDVENDOR() @@ -251,6 +269,7 @@ VENDOR( WINBOND2, "Winbond" ) DEVICE( WINBOND2, WINBOND2_89C940,"NE2000-PCI") + DEVICE( WINBOND2, WINBOND2_89C940F, "W89C940F") ENDVENDOR() VENDOR( MOTOROLA, "Motorola" ) @@ -475,6 +494,12 @@ ENDVENDOR() VENDOR( NVIDIA, "NVidia" ) + DEVICE( NVIDIA, NVIDIA_TNT, "Riva TNT") + DEVICE( NVIDIA, NVIDIA_TNT2, "Riva TNT2") + DEVICE( NVIDIA, NVIDIA_UTNT2, "Riva TNT2 (Ultra)") + DEVICE( NVIDIA, NVIDIA_VTNT2, "Riva TNT2 (Vanta)") + DEVICE( NVIDIA, NVIDIA_UVTNT2, "Riva TNT2 (Ultra Vanta)") + DEVICE( NVIDIA, NVIDIA_ITNT2, "Riva TNT2 (Integrated)") ENDVENDOR() VENDOR( IMS, "IMS" ) @@ -499,6 +524,7 @@ VENDOR( INTERG, "Intergraphics" ) DEVICE( INTERG, INTERG_1680, "IGA-1680") DEVICE( INTERG, INTERG_1682, "IGA-1682") + DEVICE( INTERG, INTERG_2000, "CyberPro 2000") ENDVENDOR() VENDOR( REALTEK, "Realtek" ) @@ -517,7 +543,8 @@ ENDVENDOR() VENDOR( TTI, "Triones Technologies, Inc." ) - DEVICE( TTI, TTI_HPT343, "HPT343") + DEVICE( TTI, TTI_HPT343, "HPT343 IDE UltraDMA/33") + DEVICE( TTI, TTI_HPT366, "HPT366 IDE UltraDMA/66") ENDVENDOR() VENDOR( VIA, "VIA Technologies" ) @@ -528,13 +555,21 @@ DEVICE( VIA, VIA_82C585, "VT 82C585 Apollo VP1/VPX") DEVICE( VIA, VIA_82C586_0, "VT 82C586 Apollo ISA") DEVICE( VIA, VIA_82C595, "VT 82C595 Apollo VP2") + DEVICE( VIA, VIA_82C596, "VT 82C596 Apollo Mobile") DEVICE( VIA, VIA_82C597_0, "VT 82C597 Apollo VP3") DEVICE( VIA, VIA_82C598_0, "VT 82C598 Apollo MVP3") + DEVICE( VIA, VIA_82C680, "VT 82C680 Apollo P6") + DEVICE( VIA, VIA_82C686, "VT 82C686 Apollo Super") + DEVICE( VIA, VIA_82C691, "VT 82C691 Apollo Pro") + DEVICE( VIA, VIA_82C693, "VT 82C693 Apollo Pro Plus") DEVICE( VIA, VIA_82C926, "VT 82C926 Amazon") DEVICE( VIA, VIA_82C416, "VT 82C416MV") DEVICE( VIA, VIA_82C595_97, "VT 82C595 Apollo VP2/97") DEVICE( VIA, VIA_82C586_2, "VT 82C586 Apollo USB") DEVICE( VIA, VIA_82C586_3, "VT 82C586B Apollo ACPI") + DEVICE( VIA, VIA_82C686_4, "VT 82C686 Apollo Super ACPI") + DEVICE( VIA, VIA_82C686_5, "VT 82C686 Apollo Super AC97/Audio") + DEVICE( VIA, VIA_82C686_6, "VT 82C686 Apollo Super AC97/Modem") DEVICE( VIA, VIA_86C100A, "VT 86C100A") DEVICE( VIA, VIA_82C597_1, "VT 82C597 Apollo VP3 AGP") DEVICE( VIA, VIA_82C598_1, "VT 82C598 Apollo MVP3 AGP") @@ -764,6 +799,10 @@ DEVICE( OPTIBASE, OPTIBASE_VQUEST,"VideoQuest") ENDVENDOR() +VENDOR( ESS, "ESS Technologies" ) + DEVICE( ESS, ESS_AUDIOPCI, "3D Audio 1969") +ENDVENDOR() + VENDOR( SATSAGEM, "SatSagem" ) DEVICE( SATSAGEM, SATSAGEM_PCR2101,"PCR2101 DVB receiver") DEVICE( SATSAGEM, SATSAGEM_TELSATTURBO,"Telsat Turbo DVB") @@ -867,6 +906,7 @@ DEVICE( INTEL, INTEL_82596, "82596") DEVICE( INTEL, INTEL_82865, "82865") DEVICE( INTEL, INTEL_82557, "EtherExpress Pro100") + DEVICE( INTEL, INTEL_82559ER, "82559ER") DEVICE( INTEL, INTEL_82437, "82437") DEVICE( INTEL, INTEL_82371FB_0,"82371FB PIIX ISA") DEVICE( INTEL, INTEL_82371FB_1,"82371FB PIIX IDE") diff -u --recursive --new-file v2.3.15/linux/drivers/pci/names.c linux/drivers/pci/names.c --- v2.3.15/linux/drivers/pci/names.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/pci/names.c Tue Aug 31 11:02:26 1999 @@ -79,12 +79,12 @@ } /* Ok, found the vendor, but unknown device */ - sprintf(name, " PCI device %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name); + sprintf(name, "PCI device %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name); return; /* Full match */ match_device: { - char *n = name + sprintf(name, " %s %s", vendor_p->name, device_p->name); + char *n = name + sprintf(name, "%s %s", vendor_p->name, device_p->name); int nr = device_p->seen + 1; device_p->seen = nr; if (nr > 1) diff -u --recursive --new-file v2.3.15/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.15/linux/drivers/pci/pci.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/pci/pci.c Tue Aug 31 11:06:09 1999 @@ -9,7 +9,6 @@ * Copyright 1997 -- 1999 Martin Mares */ -#include #include #include #include @@ -18,6 +17,7 @@ #include #include +#include #include #undef DEBUG @@ -89,6 +89,65 @@ } +int +pci_find_capability(struct pci_dev *dev, int cap) +{ + u16 status; + u8 pos, id; + int ttl = 48; + + pci_read_config_word(dev, PCI_STATUS, &status); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos); + while (ttl-- && pos >= 0x40) { + pos &= ~3; + pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id); + if (id == 0xff) + break; + if (id == cap) + return pos; + pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos); + } + return 0; +} + + +/* + * For given resource region of given device, return the resource + * region of parent bus the given region is contained in or where + * it should be allocated from. + */ +struct resource * +pci_find_parent_resource(struct pci_dev *dev, struct resource *res) +{ + struct pci_bus *bus = dev->bus; + int i; + struct resource *best = NULL; + + while (bus) { + for(i=0; i<4; i++) { + struct resource *r = bus->resource[i]; + if (!r) + continue; + if (res->start && !(res->start >= r->start && res->end <= r->end)) + continue; /* Not contained */ + if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) + continue; /* Wrong type */ + if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) + return r; /* Exact match */ + if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH)) + best = r; /* Approximating prefetchable by non-prefetchable */ + } + if (best) + return best; + bus = bus->parent; + } + printk(KERN_ERR "PCI: Bug: Parent resource not found!\n"); + return NULL; +} + + /* * This interrupt-safe spinlock protects all accesses to PCI * configuration space. @@ -152,7 +211,7 @@ static inline unsigned int pci_resource_flags(unsigned int flags) { if (flags & PCI_BASE_ADDRESS_SPACE_IO) - return IORESOURCE_IO | flags; + return IORESOURCE_IO; if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) return IORESOURCE_MEM | IORESOURCE_PREFETCH; @@ -192,7 +251,7 @@ res->start = l & PCI_BASE_ADDRESS_IO_MASK; sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; } - res->end = res->start + sz; + res->end = res->start + (unsigned long) sz; res->flags |= (l & 0xf) | pci_resource_flags(l); if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { @@ -208,7 +267,7 @@ res->end = res->start + (((unsigned long) ~l) << 32); #else if (l) { - printk("PCI: Unable to handle 64-bit address for device %s\n", dev->name); + printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->name); res->start = 0; res->flags = 0; continue; @@ -228,17 +287,80 @@ res->flags = (l & PCI_ROM_ADDRESS_ENABLE) | IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE; res->start = l & PCI_ROM_ADDRESS_MASK; - res->end = res->start + (~(sz & PCI_ROM_ADDRESS_MASK)); + sz = ~(sz & PCI_ROM_ADDRESS_MASK); + res->end = res->start + (unsigned long) sz; } res->name = dev->name; } pci_write_config_word(dev, PCI_COMMAND, cmd); } +static void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child) +{ + u8 io_base_lo, io_limit_lo; + u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi; + u32 mem_base_hi, mem_limit_hi; + unsigned long base, limit; + struct resource *res; + int i; + + for(i=0; i<3; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + + res = child->resource[0]; + pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); + pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); + pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi); + pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi); + base = ((io_base_lo & PCI_IO_RANGE_MASK) << 8) | (io_base_hi << 16); + limit = ((io_limit_lo & PCI_IO_RANGE_MASK) << 8) | (io_limit_hi << 16); + if (base && base <= limit) { + res->flags |= (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; + res->start = base; + res->end = limit + 0xfff; + res->name = child->name; + } + + res = child->resource[1]; + pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); + base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; + if (base && base <= limit) { + res->flags |= (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; + res->start = base; + res->end = limit + 0xfffff; + res->name = child->name; + } + + res = child->resource[2]; + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi); + pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi); + base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; +#if BITS_PER_LONG == 64 + base |= ((long) mem_base_hi) << 32; + limit |= ((long) mem_limit_hi) << 32; +#else + if (mem_base_hi || mem_limit_hi) { + printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name); + return; + } +#endif + if (base && base <= limit) { + res->flags |= (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; + res->start = base; + res->end = limit + 0xfffff; + res->name = child->name; + } +} + static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) { unsigned int devfn, l, max, class; - unsigned char cmd, irq, tmp, hdr_type, is_multi = 0; + unsigned char irq, hdr_type, is_multi = 0; struct pci_dev *dev, **bus_last; struct pci_bus *child; struct pci_dev *dev_cache = NULL; @@ -274,15 +396,9 @@ dev_cache = NULL; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; + sprintf(dev->name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); pci_name_device(dev); - /* non-destructively determine if device can be a master: */ - pci_read_config_byte(dev, PCI_COMMAND, &cmd); - pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); - pci_read_config_byte(dev, PCI_COMMAND, &tmp); - dev->master = ((tmp & PCI_COMMAND_MASTER) != 0); - pci_write_config_byte(dev, PCI_COMMAND, cmd); - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); class >>= 8; /* upper 3 bytes */ dev->class = class; @@ -391,11 +507,13 @@ /* * Set up the primary, secondary and subordinate - * bus numbers. + * bus numbers. Read resource ranges behind the bridge. */ child->number = child->secondary = ++max; child->primary = bus->secondary; child->subordinate = 0xff; + sprintf(child->name, "PCI Bus #%02x", child->number); + pci_read_bridge_bases(dev, child); /* * Clear all status bits and turn off memory, * I/O and master enables. @@ -410,7 +528,8 @@ * do not modify the configuration, merely note it. */ pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); - if ((buses & 0xFFFFFF) != 0) + if ((buses & 0xFFFFFF) != 0 + && ! pcibios_assign_all_busses()) { unsigned int cmax; @@ -459,20 +578,42 @@ return max; } +static int __init pci_bus_exists(struct pci_bus *b, int nr) +{ + while (b) { + if (b->number == nr) + return 1; + if (b->children && pci_bus_exists(b->children, nr)) + return 1; + b = b->next; + } + return 0; +} + struct pci_bus * __init pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { - struct pci_bus *b; + struct pci_bus *b, **r; + + if (pci_bus_exists(pci_root, bus)) { + /* If we already got to this bus through a different bridge, ignore it */ + DBG("PCI: Bus %02x already known\n", bus); + return NULL; + } b = kmalloc(sizeof(*b), GFP_KERNEL); memset(b, 0, sizeof(*b)); - if (pci_root) { - b->next = pci_root->next; - pci_root->next = b; - } else - pci_root = b; + + /* Put the new bus at the end of the chain of busses. */ + r = &pci_root; + while (*r) + r = &(*r)->next; + *r = b; + b->number = b->secondary = bus; b->sysdata = sysdata; b->ops = ops; + b->resource[0] = &ioport_resource; + b->resource[1] = &iomem_resource; b->subordinate = pci_do_scan_bus(b); return b; } diff -u --recursive --new-file v2.3.15/linux/drivers/pci/proc.c linux/drivers/pci/proc.c --- v2.3.15/linux/drivers/pci/proc.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/pci/proc.c Tue Aug 31 11:08:00 1999 @@ -418,78 +418,33 @@ */ static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) { - unsigned int class_rev, bus, devfn; - unsigned short vendor, device, status; - unsigned char bist, latency, min_gnt, max_lat; + unsigned int class_rev; + unsigned char latency, min_gnt, max_lat; int reg, len = 0; - const char *str; - bus = dev->bus->number; - devfn = dev->devfn; - - pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev); - pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device); - pcibios_read_config_word (bus, devfn, PCI_STATUS, &status); - pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist); - pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency); - pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt); - pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat); - if (len + 80 > size) { + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt); + pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat); + if (len + 160 > size) return -1; - } len += sprintf(buf + len, " Bus %2d, device %3d, function %2d:\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - - if (len + 80 > size) { - return -1; - } - len += sprintf(buf + len, " %s: %s (rev %d).\n ", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + len += sprintf(buf + len, " %s: %s (rev %d).\n", pci_strclass(class_rev >> 8), dev->name, class_rev & 0xff); - switch (status & PCI_STATUS_DEVSEL_MASK) { - case PCI_STATUS_DEVSEL_FAST: str = "Fast devsel. "; break; - case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel. "; break; - case PCI_STATUS_DEVSEL_SLOW: str = "Slow devsel. "; break; - default: str = "Unknown devsel. "; - } - if (len + strlen(str) > size) { - return -1; - } - len += sprintf(buf + len, str); - - if (status & PCI_STATUS_FAST_BACK) { -# define fast_b2b_capable "Fast back-to-back capable. " - if (len + strlen(fast_b2b_capable) > size) { - return -1; - } - len += sprintf(buf + len, fast_b2b_capable); -# undef fast_b2b_capable - } - - if (bist & PCI_BIST_CAPABLE) { -# define BIST_capable "BIST capable. " - if (len + strlen(BIST_capable) > size) { - return -1; - } - len += sprintf(buf + len, BIST_capable); -# undef BIST_capable - } - if (dev->irq) { - if (len + 40 > size) { + if (len + 40 > size) return -1; - } - len += sprintf(buf + len, "IRQ %d. ", dev->irq); + len += sprintf(buf + len, " IRQ %d.\n", dev->irq); } - if (dev->master) { - if (len + 80 > size) { + if (latency || min_gnt || max_lat) { + if (len + 80 > size) return -1; - } - len += sprintf(buf + len, "Master Capable. "); + len += sprintf(buf + len, " Master Capable. "); if (latency) len += sprintf(buf + len, "Latency=%d. ", latency); else @@ -498,15 +453,15 @@ len += sprintf(buf + len, "Min Gnt=%d.", min_gnt); if (max_lat) len += sprintf(buf + len, "Max Lat=%d.", max_lat); + len += sprintf(buf + len, "\n"); } for (reg = 0; reg < 6; reg++) { struct resource *res = dev->resource + reg; unsigned long base, end, flags; - if (len + 40 > size) { + if (len + 40 > size) return -1; - } base = res->start; end = res->end; flags = res->flags; @@ -515,16 +470,15 @@ if (flags & PCI_BASE_ADDRESS_SPACE_IO) { len += sprintf(buf + len, - "\n I/O at 0x%lx [0x%lx].", + " I/O at 0x%lx [0x%lx].\n", base, end); } else { const char *pref, *type = "unknown"; - if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) { + if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) pref = "P"; - } else { + else pref = "Non-p"; - } switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { case PCI_BASE_ADDRESS_MEM_TYPE_32: type = "32 bit"; break; @@ -534,18 +488,23 @@ type = "64 bit"; break; } len += sprintf(buf + len, - "\n %srefetchable %s memory at " - "0x%lx [0x%lx].", pref, type, + " %srefetchable %s memory at " + "0x%lx [0x%lx].\n", pref, type, base, end); } } - len += sprintf(buf + len, "\n"); return len; } +static struct proc_dir_entry proc_old_pci = { + PROC_PCI, 3, "pci", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations +}; + /* * Return list of PCI devices as a character string for /proc/pci. * BUF is a buffer that is PAGE_SIZE bytes long. @@ -563,18 +522,15 @@ for (dev = pci_devices; dev; dev = dev->next) { nprinted = sprint_dev_config(dev, buf + len, size - len); if (nprinted < 0) { - return len + sprintf(buf + len, MSG); + len += sprintf(buf + len, MSG); + proc_old_pci.size = len; + return len; } len += nprinted; } + proc_old_pci.size = len; return len; } - -static struct proc_dir_entry proc_old_pci = { - PROC_PCI, 3, "pci", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations -}; static int __init pci_proc_init(void) { diff -u --recursive --new-file v2.3.15/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.3.15/linux/drivers/pci/quirks.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/pci/quirks.c Tue Aug 31 11:02:26 1999 @@ -58,6 +58,27 @@ /* + * S3 868 and 968 chips report region size equal to 32M, but they decode 64M. + * If it's needed, re-allocate the region. + */ + +static void __init quirk_s3_64M(struct pci_dev *dev) +{ + struct resource *r = &dev->resource[0]; + + if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) { + printk("PCI: Re-allocating buggy S3 card at %s: ", dev->name); + r->start = 0; + r->end = 0x3ffffff; + if (pcibios_assign_resource(dev, 0)) + printk("FAILED\n"); + else + printk("moved to %08lx\n", r->start); + } +} + + +/* * The main table of quirks. */ @@ -69,6 +90,8 @@ * quantity. */ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, { 0 } }; diff -u --recursive --new-file v2.3.15/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.3.15/linux/drivers/pnp/isapnp.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/pnp/isapnp.c Tue Aug 31 10:50:44 1999 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.15/linux/drivers/pnp/isapnp_proc.c linux/drivers/pnp/isapnp_proc.c --- v2.3.15/linux/drivers/pnp/isapnp_proc.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/pnp/isapnp_proc.c Thu Aug 26 14:22:51 1999 @@ -230,7 +230,7 @@ NULL /* permission */ }; -__initfunc(static int isapnp_proc_init(void)) +static int __init isapnp_proc_init(void) { struct proc_dir_entry *p; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c --- v2.3.15/linux/drivers/sbus/audio/amd7930.c Thu Jan 7 09:21:53 1999 +++ linux/drivers/sbus/audio/amd7930.c Tue Aug 31 11:25:33 1999 @@ -102,6 +102,11 @@ #include #include "amd7930.h" +static __u8 bilinear2mulaw(__u8 data); +static __u8 mulaw2bilinear(__u8 data); +static __u8 linear2mulaw(__u16 data); +static __u16 mulaw2linear(__u8 data); + #if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff #include "../../isdn/hisax/hisax.h" #include "../../isdn/hisax/isdnl1.h" @@ -146,8 +151,12 @@ /* Callback routine (and argument) when input is done on */ void (*input_callback)(); void * input_callback_arg; + + int input_format; + int output_format; }; + /* Private information we store for each amd7930 chip. */ struct amd7930_info { struct amd7930_channel D; @@ -173,6 +182,9 @@ int irq; volatile int ints_on; + /* Format type */ + int format_type; + /* Someone to signal when the ISDN LIU state changes */ int liu_state; @@ -489,10 +501,25 @@ if (channel->output_ptr && channel->output_count > 0) { /* Send the next byte and advance buffer pointer. */ - *io_reg = *(channel->output_ptr); + switch(channel->output_format) { + case AUDIO_ENCODING_ULAW: + case AUDIO_ENCODING_ALAW: + *io_reg = *(channel->output_ptr); + break; + case AUDIO_ENCODING_LINEAR8: + *io_reg = bilinear2mulaw(*(channel->output_ptr)); + break; + case AUDIO_ENCODING_LINEAR: + if (channel->output_count >= 2) { + *io_reg = linear2mulaw(*((__u16*)(channel->output_ptr))); + channel->output_ptr++; + channel->output_count--; + }; + }; channel->output_ptr++; channel->output_count--; + /* Done with the buffer? Notify the midlevel driver. */ if (channel->output_count == 0) { channel->output_ptr = NULL; @@ -510,7 +537,21 @@ if (channel->input_ptr && channel->input_count > 0) { /* Get the next byte and advance buffer pointer. */ - *(channel->input_ptr) = *io_reg; + switch(channel->input_format) { + case AUDIO_ENCODING_ULAW: + case AUDIO_ENCODING_ALAW: + *(channel->input_ptr) = *io_reg; + break; + case AUDIO_ENCODING_LINEAR8: + *(channel->input_ptr) = mulaw2bilinear(*io_reg); + break; + case AUDIO_ENCODING_LINEAR: + if (channel->input_count >= 2) { + *((__u16*)(channel->input_ptr)) = mulaw2linear(*io_reg); + channel->input_ptr++; + channel->input_count--; + } else *(channel->input_ptr) = 0; + }; channel->input_ptr++; channel->input_count--; @@ -565,6 +606,20 @@ static int amd7930_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) { + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + switch(MINOR(inode->i_rdev) & 0xf) { + case SPARCAUDIO_AUDIO_MINOR: + info->format_type = AUDIO_ENCODING_ULAW; + break; + case SPARCAUDIO_DSP_MINOR: + info->format_type = AUDIO_ENCODING_LINEAR8; + break; + case SPARCAUDIO_DSP16_MINOR: + info->format_type = AUDIO_ENCODING_LINEAR; + break; + }; + MOD_INC_USE_COUNT; return 0; } @@ -637,8 +692,9 @@ 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->output_format = info->format_type; + info->Baudio->output_callback = (void *) &sparcaudio_output_done; + info->Baudio->output_callback_arg = (void *) drv; info->Baudio->xmit_idle_char = 0; } } @@ -667,6 +723,7 @@ if (info->Baudio) { info->Baudio->input_ptr = buffer; info->Baudio->input_count = count; + info->Baudio->input_format = info->format_type; info->Baudio->input_callback = (void *) &sparcaudio_input_done; info->Baudio->input_callback_arg = (void *) drv; } @@ -700,7 +757,7 @@ static int amd7930_get_formats(struct sparcaudio_driver *drv) { - return (AFMT_MU_LAW | AFMT_A_LAW); + return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_S16_BE); } static int amd7930_get_output_ports(struct sparcaudio_driver *drv) @@ -850,9 +907,11 @@ static int amd7930_get_encoding(struct sparcaudio_driver *drv) { struct amd7930_info *info = (struct amd7930_info *)drv->private; - if (info->map.mmr1 & AM_MAP_MMR1_ALAW) + if ((info->map.mmr1 & AM_MAP_MMR1_ALAW) && + (info->format_type == AUDIO_ENCODING_ALAW)) return AUDIO_ENCODING_ALAW; - return AUDIO_ENCODING_ULAW; + + return info->format_type; } static int @@ -861,15 +920,20 @@ struct amd7930_info *info = (struct amd7930_info *)drv->private; switch (value) { - case AUDIO_ENCODING_ULAW: - info->map.mmr1 &= ~AM_MAP_MMR1_ALAW; - break; case AUDIO_ENCODING_ALAW: info->map.mmr1 |= AM_MAP_MMR1_ALAW; break; + case AUDIO_ENCODING_LINEAR8: + case AUDIO_ENCODING_LINEAR: + case AUDIO_ENCODING_ULAW: + info->map.mmr1 &= ~AM_MAP_MMR1_ALAW; + break; default: return -EINVAL; - } + }; + + info->format_type = value; + amd7930_update_map(drv); return 0; } @@ -1390,6 +1454,7 @@ Bchan->output_ptr = buffer; Bchan->output_count = count; + Bchan->output_format = AUDIO_ENCODING_ULAW; Bchan->output_callback = (void *) callback; Bchan->output_callback_arg = callback_arg; @@ -1418,6 +1483,7 @@ Bchan->input_ptr = buffer; Bchan->input_count = size; + Bchan->input_format = AUDIO_ENCODING_ULAW; Bchan->input_callback = (void *) callback; Bchan->input_callback_arg = callback_arg; @@ -1568,6 +1634,11 @@ info->rgain = 128; info->pgain = 200; info->mgain = 0; + info->format_type = AUDIO_ENCODING_ULAW; + info->Bb.input_format = AUDIO_ENCODING_ULAW; + info->Bb.output_format = AUDIO_ENCODING_ULAW; + info->Bc.input_format = AUDIO_ENCODING_ULAW; + info->Bc.output_format = AUDIO_ENCODING_ULAW; amd7930_update_map(drv); /* Register the amd7930 with the midlevel audio driver. */ @@ -1608,7 +1679,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int amd7930_init(void)) +int __init amd7930_init(void) #endif { struct linux_sbus *bus; @@ -1651,3 +1722,178 @@ } } #endif + + +/*************************************************************/ +/* Audio format conversion */ +/*************************************************************/ + +/* Translation tables */ + +static unsigned char ulaw[] = { + 3, 7, 11, 15, 19, 23, 27, 31, + 35, 39, 43, 47, 51, 55, 59, 63, + 66, 68, 70, 72, 74, 76, 78, 80, + 82, 84, 86, 88, 90, 92, 94, 96, + 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, + 113, 114, 114, 115, 115, 116, 116, 117, + 117, 118, 118, 119, 119, 120, 120, 121, + 121, 121, 122, 122, 122, 122, 123, 123, + 123, 123, 124, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 126, 126, 126, 126, + 126, 126, 126, 126, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 253, 249, 245, 241, 237, 233, 229, 225, + 221, 217, 213, 209, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 174, 172, 170, 168, 166, 164, 162, 160, + 158, 157, 156, 155, 154, 153, 152, 151, + 150, 149, 148, 147, 146, 145, 144, 143, + 143, 142, 142, 141, 141, 140, 140, 139, + 139, 138, 138, 137, 137, 136, 136, 135, + 135, 135, 134, 134, 134, 134, 133, 133, + 133, 133, 132, 132, 132, 132, 131, 131, + 131, 131, 131, 131, 130, 130, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128 +}; + +static __u8 mulaw2bilinear(__u8 data) +{ + return ulaw[data]; +} + + +static unsigned char linear[] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 2, 0, 0, 0, 3, + 0, 0, 0, 4, 0, 0, 0, 5, + 0, 0, 0, 6, 0, 0, 0, 7, + 0, 0, 0, 8, 0, 0, 0, 9, + 0, 0, 0, 10, 0, 0, 0, 11, + 0, 0, 0, 12, 0, 0, 0, 13, + 0, 0, 0, 14, 0, 0, 0, 15, + 0, 0, 16, 0, 17, 0, 18, 0, + 19, 0, 20, 0, 21, 0, 22, 0, + 23, 0, 24, 0, 25, 0, 26, 0, + 27, 0, 28, 0, 29, 0, 30, 0, + 31, 0, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, + 46, 48, 50, 52, 54, 56, 58, 60, + 62, 65, 69, 73, 77, 83, 91, 103, + 255, 231, 219, 211, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 174, 173, 172, 171, 170, 169, 168, 167, + 166, 165, 164, 163, 162, 161, 160, 0, + 159, 0, 158, 0, 157, 0, 156, 0, + 155, 0, 154, 0, 153, 0, 152, 0, + 151, 0, 150, 0, 149, 0, 148, 0, + 147, 0, 146, 0, 145, 0, 144, 0, + 0, 143, 0, 0, 0, 142, 0, 0, + 0, 141, 0, 0, 0, 140, 0, 0, + 0, 139, 0, 0, 0, 138, 0, 0, + 0, 137, 0, 0, 0, 136, 0, 0, + 0, 135, 0, 0, 0, 134, 0, 0, + 0, 133, 0, 0, 0, 132, 0, 0, + 0, 131, 0, 0, 0, 130, 0, 0, + 0, 129, 0, 0, 0, 128, 0, 0 +}; + +static __u8 bilinear2mulaw(__u8 data) +{ + return linear[data]; +} + +static int exp_lut[256] = { + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +#define BIAS 0x84 +#define CLIP 32635 + +#define SWAP_ENDIAN(x) ((x >> 8) | ((x & 0xff) << 8)) + +static __u8 linear2mulaw(__u16 data) +{ + static int sign, exponent, mantissa; + + /* not really sure, if swapping is ok - comment next line to disable it */ + data = SWAP_ENDIAN(data); + + sign = (data >> 8) & 0x80; + if (sign != 0) data = -data; + + if (data > CLIP) data = CLIP; + data += BIAS; + exponent = exp_lut[(data >> 7) & 0xFF]; + mantissa = (data >> (exponent + 3)) & 0x0F; + + return (~(sign | (exponent << 4) | mantissa)); +} + +static __u16 mulaw2linear(__u8 data) +{ + /* this conversion is not working */ + return data; +} + +#if 0 +#define INOUT(x,y) (((x) << 16) | (y)) +static int convert_audio(int in_format, int out_format, __u8* buffer, int count) +{ + static int i,sign,exponent; + static __u16 data; + + if (in_format == out_format) return count; + + switch(INOUT(in_format, out_format)) { + case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR8): + for (i = 0;i < count; i++) { + buffer[i] = ulaw[buffer[i]]; + }; + break; + case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR): + break; + case INOUT(AUDIO_ENCODING_LINEAR, AUDIO_ENCODING_ULAW): + /* buffer is two-byte => convert to first */ + for (i = 0; i < count/2; i++) { + data = ((__u16*)buffer)[i]; + sign = (data >> 8) & 0x80; + if (data > CLIP) data = CLIP; + data += BIAS; + exponent = exp_lut[(data >> 7) & 0xFF]; + buffer[i] = ~(sign | (exponent << 4) | + ((data >> (exponent + 3)) & 0x0F)); + }; + break; + case INOUT(AUDIO_ENCODING_LINEAR8, AUDIO_ENCODING_ULAW): + for (i = 0; i < count; i++) { + buffer[i] = linear[buffer[i]]; + }; + break; + default: + return 0; + }; + + return count; +} +#undef INOUT +#endif + +#undef BIAS +#undef CLIP +#undef SWAP_ENDIAN diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.3.15/linux/drivers/sbus/audio/audio.c Fri Aug 6 11:58:00 1999 +++ linux/drivers/sbus/audio/audio.c Tue Aug 31 11:25:33 1999 @@ -1,12 +1,12 @@ /* * drivers/sbus/audio/audio.c * - * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) - * Copyright (C) 1997,1998 Derrick J. Brashear (shadow@dementia.org) - * Copyright (C) 1997 Brent Baccala (baccala@freesoft.org) + * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * Copyright 1997,1998,1999 Derrick J. Brashear (shadow@dementia.org) + * Copyright 1997 Brent Baccala (baccala@freesoft.org) * * Mixer code adapted from code contributed by and - * Copyright (C) 1998 Michael Mraka (michael@fi.muni.cz) + * Copyright 1998 Michael Mraka (michael@fi.muni.cz) * and with fixes from Michael Shuey (shuey@ecn.purdue.edu) * The mixer code cheats; Sparc hardware doesn't generally allow independent * line control, and this fakes it badly. @@ -40,11 +40,17 @@ #undef __AUDIO_DEBUG #define __AUDIO_ERROR #undef __AUDIO_TRACE +#undef __AUDIO_OSSDEBUG #ifdef __AUDIO_DEBUG #define dprintk(x) printk x #else #define dprintk(x) #endif +#ifdef __AUDIO_OSSDEBUG +#define oprintk(x) printk x +#else +#define oprintk(x) +#endif #ifdef __AUDIO_ERROR #define eprintk(x) printk x #else @@ -117,10 +123,12 @@ * TODO: Make number of input/output buffers tunable parameters */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x202ff init_waitqueue_head(&drv->open_wait); init_waitqueue_head(&drv->output_write_wait); init_waitqueue_head(&drv->output_drain_wait); init_waitqueue_head(&drv->input_read_wait); +#endif drv->num_output_buffers = 8; drv->output_buffer_size = (4096 * 2); @@ -269,6 +277,7 @@ * If status & 2, a buffer was claimed for DMA and is still in use. * * The playing_count for non-DMA hardware should never be non-zero. + * Value of status for non-DMA hardware should always be 1. */ if (status & 1) { if (drv->playing_count) @@ -305,15 +314,16 @@ /* If we got back a buffer, see if anyone wants to write to it */ if ((status & 1) || ((drv->output_count + drv->playing_count) - < drv->num_output_buffers)) + < drv->num_output_buffers)) { wake_up_interruptible(&drv->output_write_wait); + } /* If the output queue is empty, shut down the driver. */ if ((drv->output_count < 1) && (drv->playing_count < 1)) { kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); /* Stop the lowlevel driver from outputing. */ - drv->ops->stop_output(drv); + /* drv->ops->stop_output(drv); Should not be necessary -- DJB 5/25/98 */ drv->output_active = 0; /* Wake up any waiting writers or syncers and return. */ @@ -638,8 +648,11 @@ { struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> SPARCAUDIO_DEVICE_SHIFT)]; - unsigned long i = 0, j = 0; - unsigned int k; + unsigned long i = 0, j = 0, l = 0, m = 0; + unsigned int k = 0; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + drv->mixer_modify_counter++; if(cmd == SOUND_MIXER_INFO) { audio_device_t tmp; @@ -651,9 +664,7 @@ memset(&info, 0, sizeof(info)); strncpy(info.id, tmp.name, sizeof(info.id)); strncpy(info.name, "Sparc Audio", sizeof(info.name)); - - /* XXX do this right... */ - info.modify_counter = 0; + info.modify_counter = drv->mixer_modify_counter; if(copy_to_user((char *)arg, &info, sizeof(info))) retval = -EFAULT; @@ -665,74 +676,130 @@ switch (cmd) { case SOUND_MIXER_WRITE_RECLEV: - case SOUND_MIXER_WRITE_MIC: - case SOUND_MIXER_WRITE_CD: - case SOUND_MIXER_WRITE_LINE: - case SOUND_MIXER_WRITE_IMIX: if(COPY_IN(arg, k)) return -EFAULT; - tprintk(("setting input volume (0x%x)", k)); + iretry: + oprintk(("setting input volume (0x%x)", k)); if (drv->ops->get_input_channels) j = drv->ops->get_input_channels(drv); - if (j == 1) { - i = s_to_m(k); - tprintk((" for mono to %d\n", i)); - if (drv->ops->set_input_volume) - drv->ops->set_input_volume(drv, i); - if (drv->ops->get_input_volume) - i = drv->ops->get_input_volume(drv); - i = m_to_s(i); - } else { - i = s_to_g(k); - j = s_to_b(k); - tprintk((" for stereo to to %d (bal %d)\n", i, j)); - if (drv->ops->set_input_volume) - drv->ops->set_input_volume(drv, i); - if (drv->ops->get_input_volume) - i = drv->ops->get_input_volume(drv); - if (drv->ops->set_input_balance) - drv->ops->set_input_balance(drv, j); - if (drv->ops->get_input_balance) - j = drv->ops->get_input_balance(drv); - i = b_to_s(i,j); - } + if (drv->ops->get_input_volume) + l = drv->ops->get_input_volume(drv); + if (drv->ops->get_input_balance) + m = drv->ops->get_input_balance(drv); + i = OSS_TO_GAIN(k); + j = OSS_TO_BAL(k); + oprintk((" for stereo to to %d (bal %d):", i, j)); + if (drv->ops->set_input_volume) + drv->ops->set_input_volume(drv, i); + if (drv->ops->set_input_balance) + drv->ops->set_input_balance(drv, j); + case SOUND_MIXER_READ_RECLEV: + if (drv->ops->get_input_volume) + i = drv->ops->get_input_volume(drv); + if (drv->ops->get_input_balance) + j = drv->ops->get_input_balance(drv); + oprintk((" got (0x%x)\n", BAL_TO_OSS(i,j))); + i = BAL_TO_OSS(i,j); + /* Try to be reasonable about volume changes */ + if ((cmd == SOUND_MIXER_WRITE_RECLEV) && (i != k) && + (i == BAL_TO_OSS(l,m))) + { + k += (OSS_LEFT(k) > OSS_LEFT(i)) ? 256 : -256; + k += (OSS_RIGHT(k) > OSS_RIGHT(i)) ? 1 : -1; + oprintk((" try 0x%x\n", k)); + goto iretry; + } return COPY_OUT(arg, i); - case SOUND_MIXER_WRITE_PCM: case SOUND_MIXER_WRITE_VOLUME: - case SOUND_MIXER_WRITE_SPEAKER: if(COPY_IN(arg, k)) return -EFAULT; - tprintk(("setting output volume (0x%x)", k)); + if (drv->ops->get_output_muted && drv->ops->set_output_muted) { + i = drv->ops->get_output_muted(drv); + if ((k == 0) || ((i == 0) && (OSS_LEFT(k) < 100))) + drv->ops->set_output_muted(drv, 1); + else + drv->ops->set_output_muted(drv, 0); + } + case SOUND_MIXER_READ_VOLUME: + if (drv->ops->get_output_muted) + i = drv->ops->get_output_muted(drv); + k = 0x6464 * (1 - i); + return COPY_OUT(arg, k); + case SOUND_MIXER_WRITE_PCM: + if(COPY_IN(arg, k)) + return -EFAULT; + oretry: + oprintk(("setting output volume (0x%x)\n", k)); if (drv->ops->get_output_channels) j = drv->ops->get_output_channels(drv); - if (j == 1) { - i = s_to_m(k); - tprintk((" for mono to %d\n", i)); - if (drv->ops->set_output_volume) - drv->ops->set_output_volume(drv, i); - if (drv->ops->get_output_volume) - i = drv->ops->get_output_volume(drv); - i = m_to_s(i); - } else { - i = s_to_g(k); - j = s_to_b(k); - tprintk((" for stereo to to %d (bal %d)\n", i, j)); - if (drv->ops->set_output_volume) - drv->ops->set_output_volume(drv, i); - if (drv->ops->get_output_volume) - i = drv->ops->get_output_volume(drv); - if (drv->ops->set_output_balance) - drv->ops->set_output_balance(drv, j); - if (drv->ops->get_output_balance) - j = drv->ops->get_output_balance(drv); - i = b_to_s(i,j); - } + if (drv->ops->get_output_volume) + l = drv->ops->get_output_volume(drv); + if (drv->ops->get_output_balance) + m = drv->ops->get_output_balance(drv); + oprintk((" started as (0x%x)\n", BAL_TO_OSS(l,m))); + i = OSS_TO_GAIN(k); + j = OSS_TO_BAL(k); + oprintk((" for stereo to %d (bal %d)\n", i, j)); + if (drv->ops->set_output_volume) + drv->ops->set_output_volume(drv, i); + if (drv->ops->set_output_balance) + drv->ops->set_output_balance(drv, j); + case SOUND_MIXER_READ_PCM: + if (drv->ops->get_output_volume) + i = drv->ops->get_output_volume(drv); + if (drv->ops->get_output_balance) + j = drv->ops->get_output_balance(drv); + oprintk((" got 0x%x\n", BAL_TO_OSS(i,j))); + i = BAL_TO_OSS(i,j); + /* Try to be reasonable about volume changes */ + if ((cmd == SOUND_MIXER_WRITE_PCM) && (i != k) && + (i == BAL_TO_OSS(l,m))) + { + k += (OSS_LEFT(k) > OSS_LEFT(i)) ? 256 : -256; + k += (OSS_RIGHT(k) > OSS_RIGHT(i)) ? 1 : -1; + oprintk((" try 0x%x\n", k)); + goto oretry; + } return COPY_OUT(arg, i); + case SOUND_MIXER_READ_SPEAKER: + k = OSS_PORT_AUDIO(drv, AUDIO_SPEAKER); + return COPY_OUT(arg, k); + case SOUND_MIXER_READ_MIC: + k = OSS_IPORT_AUDIO(drv, AUDIO_MICROPHONE); + return COPY_OUT(arg, k); + case SOUND_MIXER_READ_CD: + k = OSS_IPORT_AUDIO(drv, AUDIO_CD); + return COPY_OUT(arg, k); + case SOUND_MIXER_READ_LINE: + k = OSS_IPORT_AUDIO(drv, AUDIO_LINE_IN); + return COPY_OUT(arg, k); + case SOUND_MIXER_READ_LINE1: + k = OSS_PORT_AUDIO(drv, AUDIO_HEADPHONE); + return COPY_OUT(arg, k); + case SOUND_MIXER_READ_LINE2: + k = OSS_PORT_AUDIO(drv, AUDIO_LINE_OUT); + return COPY_OUT(arg, k); + + case SOUND_MIXER_WRITE_MIC: + case SOUND_MIXER_WRITE_CD: + case SOUND_MIXER_WRITE_LINE: + case SOUND_MIXER_WRITE_LINE1: + case SOUND_MIXER_WRITE_LINE2: + case SOUND_MIXER_WRITE_SPEAKER: + if(COPY_IN(arg, k)) + return -EFAULT; + OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_LINE, AUDIO_LINE_IN, k); + OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_MIC, AUDIO_MICROPHONE, k); + OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_CD, AUDIO_CD, k); + + OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_SPEAKER, AUDIO_SPEAKER, k); + OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE1, AUDIO_HEADPHONE, k); + OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE2, AUDIO_LINE_OUT, k); + return COPY_OUT(arg, k); case SOUND_MIXER_READ_RECSRC: if (drv->ops->get_input_port) i = drv->ops->get_input_port(drv); /* only one should ever be selected */ - if (i & AUDIO_ANALOG_LOOPBACK) j = SOUND_MASK_IMIX; /* ? */ if (i & AUDIO_CD) j = SOUND_MASK_CD; if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE; if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC; @@ -744,11 +811,10 @@ if(COPY_IN(arg, k)) return -EFAULT; /* only one should ever be selected */ - if (k & SOUND_MASK_IMIX) j = AUDIO_ANALOG_LOOPBACK; if (k & SOUND_MASK_CD) j = AUDIO_CD; if (k & SOUND_MASK_LINE) j = AUDIO_LINE_IN; if (k & SOUND_MASK_MIC) j = AUDIO_MICROPHONE; - tprintk(("setting inport to %d\n", j)); + oprintk(("setting inport to %d\n", j)); i = drv->ops->set_input_port(drv, j); return COPY_OUT(arg, i); @@ -759,7 +825,6 @@ if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; if (i & AUDIO_CD) j |= SOUND_MASK_CD; - if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ return COPY_OUT(arg, j); case SOUND_MIXER_READ_CAPS: /* mixer capabilities */ @@ -767,62 +832,27 @@ return COPY_OUT(arg, i); case SOUND_MIXER_READ_DEVMASK: /* all supported devices */ - case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */ if (drv->ops->get_input_ports) i = drv->ops->get_input_ports(drv); /* what do we support? */ if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; if (i & AUDIO_CD) j |= SOUND_MASK_CD; - if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ if (drv->ops->get_output_ports) i = drv->ops->get_output_ports(drv); if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER; - if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE; /* ? */ - if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE; - + if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE1; + if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE2; + j |= SOUND_MASK_VOLUME; - + + case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */ + j |= SOUND_MASK_PCM|SOUND_MASK_RECLEV; + if (cmd == SOUND_MIXER_READ_STEREODEVS) j &= ~(MONO_DEVICES); return COPY_OUT(arg, j); - case SOUND_MIXER_READ_PCM: - case SOUND_MIXER_READ_SPEAKER: - case SOUND_MIXER_READ_VOLUME: - if (drv->ops->get_output_channels) - j = drv->ops->get_output_channels(drv); - if (j == 1) { - if (drv->ops->get_output_volume) - i = drv->ops->get_output_volume(drv); - i = m_to_s(i); - } else { - if (drv->ops->get_output_volume) - i = drv->ops->get_output_volume(drv); - if (drv->ops->get_output_balance) - j = drv->ops->get_output_balance(drv); - i = b_to_s(i,j); - } - return COPY_OUT(arg, i); - case SOUND_MIXER_READ_RECLEV: - case SOUND_MIXER_READ_MIC: - case SOUND_MIXER_READ_CD: - case SOUND_MIXER_READ_LINE: - case SOUND_MIXER_READ_IMIX: - if (drv->ops->get_input_channels) - j = drv->ops->get_input_channels(drv); - if (j == 1) { - if (drv->ops->get_input_volume) - i = drv->ops->get_input_volume(drv); - i = m_to_s(i); - } else { - if (drv->ops->get_input_volume) - i = drv->ops->get_input_volume(drv); - if (drv->ops->get_input_balance) - j = drv->ops->get_input_balance(drv); - i = b_to_s(i,j); - } - return COPY_OUT(arg, i); default: return -EINVAL; } @@ -881,6 +911,10 @@ case SPARCAUDIO_DSP_MINOR: case SPARCAUDIO_AUDIO_MINOR: case SPARCAUDIO_AUDIOCTL_MINOR: + /* According to the OSS prog int, you can mixer ioctl /dev/dsp */ + if (_IOC_TYPE(cmd) == 'M') + return sparcaudio_mixer_ioctl(inode, + file, cmd, (unsigned int *)arg); switch (cmd) { case I_GETSIG: case I_GETSIG_SOLARIS: @@ -1997,6 +2031,36 @@ return -ENXIO; } + /* From the dbri driver: + * SunOS 5.5.1 audio(7I) man page says: + * "Upon the initial open() of the audio device, the driver + * will reset the data format of the device to the default + * state of 8-bit, 8KHz, mono u-law data." + * + * Of course, we only do this for /dev/audio, and assume + * OSS semantics on /dev/dsp + */ + + if ((minor & 0xf) == SPARCAUDIO_AUDIO_MINOR) { + if (file->f_mode & FMODE_WRITE) { + if (drv->ops->set_output_channels) + drv->ops->set_output_channels(drv, 1); + if (drv->ops->set_output_encoding) + drv->ops->set_output_encoding(drv, AUDIO_ENCODING_ULAW); + if (drv->ops->set_output_rate) + drv->ops->set_output_rate(drv, 8000); + } + + if (file->f_mode & FMODE_READ) { + if (drv->ops->set_input_channels) + drv->ops->set_input_channels(drv, 1); + if (drv->ops->set_input_encoding) + drv->ops->set_input_encoding(drv, AUDIO_ENCODING_ULAW); + if (drv->ops->set_input_rate) + drv->ops->set_input_rate(drv, 8000); + } + } + MOD_INC_USE_COUNT; /* Success! */ @@ -2098,7 +2162,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int sparcaudio_init(void)) +int __init sparcaudio_init(void) #endif { #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.3.15/linux/drivers/sbus/audio/cs4231.c Fri Aug 6 11:58:00 1999 +++ linux/drivers/sbus/audio/cs4231.c Tue Aug 31 11:25:33 1999 @@ -1,7 +1,9 @@ /* * drivers/sbus/audio/cs4231.c * - * Copyright 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu) + * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu) + * The 4231/ebus support was written by David Miller, who didn't bother + * crediting himself here, so I will. * * Based on the AMD7930 driver: * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) @@ -11,7 +13,7 @@ * * This was culled from the Crystal docs on the 4231a, and the addendum they * faxed me on the 4231. - * The APC DMA controller support unfortunately is not documented. Thanks, Sun + * The APC DMA controller support unfortunately is not documented. Thanks, Sun. */ #include @@ -36,6 +38,7 @@ #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff && defined(CONFIG_PCI) #define EB4231_SUPPORT #include +#include #endif #include @@ -69,15 +72,17 @@ static int cs4231_play_gain(struct sparcaudio_driver *drv, int value, unsigned char balance); static void cs4231_ready(struct sparcaudio_driver *drv); -static void cs4231_playintr(struct sparcaudio_driver *drv); +static void cs4231_playintr(struct sparcaudio_driver *drv, int); static int cs4231_recintr(struct sparcaudio_driver *drv); static int cs4231_output_muted(struct sparcaudio_driver *drv, int value); static void cs4231_pollinput(struct sparcaudio_driver *drv); -static void eb4231_pollinput(struct sparcaudio_driver *drv); static int cs4231_length_to_samplecount(struct audio_prinfo *thisdir, unsigned int length); static void cs4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int value); +#ifdef EB4231_SUPPORT +static void eb4231_pollinput(struct sparcaudio_driver *drv); +#endif #define CHIP_READY udelay(100); cs4231_ready(drv); udelay(1000); @@ -416,8 +421,8 @@ int tmp_bits; tprintk(("input channels %d\n", value)); - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c; - tmp_bits = cs4231_chip->regs->idr; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), (IAR_AUTOCAL_BEGIN | 0x1c)); + tmp_bits = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); switch (value) { case 1: CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), CS4231_MONO_ON(tmp_bits)); @@ -1228,11 +1233,20 @@ MOD_DEC_USE_COUNT; } -static void cs4231_playintr(struct sparcaudio_driver *drv) +static void cs4231_playintr(struct sparcaudio_driver *drv, int push) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int status = 0; + if (!push) { + if (!cs4231_chip->perchip_info.play.active) { + cs4231_chip->regs->dmapnva = cs4231_chip->output_next_dma_handle; + cs4231_chip->regs->dmapnc = cs4231_chip->output_next_dma_size; + } + sparcaudio_output_done(drv, 0); + return; + } + if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) cs4231_chip->playlen = cs4231_chip->output_size; @@ -1484,14 +1498,16 @@ cs4231_chip->perchip_info.play.active = 1; cs4231_chip->playing_count = 0; - cs4231_playintr(drv); if ((cs4231_chip->regs->dmacsr & APC_PPAUSE) || !(cs4231_chip->regs->dmacsr & APC_PDMA_READY)) { - cs4231_chip->regs->dmacsr &= ~(APC_XINT_PLAY | APC_PPAUSE); - cs4231_chip->regs->dmacsr |= APC_GENL_INT | APC_XINT_ENA | APC_XINT_PLAY - | APC_XINT_GENL | APC_XINT_PENA | APC_PDMA_READY; + cs4231_chip->regs->dmacsr &= ~APC_XINT_PLAY; + cs4231_chip->regs->dmacsr &= ~APC_PPAUSE; + + cs4231_playintr(drv, cs4231_chip->regs->dmapnva == 0 ? 1 : 0); + + cs4231_chip->regs->dmacsr |= APC_PLAY_SETUP; cs4231_enable_play(drv); - + cs4231_ready(drv); } } @@ -1522,7 +1538,6 @@ /* Else subsequent speed setting changes are ignored by the chip. */ cs4231_disable_play(drv); - cs4231_chip->perchip_info.play.active = 0; } #endif @@ -1545,14 +1560,9 @@ cs4231_chip->output_next_dma_handle = 0; cs4231_chip->output_next_dma_size = 0; } -#if 1 /* Not safe without shutting off the DMA controller as well. -DaveM */ +#if 0 /* Not safe without shutting off the DMA controller as well. -DaveM */ /* Else subsequent speed setting changes are ignored by the chip. */ - cs4231_chip->regs->dmacsr &= ~(APC_GENL_INT | APC_XINT_ENA | APC_XINT_PLAY - | APC_XINT_GENL | APC_PDMA_READY - | APC_XINT_PENA | APC_PPAUSE ); - printk("in cs4231_stop_output: 0x%x\n", cs4231_chip->regs->dmacsr); cs4231_disable_play(drv); - cs4231_chip->perchip_info.play.active = 0; #endif } @@ -1874,6 +1884,7 @@ } if((dummy & EBUS_DCSR_A_LOADED) == 0) { + cs4231_chip->perchip_info.play.active = 0; eb4231_playintr(drv); eb4231_getsamplecount(drv, cs4231_chip->playlen, 0); @@ -1898,11 +1909,14 @@ * if anything since we may be doing shared interrupts */ - if (dummy & (APC_PLAY_INT|APC_XINT_PNVA|APC_XINT_PLAY|APC_XINT_EMPT|APC_XINT_PEMP)) { + if (dummy & APC_PLAY_INT) { + if (dummy & APC_XINT_PNVA) { cs4231_chip->perchip_info.play.samples += cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), cs4231_chip->playlen); - cs4231_playintr(drv); + if (!(dummy & APC_XINT_EMPT)) + cs4231_playintr(drv, 1); + } /* Any other conditions we need worry about? */ } @@ -1927,15 +1941,13 @@ } if (dummy & APC_XINT_EMPT) { -#if 0 /* Call to stop_output from midlevel will get this */ if (!cs4231_chip->output_next_dma_handle) { cs4231_chip->regs->dmacsr |= (APC_PPAUSE); cs4231_disable_play(drv); cs4231_chip->perchip_info.play.error = 1; } cs4231_chip->perchip_info.play.active = 0; - cs4231_playintr(drv); -#endif + cs4231_playintr(drv, 0); cs4231_getsamplecount(drv, cs4231_chip->playlen, 0); } @@ -2213,16 +2225,9 @@ nregs = len / sizeof(regs[0]); - cs4231_chip->regs = (struct cs4231_regs *)edev->base_address[0]; - cs4231_chip->eb2p = (struct linux_ebus_dma *)edev->base_address[1]; - cs4231_chip->eb2c = (struct linux_ebus_dma *)edev->base_address[2]; - - request_region((unsigned long)cs4231_chip->regs, - sizeof(struct cs4231_regs), "cs4231 regs"); - request_region((unsigned long)cs4231_chip->eb2c, - sizeof(struct linux_ebus_dma), "4231 capture DMA"); - request_region((unsigned long)cs4231_chip->eb2p, - sizeof(struct linux_ebus_dma), "4231 playback DMA"); + cs4231_chip->regs = (struct cs4231_regs *)edev->resource[0].start; + cs4231_chip->eb2p = (struct linux_ebus_dma *)edev->resource[1].start; + cs4231_chip->eb2c = (struct linux_ebus_dma *)edev->resource[2].start; cs4231_chip->status |= CS_STATUS_IS_EBUS; @@ -2252,13 +2257,6 @@ free_irq(cs4231_chip->irq, drv); disable_irq(cs4231_chip->irq2); free_irq(cs4231_chip->irq2, drv); - - release_region((unsigned long)cs4231_chip->regs, - sizeof(struct cs4231_regs)); - release_region((unsigned long)cs4231_chip->eb2c, - sizeof(struct linux_ebus_dma)); - release_region((unsigned long)cs4231_chip->eb2p, - sizeof(struct linux_ebus_dma)); kfree(drv->private); return -EIO; } @@ -2292,7 +2290,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int cs4231_init(void)) +int __init cs4231_init(void) #endif { struct linux_sbus *sbus; @@ -2351,9 +2349,6 @@ #ifdef EB4231_SUPPORT disable_irq(cs4231_chip->irq2); free_irq(cs4231_chip->irq2, drv); - release_region((unsigned long)cs4231_chip->regs, sizeof(struct cs4231_regs)); - release_region((unsigned long)cs4231_chip->eb2c, sizeof(struct linux_ebus_dma)); - release_region((unsigned long)cs4231_chip->eb2p, sizeof(struct linux_ebus_dma)); #endif } kfree(drv->private); diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/audio/cs4231.h linux/drivers/sbus/audio/cs4231.h --- v2.3.15/linux/drivers/sbus/audio/cs4231.h Thu Apr 22 19:24:51 1999 +++ linux/drivers/sbus/audio/cs4231.h Tue Aug 31 11:25:33 1999 @@ -255,19 +255,19 @@ #define APC_XINT_PLAY 0x40000 /* Playback ext intr */ #define APC_XINT_CAPT 0x20000 /* Capture ext intr */ #define APC_XINT_GENL 0x10000 /* Error ext intr */ -#define APC_XINT_EMPT 0x8000 /* Pipe empty interrupt */ -#define APC_XINT_PEMP 0x4000 /* Play pipe empty */ +#define APC_XINT_EMPT 0x8000 /* Pipe empty interrupt (0 write to pva) */ +#define APC_XINT_PEMP 0x4000 /* Play pipe empty (pva and pnva not set) */ #define APC_XINT_PNVA 0x2000 /* Playback NVA dirty */ #define APC_XINT_PENA 0x1000 /* play pipe empty Int enable */ #define APC_XINT_COVF 0x800 /* Cap data dropped on floor */ #define APC_XINT_CNVA 0x400 /* Capture NVA dirty */ -#define APC_XINT_CEMP 0x200 /* Capture pipe empty interrupt */ +#define APC_XINT_CEMP 0x200 /* Capture pipe empty (cva and cnva not set) */ #define APC_XINT_CENA 0x100 /* Cap. pipe empty int enable */ #define APC_PPAUSE 0x80 /* Pause the play DMA */ #define APC_CPAUSE 0x40 /* Pause the capture DMA */ #define APC_CDC_RESET 0x20 /* CODEC RESET */ -#define APC_PDMA_READY 0x08 /* Play DMA Go */ -#define APC_CDMA_READY 0x04 /* Capture DMA Go */ +#define APC_PDMA_READY 0x08 /* Play DMA Go */ +#define APC_CDMA_READY 0x04 /* Capture DMA Go */ #define APC_CHIP_RESET 0x01 /* Reset the chip */ #define APC_INIT_SETUP (APC_CDMA_READY | APC_PDMA_READY | APC_XINT_ENA | APC_XINT_PLAY | APC_XINT_GENL | APC_INT_PENDING | APC_PLAY_INT | APC_CAPT_INT | APC_GENL_INT) diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c --- v2.3.15/linux/drivers/sbus/audio/dbri.c Thu Jun 17 01:08:50 1999 +++ linux/drivers/sbus/audio/dbri.c Tue Aug 31 11:25:33 1999 @@ -1907,19 +1907,11 @@ { MOD_INC_USE_COUNT; - /* SunOS 5.5.1 audio(7I) man page says: - * "Upon the initial open() of the audio device, the driver - * will reset the data format of the device to the default - * state of 8-bit, 8KHz, mono u-law data." - * - * I've also taken the liberty of setting half gain and + /* + * I've taken the liberty of setting half gain and * mid balance, to put the codec in a known state. */ - dbri_set_output_channels(drv, 1); - dbri_set_output_encoding(drv, AUDIO_ENCODING_ULAW); - dbri_set_output_rate(drv, 8000); - dbri_set_output_balance(drv, AUDIO_MID_BALANCE); dbri_set_output_volume(drv, AUDIO_MAX_GAIN/2); @@ -2162,7 +2154,6 @@ int hdlcmode, u_char xmit_idle_char) { struct dbri *dbri; - int val; if (dev >= num_drivers || chan > 1) { return -1; @@ -2356,7 +2347,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int dbri_init(void)) +int __init dbri_init(void) #endif { struct linux_sbus *bus; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/audio/dmy.c linux/drivers/sbus/audio/dmy.c --- v2.3.15/linux/drivers/sbus/audio/dmy.c Fri Apr 16 08:20:23 1999 +++ linux/drivers/sbus/audio/dmy.c Tue Aug 31 11:25:33 1999 @@ -643,7 +643,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int dummy_init(void)) +int __init dummy_init(void) #endif { num_drivers = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in --- v2.3.15/linux/drivers/sbus/char/Config.in Wed Jun 9 14:44:25 1999 +++ linux/drivers/sbus/char/Config.in Tue Aug 31 11:25:33 1999 @@ -9,7 +9,7 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP + tristate 'Bidirectional parallel port support (obsolete)' CONFIG_SUN_BPP tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c --- v2.3.15/linux/drivers/sbus/char/aurora.c Wed Jun 30 11:24:54 1999 +++ linux/drivers/sbus/char/aurora.c Tue Aug 31 11:30:48 1999 @@ -1327,7 +1327,7 @@ bp->r[chip]->r[CD180_MSVR]=port->MSVR;/* auto drops DTR */ } sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c --- v2.3.15/linux/drivers/sbus/char/bpp.c Fri Aug 6 11:58:00 1999 +++ linux/drivers/sbus/char/bpp.c Tue Aug 31 11:25:33 1999 @@ -1050,7 +1050,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int bpp_init(void)) +int __init bpp_init(void) #endif { int rc; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c --- v2.3.15/linux/drivers/sbus/char/envctrl.c Mon Nov 16 10:37:28 1998 +++ linux/drivers/sbus/char/envctrl.c Tue Aug 31 11:25:33 1999 @@ -1,17 +1,23 @@ -/* $Id: envctrl.c,v 1.9 1998/11/06 07:38:20 ecd Exp $ +/* $Id: envctrl.c,v 1.12 1999/08/31 06:58:04 davem Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) */ +#include #include #include + +#define __KERNEL_SYSCALLS__ #include +#include #include #include #include #include +#include #include +#include #include #include @@ -20,8 +26,16 @@ #define ENVCTRL_MINOR 162 -#undef DEBUG_BUS_SCAN +#undef U450_SUPPORT /* might fry you machine, careful here !!! */ + +#define DEBUG 1 +#define DEBUG_BUS_SCAN 1 + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) +#define schedule_timeout(a) { current->timeout = jiffies + (a); schedule(); } +#endif #define PCF8584_ADDRESS 0x55 @@ -61,13 +75,196 @@ #define I2C_WRITE 0x00 #define I2C_READ 0x01 -struct pcf8584_reg +/* PCF8584 register offsets */ +#define I2C_DATA 0x00UL +#define I2C_CSR 0x01UL + +struct i2c_device { + unsigned char addr; + struct i2c_device *next; +}; + +static unsigned long i2c_regs; +static struct i2c_device *i2c_devices; + +static int errno; + +#define MAX_TEMPERATURE 111 +#define MAX_FAN_SPEED 63 + + +/* + * UltraAXi constants. + */ +#define AXI_THERM_ADDR 0x9e +#define AXI_THERM_PORT_CPU 0 +#define AXI_THERM_PORT_MOD 1 +#define AXI_THERM_PORT_PCI 2 +#define AXI_THERM_PORT_DISK 3 + +#define AXI_FAN_ADDR 0x4e +#define AXI_FAN_PORT_FRONT 0 +#define AXI_FAN_PORT_BACK 1 + +#define AXI_PIO_ADDR 0x70 + +/* + * Ultra 450 constants. + */ +#define U450_FAN_ADDR 0x4e +#define U450_FAN_PORT_CPU 0 +#define U450_FAN_PORT_PS 1 + +#define U450_PIO_ADDR 0x70 +#define U450_TIMER_ADDR 0xa0 + +static unsigned char +axi_cpu_temp_table[256] = { - __volatile__ unsigned char data; - __volatile__ unsigned char csr; + 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x67, + 0x66, 0x65, 0x64, 0x63, 0x61, 0x60, 0x5f, 0x5e, + 0x5d, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x55, 0x54, + 0x53, 0x52, 0x50, 0x4f, 0x4e, 0x4d, 0x4c, 0x4a, + 0x49, 0x48, 0x47, 0x46, 0x44, 0x43, 0x42, 0x41, + 0x40, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, + 0x3a, 0x39, 0x39, 0x38, 0x38, 0x37, 0x37, 0x36, + 0x36, 0x35, 0x35, 0x34, 0x34, 0x33, 0x33, 0x32, + 0x32, 0x31, 0x31, 0x30, 0x30, 0x2f, 0x2f, 0x2e, + 0x2d, 0x2d, 0x2c, 0x2c, 0x2b, 0x2b, 0x2a, 0x2a, + 0x29, 0x29, 0x28, 0x28, 0x27, 0x27, 0x26, 0x26, + 0x25, 0x25, 0x24, 0x24, 0x23, 0x23, 0x22, 0x22, + 0x21, 0x21, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x19, 0x19, 0x19, 0x19, 0x18, + 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, + 0x15, 0x14, 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, + 0x13, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, + 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, + 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, + 0x04, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char +axi_mod_temp_table[256] = +{ + 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, + 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, + 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, + 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, + 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, + 0x39, 0x38, 0x38, 0x37, 0x37, 0x36, 0x36, 0x35, + 0x35, 0x35, 0x34, 0x34, 0x33, 0x33, 0x32, 0x32, + 0x31, 0x31, 0x30, 0x30, 0x2f, 0x2f, 0x2e, 0x2e, + 0x2e, 0x2d, 0x2d, 0x2c, 0x2c, 0x2b, 0x2b, 0x2a, + 0x2a, 0x29, 0x29, 0x29, 0x28, 0x28, 0x27, 0x27, + 0x26, 0x26, 0x25, 0x25, 0x24, 0x24, 0x23, 0x23, + 0x23, 0x22, 0x22, 0x21, 0x21, 0x20, 0x20, 0x1f, + 0x1f, 0x1e, 0x1e, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x19, 0x19, + 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, + 0x15, 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x12, + 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, + 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, + 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, + 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char +axi_fan_speeds[112] = +{ + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, + 0x22, 0x23, 0x25, 0x27, 0x28, 0x2a, 0x2b, 0x2d, + 0x2f, 0x30, 0x32, 0x33, 0x35, 0x37, 0x38, 0x3a, + 0x3b, 0x3d, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f }; -static struct pcf8584_reg *i2c; + +struct therm_regs { + u32 addr; + u32 port; + u32 min_temp; + u32 warning; + u32 shutdown; + u32 num; + u32 den; +}; + +struct thermistor { + char name[8]; + struct therm_regs regs; + unsigned char (*temperature) (struct thermistor *); + unsigned char (*fan_speed) (struct thermistor *); + struct thermistor *next; /* all thermistors */ + struct thermistor *chain; /* thermistors for one fan */ +}; + +struct fan_regs { + u32 addr; + u32 port; +}; + +struct fan { + char name[8]; + struct fan_regs regs; + int (*set_speed)(struct fan *, unsigned char value); + int (*check_failure)(struct fan *); + unsigned char value; + struct thermistor *monitor; + struct fan *next; +}; + + +struct environment { + struct thermistor *thermistors; + struct fan *fans; + unsigned char *cpu_temp_table; + unsigned char *cpu_fan_speeds; + unsigned char *ps_temp_table; + unsigned char *ps_fan_speeds; + void (*enable) (struct environment *); + void (*disable) (struct environment *); + void (*keep_alive) (struct environment *); + int interval; + pid_t kenvd_pid; + wait_queue_head_t kenvd_wait; + int terminate; +}; + + +static struct environment envctrl; #ifdef DEBUG_BUS_SCAN @@ -78,37 +275,42 @@ }; static struct i2c_addr_map devmap[] = { - { 0x38, 0x78, "PCF8574A" }, - { 0x20, 0x78, "TDA8444" }, - { 0x48, 0x78, "PCF8591" }, + { 0x70, 0xf0, "PCF8574A" }, + { 0x40, 0xf0, "TDA8444" }, + { 0x90, 0xf0, "PCF8591" }, + { 0xa0, 0xf0, "PCF8583" }, }; #define NR_DEVMAP (sizeof(devmap) / sizeof(devmap[0])) #endif static __inline__ int -PUT_DATA(__volatile__ unsigned char *data, char *buffer, int user) +PUT_DATA(unsigned long data, char *buffer, int user) { if (user) { - if (put_user(*data, buffer)) + u8 tmp = readb(data); + if (put_user(tmp, buffer)) return -EFAULT; } else { - *buffer = *data; + *buffer = readb(data); } return 0; } static __inline__ int -GET_DATA(__volatile__ unsigned char *data, const char *buffer, int user) +GET_DATA(unsigned long data, const char *buffer, int user) { if (user) { - if (get_user(*data, buffer)) + u8 tmp; + if (get_user(tmp, buffer)) return -EFAULT; + writeb(tmp, data); } else { - *data = *buffer; + writeb(*buffer, data); } return 0; } + static int i2c_read(unsigned char dev, char *buffer, int len, int user) { @@ -117,16 +319,17 @@ int error = -ENODEV; int count = 0; - i2c->data = (dev << 1) | I2C_READ; + writeb((dev & 0xfe) | I2C_READ, i2c_regs + I2C_DATA); - while (!(i2c->csr & STATUS_BB)) + while (!(readb(i2c_regs + I2C_CSR) & STATUS_BB)) udelay(1); - i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK; + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, + i2c_regs + I2C_CSR); do { udelay(1); - while ((stat = i2c->csr) & STATUS_PIN) + while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) udelay(1); if (stat & STATUS_LRB) @@ -142,29 +345,30 @@ break; if (count++ > 0) { - error = PUT_DATA(&i2c->data, buffer++, user); + error = PUT_DATA(i2c_regs + I2C_DATA, buffer++, user); if (error) break; } else - dummy = i2c->data; + dummy = readb(i2c_regs + I2C_DATA); } while (1); - i2c->csr = CONTROL_ES0; + writeb(CONTROL_ES0, i2c_regs + I2C_CSR); if (!error && (count++ > 0)) - error = PUT_DATA(&i2c->data, buffer++, user); + error = PUT_DATA(i2c_regs + I2C_DATA, buffer++, user); else - dummy = i2c->data; + dummy = readb(i2c_regs + I2C_DATA); udelay(1); - while ((stat = i2c->csr) & STATUS_PIN) + while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) udelay(1); stop: - i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK; + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK, + i2c_regs + I2C_CSR); if (!error && (count++ > 0)) - error = PUT_DATA(&i2c->data, buffer++, user); + error = PUT_DATA(i2c_regs + I2C_DATA, buffer++, user); else - dummy = i2c->data; + dummy = readb(i2c_regs + I2C_DATA); if (error) return error; @@ -176,20 +380,33 @@ { int error = -ENODEV; int count = 0; + int timeout; - while (!(i2c->csr & STATUS_BB)) + timeout = 1000000; + while (!(readb(i2c_regs + I2C_CSR) & STATUS_BB) && --timeout) udelay(1); + if (!timeout) { + printk("%s [%d]: TIMEOUT\n", __FUNCTION__, __LINE__); + return -ENODEV; + } - i2c->data = (dev << 1) | I2C_WRITE; - i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK; + writeb((dev & 0xfe) | I2C_WRITE, i2c_regs + I2C_DATA); + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, + i2c_regs + I2C_CSR); do { unsigned char stat; udelay(1); - while ((stat = i2c->csr) & STATUS_PIN) + timeout = 1000000; + while (((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) && --timeout) udelay(1); + if (!timeout) { + printk("%s [%d]: TIMEOUT\n", __FUNCTION__, __LINE__); + break; + } + if (stat & STATUS_LRB) break; @@ -197,32 +414,172 @@ if (count == len) break; - error = GET_DATA(&i2c->data, buffer++, user); + error = GET_DATA(i2c_regs + I2C_DATA, buffer++, user); if (error) break; count++; } while (1); - i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK; + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK, + i2c_regs + I2C_CSR); return error; } -__initfunc(static int i2c_scan_bus(void)) +#ifdef U450_SUPPORT +static int +i2c_write_read(unsigned char dev, char *outbuf, int outlen, + char *inbuf, int inlen, int user) +{ + unsigned char dummy; + unsigned char stat; + int error = -ENODEV; + int count = 0; + + while (!(readb(i2c_regs + I2C_CSR) & STATUS_BB)) + udelay(1); + + writeb((dev & 0xfe) | I2C_WRITE, i2c_regs + I2C_DATA); + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, + i2c_regs + I2C_CSR); + + do { + unsigned char stat; + + udelay(1); + while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) + udelay(1); + + if (stat & STATUS_LRB) + break; + + error = count; + if (count == outlen) + break; + + error = GET_DATA(i2c_regs + I2C_DATA, outbuf++, user); + if (error) + break; + + count++; + } while (1); + + if (error < 0) { + writeb(CONTROL_PIN | CONTROL_ES0 | + CONTROL_STO | CONTROL_ACK, i2c_regs + I2C_CSR); + return error; + } + + writeb(CONTROL_ES0 | CONTROL_STA | CONTROL_ACK, i2c_regs + I2C_CSR); + udelay(1); + writeb((dev & 0xfe) | I2C_READ, i2c_regs + I2C_DATA); + + count = 0; + do { + udelay(1); + while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) + udelay(1); + + if (stat & STATUS_LRB) + goto stop; + + error = 0; + if (inlen == 0) { + count--; + break; + } + + if (count == (inlen - 1)) + break; + + if (count++ > 0) { + error = PUT_DATA(i2c_regs + I2C_DATA, inbuf++, user); + if (error) + break; + } else + dummy = readb(i2c_regs + I2C_DATA); + } while (1); + + writeb(CONTROL_ES0, i2c_regs + I2C_CSR); + if (!error && (count++ > 0)) + error = PUT_DATA(i2c_regs + I2C_DATA, inbuf++, user); + else + dummy = readb(i2c_regs + I2C_DATA); + + udelay(1); + while ((stat = readb(i2c_regs + I2C_CSR)) & STATUS_PIN) + udelay(1); + +stop: + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK, + i2c_regs + I2C_CSR); + if (!error && (count++ > 0)) + error = PUT_DATA(i2c_regs + I2C_DATA, inbuf++, user); + else + dummy = readb(i2c_regs + I2C_DATA); + + if (error) + return error; + return count - 1; +} +#endif /* U450_SUPPORT */ + +static struct i2c_device * +i2c_find_device(unsigned char addr) +{ + struct i2c_device *dev; + + for (dev = i2c_devices; dev; dev = dev->next) { + if (dev->addr == addr) + return dev; + } + return 0; +} + +static void +i2c_free_devices(void) { - unsigned char dev; + struct i2c_device *dev; + + dev = i2c_devices; + while (dev) { + i2c_devices = dev->next; + kfree(dev); + dev = i2c_devices; + } +} + +static __init int i2c_scan_bus(void) +{ + struct i2c_device *dev, **last; + unsigned int addr; int count = 0; - for (dev = 1; dev < 128; dev++) { - if (i2c_read(dev, 0, 0, 0) == 0) { + last = &i2c_devices; + for (addr = 0; addr < 256; addr += 2) { + if (i2c_write(addr, 0, 0, 0) == 0) { #ifdef DEBUG_BUS_SCAN int i; for (i = 0; i < NR_DEVMAP; i++) - if ((dev & devmap[i].mask) == devmap[i].addr) + if ((addr & devmap[i].mask) == devmap[i].addr) break; - printk("envctrl: i2c device at %02x: %s\n", dev, + printk("envctrl: i2c device at %02x: %s\n", addr, i < NR_DEVMAP ? devmap[i].name : "unknown"); #endif + + dev = kmalloc(sizeof(struct i2c_device), GFP_KERNEL); + if (!dev) { + printk("i2c: can't alloc i2c_device\n"); + i2c_free_devices(); + return -ENOMEM; + } + memset(dev, 0, sizeof(struct i2c_device)); + + dev->addr = addr; + + *last = dev; + last = &dev->next; + count++; } } @@ -233,6 +590,872 @@ return 0; } + +static int +read_8591(unsigned char dev, unsigned char offset, unsigned char *value) +{ + unsigned char data[2]; + + data[0] = 0x40 | offset; + if (i2c_write(dev, data, 1, 0) != 1) + return -1; + if (i2c_read(dev, data, 2, 0) != 2) + return -1; + *value = data[1]; + return 0; +} + +static int +write_8444(unsigned char dev, unsigned char offset, unsigned char value) +{ + unsigned char data[2]; + + data[0] = offset; + data[1] = value; + if (i2c_write(dev, data, 2, 0) != 2) + return -1; + return 0; +} + +#ifdef U450_SUPPORT +static int +read_8583(unsigned char dev, unsigned char offset, unsigned char *value) +{ + unsigned char data; + + data = offset; + if (i2c_write_read(dev, &data, 1, &data, 1, 0) != 1) + return -1; + *value = data; + return 0; +} + +static int +write_8583(unsigned char dev, unsigned char offset, unsigned char value) +{ + unsigned char data[2]; + + data[0] = offset; + data[1] = value; + if (i2c_write(dev, data, 2, 0) != 2) + return -1; + return 0; +} +#endif /* U450_SUPPORT */ + +struct thermistor * +find_thermistor(const char *name, struct thermistor *from) +{ + int n; + + if (!from) + from = envctrl.thermistors; + else + from = from->next; + + n = strlen(name); + while (from && strncmp(from->name, name, n)) + from = from->next; + + return from; +} + +void +check_temperatures(struct environment *env) +{ + struct thermistor *t; + + for (t = env->thermistors; t; t = t->next) { +#ifdef DEBUG + printk("Thermistor `%s' [%02x:%d]: " + "%d C (%d C, %d C)\n", + t->name, t->regs.addr, t->regs.port, + t->temperature(t), t->regs.warning, t->regs.shutdown); +#endif + + /* + * Implement slow-down or shutdown here... + */ + } +} + +void +check_fan_speeds(struct environment *env) +{ + unsigned char speed, max; + struct thermistor *t; + struct fan *f; + + for (f = env->fans; f; f = f->next) { +#ifdef DEBUG + printk("Fan `%s' [%02x:%d]:", f->name, + f->regs.addr, f->regs.port); +#endif + max = 0; + for (t = f->monitor; t; t = t->chain) { + speed = t->fan_speed(t); + if (speed > max) + max = speed; +#ifdef DEBUG + printk(" %s:%02x", t->name, speed); +#endif + } + + f->set_speed(f, max); +#ifdef DEBUG + printk(" -> %02x\n", f->value); +#endif + } +} + +void +envctrl_fans_blast(struct environment *env) +{ + struct fan *f; + + for (f = env->fans; f; f = f->next) + f->set_speed(f, MAX_FAN_SPEED); +} + +int +kenvd(void *data) +{ + struct environment *env = data; + + MOD_INC_USE_COUNT; + lock_kernel(); + + env->kenvd_pid = current->pid; + + exit_files(current); + exit_mm(current); + + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, sigmask(SIGKILL)); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + current->session = 1; + current->pgrp = 1; + strcpy(current->comm, "kenvd"); + + if (env->enable) + env->enable(env); + + while (!env->terminate) { + + check_temperatures(env); + check_fan_speeds(env); + if (env->keep_alive) + env->keep_alive(env); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(env->interval * HZ); + + if (signal_pending(current)) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + break; + } + } + + if (env->disable) + env->disable(env); + + env->kenvd_pid = 0; + wake_up(&envctrl.kenvd_wait); + + MOD_DEC_USE_COUNT; + return 0; +} + +void +envctrl_stop(void) +{ + DECLARE_WAITQUEUE(wait, current); + struct thermistor *t; + struct fan *f; + pid_t pid; + + if (envctrl.kenvd_pid) { + pid = envctrl.kenvd_pid; + + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&envctrl.kenvd_wait, &wait); + + envctrl.terminate = 1; + kill_proc(pid, SIGKILL, 1); + + schedule(); + + remove_wait_queue(&envctrl.kenvd_wait, &wait); + current->state = TASK_RUNNING; + } + + t = envctrl.thermistors; + while (t) { + envctrl.thermistors = t->next; + kfree(t); + t = envctrl.thermistors; + } + + f = envctrl.fans; + while (f) { + envctrl.fans = f->next; + kfree(f); + f = envctrl.fans; + } + + if (envctrl.cpu_temp_table) + kfree(envctrl.cpu_temp_table); + + if (envctrl.cpu_fan_speeds) + kfree(envctrl.cpu_fan_speeds); + + if (envctrl.ps_temp_table) + kfree(envctrl.ps_temp_table); + + if (envctrl.ps_fan_speeds) + kfree(envctrl.ps_fan_speeds); +} + + +static unsigned char +axi_get_temperature(struct thermistor *t) +{ + unsigned char value; + + if (read_8591(t->regs.addr, t->regs.port, &value) < 0) + return MAX_TEMPERATURE; + if (t->regs.port == AXI_THERM_PORT_CPU) + return axi_cpu_temp_table[value]; + else + return axi_mod_temp_table[value]; +} + +static unsigned char +axi_get_fan_speed(struct thermistor *t) +{ + unsigned char temp; + + temp = t->temperature(t); + if (temp >= MAX_TEMPERATURE) + return MAX_FAN_SPEED; + + return axi_fan_speeds[temp]; +} + +static int +axi_set_fan_speed(struct fan *f, unsigned char value) +{ + if (value != f->value) { + if (write_8444(f->regs.addr, f->regs.port, value)) + return -1; + f->value = value; + } + return 0; +} + +static void +axi_toggle_i2c_int(struct environment *env) +{ + unsigned char data; + + if (i2c_read(AXI_PIO_ADDR, &data, 1, 0) != 1) + return; + + data &= ~(0x08); + if (i2c_write(AXI_PIO_ADDR, &data, 1, 0) != 1) + return; + mdelay(1); + + data |= 0x08; + if (i2c_write(AXI_PIO_ADDR, &data, 1, 0) != 1) + return; + mdelay(1); +} + + +static int +rasctrl_setup(int node) +{ + struct thermistor *t, **tlast; + struct fan *f, **flast; + char tmp[32]; + int monitor; + int shutdown; + int warning; + int i; + + prom_getstring(prom_root_node, "name", tmp, sizeof(tmp)); + if (strcmp(tmp, "SUNW,UltraSPARC-IIi-Engine")) { + printk("SUNW,rasctrl will work only on Ultra AXi\n"); + return -ENODEV; + } + + monitor = prom_getintdefault(node, "env-monitor", 0); + if (monitor == 0) + return -ENODEV; + + envctrl.interval = prom_getintdefault(node, "env-mon-interval", 60); + warning = prom_getintdefault(node, "warning-temp", 55); + shutdown = prom_getintdefault(node, "shutdown-temp", 58); + + tlast = &envctrl.thermistors; + for (i = 0; i < 4; i++) { + t = kmalloc(sizeof(struct thermistor), GFP_KERNEL); + if (!t) + goto out; + memset(t, 0, sizeof(struct thermistor)); + + t->regs.addr = AXI_THERM_ADDR; + t->regs.port = i; + t->regs.warning = warning; + t->regs.shutdown = shutdown; + + switch (i) { + case AXI_THERM_PORT_CPU: + sprintf(t->name, "%.7s", "CPU"); + break; + case AXI_THERM_PORT_MOD: + sprintf(t->name, "%.7s", "MOD"); + break; + case AXI_THERM_PORT_PCI: + sprintf(t->name, "%.7s", "PCI"); + break; + case AXI_THERM_PORT_DISK: + sprintf(t->name, "%.7s", "DISK"); + break; + } + + t->temperature = axi_get_temperature; + t->fan_speed = axi_get_fan_speed; + + if (!i2c_find_device(t->regs.addr)) { + printk("envctrl: `%s': i2c device %02x not found\n", + t->name, t->regs.addr); + kfree(t); + continue; + } + + *tlast = t; + tlast = &t->next; + } + + flast = &envctrl.fans; + for (i = 0; i < 2; i++) { + f = kmalloc(sizeof(struct fan), GFP_KERNEL); + if (!f) + goto out; + memset(f, 0, sizeof(struct fan)); + + f->regs.addr = AXI_FAN_ADDR; + f->regs.port = i; + + switch (i) { + case AXI_FAN_PORT_FRONT: + sprintf(f->name, "%.7s", "FRONT"); + t = NULL; + while ((t = find_thermistor("CPU", t))) { + t->chain = f->monitor; + f->monitor = t; + } + break; + case AXI_FAN_PORT_BACK: + sprintf(f->name, "%.7s", "BACK"); + t = NULL; + while ((t = find_thermistor("PCI", t))) { + t->chain = f->monitor; + f->monitor = t; + } + break; + } + + if (!f->monitor) { + kfree(f); + continue; + } + + if (!i2c_find_device(f->regs.addr)) { + printk("envctrl: `%s': i2c device %02x not found\n", + f->name, f->regs.addr); + kfree(f); + continue; + } + + *flast = f; + flast = &f->next; + + f->check_failure = NULL; + f->set_speed = axi_set_fan_speed; + } + + envctrl.enable = axi_toggle_i2c_int; + envctrl.disable = envctrl_fans_blast; + +#ifdef DEBUG + printk("Warn: %d C, Shutdown %d C, Interval %d s, Monitor %d\n", + warning, shutdown, envctrl.interval, monitor); +#endif + return 0; + +out: + envctrl_stop(); + return -ENODEV; +} + + +#ifdef U450_SUPPORT + +static unsigned char +envctrl_get_temperature(struct thermistor *t) +{ + unsigned char value; + + if (read_8591(t->regs.addr, t->regs.port, &value) < 0) + return MAX_TEMPERATURE; + if (!strncmp(t->name, "CPU", 3)) + return envctrl.cpu_temp_table[value]; + else + return envctrl.ps_temp_table[value]; +} + +static unsigned char +envctrl_get_fan_speed(struct thermistor *t) +{ + unsigned char temp; + + temp = t->temperature(t); + if (temp >= MAX_TEMPERATURE) + return MAX_FAN_SPEED; + + if (!strncmp(t->name, "CPU", 3)) + return envctrl.cpu_fan_speeds[temp]; + else + return envctrl.ps_fan_speeds[temp]; +} + +static int +envctrl_set_fan_speed(struct fan *f, unsigned char value) +{ + if (value != f->value) { + if (write_8444(f->regs.addr, f->regs.port, value)) + return -1; + f->value = value; + } + + return 0; +} + +static unsigned char u450_default_thermisters[] = +{ + /* CPU0 */ + 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x30, 0x00, + /* CPU1 */ + 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x31, 0x00, + /* CPU2 */ + 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x32, 0x00, + /* CPU3 */ + 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x43, 0x50, 0x55, 0x33, 0x00, + /* PS0 */ + 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5a, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x50, 0x53, 0x30, 0x00, + /* PS1 */ + 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5a, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x50, 0x53, 0x31, 0x00, + /* PS2 */ + 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5a, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x50, 0x53, 0x32, 0x00, + /* AMB */ + 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x42, 0x00 +}; + +static unsigned char u450_default_cpu_temp_factors[] = +{ + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x94, 0x92, 0x90, 0x8f, 0x8e, 0x8d, 0x8c, + 0x8a, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, + 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, + 0x79, 0x79, 0x78, 0x78, 0x77, 0x76, 0x75, 0x74, + 0x73, 0x72, 0x71, 0x70, 0x70, 0x6f, 0x6f, 0x6e, + 0x6e, 0x6e, 0x6d, 0x6d, 0x6c, 0x6b, 0x6a, 0x6a, + 0x69, 0x69, 0x68, 0x67, 0x66, 0x65, 0x65, 0x64, + 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61, 0x61, + 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5e, 0x5d, 0x5d, + 0x5c, 0x5c, 0x5b, 0x5b, 0x5b, 0x5a, 0x5a, 0x5a, + 0x59, 0x59, 0x58, 0x58, 0x57, 0x57, 0x56, 0x56, + 0x55, 0x55, 0x54, 0x54, 0x53, 0x53, 0x52, 0x52, + 0x52, 0x51, 0x51, 0x50, 0x50, 0x50, 0x50, 0x4f, + 0x4f, 0x4f, 0x4e, 0x4e, 0x4e, 0x4d, 0x4d, 0x4d, + 0x4c, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x4a, + 0x4a, 0x49, 0x49, 0x49, 0x48, 0x48, 0x48, 0x47, + 0x47, 0x47, 0x46, 0x46, 0x46, 0x46, 0x45, 0x45, + 0x45, 0x44, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, + 0x43, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, + 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, + 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, + 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 0x37, + 0x37, 0x37, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, + 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x33, 0x32, + 0x32, 0x32, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, + 0x2f, 0x2f, 0x2f, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, + 0x2d, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2a, + 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28 +}; + +static unsigned char u450_default_cpu_fan_speeds[] = +{ + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x2a, 0x2b, 0x2d, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f +}; + +static unsigned char u450_default_ps_temp_factors[] = +{ + 0x9a, 0x96, 0x82, 0x7d, 0x78, 0x73, 0x6e, 0x6b, + 0x69, 0x67, 0x64, 0x5f, 0x5a, 0x57, 0x55, 0x53, + 0x51, 0x50, 0x4e, 0x4d, 0x4c, 0x4b, 0x49, 0x47, + 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3f, + 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3a, 0x39, 0x39, + 0x38, 0x37, 0x37, 0x36, 0x35, 0x35, 0x34, 0x33, + 0x32, 0x32, 0x32, 0x31, 0x31, 0x30, 0x30, 0x2f, + 0x2f, 0x2e, 0x2e, 0x2d, 0x2d, 0x2c, 0x2c, 0x2b, + 0x2a, 0x2a, 0x29, 0x29, 0x28, 0x28, 0x27, 0x27, + 0x26, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x24, + 0x23, 0x23, 0x23, 0x22, 0x22, 0x22, 0x21, 0x21, + 0x21, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, + 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1c, 0x1c, 0x1c, + 0x1b, 0x1b, 0x1b, 0x1a, 0x1a, 0x1a, 0x19, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, + 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, + 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, + 0x10, 0x10, 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char u450_default_ps_fan_speeds[] = +{ + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x2b, 0x2d, 0x2e, 0x2f, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f +}; + +static void +u450_toggle_i2c_int(struct environment *env) +{ + unsigned char tmp[80]; + unsigned char data; + int i, n; + + write_8583(U450_TIMER_ADDR, 0, 0x84); + write_8583(U450_TIMER_ADDR, 8, 0x0a); + write_8583(U450_TIMER_ADDR, 7, 0x00); + write_8583(U450_TIMER_ADDR, 0, 0x04); + + n = sprintf(tmp, "envctrl: PCF8583:"); + for (i = 0; i < 16; i++) { + if (read_8583(U450_TIMER_ADDR, i, &data) < 0) { + printk("envctrl: error reading PCF8583\n"); + break; + } + n += sprintf(tmp+n, " %02x", data); + } + printk("%s\n", tmp); + +#if 1 + data = 0x70; + if (i2c_write(U450_PIO_ADDR, &data, 1, 0) != 1) + return; + mdelay(1); + + data = 0x78; + if (i2c_write(U450_PIO_ADDR, &data, 1, 0) != 1) + return; + mdelay(1); +#endif +} + +static void +u450_set_egg_timer(struct environment *env) +{ + unsigned char value; + +#if 0 + write_8583(U450_TIMER_ADDR, 0x00, 0x84); + read_8583(U450_TIMER_ADDR, 0x07, &value); + write_8583(U450_TIMER_ADDR, 0x07, 0x00); + write_8583(U450_TIMER_ADDR, 0x00, 0x04); +#else + read_8583(U450_TIMER_ADDR, 0x07, &value); + printk("envctrl: TIMER [%02x:07]: %02x\n", U450_TIMER_ADDR, value); + read_8583(U450_TIMER_ADDR, 0x00, &value); + printk("envctrl: TIMER [%02x:00]: %02x\n", U450_TIMER_ADDR, value); +#endif +} + +static int +envctrl_setup(int node) +{ + struct thermistor *t, **tlast; + struct fan *f, **flast; + unsigned char *tmp = NULL, *p; + int len, n, err; + int defaults = 0; + + len = prom_getproplen(node, "thermisters"); + if (len <= 0) { + printk("envctrl: no property `thermisters', using defaults\n"); + defaults++; + len = sizeof(u450_default_thermisters); + } + + tmp = (unsigned char *)kmalloc(len, GFP_KERNEL); + if (!tmp) { + printk("envctrl: can't allocate property buffer\n"); + return -ENODEV; + } + + if (defaults) { + memcpy(tmp, u450_default_thermisters, len); + } else { + err = prom_getproperty(node, "thermisters", tmp, len); + if (err < 0) { + printk("envctrl: error reading property `thermisters'\n"); + kfree(tmp); + return -ENODEV; + } + } + + p = tmp; + err = -ENOMEM; + + tlast = &envctrl.thermistors; + while (len > sizeof(struct therm_regs)) { + t = kmalloc(sizeof(struct thermistor), GFP_KERNEL); + if (!t) { + printk("envctrl: can't allocate thermistor struct\n"); + goto out; + } + memset(t, 0, sizeof(struct thermistor)); + + memcpy(&t->regs, p, sizeof(struct therm_regs)); + p += sizeof(struct therm_regs); + len -= sizeof(struct therm_regs); + + n = strlen(p) + 1; + strncpy(t->name, p, 7); + p += n; + len -= n; + + if (!i2c_find_device(t->regs.addr)) { + printk("envctrl: `%s': i2c device %02x not found\n", + t->name, t->regs.addr); + kfree(t); + continue; + } + + t->temperature = envctrl_get_temperature; + t->fan_speed = envctrl_get_fan_speed; + + *tlast = t; + tlast = &t->next; + } + + flast = &envctrl.fans; + for (n = 0; n < 2; n++) { + f = kmalloc(sizeof(struct fan), GFP_KERNEL); + if (!f) + goto out; + memset(f, 0, sizeof(struct fan)); + + f->regs.addr = U450_FAN_ADDR; + f->regs.port = n; + + switch (n) { + case U450_FAN_PORT_CPU: + sprintf(f->name, "%.7s", "CPU"); + t = NULL; + while ((t = find_thermistor("CPU", t))) { + t->chain = f->monitor; + f->monitor = t; + } + break; + case U450_FAN_PORT_PS: + sprintf(f->name, "%.7s", "PS"); + t = NULL; + while ((t = find_thermistor("PS", t))) { + t->chain = f->monitor; + f->monitor = t; + } + break; + } + + if (!f->monitor) { + kfree(f); + continue; + } + + if (!i2c_find_device(f->regs.addr)) { + printk("envctrl: `%s': i2c device %02x not found\n", + f->name, f->regs.addr); + kfree(f); + continue; + } + + *flast = f; + flast = &f->next; + + f->check_failure = NULL; + f->set_speed = envctrl_set_fan_speed; + } + + envctrl.cpu_temp_table = kmalloc(256, GFP_KERNEL); + if (!envctrl.cpu_temp_table) { + printk("envctrl: can't allocate temperature table\n"); + goto out; + } + if (defaults) { + memcpy(envctrl.cpu_temp_table, + u450_default_cpu_temp_factors, 256); + } else { + err = prom_getproperty(node, "cpu-temp-factors", + envctrl.cpu_temp_table, 256); + if (err) { + printk("envctrl: can't read `cpu-temp-factors'\n"); + goto out; + } + } + + envctrl.cpu_fan_speeds = kmalloc(112, GFP_KERNEL); + if (!envctrl.cpu_fan_speeds) { + printk("envctrl: can't allocate fan speed table\n"); + goto out; + } + if (defaults) { + memcpy(envctrl.cpu_fan_speeds, + u450_default_cpu_fan_speeds, 112); + } else { + err = prom_getproperty(node, "cpu-fan-speeds", + envctrl.cpu_fan_speeds, 112); + if (err) { + printk("envctrl: can't read `cpu-fan-speeds'\n"); + goto out; + } + } + + envctrl.ps_temp_table = kmalloc(256, GFP_KERNEL); + if (!envctrl.ps_temp_table) { + printk("envctrl: can't allocate temperature table\n"); + goto out; + } + if (defaults) { + memcpy(envctrl.ps_temp_table, + u450_default_ps_temp_factors, 256); + } else { + err = prom_getproperty(node, "ps-temp-factors", + envctrl.ps_temp_table, 256); + if (err) { + printk("envctrl: can't read `ps-temp-factors'\n"); + goto out; + } + } + + envctrl.ps_fan_speeds = kmalloc(112, GFP_KERNEL); + if (!envctrl.ps_fan_speeds) { + printk("envctrl: can't allocate fan speed table\n"); + goto out; + } + if (defaults) { + memcpy(envctrl.ps_fan_speeds, + u450_default_ps_fan_speeds, 112); + } else { + err = prom_getproperty(node, "ps-fan-speeds", + envctrl.ps_fan_speeds, 112); + if (err) { + printk("envctrl: can't read `ps-fan-speeds'\n"); + goto out; + } + } + + envctrl.enable = u450_toggle_i2c_int; + envctrl.keep_alive = u450_set_egg_timer; + envctrl.disable = envctrl_fans_blast; + envctrl.interval = 60; + + kfree(tmp); + return 0; + +out: + if (tmp) + kfree(tmp); + + envctrl_stop(); + return err; +} +#endif /* U450_SUPPORT */ + + + static loff_t envctrl_llseek(struct file *file, loff_t offset, int type) { @@ -266,7 +1489,9 @@ case I2CIOCSADR: if (get_user(addr, (int *)arg)) return -EFAULT; - data = addr & 0x7f; + data = addr & 0xfe; + if (!i2c_find_device(addr & 0xfe)) + return -ENODEV; file->private_data = (void *)data; break; case I2CIOCGADR: @@ -317,12 +1542,13 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int envctrl_init(void)) +int __init envctrl_init(void) #endif { #ifdef CONFIG_PCI struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; + pid_t pid; int err; for_each_ebus(ebus) { @@ -339,33 +1565,55 @@ return -ENODEV; } - if (check_region(edev->base_address[0], sizeof(*i2c))) { - printk("%s: Can't get region %lx, %d\n", - __FUNCTION__, edev->base_address[0], (int)sizeof(*i2c)); - return -ENODEV; - } - - i2c = (struct pcf8584_reg *)edev->base_address[0]; - - request_region((unsigned long)i2c, sizeof(*i2c), "i2c"); - - i2c->csr = CONTROL_PIN; - i2c->data = PCF8584_ADDRESS; - i2c->csr = CONTROL_PIN | CONTROL_ES1; - i2c->data = CLK_4_43 | BUS_CLK_90; - i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK; + i2c_regs = edev->resource[0].start; + writeb(CONTROL_PIN, i2c_regs + I2C_CSR); + writeb(PCF8584_ADDRESS >> 1, i2c_regs + I2C_DATA); + writeb(CONTROL_PIN | CONTROL_ES1, i2c_regs + I2C_CSR); + writeb(CLK_4_43 | BUS_CLK_90, i2c_regs + I2C_DATA); + writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, i2c_regs + I2C_CSR); mdelay(10); if (misc_register(&envctrl_dev)) { printk("%s: unable to get misc minor %d\n", __FUNCTION__, envctrl_dev.minor); - release_region((unsigned long)i2c, sizeof(*i2c)); + return -ENODEV; } err = i2c_scan_bus(); - if (err) - release_region((unsigned long)i2c, sizeof(*i2c)); - return err; + if (err) { + i2c_free_devices(); + misc_deregister(&envctrl_dev); + return err; + } + + memset(&envctrl, 0, sizeof(struct environment)); + + err = -ENODEV; + if (!strcmp(edev->prom_name, "SUNW,rasctrl")) + err = rasctrl_setup(edev->prom_node); +#ifdef U450_SUPPORT + else if (!strcmp(edev->prom_name, "SUNW,envctrl")) + err = envctrl_setup(edev->prom_node); +#endif + + if (err) { + envctrl_stop(); + i2c_free_devices(); + misc_deregister(&envctrl_dev); + return err; + } + + init_waitqueue_head(&envctrl.kenvd_wait); + + pid = kernel_thread(kenvd, (void *)&envctrl, CLONE_FS); + if (pid < 0) { + envctrl_stop(); + i2c_free_devices(); + misc_deregister(&envctrl_dev); + return -ENODEV; + } + + return 0; #else return -ENODEV; #endif @@ -375,7 +1623,8 @@ #ifdef MODULE void cleanup_module(void) { + envctrl_stop(); + i2c_free_devices(); misc_deregister(&envctrl_dev); - release_region((unsigned long)i2c, sizeof(*i2c)); } #endif diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c --- v2.3.15/linux/drivers/sbus/char/flash.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/sbus/char/flash.c Tue Aug 31 11:25:33 1999 @@ -1,4 +1,4 @@ -/* $Id: flash.c,v 1.11 1999/03/09 14:06:45 davem Exp $ +/* $Id: flash.c,v 1.13 1999/08/31 06:58:06 davem Exp $ * flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -22,11 +22,11 @@ #include static struct { - unsigned long read_base; - unsigned long write_base; - unsigned long read_size; - unsigned long write_size; - unsigned long busy; + unsigned long read_base; /* Physical read address */ + unsigned long write_base; /* Physical write address */ + unsigned long read_size; /* Size of read area */ + unsigned long write_size; /* Size of write area */ + unsigned long busy; /* In use? */ } flash; #define FLASH_MINOR 152 @@ -41,7 +41,7 @@ return -ENXIO; if (flash.read_base == flash.write_base) { - addr = __pa(flash.read_base); + addr = flash.read_base; size = flash.read_size; } else { if ((vma->vm_flags & VM_READ) && @@ -49,10 +49,10 @@ return -EINVAL; if (vma->vm_flags & VM_READ) { - addr = __pa(flash.read_base); + addr = flash.read_base; size = flash.read_size; } else if (vma->vm_flags & VM_WRITE) { - addr = __pa(flash.write_base); + addr = flash.write_base; size = flash.write_size; } else return -ENXIO; @@ -152,7 +152,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int flash_init(void)) +int __init flash_init(void) #endif { struct linux_sbus *sbus; @@ -167,20 +167,17 @@ 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_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | + (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); 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_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | + (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); 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_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) | + (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL); flash.write_size = sdev->reg_addrs[1].reg_size; } flash.busy = 0; @@ -207,14 +204,14 @@ nregs = len / sizeof(regs[0]); - flash.read_base = edev->base_address[0]; + flash.read_base = edev->resource[0].start; flash.read_size = regs[0].reg_size; if (nregs == 1) { - flash.write_base = edev->base_address[0]; + flash.write_base = edev->resource[0].start; flash.write_size = regs[0].reg_size; } else if (nregs == 2) { - flash.write_base = edev->base_address[1]; + flash.write_base = edev->resource[1].start; flash.write_size = regs[1].reg_size; } else { printk("flash: Strange number of regs %d\n", nregs); @@ -229,8 +226,8 @@ } printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n", - __pa(flash.read_base), flash.read_size, - __pa(flash.write_base), flash.write_size); + flash.read_base, flash.read_size, + flash.write_base, flash.write_size); err = misc_register(&flash_dev); if (err) { diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c --- v2.3.15/linux/drivers/sbus/char/openprom.c Mon Aug 24 13:14:09 1998 +++ linux/drivers/sbus/char/openprom.c Tue Aug 31 11:25:33 1999 @@ -577,7 +577,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int openprom_init(void)) +int __init openprom_init(void) #endif { unsigned long flags; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.3.15/linux/drivers/sbus/char/pcikbd.c Wed Jun 9 14:44:25 1999 +++ linux/drivers/sbus/char/pcikbd.c Tue Aug 31 11:30:48 1999 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.30 1999/06/03 15:02:36 davem Exp $ +/* $Id: pcikbd.c,v 1.32 1999/08/31 06:58:11 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -367,7 +367,7 @@ } -__initfunc(static int pcikbd_wait_for_input(void)) +static int __init pcikbd_wait_for_input(void) { int status, data; unsigned long start = jiffies; @@ -384,7 +384,7 @@ return -1; } -__initfunc(static void pcikbd_write(int address, int data)) +static void __init pcikbd_write(int address, int data) { int status; @@ -436,7 +436,7 @@ extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -__initfunc(static char *do_pcikbd_init_hw(void)) +static char * __init do_pcikbd_init_hw(void) { while(pcikbd_wait_for_input() != -1) @@ -479,7 +479,7 @@ return NULL; /* success */ } -__initfunc(void pcikbd_init_hw(void)) +void __init pcikbd_init_hw(void) { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -516,16 +516,7 @@ return; found: - pcikbd_iobase = child->base_address[0]; -#ifdef __sparc_v9__ - if (check_region(pcikbd_iobase, sizeof(unsigned long))) { - printk("8042: can't get region %lx, %d\n", - pcikbd_iobase, (int)sizeof(unsigned long)); - return; - } - request_region(pcikbd_iobase, sizeof(unsigned long), "8042 controller"); -#endif - + pcikbd_iobase = child->resource[0].start; pcikbd_irq = child->irqs[0]; if (request_irq(pcikbd_irq, &pcikbd_interrupt, SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) { @@ -559,17 +550,11 @@ if (!edev) pcibeep_iobase = (pcikbd_iobase & ~(0xffffff)) | 0x722000; else - pcibeep_iobase = edev->base_address[0]; + pcibeep_iobase = edev->resource[0].start; - 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)"); - } + kd_mksound = pcikbd_kd_mksound; + printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase, + edev ? "" : " (forced)"); #endif disable_irq(pcikbd_irq); @@ -711,7 +696,7 @@ * Write to device & handle returned ack */ -__initfunc(static int aux_write_ack(int val)) +static int __init aux_write_ack(int val) { aux_write_dev(val); poll_aux_status(); @@ -893,7 +878,7 @@ return -EAGAIN; add_wait_queue(&queue->proc_list, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (queue_empty() && !signal_pending(current)) { schedule(); goto repeat; @@ -943,7 +928,7 @@ PSMOUSE_MINOR, "ps2aux", &psaux_fops }; -__initfunc(int pcimouse_init(void)) +int __init pcimouse_init(void) { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -971,14 +956,7 @@ return -ENODEV; found: - pcimouse_iobase = child->base_address[0]; - /* - * Just in case the iobases for kbd/mouse ever differ... - */ - if (!check_region(pcimouse_iobase, sizeof(unsigned long))) - request_region(pcimouse_iobase, sizeof(unsigned long), - "8042 controller"); - + pcimouse_iobase = child->resource[0].start; pcimouse_irq = child->irqs[0]; } @@ -1027,7 +1005,7 @@ } -__initfunc(int ps2kbd_probe(unsigned long *memory_start)) +int __init ps2kbd_probe(unsigned long *memory_start) { int pnode, enode, node, dnode, xnode; int kbnode = 0, msnode = 0, bnode = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.3.15/linux/drivers/sbus/char/rtc.c Wed Jun 9 14:44:25 1999 +++ linux/drivers/sbus/char/rtc.c Tue Aug 31 11:25:33 1999 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.14 1999/06/03 15:02:38 davem Exp $ +/* $Id: rtc.c,v 1.17 1999/08/31 13:32:01 anton Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -29,12 +29,16 @@ /* Retrieve the current date and time from the real time clock. */ void get_rtc_time(struct rtc_time *t) { - register struct mostek48t02 *regs = mstk48t02_regs; + struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned long flags; + u8 tmp; save_flags(flags); cli(); - regs->creg |= MSTK_CREG_READ; + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); t->sec = MSTK_REG_SEC(regs); t->min = MSTK_REG_MIN(regs); @@ -44,19 +48,24 @@ t->month = MSTK_REG_MONTH(regs); t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); - regs->creg &= ~MSTK_CREG_READ; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); restore_flags(flags); } /* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { - register struct mostek48t02 *regs = mstk48t02_regs; + struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned long flags; + u8 tmp; save_flags(flags); cli(); - regs->creg |= MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); MSTK_SET_REG_SEC(regs,t->sec); MSTK_SET_REG_MIN(regs,t->min); @@ -66,7 +75,9 @@ MSTK_SET_REG_MONTH(regs,t->month); MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); - regs->creg &= ~MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); restore_flags(flags); } @@ -145,7 +156,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int rtc_sun_init(void)) +int __init rtc_sun_init(void) #endif { int error; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.3.15/linux/drivers/sbus/char/sab82532.c Sun Jul 4 09:53:12 1999 +++ linux/drivers/sbus/char/sab82532.c Tue Aug 31 11:30:48 1999 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.32 1999/07/03 08:57:41 davem Exp $ +/* $Id: sab82532.c,v 1.34 1999/08/31 06:58:16 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -174,7 +174,7 @@ static __inline__ void sab82532_tec_wait(struct sab82532 *info) { int count = SAB82532_MAX_TEC_DELAY; - while ((info->regs->r.star & SAB82532_STAR_TEC) && --count) + while ((readb(&info->regs->r.star) & SAB82532_STAR_TEC) && --count) udelay(1); } @@ -188,12 +188,13 @@ if (info->xmit_cnt <= 0) goto out; - if (!(info->regs->r.star & SAB82532_STAR_XFW)) + if (!(readb(&info->regs->r.star) & SAB82532_STAR_XFW)) goto out; info->all_sent = 0; for (i = 0; i < info->xmit_fifo_size; i++) { - info->regs->w.xfifo[i] = info->xmit_buf[info->xmit_tail++]; + u8 val = info->xmit_buf[info->xmit_tail++]; + writeb(val, &info->regs->w.xfifo[i]); info->xmit_tail &= (SERIAL_XMIT_SIZE - 1); info->icount.tx++; if (--info->xmit_cnt <= 0) @@ -201,9 +202,9 @@ } /* Issue a Transmit Frame command. */ - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_XF; + writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr); out: restore_flags(flags); @@ -228,7 +229,7 @@ save_flags(flags); cli(); info->interrupt_mask1 |= SAB82532_IMR1_XPR; - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); restore_flags(flags); } @@ -242,14 +243,14 @@ save_flags(flags); cli(); info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); sab82532_start_tx(info); restore_flags(flags); } static void batten_down_hatches(struct sab82532 *info) { - unsigned char saved_rfc; + unsigned char saved_rfc, tmp; /* If we are doing kadb, we call the debugger * else we just drop into the boot monitor. @@ -262,11 +263,13 @@ /* * 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) + saved_rfc = readb(&info->regs->r.rfc); + tmp = readb(&info->regs->rw.rfc); + tmp &= ~(SAB82532_RFC_RFDF); + writeb(tmp, &info->regs->rw.rfc); + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_RRES; + writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); #ifndef __sparc_v9__ if ((((unsigned long)linux_dbvec) >= DEBUG_FIRSTVADDR) && @@ -279,10 +282,10 @@ /* * Reset FIFO to character + status mode. */ - info->regs->w.rfc = saved_rfc; - if (info->regs->r.star & SAB82532_STAR_CEC) + writeb(saved_rfc, &info->regs->w.rfc); + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_RRES; + writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); } /* @@ -333,15 +336,15 @@ } if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { - count = info->regs->r.rbcl & (info->recv_fifo_size - 1); + count = readb(&info->regs->r.rbcl) & (info->recv_fifo_size - 1); free_fifo++; } /* Issue a FIFO read command in case we where idle. */ if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_RFRD; + writeb(SAB82532_CMDR_RFRD, &info->regs->w.cmdr); } if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { @@ -353,13 +356,13 @@ /* Read the FIFO. */ for (i = 0; i < count; i++) - buf[i] = info->regs->r.rfifo[i]; + buf[i] = readb(&info->regs->r.rfifo[i]); /* Issue Receive Message Complete command. */ if (free_fifo) { - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_RMC; + writeb(SAB82532_CMDR_RMC, &info->regs->w.cmdr); } if (info->is_console) @@ -410,26 +413,27 @@ if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) info->all_sent = 1; - if (!(info->regs->r.star & SAB82532_STAR_XFW)) + if (!(readb(&info->regs->r.star) & SAB82532_STAR_XFW)) return; if (!info->tty) { info->interrupt_mask1 |= SAB82532_IMR1_XPR; - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); return; } if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { info->interrupt_mask1 |= SAB82532_IMR1_XPR; - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); return; } /* Stuff 32 bytes into Transmit FIFO. */ info->all_sent = 0; for (i = 0; i < info->xmit_fifo_size; i++) { - info->regs->w.xfifo[i] = info->xmit_buf[info->xmit_tail++]; + u8 val = info->xmit_buf[info->xmit_tail++]; + writeb(val, &info->regs->w.xfifo[i]); info->xmit_tail &= (SERIAL_XMIT_SIZE - 1); info->icount.tx++; if (--info->xmit_cnt <= 0) @@ -437,9 +441,9 @@ } /* Issue a Transmit Frame command. */ - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_XF; + writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr); if (info->xmit_cnt < WAKEUP_CHARS) sab82532_sched_event(info, RS_EVENT_WRITE_WAKEUP); @@ -449,7 +453,7 @@ #endif if (info->xmit_cnt <= 0) { info->interrupt_mask1 |= SAB82532_IMR1_XPR; - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); } } @@ -490,7 +494,7 @@ check_modem: if (stat->sreg.isr0 & SAB82532_ISR0_CDSC) { - info->dcd = (info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : 1; + info->dcd = (readb(&info->regs->r.vstr) & SAB82532_VSTR_CD) ? 0 : 1; info->icount.dcd++; modem_change++; #if 0 @@ -498,15 +502,15 @@ #endif } if (stat->sreg.isr1 & SAB82532_ISR1_CSC) { - info->cts = info->regs->r.star & SAB82532_STAR_CTS; + info->cts = readb(&info->regs->r.star) & SAB82532_STAR_CTS; info->icount.cts++; modem_change++; #if 0 printk("CTS change: %d, CTS %s\n", info->icount.cts, info->cts ? "on" : "off"); #endif } - if ((info->regs->r.pvr & info->pvr_dsr_bit) ^ info->dsr) { - info->dsr = (info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : 1; + if ((readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ^ info->dsr) { + info->dsr = (readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ? 0 : 1; info->icount.dsr++; modem_change++; #if 0 @@ -548,7 +552,7 @@ sab82532_sched_event(info, RS_EVENT_WRITE_WAKEUP); info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); sab82532_start_tx(info); } } else { @@ -576,10 +580,10 @@ #endif status.stat = 0; - if (info->regs->r.gis & SAB82532_GIS_ISA0) - status.sreg.isr0 = info->regs->r.isr0; - if (info->regs->r.gis & SAB82532_GIS_ISA1) - status.sreg.isr1 = info->regs->r.isr1; + if (readb(&info->regs->r.gis) & SAB82532_GIS_ISA0) + status.sreg.isr0 = readb(&info->regs->r.isr0); + if (readb(&info->regs->r.gis) & SAB82532_GIS_ISA1) + status.sreg.isr1 = readb(&info->regs->r.isr1); #ifdef SERIAL_DEBUG_INTR printk("%d<%02x.%02x>", info->line, @@ -601,10 +605,10 @@ next: info = info->next; status.stat = 0; - if (info->regs->r.gis & SAB82532_GIS_ISB0) - status.sreg.isr0 = info->regs->r.isr0; - if (info->regs->r.gis & SAB82532_GIS_ISB1) - status.sreg.isr1 = info->regs->r.isr1; + if (readb(&info->regs->r.gis) & SAB82532_GIS_ISB0) + status.sreg.isr0 = readb(&info->regs->r.isr0); + if (readb(&info->regs->r.gis) & SAB82532_GIS_ISB1) + status.sreg.isr1 = readb(&info->regs->r.isr1); #ifdef SERIAL_DEBUG_INTR printk("%d<%02x.%02x>", info->line, @@ -690,63 +694,73 @@ static void sab82532_init_line(struct sab82532 *info) { - unsigned char stat; + unsigned char stat, tmp; /* * Wait for any commands or immediate characters */ - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); sab82532_tec_wait(info); /* * Clear the FIFO buffers. */ - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_RRES; - if (info->regs->r.star & SAB82532_STAR_CEC) + writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); - info->regs->w.cmdr = SAB82532_CMDR_XRES; + writeb(SAB82532_CMDR_XRES, &info->regs->w.cmdr); /* * Clear the interrupt registers. */ - stat = info->regs->r.isr0; - stat = info->regs->r.isr1; + stat = readb(&info->regs->r.isr0); + stat = readb(&info->regs->r.isr1); /* * Now, initialize the UART */ - info->regs->w.ccr0 = 0; /* power-down */ - info->regs->w.ccr0 = SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | - SAB82532_CCR0_SM_ASYNC; - info->regs->w.ccr1 = SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7; - info->regs->w.ccr2 = SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | - SAB82532_CCR2_TOE; - info->regs->w.ccr3 = 0; - info->regs->w.ccr4 = SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG; - info->regs->w.mode = SAB82532_MODE_RTS | SAB82532_MODE_FCTS | - SAB82532_MODE_RAC; - info->regs->w.rfc = SAB82532_RFC_DPS | SAB82532_RFC_RFDF; + writeb(0, &info->regs->w.ccr0); /* power-down */ + writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | + SAB82532_CCR0_SM_ASYNC, &info->regs->w.ccr0); + writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &info->regs->w.ccr1); + writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | + SAB82532_CCR2_TOE, &info->regs->w.ccr2); + writeb(0, &info->regs->w.ccr3); + writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &info->regs->w.ccr4); + writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS | + SAB82532_MODE_RAC, &info->regs->w.mode); + writeb(SAB82532_RFC_DPS | SAB82532_RFC_RFDF, &info->regs->w.rfc); switch (info->recv_fifo_size) { case 1: - info->regs->w.rfc |= SAB82532_RFC_RFTH_1; + tmp = readb(&info->regs->w.rfc); + tmp |= SAB82532_RFC_RFTH_1; + writeb(tmp, &info->regs->w.rfc); break; case 4: - info->regs->w.rfc |= SAB82532_RFC_RFTH_4; + tmp = readb(&info->regs->w.rfc); + tmp |= SAB82532_RFC_RFTH_4; + writeb(tmp, &info->regs->w.rfc); break; case 16: - info->regs->w.rfc |= SAB82532_RFC_RFTH_16; + tmp = readb(&info->regs->w.rfc); + tmp |= SAB82532_RFC_RFTH_16; + writeb(tmp, &info->regs->w.rfc); break; default: info->recv_fifo_size = 32; /* fall through */ case 32: - info->regs->w.rfc |= SAB82532_RFC_RFTH_32; + tmp = readb(&info->regs->w.rfc); + tmp |= SAB82532_RFC_RFTH_32; + writeb(tmp, &info->regs->w.rfc); break; } - info->regs->rw.ccr0 |= SAB82532_CCR0_PU; /* power-up */ + tmp = readb(&info->regs->rw.ccr0); + tmp |= SAB82532_CCR0_PU; /* power-up */ + writeb(tmp, &info->regs->rw.ccr0); } static int startup(struct sab82532 *info) @@ -788,9 +802,16 @@ sab82532_init_line(info); if (info->tty->termios->c_cflag & CBAUD) { - info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); - info->regs->rw.mode |= SAB82532_MODE_RTS; - info->regs->rw.pvr &= ~(info->pvr_dtr_bit); + u8 tmp; + + tmp = readb(&info->regs->rw.mode); + tmp &= ~(SAB82532_MODE_FRTS); + tmp |= SAB82532_MODE_RTS; + writeb(tmp, &info->regs->rw.mode); + + tmp = readb(&info->regs->rw.pvr); + tmp &= ~(info->pvr_dtr_bit); + writeb(tmp, &info->regs->rw.pvr); } /* @@ -798,11 +819,11 @@ */ info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | SAB82532_IMR0_PLLA; - info->regs->w.imr0 = info->interrupt_mask0; + writeb(info->interrupt_mask0, &info->regs->w.imr0); info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | SAB82532_IMR1_XON | SAB82532_IMR1_XPR; - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -829,6 +850,7 @@ static void shutdown(struct sab82532 *info) { unsigned long flags; + u8 tmp; if (!(info->flags & ASYNC_INITIALIZED)) return; @@ -853,12 +875,12 @@ 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; + writeb(info->interrupt_mask0, &info->regs->w.imr0); 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; + writeb(info->interrupt_mask1, &info->regs->w.imr1); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; @@ -868,24 +890,30 @@ /* Disable Interrupts */ info->interrupt_mask0 = 0xff; - info->regs->w.imr0 = info->interrupt_mask0; + writeb(info->interrupt_mask0, &info->regs->w.imr0); info->interrupt_mask1 = 0xff; - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { - info->regs->rw.mode |= SAB82532_MODE_FRTS; - info->regs->rw.mode |= SAB82532_MODE_RTS; - info->regs->rw.pvr |= info->pvr_dtr_bit; + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit, &info->regs->rw.pvr); } /* Disable break condition */ - info->regs->rw.dafo &= ~(SAB82532_DAFO_XBRK); + tmp = readb(&info->regs->rw.dafo); + tmp &= ~(SAB82532_DAFO_XBRK); + writeb(tmp, &info->regs->rw.dafo); /* Disable Receiver */ - info->regs->rw.mode &= ~(SAB82532_MODE_RAC); + tmp = readb(&info->regs->rw.mode); + tmp &= ~(SAB82532_MODE_RAC); + writeb(tmp, &info->regs->rw.mode); /* Power Down */ - info->regs->rw.ccr0 &= ~(SAB82532_CCR0_PU); + tmp = readb(&info->regs->rw.ccr0); + tmp &= ~(SAB82532_CCR0_PU); + writeb(tmp, &info->regs->rw.ccr0); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -999,23 +1027,23 @@ SAB82532_ISR0_TIME; save_flags(flags); cli(); - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); sab82532_tec_wait(info); - info->regs->w.dafo = dafo; - info->regs->w.bgr = ebrg & 0xff; - info->regs->rw.ccr2 &= ~(0xc0); - info->regs->rw.ccr2 |= (ebrg >> 2) & 0xc0; + writeb(dafo, &info->regs->w.dafo); + writeb(ebrg & 0xff, &info->regs->w.bgr); + writeb(readb(&info->regs->rw.ccr2) & ~(0xc0), &info->regs->rw.ccr2); + writeb(readb(&info->regs->rw.ccr2) | ((ebrg >> 2) & 0xc0), &info->regs->rw.ccr2); 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); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FCTS), &info->regs->rw.mode); } else { - info->regs->rw.mode |= SAB82532_MODE_RTS; - info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); - info->regs->rw.mode |= SAB82532_MODE_FCTS; + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FCTS, &info->regs->rw.mode); } - info->regs->rw.mode |= SAB82532_MODE_RAC; + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RAC, &info->regs->rw.mode); restore_flags(flags); } @@ -1056,7 +1084,7 @@ save_flags(flags); cli(); info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); sab82532_start_tx(info); restore_flags(flags); } @@ -1108,7 +1136,7 @@ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); - info->regs->w.imr1 = info->interrupt_mask1; + writeb(info->interrupt_mask1, &info->regs->w.imr1); sab82532_start_tx(info); } @@ -1167,7 +1195,7 @@ save_flags(flags); cli(); sab82532_tec_wait(info); - info->regs->w.tic = ch; + writeb(ch, &info->regs->w.tic); restore_flags(flags); } @@ -1196,7 +1224,7 @@ sab82532_send_xchar(tty, STOP_CHAR(tty)); #if 0 if (tty->termios->c_cflag & CRTSCTS) - info->regs->rw.mode |= SAB82532_MODE_RTS; + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); #endif } @@ -1222,7 +1250,7 @@ #if 0 if (tty->termios->c_cflag & CRTSCTS) - info->regs->rw.mode &= ~(SAB82532_MODE_RTS); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode); #endif } @@ -1286,13 +1314,13 @@ { unsigned int result; - result = ((info->regs->r.mode & SAB82532_MODE_RTS) ? - ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS) + result = ((readb(&info->regs->r.mode) & SAB82532_MODE_RTS) ? + ((readb(&info->regs->r.mode) & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS) : TIOCM_RTS) - | ((info->regs->r.pvr & info->pvr_dtr_bit) ? 0 : TIOCM_DTR) - | ((info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR) - | ((info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : TIOCM_DSR) - | ((info->regs->r.star & SAB82532_STAR_CTS) ? TIOCM_CTS : 0); + | ((readb(&info->regs->r.pvr) & info->pvr_dtr_bit) ? 0 : TIOCM_DTR) + | ((readb(&info->regs->r.vstr) & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR) + | ((readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ? 0 : TIOCM_DSR) + | ((readb(&info->regs->r.star) & SAB82532_STAR_CTS) ? TIOCM_CTS : 0); return put_user(result,value); } @@ -1308,34 +1336,34 @@ switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) { - info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); - info->regs->rw.mode |= SAB82532_MODE_RTS; + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); } if (arg & TIOCM_DTR) { - info->regs->rw.pvr &= ~(info->pvr_dtr_bit); + writeb(readb(&info->regs->rw.pvr) & ~(info->pvr_dtr_bit), &info->regs->rw.pvr); } break; case TIOCMBIC: if (arg & TIOCM_RTS) { - info->regs->rw.mode |= SAB82532_MODE_FRTS; - info->regs->rw.mode |= SAB82532_MODE_RTS; + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); } if (arg & TIOCM_DTR) { - info->regs->rw.pvr |= info->pvr_dtr_bit; + writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit, &info->regs->rw.pvr); } break; case TIOCMSET: if (arg & TIOCM_RTS) { - info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); - info->regs->rw.mode |= SAB82532_MODE_RTS; + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); } else { - info->regs->rw.mode |= SAB82532_MODE_FRTS; - info->regs->rw.mode |= SAB82532_MODE_RTS; + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); } if (arg & TIOCM_DTR) { - info->regs->rw.pvr &= ~(info->pvr_dtr_bit); + writeb(readb(&info->regs->rw.pvr) & ~(info->pvr_dtr_bit), &info->regs->rw.pvr); } else { - info->regs->rw.pvr |= info->pvr_dtr_bit; + writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit, &info->regs->rw.pvr); } break; default: @@ -1363,9 +1391,9 @@ #endif save_flags(flags); cli(); if (break_state == -1) - info->regs->rw.dafo |= SAB82532_DAFO_XBRK; + writeb(readb(&info->regs->rw.dafo) | SAB82532_DAFO_XBRK, &info->regs->rw.dafo); else - info->regs->rw.dafo &= ~(SAB82532_DAFO_XBRK); + writeb(readb(&info->regs->rw.dafo) & ~(SAB82532_DAFO_XBRK), &info->regs->rw.dafo); restore_flags(flags); } @@ -1496,19 +1524,19 @@ /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { - info->regs->w.mode |= SAB82532_MODE_FRTS; - info->regs->w.mode |= SAB82532_MODE_RTS; - info->regs->w.pvr |= info->pvr_dtr_bit; + writeb(readb(&info->regs->w.mode) | SAB82532_MODE_FRTS, &info->regs->w.mode); + writeb(readb(&info->regs->w.mode) | SAB82532_MODE_RTS, &info->regs->w.mode); + writeb(readb(&info->regs->w.pvr) | info->pvr_dtr_bit, &info->regs->w.pvr); } /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { - info->regs->w.pvr &= ~(info->pvr_dtr_bit); + writeb(readb(&info->regs->w.pvr) & ~(info->pvr_dtr_bit), &info->regs->w.pvr); if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) { - info->regs->w.mode &= ~(SAB82532_MODE_FRTS); - info->regs->w.mode |= SAB82532_MODE_RTS; + writeb(readb(&info->regs->w.mode) & ~(SAB82532_MODE_FRTS), &info->regs->w.mode); + writeb(readb(&info->regs->w.mode) | SAB82532_MODE_RTS, &info->regs->w.mode); } } @@ -1606,9 +1634,9 @@ * the receiver. */ info->interrupt_mask0 |= SAB82532_IMR0_TCD; - info->regs->w.imr0 = info->interrupt_mask0; + writeb(info->interrupt_mask0, &info->regs->w.imr0); #if 0 - info->regs->rw.mode &= ~(SAB82532_MODE_RAC); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RAC), &info->regs->rw.mode); #endif if (info->flags & ASYNC_INITIALIZED) { /* @@ -1797,12 +1825,12 @@ cli(); if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) { - info->regs->rw.pvr &= ~(info->pvr_dtr_bit); - info->regs->rw.mode |= SAB82532_MODE_FRTS; - info->regs->rw.mode &= ~(SAB82532_MODE_RTS); + writeb(readb(&info->regs->rw.pvr) & ~(info->pvr_dtr_bit), &info->regs->rw.pvr); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode); } sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -1817,7 +1845,7 @@ } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && !(info->flags & ASYNC_CLOSING) && - (do_clocal || !(info->regs->r.vstr & SAB82532_VSTR_CD))) + (do_clocal || !(readb(&info->regs->r.vstr) & SAB82532_VSTR_CD))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1825,7 +1853,7 @@ } #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttyS%d, count = %d, flags = %x, clocal = %d, vstr = %02x\n", - info->line, info->count, info->flags, do_clocal, info->regs->r.vstr); + info->line, info->count, info->flags, do_clocal, readb(&info->regs->r.vstr)); #endif schedule(); } @@ -1995,19 +2023,19 @@ stat_buf[0] = 0; stat_buf[1] = 0; save_flags(flags); cli(); - if (info->regs->r.mode & SAB82532_MODE_RTS) { - if (!(info->regs->r.mode & SAB82532_MODE_FRTS)) + if (readb(&info->regs->r.mode) & SAB82532_MODE_RTS) { + if (!(readb(&info->regs->r.mode) & SAB82532_MODE_FRTS)) strcat(stat_buf, "|RTS"); } else { strcat(stat_buf, "|RTS"); } - if (info->regs->r.star & SAB82532_STAR_CTS) + if (readb(&info->regs->r.star) & SAB82532_STAR_CTS) strcat(stat_buf, "|CTS"); - if (!(info->regs->r.pvr & info->pvr_dtr_bit)) + if (!(readb(&info->regs->r.pvr) & info->pvr_dtr_bit)) strcat(stat_buf, "|DTR"); - if (!(info->regs->r.pvr & info->pvr_dsr_bit)) + if (!(readb(&info->regs->r.pvr) & info->pvr_dsr_bit)) strcat(stat_buf, "|DSR"); - if (!(info->regs->r.vstr & SAB82532_VSTR_CD)) + if (!(readb(&info->regs->r.vstr) & SAB82532_VSTR_CD)) strcat(stat_buf, "|CD"); restore_flags(flags); @@ -2065,7 +2093,7 @@ * sab82532_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- */ -__initfunc(static int get_sab82532(unsigned long *memory_start)) +static int __init get_sab82532(unsigned long *memory_start) { struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; @@ -2083,7 +2111,7 @@ if (!edev) return -ENODEV; - regs = edev->base_address[0]; + regs = edev->resource[0].start; offset = sizeof(union sab82532_async_regs); for (i = 0; i < 2; i++) { @@ -2107,16 +2135,7 @@ sab->xmit_fifo_size = 32; sab->recv_fifo_size = 32; - if (check_region((unsigned long)sab->regs, - sizeof(union sab82532_async_regs))) { - kfree(sab); - continue; - } - request_region((unsigned long)sab->regs, - sizeof(union sab82532_async_regs), - "serial(sab82532)"); - - sab->regs->w.ipc = SAB82532_IPC_IC_ACT_LOW; + writeb(SAB82532_IPC_IC_ACT_LOW, &sab->regs->w.ipc); sab->next = sab82532_chain; sab82532_chain = sab; @@ -2126,16 +2145,15 @@ return 0; } -__initfunc(static void -sab82532_kgdb_hook(int line)) +static void __init sab82532_kgdb_hook(int line) { prom_printf("sab82532: kgdb support is not implemented, yet\n"); prom_halt(); } -__initfunc(static inline void show_serial_version(void)) +static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.32 $"; + char *revision = "$Revision: 1.34 $"; char *version, *p; version = strchr(revision, ' '); @@ -2148,7 +2166,7 @@ /* * The serial driver boot-time initialization code! */ -__initfunc(int sab82532_init(void)) +int __init sab82532_init(void) { struct sab82532 *info; int i; @@ -2220,9 +2238,9 @@ for (info = sab82532_chain, i = 0; info; info = info->next, i++) { info->magic = SERIAL_MAGIC; - info->type = info->regs->r.vstr & 0x0f; - info->regs->w.pcr = ~((1 << 1) | (1 << 2) | (1 << 4)); - info->regs->w.pim = 0xff; + info->type = readb(&info->regs->r.vstr) & 0x0f; + writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &info->regs->w.pcr); + writeb(0xff, &info->regs->w.pim); if (info->line == 0) { info->pvr_dsr_bit = (1 << 0); info->pvr_dtr_bit = (1 << 1); @@ -2230,9 +2248,9 @@ info->pvr_dsr_bit = (1 << 3); info->pvr_dtr_bit = (1 << 2); } - info->regs->w.pvr = (1 << 1) | (1 << 2) | (1 << 4); - info->regs->rw.mode |= SAB82532_MODE_FRTS; - info->regs->rw.mode |= SAB82532_MODE_RTS; + writeb((1 << 1) | (1 << 2) | (1 << 4), &info->regs->w.pvr); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); info->custom_divisor = 16; info->close_delay = 5*HZ/10; @@ -2276,7 +2294,7 @@ return 0; } -__initfunc(int sab82532_probe(unsigned long *memory_start)) +int __init sab82532_probe(unsigned long *memory_start) { int node, enode, snode; char model[32]; @@ -2340,7 +2358,6 @@ { unsigned long flags; int e1, e2; - int i; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ save_flags(flags); @@ -2357,12 +2374,6 @@ e2); restore_flags(flags); - for (i = 0; i < NR_PORTS; i++) { - struct sab82532 *info = (struct sab82532 *)sab82532_table[i]->driver_data; - if (info->type != PORT_UNKNOWN) - release_region((unsigned long)info->regs, - sizeof(union sab82532_async_regs)); - } if (tmp_buf) { free_page((unsigned long) tmp_buf); tmp_buf = NULL; @@ -2379,7 +2390,7 @@ save_flags(flags); cli(); sab82532_tec_wait(info); - info->regs->w.tic = c; + writeb(c, &info->regs->w.tic); restore_flags(flags); } @@ -2445,12 +2456,12 @@ */ info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; - info->regs->w.imr0 = info->interrupt_mask0; + writeb(info->interrupt_mask0, &info->regs->w.imr0); 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; + writeb(info->interrupt_mask1, &info->regs->w.imr1); printk("Console: ttyS%d (SAB82532)\n", info->line); @@ -2524,24 +2535,24 @@ info->flags |= ASYNC_CHECK_CD; save_flags(flags); cli(); - if (info->regs->r.star & SAB82532_STAR_CEC) + if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) udelay(1); sab82532_tec_wait(info); - info->regs->w.dafo = dafo; - info->regs->w.bgr = ebrg & 0xff; - info->regs->rw.ccr2 &= ~(0xc0); - info->regs->rw.ccr2 |= (ebrg >> 2) & 0xc0; + writeb(dafo, &info->regs->w.dafo); + writeb(ebrg & 0xff, &info->regs->w.bgr); + writeb(readb(&info->regs->rw.ccr2) & ~(0xc0), &info->regs->rw.ccr2); + writeb(readb(&info->regs->rw.ccr2) | ((ebrg >> 2) & 0xc0), &info->regs->rw.ccr2); 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); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FCTS), &info->regs->rw.mode); } else { - info->regs->rw.mode |= SAB82532_MODE_RTS; - info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); - info->regs->rw.mode |= SAB82532_MODE_FCTS; + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FCTS, &info->regs->rw.mode); } - info->regs->rw.pvr &= ~(info->pvr_dtr_bit); - info->regs->rw.mode |= SAB82532_MODE_RAC; + writeb(~(info->pvr_dtr_bit), &info->regs->rw.pvr); + writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RAC, &info->regs->rw.mode); restore_flags(flags); return 0; @@ -2561,7 +2572,7 @@ NULL }; -__initfunc(int sab82532_console_init(void)) +int __init sab82532_console_init(void) { extern int con_is_present(void); diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.3.15/linux/drivers/sbus/char/su.c Sun Jul 4 09:53:12 1999 +++ linux/drivers/sbus/char/su.c Tue Aug 31 11:30:48 1999 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.22 1999/07/03 08:57:43 davem Exp $ +/* $Id: su.c,v 1.25 1999/08/31 06:58:20 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -1965,7 +1965,7 @@ serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); restore_flags(flags); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -2212,9 +2212,9 @@ * number, and identifies which options were configured into this * driver. */ -__initfunc(static __inline__ void show_su_version(void)) +static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.22 $"; + char *revision = "$Revision: 1.25 $"; char *version, *p; version = strchr(revision, ' '); @@ -2251,11 +2251,7 @@ for_each_ebus(ebus) { for_each_ebusdev(dev, ebus) { if (dev->prom_node == info->port_node) { - info->port = dev->base_address[0]; -#ifdef __sparc_v9__ - if (check_region(info->port, 8)) - return; -#endif + info->port = dev->resource[0].start; info->irq = dev->irqs[0]; goto ebus_done; } @@ -2400,10 +2396,6 @@ sprintf(info->name, "su(%s)", su_typev[info->port_type]); -#ifdef __sparc_v9__ - request_region(info->port, 8, info->name); -#endif - /* * Reset the UART. */ @@ -2418,7 +2410,7 @@ /* * The serial driver boot-time initialization code! */ -__initfunc(int su_serial_init(void)) +int __init su_serial_init(void) { int i; struct su_struct *info; @@ -2516,7 +2508,7 @@ return 0; } -__initfunc(int su_kbd_ms_init(void)) +int __init su_kbd_ms_init(void) { int i; struct su_struct *info; @@ -2541,7 +2533,7 @@ if (info->type == PORT_UNKNOWN) continue; - printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n", + printk(KERN_INFO "%s at 0x%lx (irq = %s) is a %s\n", info->name, info->port, __irq_itoa(info->irq), uart_config[info->type].name); @@ -2559,7 +2551,7 @@ * of device tree. 'su' may be found under obio, ebus, isa and pci. * We walk over the tree and find them wherever PROM hides them. */ -__initfunc(void su_probe_any(struct su_probe_scan *t, int sunode)) +void __init su_probe_any(struct su_probe_scan *t, int sunode) { struct su_struct *info; int len; @@ -2590,7 +2582,7 @@ } } -__initfunc(int su_probe (unsigned long *memory_start)) +int __init su_probe (unsigned long *memory_start) { int node; int len; @@ -2792,7 +2784,7 @@ * - initialize the serial port * Return non-zero if we didn't find a serial port. */ -__initfunc(static int serial_console_setup(struct console *co, char *options)) +static int __init serial_console_setup(struct console *co, char *options) { struct su_struct *info; unsigned cval; @@ -2915,7 +2907,7 @@ /* * Register console. */ -__initfunc(int su_serial_console_init(void)) +int __init su_serial_console_init(void) { extern int con_is_present(void); diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.3.15/linux/drivers/sbus/char/sunkbd.c Mon Aug 2 22:07:16 1999 +++ linux/drivers/sbus/char/sunkbd.c Tue Aug 31 11:25:33 1999 @@ -1212,7 +1212,7 @@ extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -__initfunc(int sun_kbd_init(void)) +int __init sun_kbd_init(void) { int i, opt_node; struct kbd_struct kbd0; @@ -1502,7 +1502,7 @@ NULL, /* revalidate */ }; -__initfunc(void keyboard_zsinit(void (*put_char)(unsigned char))) +void __init keyboard_zsinit(void (*put_char)(unsigned char)) { int timeout = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.3.15/linux/drivers/sbus/char/sunmouse.c Mon Aug 2 22:07:16 1999 +++ linux/drivers/sbus/char/sunmouse.c Tue Aug 31 11:25:33 1999 @@ -69,7 +69,7 @@ unsigned char prev_state; /* Previous button state */ int delta_x; /* Current delta-x */ int delta_y; /* Current delta-y */ - int present; + int present; int ready; /* set if there if data is available */ int active; /* set if device is open */ int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */ @@ -170,11 +170,16 @@ static int ctr = 0; if(wait_for_synchron) { - if((c < 0x80) || (c > 0x87)) + if((c & ~0x0f) != 0x80) mouse_bogon_bytes++; else { - ctr = 0; - wait_for_synchron = 0; + if (c & 8) { + ctr = 2; + wait_for_synchron = 0; + } else { + ctr = 0; + wait_for_synchron = 0; + } } } else { ctr++; @@ -212,6 +217,11 @@ mouse_baud_detection(byte); if (!gen_events){ + if (((byte & ~0x0f) == 0x80) && (byte & 0x8)) { + /* Push dummy 4th and 5th byte for last txn */ + push_char(0x0); + push_char(0x0); + } push_char (byte); return; } @@ -220,7 +230,7 @@ * we are starting at byte zero in the transaction * protocol. */ - if(byte >= 0x80 && byte <= 0x87) + if((byte & ~0x0f) == 0x80) sunmouse.byte = 0; mvalue = (signed char) byte; @@ -234,6 +244,12 @@ ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"), ((sunmouse.button_state & 0x1) ? "DOWN" : "UP")); #endif + /* To deal with the Sparcbook 3 */ + if (byte & 0x8) { + sunmouse.byte += 2; + sunmouse.delta_y = 0; + sunmouse.delta_x = 0; + } sunmouse.byte++; return; case 1: @@ -492,7 +508,7 @@ SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops }; -__initfunc(int sun_mouse_init(void)) +int __init sun_mouse_init(void) { if (!sunmouse.present) return -ENODEV; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.3.15/linux/drivers/sbus/char/sunserial.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/sbus/char/sunserial.c Tue Aug 31 11:25:33 1999 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.68 1998/12/09 18:53:51 davem Exp $ +/* $Id: sunserial.c,v 1.69 1999/08/31 06:58:29 davem Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -20,13 +20,12 @@ int serial_console; -__initfunc(int con_is_present(void)) +int __init con_is_present(void) { return serial_console ? 0 : 1; } -__initfunc(static void -nop_rs_kgdb_hook(int channel)) +static void __init nop_rs_kgdb_hook(int channel) { printk("Oops: %s called\n", __FUNCTION__); } @@ -63,13 +62,12 @@ return err; } -__initfunc(void -rs_kgdb_hook(int channel)) +void __init rs_kgdb_hook(int channel) { rs_ops.rs_kgdb_hook(channel); } -__initfunc(long serial_console_init(long kmem_start, long kmem_end)) +long __init serial_console_init(long kmem_start, long kmem_end) { return kmem_start; } @@ -352,8 +350,7 @@ extern int ps2kbd_probe(unsigned long *); #endif -__initfunc(unsigned long -sun_serial_setup(unsigned long memory_start)) +unsigned long __init sun_serial_setup(unsigned long memory_start) { int ret = 1; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.3.15/linux/drivers/sbus/char/zs.c Mon Aug 2 22:07:16 1999 +++ linux/drivers/sbus/char/zs.c Tue Aug 31 11:30:48 1999 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.43 1999/07/17 06:03:58 zaitcev Exp $ +/* $Id: zs.c,v 1.44 1999/08/31 06:58:32 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1711,7 +1711,7 @@ if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) zs_rtsdtr(info, 1); sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) { #ifdef SERIAL_DEBUG_OPEN @@ -1844,7 +1844,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.43 $"; + char *revision = "$Revision: 1.44 $"; char *version, *p; version = strchr(revision, ' '); @@ -1862,8 +1862,7 @@ * we have a special version for sun4u. */ #ifdef __sparc_v9__ -__initfunc(static struct sun_zslayout * -get_zs(int chip)) +static struct sun_zslayout * __init get_zs(int chip) { unsigned int vaddr[2] = { 0, 0 }; unsigned long mapped_addr = 0; @@ -1971,8 +1970,7 @@ return (struct sun_zslayout *) (unsigned long) vaddr[0]; } #else /* !(__sparc_v9__) */ -__initfunc(static struct sun_zslayout * -get_zs(int chip)) +static struct sun_zslayout * __init get_zs(int chip) { struct linux_prom_irqs tmp_irq[2]; unsigned int paddr = 0; @@ -2112,7 +2110,7 @@ write_zsreg(zs_soft[channel].zs_channel, R13, ((brg >> 8) & 0xff)); } -__initfunc(int zs_probe (unsigned long *memory_start)) +int __init zs_probe (unsigned long *memory_start) { char *p; int node; @@ -2265,7 +2263,7 @@ restore_flags(flags); } -__initfunc(int zs_init(void)) +int __init zs_init(void) { int channel, brg, i; unsigned long flags; @@ -2534,8 +2532,7 @@ * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */ -__initfunc(static void -zs_kgdb_hook(int tty_num)) +static void __init zs_kgdb_hook(int tty_num) { int chip = 0; @@ -2647,8 +2644,7 @@ return MKDEV(TTY_MAJOR, 64 + con->index); } -__initfunc(static int -zs_console_setup(struct console *con, char *options)) +static int __init zs_console_setup(struct console *con, char *options) { struct sun_serial *info; int i, brg, baud; @@ -2729,8 +2725,7 @@ NULL }; -__initfunc(static int -zs_console_init(void)) +static int __init zs_console_init(void) { extern int con_is_present(void); diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c --- v2.3.15/linux/drivers/sbus/dvma.c Tue Jun 1 23:25:48 1999 +++ linux/drivers/sbus/dvma.c Tue Aug 31 11:25:33 1999 @@ -29,8 +29,7 @@ return; } -__initfunc(void -init_one_dvma(struct Linux_SBus_DMA *dma, int num_dma)) +void __init init_one_dvma(struct Linux_SBus_DMA *dma, int num_dma) { printk("dma%d: ", num_dma); @@ -75,8 +74,7 @@ } /* Probe this SBus DMA module(s) */ -__initfunc(void -dvma_init(struct linux_sbus *sbus)) +void __init dvma_init(struct linux_sbus *sbus) { struct linux_sbus_device *this_dev; struct Linux_SBus_DMA *dma; @@ -133,7 +131,7 @@ #include -__initfunc(void sun4_dvma_init(void)) +void __init sun4_dvma_init(void) { struct Linux_SBus_DMA *dma; struct Linux_SBus_DMA *dchain; diff -u --recursive --new-file v2.3.15/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c --- v2.3.15/linux/drivers/sbus/sbus.c Mon Aug 2 22:07:16 1999 +++ linux/drivers/sbus/sbus.c Tue Aug 31 11:25:33 1999 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.78 1999/07/23 02:00:27 davem Exp $ +/* $Id: sbus.c,v 1.79 1999/08/31 06:57:40 davem Exp $ * sbus.c: SBus support routines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -40,8 +40,7 @@ /* #define DEBUG_FILL */ -__initfunc(static void -fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev)) +static void __init fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev) { int grrr, len; unsigned long dev_base_addr, base; @@ -210,9 +209,9 @@ extern int aurora_init(void); #endif -__initfunc(static void -sbus_do_child_siblings(int start_node, struct linux_sbus_device *child, - struct linux_sbus *sbus)) +static void __init sbus_do_child_siblings(int start_node, + struct linux_sbus_device *child, + struct linux_sbus *sbus) { struct linux_sbus_device *this_dev = child; int this_node = start_node; @@ -240,7 +239,7 @@ } } -__initfunc(void sbus_init(void)) +void __init sbus_init(void) { register int nd, this_sbus, sbus_devs, topnd, iommund; unsigned int sbus_clock; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/ChangeLog.serverraid linux/drivers/scsi/ChangeLog.serverraid --- v2.3.15/linux/drivers/scsi/ChangeLog.serverraid Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/ChangeLog.serverraid Mon Aug 30 10:43:25 1999 @@ -0,0 +1,25 @@ +Change Log +~~~~~~~~~~ + + 1.00.00 - Initial Public Release + - Functionally equivalent to 0.99.05 + + 0.99.05 - Fix an oops on certain passthru commands + + 0.99.04 - Fix race condition in the passthru mechanism + -- this required the interface to the utilities to change + - Fix error recovery code + + 0.99.03 - Make interrupt routine handle all completed request on the + adapter not just the first one + - Make sure passthru commands get woken up if we run out of + SCBs + - Send all of the commands on the queue at once rather than + one at a time since the card will support it. + + 0.99.02 - Added some additional debug statements to print out + errors if an error occurs while trying to read/write + to a logical drive (IPS_DEBUG). + + Fixed read/write errors when the adapter is using an + 8K stripe size. diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.3.15/linux/drivers/scsi/Config.in Thu Aug 26 13:05:38 1999 +++ linux/drivers/scsi/Config.in Mon Aug 30 10:43:25 1999 @@ -30,6 +30,7 @@ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 fi +dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.3.15/linux/drivers/scsi/Makefile Wed Aug 18 10:00:52 1999 +++ linux/drivers/scsi/Makefile Mon Aug 30 10:43:25 1999 @@ -370,6 +370,14 @@ endif endif +ifeq ($(CONFIG_SCSI_IPS),y) +L_OBJS += ips.o +else + ifeq ($(CONFIG_SCSI_IPS),m) + M_OBJS += ips.o + endif +endif + ifeq ($(CONFIG_SCSI_DC390T),y) L_OBJS += tmscsim.o else diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.3.15/linux/drivers/scsi/advansys.c Thu Aug 5 15:07:42 1999 +++ linux/drivers/scsi/advansys.c Thu Aug 26 14:02:45 1999 @@ -3203,11 +3203,9 @@ * are not used when the driver is built as a module, cf. linux/init.h. */ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23) -#define ASC_INITFUNC(func) func #define ASC_INITDATA #define ASC_INIT #else /* version >= v2.1.23 */ -#define ASC_INITFUNC(func) __initfunc(func) #define ASC_INITDATA __initdata #define ASC_INIT __init #endif /* version >= v2.1.23 */ @@ -4168,10 +4166,8 @@ * it must not call SCSI mid-level functions including scsi_malloc() * and scsi_free(). */ -ASC_INITFUNC( -int +int ASC_INIT advansys_detect(Scsi_Host_Template *tpnt) -) { static int detect_called = ASC_FALSE; int iop; @@ -6192,10 +6188,8 @@ * ints[2] - second argument * ... */ -ASC_INITFUNC( -void +void ASC_INIT advansys_setup(char *str, int *ints) -) { int i; @@ -7454,10 +7448,8 @@ /* * Search for an AdvanSys PCI device in the PCI configuration space. */ -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT asc_srch_pci_dev(PCI_DEVICE *pciDevice) -) { int ret = PCI_DEVICE_NOT_FOUND; @@ -7494,10 +7486,8 @@ /* * Determine the access method to be used for 'pciDevice'. */ -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT asc_scan_method(void) -) { ushort data; PCI_DATA pciData; @@ -7526,10 +7516,8 @@ * * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND. */ -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT asc_pci_find_dev(PCI_DEVICE *pciDevice) -) { PCI_DATA pciData; ushort vendorid, deviceid; @@ -7578,10 +7566,8 @@ /* * Read PCI configuration data into 'pciConfig'. */ -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig) -) { PCI_DATA pciData; uchar counter; @@ -7610,10 +7596,8 @@ * * The configuration mechanism is checked for the correct access method. */ -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT asc_get_cfg_word(PCI_DATA *pciData) -) { ushort tmp; ulong address; @@ -7693,10 +7677,8 @@ * * The configuration mechanism is checked for the correct access method. */ -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT asc_get_cfg_byte(PCI_DATA *pciData) -) { uchar tmp; ulong address; @@ -7773,10 +7755,8 @@ /* * Write a byte to the PCI configuration space. */ -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data) -) { ulong tmpl; ulong address; @@ -9366,12 +9346,10 @@ /* * Read a PCI configuration byte. */ -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT DvcReadPCIConfigByte( ASC_DVC_VAR asc_ptr_type *asc_dvc, ushort offset) -) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -9403,13 +9381,11 @@ /* * Write a PCI configuration byte. */ -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT DvcWritePCIConfigByte( ASC_DVC_VAR asc_ptr_type *asc_dvc, ushort offset, uchar byte_data) -) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -9436,13 +9412,11 @@ * Return the BIOS address of the adapter at the specified * I/O port and with the specified bus type. */ -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscGetChipBiosAddress( PortAddr iop_base, ushort bus_type ) -) { ushort cfg_lsw ; ushort bios_addr ; @@ -9519,12 +9493,10 @@ /* * Read a PCI configuration byte. */ -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT DvcAdvReadPCIConfigByte( ADV_DVC_VAR *asc_dvc, ushort offset) -) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -9556,13 +9528,11 @@ /* * Write a PCI configuration byte. */ -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT DvcAdvWritePCIConfigByte( ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data) -) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -10206,12 +10176,10 @@ * --- Asc Library Functions */ -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscGetEisaChipCfg( PortAddr iop_base ) -) { PortAddr eisa_cfg_iop; @@ -10220,13 +10188,11 @@ return (inpw(eisa_cfg_iop)); } -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT AscSetChipScsiID( PortAddr iop_base, uchar new_host_id ) -) { ushort cfg_lsw; @@ -10240,12 +10206,10 @@ return (AscGetChipScsiID(iop_base)); } -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT AscGetChipScsiCtrl( PortAddr iop_base ) -) { uchar sc; @@ -10255,13 +10219,11 @@ return (sc); } -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT AscGetChipVersion( PortAddr iop_base, ushort bus_type ) -) { if ((bus_type & ASC_IS_EISA) != 0) { PortAddr eisa_iop; @@ -10274,12 +10236,10 @@ return (AscGetChipVerNo(iop_base)); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscGetChipBusType( PortAddr iop_base ) -) { ushort chip_ver; @@ -10309,15 +10269,13 @@ return (0); } -ASC_INITFUNC( -STATIC ulong +STATIC ulong ASC_INIT AscLoadMicroCode( PortAddr iop_base, ushort s_addr, ushort *mcode_buf, ushort mcode_size ) -) { ulong chksum; ushort mcode_word_size; @@ -10335,12 +10293,10 @@ return (chksum); } -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT AscFindSignature( PortAddr iop_base ) -) { ushort sig_word; @@ -10361,13 +10317,11 @@ ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 }; -ASC_INITFUNC( -STATIC PortAddr +STATIC PortAddr ASC_INIT AscSearchIOPortAddr( PortAddr iop_beg, ushort bus_type ) -) { if (bus_type & ASC_IS_VL) { while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { @@ -10398,12 +10352,10 @@ return (0); } -ASC_INITFUNC( -STATIC PortAddr +STATIC PortAddr ASC_INIT AscSearchIOPortAddr11( PortAddr s_addr ) -) { int i; PortAddr iop_base; @@ -10429,36 +10381,30 @@ return (0); } -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AscToggleIRQAct( PortAddr iop_base ) -) { AscSetChipStatus(iop_base, CIW_IRQ_ACT); AscSetChipStatus(iop_base, 0); return; } -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AscSetISAPNPWaitForKey( void) -) { outp(ASC_ISA_PNP_PORT_ADDR, 0x02); outp(ASC_ISA_PNP_PORT_WRITE, 0x02); return; } -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT AscGetChipIRQ( PortAddr iop_base, ushort bus_type ) -) { ushort cfg_lsw; uchar chip_irq; @@ -10488,14 +10434,12 @@ return ((uchar) (chip_irq + ASC_MIN_IRQ_NO)); } -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT AscSetChipIRQ( PortAddr iop_base, uchar irq_no, ushort bus_type ) -) { ushort cfg_lsw; @@ -10529,12 +10473,10 @@ return (0); } -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AscEnableIsaDma( uchar dma_channel ) -) { if (dma_channel < 4) { outp(0x000B, (ushort) (0xC0 | dma_channel)); @@ -12396,12 +12338,10 @@ udelay((nano_sec + 999)/1000); } -ASC_INITFUNC( -STATIC ulong +STATIC ulong ASC_INIT AscGetEisaProductID( PortAddr iop_base ) -) { PortAddr eisa_iop; ushort product_id_high, product_id_low; @@ -12414,12 +12354,10 @@ return (product_id); } -ASC_INITFUNC( -STATIC PortAddr +STATIC PortAddr ASC_INIT AscSearchIOPortAddrEISA( PortAddr iop_base ) -) { ulong eisa_product_id; @@ -12608,12 +12546,10 @@ return (AscIsChipHalted(iop_base)); } -ASC_INITFUNC( -STATIC ulong +STATIC ulong ASC_INIT AscGetMaxDmaCount( ushort bus_type ) -) { if (bus_type & ASC_IS_ISA) return (ASC_MAX_ISA_DMA_COUNT); @@ -12622,12 +12558,10 @@ return (ASC_MAX_PCI_DMA_COUNT); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscGetIsaDmaChannel( PortAddr iop_base ) -) { ushort channel; @@ -12639,13 +12573,11 @@ return (channel + 4); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscSetIsaDmaChannel( PortAddr iop_base, ushort dma_channel ) -) { ushort cfg_lsw; uchar value; @@ -12663,13 +12595,11 @@ return (0); } -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT AscSetIsaDmaSpeed( PortAddr iop_base, uchar speed_value ) -) { speed_value &= 0x07; AscSetBank(iop_base, 1); @@ -12678,12 +12608,10 @@ return (AscGetIsaDmaSpeed(iop_base)); } -ASC_INITFUNC( -STATIC uchar +STATIC uchar ASC_INIT AscGetIsaDmaSpeed( PortAddr iop_base ) -) { uchar speed_value; @@ -12694,12 +12622,10 @@ return (speed_value); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscReadPCIConfigWord( ASC_DVC_VAR asc_ptr_type *asc_dvc, ushort pci_config_offset) -) { uchar lsb, msb; @@ -12708,12 +12634,10 @@ return ((ushort) ((msb << 8) | lsb)); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscInitGetConfig( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { ushort warn_code; PortAddr iop_base; @@ -12793,12 +12717,10 @@ return(warn_code); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscInitSetConfig( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { ushort warn_code = 0; @@ -12814,12 +12736,10 @@ return (warn_code); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscInitFromAscDvcVar( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { PortAddr iop_base; ushort cfg_msw; @@ -12877,12 +12797,10 @@ return (warn_code); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscInitAsc1000Driver( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { ushort warn_code; PortAddr iop_base; @@ -12919,12 +12837,10 @@ return (warn_code); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscInitAscDvcVar( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { int i; PortAddr iop_base; @@ -13034,12 +12950,10 @@ return (warn_code); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscInitFromEEP( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { ASCEEP_CONFIG eep_config_buf; ASCEEP_CONFIG *eep_config; @@ -13189,12 +13103,10 @@ return (warn_code); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscInitMicroCodeVar( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { int i; ushort warn_code; @@ -13239,12 +13151,10 @@ return (warn_code); } -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT AscTestExternalLram( ASC_DVC_VAR asc_ptr_type * asc_dvc ) -) { PortAddr iop_base; ushort q_addr; @@ -13266,13 +13176,11 @@ return (sta); } -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT AscWriteEEPCmdReg( PortAddr iop_base, uchar cmd_reg ) -) { uchar read_back; int retry; @@ -13291,13 +13199,11 @@ } } -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT AscWriteEEPDataReg( PortAddr iop_base, ushort data_reg ) -) { ushort read_back; int retry; @@ -13316,35 +13222,29 @@ } } -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AscWaitEEPRead( void ) -) { DvcSleepMilliSecond(1); return; } -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AscWaitEEPWrite( void ) -) { DvcSleepMilliSecond(20); return; } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscReadEEPWord( PortAddr iop_base, uchar addr ) -) { ushort read_wval; uchar cmd_reg; @@ -13359,14 +13259,12 @@ return (read_wval); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscWriteEEPWord( PortAddr iop_base, uchar addr, ushort word_val ) -) { ushort read_wval; @@ -13386,13 +13284,11 @@ return (read_wval); } -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AscGetEEPConfig( PortAddr iop_base, ASCEEP_CONFIG * cfg_buf, ushort bus_type ) -) { ushort wval; ushort sum; @@ -13427,13 +13323,11 @@ return (sum); } -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT AscSetEEPConfigOnce( PortAddr iop_base, ASCEEP_CONFIG * cfg_buf, ushort bus_type ) -) { int n_error; ushort *wbuf; @@ -13484,13 +13378,11 @@ return (n_error); } -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT AscSetEEPConfig( PortAddr iop_base, ASCEEP_CONFIG * cfg_buf, ushort bus_type ) -) { int retry; int n_error; @@ -14175,10 +14067,8 @@ * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. */ -ASC_INITFUNC( -int +int ASC_INIT AdvInitGetConfig(ADV_DVC_VAR *asc_dvc) -) { ushort warn_code; AdvPortAddr iop_base; @@ -14285,10 +14175,8 @@ * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. */ -ASC_INITFUNC( -int +int ASC_INIT AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) -) { AdvPortAddr iop_base; ushort warn_code; @@ -14620,10 +14508,8 @@ * * Note: Chip is stopped on entry. */ -ASC_INITFUNC( -STATIC int +STATIC int ASC_INIT AdvInitFromEEP(ADV_DVC_VAR *asc_dvc) -) { AdvPortAddr iop_base; ushort warn_code; @@ -14786,10 +14672,8 @@ * * Return a checksum based on the EEPROM configuration read. */ -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) -) { ushort wval, chksum; ushort *wbuf; @@ -14820,10 +14704,8 @@ /* * Read the EEPROM from specified location */ -ASC_INITFUNC( -STATIC ushort +STATIC ushort ASC_INIT AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) -) { AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_READ | eep_word_addr); @@ -14834,10 +14716,8 @@ /* * Wait for EEPROM command to complete */ -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AdvWaitEEPCmd(AdvPortAddr iop_base) -) { int eep_delay_ms; @@ -14859,10 +14739,8 @@ /* * Write the EEPROM from 'cfg_buf'. */ -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) -) { ushort *wbuf; ushort addr, chksum; @@ -14923,10 +14801,8 @@ * configuration is read to determine whether SCSI Bus Resets * should be performed. */ -ASC_INITFUNC( -STATIC void +STATIC void ASC_INIT AdvResetChip(ADV_DVC_VAR *asc_dvc) -) { AdvPortAddr iop_base; ushort word; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c --- v2.3.15/linux/drivers/scsi/atari_NCR5380.c Wed Aug 18 10:00:52 1999 +++ linux/drivers/scsi/atari_NCR5380.c Tue Aug 31 11:23:03 1999 @@ -323,7 +323,7 @@ static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ -__initfunc(static void init_tags( void )) +static void __init init_tags( void ) { int target, lun; TAG_ALLOC *ta; @@ -684,7 +684,7 @@ * Inputs : instance, pointer to this instance. Unused. */ -__initfunc(static void NCR5380_print_options (struct Scsi_Host *instance)) +static void __init NCR5380_print_options (struct Scsi_Host *instance) { printk(" generic options" #ifdef AUTOSENSE @@ -848,7 +848,7 @@ * */ -__initfunc(static void NCR5380_init (struct Scsi_Host *instance, int flags)) +static void __init NCR5380_init (struct Scsi_Host *instance, int flags) { int i; SETUP_HOSTDATA(instance); diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.3.15/linux/drivers/scsi/esp.c Mon Mar 15 16:11:31 1999 +++ linux/drivers/scsi/esp.c Thu Aug 26 14:30:19 1999 @@ -671,9 +671,9 @@ trash = eregs->esp_intrpt; } -__initfunc(int detect_one_esp +int __init detect_one_esp (Scsi_Host_Template *tpnt, struct linux_sbus_device *esp_dev, struct linux_sbus_device *espdma, - struct linux_sbus *sbus, int id, int hme)) + struct linux_sbus *sbus, int id, int hme) { struct Sparc_ESP *esp, *elink; struct Scsi_Host *esp_host; @@ -1022,7 +1022,7 @@ #include -__initfunc(int esp_detect(Scsi_Host_Template *tpnt)) +int __init esp_detect(Scsi_Host_Template *tpnt) { static struct linux_sbus_device esp_dev; int esps_in_use = 0; @@ -1044,7 +1044,7 @@ #else /* !CONFIG_SUN4 */ -__initfunc(int esp_detect(Scsi_Host_Template *tpnt)) +int __init esp_detect(Scsi_Host_Template *tpnt) { struct linux_sbus *sbus; struct linux_sbus_device *esp_dev, *sbdev_iter; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/fcal.c linux/drivers/scsi/fcal.c --- v2.3.15/linux/drivers/scsi/fcal.c Mon Mar 15 16:11:31 1999 +++ linux/drivers/scsi/fcal.c Tue Aug 31 11:23:03 1999 @@ -90,7 +90,7 @@ /* Detect all FC Arbitrated Loops attached to the machine. fc4 module has done all the work for us... */ -__initfunc(int fcal_detect(Scsi_Host_Template *tpnt)) +int __init fcal_detect(Scsi_Host_Template *tpnt) { int nfcals = 0; fc_channel *fc; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.3.15/linux/drivers/scsi/hosts.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/scsi/hosts.c Mon Aug 30 10:43:25 1999 @@ -135,6 +135,10 @@ #include "aic7xxx.h" #endif +#ifdef CONFIG_SCSI_IPS +#include "ips.h" +#endif + #ifdef CONFIG_SCSI_BUSLOGIC #include "BusLogic.h" #endif @@ -478,6 +482,9 @@ #endif #ifdef CONFIG_SCSI_AIC7XXX AIC7XXX, +#endif +#ifdef CONFIG_SCSI_IPS + IPS, #endif #ifdef CONFIG_SCSI_FD_MCS FD_MCS, diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.3.15/linux/drivers/scsi/ide-scsi.c Tue Jul 6 19:08:33 1999 +++ linux/drivers/scsi/ide-scsi.c Thu Aug 26 13:44:03 1999 @@ -429,7 +429,8 @@ if (drive->using_dma && rq->bh) dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); - OUT_BYTE (drive->ctl,IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl,IDE_CONTROL_REG); OUT_BYTE (dma_ok,IDE_FEATURE_REG); OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG); OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG); diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.3.15/linux/drivers/scsi/ips.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/ips.c Tue Aug 31 09:33:09 1999 @@ -0,0 +1,3936 @@ +/*****************************************************************************/ +/* ips.c -- driver for the IBM ServeRAID controller */ +/* */ +/* Written By: Keith Mitchell, IBM Corporation */ +/* */ +/* Copyright (C) 1999 IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* NO WARRANTY */ +/* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */ +/* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */ +/* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */ +/* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */ +/* solely responsible for determining the appropriateness of using and */ +/* distributing the Program and assumes all risks associated with its */ +/* exercise of rights under this Agreement, including but not limited to */ +/* the risks and costs of program errors, damage to or loss of data, */ +/* programs or equipment, and unavailability or interruption of operations. */ +/* */ +/* DISCLAIMER OF LIABILITY */ +/* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */ +/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ +/* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */ +/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */ +/* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */ +/* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */ +/* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* Bugs/Comments/Suggestions should be mailed to: */ +/* ipslinux@us.ibm.com */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Change Log */ +/* */ +/* 0.99.02 - Breakup commands that are bigger than 8 * the stripe size */ +/* 0.99.03 - Make interrupt routine handle all completed request on the */ +/* adapter not just the first one */ +/* - Make sure passthru commands get woken up if we run out of */ +/* SCBs */ +/* - Send all of the commands on the queue at once rather than */ +/* one at a time since the card will support it. */ +/* 0.99.04 - Fix race condition in the passthru mechanism -- this required */ +/* the interface to the utilities to change */ +/* - Fix error recovery code */ +/* 0.99.05 - Fix an oops when we get certain passthru commands */ +/* 1.00.00 - Initial Public Release */ +/* Functionally equivalent to 0.99.05 */ +/* */ +/*****************************************************************************/ + +/* + * Conditional Compilation directives for this driver: + * + * NO_IPS_RESET - Don't reset the controller (no matter what) + * IPS_DEBUG - More verbose error messages + * IPS_PCI_PROBE_DEBUG - Print out more detail on the PCI probe + * + */ + +#if defined (MODULE) + #include +#endif /* MODULE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef NO_IPS_CMDLINE +#include +#endif + +#include "sd.h" +#include "scsi.h" +#include "hosts.h" +#include "ips.h" + +#include +#include +#include +#include + +/* + * DRIVER_VER + */ +#define IPS_VERSION_HIGH "1.00" /* MUST be 4 chars */ +#define IPS_VERSION_LOW ".00 " /* MUST be 4 chars */ + +struct proc_dir_entry proc_scsi_ips = { +#if !defined(PROC_SCSI_IPS) + 0, /* Use dynamic inode allocation */ +#else + PROC_SCSI_IPS, +#endif + 3, "ips", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,93) + #include +#endif + +#if !defined(__i386__) + #error "This driver has only been tested on the x86 platform" +#endif + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0) + #error "This driver only works with kernel 2.2.0 and later" +#endif + +#if !defined(NO_IPS_CMDLINE) && ((SG_BIG_BUFF < 8192) || !defined(SG_BIG_BUFF)) + #error "To use the command-line interface you need to define SG_BIG_BUFF" +#endif + +#if IPS_DEBUG >= 12 + #define DBG(s) printk(KERN_NOTICE s "\n"); MDELAY(2*ONE_SEC) +#elif IPS_DEBUG >= 11 + #define DBG(s) printk(KERN_NOTICE s "\n") +#else + #define DBG(s) +#endif + +/* + * global variables + */ +static const char * ips_name = "ips"; +static struct Scsi_Host * ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */ +static ips_ha_t * ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */ +static unsigned int ips_num_controllers = 0; +static int ips_cmd_timeout = 60; +static int ips_reset_timeout = 60 * 5; + +#define MAX_ADAPTER_NAME 6 + +static char ips_adapter_name[][30] = { + "ServeRAID", + "ServeRAID II", + "ServeRAID on motherboard", + "ServeRAID on motherboard", + "ServeRAID 3H", + "ServeRAID 3L" +}; + +/* + * Function prototypes + */ +int ips_detect(Scsi_Host_Template *); +int ips_release(struct Scsi_Host *); +int ips_abort(Scsi_Cmnd *); +int ips_reset(Scsi_Cmnd *, unsigned int); +int ips_eh_abort(Scsi_Cmnd *); +int ips_eh_reset(Scsi_Cmnd *); +int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *)); +int ips_biosparam(Disk *, kdev_t, int *); +const char * ips_info(struct Scsi_Host *); +void do_ipsintr(int, void *, struct pt_regs *); +static int ips_hainit(ips_ha_t *); +static int ips_map_status(ips_scb_t *, ips_stat_t *); +static int ips_send(ips_ha_t *, ips_scb_t *, scb_callback); +static int ips_send_wait(ips_ha_t *, ips_scb_t *, int); +static int ips_send_cmd(ips_ha_t *, ips_scb_t *); +static int ips_chkstatus(ips_ha_t *); +static int ips_online(ips_ha_t *, ips_scb_t *); +static int ips_inquiry(ips_ha_t *, ips_scb_t *); +static int ips_rdcap(ips_ha_t *, ips_scb_t *); +static int ips_msense(ips_ha_t *, ips_scb_t *); +static int ips_reqsen(ips_ha_t *, ips_scb_t *); +static int ips_allocatescbs(ips_ha_t *); +static int ips_reset_adapter(ips_ha_t *); +static int ips_statupd(ips_ha_t *); +static int ips_issue(ips_ha_t *, ips_scb_t *); +static int ips_isintr(ips_ha_t *); +static int ips_wait(ips_ha_t *, int, int); +static int ips_write_driver_status(ips_ha_t *); +static int ips_read_adapter_status(ips_ha_t *); +static int ips_read_subsystem_parameters(ips_ha_t *); +static int ips_read_config(ips_ha_t *); +static int ips_clear_adapter(ips_ha_t *); +static int ips_readwrite_page5(ips_ha_t *, int); +static void ips_intr(ips_ha_t *); +static void ips_next(ips_ha_t *); +static void ipsintr_blocking(ips_ha_t *, struct ips_scb *); +static void ipsintr_done(ips_ha_t *, struct ips_scb *); +static void ips_done(ips_ha_t *, ips_scb_t *); +static void ips_free(ips_ha_t *); +static void ips_init_scb(ips_ha_t *, ips_scb_t *); +static void ips_freescb(ips_ha_t *, ips_scb_t *); +static void ips_statinit(ips_ha_t *); +static ips_scb_t * ips_getscb(ips_ha_t *); +static inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); +static inline void ips_putq_scb_tail(ips_scb_queue_t *, ips_scb_t *); +static inline ips_scb_t * ips_removeq_scb_head(ips_scb_queue_t *); +static inline ips_scb_t * ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); +static inline void ips_putq_wait_head(ips_wait_queue_t *, Scsi_Cmnd *); +static inline void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); +static inline Scsi_Cmnd * ips_removeq_wait_head(ips_wait_queue_t *); +static inline Scsi_Cmnd * ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); + +#ifndef NO_IPS_CMDLINE +static int ips_is_passthru(Scsi_Cmnd *); +static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *); +static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); +#endif + +int ips_proc_info(char *, char **, off_t, int, int, int); +static int ips_host_info(ips_ha_t *, char *, off_t, int); +static void copy_mem_info(INFOSTR *, char *, int); +static int copy_info(INFOSTR *, char *, ...); + +/*--------------------------------------------------------------------------*/ +/* Exported Functions */ +/*--------------------------------------------------------------------------*/ + +/****************************************************************************/ +/* */ +/* Routine Name: ips_detect */ +/* */ +/* Routine Description: */ +/* */ +/* Detect and initialize the driver */ +/* */ +/****************************************************************************/ +int +ips_detect(Scsi_Host_Template *SHT) { + struct Scsi_Host *sh; + ips_ha_t *ha; + u32 io_addr; + u16 planer; + u8 bus; + u8 func; + u8 irq; + int index; + struct pci_dev *dev = NULL; + + DBG("ips_detect"); + + SHT->proc_info = ips_proc_info; + SHT->proc_dir = &proc_scsi_ips; + +#if defined(CONFIG_PCI) + + /* initalize number of controllers */ + ips_num_controllers = 0; + + if (!pci_present()) + return (0); + + for (index = 0; index < IPS_MAX_ADAPTERS; index++) { + + if (!(dev = pci_find_device(IPS_VENDORID, IPS_DEVICEID, dev))) + break; + + /* stuff that we get in dev */ + irq = dev->irq; + bus = dev->bus->number; + func = dev->devfn; + io_addr = dev->resource[0].start; + + /* get planer status */ + if (pci_read_config_word(dev, 0x04, &planer)) { + printk(KERN_WARNING "(%s%d) can't get planer status.\n", + ips_name, index); + + continue; + } + + /* check I/O address */ + if ((dev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + continue; + + /* check to see if an onboard planer controller is disabled */ + if (!(planer & 0x000C)) { + + #ifdef IPS_PCI_PROBE_DEBUG + printk(KERN_NOTICE "(%s%d) detect, Onboard ServeRAID disabled by BIOS\n", + ips_name, index); + #endif + + continue; + } + + #ifdef IPS_PCI_PROBE_DEBUG + printk(KERN_NOTICE "(%s%d) detect bus %d, func %x, irq %d, io %x\n", + ips_name, index, bus, func, irq, io_addr); + #endif + + /* found a controller */ + sh = scsi_register(SHT, sizeof(ips_ha_t)); + + if (sh == NULL) { + printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n", + ips_name, index); + + continue; + } + + ha = HA(sh); + memset(ha, 0, sizeof(ips_ha_t)); + + /* Initialize spin lock */ + spin_lock_init(&ha->scb_lock); + spin_lock_init(&ha->copp_lock); + + ips_sh[ips_num_controllers] = sh; + ips_ha[ips_num_controllers] = ha; + ips_num_controllers++; + ha->active = 1; + + ha->enq = kmalloc(sizeof(ENQCMD), GFP_KERNEL|GFP_DMA); + + if (!ha->enq) { + printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + ha->adapt = kmalloc(sizeof(ADAPTER_AREA), GFP_KERNEL|GFP_DMA); + + if (!ha->adapt) { + printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + ha->conf = kmalloc(sizeof(CONFCMD), GFP_KERNEL|GFP_DMA); + + if (!ha->conf) { + printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + ha->nvram = kmalloc(sizeof(NVRAM_PAGE5), GFP_KERNEL|GFP_DMA); + + if (!ha->nvram) { + printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + ha->subsys = kmalloc(sizeof(SUBSYS_PARAM), GFP_KERNEL|GFP_DMA); + + if (!ha->subsys) { + printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + ha->dummy = kmalloc(sizeof(BASIC_IO_CMD), GFP_KERNEL|GFP_DMA); + + if (!ha->dummy) { + printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + /* Store away needed values for later use */ + sh->io_port = io_addr; + sh->n_io_port = 255; + sh->unique_id = io_addr; + sh->irq = irq; + sh->select_queue_depths = NULL; + sh->sg_tablesize = sh->hostt->sg_tablesize; + sh->can_queue = sh->hostt->can_queue; + sh->cmd_per_lun = sh->hostt->cmd_per_lun; + sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; + sh->use_clustering = sh->hostt->use_clustering; + sh->wish_block = FALSE; + + /* Store info in HA structure */ + ha->io_addr = io_addr; + ha->irq = irq; + ha->host_num = index; + + /* install the interrupt handler */ + if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { + printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + /* + * Allocate a temporary SCB for initialization + */ + ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_KERNEL|GFP_DMA); + if (!ha->scbs) { + /* couldn't allocate a temp SCB */ + printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + memset(ha->scbs, 0, sizeof(ips_scb_t)); + ha->scbs->sg_list = (SG_LIST *) kmalloc(sizeof(SG_LIST) * MAX_SG_ELEMENTS, GFP_KERNEL|GFP_DMA); + if (!ha->scbs->sg_list) { + /* couldn't allocate a temp SCB S/G list */ + printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + ha->max_cmds = 1; + + if (!ips_hainit(ha)) { + printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + /* + * Free the temporary SCB + */ + kfree(ha->scbs->sg_list); + kfree(ha->scbs); + ha->scbs = NULL; + + /* allocate CCBs */ + if (!ips_allocatescbs(ha)) { + printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", + ips_name, index); + + ha->active = 0; + + continue; + } + + /* finish setting values */ + sh->max_id = ha->ntargets; + sh->max_lun = ha->nlun; + sh->max_channel = ha->nbus; + sh->can_queue = ha->max_cmds-1; + } /* end for */ + + return (ips_num_controllers); + +#else + + /* No PCI -- No ServeRAID */ + return (0); +#endif /* CONFIG_PCI */ +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_release */ +/* */ +/* Routine Description: */ +/* */ +/* Remove a driver */ +/* */ +/****************************************************************************/ +int +ips_release(struct Scsi_Host *sh) { + ips_scb_t *scb; + ips_ha_t *ha; + int i; + + DBG("ips_release"); + + for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++); + + if (i == IPS_MAX_ADAPTERS) + panic("(%s) release, invalid Scsi_Host pointer.\n", + ips_name); + + ha = HA(sh); + + if (!ha) + return (FALSE); + + /* flush the cache on the controller */ + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_cmd_timeout; + scb->cdb[0] = FLUSH_CACHE; + + scb->cmd.flush_cache.op_code = FLUSH_CACHE; + scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.flush_cache.state = NORM_STATE; + scb->cmd.flush_cache.reserved = 0; + scb->cmd.flush_cache.reserved2 = 0; + scb->cmd.flush_cache.reserved3 = 0; + scb->cmd.flush_cache.reserved4 = 0; + + printk("(%s%d) Flushing Cache.\n", ips_name, ha->host_num); + + /* send command */ + if (ips_send_wait(ha, scb, ips_cmd_timeout) == IPS_FAILURE) + printk("(%s%d) Incomplete Flush.\n", ips_name, ha->host_num); + + printk("(%s%d) Flushing Complete.\n", ips_name, ha->host_num); + + ips_sh[i] = NULL; + ips_ha[i] = NULL; + + /* free extra memory */ + ips_free(ha); + + /* free IRQ */ + free_irq(ha->irq, ha); + + /* unregister with SCSI sub system */ + scsi_unregister(sh); + + return (FALSE); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_eh_abort */ +/* */ +/* Routine Description: */ +/* */ +/* Abort a command (using the new error code stuff) */ +/* */ +/****************************************************************************/ +int +ips_eh_abort(Scsi_Cmnd *SC) { + ips_ha_t *ha; + + DBG("ips_eh_abort"); + + if (!SC) + return (FAILED); + + ha = (ips_ha_t *) SC->host->hostdata; + + if (!ha) + return (FAILED); + + if (!ha->active) + return (FAILED); + + if (SC->serial_number != SC->serial_number_at_timeout) { + /* HMM, looks like a bogus command */ +#if IPS_DEBUG >= 1 + printk(KERN_NOTICE "Abort called with bogus scsi command\n"); +#endif + + return (FAILED); + } + + if (test_and_set_bit(IPS_IN_ABORT, &ha->flags)) + return (FAILED); + + /* See if the command is on the wait queue */ + if (ips_removeq_wait(&ha->scb_waitlist, SC) || + ips_removeq_wait(&ha->copp_waitlist, SC)) { + /* command not sent yet */ + clear_bit(IPS_IN_ABORT, &ha->flags); + + return (SUCCESS); + } else { + /* command must have already been sent */ + clear_bit(IPS_IN_ABORT, &ha->flags); + + return (FAILED); + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_abort */ +/* */ +/* Routine Description: */ +/* */ +/* Abort a command */ +/* */ +/****************************************************************************/ +int +ips_abort(Scsi_Cmnd *SC) { + ips_ha_t *ha; + + DBG("ips_abort"); + + if (!SC) + return (SCSI_ABORT_SNOOZE); + + ha = (ips_ha_t *) SC->host->hostdata; + + if (!ha) + return (SCSI_ABORT_SNOOZE); + + if (!ha->active) + return (SCSI_ABORT_SNOOZE); + + if (SC->serial_number != SC->serial_number_at_timeout) { + /* HMM, looks like a bogus command */ +#if IPS_DEBUG >= 1 + printk(KERN_NOTICE "Abort called with bogus scsi command\n"); +#endif + + return (SCSI_ABORT_NOT_RUNNING); + } + + if (test_and_set_bit(IPS_IN_ABORT, &ha->flags)) + return (SCSI_ABORT_SNOOZE); + + /* See if the command is on the wait queue */ + if (ips_removeq_wait(&ha->scb_waitlist, SC) || + ips_removeq_wait(&ha->copp_waitlist, SC)) { + /* command not sent yet */ + clear_bit(IPS_IN_ABORT, &ha->flags); + + return (SCSI_ABORT_PENDING); + } else { + /* command must have already been sent */ + clear_bit(IPS_IN_ABORT, &ha->flags); + + return (SCSI_ABORT_SNOOZE); + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_eh_reset */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller (with new eh error code) */ +/* */ +/****************************************************************************/ +int +ips_eh_reset(Scsi_Cmnd *SC) { + ips_ha_t *ha; + ips_scb_t *scb; + + DBG("ips_eh_reset"); + +#ifdef NO_IPS_RESET + return (FAILED); +#else + + if (!SC) { + +#if IPS_DEBUG >= 1 + printk(KERN_NOTICE "Reset called with NULL scsi command\n"); +#endif + + return (FAILED); + } + + ha = (ips_ha_t *) SC->host->hostdata; + + if (!ha) { + +#if IPS_DEBUG >= 1 + printk(KERN_NOTICE "Reset called with NULL ha struct\n"); +#endif + + return (FAILED); + } + + if (!ha->active) + return (FAILED); + + if (test_and_set_bit(IPS_IN_RESET, &ha->flags)) + return (FAILED); + + /* See if the command is on the waiting queue */ + if (ips_removeq_wait(&ha->scb_waitlist, SC) || + ips_removeq_wait(&ha->copp_waitlist, SC)) { + /* command not sent yet */ + clear_bit(IPS_IN_ABORT, &ha->flags); + + return (SUCCESS); + } + + /* + * command must have already been sent + * reset the controller + */ + if (!ips_reset_adapter(ha)) { + clear_bit(IPS_IN_RESET, &ha->flags); + + return (FAILED); + } + + if (!ips_clear_adapter(ha)) { + clear_bit(IPS_IN_RESET, &ha->flags); + + return (FAILED); + } + + /* Now fail all of the active commands */ +#if IPS_DEBUG >= 1 + printk(KERN_WARNING "(%s%d) Failing active commands\n", + ips_name, ha->host_num); +#endif + while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { + scb->scsi_cmd->result = DID_RESET << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + } + + /* Reset the number of active IOCTLs */ + ha->num_ioctl = 0; + + clear_bit(IPS_IN_RESET, &ha->flags); + + if (!test_bit(IPS_IN_INTR, &ha->flags)) { + /* + * Only execute the next command when + * we are not being called from the + * interrupt handler. The interrupt + * handler wants to do this and since + * interrupts are turned off here.... + */ + ips_next(ha); + } + + return (SUCCESS); + +#endif /* NO_IPS_RESET */ + +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_reset */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller */ +/* */ +/****************************************************************************/ +int +ips_reset(Scsi_Cmnd *SC, unsigned int flags) { + ips_ha_t *ha; + ips_scb_t *scb; + + DBG("ips_reset"); + +#ifdef NO_IPS_RESET + return (SCSI_RESET_SNOOZE); +#else + + if (!SC) { + +#if IPS_DEBUG >= 1 + printk(KERN_NOTICE "Reset called with NULL scsi command\n"); +#endif + + return (SCSI_RESET_SNOOZE); + } + + ha = (ips_ha_t *) SC->host->hostdata; + + if (!ha) { + +#if IPS_DEBUG >= 1 + printk(KERN_NOTICE "Reset called with NULL ha struct\n"); +#endif + + return (SCSI_RESET_SNOOZE); + } + + if (!ha->active) + return (SCSI_RESET_SNOOZE); + + if (test_and_set_bit(IPS_IN_RESET, &ha->flags)) + return (SCSI_RESET_SNOOZE); + + /* See if the command is on the waiting queue */ + if (ips_removeq_wait(&ha->scb_waitlist, SC) || + ips_removeq_wait(&ha->copp_waitlist, SC)) { + /* command not sent yet */ + clear_bit(IPS_IN_ABORT, &ha->flags); + + return (SCSI_RESET_SNOOZE); + } + + /* reset the controller */ + if (!ips_reset_adapter(ha)) { + clear_bit(IPS_IN_RESET, &ha->flags); + + return (SCSI_RESET_ERROR); + } + + if (!ips_clear_adapter(ha)) { + clear_bit(IPS_IN_RESET, &ha->flags); + + return (SCSI_RESET_ERROR); + } + + /* Now fail all of the active commands */ +#if IPS_DEBUG >= 1 + printk(KERN_WARNING "(%s%d) Failing active commands\n", + ips_name, ha->host_num); +#endif + while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { + scb->scsi_cmd->result = DID_RESET << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + } + + /* Reset the number of active IOCTLs */ + ha->num_ioctl = 0; + + clear_bit(IPS_IN_RESET, &ha->flags); + + if (!test_bit(IPS_IN_INTR, &ha->flags)) { + /* + * Only execute the next command when + * we are not being called from the + * interrupt handler. The interrupt + * handler wants to do this and since + * interrupts are turned off here.... + */ + ips_next(ha); + } + + return (SCSI_RESET_SUCCESS); + +#endif /* NO_IPS_RESET */ + +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_queue */ +/* */ +/* Routine Description: */ +/* */ +/* Send a command to the controller */ +/* */ +/****************************************************************************/ +int +ips_queue(Scsi_Cmnd *SC, void (*done) (Scsi_Cmnd *)) { + ips_ha_t *ha; + + DBG("ips_queue"); + + ha = (ips_ha_t *) SC->host->hostdata; + + if (!ha) + return (1); + + if (!ha->active) + return (1); + +#ifndef NO_IPS_CMDLINE + if (ips_is_passthru(SC)) { + if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) { + SC->result = DID_BUS_BUSY << 16; + done(SC); + + return (0); + } + } else { +#endif + if (ha->scb_waitlist.count == IPS_MAX_QUEUE) { + SC->result = DID_BUS_BUSY << 16; + done(SC); + + return (0); + } + +#ifndef NO_IPS_CMDLINE + } +#endif + + SC->scsi_done = done; + +#if IPS_DEBUG >= 10 + printk(KERN_NOTICE "%s: ips_queue: cmd 0x%X (%d %d %d)\n", + ips_name, + SC->cmnd[0], + SC->channel, + SC->target, + SC->lun); +#if IPS_DEBUG >= 11 + MDELAY(2*ONE_SEC); +#endif +#endif + +#ifndef NO_IPS_CMDLINE + if (ips_is_passthru(SC)) + ips_putq_wait_tail(&ha->copp_waitlist, SC); + else +#endif + ips_putq_wait_tail(&ha->scb_waitlist, SC); + + if ((!test_bit(IPS_IN_INTR, &ha->flags)) && + (!test_bit(IPS_IN_ABORT, &ha->flags)) && + (!test_bit(IPS_IN_RESET, &ha->flags))) + ips_next(ha); + + return (0); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_biosparam */ +/* */ +/* Routine Description: */ +/* */ +/* Set bios geometry for the controller */ +/* */ +/****************************************************************************/ +int +ips_biosparam(Disk *disk, kdev_t dev, int geom[]) { + ips_ha_t *ha; + int heads; + int sectors; + int cylinders; + + DBG("ips_biosparam"); + + ha = (ips_ha_t *) disk->device->host->hostdata; + + if (!ha) + /* ?!?! host adater info invalid */ + return (0); + + if (!ha->active) + return (0); + + if (!ips_read_adapter_status(ha)) + /* ?!?! Enquiry command failed */ + return (0); + + if ((disk->capacity > 0x400000) && + ((ha->enq->ucMiscFlag & 0x8) == 0)) { + heads = NORM_MODE_HEADS; + sectors = NORM_MODE_SECTORS; + } else { + heads = COMP_MODE_HEADS; + sectors = COMP_MODE_SECTORS; + } + + cylinders = disk->capacity / (heads * sectors); + +#if IPS_DEBUG >= 2 + printk(KERN_NOTICE "Geometry: heads: %d, sectors: %d, cylinders: %d\n", + heads, sectors, cylinders); +#endif + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return (0); +} + +/****************************************************************************/ +/* */ +/* Routine Name: do_ipsintr */ +/* */ +/* Routine Description: */ +/* */ +/* Wrapper for the interrupt handler */ +/* */ +/****************************************************************************/ +void +do_ipsintr(int irq, void *dev_id, struct pt_regs *regs) { + ips_ha_t *ha; + unsigned int cpu_flags; + + DBG("do_ipsintr"); + + ha = (ips_ha_t *) dev_id; + + spin_lock_irqsave(&io_request_lock, cpu_flags); + + if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) { + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + + return ; + } + + if (!ha) { + clear_bit(IPS_IN_INTR, &ha->flags); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + + return; + } + + if (!ha->active) { + clear_bit(IPS_IN_INTR, &ha->flags); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + + return; + } + + ips_intr(ha); + + clear_bit(IPS_IN_INTR, &ha->flags); + + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_intr */ +/* */ +/* Routine Description: */ +/* */ +/* Polling interrupt handler */ +/* */ +/* ASSUMES interrupts are disabled */ +/* */ +/****************************************************************************/ +void +ips_intr(ips_ha_t *ha) { + ips_stat_t *sp; + ips_scb_t *scb; + int status; + + DBG("ips_intr"); + + if (!ha) + return; + + if (!ha->active) + return; + + while (ips_isintr(ha)) { + sp = &ha->sp; + + if ((status = ips_chkstatus(ha)) < 0) { + /* unexpected interrupt - no ccb */ + printk(KERN_WARNING "(%s%d) Spurious interrupt; no ccb.\n", + ips_name, ha->host_num); + continue ; + } + + scb = (ips_scb_t *) sp->scb_addr; + + /* + * use the callback function to finish things up + * NOTE: interrupts are OFF for this + */ + (*scb->callback) (ha, scb); + } + + clear_bit(IPS_IN_INTR, &ha->flags); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_info */ +/* */ +/* Routine Description: */ +/* */ +/* Return info about the driver */ +/* */ +/****************************************************************************/ +const char * +ips_info(struct Scsi_Host *SH) { + static char buffer[256]; + char *bp; + ips_ha_t *ha; + + DBG("ips_info"); + + ha = HA(SH); + + if (!ha) + return (NULL); + + bp = &buffer[0]; + memset(bp, 0, sizeof(buffer)); + + strcpy(bp, "IBM PCI ServeRAID "); + strcat(bp, IPS_VERSION_HIGH); + strcat(bp, IPS_VERSION_LOW); + + if (ha->ad_type > 0 && + ha->ad_type <= MAX_ADAPTER_NAME) { + strcat(bp, " <"); + strcat(bp, ips_adapter_name[ha->ad_type-1]); + strcat(bp, ">"); + } + + return (bp); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_proc_info */ +/* */ +/* Routine Description: */ +/* */ +/* The passthru interface for the driver */ +/* */ +/****************************************************************************/ +int +ips_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func) { + int i; + int ret; + ips_ha_t *ha = NULL; + + DBG("ips_proc_info"); + + /* Find our host structure */ + for (i = 0; i < ips_num_controllers; i++) { + if (ips_sh[i] && ips_sh[i]->host_no == hostno) { + ha = (ips_ha_t *) ips_sh[i]->hostdata; + + break; + } + } + + if (!ha) + return (-EINVAL); + + if (func) { + /* write */ + return (0); + } else { + /* read */ + if (start) + *start = buffer; + + ret = ips_host_info(ha, buffer, offset, length); + + return (ret); + } +} + +/*--------------------------------------------------------------------------*/ +/* Helper Functions */ +/*--------------------------------------------------------------------------*/ + +#ifndef NO_IPS_CMDLINE + +/****************************************************************************/ +/* */ +/* Routine Name: ips_is_passthru */ +/* */ +/* Routine Description: */ +/* */ +/* Determine if the specified SCSI command is really a passthru command */ +/* */ +/****************************************************************************/ +static int +ips_is_passthru(Scsi_Cmnd *SC) { + DBG("ips_is_passthru"); + + if (!SC) + return (0); + + if ((SC->channel == 0) && + (SC->target == IPS_ADAPTER_ID) && + (SC->lun == 0) && + (SC->cmnd[0] == 0x0d) && + (SC->request_bufflen) && + (!SC->use_sg) && + (((char *) SC->request_buffer)[0] == 'C') && + (((char *) SC->request_buffer)[1] == 'O') && + (((char *) SC->request_buffer)[2] == 'P') && + (((char *) SC->request_buffer)[3] == 'P')) { + return (1); + } else { + return (0); + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_is_passthru */ +/* */ +/* Routine Description: */ +/* */ +/* Make a passthru command out of the info in the Scsi block */ +/* */ +/****************************************************************************/ +static int +ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb) { + ips_passthru_t *pt; + + DBG("ips_make_passthru"); + + if (!SC->request_bufflen || !SC->request_buffer) { + /* no data */ +#if IPS_DEBUG_PT >= 1 + printk(KERN_NOTICE "(%s%d) No passthru structure\n", + ips_name, ha->host_num); +#endif + + return (IPS_FAILURE); + } + + if (SC->request_bufflen < sizeof(ips_passthru_t)) { + /* wrong size */ +#if IPS_DEBUG_PT >= 1 + printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n", + ips_name, ha->host_num); +#endif + + return (IPS_FAILURE); + } + + if ((((char *) SC->request_buffer)[0] != 'C') || + (((char *) SC->request_buffer)[1] != 'O') || + (((char *) SC->request_buffer)[2] != 'P') || + (((char *) SC->request_buffer)[3] != 'P')) { + /* signature doesn't match */ +#if IPS_DEBUG_PT >= 1 + printk(KERN_NOTICE "(%s%d) Wrong signature on passthru structure.\n", + ips_name, ha->host_num); +#endif + + return (IPS_FAILURE); + } + + pt = (ips_passthru_t *) SC->request_buffer; + scb->scsi_cmd = SC; + + if (SC->request_bufflen < (sizeof(ips_passthru_t) + pt->CmdBSize)) { + /* wrong size */ +#if IPS_DEBUG_PT >= 1 + printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n", + ips_name, ha->host_num); +#endif + + return (IPS_FAILURE); + } + + switch (pt->CoppCmd) { + case IPS_NUMCTRLS: + memcpy(SC->request_buffer + sizeof(ips_passthru_t), + &ips_num_controllers, sizeof(int)); + SC->result = DID_OK << 16; + + return (IPS_SUCCESS_IMM); + case IPS_CTRLINFO: + memcpy(SC->request_buffer + sizeof(ips_passthru_t), + ha, sizeof(ips_ha_t)); + SC->result = DID_OK << 16; + + return (IPS_SUCCESS_IMM); + case COPPUSRCMD: + if (ips_usrcmd(ha, pt, scb)) + return (IPS_SUCCESS); + else + return (IPS_FAILURE); + break; + } + + return (IPS_FAILURE); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_usrcmd */ +/* */ +/* Routine Description: */ +/* */ +/* Process a user command and make it ready to send */ +/* */ +/****************************************************************************/ +static int +ips_usrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) { + SG_LIST *sg_list; + + DBG("ips_usrcmd"); + + if ((!scb) || (!pt) || (!ha)) + return (0); + + /* Save the S/G list pointer so it doesn't get clobbered */ + sg_list = scb->sg_list; + + /* copy in the CP */ + memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IOCTL_INFO)); + memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof(DCDB_TABLE)); + + /* FIX stuff that might be wrong */ + scb->sg_list = sg_list; + scb->scb_busaddr = VIRT_TO_BUS(scb); + scb->bus = 0; + scb->target_id = 0; + scb->lun = 0; + scb->sg_len = 0; + scb->data_len = 0; + scb->flags = 0; + scb->op_code = 0; + scb->callback = ipsintr_done; + scb->timeout = ips_cmd_timeout; + scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); + + /* we don't support DCDB/READ/WRITE Scatter Gather */ + if ((scb->cmd.basic_io.op_code == READ_SCATTER_GATHER) || + (scb->cmd.basic_io.op_code == WRITE_SCATTER_GATHER) || + (scb->cmd.basic_io.op_code == DIRECT_CDB_SCATTER_GATHER)) + return (0); + + if (pt->CmdBSize && pt->CmdBuffer) { + scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + sizeof(ips_passthru_t)); + } else { + scb->data_busaddr = 0L; + } + + if (pt->CmdBSize) { + if (scb->cmd.dcdb.op_code == DIRECT_CDB) { + scb->cmd.dcdb.dcdb_address = VIRT_TO_BUS(&scb->dcdb); + scb->dcdb.buffer_pointer = scb->data_busaddr; + } else { + scb->cmd.basic_io.sg_addr = scb->data_busaddr; + } + } + + /* set timeouts */ + if (pt->TimeOut) { + scb->timeout = pt->TimeOut; + + if (pt->TimeOut <= 10) + scb->dcdb.cmd_attribute |= TIMEOUT_10; + else if (pt->TimeOut <= 60) + scb->dcdb.cmd_attribute |= TIMEOUT_60; + else + scb->dcdb.cmd_attribute |= TIMEOUT_20M; + } + + /* assume error */ + scb->scsi_cmd->result = DID_ERROR << 16; + + /* success */ + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_cleanup_passthru */ +/* */ +/* Routine Description: */ +/* */ +/* Cleanup after a passthru command */ +/* */ +/****************************************************************************/ +static void +ips_cleanup_passthru(ips_scb_t *scb) { + ips_passthru_t *pt; + + DBG("ips_cleanup_passthru"); + + if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) { +#if IPS_DEBUG_PT >= 1 + printk(KERN_NOTICE "IPS couldn't cleanup\n"); +#endif + + return ; + } + + pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer; + + /* Copy data back to the user */ + pt->BasicStatus = scb->basic_status; + pt->ExtendedStatus = scb->extended_status; + + scb->scsi_cmd->result = DID_OK << 16; +} + +#endif + +/****************************************************************************/ +/* */ +/* Routine Name: ips_host_info */ +/* */ +/* Routine Description: */ +/* */ +/* The passthru interface for the driver */ +/* */ +/****************************************************************************/ +static int +ips_host_info(ips_ha_t *ha, char *ptr, off_t offset, int len) { + INFOSTR info; + + DBG("ips_host_info"); + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "\nIBM ServeRAID General Information:\n\n"); + + if ((ha->nvram->signature == NVRAM_PAGE5_SIGNATURE) && + (ha->nvram->adapter_type != 0)) + copy_info(&info, "\tController Type : %s\n", ips_adapter_name[ha->ad_type-1]); + else + copy_info(&info, "\tController Type : Unknown\n"); + + copy_info(&info, "\tIO port address : 0x%lx\n", ha->io_addr); + copy_info(&info, "\tIRQ number : %d\n", ha->irq); + + if (ha->nvram->signature == NVRAM_PAGE5_SIGNATURE) + copy_info(&info, "\tBIOS Version : %c%c%c%c%c%c%c%c\n", + ha->nvram->bios_high[0], ha->nvram->bios_high[1], + ha->nvram->bios_high[2], ha->nvram->bios_high[3], + ha->nvram->bios_low[0], ha->nvram->bios_low[1], + ha->nvram->bios_low[2], ha->nvram->bios_low[3]); + + copy_info(&info, "\tFirmware Version : %c%c%c%c%c%c%c%c\n", + ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], + ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], + ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], + ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]); + + copy_info(&info, "\tBoot Block Version : %c%c%c%c%c%c%c%c\n", + ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], + ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], + ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], + ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]); + + copy_info(&info, "\tDriver Version : %s%s\n", + IPS_VERSION_HIGH, IPS_VERSION_LOW); + + copy_info(&info, "\tMax Physical Devices : %d\n", + ha->enq->ucMaxPhysicalDevices); + copy_info(&info, "\tMax Active Commands : %d\n", + ha->max_cmds); + copy_info(&info, "\tCurrent Queued Commands : %d\n", + ha->scb_waitlist.count); + copy_info(&info, "\tCurrent Active Commands : %d\n", + ha->scb_activelist.count - ha->num_ioctl); + copy_info(&info, "\tCurrent Queued PT Commands : %d\n", + ha->copp_waitlist.count); + copy_info(&info, "\tCurrent Active PT Commands : %d\n", + ha->num_ioctl); + + copy_info(&info, "\n"); + + return (info.pos > info.offset ? info.pos - info.offset : 0); +} + +/****************************************************************************/ +/* */ +/* Routine Name: copy_mem_info */ +/* */ +/* Routine Description: */ +/* */ +/* Copy data into an INFOSTR structure */ +/* */ +/****************************************************************************/ +static void +copy_mem_info(INFOSTR *info, char *data, int len) { + DBG("copy_mem_info"); + + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: copy_info */ +/* */ +/* Routine Description: */ +/* */ +/* printf style wrapper for an info structure */ +/* */ +/****************************************************************************/ +static int +copy_info(INFOSTR *info, char *fmt, ...) { + va_list args; + char buf[81]; + int len; + + DBG("copy_info"); + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + + return (len); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_hainit */ +/* */ +/* Routine Description: */ +/* */ +/* Initialize the controller */ +/* */ +/* NOTE: Assumes to be called from with a lock */ +/* */ +/****************************************************************************/ +static int +ips_hainit(ips_ha_t *ha) { + int i; + + DBG("ips_hainit"); + + if (!ha) + return (0); + + /* initialize status queue */ + ips_statinit(ha); + + /* Setup HBA ID's */ + if (!ips_read_config(ha)) { + +#ifndef NO_IPS_RESET + + /* Try to reset the controller and try again */ + if (!ips_reset_adapter(ha)) { + printk(KERN_WARNING "(%s%d) unable to reset controller.\n", + ips_name, ha->host_num); + + return (0); + } + + if (!ips_clear_adapter(ha)) { + printk(KERN_WARNING "(%s%d) unable to initialize controller.\n", + ips_name, ha->host_num); + + return (0); + } + +#endif + + if (!ips_read_config(ha)) { + printk(KERN_WARNING "(%s%d) unable to read config from controller.\n", + ips_name, ha->host_num); + + return (0); + } + } /* end if */ + + /* write driver version */ + if (!ips_write_driver_status(ha)) { + printk(KERN_WARNING "(%s%d) unable to write driver info to controller.\n", + ips_name, ha->host_num); + + return (0); + } + + if (!ips_read_adapter_status(ha)) { + printk(KERN_WARNING "(%s%d) unable to read controller status.\n", + ips_name, ha->host_num); + + return (0); + } + + if (!ips_read_subsystem_parameters(ha)) { + printk(KERN_WARNING "(%s%d) unable to read subsystem parameters.\n", + ips_name, ha->host_num); + + return (0); + } + + /* set limits on SID, LUN, BUS */ + ha->ntargets = MAX_TARGETS + 1; + ha->nlun = 1; + ha->nbus = (ha->enq->ucMaxPhysicalDevices / MAX_TARGETS); + + switch (ha->conf->logical_drive[0].ucStripeSize) { + case 4: + ha->max_xfer = 0x10000; + break; + + case 5: + ha->max_xfer = 0x20000; + break; + + case 6: + ha->max_xfer = 0x40000; + break; + + case 7: + default: + ha->max_xfer = 0x80000; + break; + } + + /* setup max concurrent commands */ + if (ha->subsys->param[4] & 0x1) { + /* Use the new method */ + ha->max_cmds = ha->enq->ucConcurrentCmdCount; + } else { + /* use the old method */ + switch (ha->conf->logical_drive[0].ucStripeSize) { + case 4: + ha->max_cmds = 32; + break; + + case 5: + ha->max_cmds = 16; + break; + + case 6: + ha->max_cmds = 8; + break; + + case 7: + default: + ha->max_cmds = 4; + break; + } + } + + /* set controller IDs */ + ha->ha_id[0] = IPS_ADAPTER_ID; + for (i = 1; i < ha->nbus; i++) + ha->ha_id[i] = ha->conf->init_id[i-1] & 0x1f; + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_next */ +/* */ +/* Routine Description: */ +/* */ +/* Take the next command off the queue and send it to the controller */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static void +ips_next(ips_ha_t *ha) { + ips_scb_t *scb; + Scsi_Cmnd *SC; + int ret; + + DBG("ips_next"); + + if (!ha) + return ; + +#ifndef NO_IPS_CMDLINE + /* + * Send passthru commands + * These have priority over normal I/O + * but shouldn't affect performance too much + * since we limit the number that can be active + * on the card at any one time + */ + while ((ha->num_ioctl < IPS_MAX_IOCTL) && + (ha->copp_waitlist.head) && + (scb = ips_getscb(ha))) { + SC = ips_removeq_wait_head(&ha->copp_waitlist); + + ret = ips_make_passthru(ha, SC, scb); + + switch (ret) { + case IPS_FAILURE: + if (scb->scsi_cmd) { + scb->scsi_cmd->result = DID_ERROR << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + } + ips_freescb(ha, scb); + break; + case IPS_SUCCESS_IMM: + if (scb->scsi_cmd) + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + break; + default: + break; + } /* end case */ + + if (ret != IPS_SUCCESS) + continue; + + ret = ips_send_cmd(ha, scb); + + if (ret == IPS_SUCCESS) { + ips_putq_scb_head(&ha->scb_activelist, scb); + ha->num_ioctl++; + } + + switch(ret) { + case IPS_FAILURE: + if (scb->scsi_cmd) { + scb->scsi_cmd->result = DID_ERROR << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + } + + ips_freescb(ha, scb); + break; + case IPS_SUCCESS_IMM: + if (scb->scsi_cmd) + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + break; + default: + break; + } /* end case */ + } +#endif + + /* + * Send "Normal" I/O commands + */ + while ((ha->scb_waitlist.head) && + (scb = ips_getscb(ha))) { + SC = ips_removeq_wait_head(&ha->scb_waitlist); + + SC->result = DID_OK; + SC->host_scribble = NULL; + + memset(SC->sense_buffer, 0, sizeof(SC->sense_buffer)); + + scb->target_id = SC->target; + scb->lun = SC->lun; + scb->bus = SC->channel; + scb->scsi_cmd = SC; + scb->breakup = 0; + scb->data_len = 0; + scb->callback = ipsintr_done; + scb->timeout = ips_cmd_timeout; + memset(&scb->cmd, 0, 4); + + /* copy in the CDB */ + memcpy(scb->cdb, SC->cmnd, SC->cmd_len); + + /* Now handle the data buffer */ + if (SC->use_sg) { + struct scatterlist *sg; + int i; + + sg = SC->request_buffer; + + for (i = 0; i < SC->use_sg; i++) { + scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address); + scb->sg_list[i].length = sg[i].length; + + if (scb->data_len + sg[i].length > ha->max_xfer) { + /* + * Data Breakup required + */ + scb->breakup = i; + break; + } + + scb->data_len += sg[i].length; + } + + if (!scb->breakup) + scb->sg_len = SC->use_sg; + else + scb->sg_len = scb->breakup; + + scb->dcdb.transfer_length = scb->data_len; + scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); + } else { + if (SC->request_bufflen) { + if (SC->request_bufflen > ha->max_xfer) { + /* + * Data breakup required + */ + scb->breakup = 1; + scb->data_len = ha->max_xfer; + } else { + scb->data_len = SC->request_bufflen; + } + + scb->dcdb.transfer_length = scb->data_len; + scb->data_busaddr = VIRT_TO_BUS(SC->request_buffer); + scb->sg_len = 0; + } else { + scb->data_busaddr = 0L; + scb->sg_len = 0; + scb->data_len = 0; + scb->dcdb.transfer_length = 0; + } + + } + + if ((scb->scsi_cmd->request.cmd == READ) && (SC->request_bufflen)) + scb->dcdb.cmd_attribute |= DATA_IN; + + if ((scb->scsi_cmd->request.cmd == WRITE) && (SC->request_bufflen)) + scb->dcdb.cmd_attribute |= DATA_OUT; + + if (scb->data_len >= IPS_MAX_XFER) { + scb->dcdb.cmd_attribute |= TRANSFER_64K; + scb->dcdb.transfer_length = 0; + } + + ret = ips_send_cmd(ha, scb); + + if (ret == IPS_SUCCESS) + ips_putq_scb_head(&ha->scb_activelist, scb); + + switch(ret) { + case IPS_FAILURE: + if (scb->scsi_cmd) { + scb->scsi_cmd->result = DID_ERROR << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + } + + ips_freescb(ha, scb); + break; + case IPS_SUCCESS_IMM: + if (scb->scsi_cmd) + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + break; + default: + break; + } /* end case */ + } /* end while */ +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_putq_scb_head */ +/* */ +/* Routine Description: */ +/* */ +/* Add an item to the head of the queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline void +ips_putq_scb_head(ips_scb_queue_t *queue, ips_scb_t *item) { + DBG("ips_putq_scb_head"); + + if (!item) + return ; + + item->q_next = queue->head; + queue->head = item; + + if (!queue->tail) + queue->tail = item; + + queue->count++; +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_putq_scb_tail */ +/* */ +/* Routine Description: */ +/* */ +/* Add an item to the tail of the queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline void +ips_putq_scb_tail(ips_scb_queue_t *queue, ips_scb_t *item) { + DBG("ips_putq_scb_tail"); + + if (!item) + return ; + + item->q_next = NULL; + + if (queue->tail) + queue->tail->q_next = item; + + queue->tail = item; + + if (!queue->head) + queue->head = item; + + queue->count++; +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_removeq_scb_head */ +/* */ +/* Routine Description: */ +/* */ +/* Remove the head of the queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline ips_scb_t * +ips_removeq_scb_head(ips_scb_queue_t *queue) { + ips_scb_t *item; + + DBG("ips_removeq_scb_head"); + + item = queue->head; + + if (!item) + return (NULL); + + queue->head = item->q_next; + item->q_next = NULL; + + if (queue->tail == item) + queue->tail = NULL; + + queue->count--; + + return (item); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_removeq_scb */ +/* */ +/* Routine Description: */ +/* */ +/* Remove an item from a queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline ips_scb_t * +ips_removeq_scb(ips_scb_queue_t *queue, ips_scb_t *item) { + ips_scb_t *p; + + DBG("ips_removeq_scb"); + + if (!item) + return (NULL); + + if (item == queue->head) + return (ips_removeq_scb_head(queue)); + + p = queue->head; + + while ((p) && (item != p->q_next)) + p = p->q_next; + + if (p) { + /* found a match */ + p->q_next = item->q_next; + + if (!item->q_next) + queue->tail = p; + + item->q_next = NULL; + queue->count--; + + return (item); + } + + return (NULL); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_putq_wait_head */ +/* */ +/* Routine Description: */ +/* */ +/* Add an item to the head of the queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline void +ips_putq_wait_head(ips_wait_queue_t *queue, Scsi_Cmnd *item) { + DBG("ips_putq_wait_head"); + + if (!item) + return ; + + item->host_scribble = (char *) queue->head; + queue->head = item; + + if (!queue->tail) + queue->tail = item; + + queue->count++; +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_putq_wait_tail */ +/* */ +/* Routine Description: */ +/* */ +/* Add an item to the tail of the queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline void +ips_putq_wait_tail(ips_wait_queue_t *queue, Scsi_Cmnd *item) { + DBG("ips_putq_wait_tail"); + + if (!item) + return ; + + item->host_scribble = NULL; + + if (queue->tail) + queue->tail->host_scribble = (char *)item; + + queue->tail = item; + + if (!queue->head) + queue->head = item; + + queue->count++; +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_removeq_wait_head */ +/* */ +/* Routine Description: */ +/* */ +/* Remove the head of the queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline Scsi_Cmnd * +ips_removeq_wait_head(ips_wait_queue_t *queue) { + Scsi_Cmnd *item; + + DBG("ips_removeq_wait_head"); + + item = queue->head; + + if (!item) + return (NULL); + + queue->head = (Scsi_Cmnd *) item->host_scribble; + item->host_scribble = NULL; + + if (queue->tail == item) + queue->tail = NULL; + + queue->count--; + + return (item); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_removeq_wait */ +/* */ +/* Routine Description: */ +/* */ +/* Remove an item from a queue */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static inline Scsi_Cmnd * +ips_removeq_wait(ips_wait_queue_t *queue, Scsi_Cmnd *item) { + Scsi_Cmnd *p; + + DBG("ips_removeq_wait"); + + if (!item) + return (NULL); + + if (item == queue->head) + return (ips_removeq_wait_head(queue)); + + p = queue->head; + + while ((p) && (item != (Scsi_Cmnd *) p->host_scribble)) + p = (Scsi_Cmnd *) p->host_scribble; + + if (p) { + /* found a match */ + p->host_scribble = item->host_scribble; + + if (!item->host_scribble) + queue->tail = p; + + item->host_scribble = NULL; + queue->count--; + + return (item); + } + + return (NULL); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ipsintr_blocking */ +/* */ +/* Routine Description: */ +/* */ +/* Finalize an interrupt for internal commands */ +/* */ +/****************************************************************************/ +static void +ipsintr_blocking(ips_ha_t *ha, ips_scb_t *scb) { + DBG("ipsintr_blocking"); + + if ((ha->waitflag == TRUE) && + (ha->cmd_in_progress == scb->cdb[0])) { + ha->waitflag = FALSE; + + return ; + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: ipsintr_done */ +/* */ +/* Routine Description: */ +/* */ +/* Finalize an interrupt for non-internal commands */ +/* */ +/****************************************************************************/ +static void +ipsintr_done(ips_ha_t *ha, ips_scb_t *scb) { + DBG("ipsintr_done"); + + if (scb->scsi_cmd == NULL) { + /* unexpected interrupt */ + printk(KERN_WARNING "(%s%d) Spurious interrupt; scsi_cmd not set.\n", + ips_name, ha->host_num); + + return; + } + + ips_done(ha, scb); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_done */ +/* */ +/* Routine Description: */ +/* */ +/* Do housekeeping on completed commands */ +/* */ +/****************************************************************************/ +static void +ips_done(ips_ha_t *ha, ips_scb_t *scb) { + int ret; + + DBG("ips_done"); + + if (!scb) + return ; + +#ifndef NO_IPS_CMDLINE + if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) { + ips_cleanup_passthru(scb); + ha->num_ioctl--; + } else { +#endif + /* + * Check to see if this command had too much + * data and had to be broke up. If so, queue + * the rest of the data and continue. + */ + if (scb->breakup) { + /* we had a data breakup */ + u16 bk_save; + + bk_save = scb->breakup; + scb->breakup = 0; + + if (scb->scsi_cmd->use_sg) { + /* S/G request */ + struct scatterlist *sg; + int i; + + sg = scb->scsi_cmd->request_buffer; + + scb->data_len = 0; + + for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) { + scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address); + scb->sg_list[i - bk_save].length = sg[i].length; + + if (scb->data_len + sg[i].length > ha->max_xfer) { + /* + * Data Breakup required + */ + scb->breakup = i; + break; + } + + scb->data_len += sg[i].length; + } + + if (!scb->breakup) + scb->sg_len = scb->scsi_cmd->use_sg - bk_save; + else + scb->sg_len = scb->breakup - bk_save; + + scb->dcdb.transfer_length = scb->data_len; + scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); + } else { + /* Non S/G Request */ + if (scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) { + /* Further breakup required */ + scb->data_len = ha->max_xfer; + scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer)); + scb->breakup = bk_save + 1; + } else { + scb->data_len = scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer); + scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer)); + } + + scb->dcdb.transfer_length = scb->data_len; + scb->sg_len = 0; + } + + if ((scb->scsi_cmd->request.cmd == READ) && (scb->data_len)) + scb->dcdb.cmd_attribute |= DATA_IN; + + if ((scb->scsi_cmd->request.cmd == WRITE) && (scb->data_len)) + scb->dcdb.cmd_attribute |= DATA_OUT; + + if (scb->data_len >= IPS_MAX_XFER) { + scb->dcdb.cmd_attribute |= TRANSFER_64K; + scb->dcdb.transfer_length = 0; + } + + ret = ips_send_cmd(ha, scb); + + switch(ret) { + case IPS_FAILURE: + if (scb->scsi_cmd) { + scb->scsi_cmd->result = DID_ERROR << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + } + + ips_freescb(ha, scb); + break; + case IPS_SUCCESS_IMM: + if (scb->scsi_cmd) { + scb->scsi_cmd->result = DID_ERROR << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + } + + ips_freescb(ha, scb); + break; + default: + break; + } /* end case */ + + return ; + } +#ifndef NO_IPS_CMDLINE + } /* end if passthru */ +#endif + + /* call back to SCSI layer */ + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + + /* do the next command */ + ips_next(ha); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_map_status */ +/* */ +/* Routine Description: */ +/* */ +/* Map ServeRAID error codes to Linux Error Codes */ +/* */ +/****************************************************************************/ +static int +ips_map_status(ips_scb_t *scb, ips_stat_t *sp) { + int errcode; + + DBG("ips_map_status"); + + if (scb->bus) { + /* copy SCSI status and sense data for DCDB commands */ + memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info, + sizeof(scb->scsi_cmd->sense_buffer)); + scb->scsi_cmd->result = scb->dcdb.scsi_status; + } else + scb->scsi_cmd->result = 0; + + /* default driver error */ + errcode = DID_ERROR; + + switch (scb->basic_status & GSC_STATUS_MASK) { + case CMD_TIMEOUT: + errcode = DID_TIME_OUT; + break; + + case INVAL_OPCO: + case INVAL_CMD_BLK: + case INVAL_PARM_BLK: + case LOG_DRV_ERROR: + case CMD_CMPLT_WERROR: + break; + + case PHYS_DRV_ERROR: + /* + * For physical drive errors that + * are not on a logical drive should + * be DID_OK. The SCSI errcode will + * show what the real error is. + */ + if (scb->bus) + errcode = DID_OK; + + switch (scb->extended_status) { + case SELECTION_TIMEOUT: + if (scb->bus) { + scb->scsi_cmd->result |= DID_TIME_OUT << 16; + + return (0); + } + break; + case DATA_OVER_UNDER_RUN: + if ((scb->bus) && (scb->dcdb.transfer_length < scb->data_len)) { + if ((scb->scsi_cmd->cmnd[0] == INQUIRY) && + ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) { + /* underflow -- no error */ + /* restrict access to physical DASD */ + errcode = DID_TIME_OUT; + break; + } + + /* normal underflow Occured */ + if (scb->dcdb.transfer_length >= scb->scsi_cmd->underflow) { + scb->scsi_cmd->result |= DID_OK << 16; + + return (0); + } + } + + break; + case EXT_RECOVERY: + /* don't fail recovered errors */ + if (scb->bus) { + scb->scsi_cmd->result |= DID_OK << 16; + + return (0); + } + break; + + case EXT_HOST_RESET: + case EXT_DEVICE_RESET: + errcode = DID_RESET; + break; + + case EXT_CHECK_CONDITION: + break; + } /* end switch */ + } /* end switch */ + + scb->scsi_cmd->result |= (errcode << 16); + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_send */ +/* */ +/* Routine Description: */ +/* */ +/* Wrapper for ips_send_cmd */ +/* */ +/****************************************************************************/ +static int +ips_send(ips_ha_t *ha, ips_scb_t *scb, scb_callback callback) { + int ret; + + DBG("ips_send"); + + scb->callback = callback; + + ret = ips_send_cmd(ha, scb); + + return (ret); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_send_wait */ +/* */ +/* Routine Description: */ +/* */ +/* Send a command to the controller and wait for it to return */ +/* */ +/****************************************************************************/ +static int +ips_send_wait(ips_ha_t *ha, ips_scb_t *scb, int timeout) { + int ret; + + DBG("ips_send_wait"); + + ha->waitflag = TRUE; + ha->cmd_in_progress = scb->cdb[0]; + + ret = ips_send(ha, scb, ipsintr_blocking); + + if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + return (ret); + + ret = ips_wait(ha, timeout, IPS_INTR_OFF); + + return (ret); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_send_cmd */ +/* */ +/* Routine Description: */ +/* */ +/* Map SCSI commands to ServeRAID commands for logical drives */ +/* */ +/****************************************************************************/ +static int +ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) { + int ret; + + DBG("ips_send_cmd"); + + ret = IPS_SUCCESS; + + if (!scb->scsi_cmd) { + /* internal command */ + + if (scb->bus > 0) { + /* ServeRAID commands can't be issued */ + /* to real devices -- fail them */ + if ((ha->waitflag == TRUE) && + (ha->cmd_in_progress == scb->cdb[0])) { + ha->waitflag = FALSE; + } + + return (1); + } +#ifndef NO_IPS_CMDLINE + } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) { +#else + } else if (scb->bus == 0) { +#endif + /* command to logical bus -- interpret */ + ret = IPS_SUCCESS_IMM; + + switch (scb->scsi_cmd->cmnd[0]) { + case ALLOW_MEDIUM_REMOVAL: + case REZERO_UNIT: + case ERASE: + case WRITE_FILEMARKS: + case SPACE: + scb->scsi_cmd->result = DID_ERROR << 16; + break; + + case START_STOP: + scb->scsi_cmd->result = DID_OK << 16; + + case TEST_UNIT_READY: + case INQUIRY: + if (scb->target_id == IPS_ADAPTER_ID) { + /* + * Either we have a TUR + * or we have a SCSI inquiry + */ + if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY) + scb->scsi_cmd->result = DID_OK << 16; + + if (scb->scsi_cmd->cmnd[0] == INQUIRY) { + INQUIRYDATA inq; + + memset(&inq, 0, sizeof(INQUIRYDATA)); + + inq.DeviceType = TYPE_PROCESSOR; + inq.DeviceTypeQualifier = 0; + inq.RemoveableMedia = 0; + inq.Versions = 0x1; /* SCSI I */ + inq.AdditionalLength = 31; + strncpy(inq.VendorId, "IBM ", 8); + strncpy(inq.ProductId, "SERVERAID ", 16); + strncpy(inq.ProductRevisionLevel, "1.00", 4); + + memcpy(scb->scsi_cmd->request_buffer, &inq, scb->scsi_cmd->request_bufflen); + + scb->scsi_cmd->result = DID_OK << 16; + } + } else { + scb->cmd.logical_info.op_code = GET_LOGICAL_DRIVE_INFO; + scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.logical_info.buffer_addr = VIRT_TO_BUS(&ha->adapt->logical_drive_info); + scb->cmd.logical_info.reserved = 0; + scb->cmd.logical_info.reserved2 = 0; + ret = IPS_SUCCESS; + } + + break; + + case REQUEST_SENSE: + ips_reqsen(ha, scb); + scb->scsi_cmd->result = DID_OK << 16; + break; + + case READ_6: + case WRITE_6: + if (!scb->sg_len) { + scb->cmd.basic_io.op_code = + (scb->scsi_cmd->cmnd[0] == READ_6) ? IPS_READ : IPS_WRITE; + } else { + scb->cmd.basic_io.op_code = + (scb->scsi_cmd->cmnd[0] == READ_6) ? READ_SCATTER_GATHER : WRITE_SCATTER_GATHER; + } + + scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.basic_io.log_drv = scb->target_id; + scb->cmd.basic_io.sg_count = scb->sg_len; + scb->cmd.basic_io.sg_addr = scb->data_busaddr; + + if (scb->cmd.basic_io.lba) + scb->cmd.basic_io.lba += scb->cmd.basic_io.sector_count; + else + scb->cmd.basic_io.lba = (((scb->scsi_cmd->cmnd[1] & 0x1f) << 16) | + (scb->scsi_cmd->cmnd[2] << 8) | + (scb->scsi_cmd->cmnd[3])); + + scb->cmd.basic_io.sector_count = scb->data_len / IPS_BLKSIZE; + + if (scb->cmd.basic_io.sector_count == 0) + scb->cmd.basic_io.sector_count = 256; + + scb->cmd.basic_io.reserved = 0; + ret = IPS_SUCCESS; + break; + + case READ_10: + case WRITE_10: + if (!scb->sg_len) { + scb->cmd.basic_io.op_code = + (scb->scsi_cmd->cmnd[0] == READ_10) ? IPS_READ : IPS_WRITE; + } else { + scb->cmd.basic_io.op_code = + (scb->scsi_cmd->cmnd[0] == READ_10) ? READ_SCATTER_GATHER : WRITE_SCATTER_GATHER; + } + + scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.basic_io.log_drv = scb->target_id; + scb->cmd.basic_io.sg_count = scb->sg_len; + scb->cmd.basic_io.sg_addr = scb->data_busaddr; + + if (scb->cmd.basic_io.lba) + scb->cmd.basic_io.lba += scb->cmd.basic_io.sector_count; + else + scb->cmd.basic_io.lba = ((scb->scsi_cmd->cmnd[2] << 24) | + (scb->scsi_cmd->cmnd[3] << 16) | + (scb->scsi_cmd->cmnd[4] << 8) | + scb->scsi_cmd->cmnd[5]); + + scb->cmd.basic_io.sector_count = scb->data_len / IPS_BLKSIZE; + + scb->cmd.basic_io.reserved = 0; + + if (scb->cmd.basic_io.sector_count == 0) { + /* + * This is a null condition + * we don't have to do anything + * so just return + */ + scb->scsi_cmd->result = DID_OK << 16; + } else + ret = IPS_SUCCESS; + + break; + + case RESERVE: + case RELEASE: + scb->scsi_cmd->result = DID_OK << 16; + break; + + case MODE_SENSE: + scb->cmd.basic_io.op_code = ENQUIRY; + scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.basic_io.sg_addr = VIRT_TO_BUS(ha->enq); + ret = IPS_SUCCESS; + break; + + case READ_CAPACITY: + scb->cmd.logical_info.op_code = GET_LOGICAL_DRIVE_INFO; + scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.logical_info.buffer_addr = VIRT_TO_BUS(&ha->adapt->logical_drive_info); + scb->cmd.logical_info.reserved = 0; + scb->cmd.logical_info.reserved2 = 0; + scb->cmd.logical_info.reserved3 = 0; + ret = IPS_SUCCESS; + break; + + case SEND_DIAGNOSTIC: + case REASSIGN_BLOCKS: + case FORMAT_UNIT: + case SEEK_10: + case VERIFY: + case READ_DEFECT_DATA: + case READ_BUFFER: + case WRITE_BUFFER: + scb->scsi_cmd->result = DID_OK << 16; + break; + + default: + scb->scsi_cmd->result = DID_ERROR << 16; + break; + } /* end switch */ + } /* end if */ + + if (ret == IPS_SUCCESS_IMM) + return (ret); + + /* setup DCDB */ + if (scb->bus > 0) { + if (!scb->sg_len) + scb->cmd.dcdb.op_code = DIRECT_CDB; + else + scb->cmd.dcdb.op_code = DIRECT_CDB_SCATTER_GATHER; + + scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.dcdb.dcdb_address = VIRT_TO_BUS(&scb->dcdb); + scb->cmd.dcdb.reserved = 0; + scb->cmd.dcdb.reserved2 = 0; + scb->cmd.dcdb.reserved3 = 0; + + scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id; + scb->dcdb.cmd_attribute |= DISCONNECT_ALLOWED; + + if (scb->timeout) { + if (scb->timeout <= 10) + scb->dcdb.cmd_attribute |= TIMEOUT_10; + else if (scb->timeout <= 60) + scb->dcdb.cmd_attribute |= TIMEOUT_60; + else + scb->dcdb.cmd_attribute |= TIMEOUT_20M; + } + + if (!(scb->dcdb.cmd_attribute & TIMEOUT_20M)) + scb->dcdb.cmd_attribute |= TIMEOUT_20M; + + scb->dcdb.sense_length = sizeof(scb->scsi_cmd->sense_buffer); + scb->dcdb.buffer_pointer = scb->data_busaddr; + scb->dcdb.sg_count = scb->sg_len; + scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len; + memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len); + } + + return (ips_issue(ha, scb)); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_chk_status */ +/* */ +/* Routine Description: */ +/* */ +/* Check the status of commands to logical drives */ +/* */ +/****************************************************************************/ +static int +ips_chkstatus(ips_ha_t *ha) { + ips_scb_t *scb; + ips_stat_t *sp = &ha->sp; + u8 basic_status; + u8 ext_status; + int command_id; + int errcode; + int ret; + + DBG("ips_chkstatus"); + + command_id = ips_statupd(ha); + + if (command_id > (MAX_CMDS-1)) { + printk(KERN_NOTICE "(%s%d) invalid command id received: %d\n", + ips_name, ha->host_num, command_id); + + return (-1); + } + + scb = &ha->scbs[command_id]; + sp->scb_addr = (u32) scb; + sp->residue_len = 0; + scb->basic_status = basic_status = ha->adapt->p_status_tail->basic_status & BASIC_STATUS_MASK; + scb->extended_status = ext_status = ha->adapt->p_status_tail->extended_status; + + /* Remove the item from the active queue */ + ips_removeq_scb(&ha->scb_activelist, scb); + + if (!scb->scsi_cmd) + /* internal commands are handled in do_ipsintr */ + return (0); + +#ifndef NO_IPS_CMDLINE + if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) + /* passthru - just returns the raw result */ + return (0); +#endif + + errcode = DID_OK; + ret = 0; + + if (((basic_status & GSC_STATUS_MASK) == SSUCCESS) || + ((basic_status & GSC_STATUS_MASK) == RECOVERED_ERROR)) { + + if (scb->bus == 0) { +#if IPS_DEBUG >= 1 + if ((basic_status & GSC_STATUS_MASK) == RECOVERED_ERROR) { + printk(KERN_NOTICE "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x\n", + ips_name, ha->host_num, + scb->cmd.basic_io.op_code, basic_status, ext_status); + } +#endif + + switch (scb->scsi_cmd->cmnd[0]) { + case ALLOW_MEDIUM_REMOVAL: + case REZERO_UNIT: + case ERASE: + case WRITE_FILEMARKS: + case SPACE: + errcode = DID_ERROR; + ret = 1; + break; + + case START_STOP: + break; + + case TEST_UNIT_READY: + if (!ips_online(ha, scb)) { + errcode = DID_TIME_OUT; + ret = 1; + } + break; + + case INQUIRY: + if (ips_online(ha, scb)) { + ips_inquiry(ha, scb); + } else { + errcode = DID_TIME_OUT; + ret = 1; + } + break; + + case REQUEST_SENSE: + ips_reqsen(ha, scb); + break; + + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case RESERVE: + case RELEASE: + break; + + case MODE_SENSE: + if (!ips_online(ha, scb) || !ips_msense(ha, scb)) { + errcode = DID_ERROR; + ret = 1; + } + break; + + case READ_CAPACITY: + if (ips_online(ha, scb)) + ips_rdcap(ha, scb); + else { + errcode = DID_TIME_OUT; + ret = 1; + } + break; + + case SEND_DIAGNOSTIC: + case REASSIGN_BLOCKS: + break; + + case FORMAT_UNIT: + errcode = DID_ERROR; + ret = 1; + break; + + case SEEK_10: + case VERIFY: + case READ_DEFECT_DATA: + case READ_BUFFER: + case WRITE_BUFFER: + break; + + default: + errcode = DID_ERROR; + ret = 1; + } /* end switch */ + + scb->scsi_cmd->result = errcode << 16; + } else { /* bus == 0 */ + /* restrict access to physical drives */ + if ((scb->scsi_cmd->cmnd[0] == INQUIRY) && + ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) { + + scb->scsi_cmd->result = DID_TIME_OUT << 16; + + ret = 1; + } + } /* else */ + } else { /* recovered error / success */ +#if IPS_DEBUG >= 1 + if (scb->bus == 0) { + printk(KERN_NOTICE "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x\n", + ips_name, ha->host_num, + scb->cmd.basic_io.op_code, basic_status, ext_status); + } +#endif + + ret = ips_map_status(scb, sp); + } /* else */ + + return (ret); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_online */ +/* */ +/* Routine Description: */ +/* */ +/* Determine if a logical drive is online */ +/* */ +/****************************************************************************/ +static int +ips_online(ips_ha_t *ha, ips_scb_t *scb) { + DBG("ips_online"); + + if (scb->target_id >= MAX_LOGICAL_DRIVES) + return (0); + + if ((scb->basic_status & GSC_STATUS_MASK) > 1) { + memset(&ha->adapt->logical_drive_info, 0, sizeof(ha->adapt->logical_drive_info)); + + return (0); + } + + if (scb->target_id < ha->adapt->logical_drive_info.no_of_log_drive && + ha->adapt->logical_drive_info.drive_info[scb->target_id].state != OFF_LINE && + ha->adapt->logical_drive_info.drive_info[scb->target_id].state != FREE && + ha->adapt->logical_drive_info.drive_info[scb->target_id].state != CRS && + ha->adapt->logical_drive_info.drive_info[scb->target_id].state != SYS) + return (1); + else + return (0); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_inquiry */ +/* */ +/* Routine Description: */ +/* */ +/* Simulate an inquiry command to a logical drive */ +/* */ +/****************************************************************************/ +static int +ips_inquiry(ips_ha_t *ha, ips_scb_t *scb) { + INQUIRYDATA inq; + + DBG("ips_inquiry"); + + memset(&inq, 0, sizeof(INQUIRYDATA)); + + inq.DeviceType = TYPE_DISK; + inq.DeviceTypeQualifier = 0; + inq.RemoveableMedia = 0; + inq.Versions = 0x1; /* SCSI I */ + inq.AdditionalLength = 31; + strncpy(inq.VendorId, "IBM ", 8); + strncpy(inq.ProductId, "SERVERAID ", 16); + strncpy(inq.ProductRevisionLevel, "1.00", 4); + + memcpy(scb->scsi_cmd->request_buffer, &inq, scb->scsi_cmd->request_bufflen); + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_rdcap */ +/* */ +/* Routine Description: */ +/* */ +/* Simulate a read capacity command to a logical drive */ +/* */ +/****************************************************************************/ +static int +ips_rdcap(ips_ha_t *ha, ips_scb_t *scb) { + CAPACITY_T *cap; + + DBG("ips_rdcap"); + + if (scb->scsi_cmd->bufflen < 8) + return (0); + + cap = (CAPACITY_T *) scb->scsi_cmd->request_buffer; + + cap->lba = htonl(ha->adapt->logical_drive_info.drive_info[scb->target_id].sector_count - 1); + cap->len = htonl((u32) IPS_BLKSIZE); + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_msense */ +/* */ +/* Routine Description: */ +/* */ +/* Simulate a mode sense command to a logical drive */ +/* */ +/****************************************************************************/ +static int +ips_msense(ips_ha_t *ha, ips_scb_t *scb) { + u16 heads; + u16 sectors; + u32 cylinders; + ips_mdata_t mdata; + + DBG("ips_msense"); + + if (ha->enq->ulDriveSize[scb->target_id] > 0x400000 && + (ha->enq->ucMiscFlag & 0x8) == 0) { + heads = NORM_MODE_HEADS; + sectors = NORM_MODE_SECTORS; + } else { + heads = COMP_MODE_HEADS; + sectors = COMP_MODE_SECTORS; + } + + cylinders = ha->enq->ulDriveSize[scb->target_id] / (heads * sectors); + + mdata.plh.plh_type = 0; + mdata.plh.plh_wp = 0; + mdata.plh.plh_bdl = 8; + + switch (scb->scsi_cmd->cmnd[2] & 0x3f) { + case 0x03: /* page 3 */ + mdata.pdata.pg3.pg_pc = 0x3; + mdata.pdata.pg3.pg_res1 = 0; + mdata.pdata.pg3.pg_len = sizeof(DADF_T); + mdata.plh.plh_len = 3 + mdata.plh.plh_bdl + mdata.pdata.pg3.pg_len; + mdata.pdata.pg3.pg_trk_z = 0; + mdata.pdata.pg3.pg_asec_z = 0; + mdata.pdata.pg3.pg_atrk_z = 0; + mdata.pdata.pg3.pg_atrk_v = 0; + mdata.pdata.pg3.pg_sec_t = htons(sectors); + mdata.pdata.pg3.pg_bytes_s = htons(IPS_BLKSIZE); + mdata.pdata.pg3.pg_intl = htons(1); + mdata.pdata.pg3.pg_trkskew = 0; + mdata.pdata.pg3.pg_cylskew = 0; + mdata.pdata.pg3.pg_res2 = 0; + mdata.pdata.pg3.pg_ins = 0; + mdata.pdata.pg3.pg_surf = 0; + mdata.pdata.pg3.pg_rmb = 0; + mdata.pdata.pg3.pg_hsec = 0; + mdata.pdata.pg3.pg_ssec = 1; + break; + + case 0x4: + mdata.pdata.pg4.pg_pc = 0x4; + mdata.pdata.pg4.pg_res1 = 0; + mdata.pdata.pg4.pg_len = sizeof(RDDG_T); + mdata.plh.plh_len = 3 + mdata.plh.plh_bdl + mdata.pdata.pg4.pg_len; + mdata.pdata.pg4.pg_cylu = (cylinders >> 8) & 0xffff; + mdata.pdata.pg4.pg_cyll = cylinders & 0xff; + mdata.pdata.pg4.pg_head = heads; + mdata.pdata.pg4.pg_wrpcompu = 0; + mdata.pdata.pg4.pg_wrpcompl = 0; + mdata.pdata.pg4.pg_redwrcur = 0; + mdata.pdata.pg4.pg_drstep = htons(1); + mdata.pdata.pg4.pg_landu = 0; + mdata.pdata.pg4.pg_landl = 0; + mdata.pdata.pg4.pg_res2 = 0; + break; + default: + return (0); + } /* end switch */ + + memcpy(scb->scsi_cmd->request_buffer, &mdata, scb->scsi_cmd->request_bufflen); + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_reqsen */ +/* */ +/* Routine Description: */ +/* */ +/* Simulate a request sense command to a logical drive */ +/* */ +/****************************************************************************/ +static int +ips_reqsen(ips_ha_t *ha, ips_scb_t *scb) { + char *sp; + + DBG("ips_reqsen"); + + sp = (char *) scb->scsi_cmd->sense_buffer; + memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer)); + + sp[0] = 0x70; + sp[3] = NO_SENSE; + sp[7] = 0xe; + sp[12] = NO_SENSE; + + return (0); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_free */ +/* */ +/* Routine Description: */ +/* */ +/* Free any allocated space for this controller */ +/* */ +/****************************************************************************/ +static void +ips_free(ips_ha_t *ha) { + int i; + + DBG("ips_free"); + + if (ha) { + if (ha->enq) { + kfree(ha->enq); + ha->enq = NULL; + } + + if (ha->conf) { + kfree(ha->conf); + ha->conf = NULL; + } + + if (ha->adapt) { + kfree(ha->adapt); + ha->adapt = NULL; + } + + if (ha->nvram) { + kfree(ha->nvram); + ha->nvram = NULL; + } + + if (ha->subsys) { + kfree(ha->subsys); + ha->subsys = NULL; + } + + if (ha->dummy) { + kfree(ha->dummy); + ha->dummy = NULL; + } + + if (ha->scbs) { + for (i = 0; i < ha->max_cmds; i++) { + if (ha->scbs[i].sg_list) + kfree(ha->scbs[i].sg_list); + } + + kfree(ha->scbs); + ha->scbs = NULL; + } /* end if */ + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_allocatescbs */ +/* */ +/* Routine Description: */ +/* */ +/* Allocate the command blocks */ +/* */ +/****************************************************************************/ +static int +ips_allocatescbs(ips_ha_t *ha) { + ips_scb_t *scb_p; + int i; + + DBG("ips_allocatescbs"); + + /* Allocate memory for the CCBs */ + ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_KERNEL|GFP_DMA); + + memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t)); + + for (i = 0; i < ha->max_cmds; i++) { + scb_p = &ha->scbs[i]; + + /* allocate S/G list */ + scb_p->sg_list = (SG_LIST *) kmalloc(sizeof(SG_LIST) * MAX_SG_ELEMENTS, GFP_KERNEL|GFP_DMA); + + if (! scb_p->sg_list) + return (0); + + /* add to the free list */ + if (i < ha->max_cmds - 1) { + scb_p->q_next = ha->scb_freelist; + ha->scb_freelist = scb_p; + } + } + + /* success */ + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_init_scb */ +/* */ +/* Routine Description: */ +/* */ +/* Initialize a CCB to default values */ +/* */ +/****************************************************************************/ +static void +ips_init_scb(ips_ha_t *ha, ips_scb_t *scb) { + SG_LIST *sg_list; + + DBG("ips_init_scb"); + + if (scb == NULL) + return ; + + sg_list = scb->sg_list; + + /* zero fill */ + memset(scb, 0, sizeof(ips_scb_t)); + memset(ha->dummy, 0, sizeof(BASIC_IO_CMD)); + + /* Initialize dummy command bucket */ + ha->dummy->op_code = 0xFF; + ha->dummy->ccsar = VIRT_TO_BUS(ha->dummy); + ha->dummy->command_id = MAX_CMDS; + + /* set bus address of scb */ + scb->scb_busaddr = VIRT_TO_BUS(scb); + scb->sg_list = sg_list; + + /* Neptune Fix */ + scb->cmd.basic_io.cccr = ILE; + scb->cmd.basic_io.ccsar = VIRT_TO_BUS(ha->dummy); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_get_scb */ +/* */ +/* Routine Description: */ +/* */ +/* Initialize a CCB to default values */ +/* */ +/* ASSUMED to be callled from within a lock */ +/* */ +/****************************************************************************/ +static ips_scb_t * +ips_getscb(ips_ha_t *ha) { + ips_scb_t *scb; + unsigned int cpu_flags; + + DBG("ips_getscb"); + + spin_lock_irqsave(&ha->scb_lock, cpu_flags); + if ((scb = ha->scb_freelist) == NULL) { + spin_unlock_irqrestore(&ha->scb_lock, cpu_flags); + + return (NULL); + } + + ha->scb_freelist = scb->q_next; + scb->q_next = NULL; + + spin_unlock_irqrestore(&ha->scb_lock, cpu_flags); + + ips_init_scb(ha, scb); + + return (scb); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_free_scb */ +/* */ +/* Routine Description: */ +/* */ +/* Return an unused CCB back to the free list */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static void +ips_freescb(ips_ha_t *ha, ips_scb_t *scb) { + unsigned int cpu_flags; + + DBG("ips_freescb"); + + /* check to make sure this is not our "special" scb */ + if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { + spin_lock_irqsave(&ha->scb_lock, cpu_flags); + scb->q_next = ha->scb_freelist; + ha->scb_freelist = scb; + spin_unlock_irqrestore(&ha->scb_lock, cpu_flags); + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_reset_adapter */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller */ +/* */ +/****************************************************************************/ +static int +ips_reset_adapter(ips_ha_t *ha) { + u8 Isr; + u8 Cbsp; + u8 PostByte[MAX_POST_BYTES]; + u8 ConfigByte[MAX_CONFIG_BYTES]; + int i, j; + int reset_counter; + + DBG("ips_reset_adapter"); + +#if IPS_DEBUG >= 1 + printk(KERN_WARNING "ips_reset_adapter: io addr: %x, irq: %d\n", + ha->io_addr, ha->irq); +#endif + + reset_counter = 0; + + while (reset_counter < 2) { + reset_counter++; + + outb(RST, ha->io_addr + SCPR); + MDELAY(ONE_SEC); + outb(0, ha->io_addr + SCPR); + MDELAY(ONE_SEC); + + for (i = 0; i < MAX_POST_BYTES; i++) { + for (j = 0; j < 45; j++) { + Isr = inb(ha->io_addr + HISR); + if (Isr & GHI) + break; + + MDELAY(ONE_SEC); + } + + if (j >= 45) { + /* error occured */ + if (reset_counter < 2) + continue; + else + /* reset failed */ + return (0); + } + + PostByte[i] = inb(ha->io_addr + ISPR); + outb(Isr, ha->io_addr + HISR); + } + + if (PostByte[0] < GOOD_POST_BASIC_STATUS) { + printk("(%s%d) reset controller fails (post status %x %x).\n", + ips_name, ha->host_num, PostByte[0], PostByte[1]); + + return (0); + } + + for (i = 0; i < MAX_CONFIG_BYTES; i++) { + for (j = 0; j < 240; j++) { + Isr = inb(ha->io_addr + HISR); + if (Isr & GHI) + break; + + MDELAY(ONE_SEC); /* 100 msec */ + } + + if (j >= 240) { + /* error occured */ + if (reset_counter < 2) + continue; + else + /* reset failed */ + return (0); + } + + ConfigByte[i] = inb(ha->io_addr + ISPR); + outb(Isr, ha->io_addr + HISR); + } + + if (ConfigByte[0] == 0 && ConfigByte[1] == 2) { + printk("(%s%d) reset controller fails (status %x %x).\n", + ips_name, ha->host_num, ConfigByte[0], ConfigByte[1]); + + return (0); + } + + for (i = 0; i < 240; i++) { + Cbsp = inb(ha->io_addr + CBSP); + + if ((Cbsp & OP) == 0) + break; + + MDELAY(ONE_SEC); + } + + if (i >= 240) { + /* error occured */ + if (reset_counter < 2) + continue; + else + /* reset failed */ + return (0); + } + + /* setup CCCR */ + outw(0x1010, ha->io_addr + CCCR); + + /* Enable busmastering */ + outb(EBM, ha->io_addr + SCPR); + + /* setup status queues */ + ips_statinit(ha); + + /* Enable interrupts */ + outb(EI, ha->io_addr + HISR); + + /* if we get here then everything went OK */ + break; + } + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_statinit */ +/* */ +/* Routine Description: */ +/* */ +/* Initialize the status queues on the controller */ +/* */ +/****************************************************************************/ +static void +ips_statinit(ips_ha_t *ha) { + u32 phys_status_start; + + DBG("ips_statinit"); + + ha->adapt->p_status_start = ha->adapt->status; + ha->adapt->p_status_end = ha->adapt->status + MAX_CMDS; + ha->adapt->p_status_tail = ha->adapt->status; + + phys_status_start = VIRT_TO_BUS(ha->adapt->status); + outl(phys_status_start, ha->io_addr + SQSR); + outl(phys_status_start + STATUS_Q_SIZE, ha->io_addr + SQER); + outl(phys_status_start + STATUS_SIZE, ha->io_addr + SQHR); + outl(phys_status_start, ha->io_addr + SQTR); + + ha->adapt->hw_status_start = phys_status_start; + ha->adapt->hw_status_tail = phys_status_start; +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_statupd */ +/* */ +/* Routine Description: */ +/* */ +/* Remove an element from the status queue */ +/* */ +/****************************************************************************/ +static int +ips_statupd(ips_ha_t *ha) { + int command_id; + + DBG("ips_statupd"); + + if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { + ha->adapt->p_status_tail++; + ha->adapt->hw_status_tail += sizeof(STATUS); + } else { + ha->adapt->p_status_tail = ha->adapt->p_status_start; + ha->adapt->hw_status_tail = ha->adapt->hw_status_start; + } + + outl(ha->adapt->hw_status_tail, ha->io_addr + SQTR); + + command_id = ha->adapt->p_status_tail->command_id; + + return (command_id); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_issue */ +/* */ +/* Routine Description: */ +/* */ +/* Send a command down to the controller */ +/* */ +/* ASSUMED to be called from within a lock */ +/* */ +/****************************************************************************/ +static int +ips_issue(ips_ha_t *ha, ips_scb_t *scb) { + u32 TimeOut; + u16 val; + + DBG("ips_issue"); + +#if IPS_DEBUG >= 10 + if (scb->scsi_cmd) + printk(KERN_NOTICE "%s: ips_issue: cmd 0x%X id %d (%d %d %d)\n", + ips_name, + scb->cdb[0], + scb->cmd.basic_io.command_id, + scb->bus, + scb->target_id, + scb->lun); + else + printk(KERN_NOTICE "%s: ips_issue: logical cmd id %d\n", + ips_name, + scb->cmd.basic_io.command_id); +#if IPS_DEBUG >= 11 + MDELAY(ONE_SEC); +#endif +#endif + + TimeOut = 0; + + while ((val = inw(ha->io_addr + CCCR)) & SEMAPHORE) { + UDELAY(1000); + + if (++TimeOut >= SEMAPHORE_TIMEOUT) { + if (!(val & START_STOP_BIT)) + break; + + printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n", + ips_name, ha->host_num, val); + printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n", + ips_name, ha->host_num); + + return (IPS_FAILURE); + } /* end if */ + } /* end while */ + + outl(scb->scb_busaddr, ha->io_addr + CCSAR); + outw(START_COMMAND, ha->io_addr + CCCR); + + return (IPS_SUCCESS); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_isintr */ +/* */ +/* Routine Description: */ +/* */ +/* Test to see if an interrupt is for us */ +/* */ +/****************************************************************************/ +static int +ips_isintr(ips_ha_t *ha) { + u8 Isr; + + DBG("ips_isintr"); + + Isr = inb(ha->io_addr + HISR); + + if (Isr == 0xFF) + /* ?!?! Nothing really there */ + return (0); + + if (Isr & SCE) + return (1); + else if (Isr & (SQO | GHI)) { + /* status queue overflow or GHI */ + /* just clear the interrupt */ + outb(Isr, ha->io_addr + HISR); + } + + return (0); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_wait */ +/* */ +/* Routine Description: */ +/* */ +/* Wait for a command to complete */ +/* */ +/****************************************************************************/ +static int +ips_wait(ips_ha_t *ha, int time, int intr) { + int ret; + + DBG("ips_wait"); + + ret = IPS_FAILURE; + + time *= ONE_SEC; /* convert seconds to milliseconds */ + + while (time > 0) { + if (intr == IPS_INTR_OFF) { + if (ha->waitflag == FALSE) { + /* + * controller generated an interupt to + * acknowledge completion of the command + * and ips_intr() has serviced the interrupt. + */ + ret = IPS_SUCCESS; + break; + } + + /* + * NOTE: Interrupts are disabled here + * On an SMP system interrupts will only + * be disabled on one processor. + * So, ultimately we still need to set the + * "I'm in the interrupt handler flag" + */ + while (test_and_set_bit(IPS_IN_INTR, &ha->flags)) + UDELAY(1000); + + ips_intr(ha); + + clear_bit(IPS_IN_INTR, &ha->flags); + + } else { + if (ha->waitflag == FALSE) { + ret = IPS_SUCCESS; + break; + } + } + + UDELAY(1000); /* 1 milisecond */ + time--; + } + + return (ret); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_write_driver_status */ +/* */ +/* Routine Description: */ +/* */ +/* Write OS/Driver version to Page 5 of the nvram on the controller */ +/* */ +/****************************************************************************/ +static int +ips_write_driver_status(ips_ha_t *ha) { + DBG("ips_write_driver_status"); + + if (!ips_readwrite_page5(ha, FALSE)) { + printk(KERN_WARNING "(%s%d) unable to read NVRAM page 5.\n", + ips_name, ha->host_num); + + return (0); + } + + /* check to make sure the page has a valid */ + /* signature */ + if (ha->nvram->signature != NVRAM_PAGE5_SIGNATURE) { +#if IPS_DEBUG >= 1 + printk("(%s%d) NVRAM page 5 has an invalid signature: %X.\n", + ips_name, ha->host_num, ha->nvram->signature); +#endif + return (1); + } + +#if IPS_DEBUG >= 2 + printk("(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.\n", + ips_name, ha->host_num, ha->nvram->adapter_type, ha->nvram->adapter_slot, + ha->nvram->bios_high[0], ha->nvram->bios_high[1], + ha->nvram->bios_high[2], ha->nvram->bios_high[3], + ha->nvram->bios_low[0], ha->nvram->bios_low[1], + ha->nvram->bios_low[2], ha->nvram->bios_low[3]); +#endif + + /* save controller type */ + ha->ad_type = ha->nvram->adapter_type; + + /* change values (as needed) */ + ha->nvram->operating_system = OS_LINUX; + strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); + strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4); + + /* now update the page */ + if (!ips_readwrite_page5(ha, TRUE)) { + printk(KERN_WARNING "(%s%d) unable to write NVRAM page 5.\n", + ips_name, ha->host_num); + + return (0); + } + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_read_adapter_status */ +/* */ +/* Routine Description: */ +/* */ +/* Do an Inquiry command to the adapter */ +/* */ +/****************************************************************************/ +static int +ips_read_adapter_status(ips_ha_t *ha) { + ips_scb_t *scb; + int ret; + + DBG("ips_read_adapter_status"); + + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_cmd_timeout; + scb->cdb[0] = ENQUIRY; + + scb->cmd.basic_io.op_code = ENQUIRY; + scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.basic_io.sg_count = 0; + scb->cmd.basic_io.sg_addr = VIRT_TO_BUS(ha->enq); + scb->cmd.basic_io.lba = 0; + scb->cmd.basic_io.sector_count = 0; + scb->cmd.basic_io.log_drv = 0; + scb->cmd.basic_io.reserved = 0; + + /* send command */ + ret = ips_send_wait(ha, scb, ips_cmd_timeout); + if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + return (0); + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_read_subsystem_parameters */ +/* */ +/* Routine Description: */ +/* */ +/* Read subsystem parameters from the adapter */ +/* */ +/****************************************************************************/ +static int +ips_read_subsystem_parameters(ips_ha_t *ha) { + ips_scb_t *scb; + int ret; + + DBG("ips_read_subsystem_parameters"); + + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_cmd_timeout; + scb->cdb[0] = GET_SUBSYS_PARAM; + + scb->cmd.basic_io.op_code = GET_SUBSYS_PARAM; + scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.basic_io.sg_count = 0; + scb->cmd.basic_io.sg_addr = VIRT_TO_BUS(ha->subsys); + scb->cmd.basic_io.lba = 0; + scb->cmd.basic_io.sector_count = 0; + scb->cmd.basic_io.log_drv = 0; + scb->cmd.basic_io.reserved = 0; + + /* send command */ + ret = ips_send_wait(ha, scb, ips_cmd_timeout); + if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + return (0); + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_read_config */ +/* */ +/* Routine Description: */ +/* */ +/* Read the configuration on the adapter */ +/* */ +/****************************************************************************/ +static int +ips_read_config(ips_ha_t *ha) { + ips_scb_t *scb; + int i; + int ret; + + DBG("ips_read_config"); + + /* set defaults for initiator IDs */ + ha->conf->init_id[0] = IPS_ADAPTER_ID; + for (i = 1; i < 4; i++) + ha->conf->init_id[i] = 7; + + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_cmd_timeout; + scb->cdb[0] = READ_NVRAM_CONFIGURATION; + + scb->cmd.basic_io.op_code = READ_NVRAM_CONFIGURATION; + scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.basic_io.sg_addr = VIRT_TO_BUS(ha->conf); + + /* send command */ + if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout)) == IPS_FAILURE) || + (ret == IPS_SUCCESS_IMM) || + ((scb->basic_status & GSC_STATUS_MASK) > 1)) { + + memset(ha->conf, 0, sizeof(CONFCMD)); + + /* reset initiator IDs */ + ha->conf->init_id[0] = IPS_ADAPTER_ID; + for (i = 1; i < 4; i++) + ha->conf->init_id[i] = 7; + + return (0); + } + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_readwrite_page5 */ +/* */ +/* Routine Description: */ +/* */ +/* Read the configuration on the adapter */ +/* */ +/****************************************************************************/ +static int +ips_readwrite_page5(ips_ha_t *ha, int write) { + ips_scb_t *scb; + int ret; + + DBG("ips_readwrite_page5"); + + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_cmd_timeout; + scb->cdb[0] = RW_NVRAM_PAGE; + + scb->cmd.nvram.op_code = RW_NVRAM_PAGE; + scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.nvram.page = 5; + scb->cmd.nvram.write = write; + scb->cmd.nvram.buffer_addr = VIRT_TO_BUS(ha->nvram); + scb->cmd.nvram.reserved = 0; + scb->cmd.nvram.reserved2 = 0; + + /* issue the command */ + if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout)) == IPS_FAILURE) || + (ret == IPS_SUCCESS_IMM) || + ((scb->basic_status & GSC_STATUS_MASK) > 1)) { + + memset(ha->nvram, 0, sizeof(NVRAM_PAGE5)); + + return (0); + } + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_clear_adapter */ +/* */ +/* Routine Description: */ +/* */ +/* Clear the stripe lock tables */ +/* */ +/****************************************************************************/ +static int +ips_clear_adapter(ips_ha_t *ha) { + ips_scb_t *scb; + int ret; + + DBG("ips_clear_adapter"); + + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_reset_timeout; + scb->cdb[0] = CONFIG_SYNC; + + scb->cmd.config_sync.op_code = CONFIG_SYNC; + scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.config_sync.channel = 0; + scb->cmd.config_sync.source_target = POCL; + scb->cmd.config_sync.reserved = 0; + scb->cmd.config_sync.reserved2 = 0; + scb->cmd.config_sync.reserved3 = 0; + + /* issue command */ + ret = ips_send_wait(ha, scb, ips_reset_timeout); + if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + return (0); + + /* send unlock stripe command */ + ips_init_scb(ha, scb); + + scb->cdb[0] = GET_ERASE_ERROR_TABLE; + scb->timeout = ips_reset_timeout; + + scb->cmd.unlock_stripe.op_code = GET_ERASE_ERROR_TABLE; + scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.unlock_stripe.log_drv = 0; + scb->cmd.unlock_stripe.control = CSL; + scb->cmd.unlock_stripe.reserved = 0; + scb->cmd.unlock_stripe.reserved2 = 0; + scb->cmd.unlock_stripe.reserved3 = 0; + + /* issue command */ + ret = ips_send_wait(ha, scb, ips_reset_timeout); + if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + return (0); + + return (1); +} + +#if defined (MODULE) + +Scsi_Host_Template driver_template = IPS; + + #include "scsi_module.c" + +#endif + + +/* + * Overrides for Emacs so that we almost follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/ips.h linux/drivers/scsi/ips.h --- v2.3.15/linux/drivers/scsi/ips.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/ips.h Tue Aug 31 16:12:42 1999 @@ -0,0 +1,838 @@ +/*****************************************************************************/ +/* ips.h -- driver for the IBM ServeRAID adapter */ +/* */ +/* Written By: Keith Mitchell, IBM Corporation */ +/* */ +/* Copyright (C) 1999 IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* NO WARRANTY */ +/* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */ +/* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */ +/* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */ +/* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */ +/* solely responsible for determining the appropriateness of using and */ +/* distributing the Program and assumes all risks associated with its */ +/* exercise of rights under this Agreement, including but not limited to */ +/* the risks and costs of program errors, damage to or loss of data, */ +/* programs or equipment, and unavailability or interruption of operations. */ +/* */ +/* DISCLAIMER OF LIABILITY */ +/* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */ +/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ +/* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */ +/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */ +/* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */ +/* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */ +/* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* Bugs/Comments/Suggestions should be mailed to: */ +/* ipslinux@us.ibm.com */ +/* */ +/*****************************************************************************/ + +#ifndef _IPS_H_ + #define _IPS_H_ + + #include + #include + #include + + /* Prototypes */ + extern int ips_detect(Scsi_Host_Template *); + extern int ips_release(struct Scsi_Host *); + extern int ips_abort(Scsi_Cmnd *); + extern int ips_reset(Scsi_Cmnd *, unsigned int); + extern int ips_eh_abort(Scsi_Cmnd *); + extern int ips_eh_reset(Scsi_Cmnd *); + extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *)); + extern int ips_biosparam(Disk *, kdev_t, int *); + extern const char * ips_info(struct Scsi_Host *); + extern void do_ipsintr(int, void *, struct pt_regs *); + + /* + * Some handy macros + */ + #ifndef LinuxVersionCode + #define LinuxVersionCode(x,y,z) (((x)<<16)+((y)<<8)+(z)) + #endif + + #define HA(x) ((ips_ha_t *) x->hostdata) + #define IPS_COMMAND_ID(ha, scb) (int) (scb - ha->scbs) + #define VIRT_TO_BUS(x) (unsigned int)virt_to_bus((void *) x) + + #define UDELAY udelay + #define MDELAY mdelay + + #define verify_area_20(t,a,sz) (0) /* success */ + #define PUT_USER put_user + #define __PUT_USER __put_user + #define PUT_USER_RET put_user_ret + #define GET_USER get_user + #define __GET_USER __get_user + #define GET_USER_RET get_user_ret + +/* + * Adapter address map equates + */ + #define HISR 0x08 /* Host Interrupt Status Reg */ + #define CCSAR 0x10 /* Cmd Channel System Addr Reg */ + #define CCCR 0x14 /* Cmd Channel Control Reg */ + #define SQHR 0x20 /* Status Q Head Reg */ + #define SQTR 0x24 /* Status Q Tail Reg */ + #define SQER 0x28 /* Status Q End Reg */ + #define SQSR 0x2C /* Status Q Start Reg */ + #define SCPR 0x05 /* Subsystem control port reg */ + #define ISPR 0x06 /* interrupt status port reg */ + #define CBSP 0x07 /* CBSP register */ + +/* + * Adapter register bit equates + */ + #define GHI 0x04 /* HISR General Host Interrupt */ + #define SQO 0x02 /* HISR Status Q Overflow */ + #define SCE 0x01 /* HISR Status Channel Enqueue */ + #define SEMAPHORE 0x08 /* CCCR Semaphore Bit */ + #define ILE 0x10 /* CCCR ILE Bit */ + #define START_COMMAND 0x101A /* CCCR Start Command Channel */ + #define START_STOP_BIT 0x0002 /* CCCR Start/Stop Bit */ + #define RST 0x80 /* SCPR Reset Bit */ + #define EBM 0x02 /* SCPR Enable Bus Master */ + #define EI 0x80 /* HISR Enable Interrupts */ + #define OP 0x01 /* OP bit in CBSP */ + +/* + * Adapter Command ID Equates + */ + #define GET_LOGICAL_DRIVE_INFO 0x19 + #define GET_SUBSYS_PARAM 0x40 + #define READ_NVRAM_CONFIGURATION 0x38 + #define RW_NVRAM_PAGE 0xBC + #define IPS_READ 0x02 + #define IPS_WRITE 0x03 + #define ENQUIRY 0x05 + #define FLUSH_CACHE 0x0A + #define NORM_STATE 0x00 + #define READ_SCATTER_GATHER 0x82 + #define WRITE_SCATTER_GATHER 0x83 + #define DIRECT_CDB 0x04 + #define DIRECT_CDB_SCATTER_GATHER 0x84 + #define CONFIG_SYNC 0x58 + #define POCL 0x30 + #define GET_ERASE_ERROR_TABLE 0x17 + #define RESET_CHANNEL 0x1A + #define CSL 0xFF + #define ADAPT_RESET 0xFF + +/* + * Adapter Equates + */ + #define IPS_MAX_ADAPTERS 16 + #define IPS_MAX_IOCTL 1 + #define IPS_MAX_IOCTL_QUEUE 8 + #define IPS_MAX_QUEUE 128 + #define IPS_BLKSIZE 512 + #define MAX_SG_ELEMENTS 17 + #define MAX_LOGICAL_DRIVES 8 + #define MAX_CHANNELS 3 + #define MAX_TARGETS 15 + #define MAX_CHUNKS 16 + #define MAX_CMDS 64 + #define IPS_MAX_XFER 0x10000 + #define COMP_MODE_HEADS 128 + #define COMP_MODE_SECTORS 32 + #define NORM_MODE_HEADS 254 + #define NORM_MODE_SECTORS 63 + #define NVRAM_PAGE5_SIGNATURE 0xFFDDBB99 + #define MAX_POST_BYTES 0x02 + #define MAX_CONFIG_BYTES 0x02 + #define GOOD_POST_BASIC_STATUS 0x80 + #define SEMAPHORE_TIMEOUT 2000 + #define IPS_INTR_OFF 0 + #define IPS_INTR_ON 1 + #define IPS_ADAPTER_ID 0xF + #define IPS_VENDORID 0x1014 + #define IPS_DEVICEID 0x002E + #define TIMEOUT_10 0x10 + #define TIMEOUT_60 0x20 + #define TIMEOUT_20M 0x30 + #define STATUS_SIZE 4 + #define STATUS_Q_SIZE (MAX_CMDS+1) * STATUS_SIZE + #define ONE_MSEC 1 + #define ONE_SEC 1000 + +/* + * Adapter Basic Status Codes + */ + #define BASIC_STATUS_MASK 0xFF + #define GSC_STATUS_MASK 0x0F + #define SSUCCESS 0x00 + #define RECOVERED_ERROR 0x01 + #define IPS_CHECK_CONDITION 0x02 + #define INVAL_OPCO 0x03 + #define INVAL_CMD_BLK 0x04 + #define INVAL_PARM_BLK 0x05 + #define IPS_BUSY 0x08 + #define ADAPT_HARDWARE_ERROR 0x09 + #define ADAPT_FIRMWARE_ERROR 0x0A + #define CMD_CMPLT_WERROR 0x0C + #define LOG_DRV_ERROR 0x0D + #define CMD_TIMEOUT 0x0E + #define PHYS_DRV_ERROR 0x0F + +/* + * Adapter Extended Status Equates + */ + #define SELECTION_TIMEOUT 0xF0 + #define DATA_OVER_UNDER_RUN 0xF2 + #define EXT_HOST_RESET 0xF7 + #define EXT_DEVICE_RESET 0xF8 + #define EXT_RECOVERY 0xFC + #define EXT_CHECK_CONDITION 0xFF + +/* + * Operating System Defines + */ + #define OS_WINDOWS_NT 0x01 + #define OS_NETWARE 0x02 + #define OS_OPENSERVER 0x03 + #define OS_UNIXWARE 0x04 + #define OS_SOLARIS 0x05 + #define OS_OS2 0x06 + #define OS_LINUX 0x07 + #define OS_FREEBSD 0x08 + +/* + * Adapter Command/Status Packet Definitions + */ + #define IPS_SUCCESS 0x01 /* Successfully completed */ + #define IPS_SUCCESS_IMM 0x02 /* Success - Immediately */ + #define IPS_FAILURE 0x04 /* Completed with Error */ + +/* + * Logical Drive Equates + */ + #define OFF_LINE 0x02 + #define OKAY 0x03 + #define FREE 0x00 + #define SYS 0x06 + #define CRS 0x24 + +/* + * DCDB Table Equates + */ + #define NO_DISCONNECT 0x00 + #define DISCONNECT_ALLOWED 0x80 + #define NO_AUTO_REQUEST_SENSE 0x40 + #define DATA_IN 0x01 + #define DATA_OUT 0x02 + #define TRANSFER_64K 0x08 + #define NOTIMEOUT 0x00 + #define TIMEOUT10 0x10 + #define TIMEOUT60 0x20 + #define TIMEOUT20M 0x30 + +/* + * Host adapter Flags (bit numbers) + */ + #define IPS_IN_INTR 0 + #define IPS_IN_ABORT 1 + #define IPS_IN_RESET 2 + +/* + * SCB Flags + */ + #define SCB_ACTIVE 0x00001 + #define SCB_WAITING 0x00002 + +/* + * Passthru stuff + */ + #define COPPUSRCMD (('C'<<8) | 65) + #define IPS_NUMCTRLS (('C'<<8) | 68) + #define IPS_CTRLINFO (('C'<<8) | 69) + +/* + * Scsi_Host Template + */ + #define IPS { \ + next : NULL, \ + module : NULL, \ + proc_dir : NULL, \ + proc_info : NULL, \ + name : NULL, \ + detect : ips_detect, \ + release : ips_release, \ + info : ips_info, \ + command : NULL, \ + queuecommand : ips_queue, \ + eh_strategy_handler : NULL, \ + eh_abort_handler : ips_eh_abort, \ + eh_device_reset_handler : NULL, \ + eh_bus_reset_handler : NULL, \ + eh_host_reset_handler : ips_eh_reset, \ + abort : ips_abort, \ + reset : ips_reset, \ + slave_attach : NULL, \ + bios_param : ips_biosparam, \ + can_queue : 0, \ + this_id: -1, \ + sg_tablesize : MAX_SG_ELEMENTS, \ + cmd_per_lun: 16, \ + present : 0, \ + unchecked_isa_dma : 0, \ + use_clustering : ENABLE_CLUSTERING, \ + use_new_eh_code : 1 \ + } + +/* + * IBM PCI Raid Command Formats + */ +typedef struct { + u8 op_code; + u8 command_id; + u8 log_drv; + u8 sg_count; + u32 lba; + u32 sg_addr; + u16 sector_count; + u16 reserved; + u32 ccsar; + u32 cccr; +} BASIC_IO_CMD, *PBASIC_IO_CMD; + +typedef struct { + u8 op_code; + u8 command_id; + u16 reserved; + u32 reserved2; + u32 buffer_addr; + u32 reserved3; + u32 ccsar; + u32 cccr; +} LOGICAL_INFO, *PLOGICAL_INFO; + +typedef struct { + u8 op_code; + u8 command_id; + u8 reserved; + u8 reserved2; + u32 reserved3; + u32 buffer_addr; + u32 reserved4; +} IOCTL_INFO, *PIOCTL_INFO; + +typedef struct { + u8 op_code; + u8 command_id; + u16 reserved; + u32 reserved2; + u32 dcdb_address; + u32 reserved3; + u32 ccsar; + u32 cccr; +} DCDB_CMD, *PDCDB_CMD; + +typedef struct { + u8 op_code; + u8 command_id; + u8 channel; + u8 source_target; + u32 reserved; + u32 reserved2; + u32 reserved3; + u32 ccsar; + u32 cccr; +} CONFIG_SYNC_CMD, *PCONFIG_SYNC_CMD; + +typedef struct { + u8 op_code; + u8 command_id; + u8 log_drv; + u8 control; + u32 reserved; + u32 reserved2; + u32 reserved3; + u32 ccsar; + u32 cccr; +} UNLOCK_STRIPE_CMD, *PUNLOCK_STRIPE_CMD; + +typedef struct { + u8 op_code; + u8 command_id; + u8 reserved; + u8 state; + u32 reserved2; + u32 reserved3; + u32 reserved4; + u32 ccsar; + u32 cccr; +} FLUSH_CACHE_CMD, *PFLUSH_CACHE_CMD; + +typedef struct { + u8 op_code; + u8 command_id; + u8 reserved; + u8 desc; + u32 reserved2; + u32 buffer_addr; + u32 reserved3; + u32 ccsar; + u32 cccr; +} STATUS_CMD, *PSTATUS_CMD; + +typedef struct { + u8 op_code; + u8 command_id; + u8 page; + u8 write; + u32 reserved; + u32 buffer_addr; + u32 reserved2; + u32 ccsar; + u32 cccr; +} NVRAM_CMD, *PNVRAM_CMD; + +typedef union { + BASIC_IO_CMD basic_io; + LOGICAL_INFO logical_info; + IOCTL_INFO ioctl_info; + DCDB_CMD dcdb; + CONFIG_SYNC_CMD config_sync; + UNLOCK_STRIPE_CMD unlock_stripe; + FLUSH_CACHE_CMD flush_cache; + STATUS_CMD status; + NVRAM_CMD nvram; +} HOST_COMMAND, *PHOST_COMMAND; + +typedef struct { + u8 logical_id; + u8 reserved; + u8 raid_level; + u8 state; + u32 sector_count; +} DRIVE_INFO, *PDRIVE_INFO; + +typedef struct { + u8 no_of_log_drive; + u8 reserved[3]; + DRIVE_INFO drive_info[MAX_LOGICAL_DRIVES]; +} LOGICAL_DRIVE_INFO, *PLOGICAL_DRIVE_INFO; + +typedef struct { + u8 ha_num; + u8 bus_num; + u8 id; + u8 device_type; + u32 data_len; + u32 data_ptr; + u8 scsi_cdb[12]; + u32 data_counter; + u32 block_size; +} NON_DISK_DEVICE_INFO, *PNON_DISK_DEVICE_INFO; + +typedef struct { + u8 device_address; + u8 cmd_attribute; + u16 transfer_length; + u32 buffer_pointer; + u8 cdb_length; + u8 sense_length; + u8 sg_count; + u8 reserved; + u8 scsi_cdb[12]; + u8 sense_info[64]; + u8 scsi_status; + u8 reserved2[3]; +} DCDB_TABLE, *PDCDB_TABLE; + +typedef struct { + volatile u8 reserved; + volatile u8 command_id; + volatile u8 basic_status; + volatile u8 extended_status; +} STATUS, *PSTATUS; + +typedef struct { + STATUS status[MAX_CMDS + 1]; + volatile PSTATUS p_status_start; + volatile PSTATUS p_status_end; + volatile PSTATUS p_status_tail; + volatile u32 hw_status_start; + volatile u32 hw_status_tail; + LOGICAL_DRIVE_INFO logical_drive_info; +} ADAPTER_AREA, *PADAPTER_AREA; + +typedef struct { + u8 ucLogDriveCount; + u8 ucMiscFlag; + u8 ucSLTFlag; + u8 ucBSTFlag; + u8 ucPwrChgCnt; + u8 ucWrongAdrCnt; + u8 ucUnidentCnt; + u8 ucNVramDevChgCnt; + u8 CodeBlkVersion[8]; + u8 BootBlkVersion[8]; + u32 ulDriveSize[MAX_LOGICAL_DRIVES]; + u8 ucConcurrentCmdCount; + u8 ucMaxPhysicalDevices; + u16 usFlashRepgmCount; + u8 ucDefunctDiskCount; + u8 ucRebuildFlag; + u8 ucOfflineLogDrvCount; + u8 ucCriticalDrvCount; + u16 usConfigUpdateCount; + u8 ucBlkFlag; + u8 reserved; + u16 usAddrDeadDisk[MAX_CHANNELS * MAX_TARGETS]; +} ENQCMD, *PENQCMD; + +typedef struct { + u8 ucInitiator; + u8 ucParameters; + u8 ucMiscFlag; + u8 ucState; + u32 ulBlockCount; + u8 ucDeviceId[28]; +} DEVSTATE, *PDEVSTATE; + +typedef struct { + u8 ucChn; + u8 ucTgt; + u16 ucReserved; + u32 ulStartSect; + u32 ulNoOfSects; +} CHUNK, *PCHUNK; + +typedef struct { + u16 ucUserField; + u8 ucState; + u8 ucRaidCacheParam; + u8 ucNoOfChunkUnits; + u8 ucStripeSize; + u8 ucParams; + u8 ucReserved; + u32 ulLogDrvSize; + CHUNK chunk[MAX_CHUNKS]; +} LOGICAL_DRIVE, *PLOGICAL_DRIVE; + +typedef struct { + u8 board_disc[8]; + u8 processor[8]; + u8 ucNoChanType; + u8 ucNoHostIntType; + u8 ucCompression; + u8 ucNvramType; + u32 ulNvramSize; +} HARDWARE_DISC, *PHARDWARE_DISC; + +typedef struct { + u8 ucLogDriveCount; + u8 ucDateD; + u8 ucDateM; + u8 ucDateY; + u8 init_id[4]; + u8 host_id[12]; + u8 time_sign[8]; + + struct { + u32 usCfgDrvUpdateCnt:16; + u32 ConcurDrvStartCnt:4; + u32 StartupDelay:4; + u32 auto_rearrange:1; + u32 cd_boot:1; + u32 cluster:1; + u32 reserved:5; + } UserOpt; + + u16 user_field; + u8 ucRebuildRate; + u8 ucReserve; + HARDWARE_DISC hardware_disc; + LOGICAL_DRIVE logical_drive[MAX_LOGICAL_DRIVES]; + DEVSTATE dev[MAX_CHANNELS][MAX_TARGETS+1]; + u8 reserved[512]; + +} CONFCMD, *PCONFCMD; + +typedef struct { + u32 signature; + u8 reserved; + u8 adapter_slot; + u16 adapter_type; + u8 bios_high[4]; + u8 bios_low[4]; + u16 reserved2; + u8 reserved3; + u8 operating_system; + u8 driver_high[4]; + u8 driver_low[4]; + u8 reserved4[100]; +} NVRAM_PAGE5, *PNVRAM_PAGE5; + +typedef struct _SUBSYS_PARAM { + u32 param[128]; +} SUBSYS_PARAM, *PSUBSYS_PARAM; + +/* + * Inquiry Data Format + */ +typedef struct { + u8 DeviceType:5; + u8 DeviceTypeQualifier:3; + u8 DeviceTypeModifier:7; + u8 RemoveableMedia:1; + u8 Versions; + u8 ResponseDataFormat; + u8 AdditionalLength; + u16 Reserved; + u8 SoftReset:1; + u8 CommandQueue:1; + u8 Reserved2:1; + u8 LinkedCommands:1; + u8 Synchronous:1; + u8 Wide16Bit:1; + u8 Wide32Bit:1; + u8 RelativeAddressing:1; + u8 VendorId[8]; + u8 ProductId[16]; + u8 ProductRevisionLevel[4]; + u8 VendorSpecific[20]; + u8 Reserved3[40]; +} INQUIRYDATA, *PINQUIRYDATA; + +/* + * Read Capacity Data Format + */ +typedef struct { + u32 lba; + u32 len; +} CAPACITY_T; + +/* + * Sense Data Format + */ +typedef struct { + u8 pg_pc:6; /* Page Code */ + u8 pg_res1:2; /* Reserved */ + u8 pg_len; /* Page Length */ + u16 pg_trk_z; /* Tracks per zone */ + u16 pg_asec_z; /* Alternate sectors per zone */ + u16 pg_atrk_z; /* Alternate tracks per zone */ + u16 pg_atrk_v; /* Alternate tracks per volume */ + u16 pg_sec_t; /* Sectors per track */ + u16 pg_bytes_s; /* Bytes per physical sectors */ + u16 pg_intl; /* Interleave */ + u16 pg_trkskew; /* Track skew factor */ + u16 pg_cylskew; /* Cylinder Skew Factor */ + u32 pg_res2:27; /* Reserved */ + u32 pg_ins:1; /* Inhibit Slave */ + u32 pg_surf:1; /* Allocate Surface Sectors */ + u32 pg_rmb:1; /* Removeable */ + u32 pg_hsec:1; /* Hard sector formatting */ + u32 pg_ssec:1; /* Soft sector formatting */ +} DADF_T; + +typedef struct { + u8 pg_pc:6; /* Page Code */ + u8 pg_res1:2; /* Reserved */ + u8 pg_len; /* Page Length */ + u16 pg_cylu; /* Number of cylinders (upper) */ + u8 pg_cyll; /* Number of cylinders (lower) */ + u8 pg_head; /* Number of heads */ + u16 pg_wrpcompu; /* Write precomp (upper) */ + u32 pg_wrpcompl:8; /* Write precomp (lower) */ + u32 pg_redwrcur:24; /* Reduced write current */ + u32 pg_drstep:16; /* Drive step rate */ + u32 pg_landu:16; /* Landing zone cylinder (upper) */ + u32 pg_landl:8; /* Landing zone cylinder (lower) */ + u32 pg_res2:24; /* Reserved */ +} RDDG_T; + +struct blk_desc { + u8 bd_dencode; + u8 bd_nblks1; + u8 bd_nblks2; + u8 bd_nblks3; + u8 bd_res; + u8 bd_blen1; + u8 bd_blen2; + u8 bd_blen3; +}; + +typedef struct { + u8 plh_len; /* Data length */ + u8 plh_type; /* Medium type */ + u8 plh_res:7; /* Reserved */ + u8 plh_wp:1; /* Write protect */ + u8 plh_bdl; /* Block descriptor length */ +} SENSE_PLH_T; + +typedef struct { + SENSE_PLH_T plh; + struct blk_desc blk_desc; + + union { + DADF_T pg3; + RDDG_T pg4; + } pdata; +} ips_mdata_t; + +/* + * Scatter Gather list format + */ +typedef struct ips_sglist { + u32 address; + u32 length; +} SG_LIST, *PSG_LIST; + +typedef struct _INFOSTR { + char *buffer; + int length; + int offset; + int pos; +} INFOSTR; + +/* + * Status Info + */ +typedef struct ips_stat { + u32 residue_len; + u32 scb_addr; +} ips_stat_t; + +/* + * SCB Queue Format + */ +typedef struct ips_scb_queue { + struct ips_scb *head; + struct ips_scb *tail; + unsigned int count; +} ips_scb_queue_t; + +/* + * Wait queue_format + */ +typedef struct ips_wait_queue { + Scsi_Cmnd *head; + Scsi_Cmnd *tail; + unsigned int count; +} ips_wait_queue_t; + +typedef struct ips_ha { + u8 ha_id[MAX_CHANNELS+1]; + u32 io_addr; /* Base I/O address */ + u8 irq; /* IRQ for adapter */ + u8 ntargets; /* Number of targets */ + u8 nbus; /* Number of buses */ + u8 nlun; /* Number of Luns */ + u16 ad_type; /* Adapter type */ + u16 host_num; /* Adapter number */ + u32 max_xfer; /* Maximum Xfer size */ + u32 max_cmds; /* Max concurrent commands */ + u32 num_ioctl; /* Number of Ioctls */ + ips_stat_t sp; /* Status packer pointer */ + struct ips_scb *scbs; /* Array of all CCBS */ + struct ips_scb *scb_freelist; /* SCB free list */ + ips_wait_queue_t scb_waitlist; /* Pending SCB list */ + ips_wait_queue_t copp_waitlist; /* Pending PT list */ + ips_scb_queue_t scb_activelist; /* Active SCB list */ + BASIC_IO_CMD *dummy; /* dummy command */ + ADAPTER_AREA *adapt; /* Adapter status area */ + ENQCMD *enq; /* Adapter Enquiry data */ + CONFCMD *conf; /* Adapter config data */ + NVRAM_PAGE5 *nvram; /* NVRAM page 5 data */ + SUBSYS_PARAM *subsys; /* Subsystem parameters */ + u32 cmd_in_progress; /* Current command in progress*/ + u32 flags; /* HA flags */ + u8 waitflag; /* are we waiting for cmd */ + u8 active; + u32 reserved:16; /* reserved space */ + wait_queue_head_t copp_queue; /* passthru sync queue */ + + #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) + spinlock_t scb_lock; + spinlock_t copp_lock; + #endif +} ips_ha_t; + +typedef void (*scb_callback) (ips_ha_t *, struct ips_scb *); + +/* + * SCB Format + */ +typedef struct ips_scb { + HOST_COMMAND cmd; + DCDB_TABLE dcdb; + u8 target_id; + u8 bus; + u8 lun; + u8 cdb[12]; + u32 scb_busaddr; + u32 data_busaddr; + u32 timeout; + u8 basic_status; + u8 extended_status; + u16 breakup; + u32 data_len; + u32 sg_len; + u32 flags; + u32 op_code; + SG_LIST *sg_list; + Scsi_Cmnd *scsi_cmd; + struct ips_scb *q_next; + scb_callback callback; +} ips_scb_t; + +/* + * Passthru Command Format + */ +typedef struct { + u8 CoppID[4]; + u32 CoppCmd; + u32 PtBuffer; + u8 *CmdBuffer; + u32 CmdBSize; + ips_scb_t CoppCP; + u32 TimeOut; + u8 BasicStatus; + u8 ExtendedStatus; + u16 reserved; +} ips_passthru_t; + +#endif + + + +/* + * Overrides for Emacs so that we almost follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c --- v2.3.15/linux/drivers/scsi/mesh.c Wed Dec 30 10:55:07 1998 +++ linux/drivers/scsi/mesh.c Tue Aug 31 11:35:59 1999 @@ -40,6 +40,8 @@ * - retry arbitration if lost (unless higher levels do this for us) */ +#define MESH_NEW_STYLE_EH + #if 1 #undef KERN_DEBUG #define KERN_DEBUG KERN_WARNING @@ -151,10 +153,12 @@ u8 msgout[16]; struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ int clk_freq; + struct mesh_target tgts[8]; +#ifndef MESH_NEW_STYLE_EH Scsi_Cmnd *completed_q; Scsi_Cmnd *completed_qtail; - struct mesh_target tgts[8]; struct tq_struct tqueue; +#endif #ifdef MESH_DBG int log_ix; int n_log; @@ -186,7 +190,9 @@ static void mesh_dump_regs(struct mesh_state *); static void mesh_start(struct mesh_state *); static void mesh_start_cmd(struct mesh_state *, Scsi_Cmnd *); +#ifndef MESH_NEW_STYLE_EH static void finish_cmds(void *); +#endif static void add_sdtr_msg(struct mesh_state *); static void set_sdtr(struct mesh_state *, int, int); static void start_phase(struct mesh_state *); @@ -252,8 +258,10 @@ continue; } mesh_host->unique_id = nmeshes; +#ifndef MODULE note_scsi_host(mesh, mesh_host); - +#endif + ms = (struct mesh_state *) mesh_host->hostdata; if (ms == 0) panic("no mesh state"); @@ -282,10 +290,10 @@ ms->tgts[tgt].sync_params = ASYNC_PARAMS; ms->tgts[tgt].current_req = 0; } - +#ifndef MESH_NEW_STYLE_EH ms->tqueue.routine = finish_cmds; ms->tqueue.data = ms; - +#endif *prev_statep = ms; prev_statep = &ms->next; @@ -428,7 +436,9 @@ { handle_reset(ms); restore_flags(flags); +#ifndef MESH_NEW_STYLE_EH finish_cmds(ms); +#endif ret |= SCSI_RESET_SUCCESS; } return ret; @@ -677,6 +687,7 @@ } } +#ifndef MESH_NEW_STYLE_EH static void finish_cmds(void *data) { @@ -685,18 +696,18 @@ unsigned long flags; for (;;) { - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); cmd = ms->completed_q; if (cmd == NULL) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); break; } ms->completed_q = (Scsi_Cmnd *) cmd->host_scribble; - restore_flags(flags); (*cmd->scsi_done)(cmd); + spin_unlock_irqrestore(&io_request_lock, flags); } } +#endif /* MESH_NEW_STYLE_EH */ static inline void add_sdtr_msg(struct mesh_state *ms) @@ -762,8 +773,8 @@ Scsi_Cmnd *cmd = ms->current_req; struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; - dlog(ms, "start_phase err/exc/fc/seq = %.8x", - MKWORD(mr->error, mr->exception, mr->fifo_count, mr->sequence)); + dlog(ms, "start_phase nmo/exc/fc/seq = %.8x", + MKWORD(ms->n_msgout, mr->exception, mr->fifo_count, mr->sequence)); out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0); switch (ms->msgphase) { @@ -1057,6 +1068,7 @@ t = 230; /* wait up to 230us */ while ((mr->bus_status0 & BS0_REQ) == 0) { if (--t < 0) { + dlog(ms, "impatient for req", ms->n_msgout); ms->msgphase = msg_none; break; } @@ -1643,7 +1655,9 @@ static void mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd) { -#if 0 +#ifdef MESH_NEW_STYLE_EH + (*cmd->scsi_done)(cmd); +#else if (ms->completed_q == NULL) ms->completed_q = cmd; else @@ -1652,9 +1666,7 @@ cmd->host_scribble = NULL; queue_task(&ms->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); -#else - (*cmd->scsi_done)(cmd); -#endif +#endif /* MESH_NEW_STYLE_EH */ } /* diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/mesh.h linux/drivers/scsi/mesh.h --- v2.3.15/linux/drivers/scsi/mesh.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/mesh.h Tue Aug 31 11:35:59 1999 @@ -28,6 +28,7 @@ sg_tablesize: SG_ALL, \ cmd_per_lun: 2, \ use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code: 1, \ } /* diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.3.15/linux/drivers/scsi/ncr53c8xx.c Mon Aug 16 10:33:58 1999 +++ linux/drivers/scsi/ncr53c8xx.c Tue Aug 31 11:25:33 1999 @@ -146,9 +146,6 @@ #ifndef __initdata #define __initdata #endif -#ifndef __initfunc -#define __initfunc(__arginit) __arginit -#endif #endif #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92) @@ -9578,8 +9575,10 @@ static int __init pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) { - *base = pdev->resource[++index].start; - return index; + *base = pdev->resource[index].start; + if ((pdev->resource[index].flags & 0x7) == 0x4) + ++index; + return ++index; } /* @@ -9764,9 +9763,6 @@ * each and every PCI card, if they don't use Fcode? */ - base = __pa(base); - base_2 = __pa(base_2); - if (!(command & PCI_COMMAND_MASTER)) { if (initverbose >= 2) printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n"); @@ -9807,28 +9803,16 @@ /* * Check availability of IO space, memory space and master capability. + * No need to test BARs flags since they are hardwired to the + * expected value. */ - if (command & PCI_COMMAND_IO) { - if ((io_port & 3) != 1) { - printk("ncr53c8xx: disabling I/O mapping since base address 0 (0x%x)\n" - " bits 0..1 indicate a non-IO mapping\n", (int) io_port); - io_port = 0; - } - else - io_port &= PCI_BASE_ADDRESS_IO_MASK; - } + if (command & PCI_COMMAND_IO) + io_port &= PCI_BASE_ADDRESS_IO_MASK; else io_port = 0; - if (command & PCI_COMMAND_MEMORY) { - if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { - printk("ncr53c8xx: disabling memory mapping since base address 1\n" - " contains a non-memory mapping\n"); - base = 0; - } - else - base &= PCI_BASE_ADDRESS_MEM_MASK; - } + if (command & PCI_COMMAND_MEMORY) + base &= PCI_BASE_ADDRESS_MEM_MASK; else base = 0; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/pluto.c linux/drivers/scsi/pluto.c --- v2.3.15/linux/drivers/scsi/pluto.c Wed May 12 08:41:15 1999 +++ linux/drivers/scsi/pluto.c Tue Aug 31 11:23:03 1999 @@ -58,18 +58,18 @@ static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); -__initfunc(static void pluto_detect_timeout(unsigned long data)) +static void __init pluto_detect_timeout(unsigned long data) { PLND(("Timeout\n")) up(&fc_sem); } -__initfunc(static void pluto_detect_done(Scsi_Cmnd *SCpnt)) +static void __init pluto_detect_done(Scsi_Cmnd *SCpnt) { /* Do nothing */ } -__initfunc(static void pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)) +static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt) { SCpnt->request.rq_status = RQ_SCSI_DONE; PLND(("Detect done %08lx\n", (long)SCpnt)) @@ -92,7 +92,7 @@ /* Detect all SSAs attached to the machine. To be fast, do it on all online FC channels at the same time. */ -__initfunc(int pluto_detect(Scsi_Host_Template *tpnt)) +int __init pluto_detect(Scsi_Host_Template *tpnt) { int i, retry, nplutos; fc_channel *fc; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.3.15/linux/drivers/scsi/qlogicfc.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/scsi/qlogicfc.c Mon Aug 30 10:25:30 1999 @@ -635,7 +635,8 @@ #define AS_FIRMWARE_DEAD -1 #define AS_LOOP_DOWN 0 #define AS_LOOP_GOOD 1 -#define AS_REDO_PORTDB 2 +#define AS_REDO_FABRIC_PORTDB 2 +#define AS_REDO_LOOP_PORTDB 4 struct isp2x00_hostdata { u_char revision; @@ -965,30 +966,31 @@ } printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); - - memset(&req, 0, sizeof(req)); - - req.len = 8; - req.response_low = virt_to_bus_low32(sns_response); - req.response_high = virt_to_bus_high32(sns_response); - req.sub_len = 22; - req.data[0] = 0x17; - req.data[1] = 0x02; - req.data[8] = (u_char) (hostdata->port_id & 0xff); - req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); - req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); - req.data[13] = 0x01; - param[0] = MBOX_SEND_SNS; - param[1] = 30; - param[2] = virt_to_bus_low32(&req) >> 16; - param[3] = virt_to_bus_low32(&req); - param[6] = virt_to_bus_high32(&req) >> 16; - param[7] = virt_to_bus_high32(&req); + if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){ + memset(&req, 0, sizeof(req)); - isp2x00_mbox_command(host, param); + req.len = 8; + req.response_low = virt_to_bus_low32(sns_response); + req.response_high = virt_to_bus_high32(sns_response); + req.sub_len = 22; + req.data[0] = 0x17; + req.data[1] = 0x02; + req.data[8] = (u_char) (hostdata->port_id & 0xff); + req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); + req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); + req.data[13] = 0x01; + param[0] = MBOX_SEND_SNS; + param[1] = 30; + param[2] = virt_to_bus_low32(&req) >> 16; + param[3] = virt_to_bus_low32(&req); + param[6] = virt_to_bus_high32(&req) >> 16; + param[7] = virt_to_bus_high32(&req); + + isp2x00_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) - printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); + if (param[0] != MBOX_COMMAND_COMPLETE) + printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); + } port_id = hostdata->port_id; while (!done) { @@ -1131,9 +1133,9 @@ DEBUG(isp2x00_print_scsi_cmd(Cmnd)); - if (hostdata->adapter_state == AS_REDO_PORTDB) { - hostdata->adapter_state = AS_LOOP_GOOD; + if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) { isp2x00_make_portdb(host); + hostdata->adapter_state = AS_LOOP_GOOD; printk("qlogicfc%d : Port Database\n", hostdata->host_id); for (i = 0; hostdata->port_db[i].wwn != 0; i++) { printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id); @@ -1270,6 +1272,9 @@ } switch (Cmnd->cmnd[0]) { + case TEST_UNIT_READY: + case START_STOP: + break; case WRITE_10: case WRITE_6: case WRITE_BUFFER: @@ -1378,7 +1383,7 @@ case LOOP_UP: case POINT_TO_POINT_UP: printk("qlogicfc%d : link is up\n", hostdata->host_id); - hostdata->adapter_state = AS_REDO_PORTDB; + hostdata->adapter_state = AS_REDO_FABRIC_PORTDB | AS_REDO_LOOP_PORTDB; break; case LOOP_DOWN: printk("qlogicfc%d : link is down\n", hostdata->host_id); @@ -1387,12 +1392,15 @@ case CONNECTION_MODE: printk("received CONNECTION_MODE irq %x\n", inw(host->io_port + MBOX1)); break; - case LIP_OCCURED: case CHANGE_NOTIFICATION: + if (hostdata->adapter_state == AS_LOOP_GOOD) + hostdata->adapter_state = AS_REDO_FABRIC_PORTDB; + break; + case LIP_OCCURED: case PORT_DB_CHANGED: case LIP_RECEIVED: if (hostdata->adapter_state == AS_LOOP_GOOD) - hostdata->adapter_state = AS_REDO_PORTDB; + hostdata->adapter_state = AS_REDO_LOOP_PORTDB; break; case SYSTEM_ERROR: printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id); diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.3.15/linux/drivers/scsi/qlogicisp.c Thu Aug 5 15:11:52 1999 +++ linux/drivers/scsi/qlogicisp.c Tue Aug 31 10:50:45 1999 @@ -1170,7 +1170,7 @@ static int isp1020_init(struct Scsi_Host *sh) { - u_long io_base; + u_long io_base, io_flags; struct isp1020_hostdata *hostdata; u_char revision; u_int irq; @@ -1188,7 +1188,9 @@ printk("qlogicisp : error reading PCI configuration\n"); return 1; } + io_base = pdev->resource[0].start; + io_flags = pdev->resource[0].flags; irq = pdev->irq; if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { @@ -1212,9 +1214,9 @@ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); #endif - if (command & PCI_COMMAND_IO && (io_base & 3) == 1) - io_base &= PCI_BASE_ADDRESS_IO_MASK; - else { + if (! ((command & PCI_COMMAND_IO) + && ((io_flags & PCI_BASE_ADDRESS_SPACE) + == PCI_BASE_ADDRESS_SPACE_IO))) { printk("qlogicisp : i/o mapping is disabled\n"); return 1; } diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.3.15/linux/drivers/scsi/qlogicpti.c Mon Mar 15 16:11:31 1999 +++ linux/drivers/scsi/qlogicpti.c Tue Aug 31 11:23:03 1999 @@ -353,7 +353,7 @@ #define PTI_RESET_LIMIT 400 -__initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti)) +static int __init qlogicpti_load_firmware(struct qlogicpti *qpti) { struct qlogicpti_regs *qregs = qpti->qregs; unsigned short csum = 0; @@ -583,7 +583,7 @@ #endif /* Detect all PTI Qlogic ISP's in the machine. */ -__initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt)) +int __init qlogicpti_detect(Scsi_Host_Template *tpnt) { struct qlogicpti *qpti, *qlink; struct Scsi_Host *qpti_host; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.3.15/linux/drivers/scsi/scsi.h Wed Aug 18 16:44:19 1999 +++ linux/drivers/scsi/scsi.h Tue Aug 31 16:12:41 1999 @@ -715,7 +715,7 @@ DECLARE_WAITQUEUE(wait, current); \ add_wait_queue(QUEUE, &wait); \ for(;;) { \ - current->state = TASK_UNINTERRUPTIBLE; \ + set_current_state(TASK_UNINTERRUPTIBLE); \ if (CONDITION) { \ if (in_interrupt()) \ panic("scsi: trying to call schedule() in interrupt" \ diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/sgiwd93.c linux/drivers/scsi/sgiwd93.c --- v2.3.15/linux/drivers/scsi/sgiwd93.c Fri May 8 00:22:12 1998 +++ linux/drivers/scsi/sgiwd93.c Tue Aug 31 11:23:03 1999 @@ -217,7 +217,7 @@ hcp->desc.pnext = PHYSADDR(buf); } -__initfunc(int sgiwd93_detect(Scsi_Host_Template *HPsUX)) +int __init sgiwd93_detect(Scsi_Host_Template *HPsUX) { static unsigned char called = 0; struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.3.15/linux/drivers/scsi/sr.c Mon Aug 9 12:34:22 1999 +++ linux/drivers/scsi/sr.c Tue Aug 31 16:03:17 1999 @@ -20,6 +20,9 @@ * Modified by Gerd Knorr to support the * generic cdrom interface * + * Modified by Jens Axboe - Uniform sr_packet() + * interface, capabilities probe additions, ioctl cleanups, etc. + * */ #include @@ -925,10 +928,13 @@ scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ scsi_CDs[i].needs_sector_size = 1; } else { - scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); + if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), + (long*)&scsi_CDs[i].capacity)) { + scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); + } scsi_CDs[i].sector_size = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; switch (scsi_CDs[i].sector_size) { diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.3.15/linux/drivers/scsi/sr_ioctl.c Thu Aug 5 16:24:15 1999 +++ linux/drivers/scsi/sr_ioctl.c Tue Aug 31 16:03:17 1999 @@ -19,9 +19,6 @@ # define DEBUG #endif -/* for now we borrow the "operation not supported" from the network folks */ -#define EDRIVE_CANT_DO_THIS EOPNOTSUPP - /* The sr_is_xa() seems to trigger firmware bugs with some drives :-( * It is off by default and can be turned on with this module parameter */ static int xa_test = 0; @@ -160,7 +157,7 @@ { u_char sr_cmd[10]; - sr_cmd[0] = TEST_UNIT_READY; + sr_cmd[0] = GPCMD_TEST_UNIT_READY; sr_cmd[1] = ((scsi_CDs[minor].device -> lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1); @@ -170,7 +167,7 @@ { u_char sr_cmd[10]; - sr_cmd[0] = START_STOP; + sr_cmd[0] = GPCMD_START_STOP_UNIT; sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device -> lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */; @@ -243,7 +240,7 @@ char buffer[32]; int result; - sr_cmd[0] = SCMD_READ_SUBCHANNEL; + sr_cmd[0] = GPCMD_READ_SUBCHANNEL; sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); sr_cmd[2] = 0x40; /* I do want the subchannel info */ sr_cmd[3] = 0x02; /* Give me medium catalog number info */ @@ -277,7 +274,7 @@ speed *= 177; /* Nx to kbyte/s */ memset(sr_cmd,0,12); - sr_cmd[0] = 0xbb; /* SET CD SPEED */ + sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5; sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ sr_cmd[3] = speed & 0xff; /* LSB */ @@ -290,6 +287,8 @@ /* ----------------------------------------------------------------------- */ /* this is called by the generic cdrom driver. arg is a _kernel_ pointer, */ /* becauce the generic cdrom driver does the user access stuff for us. */ +/* only cdromreadtochdr and cdromreadtocentry are left - for use with the */ +/* sr_disk_status interface for the generic cdrom driver. */ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) { @@ -300,94 +299,12 @@ switch (cmd) { - /* Sun-compatible */ - case CDROMPAUSE: - - sr_cmd[0] = SCMD_PAUSE_RESUME; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; - sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; - sr_cmd[8] = 0; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMRESUME: - - sr_cmd[0] = SCMD_PAUSE_RESUME; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; - sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; - sr_cmd[8] = 1; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMPLAYMSF: - { - struct cdrom_msf* msf = (struct cdrom_msf*)arg; - - sr_cmd[0] = SCMD_PLAYAUDIO_MSF; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = 0; - sr_cmd[3] = msf->cdmsf_min0; - sr_cmd[4] = msf->cdmsf_sec0; - sr_cmd[5] = msf->cdmsf_frame0; - sr_cmd[6] = msf->cdmsf_min1; - sr_cmd[7] = msf->cdmsf_sec1; - sr_cmd[8] = msf->cdmsf_frame1; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - } - - case CDROMPLAYBLK: - { - struct cdrom_blk* blk = (struct cdrom_blk*)arg; - - sr_cmd[0] = SCMD_PLAYAUDIO10; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = blk->from >> 24; - sr_cmd[3] = blk->from >> 16; - sr_cmd[4] = blk->from >> 8; - sr_cmd[5] = blk->from; - sr_cmd[6] = 0; - sr_cmd[7] = blk->len >> 8; - sr_cmd[8] = blk->len; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - } - - case CDROMPLAYTRKIND: - { - struct cdrom_ti* ti = (struct cdrom_ti*)arg; - - sr_cmd[0] = SCMD_PLAYAUDIO_TI; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = 0; - sr_cmd[3] = 0; - sr_cmd[4] = ti->cdti_trk0; - sr_cmd[5] = ti->cdti_ind0; - sr_cmd[6] = 0; - sr_cmd[7] = ti->cdti_trk1; - sr_cmd[8] = ti->cdti_ind1; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - } - case CDROMREADTOCHDR: { struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg; char buffer[32]; - sr_cmd[0] = SCMD_READ_TOC; + sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[6] = 0; @@ -408,7 +325,7 @@ struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg; unsigned char buffer[32]; - sr_cmd[0] = SCMD_READ_TOC; + sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; @@ -432,39 +349,7 @@ break; } - - case CDROMSUBCHNL: - { - struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; - char buffer[32]; - - sr_cmd[0] = SCMD_READ_SUBCHANNEL; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ - sr_cmd[2] = 0x40; /* I do want the subchannel info */ - sr_cmd[3] = 0x01; /* Give me current position info */ - sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[6] = 0; - sr_cmd[7] = 0; - sr_cmd[8] = 16; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0); - - subchnl->cdsc_audiostatus = buffer[1]; - subchnl->cdsc_format = CDROM_MSF; - subchnl->cdsc_ctrl = buffer[5] & 0xf; - subchnl->cdsc_trk = buffer[6]; - subchnl->cdsc_ind = buffer[7]; - - subchnl->cdsc_reladdr.msf.minute = buffer[13]; - subchnl->cdsc_reladdr.msf.second = buffer[14]; - subchnl->cdsc_reladdr.msf.frame = buffer[15]; - subchnl->cdsc_absaddr.msf.minute = buffer[9]; - subchnl->cdsc_absaddr.msf.second = buffer[10]; - subchnl->cdsc_absaddr.msf.frame = buffer[11]; - - break; - } + default: return -EINVAL; } @@ -502,7 +387,7 @@ #endif memset(cmd,0,12); - cmd[0] = 0xbe /* READ_CD */; + cmd[0] = GPCMD_READ_CD; /* READ_CD */ cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2); cmd[2] = (unsigned char)(lba >> 24) & 0xff; cmd[3] = (unsigned char)(lba >> 16) & 0xff; @@ -548,7 +433,7 @@ #endif memset(cmd,0,12); - cmd[0] = READ_10; + cmd[0] = GPCMD_READ_10; cmd[1] = (scsi_CDs[minor].device->lun << 5); cmd[2] = (unsigned char)(lba >> 24) & 0xff; cmd[3] = (unsigned char)(lba >> 16) & 0xff; @@ -603,89 +488,6 @@ target = MINOR(cdi->dev); switch (cmd) { - case CDROMREADMODE1: - case CDROMREADMODE2: - case CDROMREADRAW: - { - unsigned char *raw; - struct cdrom_msf msf; - int lba, rc; - int blocksize = 2048; - unsigned long flags; - - switch (cmd) { - case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; /* 2336 */ - case CDROMREADRAW: blocksize = CD_FRAMESIZE_RAW; break; /* 2352 */ - } - - if (copy_from_user(&msf,(void*)arg,sizeof(msf))) - return -EFAULT; - spin_lock_irqsave(&io_request_lock, flags); - raw = scsi_malloc(2048+512); - spin_unlock_irqrestore(&io_request_lock, flags); - if (!(raw)) - return -ENOMEM; - - lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0) - * CD_FRAMES + msf.cdmsf_frame0) - CD_MSF_OFFSET; - if (lba < 0 || lba >= scsi_CDs[target].capacity) - return -EINVAL; - - rc = sr_read_sector(target, lba, blocksize, raw); - if (!rc) - if (copy_to_user((void*)arg, raw, blocksize)) - rc = -EFAULT; - - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(raw,2048+512); - spin_unlock_irqrestore(&io_request_lock, flags); - return rc; - } - case CDROMREADAUDIO: - { - unsigned char *raw; - int lba, rc=0; - struct cdrom_read_audio ra; - unsigned long flags; - - if (!scsi_CDs[target].readcd_known || !scsi_CDs[target].readcd_cdda) - return -EINVAL; /* -EDRIVE_DOES_NOT_SUPPORT_THIS ? */ - - if (copy_from_user(&ra,(void*)arg,sizeof(ra))) - return -EFAULT; - - if (ra.addr_format == CDROM_LBA) - lba = ra.addr.lba; - else - lba = (((ra.addr.msf.minute * CD_SECS) + ra.addr.msf.second) - * CD_FRAMES + ra.addr.msf.frame) - CD_MSF_OFFSET; - - if (lba < 0 || lba >= scsi_CDs[target].capacity) - return -EINVAL; - spin_lock_irqsave(&io_request_lock, flags); - raw = scsi_malloc(2048+512); - spin_unlock_irqrestore(&io_request_lock, flags); - if (!(raw)) - return -ENOMEM; - - while (ra.nframes > 0) { - rc = sr_read_cd(target, raw, lba, 1, CD_FRAMESIZE_RAW); - if (!rc) - if (copy_to_user(ra.buf, raw, CD_FRAMESIZE_RAW)) - rc = -EFAULT; - if (rc) - break; - - ra.buf += CD_FRAMESIZE_RAW; - ra.nframes -= 1; - lba++; - } - spin_lock_irqsave(&io_request_lock, flags); - scsi_free(raw,2048+512); - spin_unlock_irqrestore(&io_request_lock, flags); - return rc; - } - case BLKROSET: case BLKROGET: case BLKRASET: diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.15/linux/drivers/scsi/st.c Mon Aug 9 10:25:01 1999 +++ linux/drivers/scsi/st.c Tue Aug 31 11:23:03 1999 @@ -3499,7 +3499,7 @@ static int st_registered = 0; -/* Driver initialization (not __initfunc because may be called later) */ +/* Driver initialization (not __init because may be called later) */ static int st_init() { int i; diff -u --recursive --new-file v2.3.15/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.3.15/linux/drivers/scsi/sym53c8xx.c Wed Aug 4 10:54:13 1999 +++ linux/drivers/scsi/sym53c8xx.c Tue Aug 31 11:25:33 1999 @@ -134,8 +134,8 @@ #ifndef __initdata #define __initdata #endif -#ifndef __initfunc -#define __initfunc(__arginit) __arginit +#ifndef __init +#define __init #endif #endif @@ -569,16 +569,13 @@ #endif #ifdef __sparc__ -#define remap_pci_mem(base, size) ((u_long) __va(base)) -#define unmap_pci_mem(vaddr, size) #define pcivtobus(p) ((p) & pci_dvma_mask) #else /* __sparc__ */ #define pcivtobus(p) (p) +#endif #if !defined(NCR_IOMAPPED) || defined(__i386__) -__initfunc( -static u_long remap_pci_mem(u_long base, u_long size) -) +static u_long __init remap_pci_mem(u_long base, u_long size) { u_long page_base = ((u_long) base) & PAGE_MASK; u_long page_offs = ((u_long) base) - page_base; @@ -587,15 +584,12 @@ return page_remapped? (page_remapped + page_offs) : 0UL; } -__initfunc( -static void unmap_pci_mem(u_long vaddr, u_long size) -) +static void __init unmap_pci_mem(u_long vaddr, u_long size) { if (vaddr) iounmap((void *) (vaddr & PAGE_MASK)); } #endif /* !NCR_IOMAPPED || __i386__ */ -#endif /* __sparc__ */ /* ** Insert a delay in micro-seconds and milli-seconds. @@ -3802,9 +3796,7 @@ **========================================================== */ -__initfunc( -void ncr_script_fill (struct script * scr, struct scripth * scrh) -) +void __init ncr_script_fill (struct script * scr, struct scripth * scrh) { int i; ncrcmd *p; @@ -3868,9 +3860,7 @@ **========================================================== */ -__initfunc( -static void ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len) -) +static void __init ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len) { ncrcmd opcode, new, old, tmp1, tmp2; ncrcmd *start, *end; @@ -4138,10 +4128,8 @@ ** Get target set-up from Symbios format NVRAM. */ -__initfunc( -static void +static void __init ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram) -) { tcb_p tp = &np->target[target]; Symbios_target *tn = &nvram->target[target]; @@ -4161,10 +4149,8 @@ ** Get target set-up from Tekram format NVRAM. */ -__initfunc( -static void +static void __init ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram) -) { tcb_p tp = &np->target[target]; struct Tekram_target *tn = &nvram->target[target]; @@ -4190,9 +4176,7 @@ } #endif /* SCSI_NCR_NVRAM_SUPPORT */ -__initfunc( -static int ncr_prepare_setting(ncb_p np, ncr_nvram *nvram) -) +static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram) { u_char burst_max; u_long period; @@ -4514,9 +4498,7 @@ #ifdef SCSI_NCR_DEBUG_NVRAM -__initfunc( -void ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram) -) +void __init ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram) { int i; @@ -4546,9 +4528,7 @@ static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120}; -__initfunc( -void ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram) -) +void __init ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram) { int i, tags, boot_delay; char *rem; @@ -4607,9 +4587,7 @@ ** start the timer daemon. */ -__initfunc( -static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) -) +static int __init ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) { struct host_data *host_data; ncb_p np = 0; @@ -9202,9 +9180,7 @@ */ #ifndef NCR_IOMAPPED -__initfunc( -static int ncr_regtest (struct ncb* np) -) +static int __init ncr_regtest (struct ncb* np) { register volatile u_int32 data; /* @@ -9228,9 +9204,7 @@ } #endif -__initfunc( -static int ncr_snooptest (struct ncb* np) -) +static int __init ncr_snooptest (struct ncb* np) { u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; int i, err=0; @@ -9460,9 +9434,7 @@ /* * calculate NCR SCSI clock frequency (in KHz) */ -__initfunc( -static unsigned ncrgetfreq (ncb_p np, int gen) -) +static unsigned __init ncrgetfreq (ncb_p np, int gen) { unsigned ms = 0; @@ -9510,9 +9482,7 @@ /* * Get/probe NCR SCSI clock frequency */ -__initfunc( -static void ncr_getclock (ncb_p np, int mult) -) +static void __init ncr_getclock (ncb_p np, int mult) { unsigned char scntl3 = INB(nc_scntl3); unsigned char stest1 = INB(nc_stest1); @@ -9644,9 +9614,7 @@ #define ARG_SEP ',' #endif -__initfunc( -static int get_setup_token(char *p) -) +static int __init get_setup_token(char *p) { char *cur = setup_token; char *pc; @@ -9663,9 +9631,7 @@ } -__initfunc( -void sym53c8xx_setup(char *str, int *ints) -) +void __init sym53c8xx_setup(char *str, int *ints) { #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT char *cur = str; @@ -9799,9 +9765,7 @@ ** Returns the number of boards successfully attached. */ -__initfunc( -static void ncr_print_driver_setup(void) -) +static void __init ncr_print_driver_setup(void) { #define YesNo(y) y ? 'y' : 'n' printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d," @@ -9860,9 +9824,7 @@ #define SCSI_NCR_MAX_PQS_BUS 16 static int pqs_bus[SCSI_NCR_MAX_PQS_BUS] __initdata = { 0 }; -__initfunc( -static void ncr_detect_pqs_pds(void) -) +static void __init ncr_detect_pqs_pds(void) { short index; @@ -9900,9 +9862,7 @@ ** the the order they are detected. **=================================================================== */ -__initfunc( -int sym53c8xx_detect(Scsi_Host_Template *tpnt) -) +int __init sym53c8xx_detect(Scsi_Host_Template *tpnt) { int i, j, chips, hosts, count; u_char bus, device_fn; @@ -10090,10 +10050,8 @@ **=================================================================== */ #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92) -__initfunc( -static int +static int __init pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base) -) { u_int32 tmp; @@ -10110,10 +10068,8 @@ return offset; } #else /* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */ -__initfunc( -static int +static int __init pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) -) { /* FIXME! This is just unbelieably horrible backwards compatibility code */ struct resource *res = pdev->resource + index; @@ -10132,10 +10088,8 @@ ** been detected. **=================================================================== */ -__initfunc( -static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt, +static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt, uchar bus, uchar device_fn, ncr_device *device) -) { u_short vendor_id, device_id, command; u_char cache_line_size, latency_timer; @@ -10313,9 +10267,6 @@ ** coherent with hardware and software resource identifications. ** This is fairly simple, but seems still too complex for Sparc. */ - base = __pa(base); - base_2 = __pa(base_2); - if (!cache_line_size) suggested_cache_line_size = 16; @@ -10470,7 +10421,7 @@ *=================================================================== */ #ifdef SCSI_NCR_NVRAM_SUPPORT -__initfunc(static void ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp)) +static void __init ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp) { devp->nvram = nvp; if (!nvp) @@ -11335,9 +11286,7 @@ static void nvram_stop(ncr_slot *np, u_char *gpreg); static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode); -__initfunc( -static int ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram) -) +static int __init ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram) { static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; u_char gpcntl, gpreg; @@ -11426,9 +11375,7 @@ /* * Read Symbios NvRAM data and compute checksum. */ -__initfunc( -static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl) -) +static u_short __init nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl) { int x; u_short csum; @@ -11445,9 +11392,7 @@ /* * Send START condition to NVRAM to wake it up. */ -__initfunc( -static void nvram_start(ncr_slot *np, u_char *gpreg) -) +static void __init nvram_start(ncr_slot *np, u_char *gpreg) { nvram_setBit(np, 1, gpreg, SET_BIT); nvram_setBit(np, 0, gpreg, SET_CLK); @@ -11459,9 +11404,7 @@ * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, * GPIO0 must already be set as an output */ -__initfunc( -static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl) -) +static void __init nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl) { int x; @@ -11475,9 +11418,7 @@ * READ a byte from the NVRAM and then send an ACK to say we have got it, * GPIO0 must already be set as an input */ -__initfunc( -static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl) -) +static void __init nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl) { int x; u_char read_bit; @@ -11495,9 +11436,7 @@ * Output an ACK to the NVRAM after reading, * change GPIO0 to output and when done back to an input */ -__initfunc( -static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl) -) +static void __init nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl) { OUTB (nc_gpcntl, *gpcntl & 0xfe); nvram_doBit(np, 0, write_bit, gpreg); @@ -11508,9 +11447,7 @@ * Input an ACK from NVRAM after writing, * change GPIO0 to input and when done back to an output */ -__initfunc( -static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl) -) +static void __init nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl) { OUTB (nc_gpcntl, *gpcntl | 0x01); nvram_doBit(np, read_bit, 1, gpreg); @@ -11521,9 +11458,7 @@ * Read or write a bit to the NVRAM, * read if GPIO0 input else write if GPIO0 output */ -__initfunc( -static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg) -) +static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg) { nvram_setBit(np, write_bit, gpreg, SET_BIT); nvram_setBit(np, 0, gpreg, SET_CLK); @@ -11536,9 +11471,7 @@ /* * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! */ -__initfunc( -static void nvram_stop(ncr_slot *np, u_char *gpreg) -) +static void __init nvram_stop(ncr_slot *np, u_char *gpreg) { nvram_setBit(np, 0, gpreg, SET_CLK); nvram_setBit(np, 1, gpreg, SET_BIT); @@ -11547,9 +11480,7 @@ /* * Set/clear data/clock bit in GPIO0 */ -__initfunc( -static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode) -) +static void __init nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode) { UDELAY (5); switch (bit_mode){ @@ -11600,9 +11531,7 @@ static void Tnvram_Stop(ncr_slot *np, u_char *gpreg); static void Tnvram_Clk(ncr_slot *np, u_char *gpreg); -__initfunc( -static int ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram) -) +static int __init ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram) { u_char gpcntl, gpreg; u_char old_gpcntl, old_gpreg; @@ -11637,9 +11566,7 @@ /* * Read Tekram NvRAM data and compute checksum. */ -__initfunc( -static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg) -) +static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg) { u_char read_bit; u_short csum; @@ -11664,9 +11591,7 @@ /* * Send read command and address to NVRAM */ -__initfunc( -static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg) -) +static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg) { int x; @@ -11680,9 +11605,7 @@ /* * READ a byte from the NVRAM */ -__initfunc( -static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg) -) +static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg) { int x; u_char read_bit; @@ -11701,9 +11624,7 @@ /* * Read bit from NVRAM */ -__initfunc( -static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg) -) +static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg) { UDELAY (2); Tnvram_Clk(np, gpreg); @@ -11713,9 +11634,7 @@ /* * Write bit to GPIO0 */ -__initfunc( -static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg) -) +static void __init Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg) { if (write_bit & 0x01) *gpreg |= 0x02; @@ -11733,9 +11652,7 @@ /* * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! */ -__initfunc( -static void Tnvram_Stop(ncr_slot *np, u_char *gpreg) -) +static void __init Tnvram_Stop(ncr_slot *np, u_char *gpreg) { *gpreg &= 0xef; OUTB (nc_gpreg, *gpreg); @@ -11747,9 +11664,7 @@ /* * Pulse clock bit in GPIO0 */ -__initfunc( -static void Tnvram_Clk(ncr_slot *np, u_char *gpreg) -) +static void __init Tnvram_Clk(ncr_slot *np, u_char *gpreg) { OUTB (nc_gpreg, *gpreg | 0x04); UDELAY (2); diff -u --recursive --new-file v2.3.15/linux/drivers/sgi/char/ds1286.c linux/drivers/sgi/char/ds1286.c --- v2.3.15/linux/drivers/sgi/char/ds1286.c Fri Jun 25 17:39:34 1999 +++ linux/drivers/sgi/char/ds1286.c Tue Aug 31 11:23:03 1999 @@ -392,7 +392,7 @@ &ds1286_fops }; -__initfunc(int ds1286_init(void)) +int __init ds1286_init(void) { printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION); misc_register(&ds1286_dev); diff -u --recursive --new-file v2.3.15/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c --- v2.3.15/linux/drivers/sgi/char/graphics.c Fri Jul 2 15:15:51 1999 +++ linux/drivers/sgi/char/graphics.c Tue Aug 31 11:23:03 1999 @@ -324,13 +324,13 @@ }; /* This is called later from the misc-init routine */ -__initfunc(void gfx_register (void)) +void __init gfx_register (void) { misc_register (&dev_graphics); misc_register (&dev_opengl); } -__initfunc(void gfx_init (const char **name)) +void __init gfx_init (const char **name) { #if 0 struct console_ops *console; diff -u --recursive --new-file v2.3.15/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c --- v2.3.15/linux/drivers/sgi/char/sgiserial.c Tue Jun 29 09:22:08 1999 +++ linux/drivers/sgi/char/sgiserial.c Tue Aug 31 11:30:48 1999 @@ -1591,7 +1591,7 @@ if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) zs_rtsdtr(info, 1); sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -2045,7 +2045,7 @@ } -__initfunc(static int zs_console_setup(struct console *con, char *options)) +static int __init zs_console_setup(struct console *con, char *options) { struct sgi_serial *info; int baud = 9600; @@ -2185,7 +2185,7 @@ /* * Register console. */ -__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +long __init serial_console_init(long kmem_start, long kmem_end) { register_console(&sgi_console_driver); return kmem_start; diff -u --recursive --new-file v2.3.15/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.3.15/linux/drivers/sound/Config.in Thu Aug 26 13:05:39 1999 +++ linux/drivers/sound/Config.in Mon Aug 30 18:15:21 1999 @@ -274,7 +274,7 @@ dep_tristate 'Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 - int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 + int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 12 int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 fi diff -u --recursive --new-file v2.3.15/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.3.15/linux/drivers/sound/Makefile Thu Aug 26 13:05:39 1999 +++ linux/drivers/sound/Makefile Mon Aug 30 10:23:14 1999 @@ -81,6 +81,7 @@ obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o +obj-$(CONFIG_SOUND_MAESTRO) += maestro.o # Declare multi-part drivers. diff -u --recursive --new-file v2.3.15/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.3.15/linux/drivers/sound/cmpci.c Thu Aug 5 15:11:52 1999 +++ linux/drivers/sound/cmpci.c Thu Aug 26 14:23:32 1999 @@ -2176,9 +2176,9 @@ }; #ifdef MODULE -__initfunc(int init_module(void)) +int __init init_module(void) #else -__initfunc(int init_cmpci(void)) +int __init init_cmpci(void) #endif { struct cm_state *s; diff -u --recursive --new-file v2.3.15/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.3.15/linux/drivers/sound/dev_table.h Mon Jul 5 19:58:24 1999 +++ linux/drivers/sound/dev_table.h Mon Aug 30 18:15:21 1999 @@ -33,7 +33,7 @@ #define SNDCARD_WAVEFRONT 41 #define SNDCARD_OPL3SA2 42 #define SNDCARD_OPL3SA2_MPU 43 -#define SNDCARD_WAVEARTIST 44 +#define SNDCARD_WAVEARTIST 44 /* Rebel Waveartist */ #define SNDCARD_OPL3SA2_MSS 45 /* Originally missed */ #define SNDCARD_AD1816 88 diff -u --recursive --new-file v2.3.15/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.3.15/linux/drivers/sound/maestro.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/maestro.c Tue Aug 31 11:23:03 1999 @@ -0,0 +1,2918 @@ +/***************************************************************************** + * + * ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.2.x + * + * 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. + * + * (c) Copyright 1999 Alan Cox + * + * Based heavily on SonicVibes.c: + * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * Heavily modified by Zach Brown based on lunch + * with ESS engineers. Many thanks to Howard Kim for providing + * contacts and hardware. Honorable mention goes to Eric + * Brombaugh for the BOB routines and nice hacking in general. + * + * Supported devices: + * /dev/dsp0-7 standard /dev/dsp device, (mostly) OSS compatible + * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible + * + * Hardware Description + * + * A working Maestro setup contains the Maestro chip wired to a + * codec or 2. In the Maestro we have the APUs, the ASP, and the + * Wavecache. The APUs can be though of as virtual audio routing + * channels. They can take data from a number of sources and perform + * basic encodings of the data. The wavecache is a storehouse for + * PCM data. Typically it deals with PCI and interracts with the + * APUs. The ASP is a wacky DSP like device that ESS is loathe + * to release docs on. Thankfully it isn't required on the Maestro + * until you start doing insane things like FM emulation and surround + * encoding. The codecs are almost always AC-97 compliant codecs, + * but it appears that early Maestros may have had PT101 (an ESS + * part?) wired to them. The only real difference in the Maestro + * families is external goop like docking capability, memory for + * the ASP, and trivial initialization differences. + * + * Driver Operation + * + * We only drive the APU/Wavecache as typical DACs and drive the + * mixers in the codecs. There are 64 APUs. We assign 4 to each + * /dev/dsp? device. 2 channels for both in and out. + * + * For output we maintain a ring buffer of data that we are dmaing + * to the card. In mono operation this is nice and easy. When + * we receive data we tack it onto the ring buffer and make sure + * the APU assigned to it is playing over the data. When we fill + * the ring buffer we put the client to sleep until there is + * room again. Easy. + * + * However, this starts to stink when we use stereo. The APUs + * supposedly can decode LRLR packed stereo data, but it + * doesn't work. So we're forced to use dual mono APUs walking over + * mono encoded data. This requires us to split the input from + * the client and complicates the buffer maths tremendously. Ick. + * + * Once input is actually written, it will be worth pointing out + * that only 44/16 input actually works. + * + * TODO + * Leaks memory? + * recording is horribly broken + * apus or dmas get out sync + * bob can be started twice + * anyone have a pt101 codec? + * ess's ac97 codec (es1921) doesn't work + * generally test across codecs.. + * mmap(), but beware stereo encoding nastiness. + */ + +/*****************************************************************************/ + + +#ifdef MODULE +#include +#ifdef MODVERSIONS +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "maestro.h" +#include "maestro_tables.h" + +/* --------------------------------------------------------------------- */ + +#define M_DEBUG 1 + +#ifdef M_DEBUG +static int debug=0; +#define M_printk(args...) {if (debug) printk(args);} +#else +#define M_printk(x) +#endif + +/* --------------------------------------------------------------------- */ + +#define DRIVER_VERSION "0.03" + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ + +#define PCI_VENDOR_ESS_OLD 0x1285 /* vendor id for maestro 1 */ +#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 /* maestro 1 */ +#endif /* PCI_VENDOR_ESS */ + +#define ESS_CHAN_HARD 0x100 + +#define ESS_CFMT_STEREO 0x01 +#define ESS_CFMT_16BIT 0x02 +#define ESS_CFMT_MASK 0x03 +#define ESS_CFMT_ASHIFT 0 +#define ESS_CFMT_CSHIFT 4 + +#define ESS_ENABLE_PE 1 +#define ESS_ENABLE_RE 2 + +#define ESS_STATE_MAGIC 0x125D1968 +#define ESS_CARD_MAGIC 0x19283746 + +#define DAC_RUNNING 1 +#define ADC_RUNNING 2 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +enum card_types_t { + TYPE_MAESTRO, + TYPE_MAESTRO2, + TYPE_MAESTRO2E +}; + +static const char *card_names[]={ + [TYPE_MAESTRO] = "ESS Maestro", + [TYPE_MAESTRO2] = "ESS Maestro 2", + [TYPE_MAESTRO2E] = "ESS Maestro 2E" +}; + +#define SND_DEV_DSP16 5 + +/* --------------------------------------------------------------------- */ + +struct ess_state { + unsigned int magic; + /* FIXME: we probably want submixers in here, but only one record pair */ + u8 apu[4]; /* Left, Right, Left In, Right In */ + u8 apu_mode[4]; /* Running mode for this APU */ + u8 apu_pan[4]; /* Panning setup for this APU */ + struct ess_card *card; /* Card info */ + /* wave stuff */ + unsigned int rateadc, ratedac; + unsigned char fmt, enable; + + spinlock_t lock; + struct semaphore open_sem; + mode_t open_mode; + wait_queue_head_t open_wait; + + /* soundcore stuff */ + int dev_audio; + + struct dmabuf { + void *rawbuf; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + unsigned hwptr, swptr; + unsigned total_bytes; + int count; + unsigned error; /* over/underrun */ + wait_queue_head_t wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + u16 base; /* Offset for ptr */ + } dma_dac, dma_adc; +}; + +struct ess_card { + unsigned int magic; + + /* We keep maestro cards in a linked list */ + struct ess_card *next; + + int dev_mixer; + + int card_type; + + /* as most of this is static, + perhaps it should be a pointer to a global struct */ + struct mixer_goo { + int modcnt; + int supported_mixers; + int stereo_mixers; + int record_sources; + /* the caller must guarantee arg sanity before calling these */ + int (*read_mixer)(struct ess_card *card, int index); + void (*write_mixer)(struct ess_card *card,int mixer, int vol); + int (*recmask_io)(struct ess_card *card,int rw,int mask); + } mix; + + struct ess_state channels[8]; + u16 maestro_map[32]; /* Register map */ + + /* hardware resources */ + u32 iobase; + u32 irq; + +}; + +extern __inline__ unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + + +/* --------------------------------------------------------------------- */ + +static struct ess_card *devs = NULL; + +/* --------------------------------------------------------------------- */ + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + /* should actually be delaying 10 milliseconds? */ + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "maestro: ac97 codec read timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + + int val, seid, caps; + u16 vend1, vend2; + +#if 0 /* an experiment for another time */ + /* aim at the second codec */ + outw(0x21, iobase+0x38); + outw(0x5555, iobase+0x3a); + outw(0x5555, iobase+0x3c); + udelay(1); + vend1 = maestro_ac97_get(iobase, 0x7c); + vend2 = maestro_ac97_get(iobase, 0x7e); + if(vend1 != 0xffff || vend2 != 0xffff) { + printk("maestro: It seems you have a second codec: %x %x, please report this.\n", + vend1,vend2); + } + /* back to the first */ + outw(0x0, iobase+0x38); + outw(0x0, iobase+0x3a); + outw(0x0, iobase+0x3c); +#endif + + /* should make sure we're ac97 2.1? */ + vend1 = maestro_ac97_get(iobase, 0x7c); + vend2 = maestro_ac97_get(iobase, 0x7e); + + val = maestro_ac97_get(iobase, 0x00); + seid = val >> 8; + caps = val & 255; + + printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x 3d: 0x%x caps: 0x%x\n", + vend1,vend2,seid, caps); + + switch ((long)(vend1 << 16) | vend2) { + /* magic vendor specifc init code, _no_ idea what these do */ +#if 0 + case 0x83847609: /* ESS 1921 */ + maestro_ac97_set(iobase,0x76,0xABBA); /* o/~ Take a chance on me o/~ */ + udelay(20); + maestro_ac97_set(iobase,0x78,0x3002); + udelay(20); + maestro_ac97_set(iobase,0x78,0x3802); + udelay(20); + break; +#endif + default: break; + } + + /* set master, headphone, master mono */ + maestro_ac97_set(iobase, 0x02, 0x0000); + /* always set headphones to max unmuted, OSS won't + let us change it :( */ + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x0606); + /* beep, phone, mic, line, cd video, aux */ + maestro_ac97_set(iobase, 0x0A, 0x1F1F); + maestro_ac97_set(iobase, 0x0C, 0x1F1F); + maestro_ac97_set(iobase, 0x0E, 0x1F1F); + maestro_ac97_set(iobase, 0x10, 0x1F1F); + maestro_ac97_set(iobase, 0x12, 0x1F1F); + maestro_ac97_set(iobase, 0x14, 0x1F1F); + maestro_ac97_set(iobase, 0x16, 0x1F1F); + /* unmute, but set pcm out to 1/2 */ + maestro_ac97_set(iobase, 0x18, 0x0808); + /* null record select */ + maestro_ac97_set(iobase, 0x1A, 0x0000); + /* record gain, record gain mic.. */ + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + /* null misc stuff */ + maestro_ac97_set(iobase, 0x20, 0x0000); + /* power up various units? */ + maestro_ac97_set(iobase, 0x26, 0x000F); + + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); + /* who knows.. */ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(20); + outw(0x0000, ioaddr+0x36); + udelay(200); +} + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The Maestro engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(struct ess_state *ess, u16 reg, u16 data) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + ess->card->maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + if(READABLE_MAP & (1<card->maestro_map[reg]=inw(ioaddr+0x00); + restore_flags(flags); + } + return ess->card->maestro_map[reg]; +} + +/* + * These routines handle accessing the second level indirections to the + * wave ram. + */ + +/* + * The register names are the ones ESS uses (see 104T31.ZIP) + */ + +#define IDR0_DATA_PORT 0x00 +#define IDR1_CRAM_POINTER 0x01 +#define IDR2_CRAM_DATA 0x02 +#define IDR3_WAVE_DATA 0x03 +#define IDR4_WAVE_PTR_LOW 0x04 +#define IDR5_WAVE_PTR_HI 0x05 +#define IDR6_TIMER_CTRL 0x06 +#define IDR7_WAVE_ROMRAM 0x07 + +static void apu_index_set(struct ess_state *ess, u16 index) +{ + int i; + maestro_write(ess, IDR1_CRAM_POINTER, index); + for(i=0;i<1000;i++) + if(maestro_read(ess, IDR1_CRAM_POINTER)==index) + return; + printk(KERN_WARNING "maestro: APU register select failed.\n"); +} + +static void apu_data_set(struct ess_state *ess, u16 data) +{ + int i; + for(i=0;i<1000;i++) + { + if(maestro_read(ess, IDR0_DATA_PORT)==data) + return; + maestro_write(ess, IDR0_DATA_PORT, data); + } +} + +/* + * This is the public interface for APU manipulation. It handles the + * interlock to avoid two APU writes in parallel etc. Don't diddle + * directly with the stuff above. + */ + +static void apu_set_register(struct ess_state *ess, u16 channel, u8 reg, u16 data) +{ + unsigned long flags; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + { + if(channel>3) + printk("BAD CHANNEL %d.\n",channel); + else + channel = ess->apu[channel]; + } + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + apu_data_set(ess, data); + restore_flags(flags); +} + +static u16 apu_get_register(struct ess_state *ess, u16 channel, u8 reg) +{ + unsigned long flags; + u16 v; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + channel = ess->apu[channel]; + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + v=maestro_read(ess, IDR0_DATA_PORT); + restore_flags(flags); + return v; +} + + +/* + * The wavecache does pci fetches for us and feeds + * them to the APUs.. + * XXX describe interface + */ + +static void wave_set_register(struct ess_state *ess, u16 reg, u16 value) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + outw(value, ioaddr+0x12); + restore_flags(flags); +} + +static u16 wave_get_register(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + u16 value; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + value=inw(ioaddr+0x12); + restore_flags(flags); + + return value; +} + +static void sound_reset(int ioaddr) +{ + outw(0x2000, 0x18+ioaddr); + udelay(10); + outw(0x0000, 0x18+ioaddr); + udelay(10); +} + +static void set_apu_fmt(struct ess_state *s, int apu, int mode) +{ + if(mode&ESS_CFMT_16BIT) { + s->apu_mode[apu] = 0x10; + s->apu_mode[apu+1] = 0x10; + } else { + s->apu_mode[apu] = 0x30; + s->apu_mode[apu+1] = 0x30; + } +} + +static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data) +{ + s->fmt = (s->fmt & mask) | data; + set_apu_fmt(s, 0, s->fmt & ESS_CFMT_MASK); + set_apu_fmt(s, 2, (s->fmt >> ESS_CFMT_CSHIFT) & ESS_CFMT_MASK); +} + +static u16 compute_rate(u32 freq) +{ + if(freq==48000) + return 0xFFFF; + freq<<=16; + freq/=48000; + return freq; +} + +static void set_dac_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + + s->ratedac = rate; + + if(!(s->fmt & ESS_CFMT_16BIT)) + rate >>= 1; /* who knows */ + +/* M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/ + + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 0, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 0, 3, freq>>8); + apu_set_register(s, 1, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 1, 3, freq>>8); +} + +static void set_adc_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + + s->rateadc = rate; + + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 2, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 2, 3, freq>>8); + apu_set_register(s, 3, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 3, 3, freq>>8); +} + + +/* + * Native play back driver + */ + +static void ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size) +{ + u32 pa; + u32 tmpval; + int high_apu = 0; + int channel; + + M_printk("mode=%d rate=%d buf=%p len=%d.\n", + mode, rate, buffer, size); + + /* all maestro sizes are in 16bit words */ + size >>=1; + + /* we're given the full size of the buffer, but + in stereo each channel will only play its half */ + if(mode&ESS_CFMT_STEREO) { + size >>=1; + high_apu++; + } + + for(channel=0; channel <= high_apu; channel++) + { + int i; + + /* + * To understand this it helps to know how the + * wave cache works. There are 4 DSP wavecache + * blocks which are 0x1FC->0x1FF. They are selected + * by setting bits 22,21,20 of the address to + * 1 X Y where X Y select the block. + * + * In addition stereo pairing is supported. This is + * set in the wave cache control for the channel as is + * 8bit unsigned. + * + * Note that this causes a problem. With our limit of + * about 12 full duplex pairs (48 channels active) we + * will need to do a lot of juggling to get all the + * memory we want sufficiently close together. + * + * Even with 64K blocks that means + * 24 channel pairs + * 6 pairs/block + * + * 10K per channel pair = 5000 samples. + */ + + if(!channel) + pa = virt_to_bus(buffer); + else + /* right channel plays its split half. + *2 accomodates for rampant shifting earlier */ + pa = virt_to_bus(buffer + size*2); + + M_printk("sending pa %x to %d\n",pa,channel); + + wave_set_register(ess, 0x01FC, (pa&0xFFE00000)>>12); + + /* set the wavecache control reg */ + tmpval = (pa - 0x10) & 0xFFF8; +#if 0 + if(mode & 1) tmpval |= 2; /* stereo */ +#endif + if(!(mode & 2)) tmpval |= 4; /* 8bit */ + wave_set_register(ess, ess->apu[channel]<<3, tmpval); + + pa&=0x1FFFFF; /* Low 21 bits */ + pa>>=1; /* words */ + + /* base offset of dma calcs when reading the pointer + on this left one */ + if(!channel) ess->dma_dac.base = pa&0xFFFF; + +#if 0 + if(mode&ESS_CFMT_STEREO) /* Enable stereo */ + pa|=0x00800000; +#endif + pa|=0x00400000; /* System RAM */ + + /* Begin loading the APU */ + for(i=0;i<15;i++) /* clear all PBRs */ + apu_set_register(ess, channel, i, 0x0000); + + /* Load the frequency, turn on 6dB, turn off the effects */ +/* apu_set_register(ess, channel, 2, (rate&0xFF)<<8|0x10); + apu_set_register(ess, channel, 3, rate>>8);*/ + + /* Load the buffer into the wave engine */ + apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); + /* XXX reg is little endian.. */ + apu_set_register(ess, channel, 5, pa&0xFFFF); + apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); + /* setting loop == sample len */ + apu_set_register(ess, channel, 7, size); + + /* clear effects/env.. */ + apu_set_register(ess, channel, 8, 0x0000); + /* aplitudeNow to 0xd0? */ + apu_set_register(ess, channel, 9, 0xD000); + + /* set the panning reg of the apu to left/right/mid.. */ + + /* clear routing stuff */ + apu_set_register(ess, channel, 11, 0x0000); + /* mark dma and turn on filter stuff? */ + apu_set_register(ess, channel, 0, 0x400F); + + if(mode&ESS_CFMT_STEREO) + /* set panning: left or right */ + apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0)); + else + apu_set_register(ess, channel, 10, 0x8F08); + + } + + /* clear WP interupts */ + outw(1, ess->card->iobase+0x04); + /* enable WP ints */ + outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); + + set_dac_rate(ess,rate); + + for(channel=0; channel<=high_apu; channel++) + { + /* Turn on the DMA */ + if(mode&ESS_CFMT_16BIT) + { + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x10); + ess->apu_mode[channel]=0x10; + } + else + { + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x30); + ess->apu_mode[channel]=0x30; + } + } +} + +/* --------------------------------------------------------------------- */ + +static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +/* Playback pointer */ +extern __inline__ unsigned get_dmaa(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[0]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + +/* M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base);*/ + + offset-=s->dma_dac.base; + + return (offset&0xFFFE)/*<<1*/; /* XXX printk didn't have it */ +} + +/* Record pointer */ +extern __inline__ unsigned get_dmac(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[2]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + + /* The offset is an address not a position relative to base */ + + return (offset&0xFFFE)<<1; /* hardware is in words */ +} + +/* + * Meet Bob, the timer... + */ + +static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +#define ESS_HW_TIMER + +#ifndef ESS_HW_TIMER + +/* old kernel timer based timer ints, should BOB prove flakey */ + +static struct timer_list tmp_timer; + +static int bob_stopped; + +static void ess_interrupt_fake(unsigned long v) +{ + ess_interrupt(5, (void *)v, NULL); + del_timer(&tmp_timer); + if(!bob_stopped) + { + tmp_timer.expires=jiffies+1; + add_timer(&tmp_timer); + } + else + M_printk("Stopping bob (SW)\n"); +} + +static void stop_bob(struct ess_state *s) +{ + bob_stopped=1; +} + +static void kill_bob(struct ess_state *s) +{ + del_timer(&tmp_timer); + M_printk("Killing bob (SW)\n"); +} + +static void start_bob(struct ess_state *s) +{ + static int init=1; + if(init) + { + init=0; + init_timer(&tmp_timer); + tmp_timer.function = ess_interrupt_fake; + } + bob_stopped = 0; + if(!timer_pending(&tmp_timer)) + { + del_timer(&tmp_timer); + tmp_timer.expires = jiffies+1; + tmp_timer.data = (unsigned long)s->card; + add_timer(&tmp_timer); + M_printk("Starting bob (SW)\n"); + } +} + +#else + +/* nice HW BOB implementation. cheers, eric. */ + +static void stop_bob(struct ess_state *s) +{ + /* Mask IDR 11,17 */ + maestro_write(s, 0x11, maestro_read(s, 0x11)&~1); + maestro_write(s, 0x17, maestro_read(s, 0x17)&~1); +} + +/* eventually we could be clever and limit bob ints + to the frequency at which our smallest duration + chunks may expire */ +static void start_bob(struct ess_state *s) +{ + stop_bob(s); // make sure bob's not already running + + maestro_write(s, 6, 0x8000 |(1<<12) | (5<<5) | 11); // (50MHz/2^14)/12 = 254 Hz = 40 mS + + /* Now set IDR 11/17 */ + maestro_write(s, 0x11, maestro_read(s, 0x11)|1); + maestro_write(s, 0x17, maestro_read(s, 0x17)|1); +} +#endif // ESS_HW_TIMER +/* --------------------------------------------------------------------- */ + +static int adc_active = 0; + +extern inline void stop_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + /* Stop left and right recording APU */ + s->enable &= ~ADC_RUNNING; + apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F); + apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F); + adc_active&=~1; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +extern inline void stop_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + s->enable &= ~DAC_RUNNING; + apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F); + apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F); + adc_active&=~2; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { + s->enable |= DAC_RUNNING; + + apu_set_register(s, 0, 0, + (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]); + + if(s->fmt & ESS_CFMT_STEREO) + apu_set_register(s, 1, 0, + (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=2; + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) + && s->dma_adc.ready) { + s->enable |= ADC_RUNNING; + apu_set_register(s, 2, 0, + (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]); + apu_set_register(s, 3, 0, + (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=1; + spin_unlock_irqrestore(&s->lock, flags); +} + +/* --------------------------------------------------------------------- */ + +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +static void dealloc_dmabuf(struct dmabuf *db) +{ + unsigned long map, mapend; + + if (db->rawbuf) { + /* undo marking the pages as reserved */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &mem_map[map].flags); + free_pages((unsigned long)db->rawbuf, db->buforder); + } + db->rawbuf = NULL; + db->mapped = db->ready = 0; +} + + +static int prog_dmabuf(struct ess_state *s, unsigned rec) +{ + struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; + unsigned rate = rec ? s->rateadc : s->ratedac; + int order; + unsigned bytepersec; + unsigned bufs; + unsigned long map, mapend; + unsigned char fmt; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + fmt = s->fmt; + if (rec) { + s->enable &= ~ESS_ENABLE_RE; + fmt >>= ESS_CFMT_CSHIFT; + } else { + s->enable &= ~ESS_ENABLE_PE; + fmt >>= ESS_CFMT_ASHIFT; + } + spin_unlock_irqrestore(&s->lock, flags); + + db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; + + if (!db->rawbuf) { + db->ready = db->mapped = 0; + + /* alloc as big a chunk as we can */ + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) + db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order); + + if (!db->rawbuf) + return -ENOMEM; + + db->buforder = order; + + if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff) + printk(KERN_DEBUG "maestro: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + + if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff) + printk(KERN_DEBUG "maestro: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + set_bit(PG_reserved, &mem_map[map].flags); + } + bytepersec = rate << sample_shift[fmt]; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + if ((1000 << db->ossfragshift) < bytepersec) + db->fragshift = ld2(bytepersec/1000); + else + db->fragshift = db->ossfragshift; + } else { + db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); + if (db->fragshift < 3) + db->fragshift = 3; + } + db->numfrag = bufs >> db->fragshift; + while (db->numfrag < 4 && db->fragshift > 3) { + db->fragshift--; + db->numfrag = bufs >> db->fragshift; + } + db->fragsize = 1 << db->fragshift; + if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) + db->numfrag = db->ossmaxfrags; + db->fragsamples = db->fragsize >> sample_shift[fmt]; + db->dmasize = db->numfrag << db->fragshift; + memset(db->rawbuf, (fmt & ESS_CFMT_16BIT) ? 0 : 0x80, db->dmasize); + spin_lock_irqsave(&s->lock, flags); + if (rec) { + set_dmac(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + } else { + //set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + //set_dac_rate(s, s->ratedac); // redundant + ess_play_setup(s, fmt, s->ratedac, + db->rawbuf, db->numfrag << db->fragshift); + } + spin_unlock_irqrestore(&s->lock, flags); + db->ready = 1; + return 0; +} + +extern __inline__ void clear_advance(struct ess_state *s) +{ + unsigned char c = (s->fmt & (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT)) ? 0 : 0x80; + unsigned char *buf = s->dma_dac.rawbuf; + unsigned bsize = s->dma_dac.dmasize; + unsigned bptr = s->dma_dac.swptr; + unsigned len = s->dma_dac.fragsize; + + if (bptr + len > bsize) { + unsigned x = bsize - bptr; + memset(buf + bptr, c, x); + /* account for wrapping? */ + bptr = 0; + len -= x; + } + memset(buf + bptr, c, len); +} + +/* call with spinlock held! */ +static void ess_update_ptr(struct ess_state *s) +{ + unsigned hwptr; + int diff; + + /* update ADC pointer */ + if (s->dma_adc.ready) { + M_printk("adc ready.. \n"); + hwptr = (/*s->dma_adc.dmasize - */get_dmac(s)) % s->dma_adc.dmasize; + diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; + s->dma_adc.hwptr = hwptr; + s->dma_adc.total_bytes += diff; + s->dma_adc.count += diff; + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + wake_up(&s->dma_adc.wait); + if (!s->dma_adc.mapped) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { + s->enable &= ~ESS_ENABLE_RE; + /* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + stop_adc(s); + s->dma_adc.error++; + } + } + } + /* update DAC pointer */ + if (s->dma_dac.ready) { + hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; + diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; +/* M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/ + s->dma_dac.hwptr = hwptr; + s->dma_dac.total_bytes += diff; + if (s->dma_dac.mapped) { + s->dma_dac.count += diff; + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + wake_up(&s->dma_dac.wait); + } else { + s->dma_dac.count -= diff; + if (s->dma_dac.count <= 0) { + s->enable &= ~ESS_ENABLE_PE; +/* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + + stop_dac(s); + s->dma_dac.error++; + } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { + clear_advance(s); + s->dma_dac.endcleared = 1; + } + if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) + wake_up(&s->dma_dac.wait); + } + } +} + +static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ess_state *s; + struct ess_card *c = (struct ess_card *)dev_id; + int i; + u32 event; + + event = inb(c->iobase+0x1A); + + outw(inw(c->iobase+4)&1, c->iobase+4); + +/* M_printk("maestro int: %x\n",event);*/ + + if(event&(1<<6)) + { + /* XXX if we have a hw volume control int enable + all the ints? doesn't make sense.. */ + event = inw(c->iobase+0x18); + outb(0xFF, c->iobase+0x1A); + } + else + { + /* else ack 'em all, i imagine */ + outb(0xFF, c->iobase+0x1A); + } + + /* + * Update the pointers for all APU's we are running. + */ + for(i=0;i<8;i++) + { + s=&c->channels[i]; + if(s->dev_audio == -1) + break; + spin_lock(&s->lock); + ess_update_ptr(s); + spin_unlock(&s->lock); + } +} + + +/* --------------------------------------------------------------------- */ + +static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n"; + +#define VALIDATE_MAGIC(FOO,MAG) \ +({ \ + if (!(FOO) || (FOO)->magic != MAG) { \ + printk(invalid_magic,__FUNCTION__); \ + return -ENXIO; \ + } \ +}) + +#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC) +#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC) + +/* --------------------------------------------------------------------- */ + +/* ac97 mixer routines. */ + +#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\ + SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\ + SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN) + +#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ + SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\ + SOUND_MASK_SPEAKER) + +#define AC97_RECORD_MASK (SOUND_MASK_MIC|\ + SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\ + SOUND_MASK_PHONEIN) + +#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<iobase , mh->offset); + + if(AC97_STEREO_MASK & (1<> 8) & 0x7f; + right = val & 0x7f; + + right = 100 - ((right * 100) / mh->scale); + left = 100 - ((left * 100) / mh->scale); + ret = left | (right << 8); + } else if (mixer == SOUND_MIXER_SPEAKER) { + ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); + } else if (mixer == SOUND_MIXER_MIC) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); + /* the low bit is optional in the tone sliders and masking + it lets is avoid the 0xf 'bypass'.. */ + } else if (mixer == SOUND_MIXER_BASS) { + ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); + } else if (mixer == SOUND_MIXER_TREBLE) { + ret = 100 - (((val & 0xe) * 100) / mh->scale); + } + + M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret); + + return ret; +} + +/* write the OSS encoded volume to the given OSS encoded mixer, + again caller's job to make sure all is well in arg land, + call with spinlock held */ +static void ac97_write_mixer(struct ess_card *card,int mixer, int vol) +{ + u16 val=0; + unsigned left, right; + struct ac97_mixer_hw *mh = &ac97_hw[mixer]; + + /* cleanse input a little */ + right = ((vol >> 8) & 0x7f) ; + left = (vol & 0x7f) ; + + if(right > 100) right = 100; + if(left > 100) left = 100; + + M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right); + + if(AC97_STEREO_MASK & (1<scale) / 100; + left = ((100 - left) * mh->scale) / 100; + + val = (left << 8) | right; + } else if (mixer == SOUND_MIXER_SPEAKER) { + val = (((100 - left) * mh->scale) / 100) << 1; + } else if (mixer == SOUND_MIXER_MIC) { + val = maestro_ac97_get(card->iobase , mh->offset) & ~0x001f; + val |= (((100 - left) * mh->scale) / 100); + /* the low bit is optional in the tone sliders and masking + it lets is avoid the 0xf 'bypass'.. */ + } else if (mixer == SOUND_MIXER_BASS) { + val = maestro_ac97_get(card->iobase , mh->offset) & ~0x0f00; + val |= ((((100 - left) * mh->scale) / 100) << 8) & 0xe0; + } else if (mixer == SOUND_MIXER_TREBLE) { + val = maestro_ac97_get(card->iobase , mh->offset) & ~0x000f; + val |= (((100 - left) * mh->scale) / 100) & 0xe; + } + + maestro_ac97_set(card->iobase , mh->offset, val); + + M_printk(" -> %x\n",val); +} + +enum ac97_recsettings { + AC97_REC_MIC=0, + AC97_REC_CD, + AC97_REC_VIDEO, + AC97_REC_AUX, + AC97_REC_LINE, + AC97_REC_STEREO, /* combination of all enabled outputs.. */ + AC97_REC_MONO, /*.. or the mono equivalent */ + AC97_REC_PHONE +}; +static unsigned int ac97_rm2oss[] = { + [AC97_REC_MIC] = SOUND_MASK_MIC, + [AC97_REC_CD] = SOUND_MASK_CD, + [AC97_REC_VIDEO] = SOUND_MASK_VIDEO, + [AC97_REC_AUX] = SOUND_MASK_LINE1, + [AC97_REC_LINE] = SOUND_MASK_LINE, + [AC97_REC_PHONE] = SOUND_MASK_PHONEIN +}; + +/* indexed by bit position, XXX dependant on OSS header internals */ +static unsigned int ac97_oss_rm[] = { + [SOUND_MIXER_MIC] = AC97_REC_MIC, + [SOUND_MIXER_CD] = AC97_REC_CD, + [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, + [SOUND_MIXER_LINE1] = AC97_REC_AUX, + [SOUND_MIXER_LINE] = AC97_REC_LINE, + [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE +}; + +/* read or write the recmask + the ac97 can really have left and right recording + inputs independantly set, but OSS doesn't seem to + want us to express that to the user. + the caller guarantees that we have a supported bit set, + and they must be holding the card's spinlock */ +static int ac97_recmask_io(struct ess_card *card, int rw, int mask) +{ + unsigned int val; + + if (rw) { + /* read it from the card */ + val = maestro_ac97_get(card->iobase, 0x1a) & 0x7; + return ac97_rm2oss[val]; + } + + /* else, write the first set in the mask as the + output */ + + val = ffs(mask); + val = ac97_oss_rm[val-1]; + val |= val << 8; /* set both channels */ + + maestro_ac97_set(card->iobase,0x1a,val); + + return 0; +}; + +static int ac97_mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int i, val=0; + struct ess_state *s = &card->channels[0]; + + VALIDATE_CARD(card); + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, card_names[card->card_type], sizeof(info.id)); + strncpy(info.name,card_names[card->card_type],sizeof(info.name)); + info.modify_counter = card->mix.modcnt; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, card_names[card->card_type], sizeof(info.id)); + strncpy(info.name,card_names[card->card_type],sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* give them the current record source */ + spin_lock_irqsave(&s->lock, flags); + val = card->mix.recmask_io(card,1,0); + spin_unlock_irqrestore(&s->lock, flags); + break; + + case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ + val = card->mix.supported_mixers; + break; + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + val = card->mix.record_sources; + break; + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + val = card->mix.stereo_mixers; + break; + + case SOUND_MIXER_CAPS: + val = SOUND_CAP_EXCL_INPUT; + break; + + default: /* read a specific mixer */ + i = _IOC_NR(cmd); + + if ( ! supported_mixer(card,i)) + return -EINVAL; + + spin_lock_irqsave(&s->lock, flags); + val = card->mix.read_mixer(card,i); + spin_unlock_irqrestore(&s->lock, flags); + + break; + } + return put_user(val,(int *)arg); + } + + if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ)) + return -EINVAL; + + card->mix.modcnt++; + + get_user_ret(val, (int *)arg, -EFAULT); + + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + + if(! (val &= card->mix.record_sources)) return -EINVAL; + + spin_lock_irqsave(&s->lock, flags); + card->mix.recmask_io(card,0,val); + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + default: + i = _IOC_NR(cmd); + + if ( ! supported_mixer(card,i)) + return -EINVAL; + + spin_lock_irqsave(&s->lock, flags); + card->mix.write_mixer(card,i,val); + spin_unlock_irqrestore(&s->lock, flags); + + return 0; + } +} + +/* --------------------------------------------------------------------- */ + +static loff_t ess_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + +static int ess_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_card *card = devs; + + while (card && card->dev_mixer != minor) + card = card->next; + if (!card) + return -ENODEV; + + file->private_data = card; + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release_mixdev(struct inode *inode, struct file *file) +{ + struct ess_card *card = (struct ess_card *)file->private_data; + + VALIDATE_CARD(card); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ess_card *card = (struct ess_card *)file->private_data; + + VALIDATE_CARD(card); + + return ac97_mixer_ioctl(card, cmd, arg); +} + +static /*const*/ struct file_operations ess_mixer_fops = { + &ess_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &ess_ioctl_mixdev, + NULL, /* mmap */ + &ess_open_mixdev, + NULL, /* flush */ + &ess_release_mixdev, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +/* --------------------------------------------------------------------- */ + +static int drain_dac(struct ess_state *s, int nonblock) +{ + DECLARE_WAITQUEUE(wait,current); + unsigned long flags; + int count, tmo; + + if (s->dma_dac.mapped || !s->dma_dac.ready) + return 0; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac.wait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) { + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + tmo = (count * HZ) / s->ratedac; + tmo >>= sample_shift[(s->fmt >> ESS_CFMT_ASHIFT) & ESS_CFMT_MASK]; + if (!schedule_timeout(tmo ? : 1) && tmo) + printk(KERN_DEBUG "maestro: dma timed out??\n"); + } + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static ssize_t ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + /* for damned dual players */ + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_adc.mapped) + return -ENXIO; + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + swptr = s->dma_adc.swptr; + cnt = s->dma_adc.dmasize-swptr; + if (s->dma_adc.count < cnt) + cnt = s->dma_adc.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_adc(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + spin_lock_irqsave(&s->lock, flags); + set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); + /* program enhanced mode registers */ + /* FILL ME */ +// wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_adc.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_adc.swptr = swptr; + s->dma_adc.count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(s); + } + + return ret; +} + +/* god this is gross..*/ +int split_stereo(unsigned char *real_buffer,unsigned char *tmp_buffer, int offset, + int count, int bufsize, int mode) +{ + /* oh, bother. stereo decoding APU's don't work in 16bit so we + use dual linear decoders. which means we have to hack up stereo + buffer's we're given. yuck. + + and we have to be able to work a byte at a time..*/ + + unsigned char *so,*left,*right; + int i; + + so = tmp_buffer; + left = real_buffer + offset; + right = real_buffer + bufsize/2 + offset; + + M_printk("writing %d to %p and %p from %p:%d bufs: %d\n",count/2, left,right,real_buffer,offset,bufsize); + + if(mode & ESS_CFMT_16BIT) { + for(i=count/4; i ; i--) { + *(right++) = (*(so+2)); + *(right++) = (*(so+3)); + *(left++) = (*so); + *(left++) = (*(so+1)); + so+=4; + } + } else { + for(i=count/2; i ; i--) { + *(right++) = (*(so+1)); + *(left++) = (*so); + so+=2; + } + } + + return 0; +} + +static ssize_t ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + unsigned char *splitbuf = NULL; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_dac.mapped) + return -ENXIO; + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + /* I wish we could be more clever than this */ + if (!(splitbuf = kmalloc(count,GFP_KERNEL))) + return -ENOMEM; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + + if (s->dma_dac.count < 0) { + s->dma_dac.count = 0; + s->dma_dac.swptr = s->dma_dac.hwptr; + } + swptr = s->dma_dac.swptr; + + if(s->fmt & ESS_CFMT_STEREO) { + /* in stereo we have the 'dual' buffers.. */ + cnt = ((s->dma_dac.dmasize/2)-swptr)*2; + } else { + cnt = s->dma_dac.dmasize-swptr; + } + if (s->dma_dac.count + cnt > s->dma_dac.dmasize) + cnt = s->dma_dac.dmasize - s->dma_dac.count; + + spin_unlock_irqrestore(&s->lock, flags); + + if (cnt > count) + cnt = count; + + /* our goofball stereo splitter can only deal in mults of 4 */ + if (cnt > 0) + cnt &= ~3; + + if (cnt <= 0) { + /* buffer is full, wait for it to be played */ + start_dac(s); + if (file->f_flags & O_NONBLOCK) { + if(!ret) ret = -EAGAIN; + goto return_free; + } + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + spin_lock_irqsave(&s->lock, flags); + set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); + /* program enhanced mode registers */ +// wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); + /* FILL ME */ + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) { + if (!ret) ret = -ERESTARTSYS; + goto return_free; + } + continue; + } + if(s->fmt & ESS_CFMT_STEREO) { + if (copy_from_user(splitbuf, buffer, cnt)) { + if (!ret) ret = -EFAULT; + goto return_free; + } + split_stereo(s->dma_dac.rawbuf,splitbuf,swptr,cnt,s->dma_dac.dmasize,s->fmt); + } else { + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { + if (!ret) ret = -EFAULT; + goto return_free; + } + } + + if(s->fmt & ESS_CFMT_STEREO) { + /* again with the weird pointer magic*/ + swptr = (swptr + (cnt/2)) % (s->dma_dac.dmasize/2); + } else { + swptr = (swptr + cnt) % s->dma_dac.dmasize; + } + spin_lock_irqsave(&s->lock, flags); + s->dma_dac.swptr = swptr; + s->dma_dac.count += cnt; + s->dma_dac.endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } +return_free: + if (splitbuf) kfree(splitbuf); + return ret; +} + +static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &s->dma_dac.wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &s->dma_adc.wait, wait); + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + +/* this needs to be fixed to deal with the dualing apus/buffers */ +#if 0 +static int ess_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + struct dmabuf *db; + int ret; + unsigned long size; + + VALIDATE_STATE(s); + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(s, 1)) != 0) + return ret; + db = &s->dma_dac; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(s, 0)) != 0) + return ret; + db = &s->dma_adc; + } else + return -EINVAL; + if (vma->vm_offset != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + return -EAGAIN; + db->mapped = 1; + return 0; +} +#endif + +static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + unsigned char fmtm, fmtd; + + VALIDATE_STATE(s); + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(0/*DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP*/, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SPEED: + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + set_adc_rate(s, val); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + set_dac_rate(s, val); + } + } + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SNDCTL_DSP_STEREO: + get_user_ret(val, (int *)arg, -EFAULT); + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + return 0; + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? + (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? + AFMT_S16_LE : + AFMT_S8, + (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && s->enable & ESS_ENABLE_RE) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && s->enable & ESS_ENABLE_PE) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + start_adc(s); + } else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + start_dac(s); + } else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!(s->enable & ESS_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_dac.fragsize; + abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!(s->enable & ESS_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_adc.fragsize; + abinfo.bytes = s->dma_adc.count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + val = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_adc.total_bytes; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + cinfo.ptr = s->dma_adc.hwptr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_dac.total_bytes; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + cinfo.ptr = s->dma_dac.hwptr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(s, 0))) + return val; + return put_user(s->dma_dac.fragsize, (int *)arg); + } + if ((val = prog_dmabuf(s, 1))) + return val; + return put_user(s->dma_adc.fragsize, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + s->dma_adc.ossfragshift = val & 0xffff; + s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_adc.ossfragshift < 4) + s->dma_adc.ossfragshift = 4; + if (s->dma_adc.ossfragshift > 15) + s->dma_adc.ossfragshift = 15; + if (s->dma_adc.ossmaxfrags < 4) + s->dma_adc.ossmaxfrags = 4; + } + if (file->f_mode & FMODE_WRITE) { + s->dma_dac.ossfragshift = val & 0xffff; + s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_dac.ossfragshift < 4) + s->dma_dac.ossfragshift = 4; + if (s->dma_dac.ossfragshift > 15) + s->dma_dac.ossfragshift = 15; + if (s->dma_dac.ossmaxfrags < 4) + s->dma_dac.ossmaxfrags = 4; + } + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_adc.subdivision = val; + if (file->f_mode & FMODE_WRITE) + s->dma_dac.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + + } +// return mixer_ioctl(s, cmd, arg); + return -EINVAL; +} + +static int ess_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_card *c = devs; + struct ess_state *s = NULL, *sp; + int i; + unsigned char fmtm = ~0, fmts = 0; + + /* + * Scan the cards and find the channel. We only + * do this at open time so it is ok + */ + + while (c!=NULL) + { + for(i=0;i<8;i++) + { + sp=&c->channels[i]; + if(sp->dev_audio < 0) + continue; + if((sp->dev_audio ^ minor) & ~0xf) + continue; + s=sp; + } + c=c->next; + } + + if (!s) + return -ENODEV; + + VALIDATE_STATE(s); + file->private_data = s; + /* wait for device to become free */ + down(&s->open_sem); + while (s->open_mode & file->f_mode) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EWOULDBLOCK; + } + up(&s->open_sem); + interruptible_sleep_on(&s->open_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + if (file->f_mode & FMODE_READ) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_CSHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + set_adc_rate(s, 8000); + } + if (file->f_mode & FMODE_WRITE) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_ASHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + set_dac_rate(s, 8000); + } + set_fmt(s, fmtm, fmts); + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + start_bob(s); + up(&s->open_sem); + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + dealloc_dmabuf(&s->dma_dac); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + dealloc_dmabuf(&s->dma_adc); + } + s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + stop_bob(s); + up(&s->open_sem); + wake_up(&s->open_wait); + MOD_DEC_USE_COUNT; + return 0; +} + +static /*const*/ struct file_operations ess_audio_fops = { + &ess_llseek, + &ess_read, + &ess_write, + NULL, /* readdir */ + &ess_poll, + &ess_ioctl, + NULL, /* XXX &ess_mmap, */ + &ess_open, + NULL, /* flush */ + &ess_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + + +/* --------------------------------------------------------------------- */ + +/* XXX get rid of this + * maximum number of devices + */ +#define NR_DEVICE 4 + +/* --------------------------------------------------------------------- */ + +static int maestro_install(struct pci_dev *pcidev, int card_type, int index) +{ + u16 w; + u32 n; + int iobase; + int i; + struct ess_card *card; + struct ess_state *ess; + int apu; + int num = 0; + + iobase = pcidev->resource[0].start; + + card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); + if(card == NULL) + { + printk(KERN_WARNING "maestro: out of memory\n"); + return 0; + } + + memset(card, 0, sizeof(*card)); + + card->iobase = iobase; + card->card_type = card_type; + card->irq = pcidev->irq; + card->next = devs; + card->magic = ESS_CARD_MAGIC; + devs = card; + + /* init our 8 groups of 4 apus */ + for(i=0;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + + s->card = card; + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + init_MUTEX(&s->open_sem); + s->magic = ESS_STATE_MAGIC; + + s->apu[0] = 4*i; + s->apu[1] = (4*i)+1; + s->apu[2] = (4*i)+2; + s->apu[3] = (4*i)+3; + + if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) + printk("BOTCH!\n"); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0) + break; + } + + num = i; + + /* clear the rest if we ran out of slots to register */ + for(;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + s->dev_audio = -1; + } + + ess = &card->channels[0]; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "maestro: Configuring %s at 0x%04X\n", card_names[card_type], iobase); + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + pci_write_config_dword(pcidev, 0x56, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + +/* XXX do we care about these two ? */ + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + +#if 0 /* huh? its sub decode.. */ + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); +#endif + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + /* XXX huh? claims to be reserved.. */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + /* XXX how do we know which to use? */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<1); /* reserved, always write 0 */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w|=(1<<15); /* legacy decode off */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(0x1f); /* disable mpu irq/io, game port, fm, SB */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(apu=0;apu<16;apu++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + + /* + * The 1.10 test program seem to write 0 into the buffer area + * 0x1D0-0x1DF too. + */ + outw(0x01D0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + +#if 1 + wave_set_register(ess, IDR7_WAVE_ROMRAM, + (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400); +#else + maestro_write(ess, IDR7_WAVE_ROMRAM, + (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400); +#endif + + maestro_write(ess, IDR2_CRAM_DATA, 0x0000); + maestro_write(ess, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(ess, 0x09, 0x001B); + maestro_write(ess, 0x0A, 0x8000); + maestro_write(ess, 0x0B, 0x3F37); + maestro_write(ess, 0x0C, 0x0098); + + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0xF000)|0x8000); + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0x0F00)|0x0500); + + maestro_write(ess, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); /* 0300 ? */ + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + maestro_pt101_init(iobase); + } + else + { + maestro_ac97_init(iobase); + card->mix.supported_mixers = AC97_SUPPORTED_MASK; + card->mix.stereo_mixers = AC97_STEREO_MASK; + card->mix.record_sources = AC97_RECORD_MASK; + card->mix.read_mixer = ac97_read_mixer; + card->mix.write_mixer = ac97_write_mixer; + card->mix.recmask_io = ac97_recmask_io; + + if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) + printk("maestro: couldn't register mixer!\n"); + } + + /* Now clear the channel data */ + for(apu=0;apu<64;apu++) + { + for(w=0;w<0x0E;w++) + apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0); + } + + if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card)) + { + printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq); + return 0; + } + +// ess_play_test(ess); + printk("maestro: %d channels configured.\n", num); + return 1; +} + +#ifdef MODULE + +int __init init_module(void) +#else +int __init init_maestro(void) +#endif +{ + struct pci_dev *pcidev = NULL; + int index = 0; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + printk(KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n"); + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + index+=maestro_install(pcidev, TYPE_MAESTRO2, index); + if(index == NR_DEVICE) + return index; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { + index+=maestro_install(pcidev, TYPE_MAESTRO2E, index); + if(index == NR_DEVICE) + return index; + } + + /* + * ESS Maestro 1 + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, pcidev))!=NULL) + { + index+=maestro_install(pcidev, TYPE_MAESTRO, index); + if(index == NR_DEVICE) + return index; + } + if(index==0) + return -ENODEV; + return 0; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +MODULE_AUTHOR("Alan Cox "); +MODULE_DESCRIPTION("ESS Maestro Driver"); +#ifdef M_DEBUG +MODULE_PARM(debug,"i"); +#endif + +void cleanup_module(void) +{ + struct ess_card *s; + + while ((s = devs)) { + int i; + devs = devs->next; +// ess_play_test(&s->channels[0]); +#ifndef ESS_HW_TIMER + kill_bob(&s->channels[0]); +#else + stop_bob(&s->channels[0]); +#endif +// outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ +// synchronize_irq(); +// inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ +// wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ + //outb(0, s->iodmaa + SV_DMA_RESET); + //outb(0, s->iodmac + SV_DMA_RESET); + free_irq(s->irq, s); + unregister_sound_mixer(s->dev_mixer); + for(i=0;i<8;i++) + { + struct ess_state *ess = &s->channels[i]; + if(ess->dev_audio != -1) + unregister_sound_dsp(ess->dev_audio); + } + kfree(s); + } + M_printk("maestro: unloading\n"); +} + +#endif /* MODULE */ + +#if 0 +/*============================================================================ + * ex-code that we're not using anymore.. + *============================================================================ + */ +/* + * The ASSP is fortunately not double indexed + */ + +static void assp_set_register(int ioaddr, u32 reg, u32 value) +{ + unsigned long flags; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + outl(value, ioaddr+0x84); + restore_flags(flags); +} + +static u32 assp_get_register(int ioaddr, u32 reg) +{ + unsigned long flags; + u32 value; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + value=inl(ioaddr+0x84); + restore_flags(flags); + + return value; +} + +/* the ASP is basically a DSP that one can dma instructions + into. it can do things like surround encoding or + fm synth in sb emul mode. It is highly proprietary + and the ESS dudes are none too excited about telling + us about it. so screw it, we'll just turn it off and + not bother with it. Its not needed for apu/dac work. */ + + +static void asp_load(int ioaddr, u16 l, u16 h, u16 *data, int len) +{ + int i; + outw(l, ioaddr+0x80); + outw(h, ioaddr+0x82); + for(i=0;icp0_epc += 4; } -__initfunc(static void tc_probe(unsigned long startaddr, unsigned long size, int max_slot)) +static void __init tc_probe(unsigned long startaddr, unsigned long size, int max_slot) { int i, slot; long offset; @@ -164,7 +164,7 @@ /* * the main entry */ -__initfunc(void tc_init(void)) +void __init tc_init(void) { int tc_clock; int i; diff -u --recursive --new-file v2.3.15/linux/drivers/tc/zs.c linux/drivers/tc/zs.c --- v2.3.15/linux/drivers/tc/zs.c Fri Jun 25 17:38:40 1999 +++ linux/drivers/tc/zs.c Tue Aug 31 11:30:48 1999 @@ -1315,7 +1315,6 @@ 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 */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -1433,7 +1432,7 @@ (tty->termios->c_cflag & CBAUD)) zs_rtsdtr(info, 1); sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -1564,7 +1563,7 @@ /* Finally, routines used to initialize the serial driver. */ -__initfunc(static void show_serial_version(void)) +static void __init show_serial_version(void) { printk("DECstation Z8530 serial driver version 0.03\n"); } @@ -1572,7 +1571,7 @@ /* Initialize Z8530s zs_channels */ -__initfunc(static void probe_sccs(void)) +static void __init probe_sccs(void) { struct dec_serial **pp; int i, n, n_chips = 0, n_channels, chip, channel; @@ -1654,7 +1653,7 @@ } /* zs_init inits the driver */ -__initfunc(int zs_init(void)) +int __init zs_init(void) { int channel, i; unsigned long flags; @@ -1886,7 +1885,7 @@ * - initialize the serial port * Return non-zero if we didn't find a serial port. */ -__initfunc(static int serial_console_setup(struct console *co, char *options)) +static int __init serial_console_setup(struct console *co, char *options) { struct dec_serial *info; int baud = 9600; @@ -2022,7 +2021,7 @@ /* * Register console. */ -__initfunc (long zs_serial_console_init(long kmem_start, long kmem_end)) +long __init zs_serial_console_init(long kmem_start, long kmem_end) { register_console(&sercons); return kmem_start; @@ -2087,7 +2086,7 @@ * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */ -__initfunc(void zs_kgdb_hook(int tty_num)) +void __init zs_kgdb_hook(int tty_num) { /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) diff -u --recursive --new-file v2.3.15/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.15/linux/drivers/usb/acm.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/acm.c Tue Aug 31 12:38:12 1999 @@ -23,10 +23,7 @@ * uhci.c. Should have the correct interface now. * (6/6/99) * - * version 0.5 driver now generates a tty instead of a simple character - * device - * - * version 0.3: Mayor changes. Changed Bulk transfer to interrupt based + * version 0.3: Major changes. Changed Bulk transfer to interrupt based * transfer. Using FIFO Buffers now. Consistent handling of open/close * file state and detected/nondetected device. File operations behave * according to this. Driver is able to send+receive now! Heureka! @@ -485,6 +482,7 @@ struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; int cfgnum,acmno; + int swapped=0; info("acm_probe\n"); @@ -500,14 +498,13 @@ dev->descriptor.bDeviceProtocol != 0) return -1; - /* Now scan all configs for a ACM configuration */ +#define IFCLASS(if) ((if->bInterfaceClass << 24) | (if->bInterfaceSubClass << 16) | (if->bInterfaceProtocol << 8) | (if->bNumEndpoints)) + + /* Now scan all configs for a ACM configuration*/ for (cfgnum=0;cfgnumdescriptor.bNumConfigurations;cfgnum++) { /* The first one should be Communications interface? */ interface = &dev->config[cfgnum].interface[0].altsetting[0]; - if (interface->bInterfaceClass != 2 || - interface->bInterfaceSubClass != 2 || - interface->bInterfaceProtocol != 1 || - interface->bNumEndpoints != 1) + if (IFCLASS(interface) != 0x02020101) continue; /*Which uses an interrupt input */ @@ -519,19 +516,20 @@ /* The second one should be a Data interface? */ interface = &dev->config[cfgnum].interface[1].altsetting[0]; if (interface->bInterfaceClass != 10 || - interface->bInterfaceSubClass != 0 || - interface->bInterfaceProtocol != 0 || - interface->bNumEndpoints != 2) + interface->bNumEndpoints != 2) continue; + if ((endpoint->bEndpointAddress & 0x80) == 0x80) + swapped = 1; + /*With a bulk input */ - endpoint = &interface->endpoint[0]; + endpoint = &interface->endpoint[0^swapped]; if ((endpoint->bEndpointAddress & 0x80) != 0x80 || (endpoint->bmAttributes & 3) != 2) continue; /*And a bulk output */ - endpoint = &interface->endpoint[1]; + endpoint = &interface->endpoint[1^swapped]; if ((endpoint->bEndpointAddress & 0x80) == 0x80 || (endpoint->bmAttributes & 3) != 2) continue; @@ -542,30 +540,30 @@ acm->dev=dev; dev->private=acm; - acm->readendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0].bEndpointAddress; + acm->readendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0^swapped].bEndpointAddress; acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp); - acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0].wMaxPacketSize,GFP_KERNEL); + acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0^swapped].wMaxPacketSize,GFP_KERNEL); acm->reading=0; if (!acm->readbuffer) { printk("ACM: Couldn't allocate readbuffer\n"); return -1; } - - acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1].bEndpointAddress; + + acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].bEndpointAddress; acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp); - acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1].wMaxPacketSize, GFP_KERNEL); + acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].wMaxPacketSize, GFP_KERNEL); acm->writing=0; if (!acm->writebuffer) { printk("ACM: Couldn't allocate writebuffer\n"); kfree(acm->readbuffer); return -1; } - + acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress; acm->ctrlpipe=usb_rcvctrlpipe(acm->dev,acm->ctrlendp); acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval; - acm->present=1; + acm->present=1; MOD_INC_USE_COUNT; return 0; } @@ -660,7 +658,10 @@ acm_tty_driver.read_proc = NULL; //rs_read_proc; acm_tty_driver.chars_in_buffer = rs_chars_in_buffer; acm_tty_driver.flush_buffer = NULL; //rs_flush_buffer; - tty_register_driver(&acm_tty_driver); + if (tty_register_driver(&acm_tty_driver)) { + printk( "acm: failed to register tty driver\n" ); + return -EPERM; + } //REGISTER USB DRIVER usb_register(&acm_driver); diff -u --recursive --new-file v2.3.15/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.3.15/linux/drivers/usb/printer.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/printer.c Fri Aug 27 12:35:57 1999 @@ -163,6 +163,11 @@ unsigned long partial; int result = USB_ST_NOERROR; int maxretry; + int endpoint_num; + struct usb_interface_descriptor *interface; + + interface = p->pusb_dev->config->interface->altsetting; + endpoint_num = (interface->endpoint[1].bEndpointAddress & 0x0f); do { char *obuf = p->obuf; @@ -179,7 +184,8 @@ return bytes_written ? bytes_written : -EINTR; } result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev, - usb_sndbulkpipe(p->pusb_dev, 1), obuf, thistime, &partial); + usb_sndbulkpipe(p->pusb_dev, endpoint_num), + obuf, thistime, &partial); if (partial) { obuf += partial; thistime -= partial; @@ -218,6 +224,11 @@ char buf[64]; unsigned long partial; int result; + int endpoint_num; + struct usb_interface_descriptor *interface; + + interface = p->pusb_dev->config->interface->altsetting; + endpoint_num = (interface->endpoint[0].bEndpointAddress & 0x0f); if (p->noinput) return -EINVAL; @@ -232,7 +243,8 @@ this_read = (count > sizeof(buf)) ? sizeof(buf) : count; result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev, - usb_rcvbulkpipe(p->pusb_dev, 2), buf, this_read, &partial); + usb_rcvbulkpipe(p->pusb_dev, endpoint_num), + buf, this_read, &partial); /* unlike writes, we don't retry a NAK, just stop now */ if (!result & partial) @@ -276,10 +288,10 @@ return -1; } - if (interface->endpoint[0].bEndpointAddress != 0x01 || + if ((interface->endpoint[0].bEndpointAddress & 0xf0) != 0x00 || interface->endpoint[0].bmAttributes != 0x02 || (interface->bNumEndpoints > 1 && ( - interface->endpoint[1].bEndpointAddress != 0x82 || + (interface->endpoint[1].bEndpointAddress & 0xf0) != 0x80 || interface->endpoint[1].bmAttributes != 0x02))) { return -1; } diff -u --recursive --new-file v2.3.15/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c --- v2.3.15/linux/drivers/usb/proc_usb.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/proc_usb.c Fri Aug 27 11:46:35 1999 @@ -1,6 +1,7 @@ /* * drivers/usb/proc_usb.c * (C) Copyright 1999 Randy Dunlap. + * (C) Copyright 1999 Thomas Sailer . (proc file per device) * * 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 @@ -48,6 +49,9 @@ #include #include #include +#include +#include +#include #include "usb.h" @@ -191,7 +195,7 @@ * which ones are active, if any) * 2. Add proc_usb_init() call from usb-core.c. * 3. proc_usb as a MODULE ? - * 4. use __initfunc() ? + * 4. use __init ? * 5. add status to each endpoint line */ @@ -435,12 +439,7 @@ /* * proc entry for every device - * sailer@ife.ee.ethz.ch */ -#include -#include -#include -#include "ezusb.h" static long long usbdev_lseek(struct file * file, long long offset, int orig) { @@ -484,8 +483,12 @@ return ret; } -static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +/* note: this is a compatibility kludge that will vanish soon. */ +#include "ezusb.h" + +static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + static unsigned obsolete_warn = 0; struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip; struct usb_device *dev = (struct usb_device *)dp->data; struct ezusb_ctrltransfer ctrl; @@ -498,6 +501,11 @@ switch (cmd) { case EZUSB_CONTROL: + if (obsolete_warn < 20) { + printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_CONTROL ioctl\n", + current->pid, current->comm); + obsolete_warn++; + } if (!capable(CAP_SYS_RAWIO)) return -EPERM; copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT); @@ -529,6 +537,11 @@ return 0; case EZUSB_BULK: + if (obsolete_warn < 20) { + printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_BULK ioctl\n", + current->pid, current->comm); + obsolete_warn++; + } if (!capable(CAP_SYS_RAWIO)) return -EPERM; copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); @@ -567,6 +580,11 @@ return len2; case EZUSB_RESETEP: + if (obsolete_warn < 20) { + printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_RESETEP ioctl\n", + current->pid, current->comm); + obsolete_warn++; + } if (!capable(CAP_SYS_RAWIO)) return -EPERM; get_user_ret(ep, (unsigned int *)arg, -EFAULT); @@ -576,12 +594,131 @@ return 0; case EZUSB_SETINTERFACE: + if (obsolete_warn < 20) { + printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_SETINTERFACE ioctl\n", + current->pid, current->comm); + obsolete_warn++; + } if (!capable(CAP_SYS_RAWIO)) return -EPERM; copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT); if (usb_set_interface(dev, setintf.interface, setintf.altsetting)) return -EINVAL; return 0; + } + return -ENOIOCTLCMD; +} + + + +static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip; + struct usb_device *dev = (struct usb_device *)dp->data; + struct usb_proc_ctrltransfer ctrl; + struct usb_proc_bulktransfer bulk; + struct usb_proc_setinterface setintf; + unsigned int len1, ep, pipe; + unsigned long len2; + unsigned char *tbuf; + int i; + + switch (cmd) { + case USB_PROC_CONTROL: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT); + if (ctrl.length > PAGE_SIZE) + return -EINVAL; + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (ctrl.requesttype & 0x80) { + if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) { + free_page((unsigned long)tbuf); + return -EINVAL; + } + i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, + ctrl.requesttype, ctrl.value, ctrl.index, tbuf, + ctrl.length); + if (!i && ctrl.length) { + copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT); + } + } else { + if (ctrl.length) { + copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT); + } + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, + ctrl.requesttype, ctrl.value, ctrl.index, tbuf, + ctrl.length); + } + free_page((unsigned long)tbuf); + if (i) { + printk(KERN_WARNING "/proc/bus/usb: USB_PROC_CONTROL failed rqt %u rq %u len %u ret %d\n", + ctrl.requesttype, ctrl.request, ctrl.length, i); + return -ENXIO; + } + return 0; + + case USB_PROC_BULK: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); + if (bulk.ep & 0x80) + pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); + else + pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); + if (!usb_maxpacket(dev, pipe, !(bulk.ep & 0x80))) + return -EINVAL; + len1 = bulk.len; + if (len1 > PAGE_SIZE) + len1 = PAGE_SIZE; + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (bulk.ep & 0x80) { + if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { + free_page((unsigned long)tbuf); + return -EINVAL; + } + i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2); + if (!i && len2) { + copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT); + } + } else { + if (len1) { + copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT); + } + i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2); + } + free_page((unsigned long)tbuf); + if (i) { + printk(KERN_WARNING "/proc/bus/usb: USB_PROC_BULK failed ep 0x%x len %u ret %d\n", + bulk.ep, bulk.len, i); + return -ENXIO; + } + return len2; + + case USB_PROC_RESETEP: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if ((ep & ~0x80) >= 16) + return -EINVAL; + usb_settoggle(dev, ep & 0xf, !(ep & 0x80), 0); + return 0; + + case USB_PROC_SETINTERFACE: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT); + if (usb_set_interface(dev, setintf.interface, setintf.altsetting)) + return -EINVAL; + return 0; + + case EZUSB_CONTROL: + case EZUSB_BULK: + case EZUSB_RESETEP: + case EZUSB_SETINTERFACE: + return usbdev_ioctl_ezusbcompat(inode, file, cmd, arg); } return -ENOIOCTLCMD; } diff -u --recursive --new-file v2.3.15/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.15/linux/drivers/usb/uhci.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/uhci.c Fri Aug 27 15:03:07 1999 @@ -192,7 +192,7 @@ if ((status == TD_CTRL_ACTIVE) && (!rval)) return USB_ST_DATAUNDERRUN; - return uhci_map_status(status, usb_pipeout(tmp->info) ^ 1); + return uhci_map_status(status, uhci_packetout(tmp->info)); } /* @@ -593,7 +593,7 @@ */ static int uhci_get_current_frame_number(struct usb_device *usb_dev) { - return inw (usb_to_uhci(usb_dev)->uhci->io_addr + USBFRNUM) & 0x3ff; + return inw (usb_to_uhci(usb_dev)->uhci->io_addr + USBFRNUM); } @@ -747,26 +747,52 @@ return -EINVAL; } + /* + * Check start_frame for inside a valid range. + * Only allow transfer requests to be made 1.000 second + * into the future. + */ + cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev); + /* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */ - if (!pr_isocdesc && (isocdesc->start_type != START_ASAP)) - if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > 1000)) { + if (!pr_isocdesc) + if (isocdesc->start_type == START_RELATIVE) { + if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > CAN_SCHEDULE_FRAMES)) { #ifdef CONFIG_USB_DEBUG_ISOC - printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", - isocdesc->start_frame); + printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", + isocdesc->start_frame); #endif - return -EINVAL; - } + return -EINVAL; + } + } /* end START_RELATIVE */ + else + if (isocdesc->start_type == START_ABSOLUTE) { + if (isocdesc->start_frame > cur_frame) { + if ((isocdesc->start_frame - cur_frame) > CAN_SCHEDULE_FRAMES) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", + isocdesc->start_frame); +#endif + return -EINVAL; + } + } + else /* start_frame <= cur_frame */ { + if ((isocdesc->start_frame + UHCI_MAX_SOF_NUMBER + 1 + - cur_frame) > CAN_SCHEDULE_FRAMES) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", + isocdesc->start_frame); +#endif + return -EINVAL; + } + } + } /* end START_ABSOLUTE */ /* * Set the start/end frame numbers. */ - if (!pr_isocdesc) - cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev); - if (pr_isocdesc) { isocdesc->start_frame = pr_isocdesc->end_frame + 1; - } else if (isocdesc->start_type == START_ABSOLUTE) { - /* Use start_frame as is. */ } else if (isocdesc->start_type == START_RELATIVE) { if (isocdesc->start_frame < START_FRAME_FUDGE) isocdesc->start_frame = START_FRAME_FUDGE; @@ -774,15 +800,16 @@ } else if (isocdesc->start_type == START_ASAP) { isocdesc->start_frame = cur_frame + START_FRAME_FUDGE; } + /* else for start_type == START_ABSOLUTE, use start_frame as is. */ /* and see if start_frame needs any correction */ - if (isocdesc->start_frame >= 1000) - isocdesc->start_frame -= 1000; + if (isocdesc->start_frame >= UHCI_NUMFRAMES) + isocdesc->start_frame -= UHCI_NUMFRAMES; /* and fix the end_frame value */ isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1; - if (isocdesc->end_frame >= 1000) - isocdesc->end_frame -= 1000; + if (isocdesc->end_frame >= UHCI_NUMFRAMES) + isocdesc->end_frame -= UHCI_NUMFRAMES; isocdesc->prev_completed_frame = -1; isocdesc->cur_completed_frame = -1; @@ -807,7 +834,7 @@ isocdesc->frame_spacing = 1; for (ix = 0, td = isocdesc->td, fd = isocdesc->frames; - ix < isocdesc->frame_count; ix++, td++, fd++, cur_frame++) { + ix < isocdesc->frame_count; ix++, td++, fd++) { frlen = fd->frame_length; if (frlen > isocdesc->frame_size) frlen = isocdesc->frame_size; @@ -823,7 +850,7 @@ td->info = destination | ((frlen - 1) << 21); td->buffer = virt_to_bus (bufptr); td->dev = dev; - td->isoc_td_number = ix; /* 0-based; does not wrap 999 -> 0 */ + td->isoc_td_number = ix; /* 0-based; does not wrap/overflow back to 0 */ if (isocdesc->callback_frames && (++cb_frames >= isocdesc->callback_frames)) { @@ -841,8 +868,8 @@ td->link = uhci->fl->frame [cur_frame]; uhci->fl->frame [cur_frame] = virt_to_bus (td); - if (cur_frame >= 999) - cur_frame = -1; + if (++cur_frame >= UHCI_NUMFRAMES) + cur_frame = 0; } /* end for ix */ /* @@ -872,7 +899,7 @@ struct uhci_td *td; int ix, cur_frame; - if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= 1000)) { + if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= UHCI_NUMFRAMES)) { #ifdef CONFIG_USB_DEBUG_ISOC printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n", isocdesc->start_frame); @@ -885,7 +912,7 @@ td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC); uhci->fl->frame [cur_frame] = td->link; - if (++cur_frame >= 1000) + if (++cur_frame >= UHCI_NUMFRAMES) cur_frame = 0; } /* end for ix */ @@ -1551,7 +1578,7 @@ usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1); td->info &= ~(1 << 19); /* clear data toggle */ td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info), - usb_pipeout(td->info) ^ 1) << 19; /* toggle between data0 and data1 */ + uhci_packetout(td->info)) << 19; /* toggle between data0 and data1 */ td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; /* The HC only removes it when it completed */ /* successfully, so force remove and readd it */ @@ -1562,7 +1589,7 @@ /* marked for removal */ td->flags &= ~UHCI_TD_REMOVE; - usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1); + usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), uhci_packetout(td->info)); uhci_remove_qh(td->qh->skel, td->qh); uhci_qh_free(td->qh); uhci_td_free(td); diff -u --recursive --new-file v2.3.15/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h --- v2.3.15/linux/drivers/usb/uhci.h Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/uhci.h Fri Aug 27 15:03:07 1999 @@ -60,7 +60,9 @@ #define UHCI_PTR_QH 0x0002 #define UHCI_PTR_DEPTH 0x0004 -#define UHCI_NUMFRAMES 1024 +#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */ +#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ +#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ struct uhci_td; @@ -80,7 +82,7 @@ } __attribute__((aligned(16))); struct uhci_framelist { - __u32 frame[1024]; + __u32 frame[UHCI_NUMFRAMES]; } __attribute__((aligned(4096))); /* @@ -127,20 +129,6 @@ #define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) #define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) -/* - * for TD : (a.k.a. Token) - */ -#define TD_TOKEN_TOGGLE 19 - -#define uhci_maxlen(token) ((token) >> 21) -#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) -#define uhci_endpoint(token) (((token) >> 15) & 0xf) -#define uhci_devaddr(token) (((token) >> 8) & 0x7f) -#define uhci_devep(token) (((token) >> 8) & 0x7ff) -#define uhci_packetid(token) ((token) & 0xff) -#define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) -#define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) - /* * The documentation says "4 words for hardware, 4 words for software". @@ -176,16 +164,6 @@ int isoc_td_number; /* 0-relative number within a usb_isoc_desc. */ } __attribute__((aligned(16))); -struct uhci_iso_td { - int num; /* Total number of TD's */ - char *data; /* Beginning of buffer */ - int maxsze; /* Maximum size of each data block */ - - struct uhci_td *td; /* Pointer to first TD */ - - int frame; /* Beginning frame */ - int endframe; /* End frame */ -}; /* * Note the alignment requirements of the entries diff -u --recursive --new-file v2.3.15/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.15/linux/drivers/usb/usb.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/usb.c Fri Aug 27 11:46:35 1999 @@ -1044,8 +1044,7 @@ dr.index = cpu_to_le16p(&index); dr.length = cpu_to_le16p(&size); - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, - data, size); + return dev->bus->op->control_msg(dev, pipe, &dr, data, size); } void *usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) diff -u --recursive --new-file v2.3.15/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.15/linux/drivers/usb/usb.h Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/usb.h Fri Aug 27 11:46:35 1999 @@ -1,33 +1,10 @@ #ifndef __LINUX_USB_H #define __LINUX_USB_H -#include #include -#include -#include +#include -extern int usb_hub_init(void); -extern int usb_kbd_init(void); -extern int usb_cpia_init(void); -extern int usb_mouse_init(void); -extern int usb_printer_init(void); - -extern void usb_hub_cleanup(void); -extern void usb_mouse_cleanup(void); - -static __inline__ void wait_ms(unsigned int ms) -{ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1 + ms * HZ / 1000); -} - -typedef struct { - __u8 requesttype; - __u8 request; - __u16 value; - __u16 index; - __u16 length; -} devrequest __attribute__ ((packed)); +/* USB constants */ /* * Device and/or Interface Class codes @@ -132,6 +109,69 @@ #define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE) +/* /proc/bus/usb/xxx/yyy ioctl codes */ + +struct usb_proc_ctrltransfer { + __u8 requesttype; + __u8 request; + __u16 value; + __u16 index; + __u16 length; + /* pointer to data */ + void *data; +}; + +#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer) + +struct usb_proc_bulktransfer { + unsigned int ep; + unsigned int len; + void *data; +}; + +#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer) + +#define USB_PROC_RESETEP _IOR('U', 3, unsigned int) + +struct usb_proc_setinterface { + unsigned int interface; + unsigned int altsetting; +}; + +#define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface) + + + + +#ifdef __KERNEL__ + +#include +#include +#include + +extern int usb_hub_init(void); +extern int usb_kbd_init(void); +extern int usb_cpia_init(void); +extern int usb_mouse_init(void); +extern int usb_printer_init(void); + +extern void usb_hub_cleanup(void); +extern void usb_mouse_cleanup(void); + +static __inline__ void wait_ms(unsigned int ms) +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1 + ms * HZ / 1000); +} + +typedef struct { + __u8 requesttype; + __u8 request; + __u16 value; + __u16 index; + __u16 length; +} devrequest __attribute__ ((packed)); + /* * Status codes (these follow OHCI controllers condition codes) */ @@ -639,6 +679,8 @@ extern inline void proc_usb_add_device(struct usb_device *dev) {} extern inline void proc_usb_remove_device(struct usb_device *dev) {} #endif + +#endif /* __KERNEL */ #endif diff -u --recursive --new-file v2.3.15/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c --- v2.3.15/linux/drivers/video/acornfb.c Thu Aug 26 13:05:40 1999 +++ linux/drivers/video/acornfb.c Mon Aug 30 18:15:21 1999 @@ -34,6 +34,7 @@ #include