diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/CREDITS linux.ac/CREDITS --- linux.vanilla/CREDITS Tue Apr 3 17:31:50 2001 +++ linux.ac/CREDITS Sun Apr 22 01:13:13 2001 @@ -311,9 +311,6 @@ W: http://samba.org/~anton/ P: 1024/8462A731 4C 55 86 34 44 59 A7 99 2B 97 88 4A 88 9A 0D 97 D: sun4 port, Sparc hacker -S: 47 Robert Street -S: Marrickville NSW 2204 -S: Australia N: Hugh Blemings E: hugh@misc.nu @@ -331,6 +328,9 @@ D: AUN network protocols D: Co-architect of the parallel port sharing system D: IPv6 netfilter +S: FutureTV Labs Ltd +S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG +S: United Kingdom N: Thomas Bogendörfer E: tsbogend@alpha.franken.de @@ -666,6 +666,14 @@ S: K1N 6Z9 S: CANADA +N: Jeff Dike +E: jdike@karaya.com +W: http://user-mode-linux.sourceforge.net +D: User mode kernel port +S: RR1 Box 67C +S: Deering NH 03244 +S: USA + N: Eddie C. Dost E: ecd@skynet.be D: Linux/Sparc kernel hacker @@ -766,6 +774,11 @@ S: S-114 53 Stockholm S: Sweden +N: Michael Engel +E: engel@unix-ag.org +D: DECstation framebuffer drivers +S: Germany + N: Paal-Kristian Engstad E: engstad@intermetrics.com D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.) @@ -1116,8 +1129,8 @@ E: rth@twiddle.net E: rth@cygnus.com D: Alpha hacker, kernel and userland -S: 50 E. Middlefield #10 -S: Mountain View, California 94043 +S: 1668 California St. +S: Mountain View, California 94041 S: USA N: Benjamin Herrenschmidt @@ -1220,13 +1233,12 @@ S: USA N: Harald Hoyer -E: HarryH@Royal.Net -W: http://hot.spotline.de/ -W: http://home.pages.de/~saturn +E: harald.hoyer@parzelle.de +W: http://parzelle.de/ D: ip_masq_quake D: md boot support -S: Alleenstrasse 27 -S: D-71679 Asperg +S: Hohe Strasse 30 +S: D-70176 Stuttgart S: Germany N: Jan Hubicka @@ -1479,8 +1491,9 @@ D: 6pack driver for AX.25 N: Harald Koerfgen -E: harald@unix-ag.org -D: DECstation port +E: hkoerfg@web.de +D: Linux/MIPS kernel hacks and fixes, +D: DECstation port, Sharp Mobilon port S: D-50931 Koeln S: Germany @@ -1725,12 +1738,8 @@ S: Czech Republic N: Paul Mackerras -E: paulus@linuxcare.com +E: paulus@samba.org D: Linux port for PCI Power Macintosh -S: Linuxcare, Inc. -S: 24 Marcus Clarke Street -S: Canberra ACT 2601 -S: Australia N: Pat Mackinlay E: pat@it.com.au @@ -1879,6 +1888,11 @@ S: 80050-430 - Curitiba - Paraná S: Brazil +N: Karsten Merker +E: merker@linuxtag.org +D: DECstation framebuffer drivers +S: Germany + N: Michael Meskes E: meskes@debian.org P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03 AB AB 15 A3 AE AD 39 7D @@ -2359,8 +2373,8 @@ S: Brazil N: Stephen Rothwell -E: sfr@linuxcare.com.au -W: http://linuxcare.com.au/sfr +E: sfr@canb.auug.org.au +W: http://www.canb.auug.org.au/~sfr P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02 D: Boot/setup/build work for setup > 2K D: Author, APM driver @@ -2403,12 +2417,12 @@ S: Germany N: Paul `Rusty' Russell -E: rusty@linuxcare.com +E: rusty@rustcorp.com.au W: http://www.samba.org/netfilter D: Ruggedly handsome. D: netfilter, ipchains with Michael Neuling. -S: 301/222 City Walk -S: Canberra ACT 2601 +S: 52 Moore St +S: Turner ACT 2612 S: Australia N: Bill Ryder @@ -2429,11 +2443,11 @@ S: Finland N: Thomas Sailer -E: sailer@ife.ee.ethz.ch +E: t.sailer@alumni.ethz.ch E: HB9JNX@HB9W.CHE.EU (packet radio) D: hfmodem, Baycom and sound card radio modem driver -S: Weinbergstrasse 76 -S: 8408 Winterthur +S: Markusstrasse 18 +S: 8006 Zuerich S: Switzerland N: Robert Sanders @@ -2516,6 +2530,14 @@ S: San Jose, California S: USA +N: Robert Siemer +E: Robert.Siemer@gmx.de +P: 2048/C99A4289 2F DC 17 2E 56 62 01 C8 3D F2 AC 09 F2 E5 DD EE +D: miroSOUND PCM20 radio RDS driver, ACI rewrite +S: Klosterweg 28 / i309 +S: 76131 Karlsruhe +S: Germany + N: Jaspreet Singh E: jaspreet@sangoma.com W: www.sangoma.com @@ -2696,7 +2718,7 @@ N: Andrew Tridgell E: tridge@samba.org -W: http://linuxcare.com.au/tridge/ +W: http://samba.org/tridge/ D: dosemu, networking, samba S: 3 Ballow Crescent S: MacGregor A.C.T 2615 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/Changes linux.ac/Documentation/Changes --- linux.vanilla/Documentation/Changes Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/Changes Thu Apr 12 11:47:29 2001 @@ -31,7 +31,7 @@ Eine deutsche Version dieser Datei finden Sie unter . -Last updated: January 11, 2001 +Last updated: April 6, 2001 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -54,7 +54,7 @@ o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V o e2fsprogs 1.19 # tune2fs -o reiserfsprogs 3.x.0d # reiserfsck 2>&1|grep reiserfsprogs +o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -148,7 +148,7 @@ -------- Upgrade to recent modutils to fix various outstanding bugs which are -seen more frequently under 2.3.x, and to enable auto-loading of USB +seen more frequently under 2.4.x, and to enable auto-loading of USB modules. In addition, the layout of modules under /lib/modules/`uname -r`/ has been made more sane. This change also requires that you upgrade to a recent modutils. @@ -227,7 +227,7 @@ The PPP driver has been restructured to support multilink and to enable it to operate over diverse media layers. If you use PPP, -upgrade pppd to at least 2.4.0b1. +upgrade pppd to at least 2.4.0. If you are not using devfs, you must have the device file /dev/ppp which can be made by: @@ -307,16 +307,16 @@ Mkinitrd -------- -o +o E2fsprogs --------- -o -o +o +o Reiserfsprogs ------------- -o +o LVM toolset ----------- @@ -347,7 +347,7 @@ PPP --- -o +o Isdn4k-utils ------------ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help --- linux.vanilla/Documentation/Configure.help Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/Configure.help Sun Apr 22 01:39:25 2001 @@ -1,4 +1,5 @@ -# Maintained by Axel Boldt (axel@uni-paderborn.de) +# Maintained by Eric S. Raymond +# and by Steven P. Cole # # This version of the Linux kernel configuration help texts # corresponds to the kernel versions 2.4.x. @@ -6,18 +7,20 @@ # Translations of this file available on the WWW: # # - Japanese, maintained by the JF Project (JF@linux.or.jp), at -# http://www.linux.or.jp/JF/JFdocs/Configure.help/ +# # - Russian, by kaf@linux.nevod.perm.su, at -# http://nevod.perm.su/service/linux/doc/kernel/Configure.help +# # - French, by Pierre Tane (tanep@bigfoot.com), at -# http://www.traduc.org/kernelfr +# # - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at -# http://visar.csustan.edu/~carlos/ +# +# XXX: Site has moved, new location has no Configure.help trans. # - Italian, by Alessandro Rubini (rubini@linux.it), at -# ftp://ftp-pavia1.linux.it/pub/linux/Configure.help +# +# XXX: ftp-pavia1.linux.it: Non-existent host/domain # - Polish, by Cezar Cichocki (cezar@cs.net.pl), at -# http://www.cs.net.pl/~cezar/Kernel -# - German, by SuSE, at http://www.suse.de/~ke/kernel . This patch +# +# - German, by SuSE, at . This patch # also includes infrastructure to support different languages. # # To access a document on the WWW, you need to have a direct Internet @@ -29,7 +32,7 @@ # # Information about what a kernel is, what it does, how to patch and # compile it and much more is contained in the Kernel-HOWTO, available -# at http://www.linuxdoc.org/docs.html#howto . Before you start +# at . Before you start # compiling, make sure that you have the necessary versions of all # programs and libraries required to compile and run this kernel; they # are listed in the file Documentation/Changes. Make sure to read the @@ -91,6 +94,12 @@ you say Y here, you will be offered the choice of using features or drivers that are currently considered to be in the alpha-test phase. +Prompt for drivers for obsolete features and hardware +CONFIG_OBSOLETE + Obsolete drivers have usually been replaced by more recent software that + can talk to the same hardware. Obsolete hardware is things like MGA + monitors that you are very unlikely to see on today's systems. + Symmetric Multi Processing CONFIG_SMP This enables support for systems with more than one CPU. If you have @@ -113,22 +122,40 @@ Management" code will be disabled if you say Y here. See also the files Documentation/smp.tex, Documentation/smp.txt, - Documentation/i386/IO-APIC.txt, Documentation/nmi_watchdog.txt and the - SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ . + Documentation/i386/IO-APIC.txt, Documentation/nmi_watchdog.txt and + the SMP-FAQ on the WWW at . If you don't know what to do here, say N. -APIC and IO-APIC Support on Uniprocessors +IO-APIC Support on Uniprocessors CONFIG_X86_UP_IOAPIC APIC (Advanced Programmable Interrupt Controller) is a scheme for delivering hardware interrupt requests to the CPU. It is commonly - used on systems with several CPU's. If you have a single-CPU system - which uses APIC, you can say Y here to use it. If you say Y here - even though your machine doesn't have APIC, then the kernel will - still run with no slowdown at all. + used on systems with several CPUs. If you have a single-CPU system + which has a processor that has an integrated APIC, you can say Y + here to enable and use it. If you say Y here even though your + machine doesn't have an APIC, then the kernel will still run with no + slowdown at all. The advantage of APIC support is the possibility + to use performance counters, and the APIC based NMI watchdog which + detects hard lockups. + + An IO-APIC is an SMP-capable replacement for PC-style interrupts + controllers, most SMP systems and a small number of uniprocessor + systems have these chips. Linux will try to detect and use this + chip, if it's not found then Linux falls back to PC-style interrupt + handling. - If you have system with several CPU's, you do not need to say Y - here: APIC will be used automatically. +APIC Support on Uniprocessors +CONFIG_X86_UP_APIC + APIC (Advanced Programmable Interrupt Controller) is a scheme for + delivering hardware interrupt requests to the CPU. It is commonly + used on systems with several CPUs. If you have a single-CPU system + which has a processor that has an integrated APIC, you can say Y + here to enable and use it. If you say Y here even though your + machine doesn't have an APIC, then the kernel will still run with no + slowdown at all. The advantage of APIC support is the possibility + to use performance counters, and the APIC based NMI watchdog which + detects hard lockups. Kernel math emulation CONFIG_MATH_EMULATION @@ -268,6 +295,11 @@ Most normal users won't need the RAM disk functionality, and can thus say N here. +Default RAM disk size +CONFIG_BLK_DEV_RAM_SIZE + The default value is 4096. Only change this if you know what are + you doing. If you are using IBM S/390, then set this to 8192. + Initial RAM disk (initrd) support CONFIG_BLK_DEV_INITRD The initial RAM disk is a RAM disk that is loaded by the boot loader @@ -298,18 +330,18 @@ bits of, say, a sound file). This is also safe if the file resides on a remote file server. If you want to do this, you will first have to acquire and install a kernel patch from - ftp://ftp.kerneli.org/pub/kerneli/ , and then you need to + , and then you need to say Y to this option. Note that alternative ways to use encrypted file systems are provided by the cfs package, which can be gotten from - ftp://ftp.kerneli.org/pub/kerneli/net-source/ , and the newer tcfs - package, available at http://tcfs.dia.unisa.it/ . You do not need to + , and the newer tcfs + package, available at . You do not need to say Y here if you want to use one of these. However, using cfs requires saying Y to "NFS file system support" below while using tcfs requires applying a kernel patch. An alternative steganography solution is provided by StegFS, also available from - ftp://ftp.kerneli.org/pub/kerneli/net-source/ . + . To use the loop device, you need the losetup utility and a recent version of the mount program, both contained in the util-linux @@ -411,11 +443,11 @@ topics, is contained in Documentation/ide.txt. For detailed information about hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . To fine-tune ATA/IDE drive/interface parameters for improved performance, look for the hdparm package at - ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -444,7 +476,7 @@ If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver instead of this one. For more detailed information, read the Disk-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Use old disk-only driver on primary interface CONFIG_BLK_DEV_HD_IDE @@ -500,11 +532,11 @@ to say Y or M to "ISO 9660 CDROM file system support". Read the CDROM-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto and the file + and the file Documentation/cdrom/ide-cd. Note that older versions of lilo (the Linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so install lilo-16 or higher, available from - ftp://metalab.unc.edu/pub/Linux/system/boot/lilo . + . 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), @@ -543,7 +575,7 @@ The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by this driver. For information about jumper settings and the question of when a ZIP drive uses a partition table, see - http://www.win.tue.nl/~aeb/linux/zip/zip-1.html . + . (ATAPI PD-CD/CDR drives are not supported by this driver; support for PD-CD/CDR drives is available if you answer Y to "SCSI emulation support", below). @@ -653,7 +685,7 @@ for these drives, but you can change that by saying Y to the following question "Use DMA by default when available". You can get the latest version of the hdparm utility from - ftp://metalab.unc.edu/pub/Linux/system/hardware/ . + . Read the comments at the beginning of drivers/ide/ide-dma.c and the file Documentation/ide.txt for more information. @@ -711,7 +743,7 @@ IGNORE word93 Validation BITS CONFIG_IDEDMA_IVB Since various rules were applied and created ... et al. as it relates - the detection of vaild cable signals. This is a result of unclear terms + the detection of valid cable signals. This is a result of unclear terms in ATA-4 and ATA-5 standards. It is normally safe to answer Y; however, the default is N. @@ -730,7 +762,7 @@ This card is 2,4, or 8 channel master mode support only. SCSI support required!!! - http://www.3ware.com/ + Please read the comments at the top of drivers/scsi/3w-xxxx.c @@ -868,9 +900,9 @@ This is a driver for the OPTi 82C621 EIDE controller. Please read the comments at the top of drivers/ide/opti621.c. -ServerWorks OSB4 chipset support (EXPERIMENTAL) +ServerWorks OSB4 chipset support CONFIG_BLK_DEV_OSB4 - This driver adds PIO/DMA support for the Serverworks OSB4 chipset + This driver adds PIO/(U)DMA support for the ServerWorks OSB4 chipset. Intel PIIXn chipsets support CONFIG_BLK_DEV_PIIX @@ -898,7 +930,7 @@ If unsure, say N. -PROMISE PDC20246/PDC20262/PDC20267 support +PROMISE PDC20246/PDC20262/PDC20265/PDC20267 support CONFIG_BLK_DEV_PDC202XX Promise Ultra33 or PDC20246 Promise Ultra66 or PDC20262 @@ -972,12 +1004,10 @@ VIA82CXXX chipset support CONFIG_BLK_DEV_VIA82CXXX This allows you to configure your chipset for a better use while - running (U)DMA: it will allow you to enable efficiently the second - channel dma usage, as it may not be set by BIOS. It allows you to - pass a kernel command line at boot time in order to set fifo - config. If no command line is provided, it will try to set fifo + running PIO/(U)DMA, it will allow you to enable efficiently the second + channel dma usage, as it may not be set by BIOS. It will try to set fifo configuration at its best. It will allow you to get information from - /proc/ide/via provided you enabled "proc" support. + /proc/ide/via provided you enabled "/proc file system" support. Please read the comments at the top of drivers/ide/via82cxxx.c @@ -986,12 +1016,6 @@ If unsure, say N. -VIA82CXXX Tuning support (WIP) -CONFIG_VIA82CXXX_TUNING - Please read the comments at the top of drivers/ide/via82cxxx.c - - If unsure, say N. - Other IDE chipset support CONFIG_IDE_CHIPSETS Say Y here if you want to include enhanced support for various IDE @@ -1285,7 +1309,7 @@ driver. See include/linux/pg.h for details. You can obtain the most recent version of cdrecord from - ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ . Versions 1.6.1a3 and + . Versions 1.6.1a3 and later fully support this driver. ATEN EH-100 protocol @@ -1299,14 +1323,37 @@ have a high-level driver for the type of device that you want to support. -MicroSolutions backpack protocol +Micro Solutions BACKPACK Series 5 protocol CONFIG_PARIDE_BPCK - This option enables support for the MicroSolutions backpack parallel - port IDE protocol. If you chose to build PARIDE support into your - kernel, you may answer Y here to build in the protocol driver, - otherwise you should answer M to build it as a loadable module. The - module will be called bpck.o. You must also have a high-level driver - for the type of device that you want to support. + This option enables support for the Micro Solutions BACKPACK parallel + port Series 5 IDE protocol. (Most BACKPACK drives made before 1999 were + Series 5) Series 5 drives will NOT always have the Series noted on the + bottom of the drive. Series 6 drivers will. + + In other words, if your BACKPACK drive dosen't say "Series 6" on the + bottom, enable this option. + + If you chose to build PARIDE support into your kernel, you may answer Y + here to build in the protocol driver, otherwise you should answer M to + build it as a loadable module. The module will be called bpck.o. You + must also have a high-level driver for the type of device that you want + to support. + +Micro Solutions BACKPACK Series 6 protocol +CONFIG_PARIDE_BPCK6 + This option enables support for the Micro Solutions BACKPACK parallel + port Series 6 IDE protocol. (Most BACKPACK drives made after 1999 were + Series 6) Series 6 drives will have the Series noted on the bottom of + the drive. Series 5 drivers don't always have it noted. + + In other words, if your BACKPACK drive says "Series 6" on the bottom, + enable this option. + + If you chose to build PARIDE support into your kernel, you may answer Y + here to build in the protocol driver, otherwise you should answer M to + build it as a loadable module. The module will be called bpck6.o. You + must also have a high-level driver for the type of device that you want + to support. DataStor Commuter protocol CONFIG_PARIDE_COMM @@ -1463,7 +1510,7 @@ More information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . There you will also + . There you will also learn where to get the supporting user space utilities raidtools. If unsure, say N. @@ -1491,7 +1538,7 @@ Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . There you will also + . There you will also learn where to get the supporting user space utilities raidtools. If you want to compile this as a module ( = code which can be @@ -1501,6 +1548,15 @@ If unsure, say Y. +RAID-1/RAID-5 code (DANGEROUS) +CONFIG_RAID15_DANGEROUS + This new RAID1/RAID5 code has been freshly merged, and has not seen + enough testing yet. While there are no known bugs in it, it might + destroy your file systems, eat your data and start World War III. + You have been warned. + + If unsure, say N. + RAID-1 (mirroring) mode CONFIG_MD_RAID1 A RAID-1 set consists of several disk drives which are exact copies @@ -1513,7 +1569,7 @@ Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . There you will also + . There you will also learn where to get the supporting user space utilities raidtools. If you want to use such a RAID-1 set, say Y. This code is also @@ -1536,7 +1592,7 @@ Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . There you will also + . There you will also learn where to get the supporting user space utilities raidtools. If you want to use such a RAID-4/RAID-5 set, say Y. This code is @@ -1552,25 +1608,31 @@ This is a machine with a R4400 133/150 MHz CPU. To compile a Linux kernel that runs on these, say Y here. For details about Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at - http://oss.sgi.com/mips . + . Support for Algorithmics P4032 (EXPERIMENTAL) CONFIG_ALGOR_P4032 This is an evaluation board of the British company Algorithmics. The board uses the R4300 and a R5230 CPUs. For more information about - this board see http://www.algor.co.uk . + this board see . Support for BAGET MIPS series CONFIG_BAGET_MIPS This enables support for the Baget, a Russian embedded system. For more details about the Baget see the Linux/MIPS FAQ on - http://oss.sgi.com/mips . + . + +Baget AMD LANCE support +CONFIG_BAGETLANCE + Say Y to enable kernel support for AMD Lance ethernet cards on the + MIPS-32-based Baget embedded system. This chipset is better known + via the NE2100 cards. Support for DECstations CONFIG_DECSTATION This enables support for DEC's MIPS based workstations. For details - see the Linux/MIPS FAQ on http://oss.sgi.com/mips and the - DECstation porting pages on http://decstation.unix-ag.org . + see the Linux/MIPS FAQ on and the + DECstation porting pages on . If you have one of the following DECstation Models you definitely want to choose R4xx0 for the CPU Type: @@ -1587,19 +1649,40 @@ This enables support for the VR5000-based NEC DDB Vrc-5074 evaluation board. +Support for NEC DDB Vrc-5476 +CONFIG_DDB5476 + This enables support for the R5432-based NEC DDB Vrc-5476 + evaluation board. + + Features : kernel debugging, serial terminal, NFS root fs, on-board + ether port (with a patch to tulip driver), IDE controller, PS2 keyboard + PS2 mouse, etc. + + TODO : USB, Compact-PCI interface. + +Support for MIPS Atlas board +CONFIG_MIPS_ATLAS + This enables support for the QED R5231-based MIPS Atlas evaluation + board. + +Support for MIPS Malta board +CONFIG_MIPS_MALTA + This enables support for the VR5000-based MIPS Malta evaluation + board. + Support for Mips Magnum 4000 CONFIG_MIPS_MAGNUM_4000 This is a machine with a R4000 100 MHz CPU. To compile a Linux kernel that runs on these, say Y here. For details about Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at - http://oss.sgi.com/mips. + . Support for Olivetti M700 CONFIG_OLIVETTI_M700 This is a machine with a R4000 100 MHz CPU. To compile a Linux kernel that runs on these, say Y here. For details about Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at - http://oss.sgi.com/mips. + . Support for SGI IP22 CONFIG_SGI_IP22 @@ -1616,12 +1699,12 @@ CONFIG_SGI_SN0_N_MODE The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be configured in either N-Modes which allows for more nodes or M-Mode - which allows for more more memory. Your system is most probably + which allows for more memory. Your system is most probably running in M-Mode, so you should say N here. MIPS JAZZ onboard SONIC Ethernet support CONFIG_MIPS_JAZZ_SONIC - This is the driver for the onboard card of of MIPS Magnum 4000, + This is the driver for the onboard card of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. MIPS JAZZ FAS216 SCSI support @@ -1630,6 +1713,12 @@ 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. +Kernel floating-point instruction emulation +CONFIG_MIPS_FPU_EMULATOR + This option enables the MIPS software floatingpoint support. Due to the + way floatingpoint works you should always enable this option unless + you exactly know what you're doing. + PCMCIA SCSI adapter support CONFIG_SCSI_PCMCIA Say Y here if you intend to attach a PCMCIA or CardBus card to your @@ -1680,6 +1769,16 @@ whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support +CONFIG_PCMCIA_NINJA_SCSI + If you intend to attach this type of PCMCIA SCSI host adapter to + your computer, say Y here and read Documentation/README.nsp_cs. + + This driver is also available as a module called nsp_cs.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + CPU type CONFIG_CPU_R3000 Please make sure to pick the right CPU type. Linux/MIPS is not @@ -1716,7 +1815,7 @@ For a general introduction to Linux networking, it is highly recommended to read the NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Socket filtering CONFIG_FILTER @@ -1726,6 +1825,10 @@ certain types of data to get through the socket. Linux Socket Filtering works on all socket types except TCP for now. See the text file Documentation/networking/filter.txt for more information. + + You need to say Y here if you want to use PPP packet filtering + (see the CONFIG_PPP_FILTER option below). + If unsure, say N. Network packet filtering @@ -1837,8 +1940,8 @@ MAC address match support CONFIG_IP_NF_MATCH_MAC - mac matching allows you to match packets based on the source - ethernet address of the packet. + MAC matching allows you to match packets based on the source + Ethernet address of the packet. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. @@ -1972,7 +2075,7 @@ CONFIG_IP_NF_TARGET_MARK This option adds a `MARK' target, which allows you to create rules in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet packet prior to routing. This can change + associated with the packet prior to routing. This can change the routing method (see `IP: use netfilter MARK value as routing key') and can also be used by other subsystems to change their behavior. @@ -2110,7 +2213,6 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. - TCP Explicit Congestion Notification support CONFIG_INET_ECN Explicit Congestion Notification (ECN) allows routers to notify @@ -2128,72 +2230,6 @@ If in doubt, say N. -IP6 tables support (required for filtering/masq/NAT) -CONFIG_IP6_NF_IPTABLES - ip6tables is a general, extensible packet identification framework. - Currently only the packet filtering and packet mangling subsystem - for IPv6 use this, but connection tracking is going to follow. - Say 'Y' or 'M' here if you want to use either of those. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -IPv6 limit match support -CONFIG_IP6_NF_MATCH_LIMIT - limit matching allows you to control the rate at which a rule can be - matched: mainly useful in combination with the LOG target ("LOG - target support", below) and to avoid some Denial of Service attacks. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -MAC address match support -CONFIG_IP6_NF_MATCH_MAC - mac matching allows you to match packets based on the source - ethernet address of the packet. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -netfilter mark match support -CONFIG_IP6_NF_MATCH_MARK - Netfilter mark matching allows you to match packets based on the - `nfmark' value in the packet. This can be set by the MARK target - (see below). - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Packet filtering -CONFIG_IP6_NF_FILTER - Packet filtering defines a table `filter', which has a series of - rules for simple packet filtering at local input, forwarding and - local output. See the man page for iptables(8). - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Packet mangling -CONFIG_IP6_NF_MANGLE - This option adds a `mangle' table to iptables: see the man page for - iptables(8). This table is used for various packet alterations - which can effect how the packet is routed. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -MARK target support -CONFIG_IP6_NF_TARGET_MARK - This option adds a `MARK' target, which allows you to create rules - in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet packet prior to routing. This can change - the routing method (see `IP: use netfilter MARK value as routing - key') and can also be used by other subsystems to change their - behavior. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN @@ -2209,7 +2245,7 @@ is no need for the legitimate users to change their TCP/IP software; SYN cookies work transparently to them. For technical information about SYN cookies, check out - ftp://koobera.math.uic.edu/syncookies.html . + . If you are SYN flooded, the source address reported by the kernel is likely to have been forged by the attacker; it is only reported as @@ -2238,7 +2274,7 @@ To find out what type of Alpha system you have, you may want to check out the Linux/Alpha FAQ, accessible on the WWW from - http://www.alphalinux.org . In summary: + . In summary: Alcor/Alpha-XLT AS 600 Alpha-XL XL-233, XL-266 @@ -2283,7 +2319,7 @@ which is command line driven, and ARC, which uses menus and arrow keys. Details about the Linux/Alpha booting process are contained in the Linux/Alpha FAQ, accessible on the WWW from - http://www.alphalinux.org . + . The usual way to load Linux on an Alpha machine is to use MILO (a bootloader that lets you pass command line parameters to the @@ -2356,7 +2392,7 @@ Say Y here if you have dumb serial boards other than the four standard COM 1/2/3/4 ports. This may happen if you have an AST FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto ), or other custom + from ), or other custom serial port hardware which acts similar to standard serial port hardware. If you only use the standard COM 1/2/3/4 ports, you can say N here to save some memory. You can also say Y if you have an @@ -2386,7 +2422,7 @@ of those special I/O ports. SGI PROM Console Support -CONFIG_SGI_PROM_CONSOLE +CONFIG_ARC_CONSOLE Say Y here if you want to use the PROMs for console I/O. SGI Zilog85C30 serial support @@ -2433,20 +2469,6 @@ a module, say M here and read Documentation/modules.txt. If unsure, say N. -CardBus serial device support -CONFIG_PCMCIA_SERIAL_CB - Say Y here to enable support for CardBus serial devices, including - serial port cards, modems, and the modem functions of multi-function - ethernet/modem devices. (CardBus cards are the newer and better - version of PCMCIA- or PC-cards: credit card size devices often - used with laptops.) - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called serial_cb.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. If unsure, - say N. - /dev/agpgart (AGP Support) (EXPERIMENTAL) CONFIG_AGP AGP (Accelerated Graphics Port) is a bus system mainly used to @@ -2470,7 +2492,7 @@ For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ , or need to use the 810 Xserver in + , or need to use the 810 Xserver in XFree 3.3.6. This driver is available as a module. If you want to compile it as a @@ -2484,7 +2506,7 @@ For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + . Intel I810/I810 DC100/I810e support CONFIG_AGP_I810 @@ -2499,7 +2521,7 @@ For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + . AMD Irongate support CONFIG_AGP_AMD @@ -2508,7 +2530,7 @@ For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + . Generic SiS support CONFIG_AGP_SIS @@ -2520,21 +2542,32 @@ For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + . -ALI M1541 support +ALI chipset support CONFIG_AGP_ALI This option gives you AGP support for the GLX component of the - XFree86 4.x on the ALi M1541 chipset. + XFree86 4.x on the following ALi chipsets. The supported chipsets + include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. + For ALi-chipset question, ALi welcome you refer to + - This chipset can do AGP 1x and 2x, but note that there is an + The M1541 chipset can do AGP 1x and 2x, but note that there is an acknowledged incompatibility with Matrox G200 cards. Due to timing issues, this chipset cannot do AGP 2x with the G200. This is a hardware limitation. AGP 1x seems to be fine, though. For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + . + +Support for ISA-bus hardware +CONFIG_ISA + Find out whether you have ISA slots on your motherboard. ISA is the + name of a bus system, i.e. the way the CPU talks to the other stuff + inside your box. Other bus systems are PCI, EISA, Microchannel (MCA) or + VESA. ISA is an older system, now being displaced by PCI; newer boards + don't support it. If you have ISA, say Y, otherwise N. PCI support CONFIG_PCI @@ -2544,7 +2577,7 @@ VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , contains valuable + , contains valuable information about which PCI hardware does work under Linux and which doesn't. @@ -2556,7 +2589,7 @@ VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , contains valuable + , contains valuable information about which PCI hardware does work under Linux and which doesn't. @@ -2568,7 +2601,7 @@ VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , contains valuable + , contains valuable information about which PCI hardware does work under Linux and which doesn't. @@ -2742,6 +2775,23 @@ If unsure, say Y. +PNPBIOS support +CONFIG_PNPBIOS + The PNPBIOS as defined in "Plug and Play BIOS Specification Version 1.0A + May 5, 1994" is used in Linux to autodetect built-in mainboard resources + (e.g. parallel port resources). + + Other features (e.g. change resources, ESCD, event notification, Docking + station information, ISAPNP services) are not used. + + Note: ACPI is expected to supersede PNPBIOS some day, currently it + co-exists nicely. + + See latest pcmcia-cs (stand-alone package) for a nice "lspnp" tools, + or have a look at /proc/bus/pnp. + + If unsure, say Y. + Support for hot-pluggable devices CONFIG_HOTPLUG Say Y here if you want to plug devices into your computer while @@ -2754,7 +2804,7 @@ example, used on modern desktops as well as laptops, is USB. Enable HOTPLUG and KMOD, and build a modular kernel. Get agent - software (at http://linux-hotplug.sourceforge.net) and install it. + software (at ) and install it. Then your kernel will automatically call out to a user mode "policy agent" (/sbin/hotplug) to load modules and set up software needed to use devices as you hotplug them. @@ -2771,7 +2821,7 @@ To use your PC-cards, you will need supporting software from David Hinds' pcmcia-cs package (see the file Documentation/Changes for location). Please also read the PCMCIA-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto + This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -2814,20 +2864,12 @@ and some programs won't run unless you say Y here. In particular, if you want to run the DOS emulator dosemu under Linux (read the DOSEMU-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto ), you'll need to say Y + ), you'll need to say Y here. You can find documentation about IPC with "info ipc" and also in section 6.4 of the Linux Programmer's Guide, available from - http://www.linuxdoc.org/docs.html#guide . - - Shared memory is now implemented using a new (minimal) virtual file - system. To mount it automatically at system startup just add the - following line to your /etc/fstab: - - none /dev/shm shm defaults 0 0 - - Saying Y here enlarges your kernel by about 18 KB. Just say Y. + . BSD Process Accounting CONFIG_BSD_PROCESS_ACCT @@ -2849,7 +2891,7 @@ interface consists of a system call, but if you say Y to "/proc file system support", a tree of modifiable sysctl entries will be generated beneath the /proc/sys directory. They are explained in the - files in Documentation/sysctl/. Note that enabling this option will + files in Documentation/sysctl/ . Note that enabling this option will enlarge the kernel by at least 8 KB. As it is generally a good thing, you should say Y here unless @@ -2890,7 +2932,7 @@ want to say Y here. Information about ELF is contained in the ELF HOWTO available from - http://www.linuxdoc.org/docs.html#howto . + . If you find that after upgrading from Linux kernel 1.2 and saying Y here, you still can't run any ELF binaries (they just crash), then @@ -2945,7 +2987,7 @@ programs that need an interpreter to run like Java, Python or Emacs-Lisp. It's also useful if you often run DOS executables under the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto ). Once you have + ). Once you have registered such a binary class with the kernel, you can start one of those programs simply by typing in its name at a shell prompt; Linux will automatically feed it to the correct interpreter. @@ -2994,14 +3036,16 @@ - "Pentium-Classic" for the Intel Pentium. - "Pentium-MMX" for the Intel Pentium MMX. - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II. - - "Pentium-III" for the Intel Pentium III. - - "Pentium-4" for the Intel Pentium 4 + - "Pentium-III" for the Intel Pentium III + and Celerons based on the coppermine core. + - "Pentium-4" for the Intel Pentium 4. - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D). - - "Athlon" for the AMD Athlon (K7). + - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird). - "Crusoe" for the Transmeta Crusoe series. - "Winchip-C6" for original IDT Winchip. - "Winchip-2" for IDT Winchip 2. - "Winchip-2A" for IDT Winchips with 3dNow! capabilities. + - "CyrixIII" for VIA Cyrix III or VIA C3. If you don't know what to do, choose "386". @@ -3013,7 +3057,7 @@ The program SVGATextMode can be used to utilize SVGA video cards to their full potential in text mode. Download it from - ftp://metalab.unc.edu/pub/Linux/utils/console . + . Say Y. @@ -3052,7 +3096,7 @@ You need an utility program called fbset to make full use of frame buffer devices. Please read Documentation/fb/framebuffer.txt and the Framebuffer-HOWTO at - http://www.tahallah.demon.co.uk/programming/prog.html for more + for more information. Say Y here and to the driver for your graphics board below if you @@ -3070,6 +3114,26 @@ hardware found in Acorn RISC PCs and other ARM-based machines. If unsure, say N. +Permedia2 support +CONFIG_FB_PM2 + This is the frame buffer device driver for the Permedia2 AGP frame buffer + card from ASK, aka `Graphic Blaster Exxtreme'. There is a product page + at . + +Enable FIFO disconnect feature +CONFIG_FB_PM2_FIFO_DISCONNECT + Support the Permedia2 FIFOI disconnect feature (see CONFIG_FB_PM2). + +Generic Permedia2 PCI board support +CONFIG_FB_PM2_PCI + Say Y to enable support for Permedia2 AGP frame buffer card from 3Dlabs + (aka `Graphic Blaster Exxtreme') on the PCI bus. + +Phase5 CVisionPPC/BVisionPPC support +CONFIG_FB_PM2_CVPPC + Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC + framebuffer cards. Phase 5 is no longer with us, alas. + Amiga native chipset support CONFIG_FB_AMIGA This is the frame buffer device driver for the builtin graphics @@ -3144,10 +3208,6 @@ Say N unless you have such a graphics board or plan to get one before you next recompile the kernel. -Permedia2 support (EXPERIMENTAL) -CONFIG_FB_PM2 - Say Y here if this is your graphics board. - Apollo support CONFIG_APOLLO Say Y here if you want to run Linux on an MC680x0-based Apollo @@ -3165,6 +3225,11 @@ This is the frame buffer device driver for the builtin graphics chipset found in Ataris. +Amiga FrameMaster II/Rainbow II support +CONFIG_FB_FM2 + This is the frame buffer device driver for the Amiga FrameMaster + card from BSC (exhibited 1992 but not shipped as a CBM product). + Open Firmware frame buffer device support CONFIG_FB_OF Say Y if you want support with Open Firmware for your graphics @@ -3216,6 +3281,11 @@ module will be called aty128fb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Link-Up Systems LCD support (EXPERIMENTAL) +CONFIG_FB_L7200 + This driver supports the L7200 Color LCD. + Say Y if you want graphics support. + PowerMac "control" frame buffer device support CONFIG_FB_CONTROL This driver supports a frame buffer for the graphics adapter in the @@ -3411,7 +3481,7 @@ also load i2c-matroxfb to get it to run. The driver starts in monitor mode and you must use the matroxset - tool (available at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) + tool (available at ) to switch it to PAL or NTSC or to swap primary and secondary head outputs. Secondary head driver also always start in 640x480 resolution, you must use fbset to change it. @@ -3436,7 +3506,7 @@ The driver starts in monitor mode and currently does not support output in TV modes. You must use the matroxset tool (available - at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) to swap primary + at ) to swap primary and secondary head outputs. Secondary head driver always start in 640x480 resolution and you must use fbset to change it. @@ -3501,15 +3571,50 @@ CONFIG_FB_CGTHREE This is the frame buffer device driver for the CGthree frame buffer. +CGfourteen (SX) support +CONFIG_FB_CGFOURTEEN + This is the frame buffer device driver for the CGfourteen frame buffer + on Desktop SPARCsystems with the SX graphics option. + +P9100 (Sparcbook 3 only) support +CONFIG_FB_P9100 + This is the frame buffer device driver for the P9100 card supported + on Sparcbook 3 machines. + +Leo (ZX) support +CONFIG_FB_LEO + This is the frame buffer device driver for the SBUS-based Sun ZX (leo) + frame buffer cards. + +IGA 168x display support +CONFIG_FB_IGA + This is the framebuffer device for the INTERGRAPHICS 1680 and + successor frame buffer cards. + TCX (SS4/SS5 only) support CONFIG_FB_TCX This is the frame buffer device driver for the TCX 24/8bit frame buffer. +HD64461 Frame Buffer support +CONFIG_FB_HIT + This is the frame buffer device driver for the Hitachi HD64461 LCD frame + buffer card. + +SIS 630/540 display support +CONFIG_FB_SIS + This is the frame buffer device driver for the SiS 630 and 640 Super + Socket 7 UMA cards. Specs available at . + +IMS Twin Turbo display support +CONFIG_FB_IMSTT + The IMS Twin Turbo is a PCI-based frame buffer card bundled with many + Macintosh and compatible computers. + Virtual Frame Buffer support (ONLY FOR TESTING!) CONFIG_FB_VIRTUAL This is a `virtual' frame buffer device. It operates on a chunk of - unswapable kernel memory instead of on the memory of a graphics + unswappable kernel memory instead of on the memory of a graphics board. This means you cannot see any output sent to this frame buffer device, while it does consume precious memory. The main use of this frame buffer device is testing and debugging the frame @@ -3526,7 +3631,7 @@ CONFIG_FB_SA1100 This is a framebuffer device for the SA-1100 LCD Controller. - See http://www.linux-fbdev.org/ for information on framebuffer + See for information on framebuffer devices. If you plan to use the LCD display with your SA-1100 system, say @@ -3644,7 +3749,7 @@ Documentation/parport.txt and drivers/parport/BUGS-parport. For extensive information about drivers for many devices attaching - to the parallel port see http://www.torque.net/linux-pp.html on the + to the parallel port see on the WWW. It is possible to share a single parallel port among several devices @@ -3700,12 +3805,6 @@ other non-standard types of parallel ports. This causes a performance loss, so most people say N. -Sun Ultra/AX-style hardware -CONFIG_PARPORT_AX - Say Y here if you need support for the parallel port hardware on Sun - Ultra/AX machines. This code is also available as a module (say M), - called parport_ax.o. If in doubt, saying N is the safe plan. - Amiga built-in parallel port support CONFIG_PARPORT_AMIGA Say Y here if you need support for the parallel port hardware on @@ -3810,13 +3909,13 @@ For an excellent introduction to Linux networking, please read the NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This option is also necessary if you want to use the full power of term (term is a program which gives you almost full Internet connectivity if you have a regular dial up shell account on some Internet connected Unix computer; for more information, read - http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). + ). If you say Y here and also to "/proc file system support" and "Sysctl support" below, you can change various aspects of the @@ -3833,7 +3932,7 @@ intend to participate in the MBONE, a high bandwidth network on top of the Internet which carries audio and video broadcasts. More information about the MBONE is on the WWW at - http://www-itg.lbl.gov/mbone/ . Information about the multicast + . Information about the multicast capabilities of the various network cards is contained in Documentation/networking/multicast.txt. For most people, it's safe to say N. @@ -3887,9 +3986,9 @@ addresses of forwarded packets. If you are interested in this, please see the preliminary - documentation at http://www.compendium.com.ar/policy-routing.txt and - ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex . You - will need supporting software from ftp://ftp.inr.ac.ru/ip-routing/ + documentation at and + . You + will need supporting software from . If unsure, say N. @@ -3936,7 +4035,7 @@ destination addresses of packets that pass through it, in a manner you specify. General information about Network Address Translation can be gotten from the document - http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html + IP: kernel level autoconfiguration CONFIG_IP_PNP @@ -3982,7 +4081,7 @@ appear on a different network than it physically is, or to use mobile-IP facilities (allowing laptops to seamlessly move between networks without changing their IP addresses; check out - http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html ). + ). Saying Y to this option will produce two modules ( = code which can be inserted in and removed from the running kernel whenever you @@ -4023,7 +4122,7 @@ Kernel side support for Sparse Mode PIM (Protocol Independent Multicast) version 1. This multicast routing protocol is used widely because Cisco supports it. You need special software to use it - (pimd-v1). Please see http://netweb.usc.edu/pim/ for more + (pimd-v1). Please see for more information about PIM. Say Y if you want to use PIM-SM v1. Note that you can say N here if @@ -4036,41 +4135,6 @@ gated-5). This routing protocol is not used widely, so say N unless you want to play with it. -PC/TCP compatibility mode -CONFIG_INET_PCTCP - If you have been having difficulties telnetting to your Linux - machine from a DOS system that uses (broken) PC/TCP networking - software (all versions up to OnNet 2.0) over your local Ethernet try - saying Y here. Everyone else says N. - - People having problems with NCSA telnet should see the file - Documentation/networking/ncsa-telnet. - -Path MTU Discovery (normally enabled) -CONFIG_PATH_MTU_DISCOVERY - MTU (maximal transfer unit) is the size of the chunks we send out - over the net. "Path MTU Discovery" means that, instead of always - sending very small chunks, we start out sending big ones and if we - then discover that some host along the way likes its chunks smaller, - we adjust to a smaller size. This is good, so most people say Y - here. - - However, some DOS software (versions of DOS NCSA telnet and Trumpet - Winsock in PPP mode) is broken and won't be able to connect to your - Linux machine correctly in all cases (especially through a terminal - server) unless you say N here. See - Documentation/networking/ncsa-telnet for the location of fixed NCSA - telnet clients. If in doubt, say Y. - -Disable NAGLE algorithm (normally enabled) -CONFIG_TCP_NAGLE_OFF - The NAGLE algorithm works by requiring an acknowledgment before - sending small IP frames (packets). This keeps tiny telnet and - rlogin packets from congesting Wide Area Networks. Most people - strongly recommend to say N here, thereby leaving NAGLE - enabled. Those programs that would benefit from disabling this - facility can do it on a per connection basis themselves. - IP: Allow large windows (not recommended if <16 MB of memory) CONFIG_SKB_LARGE On high speed, long distance networks the performance limit on @@ -4114,9 +4178,9 @@ Features of this new protocol include: expanded address space, authentication and privacy, and seamless interoperability with the current version of IP (IP version 4). For general information about - IPv6, see http://playground.sun.com/pub/ipng/html/ipng-main.html ; + IPv6, see ; for specific information about IPv6 under Linux read the HOWTO at - http://www.bieringer.de/linux/IPv6/ and the file net/ipv6/README in + and the file net/ipv6/README in the kernel source. If you want to use IPv6, please upgrade to the newest net-tools as @@ -4178,9 +4242,9 @@ used for local networks of Windows machines. You need it if you want to access Novell NetWare file or print servers using the Linux Novell client ncpfs (available from - ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) or from within + ) or from within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto ). In order to do the + ). In order to do the former, you'll also have to say Y to "NCP file system support", below. @@ -4190,13 +4254,13 @@ To turn your Linux box into a fully featured NetWare file server and IPX router, say Y here and fetch either lwared from - ftp://metalab.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe - from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs . For more information, + or mars_nwe + from . For more information, read the IPX-HOWTO available from - http://www.linuxdoc.org/docs.html#howto . + . General information about how to connect Linux, Windows machines and - Macs is on the WWW at http://www.eats.com/linux_mac_win.html . + Macs is on the WWW at . The IPX driver would enlarge your kernel by about 16 KB. This driver is also available as a module ( = code which can be inserted in and @@ -4214,7 +4278,7 @@ same address). The way this is done is to create a virtual internal "network" inside your box and to assign an IPX address to this network. Say Y here if you want to do this; read the IPX-HOWTO at - http://www.linuxdoc.org/docs.html#howto for details. + for details. The full internal IPX network enables you to allocate sockets on different virtual nodes of the internal network. This is done by @@ -4227,7 +4291,7 @@ 'special' sockets to sockets listening on the primary network is disabled. This might break existing applications, especially RIP/SAP daemons. A RIP/SAP daemon that works well with the full internal net - can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs . + can be found on . If you don't know what you are doing, say N. @@ -4244,7 +4308,7 @@ space programs lwared or mars_nwe for the server side). Say Y here if you have use for SPX; read the IPX-HOWTO at - http://www.linuxdoc.org/docs.html#howto for details. + for details. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4260,7 +4324,7 @@ To find some tools to use with the kernel layer support, please look at Patrick Caulfield's web site: - http://linux.dreamtime.org/decnet/ + More detailed documentation is available in the Documentation/networking/decnet.txt file. @@ -4290,7 +4354,7 @@ network link driver", "Routing messages" and "Network packet filtering". The first two are required to allow configuration via rtnetlink (currently you need Alexey Kuznetsov's iproute2 package - from ftp://ftp.inr.ac.ru). The "Network packet filtering" option + from ). The "Network packet filtering" option will be required for the forthcoming routing daemon to work. See Documentation/networking/decnet.txt for more information. @@ -4301,7 +4365,7 @@ packets with different FWMARK ("firewalling mark") values (see ipchains(8), "-m" argument). -Appletalk interfaces support +AppleTalk interfaces support CONFIG_APPLETALK AppleTalk is the way Apple computers speak to each other on a network. If your Linux box is connected to such a network and you @@ -4314,23 +4378,24 @@ want to join the conversation, say Y. You will need to use the netatalk package so that your Linux box can act as a print and file server for Macs as well as access AppleTalk printers. Check out - http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW - for details. EtherTalk is the name used for AppleTalk over Ethernet - and the cheaper and slower LocalTalk is AppleTalk over a proprietary - Apple network using serial links. EtherTalk and LocalTalk are fully - supported by Linux. + on the WWW for details. EtherTalk + is the name used for AppleTalk over Ethernet and the cheaper and + slower LocalTalk is AppleTalk over a proprietary Apple network using + serial links. EtherTalk and LocalTalk are fully supported by Linux. General information about how to connect Linux, Windows machines and - Macs is on the WWW at http://www.eats.com/linux_mac_win.html . The + Macs is on the WWW at . The NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , contains valuable + , contains valuable information as well. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called appletalk.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. I hear that - the GNU boycott of Apple is over, so even politically correct people + module, say M here and read Documentation/modules.txt. You almost + certainly want to compile it as a module so you can restart your + AppleTalk stack without rebooting your machine. I hear that the + GNU boycott of Apple is over, so even politically correct people are allowed to say Y here. AppleTalk-IP driver support @@ -4409,9 +4474,9 @@ Amateur Radio support CONFIG_HAMRADIO If you want to connect your Linux box to an amateur radio, answer Y - here. You want to read http://www.tapr.org/tapr/html/pkthome.html + here. You want to read and the HAM-HOWTO and the AX25-HOWTO, both available from - http://www.linuxdoc.org/docs.html#howto . + . Note that the answer to this question won't directly affect the kernel: saying N will just cause this configure script to skip all @@ -4435,10 +4500,10 @@ Information about where to get supporting software for Linux amateur radio as well as information about how to configure an AX.25 port is contained in the AX25-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . You might also want to + . You might also want to check out the file Documentation/networking/ax25.txt in the kernel source. More information about digital amateur radio in general is - on the WWW at http://www.tapr.org/tapr/html/pkthome.html . + on the WWW at . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4471,10 +4536,10 @@ A comprehensive listing of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is contained in the AX25-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . You also might want to + . You also might want to check out the file Documentation/networking/ax25.txt. More information about digital amateur radio in general is on the WWW at - http://www.tapr.org/tapr/html/pkthome.html . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4490,10 +4555,10 @@ A comprehensive listing of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is contained in the AX25-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . You also might want to + . You also might want to check out the file Documentation/networking/ax25.txt. More information about digital amateur radio in general is on the WWW at - http://www.tapr.org/tapr/html/pkthome.html . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4554,7 +4619,7 @@ Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis PackeTwin, and S5SCC/DMA boards. They are detected automatically. If you have one of these cards, say Y here and read the AX25-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . This driver can operate multiple boards simultaneously. If you compile it as a module (by saying M instead of Y), it will be called @@ -4570,7 +4635,7 @@ certain parameters, such as channel access timing, clock mode, and DMA channel. This is accomplished with a small utility program, dmascc_cfg, available at - http://www.nt.tuwien.ac.at/~kkudielk/Linux/ . Please be sure to get + . Please be sure to get at least version 1.27 of dmascc_cfg, as older versions will not work with the current driver. @@ -4579,7 +4644,7 @@ These cards are used to connect your Linux box to an amateur radio in order to communicate with other computers. If you want to use this, read Documentation/networking/z8530drv.txt and the AX25-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . Also + available from . Also make sure to say Y to "Amateur Radio AX.25 Level 2" support. If you want to compile this as a module ( = code which can be @@ -4616,7 +4681,7 @@ connect to a parallel interface. The driver supports the picpar and par96 designs. To configure the driver, use the sethdlc utility available in the standard ax25 utilities package. For information on - the modems, see http://www.baycom.de and the file + the modems, see and the file Documentation/networking/baycom.txt. If you want to compile this driver as a module ( = code which can be @@ -4630,7 +4695,7 @@ connect to a parallel interface. The driver supports the EPP designs. To configure the driver, use the sethdlc utility available in the standard ax25 utilities package. For information on the - modems, see http://www.baycom.de and the file + modems, see and the file Documentation/networking/baycom.txt. If you want to compile this driver as a module ( = code which can be @@ -4649,7 +4714,7 @@ driver and still provided in case this driver does not work with your serial interface chip. To configure the driver, use the sethdlc utility available in the standard ax25 utilities package. For - information on the modems, see http://www.baycom.de and + information on the modems, see and Documentation/networking/baycom.txt. If you want to compile this driver as a module ( = code which can be @@ -4666,7 +4731,7 @@ the full duplex driver. This driver is depreciated. To configure the driver, use the sethdlc utility available in the standard ax25 utilities package. For information on the modems, see - http://www.baycom.de and Documentation/networking/baycom.txt. + and Documentation/networking/baycom.txt. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -4683,7 +4748,7 @@ To configure the driver, use the sethdlc, smdiag and smmixer utilities available in the standard ax25 utilities package. For information on how to key the transmitter, see - http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html and + and Documentation/networking/soundmodem.txt. If you want to compile this driver as a module ( = code which can be @@ -4780,8 +4845,8 @@ if you want that) and the lower level data link layer protocol LAPB (say Y to "LAPB Data Link Driver" below if you want that). - You can read more about X.25 at http://www.sangoma.com/x25.htm and - http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm . + You can read more about X.25 at and + . Information about X.25 for Linux is contained in the files Documentation/networking/x25.txt and Documentation/networking/x25-iface.txt. @@ -4831,7 +4896,7 @@ with the Frames Diverter on, can do some *really* transparent www caching using a Squid proxy for example. - This is very usefull when you don't want to change your router's + This is very useful when you don't want to change your router's config (or if you simply don't have access to it). The other possible usages of diverting Ethernet Frames are numberous: @@ -4841,8 +4906,8 @@ - etc... For more informations, please refer to: - http://www.freshmeat.net/projects/etherdivert - http://perso.wanadoo.fr/magpie/EtherDivert.html + + If unsure, say N @@ -4863,7 +4928,7 @@ Note that if your box acts as a bridge, it probably contains several Ethernet devices, but the kernel is not able to recognize more than one at boot time without help; for details read the Ethernet-HOWTO, - available from in http://www.linuxdoc.org/docs.html#howto . + available from in . If you want to compile this code as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -4902,7 +4967,7 @@ Over this socket, the kernel can send and receive datagrams carrying information. It is documented on many systems in netlink(7), a HOWTO is provided as well, for example on - http://snafu.freedom.org/linux2.2/docs/netlink-HOWTO.html + So far, the kernel uses this feature to publish some network related information if you say Y to "Routing messages", below. You also need @@ -4916,9 +4981,9 @@ Routing messages CONFIG_RTNETLINK - If you say Y here, userspace programs can receive some network + If you say Y here, user space programs can receive some network related routing information over the netlink. 'rtmon', supplied - with the iproute2 package (ftp://ftp.inr.ac.ru), can read and + with the iproute2 package (), can read and interpret this data. Information sent to the kernel over this link is ignored. @@ -5084,6 +5149,15 @@ Note that extended debugging may create certain race conditions itself. Enable this ONLY if you suspect problems with the driver. +Fujitsu FireStream (FS50/FS155) +CONFIG_ATM_FIRESTREAM + Driver for the Fujitsu FireStream 155 (MB86697) and + FireStream 50 (MB86695) ATM PCI chips. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read Documentation/modules.txt. The + module will be called firestream.o. + Enable usec resolution timestamps CONFIG_ATM_ZATM_EXACT_TS The uPD98401 SAR chip supports a high-resolution timer (approx. 30 @@ -5219,7 +5293,7 @@ isapnp support. Please read Documentation/telephony/ixj.txt. For more information on these cards, see Quicknet's web site at: - http://www.quicknet.net/ . + . If you do not have any Quicknet telephony cards, you can safely say N here. @@ -5304,6 +5378,117 @@ the performances of the driver, and the size of your syslog files! Keep the debugging level to 0 during normal operations. +Fusion MPT device support +CONFIG_FUSION + LSI Logic Fusion(TM) Message Passing Technology (MPT) device support + provides high performance SCSI host initiator, and LAN [1] interface + services to a host system. The Fusion architecture is capable of + duplexing these protocols on high-speed Fibre Channel + (up to 2 GHz x 2 ports = 4 GHz) and parallel SCSI (up to Ultra-320) + physical medium. + + [1] LAN is not supported on parallel SCSI medium. + + These drivers require a Fusion MPT compatible PCI adapter installed in + the host system. MPT adapters contain specialized I/O processors + to handle I/O workload, and more importantly to offload this work + from the host CPU(s). + + If you have Fusion MPT hardware and want to use it, you can say + Y or M here to add MPT (base + ScsiHost) drivers. + = build lib (fusion.o), and link [static] into the kernel [2] proper + = compiled as [dynamic] modules [3] named: (mptbase.o, mptscsih.o) + + [2] In order enable capability to boot the linux kernel natively + from a Fusion MPT target device, you MUST answer Y here! + (currently requires CONFIG_BLK_DEV_SD) + [3] This support is also available as a module + ( = code which can be inserted in and removed + from the running kernel whenever you want). + If you want to compile as modules, say M here and read + Documentation/modules.txt. + + If unsure, say N. + + If you say Y or M here you will get a choice of these + additional protocol and support module options: Module Name: + Enhanced SCSI error reporting (isense.o) + Fusion MPT misc device (ioctl) driver (mptctl.o) + Fusion MPT LAN driver (mptlan.o) + + --- + Fusion MPT is trademark of LSI Logic Corporation, and it's architecture + is based on LSI Logic's Message Passing Interface (MPI) specification. + +Fusion MPT enhanced SCSI error reporting [optional] module +CONFIG_FUSION_ISENSE + The isense module (roughly stands for Interpret SENSE data) is + completely optional. It simply provides extra English readable + strings in SCSI Error Report(s) that might be generated from the + Fusion MPT SCSI Host driver, for example when a target device + returns a SCSI check condition on a I/O. Without this module + loaded you might see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h + + Where otherwise, if this module had been loaded, you would see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)" + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" + + Say M for "Enhanced SCSI error reporting" to compile this optional module, + creating a driver named: isense.o + + NOTE: Support for building this feature into the kernel is not + available, due to kernel size considerations. + +Fusion MPT misc device (ioctl) driver [optional] module +CONFIG_FUSION_CTL + The Fusion MPT misc device driver provides specialized control + of MPT adapters via system ioctl calls. Use of ioctl calls to + the MPT driver requires that you create and use a misc device + node ala: + mknod /dev/mptctl c 10 240 + + One use of this ioctl interface is to perform an upgrade (reflash) + of the MPT adapter firmware. Refer to readme file(s) distributed + with the Fusion MPT linux driver for additional details. + + If enabled by saying M to this, a driver named: mptctl.o + will be compiled. + + If unsure whether you really want or need this, say no. + +Fusion MPT LAN driver [optional] +CONFIG_FUSION_LAN + This module supports LAN IP traffic over Fibre Channel port(s) + on Fusion MPT compatible hardware (LSIFC9xx chips). + The physical interface used is defined in RFC 2625. + Please refer to that document for details. + + Installing this driver requires the knowledge to configure and + activate a new network interface, "fc0", using standard Linux tools. + + If enabled by saying M to this, a driver named: mptlan.o + will be compiled. + + If unsure whether you really want or need this, say no. + + NOTES: This feature is NOT available nor supported for linux-2.2.x + kernels. You must be building a linux-2.3.x or linux-2.4.x kernel + in order to configure this option. + Support for building this feature into the linux kernel is not + yet available. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -5316,7 +5501,7 @@ port version of the 100 MB IOMEGA ZIP drive. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . The + . The SCSI-Programming-HOWTO contains information about how to add or remove an SCSI device from a running Linux machine without rebooting. @@ -5334,7 +5519,7 @@ If you want to use a SCSI hard disk or the SCSI or parallel port version of the IOMEGA ZIP drive under Linux, say Y and read the SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . This is NOT for SCSI + . This is NOT for SCSI CDROMs. This driver is also available as a module ( = code which can be @@ -5360,11 +5545,25 @@ If you don't understand what's going on, go with the default. +Extra SCSI Tapes +CONFIG_ST_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In + the event that the SCSI core itself was loaded as a module, this + value is the number of additional tapes that can be loaded after the + first host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + + If you don't understand what's going on, go with the default. + SCSI tape support CONFIG_CHR_DEV_ST If you want to use a SCSI tape drive under Linux, say Y and read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , and + , and drivers/scsi/README.st in the kernel source. This is NOT for SCSI CDROMs. @@ -5385,10 +5584,10 @@ commands for tapes (QIC-157) and can be driven by the standard driver st. For more information, you may have a look at the SCSI-HOWTO - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and + and drivers/scsi/README.osst in the kernel source. More info on the OnStream driver may be found on - http://linux1.onstream.nl/test/ + Please also have a look at the standard st docu, as most of it applies to osst as well. @@ -5402,7 +5601,7 @@ CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the SCSI-HOWTO and the CDROM-HOWTO at - http://www.linuxdoc.org/docs.html#howto . Also make sure to say Y + . Also make sure to say Y or M to "ISO 9660 CDROM file system support" later. This driver is also available as a module ( = code which can be @@ -5440,12 +5639,12 @@ directly, so you need some additional software which knows how to talk to these devices using the SCSI protocol: - For scanners, look at SANE (http://www.mostang.com/sane). For CD + For scanners, look at SANE (). For CD writer software look at cdrecord - (http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html) + () and for burning a "disk at once": cdrdao - (http://www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high - quality digital reader of audio CDs (http://www.xiph.org/paranoia). + (). Cdparanoia is a high + quality digital reader of audio CDs (). For other devices, it's possible that you'll have to write the driver software yourself. Please read the file Documentation/scsi-generic.txt for more information. @@ -5464,7 +5663,7 @@ This will typically cause the kernel to panic if an error is detected, but it would have probably crashed if the panic weren't there. Comments/questions/problems to linux-scsi mailing list - please. See http://www.andante.org/scsi_queue.html for more + please. See for more up-to-date information. Probe all LUNs on each SCSI device @@ -5524,7 +5723,7 @@ must be manually specified in this case. It is explained in section 3.3 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . You might also want to + . You might also want to read the file drivers/scsi/README.aha152x. This driver is also available as a module ( = code which can be @@ -5536,7 +5735,7 @@ CONFIG_SCSI_AHA1542 This is support for a SCSI host adapter. It is explained in section 3.4 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that Trantor was + . Note that Trantor was purchased by Adaptec, and some former Trantor products are being sold under the Adaptec name. If it doesn't work out of the box, you may have to change some settings in drivers/scsi/aha1542.h. @@ -5550,7 +5749,7 @@ CONFIG_SCSI_AHA1740 This is support for a SCSI host adapter. It is explained in section 3.5 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/aha1740.h. @@ -5585,7 +5784,7 @@ Default: 253 Initial Bus Reset Settle Delay -CONFIG_AIC7XXX_RESET_DELAY +CONFIG_AIC7XXX_RESET_DELAY_MS The number of milliseconds to delay after an initial bus reset. The bus settle delay following all error recovery actions is dictated by the SCSI layer and is not affected by this value. @@ -5624,7 +5823,7 @@ configuration options. You should read drivers/scsi/aic7xxx_old/README.aic7xxx at a minimum before contacting the maintainer with any questions. The SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , can also be of great + , can also be of great help. If you want to compile this driver as a module ( = code which can be @@ -5703,7 +5902,7 @@ IBM ServeRAID Support CONFIG_SCSI_IPS This is support for the IBM ServeRAID hardware RAID controllers. - See http://www.developer.ibm.com/welcome/netfinity/serveraid.html + See for more information. If this driver does not work correctly without modification please contact the author by email at ipslinux@us.ibm.com. @@ -5718,7 +5917,7 @@ CONFIG_SCSI_BUSLOGIC This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters. Consult the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , and the files + , and the files README.BusLogic and README.FlashPoint in drivers/scsi for more information. If this driver does not work correctly without modification, please contact the author, Leonard N. Zubkoff, by @@ -5750,7 +5949,7 @@ CONFIG_SCSI_DTC3280 This is support for DTC 3180/3280 SCSI Host Adapters. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , and the file + , and the file drivers/scsi/README.dtc3x80. This driver is also available as a module ( = code which can be @@ -5767,7 +5966,7 @@ Note that this driver is obsolete; if you have one of the above SCSI Host Adapters, you should normally say N here and Y to "EATA ISA/EISA/PCI support", below. Please read the SCSI-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -5781,7 +5980,7 @@ host adapters could also use this driver but are discouraged from doing so, since this driver only supports hard disks and lacks numerous features. You might want to have a look at the SCSI-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -5795,7 +5994,7 @@ this hardware. If the driver doesn't work out of the box, you may have to change some settings in drivers/scsi/u14-34f.c. Read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that there is also + . Note that there is also another driver for the same hardware: "UltraStor SCSI support", below. You should say Y to both only if you want 24F support as well. @@ -5830,7 +6029,7 @@ other adapters based on the Future Domain chipsets (Quantum ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board). It is explained in section 3.7 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI @@ -5860,7 +6059,7 @@ This is the generic NCR family of SCSI controllers, not to be confused with the NCR 53c7 or 8xx controllers. It is explained in section 3.8 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/g_NCR5380.h. @@ -5889,7 +6088,7 @@ This is a driver for the 53c7 and 8xx NCR family of SCSI controllers, not to be confused with the NCR 5380 controllers. It is explained in section 3.8 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/53c7,8xx.h. Please read drivers/scsi/README.ncr53c7xx for the available boot time command line options. @@ -6187,7 +6386,7 @@ CONFIG_SCSI_INITIO This is support for the Initio 91XXU(W) SCSI host adapter. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6198,7 +6397,7 @@ CONFIG_SCSI_PAS16 This is support for a SCSI host adapter. It is explained in section 3.10 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/pas16.h. @@ -6211,7 +6410,7 @@ CONFIG_SCSI_INIA100 This is support for the Initio INI-A100U2W SCSI host adapter. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6222,7 +6421,7 @@ CONFIG_SCSI_PCI2000 This is support for the PCI2000I EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module called pci2000.o ( = code which can be inserted in and removed from the running kernel @@ -6233,7 +6432,7 @@ CONFIG_SCSI_PCI2220I This is support for the PCI2220i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module called pci2220i.o ( = code which can be inserted in and removed from the running kernel @@ -6244,7 +6443,7 @@ CONFIG_SCSI_PSI240I This is support for the PSI240i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module called psi240i.o ( = code which can be inserted in and removed from the running kernel @@ -6263,7 +6462,7 @@ Information about this driver is contained in drivers/scsi/README.qlogicfas. You should also read the SCSI-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6281,7 +6480,7 @@ Please read the file drivers/scsi/README.qlogicisp. You should also read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6310,7 +6509,7 @@ CONFIG_SCSI_SEAGATE These are 8-bit SCSI controllers; the ST-01 is also supported by this driver. It is explained in section 3.9 of the SCSI-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . If it + available from . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/seagate.h. @@ -6323,7 +6522,7 @@ CONFIG_SCSI_T128 This is support for a SCSI host adapter. It is explained in section 3.11 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/t128.h. Note that Trantor was purchased by Adaptec, and some former Trantor products are being sold under the Adaptec name. @@ -6338,7 +6537,7 @@ This is support for the UltraStor 14F, 24F and 34F SCSI-2 host adapter family. This driver is explained in section 3.12 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/ultrastor.h. @@ -6379,7 +6578,7 @@ You want to read the start of drivers/scsi/eata.c and the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Note that there is also another driver for the same hardware available: "EATA-DMA support". You should say Y to only one of them. @@ -6419,7 +6618,7 @@ This is support for the NCR53c406a SCSI host adapter. For user configurable parameters, check out drivers/scsi/NCR53c406.c in the kernel source. Also read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6501,7 +6700,7 @@ CONFIG_SCSI_AM53C974 This is support for the AM53/79C974 SCSI host adapters. Please read drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto , is for + available from , is for you. Note that there is another driver for AM53C974 based adapters: @@ -6551,7 +6750,7 @@ For more information about this driver and how to use it you should read the file drivers/scsi/README.ppa. You should also read the SCSI-HOWTO, which is available from - http://www.linuxdoc.org/docs.html#howto . If you use this driver, + . If you use this driver, you will still be able to use the parallel port for other tasks, such as a printer; it is safe to compile both drivers into the kernel. @@ -6578,7 +6777,7 @@ For more information about this driver and how to use it you should read the file drivers/scsi/README.ppa. You should also read the SCSI-HOWTO, which is available from - http://www.linuxdoc.org/docs.html#howto . If you use this driver, + . If you use this driver, you will still be able to use the parallel port for other tasks, such as a printer; it is safe to compile both drivers into the kernel. @@ -6613,66 +6812,6 @@ Generally, saying N is fine. -Parallel port SCSI device support -CONFIG_PPSCSI - There are many external CD-ROM and disk devices that connect through - your computer's parallel port. Lots of them are actually SCSI - devices using a parallel port SCSI adapter. This option enables the - ppSCSI subsystem which contains drivers for many of these external - drives. You may also want to look at CONFIG_PARIDE (Parallel port - IDE device support). - - If you built ppSCSI support into your kernel, you may still build - the individual protocol modules and high-level drivers as loadable - modules. If you build this support as a module, it will be called - ppscsi.o. - - To use the ppSCSI support, you must say Y or M here and also to at - least one protocol driver (e.g. "Shuttle EPST adapter", "Iomega VPI0 - adapter", "Shining ScarSCI adapter" etc.). - -Adaptec APA-348 adapter -CONFIG_PPSCSI_T348 - This option enables support for the APA-348 adapter from Adaptec - (also known as Trantor T348). If you build this as a module it will - be called t348.o. - -Adaptec APA-358 adapter -CONFIG_PPSCSI_T358 - This option enables support for the APA-358 adapter from Adaptec - (also known as Trantor T358). If you build this as a module it will - be called t358.o. - -Iomega VPI0 adapter -CONFIG_PPSCSI_VPI0 - This option enables support for the Iomega VPI0 adapter found in the - original ZIP-100 drives and the Jaz Traveller. If you build this as - a module it will be called vpi0.o. - -OnSpec 90c26 adapter -CONFIG_PPSCSI_ONSCSI - This option enables support for the OnSpec 90c26 in its SCSI adapter - mode. If you build this as a module it will be called onscsi.o. - -Shining SparSCI adapter -CONFIG_PPSCSI_SPARCSI - This option enables support for the WBS-11A parallel port SCSI - adapter. This adapter has been marketed by LinkSys as the - "ParaSCSI+" and by Shining Technologies as the "SparCSI". If you - build this as a module it will be called sparcsi.o. - -Shuttle EPSA-2 adapter -CONFIG_PPSCSI_EPSA2 - This option enables support for the Shuttle Technologies EPSA2 - parallel port SCSI adapter. EPAS2 is a predecessor to the EPST. If - you build this as a module it will be called epsa2.o. - -Shuttle EPST adapter -CONFIG_PPSCSI_EPST - This option enables support for the Shuttle Technologies EPST - parallel port SCSI adapter. If you build this as a module is will - be called epst.o. - SCSI Debug host simulator. (EXPERIMENTAL) CONFIG_SCSI_DEBUG This is a host adapter simulator that can be programmed to simulate @@ -6872,6 +7011,11 @@ say M here and read Documentation/modules.txt. The module will be called ohci1394.o. +Video1394 support +CONFIG_IEEE1394_VIDEO1394 + Say Y here if you want support for IEEE1394 FireWire interfacing + to digital cameras using the video1394 conventions. + Raw IEEE 1394 I/O support CONFIG_IEEE1394_RAWIO Say Y here if you want support for the raw device. This is generally @@ -6902,11 +7046,11 @@ telephone line with a modem either via UUCP (UUCP is a protocol to forward mail and news between unix hosts over telephone lines; read the UUCP-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto ) or dialing up a shell + ) or dialing up a shell account or a BBS, even using term (term is a program which gives you almost full Internet connectivity if you have a regular dial up shell account on some Internet connected Unix computer. Read - http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). + ). You'll have to say Y if your computer contains a network card that you want to use under Linux (make sure you know its name because you @@ -6922,7 +7066,7 @@ Make sure to read the NET-3-HOWTO. Eventually, you will have to read Olaf Kirch's excellent and free book "Network Administrator's - Guide", to be found in http://www.linuxdoc.org/docs.html#guide . If + Guide", to be found in . If unsure, say Y. Dummy net driver support @@ -6935,7 +7079,7 @@ thing often comes in handy, the default is Y. It won't enlarge your kernel either. What a deal. Read about it in the Network Administrator's Guide, available from - http://www.linuxdoc.org/docs.html#guide . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6978,16 +7122,16 @@ Normally, your access provider has to support SLIP in order for you to be able to use it, but there is now a SLIP emulator called SLiRP around (available via FTP (user: anonymous) from - ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which + ) which allows you to use SLIP over a regular dial up shell connection. If you plan to use SLiRP, make sure to say Y to CSLIP, below. The NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , explains how to + , explains how to configure SLIP. Note that you don't need this option if you just want to run term (term is a program which gives you almost full Internet connectivity if you have a regular dial up shell account on some Internet connected Unix computer. Read - http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). SLIP + ). SLIP support will enlarge your kernel by about 4 KB. If unsure, say N. If you want to compile this as a module ( = code which can be @@ -7003,10 +7147,10 @@ on both ends. Ask your access provider if you are not sure and answer Y, just in case. You will still be able to use plain SLIP. If you plan to use SLiRP, the SLIP emulator (available from - ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which + ) which allows you to use SLIP over a regular dial up shell connection, you definitely want to say Y here. The NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , explains how to configure + , explains how to configure CSLIP. This won't enlarge your kernel. Keepalive and linefill @@ -7030,14 +7174,14 @@ PPP (Point to Point Protocol) is a newer and better SLIP. It serves the same purpose: sending Internet traffic over telephone (and other serial) lines. Ask your access provider if they support it, because - otherwise you can't use it; most internet access providers these + otherwise you can't use it; most Internet access providers these days support PPP rather than SLIP. To use PPP, you need an additional program called pppd as described - in Documentation/networking/ppp.txt and in the PPP-HOWTO, available - at http://www.linuxdoc.org/docs.html#howto . If you upgrade - from an older kernel, you might need to upgrade pppd as well. The - PPP option enlarges your kernel by about 16 KB. + in the PPP-HOWTO, available at + Make sure that you have the version of pppd recommended in + Documentation/Changes. The PPP option enlarges your kernel by about + 16 KB. There are actually two versions of PPP: the traditional PPP for asynchronous lines, such as regular analog phone lines, and @@ -7068,6 +7212,17 @@ If unsure, say N. +PPP filtering (EXPERIMENTAL) +CONFIG_PPP_FILTER + Say Y here if you want to be able to filter the packets passing over + PPP interfaces. This allows you to control which packets count as + activity (i.e. which packets will reset the idle timer or bring up + a demand-dialled link) and which packets are to be dropped entirely. + You need to say Y here if you wish to use the pass-filter and + active-filter options to pppd. + + If unsure, say N. + PPP support for async serial ports CONFIG_PPP_ASYNC Say Y (or M) here if you want to be able to use PPP over standard @@ -7127,8 +7282,8 @@ This driver requires a specially patched pppd daemon. The patch to pppd, along with binaries of a patched pppd package can be found at: - http://www.math.uwaterloo.ca/~mostrows - + + Wireless LAN (non-hamradio) CONFIG_NET_RADIO Support for wireless LANs and everything having to do with radio, @@ -7145,17 +7300,17 @@ driver (or Linux). If you wish to use Wireless Extensions with wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch the tools from - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html . + . Some user-level drivers for scarab devices which don't require special kernel support are available from - ftp://shadow.cabi.net/pub/Linux . + . STRIP (Metricom Starmode radio IP) CONFIG_STRIP Say Y if you have a Metricom radio and intend to use Starmode Radio IP. STRIP is a radio protocol developed for the MosquitoNet project - (on the WWW at http://mosquitonet.stanford.edu/ ) to send Internet + (on the WWW at ) to send Internet traffic using Metricom radios. Metricom radios are small, battery powered, 100kbit/sec packet radio transceivers, about the size and weight of a cellular telephone. (You may also have heard them called @@ -7187,12 +7342,12 @@ If you want to use an ISA WaveLAN card under Linux, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Some more specific + . Some more specific information is contained in Documentation/networking/wavelan.txt and in the source code drivers/net/wavelan.p.h. You will also need the wireless tools package available from - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html . + . Please read the man pages contained therein. This driver is also available as a module ( = code which can be @@ -7206,7 +7361,7 @@ Aironet makes Arlan, a class of wireless LAN adapters. These use the www.Telxon.com chip, which is also used on several similar cards. This driver is tested on the 655 and IC2200 series cards. Look at - http://www.ylenurme.ee/~elmer/655/ for the latest information. + for the latest information. The driver is built as two modules, arlan and arlan-proc. The latter is the /proc interface and is not needed most of time. @@ -7347,7 +7502,7 @@ To use your PC-cards, you will need supporting software from David Hinds' pcmcia-cs package (see the file Documentation/Changes for location). You also want to check out the PCMCIA-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . If unsure, say N. @@ -7472,7 +7627,7 @@ To use your PC-cards, you will need supporting software from David Hinds' pcmcia-cs package (see the file Documentation/Changes for location). You also want to check out the PCMCIA-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards) CONFIG_PCMCIA_HERMES @@ -7486,11 +7641,11 @@ To use your PC-cards, you will need supporting software from David Hinds' pcmcia-cs package (see the file Documentation/Changes for location). You also want to check out the PCMCIA-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . You will also very likely also need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works : - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + configure your card and that /etc/pcmcia/wireless.opts works: + Aviator/Raytheon 2.4MHz wireless support CONFIG_PCMCIA_RAYCS @@ -7547,12 +7702,12 @@ Documentation/networking/PLIP.txt. The cables can be up to 15m long. Mode 0 works also if one of the machines runs DOS/Windows and has some PLIP software installed, e.g. the Crynwr PLIP packet driver - (http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html ) and + () and winsock or NCSA's telnet. If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well as the NET-3-HOWTO, both available from - http://www.linuxdoc.org/docs.html#howto . Note that the PLIP + . Note that the PLIP protocol has been changed and this PLIP driver won't work together with the PLIP support in Linux versions 1.0.x. This option enlarges your kernel by about 8 KB. @@ -7575,7 +7730,7 @@ Say Y if you want this and read Documentation/networking/eql.txt. You may also want to read section 6.2 of the NET-3-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7654,7 +7809,7 @@ network, usually at the phone company) can carry several logical point-to-point connections to other computers connected to the frame relay network. For a general explanation of the protocol, check out - http://www.frforum.com/ on the WWW. To use frame relay, you need + on the WWW. To use frame relay, you need supporting hardware (called FRAD) and certain programs from the net-tools package as explained in Documentation/networking/framerelay.txt. @@ -7733,7 +7888,7 @@ the price of an external router. If you have one of those cards and wish to use your Linux box as a WAN router, say Y here and also to the WAN driver for your card, below. You will then need the - wan-tools package which is available from ftp://ftp.sangoma.com . + wan-tools package which is available from . Read Documentation/networking/wan-router.txt for more information. The WAN routing support is also available as a module called @@ -7757,7 +7912,7 @@ At the moment, few devices support fast switching (tulip is one of them, a modified 8390 driver can be found at - ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz ). + ). If unsure, say N. @@ -7767,7 +7922,7 @@ during periods of extremal congestion. At the moment only a couple of device drivers support it (really only one -- tulip, a modified 8390 driver can be found at - ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz ). + ). Really, this option is applicable to any machine attached to a fast enough network, and even a 10 Mb NIC is able to kill a not very slow @@ -7794,15 +7949,15 @@ This code is considered to be experimental. To administer these schedulers, you'll need the user-level utilities - from the package iproute2+tc at ftp://ftp.inr.ac.ru/ip-routing/ . + from the package iproute2+tc at . That package also contains some documentation; for more, check out - http://snafu.freedom.org/linux2.2/iproute-notes.html . + . This Quality of Service (QoS) support will enable you to use Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router if you also say Y to "QoS support", "Packet classifier API" and to some classifiers below. Documentation - and software is at http://icawww1.epfl.ch/linux-diffserv/ . + and software is at . If you say Y here and to "/proc file system" below, you will be able to read status information about packet schedulers from the file @@ -7932,7 +8087,7 @@ Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router if you also say Y to "Packet classifier API" and to some classifiers below. Documentation and software is at - http://icawww1.epfl.ch/linux-diffserv/ . + . Note that the answer to this question won't directly affect the kernel: saying N will just cause this configure script to skip all @@ -7955,7 +8110,7 @@ This will enable you to use Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router. Documentation and software is at - http://icawww1.epfl.ch/linux-diffserv/ . + . ### Add #tristate ' TC index classifier' CONFIG_NET_CLS_TCINDEX @@ -8067,7 +8222,7 @@ To actually use the COSA or SRP board, you will need user-space utilities for downloading the firmware to the cards and to set them - up. Look at the http://www.fi.muni.cz/~kas/cosa/ for more + up. Look at the for more information about the cards (including the pointer to the user-space utilities). You can also read the comment at the top of the drivers/net/cosa.c for details about the cards and the driver @@ -8078,6 +8233,18 @@ The module will be called cosa.o. For general information about modules read Documentation/modules.txt. +Etinc PCISYNC serial boards support +CONFIG_DSCC4 + This is a driver for Etinc PCISYNC boards based on the Infineon + (ex. Siemens) DSCC4 chipset. It is supposed to work with the four + ports card. Take a look at + for further informations about the driver and his configuration. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dscc4.o. For general information about + modules read Documentation/modules.txt. + Lan Media sync serial boards support CONFIG_LANMEDIA This is a driver for the following Lan Media family of serial boards. @@ -8141,7 +8308,7 @@ module will be called sbni.o). You can find more information and last versions of drivers and - utilities at http://www.granch.ru . If you have any question you + utilities at . If you have any question you can send email to sbni@granch.ru. Say N if unsure. @@ -8155,7 +8322,7 @@ Router". You will need the wan-tools package which is available from - ftp://ftp.sangoma.com . Read Documentation/networking/wan-router.txt + . Read Documentation/networking/wan-router.txt for more information. Note that the answer to this question won't directly affect the @@ -8164,13 +8331,26 @@ Sangoma WANPIPE(tm) multiprotocol cards CONFIG_VENDOR_SANGOMA - WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com ) is - a family of intelligent multiprotocol WAN adapters with data - transfer rates up to T1 (1.544 Mbps). They are also known as - Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503 - or S508. These cards support the X.25, Frame Relay, and PPP - protocols. If you have one or more of these cards, say Y to this - option; you may then also want to read the file + + WANPIPE from Sangoma Technologies Inc. ( + is a family of intelligent multiprotocol WAN adapters with data + transfer rates up to 4Mbps. They are also known as Synchronous + Data Link Adapters (SDLA) and are designated as S514-PCI or S508-ISA. + These cards support + + - X.25, Frame Relay, PPP, Cisco HDLC protocols. + + - API support for protocols like HDLC (LAPB), + HDLC Streaming, X.25, Frame Relay and BiSync. + + - Ethernet Bridging over Frame Relay protocol. + + - MULTILINK PPP + + - Async PPP (Modem Dialup) + + If you have one or more of these cards, say M to this option; you + may then also want to read the file Documentation/networking/wanpipe.txt. The next questions will ask you about the protocols you want the driver to support. @@ -8179,44 +8359,58 @@ The module will be called wanpipe.o. For general information about modules read Documentation/modules.txt. -Maximum number of cards -CONFIG_WANPIPE_CARDS - Enter number of WANPIPE adapters installed in your machine. The - driver can support up to 8 cards. You may enter more than you - actually have if you plan to add more cards in the future without - re-compiling the driver, but remember that in this case you'll waste - some kernel memory (about 1K per card). - -WANPIPE Cisco HDLC support -CONFIG_WANPIPE_CHDLC - Say Y to this option if you are planning to connect a WANPIPE card - to a connection which uses the synchronous Cisco HDLC (High-level - Data Link Control) protocol. This protocol is often used on - high-speed leased lines like T1/E1. - WANPIPE X.25 support CONFIG_WANPIPE_X25 Say Y to this option if you are planning to connect a WANPIPE card - to an X.25 network. You should then also have said Y to "CCITT X.25 - Packet Layer" and "LAPB Data Link Driver", above. If you say N, the - X.25 support will not be included in the driver (saves about 16 KB - of kernel memory). + to an X.25 network. Note, this feature also includes the X.25 API + support used to develope custom applications over the X.25 protocol. + If you say N, the X.25 support will not be included in the driver. + The X.25 option is supported on S514-PCI and S508-ISA cards. WANPIPE Frame Relay support CONFIG_WANPIPE_FR Say Y to this option if you are planning to connect a WANPIPE card - to a frame relay network. You should then also have said Y to "Frame - Relay (DLCI) support", above. If you say N, the frame relay - support will not be included in the driver (saves about 16 KB of - kernel memory). + to a frame relay network, or use frame relay API to develope + custom applications over the Frame Relay protocol. + This feature also contains the Ethernet Bridging over Frame Relay, + where a WANPIPE frame relay link can be directly connected to the Linux + kernel bridge. If you say N, the frame relay support will + not be included in the driver. The Frame Relay option is + supported on S514-PCI and S508-ISA cards. WANPIPE PPP support CONFIG_WANPIPE_PPP Say Y to this option if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). You should - then also have said Y to "PPP (point-to-point) support", above. If - you say N, the PPP support will not be included in the driver (saves - about 16 KB of kernel memory). + to a leased line using Point-to-Point protocol (PPP). If you say N, + the PPP support will not be included in the driver. The PPP option + is supported on S514-PCI/S508-ISA cards. + +WANPIPE MultiPort PPP support +CONFIG_WANPIPE_MULTPPP + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using Point-to-Point protocol (PPP). Note, the + MultiPort PPP uses the Linux Kernel SyncPPP protocol over the Sangoma + HDLC Streaming adapter. In this case each Sangoma adapter port + can support an independent PPP connection. For example, a single + Quad-Port PCI adapter can support up to four independent + PPP links. If you say N,the PPP support will not be included + in the driver. The PPP option is supported on S514-PCI/S508-ISA cards. + +WANPIPE Cisco HDLC support +CONFIG_WANPIPE_CHDLC + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using the Cisco HDLC protocol. This now supports + Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards. + This support also allows user to build applications using the + HDLC streaming API. + + CHDLC Streaming driver also supports MULTILINK PPP + support that can bind multiple WANPIPE T1 cards into + a single logical channel. + + If you say N, the Cisco HDLC support and + HDLC streaming API and MULTILINK PPP will not be + included in the driver. MultiGate/COMX support CONFIG_COMX @@ -8226,7 +8420,7 @@ Read linux/Documentation/networking/comx.txt for help on configuring and using COMX interfaces. Further info on these cards can be found - at http://www.itc.hu or . + at or . You must say Y to "/proc file system support" (CONFIG_PROC_FS) to use this driver. @@ -8240,7 +8434,7 @@ MultiGate family. Say Y if you have one of these. You will need additional firmware to use these cards, which are - downloadable from ftp://ftp.itc.hu/. + downloadable from . If you want to compile this as a module, say M and read Documentation/modules.txt. The module will be called comx-hw-comx.o. @@ -8264,7 +8458,7 @@ configuration. The ISDN interface of this card is Teles 16.3 compatible, you should enable it in the ISDN configuration menu. The driver for the flash ROM of this card is available separately on - ftp://ftp.itc.hu/. + . If you want to compile this as a module, say M and read Documentation/modules.txt. The module will be called @@ -8288,7 +8482,7 @@ If you want to compile this as a module, say M and read Documentation/modules.txt. The module will be called i810-tco.o. - + MultiGate Cisco-HDLC and synchronous PPP protocol support CONFIG_COMX_PROTO_PPP Cisco-HDLC and synchronous PPP protocol driver for all MultiGate @@ -8319,8 +8513,8 @@ Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL) CONFIG_CYCLADES_SYNC - Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and - http://www.cyclades.com.br) is an intelligent multiprotocol WAN + Cyclom 2X from Cyclades Corporation (and + is an intelligent multiprotocol WAN adapter with data transfer rates up to 512 Kbps. These cards support the X.25 and SNA related protocols. If you have one or more of these cards, say Y to this option. The next questions will ask you about @@ -8328,10 +8522,10 @@ supported). While no documentation is available at this time please grab the - wanconfig tarball in http://www.conectiva.com.br/~acme/cycsyn-devel - (with minor changes to make it compile with the current wanrouter + wanconfig tarball in + (with minor changes to make it compile with the current wanrouter include files; efforts are being made to use the original package - available at ftp://ftp.sangoma.com ). + available at ). Feel free to contact me or the cycsyn-devel mailing list at acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for @@ -8351,6 +8545,49 @@ If you say N, the X.25 support will not be included in the driver (saves about 11 KB of kernel memory). +Generic HDLC driver +CONFIG_HDLC + Say Y to this option if your Linux box contains a WAN card supported + by this driver and you are planning to connect the box to a WAN + ( = Wide Area Network). You will need supporting software from + . + Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame + Relay, synchronous Point-to-Point Protocol (PPP) and X.25. + + If unsure, say N here. + +Synchronous Point-to-Point Protocol (PPP) +CONFIG_HDLC_PPP + Say Y to this option if you want generic HDLC driver to support + PPP over WAN (Wide Area Network) connections. + + If unsure, say N here. + +CCITT X.25 protocol +CONFIG_HDLC_X25 + Say Y to this option if you want generic HDLC driver to support + X.25 protocol over WAN (Wide Area Network) connections. + + If unsure, say N here. + +SDL RISCom/N2 driver +CONFIG_N2 + This driver is for RISCom/N2 single or dual channel ISA cards + made by SDL Communications Inc. If you have such a card, + say Y here and see + + Note that N2csu and N2dds cards are not supported by this driver. + + If unsure, say N here. + +Moxa C101 driver +CONFIG_C101 + This driver is for C101 SuperSync ISA cards made by Moxa + Technologies Co., Ltd. If you have such a card, + say Y here and see +x + If unsure, say N here. + Ethernet (10 or 100Mbit) CONFIG_NET_ETHERNET Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common @@ -8369,7 +8606,7 @@ If your Linux machine will be connected to an Ethernet and you have an Ethernet network interface card (NIC) installed in your computer, say Y here and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . You will then also have + . You will then also have to say Y to the driver for your particular NIC. Note that the answer to this question won't directly affect the @@ -8380,7 +8617,7 @@ CONFIG_NET_VENDOR_SMC If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -8391,7 +8628,7 @@ CONFIG_WD80x3 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8403,7 +8640,7 @@ CONFIG_ULTRAMCA If you have a network (Ethernet) card of this type and are running an MCA based system (PS/2), say Y and read the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8415,7 +8652,7 @@ CONFIG_ULTRA If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Important: There have been many reports that, with some motherboards mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, @@ -8434,7 +8671,7 @@ CONFIG_ULTRA32 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8449,7 +8686,7 @@ another SMC9192/9194 based chipset. Say Y if you want it compiled into the kernel, and read the file Documentation/networking/smc9.txt and the Ethernet-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -8463,7 +8700,7 @@ with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 support" below). If you have a PCI NE2000 network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver also works for the following NE2000 clone cards: RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2 @@ -8480,7 +8717,7 @@ CONFIG_NET_VENDOR_RACAL If you have a network (Ethernet) card belonging to this class, such as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -8491,7 +8728,7 @@ CONFIG_NI5010 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that this is still + . Note that this is still experimental code. This driver is also available as a module ( = code which can be @@ -8504,7 +8741,7 @@ CONFIG_NI52 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8516,7 +8753,7 @@ CONFIG_NI65 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8529,7 +8766,7 @@ This is a driver for the Fast Ethernet PCI network cards based on the RTL8139 chips. If you have one of those, say Y and read Documentation/networking/8139too.txt as well as the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -8562,7 +8799,7 @@ the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in SiS 630 and SiS 540 chipsets. If you have one of those, say Y and read the Ethernet-HOWTO, available at - http://www.linuxdoc.org/docs.html#howto . Please read + . Please read Documentation/networking/sis900.txt and comments at the beginning of drivers/net/sis900.c for more information. @@ -8578,7 +8815,7 @@ CONFIG_YELLOWFIN Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet adapter. This adapter is used by the Beowulf Linux cluster project. - See http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html for + See for more information about this driver in particular and Beowulf in general. @@ -8603,9 +8840,9 @@ connection. Further documentation and the necessary scripts can be found at: - http://www.jacksonville.net/~fventuri/ - http://home.adelphia.net/~siglercm/sb1000.html - http://linuxpower.cx/~cable/ + + + If you don't have this card, of course say N. @@ -8685,7 +8922,7 @@ CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Some LinkSys cards are + . Some LinkSys cards are of this type. If you want to compile this driver as a module ( = code which can be @@ -8697,13 +8934,13 @@ CONFIG_SGI_IOC3_ETH If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . 3COM cards CONFIG_NET_VENDOR_3COM If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -8714,7 +8951,7 @@ CONFIG_EL1 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Also, consider buying a + . Also, consider buying a new card, since the 3c501 is slow, broken, and obsolete: you will have problems. Some people suggest to ping ("man ping") a nearby machine every minute ("man cron") when using this card. @@ -8729,7 +8966,7 @@ CONFIG_EL2 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8742,7 +8979,7 @@ Information about this network (Ethernet) card can be found in Documentation/networking/3c505.txt. If you have a card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -8754,7 +8991,7 @@ CONFIG_EL16 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8766,7 +9003,7 @@ CONFIG_ELMC If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8778,7 +9015,7 @@ CONFIG_ELMC_II If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8790,7 +9027,7 @@ CONFIG_EL3 If you have a network (Ethernet) card belonging to the 3Com EtherLinkIII series, say Y and read the Ethernet-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . If your card is not working you may need to use the DOS setup disk to disable Plug & Play mode, and to select the default @@ -8806,7 +9043,7 @@ CONFIG_3C515 If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet network card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -8826,7 +9063,7 @@ "Hurricane" (3c555/3cSOHO) PCI If you have such a card, say Y and read the Ethernet-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . More specific + from . More specific information is in Documentation/networking/vortex.txt and in the comments at the beginning of drivers/net/3c59x.c. @@ -8841,7 +9078,7 @@ bus system (that's the way the cards talks to the other components of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y. Make sure you know the name of your card. Read the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . If unsure, say Y. @@ -8861,7 +9098,7 @@ support" below. You might also want to have a look at the Ethernet-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto (even though ARCnet + from (even though ARCnet is not really Ethernet). This driver is also available as a module ( = code which can be @@ -8870,18 +9107,6 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. -Enable arc0e (ARCnet "ether-encap" packet format) -CONFIG_ARCNET_ETH - This allows you to use "Ethernet encapsulation" with your ARCnet - card via the virtual arc0e device. You only need arc0e if you want - to talk to nonstandard ARCnet software, specifically, - DOS/Windows-style "NDIS" drivers. You do not need to say Y here to - communicate with industry-standard RFC1201 implementations, like the - arcether.com packet driver or most DOS/Windows ODI drivers. RFC1201 - is included automatically as the arc0 device. Please read the - ARCnet documentation in Documentation/networking/arcnet.txt for more - information about using arc0e and arc0s. - Enable old ARCNet packet format (RFC 1051) CONFIG_ARCNET_1051 This allows you to use RFC1051 with your ARCnet card via the virtual @@ -8895,6 +9120,15 @@ documentation in Documentation/networking/arcnet.txt for more information about using arc0e and arc0s. +Enable standard ARCNet packet format (RFC 1201) +CONFIG_ARCNET_1201 + This allows you to use RFC1201 with your ARCnet card via the virtual + arc0 device. You need to say Y here to communicate with + industry-standard RFC1201 implementations, like the arcether.com + packet driver or most DOS/Windows ODI drivers. Please read the ARCnet + documentation in Documentation/networking/arcnet.txt for more + information about using arc0. + ARCnet COM90xx (normal) chipset driver CONFIG_ARCNET_COM90xx This is the chipset driver for the standard COM90xx cards. If you @@ -8949,7 +9183,7 @@ CONFIG_E2100 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8962,7 +9196,7 @@ Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto as well as + as well as Documentation/networking/cs89x0.txt. If you want to compile this as a module ( = code which can be @@ -8975,7 +9209,7 @@ CONFIG_DEPCA If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto as well as + as well as drivers/net/depca.c. If you want to compile this as a module ( = code which can be @@ -8990,7 +9224,7 @@ cards. If this is for you, say Y and read Documentation/networking/ewrk3.txt in the kernel source as well as the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -9002,7 +9236,7 @@ CONFIG_SEEQ8005 This is a driver for the SEEQ 8005 network (Ethernet) card. If this is for you, read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -9014,7 +9248,7 @@ CONFIG_AT1700 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9027,7 +9261,7 @@ CONFIG_FMV18X If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you use an FMV-183 or FMV-184 and it is not working, you may need to disable Plug & Play mode of the card. @@ -9044,7 +9278,7 @@ driver supports intel i82595{FX,TX} based boards. Note however that the EtherExpress PRO/100 Ethernet card has its own separate driver. Please read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9056,7 +9290,7 @@ CONFIG_EEXPRESS If you have an EtherExpress16 network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that the Intel + . Note that the Intel EtherExpress16 card used to be regarded as a very poor choice because the driver was very unreliable. We now have a new driver that should do better. @@ -9071,7 +9305,7 @@ CONFIG_HAMACHI If you have a Gigabit Ethernet card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -9083,7 +9317,7 @@ CONFIG_HPLAN_PLUS If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9095,7 +9329,7 @@ CONFIG_HPLAN If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9107,7 +9341,7 @@ CONFIG_HP100 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -9119,7 +9353,7 @@ CONFIG_NE2000 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Many Ethernet cards + . Many Ethernet cards without a specific driver are compatible with NE2000. If you have a PCI NE2000 card however, say N here and Y to "PCI @@ -9139,19 +9373,19 @@ This driver is for the National Semiconductor DP83810 series, including the 83815 chip. More specific information and updates are available from - http://www.scyld.com/network/natsemi.html + SK_G16 support CONFIG_SK_G16 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . NE/2 (ne2000 MCA version) support CONFIG_NE2_MCA If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9194,7 +9428,7 @@ CONFIG_NET_PCI This is another class of network cards which attach directly to the bus. If you have one of those, say Y and read the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -9206,7 +9440,7 @@ CONFIG_PCNET32 If you have a PCnet32 or PCnetPCI based network (Ethernet) card, answer Y here and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9218,7 +9452,7 @@ CONFIG_AC3200 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9230,7 +9464,7 @@ CONFIG_LNE390 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9242,7 +9476,7 @@ CONFIG_NE3210 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that this driver + . Note that this driver will NOT WORK for NE3200 cards as they are completely different. This driver is also available as a module ( = code which can be @@ -9255,7 +9489,7 @@ CONFIG_APRICOT If you have a network (Ethernet) controller of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -9269,7 +9503,7 @@ These include the DE425, DE434, DE435, DE450 and DE500 models. If you have a network card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . More specific + . More specific information is contained in Documentation/networking/de4x5.txt. This driver is also available as a module ( = code which can be @@ -9287,7 +9521,7 @@ (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type will say Y here.) Do read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . More specific + . More specific information is contained in Documentation/networking/tulip.txt. This driver is also available as a module ( = code which can be @@ -9302,7 +9536,7 @@ PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 models. If you have a network card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . More specific + . More specific information is contained in Documentation/networking/dgrs.txt. This driver is also available as a module ( = code which can be @@ -9315,7 +9549,7 @@ CONFIG_EEPRO100 If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9339,7 +9573,7 @@ CONFIG_ETH16I If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9352,7 +9586,7 @@ If you have a PCI Ethernet network card based on the ThunderLAN chip which is supported by this driver, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Devices currently supported by this driver are Compaq Netelligent, Compaq NetFlex and Olicom cards. Please read the file @@ -9380,7 +9614,7 @@ PCI DM9102(A)/DM9132/DM9801 support CONFIG_DM9102 This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from - Davicom ( http://www.davicom.com.tw ). If you have such a network + Davicom ( ). If you have such a network (Ethernet) card, say Y. Some information is contained in the file Documentation/networking/dmfe.txt. @@ -9394,7 +9628,7 @@ CONFIG_ES3210 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9407,7 +9641,13 @@ This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, which is based on the SMC83c17x (EPIC/100). More specific information and updates are available from - http://www.scyld.com/network/epic100.html + + +DEC LANCE ethernet controller support +CONFIG_DECLANCE + This driver is for the series of Ethernet controllers produced by + DEC (now Compaq) based on the AMD Lance chipset, including the + DEPCA series. (This chipset is better known via the NE2100 cards.) SGI Seeq ethernet controller support CONFIG_SGISEEQ @@ -9418,14 +9658,14 @@ CONFIG_SUNDANCE This driver is for the Sundance "Alta" chip. More specific information and updates are available from - http://www.scyld.com/network/sundance.html + Winbond W89c840 PCI Ethernet support CONFIG_WINBOND_840 This driver is for the Winbond W89c840 chip. It also works with the TX9882 chip on the Compex RL100-ATX board. More specific information and updates are available from - http://www.scyld.com/network/drivers.html + Zenith Z-Note support (EXPERIMENTAL) CONFIG_ZNET @@ -9433,14 +9673,14 @@ (Ethernet) card, and this is the Linux driver for it. Note that the IBM Thinkpad 300 is compatible with the Z-Note and is also supported by this driver. Read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Pocket and portable adapters CONFIG_NET_POCKET Cute little network (Ethernet) devices which attach to the parallel port ("pocket adapters"), commonly used with laptops. If you have one of those, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to plug a network (or some other) card into the PCMCIA (or PC-card) slot of your laptop instead (PCMCIA is the standard for @@ -9449,7 +9689,7 @@ Documentation/Changes) and you can say N here. Laptop users should read the Linux Laptop home page at - http://www.cs.utexas.edu/users/kharker/linux-laptop/ . + . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -9460,7 +9700,7 @@ CONFIG_ATP This is a network (Ethernet) device which attaches to your parallel port. Read drivers/net/atp.c as well as the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto , if you + available from , if you want to use this. If you intend to use this driver, you should have said N to the "Parallel printer support", because the two drivers don't like each other. @@ -9475,7 +9715,7 @@ This is a network (Ethernet) device which attaches to your parallel port. Read Documentation/networking/DLINK.txt as well as the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , if you want to use + , if you want to use this. It is possible to have several devices share a single parallel port and it is safe to compile the corresponding drivers into the kernel. @@ -9490,7 +9730,7 @@ This is a network (Ethernet) device which attaches to your parallel port. Read Documentation/networking/DLINK.txt as well as the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , if you want to use + , if you want to use this. It is possible to have several devices share a single parallel port and it is safe to compile the corresponding drivers into the kernel. @@ -9508,14 +9748,14 @@ connected to such a Token Ring network and want to use your Token Ring card under Linux, say Y here and to the driver for your particular card below and read the Token-Ring mini-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . Most people can + from . Most people can say N here. IBM Tropic chipset based adapter support CONFIG_IBMTR This is support for all IBM Token Ring cards that don't use DMA. If you have such a beast, say Y and read the Token-Ring mini-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . Warning: this driver will almost definitely fail if more than one active Token Ring card is present. @@ -9533,7 +9773,7 @@ If you have such an adapter, say Y and read the Token-Ring mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9542,7 +9782,7 @@ Also read the file Documentation/networking/olympic.txt or check the Linux Token Ring Project site for the latest information at - http://www.linuxtr.net . + . IBM Lanstreamer chipset PCI adapter support CONFIG_IBMLS @@ -9550,7 +9790,7 @@ If you have such an adapter, say Y and read the Token-Ring mini-HOWTO available via FTP (user:anonymous) from - ftp://metalab.unc/edu/pub/Linux/docs/HOWTO. + . This driver is also available as a modules ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9570,10 +9810,10 @@ If you have such an adapter and would like to use it, say Y and read the Token-Ring mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Also read the file Documentation/networking/tms380tr.txt or - check http://www.auk.cx/tms380tr/ . + check . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9595,6 +9835,18 @@ The module will be called tmspci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Generic TMS380 ISA support +CONFIG_TMSISA + This tms380 module supports generic TMS380-based ISA cards. + + These cards are known to work: + - SysKonnect TR4/16 ISA (SK-4190) + + This driver is available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tmsisa.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + Madge Smart 16/4 PCI Mk2 support CONFIG_ABYSS This tms380 module supports the Madge Smart 16/4 PCI Mk2 @@ -9623,7 +9875,7 @@ If you have such an adapter and would like to use it, say Y or M and read the Token-Ring mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto and the file + and the file Documentation/networking/smctr.txt. This driver is also available as a module ( = code which can be @@ -9646,7 +9898,9 @@ Sun Lance support CONFIG_SUNLANCE This driver supports the "le" interface present on all 32-bit Sparc - systems, on some older Ultra systems and as an Sbus option. + systems, on some older Ultra systems and as an Sbus option. These + cards are based on the AMD Lance chipset, which is better known + via the NE2100 cards. This support is also available as a module called sunlance.o ( = code which can be inserted in and removed from the running kernel @@ -9687,7 +9941,7 @@ say Y to "QoS and/or fair queueing" above. To set up and configure shaper devices, you need the shapecfg - program, available from ftp://shadow.cabi.net/pub/Linux in the + program, available from in the shaper package. This driver is also available as a module ( = code which can be @@ -9794,7 +10048,7 @@ CONFIG_CD_NO_IDESCSI If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y here, otherwise N. Read the CDROM-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -9939,6 +10193,22 @@ include/linux/sbpcd.h before compiling the new kernel. Read the file Documentation/cdrom/sbpcd. +Matsushita/Panasonic, ... third CDROM controller support +CONFIG_SBPCD3 + Say Y here only if you have three CDROM controller cards of this type + (usually only if you have more than six drives). You should enter + the parameters for the second, third and fourth interface card into + include/linux/sbpcd.h before compiling the new kernel. Read + the file Documentation/cdrom/sbpcd. + +Matsushita/Panasonic, ... fourth CDROM controller support +CONFIG_SBPCD4 + Say Y here only if you have four CDROM controller cards of this type + (usually only if you have more than eight drives). You should enter + the parameters for the second, third and fourth interface card into + include/linux/sbpcd.h before compiling the new kernel. Read + the file Documentation/cdrom/sbpcd. + Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support CONFIG_AZTCD This is your driver if you have an Aztech CDA268-01A, Orchid @@ -10049,68 +10319,106 @@ usage (also called disk quotas). Currently, it works only for the ext2 file system. You need additional software in order to use quota support; for details, read the Quota mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Probably the quota + . Probably the quota support is only useful for multi user systems. If unsure, say N. Memory Technology Device (MTD) support CONFIG_MTD Memory Technology Devices are flash, RAM and similar chips, often - used for solid state filesystems on embedded devices. This option + used for solid state file systems on embedded devices. This option will provide the generic support for MTD drivers to register themselves with the kernel and for potential users of MTD devices to enumerate the devices which are present and obtain a handle on them. It will also allow you to select individual drivers for particular hardware and users of MTD device. If unsure, say N. +MTD debugging support +CONFIG_MTD_DEBUG + This turns on low-level debugging for the entire MTD sub-system. + +MTD debugging verbosity +CONFIG_MTD_DEBUG_VERBOSE + Determines the verbosity level of the MTD debugging messages. + M-Systems Disk-On-Chip 1000 support CONFIG_MTD_DOC1000 This provides an MTD device driver for the M-Systems DiskOnChip 1000 devices, which are obsolete so you probably want to say 'N'. -M-Systems Disk-On-Chip 2000 support +M-Systems Disk-On-Chip 2000 and Millennium support CONFIG_MTD_DOC2000 This provides an MTD device driver for the M-Systems DiskOnChip - 2000 devices. If you use this, you probably also want the NFTL - 'NAND Flash Translation Layer' below, which is used to emulate + 2000 and Millennium devices. Originally designed for the DiskOnChip + 2000, it also now includes support for the DiskOnChip Millennium. + If you have problems with this driver and the DiskOnChip Millennium, + you may wish to try the alternative Millennium driver below. To use + the alternative driver, you will need to undefine DOC_SINGLE_DRIVER + in the drivers/mtd/docprobe.c source code. + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to emulate a block device by using a kind of filesystem on the flash chips. -M-Systems Disk-On-Chip Millennium support +Alternative Disk-On-Chip Millennium support CONFIG_MTD_DOC2001 - This provides an MTD device driver for the M-Systems DiskOnChip - Millennium devices. If you use this, you probably also want the - NFTL 'NAND Flash Translation Layer' below, which is used to emulate + This provides an alternative MTD device driver for the M-Systems + DiskOnChip Millennium devices. Use this if you have problems with + the combined DiskOnChip 2000 and Millennium driver above. To get + the DiskOnChip probe code to load and use this driver instead of + the other one, you will need to undefine DOC_SINGLE_DRIVER near + the beginning of drivers/mtd/docprobe.c + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to emulate a block device by using a kind of filesystem on the flash chips. +Ramix PMC551 PCI Mezzanine ram card support +CONFIG_MTD_PMC551 + This provides a MTD device driver for the Ramix PMC551 RAM PCI card + from Ramix Inc. (). + These devices come in memory configurations from 32M - 1G. If you + have one, you probably want to enable this. + + If this driver is compiled as a module you get the ability to select the + size of the aperture window pointing into the devices memory. What this + means is that if you have a 1G card, normally the kernel will use a 1G + memory map as it's view of the device. As a module, you can select a + 1M window into the memory and the driver will "slide" the window around + the PMC551's memory. This was particularly useful on the 2.2 kernels + on PPC architectures as there was limited kernel space to deal with. + Use extra onboard system memory as MTD device CONFIG_MTD_SLRAM If your CPU cannot cache all of the physical memory in your machine, you can still use it for storage or swap by using this driver to present it to the system as a Memory Technology Device. -Ramix PMC551 PCI Mezzanine ram card support -CONFIG_MTD_PMC551 - This provides an MTD device driver for the Ramix PMC551 RAM card. - If you have one, you probably want to enable this. - -PMC551 256M DRAM Bugfix. +PMC551 256M DRAM Bugfix CONFIG_MTD_PMC551_BUGFIX - Some PMC551 boards hacve invalid column and row mux values. This - option will fix them, but will break other memory configurations. + Some of Ramix's PMC551 boards with 256M configurations have invalid + column and row mux values. This option will fix them, but will break + other memory configurations. If unsure say N. + +PMC551 Debugging +CONFIG_MTD_PMC551_DEBUG + This option makes the PMC551 more verbose during it's operation and is + only really useful if you are developing on this driver or suspect a + possible hardware or driver bug. If unsure say N. Debugging RAM test driver CONFIG_MTD_MTDRAM - This enables a test MTD device driver which uses vmalloc() to - provide storage. You probably want to say 'N' unless you're - testing stuff, or unless you want to use it in place of a ramdisk - when I've eventually got round to making the CONFIG_BLK_DEV option - and you've turned it off. + This enables a test MTD device driver which uses vmalloc() to + provide storage. You probably want to say 'N' unless you're + testing stuff. Common Flash Interface (CFI) support CONFIG_MTD_CFI - Intel's Common Flash Interface specification provides a universal - method for probing the capabilities of flash devices. If you wish - to support any device which uses CFI-compliant devices, you need - to enable this option. + The Common Flash Interface specification was developed by Intel, + AMD and other flash manufactures that provides a universal method + for probing the capabilities of flash devices. If you wish to + support any device that is CFI-compliant, you need to enable this + option. Visit () + for more information on CFI. CFI support for Intel/Sharp Extended Command Set chips CONFIG_MTD_CFI_INTELEXT @@ -10122,10 +10430,10 @@ Flash chip mapping in physical memory CONFIG_MTD_PHYSMAP This provides a 'mapping' driver which allows the CFI probe and - command set driver code to communicate with flash chips which + command set driver code to communicate with flash chips which are mapped physically into the CPU's memory. You will need to configure the physical address and size of the flash chips on - your particular board. + your particular board as well as the bus width. Physical start location of flash chip mapping CONFIG_MTD_PHYSMAP_START @@ -10143,38 +10451,51 @@ map which should hopefully be in the documentation for your board. +CONFIG_MTD_PHYSMAP_BUSWIDTH + This is the total width of the data bus of the flash devices + in octets. For example, if you have a data bus width of 32 + bits, you would set the bus width octect value to 4. This is + used internally by the CFI drivers. + Flash chip mapping on Mixcom piggyback card CONFIG_MTD_MIXMEM This supports the paging arrangement for access to flash chips - on the Mixcom piggyback card, allowing the flash chip drivers - to get on with their job of driving the flash chips without + on the MixCOM piggyback card, allowing the flash chip drivers + to get on with their job of driving the flash chips without having to know about the paging. If you have one of these boards, - you probably want to enable this mapping driver. + you probably want to enable this mapping driver. More info is at + (). Flash chip mapping on Nora CONFIG_MTD_NORA If you had to ask, you don't have one. Say 'N'. +Flash chip mapping on PNC2000 +CONFIG_MTD_PNC2000 + PNC-2000 is the name of Network Camera product from PHOTRON + Ltd. in Japan. It uses CFI-compliant flash. + Flash chip mapping on Octagon 5066 SBC CONFIG_MTD_OCTAGON This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Octagon-5066 Single Board - Computer. You will also need to complete and enable the driver - for JEDEC flash chips. + Computer. More information on the board is available at + (). Flash chip mapping on RPXlite PPC board CONFIG_MTD_RPXLITE - The RPXLite PowerPC board has CFI-compliant chips mapped in + The RPXLite PowerPC board has CFI-compliant chips mapped in a strange sparse mapping. This 'mapping' driver supports that arrangement, allowing the CFI probe and command set driver code - to communicate with the chips on the RPXLite board. + to communicate with the chips on the RPXLite board. More at + (). Flash chip mapping on Tempustech VMAX SBC301 CONFIG_MTD_VMAX This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Tempustech VMAX SBC301 Single - Board Computer. You will also need to complete and enable the driver - for JEDEC flash chips. + Board Computer. More information on the board is available at + (). Direct chardevice access to MTD devices CONFIG_MTD_CHAR @@ -10195,15 +10516,15 @@ Later, it may be extended to perform read/erase/modify/write cycles on flash chips to emulate a smaller block size. Needless to say, - this is very unsafe, but could be useful for filesystems which are + this is very unsafe, but could be useful for file systems which are almost never written to. FTL (Flash Translation Layer) support CONFIG_FTL This provides support for the original Flash Translation Layer which is part of the PCMCIA specification. It uses a kind of pseudo- - filesystem on a flash device to emulate a block device with 512-byte - sectors, on top of which you put a 'normal' filesystem. You may find + file system on a flash device to emulate a block device with 512-byte + sectors, on top of which you put a 'normal' file system. You may find that the algorithms used in this code are patented unless you live in the Free World where software patents aren't legal - in the USA you are only permitted to use this on PCMCIA hardware, although @@ -10214,8 +10535,8 @@ CONFIG_NFTL This provides support for the NAND Flash Translation Layer which is used on M-Systems' DiskOnChip devices. It uses a kind of pseudo- - filesystem on a flash device to emulate a block device with 512-byte - sectors, on top of which you put a 'normal' filesystem. You may find + file system on a flash device to emulate a block device with 512-byte + sectors, on top of which you put a 'normal' file system. You may find that the algorithms used in this code are patented unless you live in the Free World where software patents aren't legal - in the USA you are only permitted to use this on DiskOnChip hardware, although @@ -10224,8 +10545,8 @@ Write support for NFTL (EXPERIMENTAL) CONFIG_NFTL_RW - If you're lucky, this will actually work. Don't whinge if it doesn't. - Contact dwmw2@infradead.org if you want to help to make it more + If you're lucky, this will actually work. Don't whine if it doesn't. + Contact (dwmw2@infradead.org) if you want to help to make it more reliable. Support for USB @@ -10300,10 +10621,6 @@ The module will be called uhci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -UHCI unlink optimizations (EXPERIMENTAL) -CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE - This option currently does nothing. You may say Y or N. - OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support CONFIG_USB_OHCI The Open Host Controller Interface is a standard by @@ -10399,6 +10716,16 @@ If unsure, say Y. +Input core support +CONFIG_INPUT + Say Y here if you want to enable any of the following options for + USB Human Interface Device (HID) support. + + Say Y here if you want to enable any of the USB HID options in the + USB support section which require Input core support. + + Otherwise, say N. + Keyboard support CONFIG_INPUT_KEYBDEV Say Y here if you want your USB HID keyboard (or an ADB keyboard @@ -10522,7 +10849,7 @@ USB Handspring Visor Driver CONFIG_USB_SERIAL_VISOR Say Y here if you want to connect to your HandSpring Visor through - its USB docking station. See http://usbvisor.sourceforge.net for + its USB docking station. See for more information on using this driver. This code is also available as a module ( = code which can be @@ -10546,7 +10873,7 @@ Say Y here if you want to use a FTDI SIO single port USB to serial converter device. The implementation I have is called the USC-1000. - See http://reality.sgi.com/bryder_wellington/ftdi_sio for more + See for more information on this driver and the device. This code is also available as a module ( = code which can be @@ -10572,7 +10899,7 @@ and was developed with their support. You must also include firmware to support your particular device(s). - See http://www.linuxcare.com.au/hugh/keyspan.html for + See for more information. This code is also available as a module ( = code which can be @@ -10704,7 +11031,7 @@ (Y or M in config) Video For Linux (under Character Devices) to use this driver. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -10722,13 +11049,26 @@ This driver uses the Video For Linux API. You must say Y or M to "Video For Linux" (under Character Devices) to use this driver. Information on this API and pointers to "v4l" programs may be found - on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml . + on the WWW at . This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called ov511.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB Communication Class Ethernet driver +CONFIG_USB_CDCETHER + This driver supports devices conforming to the Communication + Device Class Ethernet Control Model. This is used in some + cable modems (Ericsson, Broadcom and others). For more + details on the specification, get the Communication + Device Class specification from + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called CDCether.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + USB ADMtek Pegasus-based ethernet device support CONFIG_USB_PEGASUS Say Y if you want to use your USB ethernet device. Supported @@ -10755,6 +11095,36 @@ The module will be called pegasus.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' +CONFIG_USB_KAWETH + Say Y here if you want to use one of the following 10Mbps only + USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: + 3Com 3C19250 + ADS USB-10BT + ATEN USB Ethernet + ASANTE USB To Ethernet Adapter + AOX Endpoints USB Ethernet + Correga K.K. + D-Link DSB-650C and DU-E10 + Entrega / Portgear E45 + Jaton USB Ethernet Device Adapter + Kingston Technology USB Ethernet Adapter + Linksys USB10T + Mobility USB-Ethernet Adapter + NetGear EA-101 + Peracom Enet and Enet2 + Portsmith Express Ethernet Adapter + Shark Pocket Adapter + SMC 2202USB + Sony Vaio port extender + + This driver is likely to work with most 10Mbps only USB Ethernet + adapters, including some "no brand" devices. + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called kaweth.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + USB Kodak DC-2xx Camera support CONFIG_USB_DC2XX Say Y here if you want to connect this type of still camera to @@ -10771,7 +11141,7 @@ CONFIG_USB_MDC800 Say Y here if you want to connect this type of still camera to your computer's USB port. This driver can be used with gphoto 0.4.3 - and higher (look at http://www.gphoto.org ). + and higher (look at ). To use it create a device node with "mknod /dev/mustek c 180 32" and configure it in your software. @@ -10826,16 +11196,16 @@ USB device file system CONFIG_USB_DEVICEFS If you say Y here (and to "/proc file system support" below), you - will get a file /proc/usb/devices which lists the devices currently - connected to your USB busses, a file /proc/usb/drivers which lists - the USB kernel client drivers currently loaded, and for every - connected device a file named "/proc/usb/xxx/yyy", where xxx is the - bus number and yyy the device number; the latter files can be used - by user space programs to talk directly to the device. These files - are "virtual", meaning they are generated on the fly and not stored - on the hard drive. + will get a file /proc/bus/usb/devices which lists the devices + currently connected to your USB busses, a file /proc/bus/usb/drivers + which lists the USB kernel client drivers currently loaded, and for + every connected device a file named "/proc/bus/usb/xxx/yyy", where + xxx is the bus number and yyy the device number; the latter files + can be used by user space programs to talk directly to the device. + These files are "virtual", meaning they are generated on the fly + and not stored on the hard drive. - For the format of the /proc/usb/ files, please read + For the format of the /proc/bus/usb/ files, please read Documentation/usb/proc_usb_info.txt. Please note that this code is completely unrelated to devfs, the @@ -10857,7 +11227,7 @@ DABUSB driver CONFIG_USB_DABUSB A Digital Audio Broadcasting (DAB) Receiver for USB and Linux - brought to you by the DAB-Team (http://dab.in.tum.de). This driver + brought to you by the DAB-Team (This driver can be taken as an example for URB-based bulk, control, and isochronous transactions. URB's are explained in Documentation/usb/URB.txt. @@ -10867,12 +11237,29 @@ The module will be called dabusb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Host-to-Host USB networking +CONFIG_USB_USBNET + This driver supports network links over USB with USB "Network" + or "data transfer" cables, often used to network laptops to PCs. + Such cables have chips from suppliers such as NetChip and Prolific. + Intelligent USB devices could also use this approach to provide + Internet access, using standard USB cabling. + + These links will have names like "usb0", "usb1", etc. They act + like two-node Ethernets, so you can use 802.1d Ethernet Bridging + (CONFIG_BRIDGE) to simplify your network routing. + + This code is also available as a kernel module (code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbnet.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + PLUSB driver CONFIG_USB_PLUSB A driver for the Prolific PL-2302 USB-to-USB network device. This 'USB cable' connects two hosts via a point-to-point network with - bandwidth of 5 Mbit/s. Configure this driver after connecting the - USB cable via ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 (and + bandwidth of 6 Mbit/s. Configure this driver after connecting the + USB cable via "ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2" (and vice versa on the other host). This code is also available as a module ( = code which can be @@ -10902,13 +11289,56 @@ (Y or M in config) Video For Linux (under Character Devices) to use this driver. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called dsbr100.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Always do synchronous disk IO for UBD +CONFIG_BLK_DEV_UBD_SYNC + The User-Mode Linux port includes a driver called UBD which will let + you access arbitrary files on the host computer as block devices. + Writes to such a block device are not immediately written to the + host's disk; this may cause problems if, for example, the User-Mode + Linux 'Virtual Machine' uses a journalling filesystem and the host + computer crashes. + + Synchronous operation (i.e. always writing data to the host's disk + immediately) is configurable on a per-UBD basis by using a special + kernel command line option. Alternatively, you can say Y here to turn + on synchronous operation by default for all block. + + If you're running a journalling filesystem (like reiserfs, for example) + in your virtual machine, you will want to say Y here. If you care for + the safety of the data in your virtual machine, Y is a wise choice too. + In all other cases (for example, if you're just playing around with + User-Mode Linux) you can choose N. + +Prompt for filesystems other than ext2, proc, /dev/pts, /dev +CONFIG_PROMPT_FS + Most User-Mode Linux users will use one of the pre-built root + filesystem images, and won't access any other filesystems. + + If you say N here, then the kernel will be compiled with support + for quota, procfs, ext2, the /dev/pts filesystem, optionally the + /dev filesystem, and no other filesystem options. + + If you are doing filesystem hacking, or want to use NFS or cramfs + (or any other filesystem option), you should say Y here and you'll + be asked the normal filesystem questions. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about filesystems except devfs. If unsure, say N. + +Enable ptrace proxy +CONFIG_PT_PROXY + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. + If you want to do kernel debugging, say Y here; otherwise say N. + Microtek USB scanner support CONFIG_USB_MICROTEK Say Y here if you want support for the Microtek X6USB and possibly @@ -10916,14 +11346,14 @@ scsi generic device to the rest of the system. A patched version of SANE is necessary to use the scanner. It's available at - http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html + This driver can be compiled as a module. USB Bluetooth support CONFIG_USB_BLUETOOTH Say Y here if you want to connect a USB Bluetooth device to your computer's USB port. You will need the Bluetooth stack (available - at http://developer.axis.com/software/index.shtml) to fully use + at to fully use the device. This code is also available as a module ( = code which can be @@ -11008,7 +11438,7 @@ by about 44 KB. The Ext2fs-Undeletion mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , gives information about + , gives information about how to retrieve deleted files on ext2fs file systems. To change the behavior of ext2 file systems, you can use the tune2fs @@ -11017,13 +11447,13 @@ Ext2fs partitions can be read from within DOS using the ext2tool command line tool package (available via FTP (user: anonymous) from - ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2 ) and from + ) and from within Windows NT using the ext2nt command line tool package from - ftp://metalab.unc.edu/pub/Linux/utils/dos . Explore2fs is a + . Explore2fs is a graphical explorer for ext2fs partitions which runs on Windows 95 and Windows NT and includes experimental write support; it is available from - http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm . + . If you want to compile this file system as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -11053,6 +11483,12 @@ called bfs.o. Note that the file system of your root partition (the one containing the directory /) cannot be compiled as a module. +CMS file system support +CONFIG_CMS_FS + Read only support for CMS minidisk file systems found on IBM mainframe + systems. Only the basic format is supported so far. + If you don't know what CMS is you probably don't want to know any more. + Compressed ROM file system support CONFIG_CRAMFS Saying Y here includes support for CramFs (Compressed ROM File @@ -11072,23 +11508,44 @@ If unsure, say N. +Virtual memory file system support +CONFIG_TMPFS + Tmpfs is a file system which keeps all files in virtual memory. + + In contrast to RAM disks, which get allocated a fixed amount of + physical RAM, tmpfs grows and shrinks to accommodate the files it + contains and is able to swap unneeded pages out to swap space. + + Everything is "virtual" in the sense that no files will be created + on your hard drive; if you reboot, everything in tmpfs will be + lost. + + You should mount the filesystem somewhere to be able to use + POSIX shared memory. Adding the following line to /etc/fstab should + take care of things: + + tmpfs /dev/shm tmpfs defaults 0 0 + + Remember to create the directory that you intend to mount tmpfs on + if necessary (/dev/shm is automagically created if you use devfs). + + You can set limits for the number of blocks and inodes used by the + filesystem with the mount options "size", "nr_blocks" and + "nr_inodes". These parameters accept a suffix k, m or g for kilo, + mega and giga and can be changed on remount. + + The initial permissions of the root directory can be set with the + mount option "mode". + Simple RAM-based file system support CONFIG_RAMFS Ramfs is a file system which keeps all files in RAM. It allows read and write access. - In contrast to RAM disks, which get allocated a fixed amount of RAM, - ramfs grows and shrinks to accommodate the files it contains. + It is more of an programming example than a useable filesystem. If + you need a file system which lives in RAM with limit checking use + tmpfs. - Before you can use this RAM-based file system, it has to be mounted, - meaning it has to be given a location in the directory hierarchy. If - you want to use the location /ramfiles for example, you would have - to create that directory first and then mount the file system by - saying "mount -t ramfs ramfs /ramfiles" or the equivalent line in - /etc/fstab. Everything is "virtual" in the sense that no files will - be created on your hard drive; if you reboot, everything in - /ramfiles will be lost. - If you want to compile this 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 @@ -11103,7 +11560,7 @@ driver. If you have a CDROM drive and want to do more with it than just listen to audio CDs and watch its LEDs, say Y (and read Documentation/filesystems/isofs.txt and the CDROM-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto ), thereby enlarging + from ), thereby enlarging your kernel by about 27 KB; otherwise say N. If you want to compile this as a module ( = code which can be @@ -11117,7 +11574,7 @@ which allows for long filenames in unicode format (unicode is the new 16 bit character code, successor to ASCII, which encodes the characters of almost all languages of the world; see - http://www.unicode.org for more information). Say Y here if you want + for more information). Say Y here if you want to be able to read Joliet CDROMs under Linux. UDF File System support (read only) @@ -11192,8 +11649,8 @@ they are compressed; to access compressed MSDOS partitions under Linux, you can either use the DOS emulator DOSEMU, described in the DOSEMU-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , or try dmsdosfs in - ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs . If you + , or try dmsdosfs in + . If you intend to use dosemu with a non-compressed MSDOS partition, say Y here) and MSDOS floppies. This means that file access becomes transparent, i.e. the MSDOS files look and behave just like all @@ -11253,7 +11710,7 @@ To get utilities for initializing/checking UMSDOS file system, or latest patches and/or information, visit the UMSDOS home page at - http://www.voyager.hr/~mnalis/umsdos/ . + . This option enlarges your kernel by about 28 KB and it only works if you said Y to both "DOS FAT fs support" and "MSDOS fs support" @@ -11264,6 +11721,16 @@ (the one containing the directory /) cannot be a module, so saying M could be dangerous. If unsure, say N. +PReP residual data support +CONFIG_PREP_RESIDUAL + Some PReP systems have residual data passed to the kernel by the + firmware. This allows detection of memory size, devices present and + other useful pieces of information. Sometimes this information is not + present or incorrect. + + Unless you expect to boot on a PReP system, there is not need to select + yes. + /proc file system support CONFIG_PROC_FS This is a virtual file system providing information about the status @@ -11336,7 +11803,7 @@ programs nfsd and mountd (but does not need to have NFS file system support enabled in its kernel). NFS is explained in the Network Administrator's Guide, available from - http://www.linuxdoc.org/docs.html#guide , on its man page: "man + , on its man page: "man nfs", and in the NFS-HOWTO. A superior but less widely used alternative to NFS is provided by @@ -11356,7 +11823,7 @@ below. You cannot compile this driver as a module in this case. There are two packages designed for booting diskless machines over the net: netboot and etherboot, both available via FTP from - ftp://metalab.unc.edu/pub/Linux/system/boot/ethernet/ . + . If you don't know what all this is about, say N. @@ -11398,7 +11865,7 @@ as well. Please read the NFS-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . The NFS server is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -11448,12 +11915,16 @@ NTFS write support (DANGEROUS) CONFIG_NTFS_RW If you say Y here, you will (maybe) be able to write to NTFS file - systems as well as read from them. The read-write support in - NTFS is far from being complete and is not well tested. If you - say Y here, back up your NTFS volume first since it may get - damaged. Also, make sure to run chkdsk from within Microsoft - Windows NT after having performed any writes to a NTFS partition - from Linux to detect any problems as early as possible. + systems as well as read from them. The read-write support in NTFS + is far from being complete and is not well tested. If you say Y + here, back up your NTFS volume first, since it will probably get + damaged. Also, download the Linux-NTFS project distribution from + Sourceforge at and + always run the included ntfsfix utility after writing to an NTFS + partition from Linux to fix some of the damage done by the driver. + You should run ntfsfix _after_ unmounting the partition in Linux + but _before_ rebooting into Windows. When Windows next boots, + chkdsk will be run automatically to fix the remaining damage. Please note that write support is limited to Windows NT4 and earlier versions. @@ -11473,7 +11944,7 @@ Xenix, Wyse, UnixWare, Dell Unix and System V programs under Linux and is often needed to run commercial software that's only available for those systems. It's available via FTP (user: anonymous) from - ftp://tsx-11.mit.edu/pub/linux/BETA ). + ). If you only intend to mount files from some other Unix over the network using NFS, you don't need the System V file system support @@ -11515,7 +11986,7 @@ fs/affs/Changes. With this driver you can also mount disk files used by Bernd - Schmidt's Un*X Amiga Emulator (http://www.freiburg.linux.de/~uae/ ). + Schmidt's Un*X Amiga Emulator (). If you want to do this, you will also need to say Y or M to "Loop device support", above. @@ -11605,7 +12076,7 @@ automounter (amd), which is a pure user space daemon. To use the automounter you need the user-space tools from - ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4 ; you also + ; you also want to answer Y to "NFS file system support", below. If you want to compile this as a module ( = code which can be @@ -11627,28 +12098,47 @@ This implementation only offers read-only access. If you don't know what all this is about, it's safe to say N. For more information - about EFS see its home page at http://aeschi.ch.eu.org/efs/ . + about EFS see its home page at . If you want to compile the EFS file system support 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 efs.o. -Journalling Flash File System (JFFS) support (EXPERIMENTAL) +Support for the Journalling Flash Filesystem CONFIG_JFFS_FS - JFFS is a new file system designed for use on flash memory devices - rather than on block devices. It was developed on the 2.0 kernel - by Axis Communications AB for use on their Linux-based products, - and released under GPL, then 'borrowed' and ported to work with - the 2.4 kernel and the new Memory Technology Device system. - - The 2.4 port is experimental and not yet supported by Axis. Basically, - the good bits are probably theirs, and if it's broken in 2.4 it's - probably our fault. See http://www.developer.axis.com/software/jffs/ - for more information about JFFS. + JFFS is the Journaling Flash File System developed by Axis + Communications in Sweden, aimed at providing a crash/powerdown-safe + filesystem for disk-less embedded devices. Further information is + available at (). + +JFFS debugging verbosity +CONFIG_JFFS_FS_VERBOSE + Determines the verbosity level of the JFFS debugging messages. + +Journalling Flash Filesystem version 2 +CONFIG_JFFS2_FS + JFFS2 is the second generation of the Journalling Flash File System + for use on diskless embedded devices. It provides improved wear + levelling, compression and support for hard links. You cannot use + this on normal block devices, only on 'MTD' devices. + + Further information should be made available soon at + + +JFFS2 debugging verbosity +CONFIG_JFFS2_FS_DEBUG + This controls the amount of debugging messages produced by the JFFS2 + code. Set it to zero for use in production systems. For evaluation, + testing and debugging, it's advisable to set it to one. This will + enable a few assertions and will print debugging messages at the + KERN_DEBUG loglevel, where they won't normally be visible. Level 2 + is unlikely to be useful - it enables extra debugging in certain + areas which at one point needed debugging, but when the bugs were + located and fixed, the detailed messages were relegated to level 2. - Any potential patches or queries should be sent to Axis' mailing - list for JFFS: + If reporting bugs, please try to have available a full dump of the + messages at debug level 1 while the misbehaviour was occurring. UFS file system support (read-only) CONFIG_UFS_FS @@ -11697,6 +12187,33 @@ If unsure, say N. +Acorn partition support +CONFIG_ACORN_PARTITION + Support hard disks partitioned under Acorn operating systems. + +Native filecore partition support +CONFIG_ACORN_PARTITION_ADFS + The Acorn Disc Filing System is the standard file system of the + RiscOS operating system which runs on Acorn's ARM-based Risc PC + systems and the Acorn Archimedes range of machines. If you say + `Y' here, Linux will support disk partitions created under ADFS. + +PowerTec partition support +CONFIG_ACORN_PARTITION_POWERTEC + Support reading partition tables created on Acorn machines using + the PowerTec SCSI drive. + +RISCiX partition support +CONFIG_ACORN_PARTITION_RISCIX + Once upon a time, there was a native Unix port for the Acorn series + of machines called RISCiX. If you say 'Y' here, Linux will be able to + read disks partitioned under RISCiX. + +ICS partition support +CONFIG_ACORN_PARTITION_ICS + Say Y here if you would like to use hard disks under Linux which + were partitioned using the ICS interface on Acorn machines. + Alpha OSF partition support CONFIG_OSF_PARTITION Say Y here if you would like to use hard disks under Linux which @@ -11712,6 +12229,16 @@ Say Y here if you would like to use hard disks under Linux which were partitioned on an x86 PC (not necessarily by DOS). +Amiga partition table support +CONFIG_AMIGA_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned under AmigaOS. + +Atari partition table support +CONFIG_ATARI_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned under the Atari OS. + BSD disklabel (FreeBSD partition tables) support CONFIG_BSD_DISKLABEL FreeBSD uses its own hard disk partition scheme on your PC. It @@ -11723,6 +12250,12 @@ file system support", above. If you don't know what all this is about, say N. +Minix subpartition support +CONFIG_MINIX_SUBPARTITION + Minix 2.0.0/2.0.2 subpartition table support for Linux. + Say Y here if you want to mount and use Minix 2.0.0/2.0.2 + subpartitions. + Sun partition tables support CONFIG_SUN_PARTITION Like most systems, SunOS uses its own hard disk partition table @@ -11749,6 +12282,18 @@ Say Y here if you would like to be able to read the hard disk partition table format used by SGI machines. +Ultrix partition support +CONFIG_ULTRIX_PARTITION + Say Y here if you would like to be able to read the hard disk + partition table format used by DEC (now Compaq) Ultrix machines. + Otherwise, say N. + +IBM disk label and partition support +CONFIG_IBM_PARTITION + Say Y here if you would like to be able to read the hard disk + partition table format used by IBM DASD disks operating under CMS. + Otherwise, say N. + ADFS file system support (EXPERIMENTAL) CONFIG_ADFS_FS The Acorn Disc Filing System is the standard file system of the @@ -11823,16 +12368,16 @@ works only if the Windows machines use TCP/IP as the underlying transport protocol, and not NetBEUI. For details, read Documentation/filesystems/smbfs.txt and the SMB-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + from . Note: if you just want your box to act as an SMB *server* and make files and printing services available to Windows clients (which need to have a TCP/IP stack), you don't need to say Y here; you can use the program samba (available via FTP (user: anonymous) in - ftp://metalab.unc.edu/pub/Linux/system/network/samba ) for that. + ) for that. General information about how to connect Linux, Windows machines and - Macs is on the WWW at http://www.eats.com/linux_mac_win.html . + Macs is on the WWW at . If you want to compile the SMB support as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -11852,7 +12397,7 @@ Currently no smbmount distributed with samba supports this, it is assumed future versions will. In the meantime you can get an unofficial patch for samba 2.0.7 from: - http://www.hojdpunkten.ac.se/054/samba/index.html + nls support setting CONFIG_SMB_NLS_REMOTE @@ -11867,7 +12412,7 @@ Currently no smbmount distributed with samba supports this, it is assumed future versions will. In the meantime you can get an unofficial patch for samba 2.0.7 from: - http://www.hojdpunkten.ac.se/054/samba/index.html + Coda file system support (advanced network fs) CONFIG_CODA_FS @@ -11883,7 +12428,7 @@ *client*. You will need user level code as well, both for the client and server. Servers are currently user level, i.e. they need no kernel support. Please read Documentation/filesystems/coda.txt and - check out the Coda home page http://www.coda.cs.cmu.edu . + check out the Coda home page . If you want to compile the coda client support as a module ( = code which can be inserted in and removed from the running kernel @@ -11898,13 +12443,13 @@ mount NetWare file server volumes and to access them just like any other Unix directory. For details, please read the file Documentation/filesystems/ncpfs.txt in the kernel source and the - IPX-HOWTO from http://www.linuxdoc.org/docs.html#howto . + IPX-HOWTO from . You do not have to say Y here if you want your Linux box to act as a file *server* for Novell NetWare clients. General information about how to connect Linux, Windows machines and - Macs is on the WWW at http://www.eats.com/linux_mac_win.html . + Macs is on the WWW at . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -11998,7 +12543,7 @@ nls default codepage CONFIG_NLS_DEFAULT - The default NLS used when mounting filesystem. Currently, the valid + The default NLS used when mounting file system. Currently, the valid values are: big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861, cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936, @@ -12185,9 +12730,20 @@ only, not to the file contents. You can include several codepages; say Y here if you want to include the DOS codepage for Thai. +Windows CP1251 (Bulgarian, Belarussian) +CONFIG_NLS_CODEPAGE_1251 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Russian and + Bulgarian and Belorussian. + nls codepage 932 CONFIG_NLS_CODEPAGE_932 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12199,7 +12755,7 @@ nls codepage 936 CONFIG_NLS_CODEPAGE_936 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12210,7 +12766,7 @@ nls codepage 949 CONFIG_NLS_CODEPAGE_949 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12220,7 +12776,7 @@ nls codepage 950 CONFIG_NLS_CODEPAGE_950 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -12321,6 +12877,14 @@ letters that were missing in Latin 4 to cover the entire Nordic area. +NLS ISO 8859-13 (Latin 7; Baltic) +CONFIG_NLS_ISO8859_13 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 7 character + set, which supports modern Baltic languages including Latvian. + NLS ISO 8859-14 (Latin 8; Celtic) CONFIG_NLS_ISO8859_14 If you want to display filenames with native language characters @@ -12329,7 +12893,7 @@ input/output character sets. Say Y here for the Latin 8 character set, which adds the last accented vowels for Welsh (aka Cymraeg) (and Manx Gaelic) hat were missing in Latin 1. - http://linux.speech.cymru.org/ has further information. + has further information. nls iso8859-15 CONFIG_NLS_ISO8859_15 @@ -12354,6 +12918,14 @@ input/output character sets. Say Y here for the preferred Russian character set. +NLS UTF8 +CONFIG_NLS_UTF8 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the UTF-8 encoding of + the Unicode/ISO9646 universal character set. + Virtual terminal CONFIG_VT If you say Y here, you will get support for terminal devices with @@ -12401,8 +12973,20 @@ If unsure, say Y. +Apple Desktop Bus (ADB) support +CONFIG_ADB + Include support for peripherals connected via the Apple Desktop Bus, ADB. + +Include CUDA ADB driver +CONFIG_ADB_CUDA + Macintosh PowerPCs feature an intelligent power switch called a Cuda; + its job is to turn system power on and off, manage system resets from + various commands, maintain parameter RAM (PRAM), and manage the + real-time clock. If you say `Y' the Linux kernel will support the + Cuda directly. + Support for PowerMac keyboard -CONFIG_MAC_KEYBOARD +CONFIG_ADB_KEYBOARD This option allows you to use an ADB keyboard attached to your machine. Note that this disables any other (ie. PS/2) keyboard support, even if your machine is physically capable of using both at @@ -12411,6 +12995,13 @@ If you use an ADB keyboard (4 pin connector), say Y here. If you use a PS/2 keyboard (6 pin connector), say N here. +Include IOP (IIfx/Quadra 9x0) ADB driver +CONFIG_ADB_IOP + The I/O Processor (IOP) is an Apple custom IC designed to provide + intelligent support for I/O controllers. It is described at + to enable direct + support for it, say 'Y' here. + Standard/generic serial support CONFIG_SERIAL This selects whether you want to include the driver for the standard @@ -12720,7 +13311,7 @@ box (as opposed to using a serial printer; if the connector at the printer has 9 or 25 holes ["female"], then it's serial), say Y. Also read the Printing-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . It is possible to share one parallel port among several devices (e.g. printer and ZIP drive) and it is safe to compile the @@ -12736,8 +13327,8 @@ how to pass options to the kernel at boot time.) The syntax of the "lp" command line option can be found in drivers/char/lp.c. - If you have more than 3 printers, you need to increase the LP_NO - variable in lp.c. + If you have more than 8 printers, you need to increase the LP_NO + macro in lp.c and the PARPORT_MAX macro in parport.h. Support for console on line printer CONFIG_LP_CONSOLE @@ -12869,7 +13460,7 @@ Microsoft mouse (made by Logitech) that plugs into a COM port (rectangular with 9 or 25 pins). These people say N here. If you have something else, read the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , and say Y here. + , and say Y here. If you have a laptop, you either have to check the documentation or experiment a bit to find out whether the trackball is a serial mouse @@ -12892,7 +13483,7 @@ MouseSystem or Microsoft mouse (made by Logitech) that plugs into a COM port (rectangular with 9 or 25 pins). These people say N here. If you have something else, read the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . This HOWTO contains + . This HOWTO contains information about all non-serial mice, not just bus mice. If you have a laptop, you either have to check the documentation or @@ -12909,7 +13500,7 @@ generally a round connector with 9 pins. Note that the newer mice made by Logitech don't use the Logitech protocol anymore; for those, you don't need this option. You want to read the Busmouse-HOWTO , - available from http://www.linuxdoc.org/docs.html#howto . + available from . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -12929,12 +13520,12 @@ Although PS/2 mice are not technically bus mice, they are explained in detail in the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . When using a PS/2 mouse, you can get problems if you want to use the mouse both on the Linux console and under X. Using the "-R" option of the Linux mouse managing program gpm (available from - ftp://metalab.unc.edu/pub/Linux/system/mouse ) solves this + ) solves this problem, or you can get the "mconv2" utility from the same location. C&T 82C710 mouse port support (as on TI Travelmate) @@ -12942,7 +13533,7 @@ This is a certain kind of PS/2 mouse used on the TI Travelmate. If you are unsure, try first to say N here and come back if the mouse doesn't work. Read the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . PC110 digitizer pad support CONFIG_PC110_PAD @@ -12960,7 +13551,7 @@ These animals (also called Inport mice) are connected to an expansion board using a round connector with 9 pins. If this is what you have, say Y and read the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you are unsure, say N and read the HOWTO nevertheless: it will tell you what you have. Also be aware that several vendors talk @@ -12976,7 +13567,7 @@ CONFIG_ADBMOUSE Say Y here if you have this type of bus mouse (4 pin connector) as is common on Macintoshes. You may want to read the Busmouse-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -12990,7 +13581,7 @@ most mice by ATI are actually Microsoft busmice; you should say Y to "Microsoft busmouse support" above if you have one of those. Read the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -13049,7 +13640,7 @@ Note that the Ftape-HOWTO is out of date (sorry) and documents the older version 2.08 of this software but still contains useful information. There is a web page with more recent documentation at - http://www.math1.rwth-aachen.de/~heine/ftape/ . This page + . This page always contains the latest release of the ftape driver and useful information (backup software, ftape related patches and documentation, FAQ). Note that the file system interface has changed @@ -13084,7 +13675,7 @@ file Documentation/ftape.txt contains a short description of the most important changes in the file system interface compared to previous versions of ftape. The ftape home page - http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ contains + contains further information. IMPORTANT NOTE: zftape can read archives created by previous @@ -13313,7 +13904,7 @@ introduced in XFree86 4.0. If you say Y here, you need to select the module that's right for your graphics card from the list below. These modules provide support for synchronization, security, and - DMA transfers. Please see http://dri.sourceforge.net for more + DMA transfers. Please see for more details. You should also select and configure AGP (/dev/agpgart) support. @@ -13333,6 +13924,14 @@ is selected, the module will be called r128.o. AGP support for this card is strongly suggested (unless you have a PCI version). +ATI Radeon +CONFIG_DRM_RADEON + Choose this option if you have an ATI Radeon graphics card. There + are both PCI and AGP versions. You don't need to choose this to + run the Radeon in plain VGA mode. There is a product page at + . + If M is selected, the module will be called radeon.o. + Intel I810 CONFIG_DRM_I810 Choose this option if you have an Intel I810 graphics card. If M is @@ -13345,6 +13944,12 @@ is selected, the module will be called mga.o. AGP support is required for this driver to work. +Creator/Creator3D/Elite3D +CONFIG_DRM_FFB + Choose this option if you have one of Sun's Creator3D-based graphics + and frame buffer cards. Product page at + . + MTRR control and configuration CONFIG_MTRR On Intel P6 family processors (Pentium Pro, Pentium II and later) @@ -13387,7 +13992,7 @@ Double Talk PC internal speech card support CONFIG_DTLK This driver is for the DoubleTalk PC, a speech synthesizer - manufactured by RC Systems (http://www.rcsys.com/ ). It is also + manufactured by RC Systems (). It is also called the `internal DoubleTalk'. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read @@ -13411,7 +14016,7 @@ 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/ , or by email from David Woodhouse + , or by email from David Woodhouse . To compile this driver as a module ( = code which can be inserted in @@ -13448,9 +14053,9 @@ Power Management is most important for battery powered laptop computers; if you have a laptop, check out the Linux Laptop home page on the WWW at - http://www.cs.utexas.edu/users/kharker/linux-laptop/ and the Battery + and the Battery Powered Linux mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . Note that, even if you say N here, Linux on the x86 architecture will issue the hlt instruction if nothing is to be done, thereby @@ -13481,10 +14086,20 @@ Component Architecture (ACPI CA). The latest ACPI CA source code, documentation, debug builds, and implementation status information can be downloaded from: - http://developer.intel.com/technology/iapc/acpi/downloads.htm - + + The ACPI mailing list may also be of interest: - http://phobos.fs.tum.de/acpi/index.html + + +Enable ACPI 2.0 with errata 1.3 +CONFIG_ACPI20 + Enable support for the 2.0 version of the ACPI interpreter. See the + help for ACPI for caveats and discussion. + +ACPI kernel configuration manager +CONFIG_ACPI_KERNEL_CONFIG + If you say `Y' here, Linux's ACPI support will use the hardware-level + system descriptions found on IA64 machines. Advanced Power Management BIOS support CONFIG_APM @@ -13504,7 +14119,7 @@ In order to use APM, you will need supporting software. For location and more information, read Documentation/pm.txt and the Battery Powered Linux mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . This driver does not spin down disk drives (see the hdparm(8) manpage ("man 8 hdparm") for that), and it doesn't turn off @@ -13533,7 +14148,7 @@ 5) pass the "mem=4M" option to the kernel (thereby disabling all but the first 4 MB of RAM) 6) make sure that the CPU is not over clocked. - 7) read the sig11 FAQ at http://www.bitwizard.nl/sig11/ + 7) read the sig11 FAQ at 8) disable the cache from your BIOS settings 9) install a fan for the video card or exchange video RAM 10) install a better fan for the CPU @@ -13632,7 +14247,7 @@ The watchdog is usually used together with the watchdog daemon which is available via FTP (user: anonymous) from - ftp://tsx-11.mit.edu/pub/linux/sources/sbin/ . This daemon can also + . This daemon can also monitor NFS connections and can reboot the machine when the process table is full. @@ -13706,7 +14321,7 @@ and if it does, it reboots your computer after a certain amount of time. This driver is like the WDT501 driver but for different hardware. Please read Documentation/pcwd-watchdog.txt. The PC - watchdog cards can be ordered from http://www.berkprod.com . + watchdog cards can be ordered from . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -13729,8 +14344,14 @@ module, say M here and read Documentation/modules.txt. Most people will say N. +Advantech SBC Watchdog Timer +CONFIG_ADVANTECH_WDT + If you are configuring a Linux kernel for the Advantech single-board + computer, say `Y' here to support its built-in watchdog timer feature. + See the help for CONFIG_WATCHDOG for discussion. + Mixcom Watchdog -CONFIG_MIXCOMWD +CONFIG_MIXCOMWD This is a driver for the Mixcom hardware watchdog cards. This watchdog simply watches your kernel to make sure it doesn't freeze, and if it does, it reboots your computer after a certain amount of @@ -13742,16 +14363,31 @@ module, say M here and read Documentation/modules.txt. Most people will say N. +ZF MachZ Watchdog +CONFIG_MACHZ_WDT + If you are using a ZF Micro MachZ processor, say Y here, otherwise N. + This is the driver for the watchdog timer builtin on that processor + using ZF-Logic interface. This watchdog simply watches your kernel to + make sure it doesn't freeze, and if it does, it reboots your computer + after a certain amount of time. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called machzwd.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. + Toshiba Laptop support CONFIG_TOSHIBA - If you intend to run this the kernel on a Toshiba portable say yes - here. This adds a driver to safely access the System Management - Mode of the CPU on Toshiba portables. The System Management Mode + This adds a driver to safely access the System Management Mode + of the CPU on Toshiba portables. The System Management Mode is used to set the BIOS and power saving options on Toshiba portables. For information on utilities to make use of this driver see the - Toshiba Linux utilities website at: - http://www.buzzard.org.uk/toshiba/ + Toshiba Linux utilities web site at: + + + Say Y if you intend to run this kernel on a Toshiba portable. + Say N otherwise. /dev/cpu/microcode - Intel IA32 CPU microcode support CONFIG_MICROCODE @@ -13763,7 +14399,7 @@ For latest news and information on obtaining all the required ingredients for this driver, check: - http://www.urbanmyth.org/microcode/ + This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -13787,6 +14423,18 @@ with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to /dev/cpu/31/cpuid. +SBC-60XX Watchdog Timer +CONFIG_60XX_WDT + This driver can be used with the watchdog timer found on some + single board computers, namely the 6010 PII based computer. + It may well work with other cards. It reads port 0x443 to enable + and re-set the watchdog timer, and reads port 0x45 to disable + the watchdog. If you have a card that behave in similar ways, + you can probably make this driver work with your card as well. + + You can compile this driver directly into the kernel, or use + it as a module. The module will be called sbc60xxwdt.o. + Enhanced Real Time Clock Support CONFIG_RTC If you say Y here and create a character special file /dev/rtc with @@ -13883,6 +14531,12 @@ The module will be called lightning.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Crystal SoundFusion gameports +CONFIG_INPUT_CS461X + Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion" + PCI audio accelerator. A product page for the CS4614 is at + . + Aureal Vortex and Trident 4DWave gameports CONFIG_INPUT_PCIGAME Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2 @@ -14049,6 +14703,11 @@ connected to your computer's serial port. For more information on how to use the driver please read Documentation/joystick.txt +Gravis Stinger gamepad +CONFIG_INPUT_STINGER + Say Y here if you have a Gravis Stinger connected to one of your serial + ports. Gravis has a home page at . + I-Force joysticks/wheels CONFIG_INPUT_IFORCE_232 Say Y here if you have an I-Force joystick or steering wheel @@ -14175,7 +14834,7 @@ interrupt and DMA channel), because you will be asked for it. You want to read the Sound-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . General information + . General information about the modular sound system is contained in the files Documentation/sound/Introduction. The file Documentation/sound/README.OSS contains some slightly outdated but @@ -14183,7 +14842,7 @@ If you have a PnP sound card and you want to configure it at boot time using the ISA PnP tools (read - http://www.roestock.demon.co.uk/isapnptools/ ), then you need to + ), then you need to compile the sound card support as a module ( = code which can be inserted in and removed from the running kernel whenever you want) and load that module after the PnP configuration is finished. To do @@ -14194,7 +14853,7 @@ I'm told that even without a sound card, you can make your computer say more than an occasional beep, by programming the PC speaker. Kernel patches and supporting utilities to do that are in the pcsp - package, available at ftp://ftp.infradead.org/pub/pcsp/ . + package, available at . OSS sound modules CONFIG_SOUND_OSS @@ -14253,6 +14912,8 @@ 16 or Logitech SoundMan 16 sound card. Answer N if you have some other card made by Media Vision or Logitech since those are not PAS16 compatible. Please read Documentation/sound/PAS16. + It is not necessary to add Sound Blaster support separately; it + is included in PAS support. If you compile the driver into the kernel, you have to add "pas2=,,,,,,, @@ -14459,13 +15120,15 @@ See Documentation/sound/CS4232 for more information on configuring this card. -Support for Yamaha OPL3-SA2, SA3, and SAx based PnP cards +Support for Yamaha OPL3-SA2 and SA3 based PnP cards CONFIG_SOUND_OPL3SA2 Say Y or M if you have a card based on one of these Yamaha - sound chipsets. Read Documentation/sound/OPL3-SA2 for more - information on configuring these cards. + sound chipsets or the "SAx", which is actually a SA3. Read + Documentation/sound/OPL3-SA2 for more information on configuring + these cards. - If you compile the driver into the kernel, you have to add + If you compile the driver into the kernel and do not also + configure in the optional ISA PnP support, you will have to add "opl3sa2=,,,,," to the kernel command line. @@ -14578,24 +15241,37 @@ If unsure, say Y. -ACI mixer (miroPCM12/PCM20) +Yamaha PCI native mode support (EXPERIMENTAL) +CONFIG_SOUND_YMFPCI + This is an experimental driver that uses Yamaha PCI sound cards in + the native mode. You may also want to try another driver, + "Yamaha PCI legacy mode support" under the OSS drivers. + +Yamaha PCI legacy mode support +CONFIG_SOUND_YMPCI + This is a driver for Yamaha PCI sound cards that turns them + to the Sound Blaster compatible mode. You don't need to enable + Sound Blaster support to use it. + +ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio) CONFIG_SOUND_ACI_MIXER ACI (Audio Command Interface) is a protocol used to communicate with - the microcontroller on some sound cards produced by miro, e.g. the - miroSOUND PCM12 and PCM20. The main function of the ACI is to - control the mixer and to get a product identification. - - This Voxware ACI driver currently only supports the ACI functions on - the miroSOUND PCM12 and PCM20 cards. On the PCM20, ACI also controls - the radio tuner. This is supported in the video4linux - radio-miropcm20 driver. + the microcontroller on some sound cards produced by miro and Cardinal + Technologies. The main function of the ACI is to control the mixer + and to get a product identification. + + This Voxware ACI driver currently supports the ACI functions on the + miroSOUND PCM1-pro, PCM12 and PCM20 radio. On the PCM20 radio, ACI + also controls the radio tuner. This is supported in the video4linux + miropcm20 driver (say M or Y here and go back to "Multimedia devices" + -> "Radio Adapters"). SB32/AWE support CONFIG_SOUND_AWE32_SYNTH Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or similar sound card. See Documentation/sound/README.awe, Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto for more + available from for more info. Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600) @@ -14647,7 +15323,7 @@ SC-6600 CDROM Interface CONFIG_SC6600_CDROM - This is used to activate the the CDROM interface of the Audio Excel + This is used to activate the CDROM interface of the Audio Excel DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no CDROM present. @@ -14661,6 +15337,11 @@ driver as a module you have to specify the MPU I/O base address with the parameter 'mpu_base=0xNNN'. +C-Media PCI (CMI8338/8378) +CONFIG_SOUND_CMPCI + Say Y or M if you have a PCI sound card using the CMI8338 + or the CMI8378 chip.set. + Creative EMU10K1 based PCI sound cards CONFIG_SOUND_EMU10K1 Say Y or M if you have a PCI sound card using the EMU10K1 @@ -14822,7 +15503,7 @@ conversations while downloading stuff. It only works if your computer is equipped with an ISDN card and both you and your service provider purchased an ISDN line from the phone company. For details, - read http://alumni.caltech.edu/~dank/isdn/ on the WWW. + read on the WWW. This driver allows you to use an ISDN-card for networking connections and as dialin/out device. The isdn-tty's have a built in @@ -15211,7 +15892,7 @@ can be inserted in and removed from the running kernel whenever you want, details in Documentation/modules.txt); the module will be called sc.o. See Documentation/isdn/README.sc and - http://www.spellcast.com for more information. + for more information. Eicon active card support CONFIG_ISDN_DRV_EICON @@ -15221,11 +15902,16 @@ latest isdn4k-utils package. Please read the file Documentation/isdn/README.eicon for more information. +Eicon legacy driver +CONFIG_ISDN_DRV_EICON_OLD + Say Y here to use your Eicon active ISDN card with ISDN4Linux + isdn module. + Eicon Diva Server card support CONFIG_ISDN_DRV_EICON_PCI Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card. Please read Documentation/isdn/README.eicon for more information. - + Eicon old-type card support CONFIG_ISDN_DRV_EICON_ISA Say Y here if you have an old-type Eicon active ISDN card. In order @@ -15235,7 +15921,7 @@ Documentation/isdn/README.eicon for more information. Eicon driver type standalone -CONFIG_ISDN_DRV_EICON_STANDALONE +CONFIG_ISDN_DRV_EICON_DIVAS Enable this option if you want the eicon driver as standalone version with no interface to the ISDN4Linux isdn module. If you say Y here, the eicon module only supports the Diva Server PCI @@ -15254,7 +15940,7 @@ CONFIG_ISDN_CAPI This provides the CAPI (Common ISDN Application Programming Interface, a standard making it easy for programs to access ISDN - hardware, see http://www.capi.org/ . This is needed for AVM's set of + hardware, see . This is needed for AVM's set of active ISDN controllers like B1, T1, M1. This code is also available as a module ( = code which can be @@ -15289,10 +15975,10 @@ Enable support for the AVM T1 T1B card. Note: This is a PRI card and handle 30 B-channels. -AVM C4 support +AVM C4/C2 support CONFIG_ISDN_DRV_AVMB1_C4 - Enable support for the AVM C4 PCI card. - This card handle 4 BRI ISDN lines (8 channels). + Enable support for the AVM C4/C2 PCI cards. + These cards handle 4/2 BRI ISDN lines (8/4 channels). Verbose reason code reporting (kernel size +=7K) CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON @@ -15388,7 +16074,7 @@ CONFIG_SUNOS_EMUL This allows you to run most SunOS binaries. If you want to do this, say Y here and place appropriate files in /usr/gnemul/sunos. See - http://www.ultralinux.org/faq.html for more information. If you want + for more information. If you want to run SunOS binaries on an Ultra you must also say Y to "Kernel support for 32-bit a.out binaries" above. @@ -15425,7 +16111,7 @@ This driver provides support for the build-in sound devices on most Sun machines. If you want to be able to use this, select this option and one or more of the lowlevel drivers below. See - http://www.dementia.org/~shadow/sparcaudio.html for more + for more information. AMD7930 Lowlevel Driver @@ -15465,6 +16151,29 @@ you plan to use this kernel on an Amiga, say Y here and browse the material available in Documentation/m68k; otherwise say N. +Commodore A2232 serial support +CONFIG_A2232 + This option supports the 2232 7-port serial card shipped with Amiga 3000 + and other Zorro-bus machines, dating from 1989. At a max of 19,200 bps, + the ports are served by a 6551 ACIA UART chip each, plus a 8520 CIA, and + a master 6502 CPU and buffer as well. The ports were connected with 8 pin + DIN connectors on the card bracket, for which 8 pin to DB25 adapters were + supplied. The card also had jumpers internally to toggle various pinning + configurations. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + +A4000T SCSI support +CONFIG_A4000T_SCSI + Support for the NCR53C710 SCSI controller on the Amiga 4000T. + +A4091 SCSI support +CONFIG_A4091_SCSI + Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller + (1993). Very obscure -- the 4091 was part of an Amiga 4000 upgrade plan + at the time the Amiga business was sold to DKB. + Atari support CONFIG_ATARI This option enables support for the 68000-based Atari series of @@ -15501,6 +16210,12 @@ If you don't want to compile a kernel for a Sun 3x, say N. +Sun3x builtin serial support +CONFIG_SUN3X_ZS + ZS refers to a type of asynchronous serial port built in to the Sun3 + and Sun3x workstations; if you have a Sun 3, you probably have these. + Say 'Y' to support ZS ports directly. + 68020 support CONFIG_M68020 If you anticipate running this kernel on a computer with a MC68020 @@ -15726,6 +16441,12 @@ If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use one in the near future, say Y to this question. Otherwise, say N. +BSC Oktagon SCSI support +OKTAGON_SCSI + If you have the BSC Oktagon SCSI disk controller for the Amiga, say Y to + this question. If you're in doubt about whether you have one, see the + picture at . + Atari native SCSI support CONFIG_ATARI_SCSI If you have an Atari with built-in NCR5380 SCSI controller (TT, @@ -15746,6 +16467,12 @@ use a Toshiba CD-ROM drive; otherwise, the option is not needed and would impact performance a bit, so say N. +Reset SCSI-devices at boottime +CONFIG_ATARI_SCSI_RESET_BOOT + Reset the devices on your Atari whenever it boots. This makes the boot + process fractionally longer but may assist recovery from errors that + leave the devices with SCSI operations partway completed. + Hades SCSI DMA emulator CONFIG_TT_DMA_EMUL This option enables code which emulates the TT SCSI DMA chip on the @@ -15908,6 +16635,16 @@ If you want to use a GVP IO-Extender serial card in Linux, say Y. Otherwise, say N. +GVP IO-Extender parallel printer support +CONFIG_GVPIOEXT_LP + Say Y to enable driving a printer from the parallel port on your + GVP IO-Extender card, N otherwise + +GVP IO-Extender PLIP support +CONFIG_GVPIOEXT_PLIP + Say Y to enable doing IP over the parallel port on your GVP IO-Extender + card, N otherwise + Multiface Card III serial support CONFIG_MULTIFACE_III_TTY If you want to use a Multiface III card's serial port in Linux, @@ -15981,22 +16718,34 @@ Processor Type CONFIG_6xx There are four types of PowerPC chips supported. The more common - types (601, 603, 604, 740, 750), the Motorola embedded versions - (821, 823, 850, 855, 860), the IBM embedded versions (403 and + types (601, 603, 604, 740, 750, 7400), the Motorola embedded versions + (821, 823, 850, 855, 860, 8260), the IBM embedded versions (403 and 405) and the high end 64 bit Power processors (Power 3, Power 4). - Unless you are building a kernel for one of the embedded - processor systems, or a 64 bit IBM RS/6000, choose 6xx. Note that - the kernel runs in 32-bit mode even on 64-bit chips. + Unless you are building a kernel for one of the embedded processor + systems, or a 64 bit IBM RS/6000, choose 6xx. Note that the kernel + runs in 32-bit mode even on 64-bit chips. + +Workarounds for PPC601 bugs +CONFIG_PPC601_SYNC_FIX + Some versions of the PPC601 (the first PowerPC chip) have bugs which + mean that extra synchronization instructions are required near certain + instructions, typically those that make major changes to the CPU state. + These extra instructions reduce performance slightly. If you say N + here, these extra instructions will not be included, resulting in a + kernel which will run faster but may not run at all on some systems + with the PPC601 chip. + + If in doubt, say Y here. Machine Type -CONFIG_PMAC +CONFIG_ALL_PPC Linux currently supports several different kinds of PowerPC-based machines: Apple Power Macintoshes and clones (such as the Motorola Starmax series), PReP (PowerPC Reference Platform) machines such as - the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP and the - embedded MBX boards from Motorola. Currently, a single kernel binary - only supports one type or the other. However, there is very early - work on support for CHRP, PReP and PowerMac's from a single binary. + the Motorola PowerStack, CHRP (Common Hardware Reference Platform), + the embedded MBX boards from Motorola and many others. Currently, + the default option is to build a kernel which works on the first + three. Support for other machines is currently incomplete. Power management support for PowerBooks CONFIG_PMAC_PBOOK @@ -16006,7 +16755,7 @@ must get the power management daemon, pmud, to make it work and you must have the /dev/pmu device (see the pmud README). - Get pmud from ftp://linuxcare.com.au/pub/ppclinux/pmud/ + Get pmud from . If you have a PowerBook, you should say Y. @@ -16018,7 +16767,7 @@ CONFIG_MOL This option enables low-level support for Mac-on-Linux. MOL lets you run MacOS and Linux simultaneously. Please - visit for more information. + visit <>for more information. If unsure, say Y. ADB raw keycode support @@ -16056,6 +16805,37 @@ an image of the device tree that the kernel copies from Open Firmware. If unsure, say Y here. +RTAS proc interface +CONFIG_PPC_RTAS + When you use this option, you will be able to use RTAS from + userspace. + + RTAS stands for RunTime Abstraction Services and should + provide a portable way to access and set system information. This is + commonly used on RS/6000 (pSeries) computers. + + You can access RTAS via the special proc filesystem entry rtas. + Don't confuse this rtas entry with the one in /proc/device-tree/rtas + which is readonly. + + If you don't know if you can use RTAS look into + /proc/device-tree/rtas. If there are some entries, it is very likely + that you will be able to use RTAS. + + You can do cool things with rtas. To print out information about + various sensors in the system, just do a + + $ cat /proc/rtas/sensors + + or if you power off your machine at night but want it running when + you enter your office at 7:45 am, do a + + # date -d 'tomorrow 7:30' +%s > /proc/rtas/poweron + + and shutdown. + + If unsure, say Y + MESH (Power Mac internal SCSI) support CONFIG_SCSI_MESH Many Power Macintoshes and clones have a MESH (Macintosh Enhanced @@ -16120,16 +16900,6 @@ whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. -Symbios 53c885 (Synergy ethernet) support -CONFIG_NCR885E - This is and Ethernet driver for the dual-function NCR 53C885 - SCSI/Ethernet controller. - - This driver is also available as a module called ncr885e.o ( = code - which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read Documentation/modules.txt. - National DP83902AV (Oak ethernet) support CONFIG_OAKNET Say Y if your machine has this type of Ethernet network card. @@ -16144,11 +16914,11 @@ Support for audio/video capture and overlay devices and FM radio cards. The exact capabilities of each device vary. User tools for this are available from - ftp://ftp.uk.linux.org/pub/linux/video4linux . + . If you are interested in writing a driver for such an audio/video device or user software interacting with such a driver, please read - the file Documentation/video4linux/API.html. + the file Documentation/video4linux/API.html . This driver is also available as a module called videodev.o ( = code which can be inserted in and removed from the running kernel @@ -16180,7 +16950,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . More information + . More information is contained in the file Documentation/video4linux/radiotrack.txt. If you want to compile this driver as a module ( = code which can be @@ -16201,7 +16971,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16221,7 +16991,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16242,10 +17012,10 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . Further documentation on this driver can be found on the WWW at - http://linux.blackhawke.net/cadet.html . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16260,7 +17030,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16279,7 +17049,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16315,7 +17085,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16337,21 +17107,36 @@ say M here and read Documentation/modules.txt. The module will be called i2c-parport.o. -Miro PCM20 Radio +miroSOUND PCM20 radio CONFIG_RADIO_MIROPCM20 Choose Y here if you have this FM radio card. You also need to say Y - to "ACI mixer (miroPCM12/PCM20)" (in "additional low level sound - drivers") for this to work. + to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound") + for this to work. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + . + + If you want 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 miropcm20.o + +Guillemot MAXI Radio FM 2000 Radio Card +CONFIG_RADIO_MAXIRADIO + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want 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 radio-miropcm20.o + called radio-maxiradio.o GemTek Radio Card CONFIG_RADIO_GEMTEK @@ -16361,7 +17146,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16380,7 +17165,7 @@ PlanB is the V4L driver for the PowerMac 7x00/8x00 series video input hardware. If you want to experiment with this, say Y. Otherwise, or if you don't understand a word, say N. - See http://www.cpu.lu/~mlan/planb.html for more info. + See for more info. Saying M will compile this driver as a module (planb.o). @@ -16398,7 +17183,7 @@ In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -16410,13 +17195,6 @@ Fill in the i/o port of your TerraTec FM radio card. If unsure, go with the default. -### Add these -# Zoran ZR36057/36060 support -# CONFIG_VIDEO_ZORAN - -# Include support for Iomega Buz -# CONFIG_VIDEO_BUZ - Trust FM radio card CONFIG_RADIO_TRUST This is a driver for the Trust FM radio cards. Say Y if you have @@ -16446,6 +17224,22 @@ whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +Stradis 4:2:2 MPEG-2 video driver +CONFIG_VIDEO_STRADIS + Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video driver + for PCI. There is a product page at . + +Zoran ZR36057/36060 Video For Linux +CONFIG_VIDEO_ZORAN + Say Y here to include support for video cards based on the the Zoran + ZR36057/36060 encoder/decoder chip (including the Iomega Buz and the + Miro DC10 and DC30 video capture cards). + +Include support for Iomega Buz +CONFIG_VIDEO_BUZ + Say Y here to include support for the Iomega Buz video card. There is + a Buz/Linux homepage at . + ZR36120/36125 Video for Linux CONFIG_VIDEO_ZR36120 Support for ZR36120/ZR36125 based frame grabber/overlay boards. @@ -16486,6 +17280,17 @@ monochrome Quickcam, Quickcam VC or QuickClip. It is also available as a module (c-qcam.o). Read Documentation/video4linux/CQcam.txt for more information. + +Winbond W9966CF Webcam Video For Linux +CONFIG_VIDEO_W9966 + Video4linux driver for Winbond's w9966 based Webcams. + Currently tested with the LifeView FlyCam Supra. + If you have one of these cameras, say Y here + otherwise say N. + This driver is also available as a module (w9966.o) + + Checkout Documentation/video4linux/w9966.txt and w9966.c + for more information. CPiA Video For Linux CONFIG_VIDEO_CPIA @@ -16523,6 +17328,96 @@ from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +IBM's S/390 architecture +CONFIG_ARCH_S390 + Select this option, if you want to run the Kernel on one of IBM's + mainframes of the S/390 generation. You should have installed the + s390-compiler released by IBM (based on gcc-2.95.1) before. + +Merge some code into the kernel to make the image IPLable +CONFIG_IPLABLE + If you want to use the produced kernel to IPL directly from a + device, you have to merge a bootsector specific to the device + into the first bytes of the kernel. You will have to select the + IPL device on another question, that pops up, when you select + CONFIG_IPLABE. + +IPL from a /390 tape unit +CONFIG_IPL_TAPE + Select this option if you want to IPL the image from a Tape. + +IPL from a virtual card reader emulated by VM/ESA +CONFIG_IPL_RDR_VM + Select this option if you are running under VM/ESA and want + to IPL the image from the emulated card reader. + +IPL from a real card reader +CONFIG_IPL_RDR + Select this option if you want to IPL the image from a real + card reader. Maybe you still got one and want to try. We didn't + test. + +IBMs S/390 Harddisks (DASDs) +CONFIG_DASD + Enable this option if you want to access DASDs directly utilizing + S/390s channel subsystem commands. This is necessary for running + natively on a single image or an LPAR. + +Enable DASD fast write +CONFIG_DASD_FAST_IO + Enable fast I/O for DASDs. That means that the next I/O command + is already issued at interrupt time, if an I/O request is pending. + This option gives significant speedup of I/O, because we don't + schedule the bottom-halves as often as Intel. + +Support for IBM-style disk-labels (S/390) +CONFIG_S390_PARTITION + Enable this option to assure standard IBM labels on the DASDs. + You must enable it, if you are planning to access DASDs also + attached to another IBM mainframe operation system (OS/390, + VM/ESA, VSE/ESA). + +ECKD devices +CONFIG_DASD_ECKD + ECKD devices are the most commonly used devices. you should enable + this option unless you are very sure to have no ECKD device. + +CKD devices +CONFIG_DASD_CKD + CKD devices are currently unsupported. + +FBA devices +CONFIG_DASD_FBA + FBA devices are currently unsupported. + +Support for 3215 line mode terminal +CONFIG_3215 + Include support for IBM 3215 line-mode terminals. Can't be used + if 3270 support is compiled in statically. + +Support for console on 3215 line mode terminal +CONFIG_3215_CONSOLE + Include support for using an IBM 3215 line-mode terminal as the Linux + system console. Can't be used if 3270 support is compiled in statically. + +Support for 3270 line mode terminal +CONFIG_3270 + Include support for IBM 3270 line-mode terminals. + +Support for console on 3270 line mode terminal +CONFIG_3270_CONSOLE + Include support for using an IBM 3270 line-mode terminal as the Linux + system console. Excludes using 3215s. + +Support for HWC line mode terminal +CONFIG_HWC + Include support for IBM HWC line-mode terminals. + +Support for console on HWC line mode terminal +CONFIG_HWC_CONSOLE + Include support for using an IBM HWC line-mode terminal as the Linux + system console. + SAB3036 tuner support CONFIG_TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. @@ -16559,7 +17454,7 @@ Saying N will reduce the size of the Footbridge kernel. Include support for the EBSA285 -CONFIG_ARCH_EBSA285 +CONFIG_ARCH_EBSA285_HOST Say Y here if you intend to run this kernel on the EBSA285 card in host ("central function") mode. @@ -16571,7 +17466,7 @@ L7200 Software Development Board which uses an ARM720T processor. Information on this board can be obtained at: - http://www.linkupsys.com/ + If you have any questions or comments about the Linux kernel port to this board, send e-mail to sjhill@cotw.com @@ -16581,7 +17476,7 @@ Say Y here if you intend to run this kernel on the Rebel.COM NetWinder. Information about this machine can be found at: - http://www.netwinder.org/ + Saying N will reduce the size of the Footbridge kernel. @@ -16596,8 +17491,8 @@ There are no product plans beyond the current research prototypes at this time. Information is available at: - http://crl.research.compaq.com/projects/personalserver - + + If you have any questions or comments about the Compaq Personal Server, send e-mail to skiff@crl.dec.com @@ -16618,8 +17513,8 @@ H3600 handheld computer. Information about this machine and the Linux port to this machine can be found at: - http://www.handhelds.org/Compaq/index.html#iPAQ_H3600 - http://www.compaq.com/products/handhelds/pocketpc/ + + Include support for Brutus CONFIG_SA1100_BRUTUS @@ -16629,66 +17524,30 @@ Include support for LART CONFIG_SA1100_LART Say Y here if you are using the Linux Advanced Radio Terminal - (also known as the LART). See http://www.lart.tudelft.nl/ for + (also known as the LART). See for information on the LART. Include support for GraphicsClient CONFIG_SA1100_GRAPHICSCLIENT Say Y here if you are using an Applied Data Systems Intel(R) StrongARM(R) SA-1100 based Graphics Client SBC. See - http://www.flatpanels.com/ for information on this system. + for information on this system. Include support for Victor CONFIG_SA1100_VICTOR Say Y here if you are using a Visu Aide Intel(R) StrongARM(R) SA-1100 based Victor Digital Talking Book Reader. See - http://www.visuaide.com/pagevictor.en.html for information on + for information on this system. -Support ARM610 processor -CONFIG_CPU_ARM6 - Say Y here if you wish to include support for the ARM610 processor. - -Support ARM710 processor -CONFIG_CPU_ARM7 - Say Y here if you wish to include support for the ARM710 processor. - -Support StrongARM(R) SA-110 processor -CONFIG_CPU_SA110 - Say Y here if you wish to include support for the Intel(R) - StrongARM(R) SA-110 processor. - -Support ARM720 processor -CONFIG_CPU_ARM720 - Say Y here if you wish to include support for the ARM720 processor. - -Support ARM920 -CONFIG_CPU_ARM920 - Say Y here if you wish to include support for the ARM920 processor. - -Support ARM610 processor -CONFIG_CPU_ARM6 - Say Y here if you wish to include support for the ARM610 processor. - -Support ARM710 processor -CONFIG_CPU_ARM7 - Say Y here if you wish to include support for the ARM710 processor. - -Support StrongARM(R) SA-110 processor -CONFIG_CPU_SA110 - Say Y here if you wish to include support for the Intel(R) - StrongARM(R) SA-110 processor. - -Support ARM720 processor -CONFIG_CPU_ARM720 - Say Y here if you wish to include support for the ARM720 processor. - -Support ARM920 -CONFIG_CPU_ARM920 - Say Y here if you wish to include support for the ARM920 processor. +Load kernel using Angel Debug Monitor +CONFIG_ANGELBOOT + Say Y if you plan to load the kernel using Angel, ARM Ltd's target + debug stub. If you are not using Angel, you must say N. It is + important to get this setting correct. Math emulation -CONFIG_NWFPE +CONFIG_FPE_NWFPE Say Y to include the NWFPE floating point emulator in the kernel. This is necessary to run most binaries. Linux does not currently support floating point hardware so you need to say Y here even if @@ -16702,6 +17561,23 @@ You may say N here if you are going to load the Acorn FPEmulator early in the bootup. +CONFIG_FPE_FASTFPE + Say Y here to include the FAST floating point emulator in the kernel. + This is an experimental much faster emulator which has only 32 bit + precision for the mantissa. It does not support any exceptions. This + makes it very simple, it is approximately 4-8 times faster than NWFPE. + + It should be sufficient for most programs. It is definitely not + suitable if you do scientific calculations that need double precision + for iteration formulas that sum up lots of very small numbers. If you + do not feel you need a faster FP emulation you should better choose + NWFPE. + + It is also possible to say M to build the emulator as a module + (fastfpe.o). But keep in mind that you should only load the FP emulator + early in the bootup. You should never change from NWFPE to FASTFPE or + vice versa in an active system! + DS1620 Thermometer support CONFIG_DS1620 Say Y here to include support for the thermal management hardware @@ -16721,11 +17597,12 @@ you are concerned with the code size or don't want to see these messages. -Compile kernel with frame pointer -CONFIG_FRAME_POINTER - If you say Y here, the resulting kernel will be slightly larger and - slower, but it will give useful debugging information. If you don't - debug the kernel, you can say N. +Compile kernel without frame pointer +CONFIG_NO_FRAME_POINTER + If you say Y here, the resulting kernel will be slightly smaller and + faster. However, when a problem occurs with the kernel, the + information that is reported is severely limited. Most people + should say N here. User fault debugging CONFIG_DEBUG_USER @@ -16833,6 +17710,21 @@ you can make the first serial port the console by answering Y to this option. +L7200 SDB keyboard support +CONFIG_KEYBOARD_L7200 + Enable this option if you would like to be able to use a keyboard + on a LinkUp Systems L7200 board. + +L7200 SDB Fujitsu keyboard support +CONFIG_KEYBOARD_L7200_NORM + Select the Fujitsu keyboard if you want a normal QWERTY style + keyboard on the LinkUp SDB. + +L7200 SDB Prototype keyboard support +CONFIG_KEYBOARD_L7200_DEMO + Select the prototype keyboard if you want to play with the + LCD/keyboard combination on the LinkUp SDB. + Footbridge Mode CONFIG_HOST_FOOTBRIDGE The 21285 Footbridge chip can operate in either `host mode' or @@ -16903,15 +17795,23 @@ infrared communication and is supported by most laptops and PDA's. To use Linux support for the IrDA (tm) protocols, you will also need - some user-space utilities like the irmanager and probably irattach - as well. For more information, see the file + some user-space utilities like irattach. For more information, see the file Documentation/networking/irda.txt. You also want to read the - IR-HOWTO, available at http://www.linuxdoc.org/docs.html#howto . + IR-HOWTO, available at . This support is also available as a module called irda.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Ultra (connectionless) protocol +CONFIG_IRDA_ULTRA + Say Y here to support the connectionless Ultra IRDA protocol, also + called IrOBEX. + +IrDA protocol options +CONFIG_IRDA_OPTIONS + Say Y here if you want to configure any of the following IrDA options. + IrDA Cache last LSAP CONFIG_IRDA_CACHE_LAST_LSAP Say Y here if you want IrLMP to cache the last LSAP used. This makes @@ -16976,6 +17876,17 @@ to another Linux machine running the IrLAN protocol for ad-hoc networking! +IrNET Protocol +CONFIG_IRNET + Say Y here if you want to build support for the IrNET protocol. If + you want to compile it as a module (irnet.o), say M here and read + Documentation/modules.txt. IrNET is a PPP driver, so you will also + need a working PPP subsystem (driver, daemon and config)... + + IrNET is an alternate way to tranfer TCP/IP traffic over IrDA. It + uses synchronous PPP over a set of point to point IrDA sockets. You + can use it between Linux machine or with W2k. + IrCOMM Protocol CONFIG_IRCOMM Say Y here if you want to build support for the IrCOMM protocol. If @@ -17014,6 +17925,19 @@ If unsure, say Y. +USB IrDA FIR Dongle Device Driver +CONFIG_USB_IRDA + Say Y here if you want to build support for the USB IrDA FIR Dongle + device driver. If you want to compile it as a module (irda-usb.o), + say M here and read Documentation/modules.txt. IrDA-USB support the + various IrDA USB dongles available and most of their pecularities. + Those dongles plug in the USB port of your computer, are plug and + play, and support SIR and FIR (4Mbps) speeds. On the other hand, + those dongles tend to be less efficient than a FIR chipset. + + Please note that the driver is still experimental. And of course, + you will need both USB and IrDA support in your kernel... + Winbond W83977AF IrDA Device Driver CONFIG_WINBOND_FIR Say Y here if you want to build IrDA support for the Winbond @@ -17219,6 +18143,390 @@ another UltraSPARC-IIi-cEngine boardset with hardware watchdog, you should say N to this option. +ETRAX Memory configuration +CONFIG_ETRAX_DRAM_SIZE + Size of DRAM (decimal in MB) typically 2, 8 or 16. + +LED configuration +CONFIG_ETRAX_PA_LEDS + The Etrax network driver is responsible for flashing LED's when + packets arrive and are sent. It uses macros defined in asm/io.h, + and those macros are defined after what YOU choose in this option. + The actual bits used are configured separately. + Some products put the leds on a memory-mapped latch instead. This + is mapped at 0x90000000. + +LED bit configuration +CONFIG_ETRAX_LED1G + Bit to use for the first green LED. + Most Axis products use bit 2 here. + +LED bit configuration +CONFIG_ETRAX_LED1R + Bit to use for the first red LED. + Most Axis products use bit 3 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +LED bit configuration +CONFIG_ETRAX_LED2G + Bit to use for the second green LED. The "Active" LED. + Most Axis products use bit 4 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +LED bit configuration +CONFIG_ETRAX_LED2R + Bit to use for the second red LED. + Most Axis products use bit 5 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +LED bit configuration +CONFIG_ETRAX_LED3G + Bit to use for the third green LED. The "Drive" LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +LED bit configuration +CONFIG_ETRAX_LED3R + Bit to use for the third red LED. + For products with only one ortwo controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Flash LED off during activity +CONFIG_ETRAX_LED_OFF_DURING_ACTIVITY + This option allows you to decide whether the network LED (and + Bluetooth LED in case you use Bluetooth) will be on or off when + the network is connected, and whether it should flash off or on + when there is activity. If you say y to this option the network + LED will be lit when there is a connection, and will flash off + when there is activity. + +Button configuration +CONFIG_ETRAX_PA_BUTTON_BITMASK + This is a bitmask with information about what bits on PA that + are used for buttons. + Most products has a so called TEST button on PA1, if that's true + use 02 here. + Use 00 if there are no buttons on PA. + If the bitmask is <> 00 a button driver will be included in the gpio + driver. Etrax general I/O support must be enabled. + +PA changeable direction bits +CONFIG_ETRAX_PA_CHANGEABLE_DIR + This is a bitmask with information of what bits in PA that a user + can change direction on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +PA changeable data bits +CONFIG_ETRAX_PA_CHANGEABLE_BITS + This is a bitmask with information of what bits in PA that a user + can change change the value on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +PA changeable direction bits +CONFIG_ETRAX_PB_CHANGEABLE_DIR + This is a bitmask with information of what bits in PB that a user + can change direction on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +CONFIG_ETRAX_PB_CHANGEABLE_BITS + This is a bitmask with information of what bits in PB that a user + can change the value on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +Kernel debugger (kgdb) +CONFIG_ETRAX_KGDB + The CRIS version of gdb can be used to remotely debug a running Linux + kernel via the serial debug port. Provided you have gdb-cris installed, + run gdb-cris vmlinux, then type + (gdb) set remotebaud 115200 <- kgdb uses 115200 as default + (gdb) target remote /dev/ttyS0 <- maybe you use another port + This should connect you to your booted kernel (or boot it now if you + didn't before). The kernel halts when it boots, waiting for gdb if + this option is turned on! + +Etrax bus waitstates +CONFIG_ETRAX_DEF_R_WAITSTATES + Waitstates for SRAM, Flash and peripherials (not DRAM). 95f8 is a + good choice for most Axis products... + +Etrax bus configuration +CONFIG_ETRAX_DEF_R_BUS_CONFIG + Assorted bits controlling write mode, DMA burst length etc. 104 is a + good choice for most Axis products... + +Etrax DRAM configuration +CONFIG_ETRAX_DEF_R_DRAM_CONFIG + The R_DRAM_CONFIG register specifies everything on how the DRAM chips + in the system are connected to the Etrax CPU. This is different + depending on the manufacturer, chip type and number of chips. + So this value often needs to be different for each Axis + product. + +Etrax DRAM timing +CONFIG_ETRAX_DEF_R_DRAM_TIMING + Different DRAM chips have different speeds. Current Axis products use + 50ns DRAM chips which can use the timing: 5611. + +Etrax SDRAM configuration +CONFIG_ETRAX_DEF_R_SDRAM_CONFIG + The R_SDRAM_CONFIG register specifies everything on how the SDRAM chips + in the system are connected to the Etrax CPU. This is different + depending on the manufacturer, chip type and number of chips. + So this value often needs to be different for each Axis + product. + +Etrax SDRAM timing +CONFIG_ETRAX_DEF_R_SDRAM_TIMING + Different SDRAM chips have different timing. + +Etrax General port A direction +CONFIG_ETRAX_DEF_R_PORT_PA_DIR + Configures the direction of general port A bits. 1 is out, 0 is in. + This is often totally different depending on the product used. There + are some guidelines though - if you know that only LED's are connected + to port PA, then they are usually connected to bits 2-4 and you can + therefore use 1c. On other boards which don't have the LED's + at the general ports, these bits are used for all kinds of stuff. + If you don't know what to use, it is always safe to put all as inputs, + although floating inputs isn't good. + +Etrax General port A data +CONFIG_ETRAX_DEF_R_PORT_PA_DATA + Configures the initial data for the general port A bits. Most products + should use 00 here. + +Etrax General port B config +CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG + Configures the type of the general port B bits. 1 is chip select, + 0 is port. Most products should use 00 here. + +Etrax General port B direction +CONFIG_ETRAX_DEF_R_PORT_PB_DIR + Configures the direction of general port B bits. 1 is out, 0 is in. + This is often totally different depending on the product used. Bits + 0 and 1 on port PB are usually used for I2C communication, but the + kernel I2C driver sets the appropriate directions itself so you don't + need to take that into consideration when setting this option. + If you don't know what to use, it is always safe to put all as inputs. + +Etrax General port B data +CONFIG_ETRAX_DEF_R_PORT_PB_DATA + Configures the initial data for the general port A bits. Most products + should use FF here. + +Etrax General port device +CONFIG_ETRAX_GPIO + Enables the Etrax general port device (major 120, minors 0 and 1). + You can use this driver to access the general port bits. It supports + these ioctl's: + #include + fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob + ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set); + ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear); + val = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS), NULL); + Remember that you need to setup the port directions appropriately in + the General configuration. + +Etrax parallel data support +CONFIG_ETRAX_PARDATA + Adds support for writing data to the parallel port par0 of the ETRAX 100. + If you create a character special file with major number 126, you can + write to the data bits of par0. + Note: you need to disable Etrax100 parallel port support. + +Etrax parallel LCD (HD44780) Driver +CONFIG_ETRAX_LCD_HD44780 + Adds support for a HD44780 controlled LCD connected to the parallel + port par0 of the Etrax. + +Etrax Serial port ser0 support +CONFIG_ETRAX_SERIAL + Enables the ETRAX 100 serial driver for ser0 (ttyS0) + You probably want this enabled. + +/proc/serial entry +CONFIG_ETRAX_SERIAL_PROC_ENTRY + Enables /proc/serial entry where errors and statistics can be viewed. + CONFIG_PROC_FS must also be set for this to work. + +Etrax Serial port fast flush of DMA using fast timer API +CONFIG_ETRAX_SERIAL_FAST_TIMER + Select this to have the serial DMAs flushed at a higher rate than normally, + possible by using the fast timer API, the timeout is approx. 4 character + times. + If unsure, say N. + +Etrax Serial port fast flush of DMA +CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + Select this to have the serial DMAs flushed at a higher rate than normally + possible through a fast timer interrupt (currently at 15360 Hz). + If unsure, say N. + +Etrax Serial port receive flush timeout +CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS + Number of timer ticks between flush of receive fifo (1 tick = 10ms). + Try 0-3 for low latency applications. Approx 5 for high load + applications (e.g. PPP). Maybe this should be more adaptive some day... + +Etrax Serial port ser0 DTR, RI, DSR and CD support on PB +CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB + Enables the status and control signals DTR, RI, DSR and CD on PB for ser0 + +Etrax Serial port ser1 support +CONFIG_ETRAX_SERIAL_PORT1 + Enables the ETRAX 100 serial driver for ser1 (ttyS1) + +Etrax Serial port ser1 DTR, RI, DSR and CD support on PB +CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB + Enables the status and control signals DTR, RI, DSR and CD on PB for ser1 + + +Etrax Serial port ser2 support +CONFIG_ETRAX_SERIAL_PORT2 + Enables the ETRAX 100 serial driver for ser2 (ttyS2) + +Etrax Serial port ser2 DTR, RI, DSR and CD support on PA +CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA + Enables the status and control signals DTR, RI, DSR and CD on PA for ser + +Etrax100 Serial port ser3 support +CONFIG_ETRAX_SERIAL_PORT3 + Enables the ETRAX 100 serial driver for ser3 (ttyS3) + +Etrax100 RS-485 Support +CONFIG_ETRAX_RS485 + Enables support for RS-485 serial communication + +Etrax100 RS-485 mode on PA +CONFIG_ETRAX_RS485_ON_PA + Control Driver Output Eanble on RS485 tranceiver using a pin on PA port: + Axis 2400/2401 uses PA 3. + +Etrax100 RS-485 disable receiver +CONFIG_ETRAX_RS485_DISABLE_RECEIVER + It's necessary to disable the serial receiver to avoid serial loopback. + Not all products are able to do this in software only. Axis 2400/2401 + must disable receiver. + +Etrax100 I2C Support +CONFIG_ETRAX_I2C + Enables an I2C driver on PB0 and PB1 on ETRAX100. + EXAMPLE usage: + i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); + ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); + i2c_arg = I2C_READARG(STA013_READ_ADDR, reg); + val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg); + +Etrax100 I2C EEPROM (NVRAM) support +CONFIG_ETRAX_I2C_EEPROM + Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C driver. + +Etrax100 I2C EEPROM (NVRAM) size/probe +CONFIG_ETRAX_I2C_EEPROM_PROBE + Specifies size or auto probe of the EEPROM size. + Options: Probed, 2k, 8k, 16k + (Probing works for 2k and 8k but no that well for 16k) + +Etrax DS1302 RTC driver +CONFIG_ETRAX_DS1302 + Enables the driver for the DS1302 Real-Time Clock battery-backed + chip on some products. The kernel reads the time when booting, and + the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a + rtc_time struct (see asm/rtc.h) on the /dev/rtc device, major 121. + You can check the time with cat /proc/rtc, but normal time reading + should be done using libc function time and friends. + +Etrax DS1302 RST on the Generic Port +CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + If your product has the RST signal line for the DS1302 RTC on the + Generic Port then say Y here, otherwise leave it as N in which + case the RST signal line is assumed to be connected to Port PB + (just like the SCL and SDA lines). + +Etrax DS1302 RST bit number +CONFIG_ETRAX_DS1302_RSTBIT + This is the bit number for the RST signal line of the DS1302 RTC on + the selected port. If you have selected the generic port then it + should be bit 27, otherwise your best bet is bit 5. + +Etrax DS1302 SCL bit number +CONFIG_ETRAX_DS1302_SCLBIT + This is the bit number for the SCL signal line of the DS1302 RTC on + Port PB. This is probably best left at 3. + +Etrax DS1302 SDA bit number +CONFIG_ETRAX_DS1302_SDABIT + This is the bit number for the SDA signal line of the DS1302 RTC on + Port PB. This is probably best left at 2. + +Etrax 100 IDE Reset +CONFIG_ETRAX_IDE_PB7_RESET + Configures the pin used to reset the IDE bus. + +ETRAX 100LX USB 1.1 Host +CONFIG_ETRAX_USB_HOST + This option enables the host functionality of the ETRAX 100LX + built-in USB controller. In host mode the controller is designed + for CTRL and BULK traffic only, INTR traffic may work as well + however (depending on the requirements of timeliness). + +ETRAX 100LX USB 1.1 Host port 1 enable +CONFIG_ETRAX_USB_HOST_PORT1 + This option enables port 1 of the ETRAX 100LX USB root hub (RH). + +ETRAX 100LX USB 1.1 Host port 2 enable +CONFIG_ETRAX_USB_HOST_PORT2 + This option enables port 2 of the ETRAX 100LX USB root hub (RH). + +ETRAX 100LX 10/100Mbit Ethernet controller +CONFIG_ETRAX_ETHERNET + This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet + controller. + +ETRAX 100LX Synchronous serial ports +CONFIG_ETRAX_SYNCHRONOUS_SERIAL + This option enables support for the ETRAX 100LX built-in + synchronous serial ports. These ports are used for continuous + streamed data like audio. The default setting is compatible + with the STA 013 MP3 decoder, but can easily be tuned to fit + any other audio encoder/decoder and SPI. + +ETRAX 100LX Synchronous serial port 0 enabled +CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0 + Enables the ETRAX 100LX synchronous serial port 0 (syncser0). + +ETRAX 100LX Synchronous serial port 0 uses DMA +CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA + Makes synchronous serial port 0 use DMA. + +ETRAX 100LX Synchronous serial port 1 enabled +CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1 + Enables the ETRAX 100LX synchronous serial port 1 (syncser1). + +ETRAX 100LX Synchronous serial port 1 uses DMA +CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA + Makes synchronous serial port 1 use DMA. + +MTD flash map support +CONFIG_ETRAX_AXISFLASHMAP + This option enables MTD mapping of flash devices. Needed to + use flash memories. If unsure, say yes. + +Ptable sector offset +CONFIG_ETRAX_PTABLE_SECTOR + Byte-offset of the partition table in the first flash chip. + The default value is 64kB and should not be changed unless + you know exactly what you are doing. The only valid reason + for changing this is when the flash block size is bigger + than 64kB (e.g. when using two parallel 16 bit flashes). + IA-64 system type CONFIG_IA64_GENERIC This selects the system type of your hardware. A "generic" kernel @@ -17226,11 +18534,11 @@ a kernel for your specific system, it will be faster and smaller. To find out what type of IA-64 system you have, you may want to - check the IA-64 Linux web site at http://www.linux-ia64.org/. + check the IA-64 Linux web site at . As of the time of this writing, most hardware is DIG compliant, so the "DIG-compliant" option is usually the right choice. - HP-simulator For the HP simulator (http://software.hp.com/ia64linux/). + HP-simulator For the HP simulator (). SN1-simulator For the SGI SN1 simulator. DIG-compliant For DIG ("Developer's Interface Guide") compliant system. @@ -17293,17 +18601,6 @@ Say Y here to enable hacks to make the kernel work on the NEC AzusA platform. Select N here if you're unsure. -Force socket buffers below 4GB? -CONFIG_SKB_BELOW_4GB - Most of today's network interface cards (NICs) support DMA to - the low 32 bits of the address space only. On machines with - more then 4GB of memory, this can cause the system to slow - down if there is no I/O TLB hardware. Turning this option on - avoids the slow-down by forcing socket buffers to be allocated - from memory below 4GB. The downside is that your system could - run out of memory below 4GB before all memory has been used up. - If you're unsure how to answer this question, answer Y. - Enable IA-64 Machine Check Abort CONFIG_IA64_MCA Say Y here to enable machine check support for IA-64. If you're @@ -17324,7 +18621,47 @@ and the PAL firmware version in use. To use this option, you have to check that the "/proc file system - support" (CONFIG_PROC_FS) is enabled, too. + support" (CONFIG_PROC_FS) is enabled too. + +Directly Connected Compact Flash support +CONFIG_CF_ENABLER + Compact Flash is a small, removable mass storage device introduced + in 1994 originally as a PCMCIA device. If you say `Y' here, you + compile in support for Compact Flash devices directly connected to + a SuperH processor. A Compact Flash FAQ is available at + . + +Kernel debugging +CONFIG_DEBUG_KERNEL + Say Y here if you are developing drivers or trying to debug and identify + kernel problems. + +Debug memory allocations +CONFIG_DEBUG_SLAB + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. + +Memory mapped I/O debug support +CONFIG_DEBUG_IOVIRT + Say Y here to get warned whenever an attempt is made to do I/O on + obviously invalid addresses such as those generated when ioremap() + calls are forgotten. Memory mapped I/O will go through an extra check to + catch access to unmapped ISA addresses, an access method that can still + be used by old drivers that are being ported from 2.0/2.2. + +Spinlock debugging +CONFIG_DEBUG_SPINLOCK + Say Y here and build SMP to catch missing spinlock initialisation and + certain other kinds of spinlock errors commonly made. This is best used + in conjunction with the NMI watchdog so that spinlock deadlocks are also + debuggable + +Verbose BUG() reporting (adds 70K) +CONFIG_DEBUG_BUGVERBOSE + Say Y here to make BUG() panics output the file name and line number of + the BUG call as well as the EIP and oops trace. This aids debugging but + costs about 70-100K of memory. # # A couple of things I keep forgetting: @@ -17348,9 +18685,9 @@ # LocalWords: netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP # LocalWords: genksyms INET loopback gatewaying ethernet PPP ARP Arp MEMSIZE # LocalWords: howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip -# LocalWords: proc acct IPIP encapsulator decapsulator klogd PCTCP RARP EXT PS +# LocalWords: proc acct IPIP encapsulator decapsulator klogd RARP EXT PS # LocalWords: telnetting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl -# LocalWords: Mb SKB IPX Novell dosemu Appletalk DDP ATALK vmalloc visar ehome +# LocalWords: Mb SKB IPX Novell dosemu DDP ATALK vmalloc visar ehome # LocalWords: SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA # LocalWords: buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext # LocalWords: QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES @@ -17378,7 +18715,7 @@ # LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem # LocalWords: carleton DECstation SUNFD JENSEN Noname XXXM SLiRP LILO's amifb # LocalWords: pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd -# LocalWords: RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff +# LocalWords: RTNETLINK mknod xos MTU lwared Macs netatalk macs cs Wolff # LocalWords: dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress # LocalWords: ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache httpd sjc dlp # LocalWords: thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ MG HIPPI cern @@ -17395,7 +18732,7 @@ # LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT # LocalWords: OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP # LocalWords: NOWAYOUT behaviour dialin isdn callback BTX Teles XXXX LVM lvm -ICN EDSS Cisco +# LocalWords: ICN EDSS Cisco # LocalWords: ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr # LocalWords: ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD # LocalWords: initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS @@ -17522,7 +18859,7 @@ # LocalWords: AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA # LocalWords: swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs # LocalWords: CyberVision Cirrus PowerBooks Topcat SBUS CGsix TurboGX BWtwo SS -# LocalWords: CGthree TCX unswapable vfb fbcon hicolor truecolor AFB ILBM SOC +# LocalWords: CGthree TCX unswappable vfb fbcon hicolor truecolor AFB ILBM SOC # LocalWords: IPLAN gracilis Fibre SBus SparcSTORAGE SV jnewbigin swin QNX qnx # LocalWords: PTY PTYS ptyxx ttyxx PTYs ssh sb Avance ALS pss pvv kerneli hd # LocalWords: synth WaveFront MSND NONPNP AudioExcelDSP STRAM APUS CHRP MBX Nx diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DMA-mapping.txt linux.ac/Documentation/DMA-mapping.txt --- linux.vanilla/Documentation/DMA-mapping.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/DMA-mapping.txt Thu Apr 19 22:36:04 2001 @@ -32,6 +32,35 @@ the dma_addr_t type which should be used everywhere you hold a DMA (bus) address returned from the DMA mapping functions. + What memory is DMA'able? + +The first piece of information you must know is what kernel memory can +be used with the DMA mapping facilitites. There has been an unwritten +set of rules regarding this, and this text is an attempt to finally +write them down. + +If you acquired your memory via the page allocator +(i.e. __get_free_page*()) or the generic memory allocators +(i.e. kmalloc() or kmem_cache_alloc()) then you may DMA to/from +that memory using the addresses returned from those routines. + +This means specifically that you may _not_ use the memory/addresses +returned from vmalloc() for DMA. It is possible to DMA to the +_underlying_ memory mapped into a vmalloc() area, but this requires +walking page tables to get the physical addresses, and then +translating each of those pages back to a kernel address using +something like __va(). + +This rule also means that you may not use kernel image addresses +(ie. items in the kernel's data/text/bss segment, or your driver's) +nor may you use kernel stack addresses for DMA. Both of these items +might be mapped somewhere entirely different than the rest of physical +memory. + +What about block I/O and networking buffers? The block I/O and +networking subsystems make sure that the buffers they use are valid +for you to DMA from/to. + DMA addressing limitations Does your device have any DMA addressing limitations? For example, is @@ -168,16 +197,21 @@ optimizations the hardware allows. To this end, when using such mappings you must be explicit about what you want to happen. +Neither type of DMA mapping has alignment restrictions that come +from PCI, although some devices may have such restrictions. + Using Consistent DMA mappings. -To allocate and map a consistent DMA region, you should do: +To allocate and map large (PAGE_SIZE or so) consistent DMA regions, +you should do: dma_addr_t dma_handle; cpu_addr = pci_alloc_consistent(dev, size, &dma_handle); where dev is a struct pci_dev *. You should pass NULL for PCI like buses -where devices don't have struct pci_dev (like ISA, EISA). +where devices don't have struct pci_dev (like ISA, EISA). This may be +called in interrupt context. This argument is needed because the DMA translations may be bus specific (and often is private to the bus which the device is attached @@ -186,7 +220,9 @@ Size is the length of the region you want to allocate. This routine will allocate RAM for that region, so it acts similarly to -__get_free_pages (but takes size instead of a page order). +__get_free_pages (but takes size instead of a page order). If your +driver needs regions sized smaller than a page, you may prefer using +the pci_pool interface, described below. It returns two values: the virtual address which you can use to access it from the CPU and dma_handle which you pass to the card. @@ -205,6 +241,51 @@ where dev, size are the same as in the above call and cpu_addr and dma_handle are the values pci_alloc_consistent returned to you. +If your driver needs lots of smaller memory regions, you can write +custom code to subdivide pages returned by pci_alloc_consistent, +or you can use the pci_pool API to do that. A pci_pool is like +a kmem_cache, but it uses pci_alloc_consistent not __get_free_pages. +Also, it understands common hardware constraints for alignment, +like queue heads needing to be aligned on N byte boundaries. + +Create a pci_pool like this: + + struct pci_pool *pool; + + pool = pci_pool_create(name, dev, size, align, alloc, flags); + +The "name" is for diagnostics (like a kmem_cache name); dev and size +are as above. The device's hardware alignment requirement for this +type of data is "align" (a power of two). The flags are SLAB_ flags +as you'd pass to kmem_cache_create. Not all flags are understood, but +SLAB_POISON may help you find driver bugs. If you call this in a non- +sleeping context (f.e. in_interrupt is true or while holding SMP +locks), pass SLAB_ATOMIC. If your device has no boundary crossing +restrictions, pass 0 for alloc; passing 4096 says memory allocated +from this pool must not cross 4KByte boundaries. + +Allocate memory from a pci pool like this: + + cpu_addr = pci_pool_alloc(pool, flags, &dma_handle); + +flags are SLAB_KERNEL if blocking is permitted (not in_interrupt nor +holding SMP locks), SLAB_ATOMIC otherwise. Like pci_alloc_consistent, +this returns two values, cpu_addr and dma_handle, + +Free memory that was allocated from a pci_pool like this: + + pci_pool_free(pool, cpu_addr, dma_handle); + +where pool is what you passed to pci_pool_alloc, and cpu_addr and +dma_handle are the values pci_pool_alloc returned. + +Destroy a pci_pool by calling: + + pci_pool_destroy(pool); + +Make sure you've called pci_pool_free for all memory allocated +from a pool before you destroy the pool. + DMA Direction The interfaces described in subsequent portions of this document @@ -389,9 +470,10 @@ longer, nor should they use bus_to_virt. Some drivers have to be changed a little bit, because there is no longer an equivalent to bus_to_virt in the dynamic DMA mapping scheme - you have to always store the DMA addresses -returned by the pci_alloc_consistent and pci_map_single calls (pci_map_sg -stores them in the scatterlist itself if the platform supports dynamic DMA -mapping in hardware) in your driver structures and/or in the card registers. +returned by the pci_alloc_consistent, pci_pool_alloc, and pci_map_single +calls (pci_map_sg stores them in the scatterlist itself if the platform +supports dynamic DMA mapping in hardware) in your driver structures and/or +in the card registers. This document, and the API itself, would not be in it's current form without the feedback and suggestions from numerous individuals. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/Makefile linux.ac/Documentation/DocBook/Makefile --- linux.vanilla/Documentation/DocBook/Makefile Sat Feb 3 20:43:55 2001 +++ linux.ac/Documentation/DocBook/Makefile Tue Apr 10 18:03:31 2001 @@ -1,6 +1,7 @@ BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ - kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml + kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \ + deviceiobook.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) @@ -9,12 +10,12 @@ EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook)) JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook)) +books: $(BOOKS) + $(BOOKS): $(TOPDIR)/scripts/docproc .PHONY: books ps pdf html clean mrproper -books: $(BOOKS) - ps: $(PS) pdf: $(PDF) @@ -55,6 +56,9 @@ $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \ sis900.sgml +deviceiobook.sgml: deviceiobook.tmpl + $(TOPDIR)/scripts/docgen deviceiobook.sgml + mcabook.sgml: mcabook.tmpl $(TOPDIR)/arch/i386/kernel/mca.c $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ mcabook.sgml @@ -64,6 +68,7 @@ videobook.sgml APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \ + $(TOPDIR)/arch/i386/kernel/irq.c \ $(TOPDIR)/arch/i386/kernel/mca.c \ $(TOPDIR)/arch/i386/kernel/mtrr.c \ $(TOPDIR)/drivers/char/misc.c \ @@ -77,11 +82,24 @@ $(TOPDIR)/drivers/net/wan/syncppp.c \ $(TOPDIR)/drivers/net/wan/z85230.c \ $(TOPDIR)/drivers/usb/usb.c \ - $(TOPDIR)/fs/locks.c \ + $(TOPDIR)/drivers/video/fbmem.c \ + $(TOPDIR)/drivers/video/fbcmap.c \ + $(TOPDIR)/drivers/video/fbcon.c \ + $(TOPDIR)/drivers/video/fbgen.c \ + $(TOPDIR)/drivers/video/fonts.c \ + $(TOPDIR)/drivers/video/macmodes.c \ + $(TOPDIR)/drivers/video/modedb.c \ $(TOPDIR)/fs/devfs/base.c \ + $(TOPDIR)/fs/locks.c \ + $(TOPDIR)/include/asm-i386/bitops.h \ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ $(TOPDIR)/kernel/kmod.c \ + $(TOPDIR)/kernel/printk.c \ + $(TOPDIR)/kernel/sched.c \ + $(TOPDIR)/kernel/sysctl.c \ + $(TOPDIR)/lib/string.c \ + $(TOPDIR)/lib/vsprintf.c \ $(TOPDIR)/net/netsyms.c kernel-api.sgml: kernel-api.tmpl $(APISOURCES) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/deviceiobook.tmpl linux.ac/Documentation/DocBook/deviceiobook.tmpl --- linux.vanilla/Documentation/DocBook/deviceiobook.tmpl Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/DocBook/deviceiobook.tmpl Sun Apr 22 01:44:28 2001 @@ -0,0 +1,232 @@ + + + + + Bus-Independent Device Accesses + + + + Matthew + Wilcox + +
+ matthew@wil.cx +
+
+
+
+ + + + Alan + Cox + +
+ alan@redhat.com +
+
+
+
+ + + 2001 + Matthew Wilcox + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later + version. + + + + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + Linux provides an API which abstracts performing IO across all busses + and devices, allowing device drivers to be written independently of + bus type. + + + + + Known Bugs And Assumptions + + None. + + + + + Memory Mapped IO + + Getting Access to the Device + + The most widely supported form of IO is memory mapped IO. + That is, a part of the CPU's address space is interpreted + not as accesses to memory, but as accesses to a device. Some + architectures define devices to be at a fixed address, but most + have some method of discovering devices. The PCI bus walk is a + good example of such a scheme. This document does not cover how + to receive such an address, but assumes you are starting with one. + Physical addresses are of type unsigned long. + + + + This address should not be used directly. Instead, to get an + address suitable for passing to the accessor functions described + below, you should call ioremap. + An address suitable for accessing the device will be returned to you. + + + + After you've finished using the device (say, in your module's + exit routine), call iounmap in order to return + the address space to the kernel. Most architectures allocate new + address space each time you call ioremap, and + they can run out unless you call iounmap. + + + + + Accessing the device + + The part of the interface most used by drivers is reading and + writing memory-mapped registers on the device. Linux provides + interfaces to read and write 8-bit, 16-bit, 32-bit and 64-bit + quantities. Due to a historical accident, these are named byte, + word, long and quad accesses. Both read and write accesses are + supported; there is no prefetch support at this time. + + + + The functions are named readb, + readw, readl, + readq, writeb, + writew, writel and + writeq. + + + + Some devices (such as framebuffers) would like to use larger + transfers than 8 bytes at a time. For these devices, the + memcpy_toio, memcpy_fromio + and memset_io functions are provided. + Do not use memset or memcpy on IO addresses; they + are not guaranteed to copy data in order. + + + + The read and write functions are defined to be ordered. That is the + compiler is not permitted to reorder the I/O sequence. When the + ordering can be compiler optimised, you can use + __readb and friends to indicate the relaxed ordering. Use + this with care. The rmb provides a read memory + barrier. The wmb provides a write memory barrier. + + + + While the basic functions are defined to be synchronous with respect + to each other and ordered with respect to each other the busses the + devices sit on may themselves have asynchronocity. In paticular many + authors are burned by the fact that PCI bus writes are posted + asynchronously. A driver author must issue a read from the same + device to ensure that writes have occurred in the specific cases the + author cares. This kind of property cannot be hidden from driver + writers in the API. + + + + + ISA legacy functions + + On older kernels (2.2 and earlier) the ISA bus could be read or + written with these functions and without ioremap being used. This is + no longer true in Linux 2.4. A set of equivalent functions exist for + easy legacy driver porting. The functions available are prefixed + with 'isa_' and are isa_readb, + isa_writeb, isa_readw, + isa_writew, isa_readl, + isa_writel, isa_memcpy_fromio + and isa_memcpy_toio + + + These functions should not be used in new drivers, and will + eventually be going away. + + + + + + + Port Space Accesses + + Port Space Explained + + + Another form of IO commonly supported is Port Space. This is a + range of addresses separate to the normal memory address space. + Access to these addresses is generally not as fast as accesses + to the memory mapped addresses, and it also has a potentially + smaller address space. + + + + Unlike memory mapped IO, no preparation is required + to access port space. + + + + + Accessing Port Space + + Accesses to this space are provided through a set of functions + which allow 8-bit, 16-bit and 32-bit accesses; also + known as byte, word and long. These functions are + inb, inw, + inl, outb, + outw and outl. + + + + Some variants are provided for these functions. Some devices + require that accesses to their ports are slowed down. This + functionality is provided by appending a _p + to the end of the function. There are also equivalents to memcpy. + The ins and outs + functions copy bytes, words or longs to the given port. + + + + + + + Public Functions Provided +!Einclude/asm-i386/io.h + + +
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/kernel-api.tmpl linux.ac/Documentation/DocBook/kernel-api.tmpl --- linux.vanilla/Documentation/DocBook/kernel-api.tmpl Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/DocBook/kernel-api.tmpl Tue Apr 10 18:03:42 2001 @@ -36,7 +36,7 @@ - Driver Basic + Driver Basics Driver Entry and Exit points !Iinclude/linux/init.h @@ -44,6 +44,10 @@ Atomics !Iinclude/asm-i386/atomic.h + + Delaying, scheduling, and timer routines +!Ekernel/sched.c + @@ -53,6 +57,29 @@ + + Basic C Library Functions + + + When writing drivers, you cannot in general use routines which are + from the C Library. Some of the functions have been found generally + useful and they are listed below. The behaviour of these functions + may vary slightly from those defined by ANSI, and these deviations + are noted in the text. + + + String Conversions +!Ilib/vsprintf.c +!Elib/vsprintf.c + + String Manipulation +!Ilib/string.c + + Bit Operations +!Iinclude/asm-i386/bitops.h + + + Memory Management in Linux The Slab Cache @@ -60,6 +87,14 @@ + + The proc filesystem + + sysctl interface +!Ekernel/sysctl.c + + + The Linux VFS The Directory Cache @@ -177,5 +212,68 @@ !Edrivers/net/wan/z85230.c + + Frame Buffer Library + + + The frame buffer drivers depend heavily on four data structures. + These structures are declared in include/linux/fb.h. They are + fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs. + The last three can be made available to and from userland. + + + + fb_info defines the current state of a particular video card. + Inside fb_info, there exists a fb_ops structure which is a + collection of needed functions to make fbdev and fbcon work. + fb_info is only visible to the kernel. + + + + fb_var_screeninfo is used to describe the features of a video card + that are user defined. With fb_var_screeninfo, things such as + depth and the resolution may be defined. + + + + The next structure is fb_fix_screeninfo. This defines the + properties of a card that are created when a mode is set and can't + be changed otherwise. A good example of this is the start of the + frame buffer memory. This "locks" the address of the frame buffer + memory, so that it cannot be changed or moved. + + + + The last structure is fb_monospecs. In the old API, there was + little importance for fb_monospecs. This allowed for forbidden things + such as setting a mode of 800x600 on a fix frequency monitor. With + the new API, fb_monospecs prevents such things, and if used + correctly, can prevent a monitor from being cooked. fb_monospecs + will not be useful until kernels 2.5.x. + + + Frame Buffer Memory +!Edrivers/video/fbmem.c + + Frame Buffer Console +!Edrivers/video/fbcon.c + + Frame Buffer Colormap +!Edrivers/video/fbcmap.c + + Frame Buffer Generic Functions +!Idrivers/video/fbgen.c + + Frame Buffer Video Mode Database +!Idrivers/video/modedb.c +!Edrivers/video/modedb.c + + Frame Buffer Macintosh Video Mode Database +!Idrivers/video/macmodes.c + + Frame Buffer Fonts +!Idrivers/video/fonts.c + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/kernel-hacking.tmpl linux.ac/Documentation/DocBook/kernel-hacking.tmpl --- linux.vanilla/Documentation/DocBook/kernel-hacking.tmpl Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/DocBook/kernel-hacking.tmpl Tue Apr 10 18:03:42 2001 @@ -11,7 +11,7 @@ Russell
- rusty@linuxcare.com + rusty@rustcorp.com.au
@@ -336,6 +336,11 @@ + If all your routine does is read or write some parameter, consider + implementing a sysctl interface instead. + + + Inside the ioctl you're in user context to a process. When a error occurs you return a negated errno (see include/linux/errno.h), @@ -407,7 +412,7 @@ Note that some functions may sleep implicitly: common ones are the user space access functions (*_user) and memory allocation - functions without GFP_ATOMIC. + functions without GFP_ATOMIC. @@ -608,7 +613,8 @@ for some weird device, you have a problem: it is poorly supported in Linux because after some time memory fragmentation in a running kernel makes it hard. The best way is to allocate the block early - in the boot process. + in the boot process via the alloc_bootmem() + routine. @@ -631,6 +637,20 @@ + + <function>udelay()</function>/<function>mdelay()</function> + <filename class=headerfile>include/asm/delay.h</filename> + <filename class=headerfile>include/linux/delay.h</filename> + + + + The udelay() function can be used for small pauses. + Do not use large values with udelay() as you risk + overflow - the helper function mdelay() is useful + here, or even consider schedule_timeout(). + + + <function>local_irq_save()</function>/<function>local_irq_restore()</function> <filename class=headerfile>include/asm/system.h</filename> @@ -687,8 +707,14 @@ modules this directive is currently ignored). <type>__exit</type> is used to declare a function which is only required on exit: the function will be dropped if this file is not compiled as a module. - See the header file for use. + See the header file for use. Note that it makes no sense for a function + marked with <type>__init</type> to be exported to modules with + <function>EXPORT_SYMBOL()</function> - this will break. </para> + <para> + Static data structures marked as <type>__initdata</type> must be initialised + (as opposed to ordinary static data which is zeroed BSS). + </para> </sect1> @@ -775,6 +801,21 @@ return 0; } </programlisting> + + <para> + You can often avoid having to deal with these problems by using the + <structfield>owner</structfield> field of the + <structname>file_operations</structname> structure. Set this field + as the macro <symbol>THIS_MODULE</symbol>. + </para> + + <para> + For more complicated module unload locking requirements, you can set the + <structfield>can_unload</structfield> function pointer to your own routine, + which should return <returnvalue>0</returnvalue> if the module is + unloadable, or <returnvalue>-EBUSY</returnvalue> otherwise. + </para> + </sect1> </chapter> @@ -822,6 +863,17 @@ <returnvalue>-ERESTARTSYS</returnvalue> if a signal is received. The <function>wait_event()</function> version ignores signals. </para> + <para> + Do not use the <function>sleep_on()</function> function family - + it is very easy to accidentally introduce races; almost certainly + one of the <function>wait_event()</function> family will do, or a + loop around <function>schedule_timeout()</function>. If you choose + to loop around <function>schedule_timeout()</function> remember + you must set the task state (with + <function>set_current_state()</function>) on each iteration to avoid + busy-looping. + </para> + </sect1> <sect1 id="queue-waking"> @@ -1212,6 +1264,13 @@ <filename>MAINTAINERS</filename> means you want to be consulted when changes are made to a subsystem, and hear about bugs; it implies a more-than-passing commitment to some part of the code. + </para> + </listitem> + + <listitem> + <para> + Finally, don't forget to read <filename>Documentation/SubmittingPatches</filename> + and possibly <filename>Documentation/SubmittingDrivers</filename>. </para> </listitem> </itemizedlist> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/kernel-locking.tmpl linux.ac/Documentation/DocBook/kernel-locking.tmpl --- linux.vanilla/Documentation/DocBook/kernel-locking.tmpl Fri Feb 16 23:53:08 2001 +++ linux.ac/Documentation/DocBook/kernel-locking.tmpl Tue Apr 10 18:03:42 2001 @@ -11,7 +11,7 @@ <surname>Russell</surname> <affiliation> <address> - <email>rusty@linuxcare.com</email> + <email>rusty@rustcorp.com.au</email> </address> </affiliation> </author> diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/parportbook.tmpl linux.ac/Documentation/DocBook/parportbook.tmpl --- linux.vanilla/Documentation/DocBook/parportbook.tmpl Thu Jul 13 00:24:33 2000 +++ linux.ac/Documentation/DocBook/parportbook.tmpl Sat Apr 14 01:14:13 2001 @@ -2079,7 +2079,7 @@ | PARPORT_STATUS_BUSY); unsigned char val = (PARPORT_STATUS_ERROR | PARPORT_STATUS_BUSY); - struct parport_frob_struct frob; + struct ppdev_frob_struct frob; struct timespec ts; /* Wait for printer to be ready */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/DocBook/tulip-user.tmpl linux.ac/Documentation/DocBook/tulip-user.tmpl --- linux.vanilla/Documentation/DocBook/tulip-user.tmpl Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/DocBook/tulip-user.tmpl Thu Apr 19 22:36:12 2001 @@ -0,0 +1,325 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]> + +<book id="TulipUserGuide"> + <bookinfo> + <title>Tulip Driver User's Guide + + + + Jeff + Garzik + +
+ jgarzik@mandrakesoft.com +
+
+
+
+ + + 2001 + Jeff Garzik + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later + version. + + + + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + + + + + + + Introduction + +The Tulip Ethernet Card Driver +is maintained by Jeff Garzik (jgarzik@mandrakesoft.com). + + + +The Tulip driver was developed by Donald Becker and changed by +Jeff Garzik, Takashi Manabe and a cast of thousands. + + + +For 2.4.x and later kernels, the Linux Tulip driver is available at +http://sourceforge.net/projects/tulip/ + + + + This driver is for the Digital "Tulip" Ethernet adapter interface. + It should work with most DEC 21*4*-based chips/ethercards, as well as + with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. + + + + The original author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation, + 410 Severn Ave., Suite 210, + Annapolis MD 21403 + + + + Additional information on Donald Becker's tulip.c + is available at http://www.scyld.com/network/tulip.html + + + + + + Driver Compatibility + + +This device driver is designed for the DECchip "Tulip", Digital's +single-chip ethernet controllers for PCI (now owned by Intel). +Supported members of the family +are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike +chips from Lite-On, Macronics, ASIX, Compex and other listed below are also +supported. + + + +These chips are used on at least 140 unique PCI board designs. The great +number of chips and board designs supported is the reason for the +driver size and complexity. Almost of the increasing complexity is in the +board configuration and media selection code. There is very little +increasing in the operational critical path length. + + + + + Board-specific Settings + + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS preferably should assign the +PCI INTA signal to an otherwise unused system IRQ line. + + + +Some boards have EEPROMs tables with default media entry. The factory default +is usually "autoselect". This should only be overridden when using +transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) +for forcing full-duplex when used with old link partners that do not do +autonegotiation. + + + + + Driver Operation + +Ring buffers + + +The Tulip can use either ring buffers or lists of Tx and Rx descriptors. +This driver uses statically allocated rings of Rx and Tx descriptors, set at +compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs +for the Rx ring buffers at open() time and passes the skb->data field to the +Tulip as receive data buffers. When an incoming frame is less than +RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is +copied to the new skbuff. When the incoming frame is larger, the skbuff is +passed directly up the protocol stack and replaced by a newly allocated +skbuff. + + + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. For small frames the copying cost is negligible (esp. considering +that we are pre-loading the cache with immediately useful header +information). For large frames the copying cost is non-trivial, and the +larger copy might flush the cache of useful data. A subtle aspect of this +choice is that the Tulip only receives into longword aligned buffers, thus +the IP header at offset 14 isn't longword aligned for further processing. +Copied frames are put into the new skbuff at an offset of "+2", thus copying +has the beneficial effect of aligning the IP header and preloading the +cache. + + + + +Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + + + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'tp->tx_full' flag. + + + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so +we can't avoid the interrupt overhead by having the Tx routine reap the Tx +stats.) After reaping the stats, it marks the queue entry as empty by setting +the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the +tx_full and tbusy flags. + + + + + + + + Errata + + +The old DEC databooks were light on details. +The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last +register of the set CSR12-15 written. Hmmm, now how is that possible? + + + +The DEC SROM format is very badly designed not precisely defined, leading to +part of the media selection junkheap below. Some boards do not have EEPROM +media tables and need to be patched up. Worse, other boards use the DEC +design kit media table when it isn't correct for their board. + + + +We cannot use MII interrupts because there is no defined GPIO pin to attach +them. The MII transceiver status is polled using an kernel timer. + + + + + Driver Change History + + Version 0.9.14 (February 20, 2001) + + Fix PNIC problems (Manfred Spraul) + Add new PCI id for Accton comet + Support Davicom tulips + Fix oops in eeprom parsing + Enable workarounds for early PCI chipsets + IA64, hppa csr0 support + Support media types 5, 6 + Interpret a bit more of the 21142 SROM extended media type 3 + Add missing delay in eeprom reading + + + + Version 0.9.11 (November 3, 2000) + + Eliminate extra bus accesses when sharing interrupts (prumpf) + Barrier following ownership descriptor bit flip (prumpf) + Endianness fixes for >14 addresses in setup frames (prumpf) + Report link beat to kernel/userspace via netif_carrier_*. (kuznet) + Better spinlocking in set_rx_mode. + Fix I/O resource request failure error messages (DaveM catch) + Handle DMA allocation failure. + + + + Version 0.9.10 (September 6, 2000) + + Simple interrupt mitigation (via jamal) + More PCI ids + + + + Version 0.9.9 (August 11, 2000) + + More PCI ids + + + + Version 0.9.8 (July 13, 2000) + + Correct signed/unsigned comparison for dummy frame index + Remove outdated references to struct enet_statistics + + + + Version 0.9.7 (June 17, 2000) + + Timer cleanups (Andrew Morton) + Alpha compile fix (somebody?) + + + + Version 0.9.6 (May 31, 2000) + + Revert 21143-related support flag patch + Add HPPA/media-table debugging printk + + + + Version 0.9.5 (May 30, 2000) + + HPPA support (willy@puffingroup) + CSR6 bits and tulip.h cleanup (Chris Smith) + Improve debugging messages a bit + Add delay after CSR13 write in t21142_start_nway + Remove unused ETHER_STATS code + Convert 'extern inline' to 'static inline' in tulip.h (Chris Smith) + Update DS21143 support flags in tulip_chip_info[] + Use spin_lock_irq, not _irqsave/restore, in tulip_start_xmit() + Add locking to set_rx_mode() + Fix race with chip setting DescOwned bit (Hal Murray) + Request 100% of PIO and MMIO resource space assigned to card + Remove error message from pci_enable_device failure + + + + Version 0.9.4.3 (April 14, 2000) + + mod_timer fix (Hal Murray) + PNIC2 resuscitation (Chris Smith) + + + + Version 0.9.4.2 (March 21, 2000) + + Fix 21041 CSR7, CSR13/14/15 handling + Merge some PCI ids from tulip 0.91x + Merge some HAS_xxx flags and flag settings from tulip 0.91x + asm/io.h fix (submitted by many) and cleanup + s/HAS_NWAY143/HAS_NWAY/ + Cleanup 21041 mode reporting + Small code cleanups + + + + Version 0.9.4.1 (March 18, 2000) + + Finish PCI DMA conversion (davem) + Do not netif_start_queue() at end of tulip_tx_timeout() (kuznet) + PCI DMA fix (kuznet) + eeprom.c code cleanup + Remove Xircom Tulip crud + + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/README.DAC960 linux.ac/Documentation/README.DAC960 --- linux.vanilla/Documentation/README.DAC960 Fri Dec 8 01:05:41 2000 +++ linux.ac/Documentation/README.DAC960 Tue Apr 3 17:54:28 2001 @@ -1,17 +1,17 @@ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - Version 2.2.9 for Linux 2.2.17 - Version 2.4.9 for Linux 2.4.0 + Version 2.2.10 for Linux 2.2.18 + Version 2.4.10 for Linux 2.4.1 PRODUCTION RELEASE - 7 September 2000 + 1 February 2001 Leonard N. Zubkoff Dandelion Digital lnz@dandelion.com - Copyright 1998-2000 by Leonard N. Zubkoff + Copyright 1998-2001 by Leonard N. Zubkoff INTRODUCTION @@ -197,19 +197,19 @@ 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. +compatibility. Mylex makes available a hard disk compatibility list at +http://www.mylex.com/support/hdcomp/hd-lists.html. DRIVER INSTALLATION -This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0. +This distribution was prepared for Linux kernel version 2.2.18 or 2.4.1. 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.9.tar.gz (or DAC960-2.4.9.tar.gz) + tar -xvzf DAC960-2.2.10.tar.gz (or DAC960-2.4.10.tar.gz) mv README.DAC960 linux/Documentation mv DAC960.[ch] linux/drivers/block patch -p0 < DAC960.patch (if DAC960.patch is included) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/README.nsp_cs.eng linux.ac/Documentation/README.nsp_cs.eng --- linux.vanilla/Documentation/README.nsp_cs.eng Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/README.nsp_cs.eng Tue Apr 3 17:54:28 2001 @@ -0,0 +1,127 @@ + + WorkBiT NinjaSCSI-3/32Bi driver for Linux + +1. Comment + This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-3 +(http://www.workbit.co.jp/ts/z_nj3r.html) and NinjaSCSI-32Bi +(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card driver module +for Linux. + +2. My Linux environment +Linux kernel: 2.4.0 / 2.2.18 +pcmcia-cs: 3.1.24 +gcc: gcc-2.95.2 +PC card: I-O data PCSC-F (NinjaSCSI-3) + I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi) +SCSI device: I-O data CDPS-PX24 (CD-ROM drive) + Media Intelligent MMO-640GT (Optical disk drive) + +3. Install +[1] Check your PC card is true "NinjaSCSI-3" card. + If you installed pcmcia-cs already, pcmcia reports your card as UNKNOWN + card, and write ["WBT", "NinjaSCSI-3", "R1.0"] or some other string to + your console or log file. + You can also use "cardctl" program (this program is in pcmcia-cs source + code) to get more info. + +# cat /var/log/messgaes +... +Jan 2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1 +Jan 2 03:45:06 lindberg cardmgr[78]: product info: "WBT", "NinjaSCSI-3", "R1.0" +... +# cardctl ident +Socket 0: + no product info available +Socket 1: + product info: "IO DATA", "CBSC16 ", "1" + + +[2] Get Linux kernel source, and extract it to /usr/src. + Because NinjaSCSI driver requiers some SCSI header files in Linux kernel + source. + I recomend rebuilding your kernel. This eliminate some versioning problem. +$ cd /usr/src +$ tar -zxvf linux-x.x.x.tar.gz +$ cd linux +$ make config +... + +[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory + and make & install. This driver requies pcmcia-cs header file. +$ cd /usr/src +$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz +... + +[4] Extract this driver's archive somewhere, and edit Makefile, then do make. +$ tar -zxvf nsp_cs-x.x.tar.gz +$ cd nsp_cs-x.x +$ make + +[5] Copy nsp_cs.o to suitable plase, like /lib/modules//pcmcia/ . + +[6] Add these lines to /etc/pcmcia/config . + If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file. + So, you don't need to edit file. Just copy to /etc/pcmcia/ . + +------------------------------------- +device "nsp_cs" + class "scsi" module "nsp_cs" + +card "WorkBit NinjaSCSI-3" + version "WBT", "NinjaSCSI-3", "R1.0" + bind "nsp_cs" + +card "WorkBit NinjaSCSI-32Bi (16bit)" + version "WORKBIT", "UltraNinja-16", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / IO-DATA" + version "IO DATA", "CBSC16 ", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-1" + version "KME ", "SCSI-CARD-001", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-2" + version "KME ", "SCSI-CARD-002", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-3" + version "KME ", "SCSI-CARD-003", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-4" + version "KME ", "SCSI-CARD-004", "1" + bind "nsp_cs" +------------------------------------- + +[7] Boot (or reboot) pcmcia-cs. +# /etc/rc.d/rc.pcmcia start (BSD style) +or +# /etc/init.d/pcmcia start (SYSV style) + + +4. History +See README.nin_cs . + +5. Caution + If you eject card when doing some operation for your SCSI device or suspend +your computer, you encount some *BAD* error like disk crash. + It works good when I using this driver right way. But I'm not guarantee +your data. Please backup your data when you use this driver. + +6. Known Bugs + Some write error occurs when you use slow device. + +7. Testing + Please send me some reports(bug reports etc..) of this software. +When you send report, please tell me these or more. + card name + kernel version + your SCSI device name(hard drive, CD-ROM, etc...) + +8. Copyright + See GPL. + + +2001/02/01 yokota@netlab.is.tsukuba.ac.jp diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/SubmittingDrivers linux.ac/Documentation/SubmittingDrivers --- linux.vanilla/Documentation/SubmittingDrivers Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/SubmittingDrivers Tue Apr 10 18:03:49 2001 @@ -111,7 +111,7 @@ Kernel traffic: Weekly summary of kernel list activity (much easier to read) - [http://kt.linuxcare.com/kernel-traffic] + [http://kt.zork.net/kernel-traffic] Linux USB project: http://sourceforge.net/projects/linux-usb/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/arm/README linux.ac/Documentation/arm/README --- linux.vanilla/Documentation/arm/README Tue Nov 28 01:07:59 2000 +++ linux.ac/Documentation/arm/README Thu Apr 12 11:47:46 2001 @@ -1,5 +1,5 @@ - ARM Linux 2.4.0test1 - ==================== + ARM Linux 2.4 + ============= Please check ftp.arm.linux.org.uk:/pub/armlinux for latest updates. @@ -7,9 +7,8 @@ --------------------- In order to compile ARM Linux, you will need a compiler capable of - generating ARM ELF code with GNU extensions. GCC-2.7.2.2 ELF, GCC 2.8.1 - and EGCS are good compilers. Note that GCC-2.7.2.2 ELF is rare, and - you probably don't have it. + generating ARM ELF code with GNU extensions. GCC 2.95.1 and EGCS 1.1.2 + are good compilers. To build ARM Linux natively, you shouldn't have to alter the ARCH = line in the top level Makefile. However, if you don't have the ARM Linux ELF @@ -166,4 +165,4 @@ receive a reply within one day. --- -Russell King (12/06/2000) +Russell King (26/01/2001) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/cris/README linux.ac/Documentation/cris/README --- linux.vanilla/Documentation/cris/README Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/cris/README Thu Apr 19 14:13:36 2001 @@ -1,20 +1,28 @@ Linux 2.4 on the CRIS architecture ================================== -$Id: README,v 1.5 2001/01/10 17:20:55 bjornw Exp $ +$Id: README,v 1.7 2001/04/19 12:38:32 bjornw Exp $ -This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded network CPU. For -more information about CRIS and ETRAX please see further below. +This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded +network CPU. For more information about CRIS and ETRAX please see further +below. -<... to come: instructions on how to grab the right gcc, compiling and booting ...> +In order to compile this you need a version of gcc with support for the +ETRAX chip family. Please see this link for more information on how to +download the compiler and other tools useful when building and booting +software for the ETRAX platform: +http://developer.axis.com/doc/software/devboard_lx/install-howto.html + + What is CRIS ? -------------- -CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU architecture in Axis -Communication AB's range of embedded network CPU's, called ETRAX. The latest CPU is called -ETRAX 100LX, where LX stands for 'Linux' because the chip was designed to be a good host for -the Linux operating system. +CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU +architecture in Axis Communication AB's range of embedded network CPU's, +called ETRAX. The latest CPU is called ETRAX 100LX, where LX stands for +'Linux' because the chip was designed to be a good host for the Linux +operating system. The ETRAX 100LX chip -------------------- @@ -23,8 +31,8 @@ http://www.axis.com/news/us/001101_etrax.htm -The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad range of -built-in interfaces, all with modern scatter/gather DMA. +The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad +range of built-in interfaces, all with modern scatter/gather DMA. Memory interfaces: @@ -44,40 +52,41 @@ * two parallel-ports * two generic 8-bit ports - (not all interfaces are available at the same time due to chip pin multiplexing) - -The previous version of the ETRAX, the ETRAX 100, sits in almost all of Axis shipping -thin-servers like the Axis 2100 web camera or the developer-board. It lacks an MMU so the -Linux we run on that is a version of uClinux (Linux 2.0 without MM-support) ported to the CRIS -architecture. The new Linux 2.4 port has full MM and needs a CPU with an MMU, so it will not -run on the ETRAX 100. + (not all interfaces are available at the same time due to chip pin + multiplexing) -A version of the Axis developer-board with ETRAX 100LX will be available as soon as the chip -is ramped up (please see http://developer.axis.com for further information on that). +The previous version of the ETRAX, the ETRAX 100, sits in almost all of +Axis shipping thin-servers like the Axis 2100 web camera or the ETRAX 100 +developer-board. It lacks an MMU so the Linux we run on that is a version +of uClinux (Linux 2.0 without MM-support) ported to the CRIS architecture. +The new Linux 2.4 port has full MM and needs a CPU with an MMU, so it will +not run on the ETRAX 100. +A version of the Axis developer-board with ETRAX 100LX (running Linux +2.4) is now available. For more information please see developer.axis.com. Bootlog ------- -Just as an example, this is the debug-output from a boot of Linux 2.4 on an Axis -developer-board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :) +Just as an example, this is the debug-output from a boot of Linux 2.4 on +a board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :) At the end you see some user-mode programs booting like telnet and ftp daemons. -Linux version 2.4.0-test11 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #358 Wed Nov 22 19:29:15 CET 2000 -ROM fs in RAM, size 368640 bytes +Linux version 2.4.1 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #207 Wed Feb 21 15:48:15 CET 2001 +ROM fs in RAM, size 1376256 bytes Setting up paging and the MMU. -On node 0 totalpages: 1024 -zone(0): 1024 pages. +On node 0 totalpages: 2048 +zone(0): 2048 pages. zone(1): 0 pages. zone(2): 0 pages. -Linux/CRIS port (c) 2000 Axis Communications AB +Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB Kernel command line: -Calibrating delay loop... 19.92 BogoMIPS -Memory: 6864k/8192k available (531k kernel code, 1328k reserved, 85k data, 24k init) +Calibrating delay loop... 19.91 BogoMIPS +Memory: 13872k/16384k available (587k kernel code, 2512k reserved, 44k data, 24k init) kmem_create: Forcing size word alignment - vm_area_struct kmem_create: Forcing size word alignment - filp -Dentry-cache hash table entries: 1024 (order: 0, 8192 bytes) +Dentry-cache hash table entries: 2048 (order: 1, 16384 bytes) Buffer-cache hash table entries: 2048 (order: 0, 8192 bytes) Page-cache hash table entries: 2048 (order: 0, 8192 bytes) kmem_create: Forcing size word alignment - kiobuf @@ -87,41 +96,52 @@ POSIX conformance testing by UNIFIX Linux NET4.0 for Linux 2.4 Based upon Swansea University Computer Society NET3.039 -kmem_create: Forcing size word alignment - skbuff_head_cache Starting kswapd v1.8 kmem_create: Forcing size word alignment - file lock cache kmem_create: Forcing size word alignment - blkdev_requests +block: queued sectors max/low 9109kB/3036kB, 64 slots per queue ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB eth0 initialized eth0: changed MAC to 00:40:8C:CD:00:00 -ETRAX 100LX serial-driver $Revision: 1.5 $, (c) 2000 Axis Communications AB +ETRAX 100LX serial-driver $Revision: 1.7 $, (c) 2000 Axis Communications AB ttyS0 at 0xb0000060 is a builtin UART with DMA ttyS1 at 0xb0000068 is a builtin UART with DMA ttyS2 at 0xb0000070 is a builtin UART with DMA ttyS3 at 0xb0000078 is a builtin UART with DMA +Axis flash mapping: 200000 at 50000000 +Axis flash: Found 1 x16 CFI device at 0x0 in 16 bit mode + Amd/Fujitsu Extended Query Table v1.0 at 0x0040 +Axis flash: JEDEC Device ID is 0xC4. Assuming broken CFI table. +Axis flash: Swapping erase regions for broken CFI table. +number of CFI chips: 1 + Using default partition table +I2C driver v2.2, (c) 1999-2001 Axis Communications AB +ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB NET4: Linux TCP/IP 1.0 for NET4.0 IP Protocols: ICMP, UDP, TCP kmem_create: Forcing size word alignment - ip_dst_cache IP: routing cache hash table of 1024 buckets, 8Kbytes -TCP: Hash tables configured (established 1024 bind 1024) +TCP: Hash tables configured (established 2048 bind 2048) NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. VFS: Mounted root (cramfs filesystem) readonly. Init starts up... +Mounted none on /proc ok. Setting up eth0 with ip 10.13.9.116 and mac 00:40:8c:18:04:60 eth0: changed MAC to 00:40:8C:18:04:60 Setting up lo with ip 127.0.0.1 Default gateway is 10.13.9.1 Hostname is bbox1 Telnetd starting, using port 23. - using /bin/sh as shell. -sftpd[14]: sftpd $Revision: 1.5 $ starting up + using /bin/sash as shell. +sftpd[15]: sftpd $Revision: 1.7 $ starting up + And here is how some /proc entries look: 17# cd /proc 17# cat cpuinfo -cpu : ETRAX +cpu : CRIS cpu revision : 10 cpu model : ETRAX 100LX cache size : 8 kB @@ -133,6 +153,7 @@ ata : yes usb : yes bogomips : 99.84 + 17# cat meminfo total: used: free: shared: buffers: cached: Mem: 7028736 925696 6103040 114688 0 229376 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/devices.txt linux.ac/Documentation/devices.txt --- linux.vanilla/Documentation/devices.txt Sat Dec 30 19:26:10 2000 +++ linux.ac/Documentation/devices.txt Tue Apr 3 17:54:28 2001 @@ -660,6 +660,12 @@ 29 char Universal frame buffer 0 = /dev/fb0 First frame buffer + 1 = /dev/fb1 Second frame buffer + ... + 31 = /dev/fb31 32nd frame buffer + + Backward compatibility aliases {2.6} + 32 = /dev/fb1 Second frame buffer ... 224 = /dev/fb7 Eighth frame buffer @@ -765,7 +771,7 @@ 36 char Netlink support 0 = /dev/route Routing, device updates, kernel to user 1 = /dev/skip enSKIP security cache control - 3 = /dec/fwmonitor Firewall packet copies + 3 = /dev/fwmonitor Firewall packet copies 16 = /dev/tap0 First Ethertap device ... 31 = /dev/tap15 16th Ethertap device @@ -2436,7 +2442,7 @@ 224 char A2232 serial card 0 = /dev/ttyY0 First A2232 port - 1 = /dev/cuy0 Second A2232 port + 1 = /dev/ttyY1 Second A2232 port ... 225 char A2232 serial card (alternate devices) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/dnotify.txt linux.ac/Documentation/dnotify.txt --- linux.vanilla/Documentation/dnotify.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/dnotify.txt Tue Apr 10 18:03:56 2001 @@ -1,7 +1,7 @@ Linux Directory Notification ============================ - Stephen Rothwell + Stephen Rothwell The intention of directory notification is to allow user applications to be notified when a directory, or any of the files in it, are changed. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/devfs/ChangeLog linux.ac/Documentation/filesystems/devfs/ChangeLog --- linux.vanilla/Documentation/filesystems/devfs/ChangeLog Thu Jul 6 05:36:49 2000 +++ linux.ac/Documentation/filesystems/devfs/ChangeLog Tue Apr 10 18:03:56 2001 @@ -495,7 +495,7 @@ - Replaced dummy .epoch inode with .devfsd character device -- Modified rc.devfs to take acount of above change +- Modified rc.devfs to take account of above change - Removed spurious driver warning messages when CONFIG_DEVFS_FS=n diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/ext2.txt linux.ac/Documentation/filesystems/ext2.txt --- linux.vanilla/Documentation/filesystems/ext2.txt Mon Oct 2 04:21:20 2000 +++ linux.ac/Documentation/filesystems/ext2.txt Sun Apr 22 01:15:08 2001 @@ -4,7 +4,7 @@ ext2 was originally released in January 1993. Written by R\'emy Card, Theodore Ts'o and Stephen Tweedie, it was a major rewrite of the -Extended Filesystem. It is currently (February 1999) the predominant +Extended Filesystem. It is currently still (April 2001) the predominant filesystem in use by Linux. There are also implementations available for NetBSD, FreeBSD, the GNU HURD, Windows 95/98/NT, OS/2 and RISC OS. @@ -17,11 +17,11 @@ bsddf (*) Makes `df' act like BSD. minixdf Makes `df' act like Minix. -check=none, nocheck Perform no checks upon the filesystem. -check=normal (*) Perform normal checks on the filesystem. -check=strict Perform extra checks on the filesystem. +check=none, nocheck (*) Don't do extra checking of bitmaps on mount + (check=normal and check=strict options removed) -debug For developers only. +debug Extra debugging information is sent to the + kernel syslog. Useful for developers. errors=continue (*) Keep going on a filesystem error. errors=remount-ro Remount the filesystem read-only on an error. @@ -30,8 +30,8 @@ grpid, bsdgroups Give objects the same group ID as their parent. nogrpid, sysvgroups (*) New objects have the group ID of their creator. -resuid=n The user which may use the reserved blocks. -resgid=n The group which may use the reserved blocks. +resuid=n The user ID which may use the reserved blocks. +resgid=n The group ID which may use the reserved blocks. sb=n Use alternate superblock at this location. @@ -53,46 +53,53 @@ ------ The space in the device or file is split up into blocks. These are -a fixed size, of 1024, 2048 or 4096 bytes, which is decided when the -filesystem is created. Smaller blocks mean less wasted space per file, -but require slightly more accounting overhead. +a fixed size, of 1024, 2048 or 4096 bytes (8192 bytes on Alpha systems), +which is decided when the filesystem is created. Smaller blocks mean +less wasted space per file, but require slightly more accounting overhead, +and also impose other limits on the size of files and the filesystem. + +Block Groups +------------ Blocks are clustered into block groups in order to reduce fragmentation -and minimise the amount of head seeking when reading a large amount of -consecutive data. Each block group has a descriptor and the array of -descriptors is stored immediately after the superblock. Two blocks at -the start of each group are reserved for the block usage bitmap and -the inode usage bitmap which show which blocks and inodes are used. -Since each bitmap fits in a block, this means that the maximum size of -a block group is 8 times the size of a block. - -The first (non-reserved) blocks in the block group are designated as -the inode table for the block and the remainder are the data blocks. -The block allocation algorithm attempts to allocate data blocks in the -same block group as the inode which contains them. +and minimise the amount of head seeking when reading a large amount +of consecutive data. Information about each block group is kept in a +descriptor table stored in the block(s) immediately after the superblock. +Two blocks near the start of each group are reserved for the block usage +bitmap and the inode usage bitmap which show which blocks and inodes +are in use. Since each bitmap is limited to a single block, this means +that the maximum size of a block group is 8 times the size of a block. + +The block(s) following the bitmaps in each block group are designated +as the inode table for that block group and the remainder are the data +blocks. The block allocation algorithm attempts to allocate data blocks +in the same block group as the inode which contains them. The Superblock -------------- The superblock contains all the information about the configuration of -the filing system. It is stored in block 1 of the filesystem (numbering -from 0) and it is essential to mounting it. Since it is so important, -backup copies of the superblock are stored in block groups throughout -the filesystem. The first revision of ext2 stores a copy at the start -of every block group. Later revisions can store a copy in only some -block groups to reduce the amount of redundancy on large filesystems. -The groups chosen are 0, 1 and powers of 3, 5 and 7. - -The information in the superblock contains fields such as how many -inodes and blocks are in the filesystem and how many are unused, how -many inodes and blocks are in a block group, when the filesystem was -mounted, when it was modified, what version of the filesystem it is -(see the Revisions section below) and which OS created it. - -If the revision of the filesystem is recent enough then there are extra -fields, such as a volume name, a unique identifier, the inode size, -support for compression, block preallocation and creating fewer backup -superblocks. +the filing system. The primary copy of the superblock is stored at an +offset of 1024 bytes from the start of the device, and it is essential +to mounting the filesystem. Since it is so important, backup copies of +the superblock are stored in block groups throughout the filesystem. +The first version of ext2 (revision 0) stores a copy at the start of +every block group, along with backups of the group descriptor block(s). +Because this can consume a considerable amount of space for large +filesystems, later revisions can optionally reduce the number of backup +copies by only putting backups in specific groups (this is the sparse +superblock feature). The groups chosen are 0, 1 and powers of 3, 5 and 7. + +The information in the superblock contains fields such as the total +number of inodes and blocks in the filesystem and how many are free, +how many inodes and blocks are in each block group, when the filesystem +was mounted (and if it was cleanly unmounted), when it was modified, +what version of the filesystem it is (see the Revisions section below) +and which OS created it. + +If the filesystem is revision 1 or higher, then there are extra fields, +such as a volume name, a unique identification number, the inode size, +and space for optional filesystem features to store configuration info. All fields in the superblock (as in all other ext2 structures) are stored on the disc in little endian format, so a filesystem is portable between @@ -101,23 +108,25 @@ Inodes ------ -The inode (index node) is the fundamental concept in the ext2 filesystem. +The inode (index node) is a fundamental concept in the ext2 filesystem. Each object in the filesystem is represented by an inode. The inode structure contains pointers to the filesystem blocks which contain the data held in the object and all of the metadata about an object except its name. The metadata about an object includes the permissions, owner, group, flags, size, number of blocks used, access time, change time, modification time, deletion time, number of links, fragments, version -(for NFS) and ACLs. +(for NFS) and extended attributes (EAs) and/or Access Control Lists (ACLs). -There are several reserved fields which are currently unused in the inode -structure and several which are overloaded. One field is used for the -directory ACL if the inode is a directory and for the top 32 bits of -the file size if the inode is a regular file. The translator field is -unused under Linux, but is used by the HURD to reference the inode of -a program which will be used to interpret this object. The HURD also -has larger permissions, owner and group fields, so it uses some of the -other unused by Linux fields to store the extra bits. +There are some reserved fields which are currently unused in the inode +structure and several which are overloaded. One field is reserved for the +directory ACL if the inode is a directory and alternately for the top 32 +bits of the file size if the inode is a regular file (allowing file sizes +larger than 2GB). The translator field is unused under Linux, but is used +by the HURD to reference the inode of a program which will be used to +interpret this object. Most of the remaining reserved fields have been +used up for both Linux and the HURD for larger owner and group fields, +The HURD also has a larger mode field so it uses another of the remaining +fields to store the extra more bits. There are pointers to the first 12 blocks which contain the file's data in the inode. There is a pointer to an indirect block (which contains @@ -126,11 +135,12 @@ trebly-indirect block (which contains pointers to doubly-indirect blocks). The flags field contains some ext2-specific flags which aren't catered -for by the standard chmod flags. These flags can be listed with -lsattr and changed with the chattr command. There are flags for secure -deletion, undeletable, compression, synchronous updates, immutability, -append-only, dumpable, no-atime, and btree directories. Not all of -these are supported yet. +for by the standard chmod flags. These flags can be listed with lsattr +and changed with the chattr command, and allow specific filesystem +behaviour on a per-file basis. There are flags for secure deletion, +undeletable, compression, synchronous updates, immutability, append-only, +dumpable, no-atime, indexed directories, and data-journaling. Not all +of these are supported yet. Directories ----------- @@ -139,10 +149,19 @@ It is a specially formatted file containing records which associate each name with an inode number. Later revisions of the filesystem also encode the type of the object (file, directory, symlink, device, fifo, -socket) in the directory entry for speed. The current implementation -of ext2 uses a linked list in directories; a planned enhancement will -use btrees instead. The current implementation also never shrinks -directories once they have grown to accommodate more files. +socket) to avoid the need to check the inode itself for this information +(support for taking advantage of this feature does not yet exist in +Glibc 2.2). + +The inode allocation code tries to assign inodes which are in the same +block group as the directory in which they are first created. + +The current implementation of ext2 uses a singly-linked list to store +the filenames in the directory; a pending enhancement uses hashing of the +filenames to allow lookup without the need to scan the entire directory. + +The current implementation never removes empty directory blocks once they +have been allocated to hold more files. Special files ------------- @@ -150,31 +169,23 @@ Symbolic links are also filesystem objects with inodes. They deserve special mention because the data for them is stored within the inode itself if the symlink is less than 60 bytes long. It uses the fields -which would normally be used to store the pointers to blocks to store -the data. This is a worthwhile optimisation to make as it does not then -take up a block, and most symlinks are less than 60 characters long. +which would normally be used to store the pointers to data blocks. +This is a worthwhile optimisation as it we avoid allocating a full +block for the symlink, and most symlinks are less than 60 characters long. Character and block special devices never have data blocks assigned to them. Instead, their device number is stored in the inode, again reusing -the fields which would be used to point to the blocks. - -Revisions ---------- - -The revisioning mechanism used in ext2 is sophisticated. The revisioning -mechanism is not supported by version 0 (EXT2_GOOD_OLD_REV) of ext2 but -was introduced in version 1. There are three 32-bit fields, one for -compatible features, one for read-only compatible features and one for -incompatible features. +the fields which would be used to point to the data blocks. Reserved Space -------------- In ext2, there is a mechanism for reserving a certain number of blocks for a particular user (normally the super-user). This is intended to -allow for the system to continue functioning even if a user fills up -all the available space. It also keeps the filesystem from filling up -entirely which helps combat fragmentation. +allow for the system to continue functioning even if non-priveleged users +fill up all the space available to them (this is independent of filesystem +quotas). It also keeps the filesystem from filling up entirely which +helps combat fragmentation. Filesystem check ---------------- @@ -183,9 +194,66 @@ filesystems. The superblock of the ext2 filesystem contains several fields which indicate whether fsck should actually run (since checking the filesystem at boot can take a long time if it is large). fsck will -run if the filesystem was not unmounted without errors, if the maximum -mount count has been exceeded or if the maximum time between checks has -been exceeded. +run if the filesystem was not cleanly unmounted, if the maximum mount +count has been exceeded or if the maximum time between checks has been +exceeded. + +Feature Compatibility +--------------------- + +The compatibility feature mechanism used in ext2 is sophisticated. +It safely allows features to be added to the filesystem, without +unnecessarily sacrificing compatibility with older versions of the +filesystem code. The feature compatibility mechanism is not supported by +the original revision 0 (EXT2_GOOD_OLD_REV) of ext2, but was introduced in +revision 1. There are three 32-bit fields, one for compatible features +(COMPAT), one for read-only compatible (RO_COMPAT) features and one for +incompatible (INCOMPAT) features. + +These feature flags have specific meanings for the kernel as follows: + +A COMPAT flag indicates that a feature is present in the filesystem, +but the on-disk format is 100% compatible with older on-disk formats, so +a kernel which didn't know anything about this feature could read/write +the filesystem without any chance of corrupting the filesystem (or even +making it inconsistent). This is essentially just a flag which says +"this filesystem has a (hidden) feature" that the kernel or e2fsck may +want to be aware of (more on e2fsck and feature flags later). The ext3 +HAS_JOURNAL feature is a COMPAT flag because the ext3 journal is simply +a regular file with data blocks in it so the kernel does not need to +take any special notice of it if it doesn't understand ext3 journaling. + +An RO_COMPAT flag indicates that the on-disk format is 100% compatible +with older on-disk formats for reading (i.e. the feature does not change +the visible on-disk format). However, an old kernel writing to such a +filesystem would/could corrupt the filesystem, so this is prevented. The +most common such feature, SPARSE_SUPER, is an RO_COMPAT feature because +sparse groups allow file data blocks where superblock/group descriptor +backups used to live, and ext2_free_blocks() refuses to free these blocks, +which would leading to inconsistent bitmaps. An old kernel would also +get an error if it tried to free a series of blocks which crossed a group +boundary, but this is a legitimate layout in a SPARSE_SUPER filesystem. + +An INCOMPAT flag indicates the on-disk format has changed in some +way that makes it unreadable by older kernels, or would otherwise +cause a problem if an old kernel tried to mount it. FILETYPE is an +INCOMPAT flag because older kernels would think a filename was longer +than 256 characters, which would lead to corrupt directory listings. +The COMPRESSION flag is an obvious INCOMPAT flag - if the kernel +doesn't understand compression, you would just get garbage back from +read() instead of it automatically decompressing your data. The ext3 +RECOVER flag is needed to prevent a kernel which does not understand the +ext3 journal from mounting the filesystem without replaying the journal. + +For e2fsck, it needs to be more strict with the handling of these +flags than the kernel. If it doesn't understand ANY of the COMPAT, +RO_COMPAT, or INCOMPAT flags it will refuse to check the filesystem, +because it has no way of verifying whether a given feature is valid +or not. Allowing e2fsck to succeed on a filesystem with an unknown +feature is a false sense of security for the user. Refusing to check +a filesystem with unknown features is a good incentive for the user to +update to the latest e2fsck. This also means that anyone adding feature +flags to ext2 also needs to update e2fsck to verify these features. Metadata -------- @@ -196,29 +264,98 @@ respective fsck programs. If you're exceptionally paranoid, there are 3 ways of making metadata -writes synchronous: +writes synchronous on ext2: -per-file if you have the source: use the O_SYNC argument to open() -per-file if you don't have the source: use chattr +S -per-filesystem: mount -o sync +per-file if you have the program source: use the O_SYNC flag to open() +per-file if you don't have the source: use "chattr +S" on the file +per-filesystem: add the "sync" option to mount (or in /etc/fstab) the first and last are not ext2 specific but do force the metadata to -be written synchronously. +be written synchronously. See also Journaling below. + +Limitations +----------- + +There are various limits imposed by the on-disk layout of ext2. Other +limits are imposed by the current implementation of the kernel code. +Many of the limits are determined at the time the filesystem is first +created, and depend upon the block size chosen. The ratio of inodes to +data blocks is fixed at filesystem creation time, so the only way to +increase the number of inodes is to increase the size of the filesystem. +No tools currently exist which can change the ratio of inodes to blocks. + +Most of these limits could be overcome with slight changes in the on-disk +format and using a compatibility flag to signal the format change (at +the expense of some compatibility). + +Filesystem block size: 1kB 2kB 4kB 8kB + +File size limit: 16GB 256GB 2048GB 2048GB +Filesystem size limit: 2047GB 8192GB 16384GB 32768GB + +There is a 2.4 kernel limit of 2048GB for a single block device, so no +filesystem larger than that can be created at this time. There is also +an upper limit on the block size imposed by the page size of the kernel, +so 8kB blocks are only allowed on Alpha systems (and other architectures +which support larger pages). + +There is a "soft" upper limit of about 10-15k files in a single directory +with the current linear linked-list directory implementation. This limit +stems from performance problems when creating and deleting (and also +finding) files in such large directories. Using a hashed directory index +(under development) allows 100k-1M+ files in a single directory without +performance problems (although RAM size becomes an issue at this point). + +The (meaningless) absolute upper limit of files in a single directory +(imposed by the file size, the realistic limit is obviously much less) +is over 130 trillion files. It would be higher except there are not +enough 4-character names to make up unique directory entries, so they +have to be 8 character filenames, even then we are fairly close to +running out of unique filenames. + +Journaling +---------- + +A journaling extension to the ext2 code has been developed by Stephen +Tweedie. It avoids the risks of metadata corruption and the need to +wait for e2fsck to complete after a crash, without requiring a change +to the on-disk ext2 layout. In a nutshell, the journal is a regular +file which stores whole metadata (and optionally data) blocks that have +been modified, prior to writing them into the filesystem. This means +it is possible to add a journal to an existing ext2 filesystem without +the need for data conversion. + +When changes to the filesystem (e.g. a file is renamed) they are stored in +a transaction in the journal and can either be complete or incomplete at +the time of a crash. If a transaction is complete at the time of a crash +(or in the normal case where the system does not crash), then any blocks +in that transaction are guaranteed to represent a valid filesystem state, +and are copied into the filesystem. If a transaction is incomplete at +the time of the crash, then there is no guarantee of consistency for +the blocks in that transaction so they are discarded (which means any +filesystem changes they represent are also lost). + +The ext3 code is currently (Apr 2001) available for 2.2 kernels only, +and not yet available for 2.4 kernels. References ========== The kernel source file:/usr/src/linux/fs/ext2/ -Design & Implementation http://khg.redhat.com/HyperNews/get/fs/ext2intro.html -Compression http://debs.fuller.edu/e2compr/ -ACL support ftp://tsx-11.mit.edu/pub/linux/ALPHA/ext2fs -updated ACL work http://aerobee.informatik.uni-bremen.de/acl_eng.html -e2fsprogs ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs +e2fsprogs (e2fsck) http://e2fsprogs.sourceforge.net/ +Design & Implementation http://e2fsprogs.sourceforge.net/ext2intro.html +Journaling (ext3) ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/ +Hashed Directories http://kernelnewbies.org/~phillips/htree/ +Filesystem Resizing http://ext2resize.sourceforge.net/ +Extended Attributes & +Access Control Lists http://acl.bestbits.at/ +Compression (*) http://www.netspace.net.au/~reiter/e2compr/ Implementations for: +Windows 95/98/NT/2000 http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm +Windows 95 (*) http://www.yipton.demon.co.uk/content.html#FSDEXT2 +DOS client (*) ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ OS/2 http://perso.wanadoo.fr/matthieu.willm/ext2-os2/ -Windows 95 http://www.yipton.demon.co.uk/ -Windows NT http://www.cyco.nl/~andreys/ext2fsnt/ - http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm -DOS client ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ RISC OS client ftp://ftp.barnet.ac.uk/pub/acorn/armlinux/iscafs/ + +(*) no longer actively developed/supported (as of Apr 2001) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/proc.txt linux.ac/Documentation/filesystems/proc.txt --- linux.vanilla/Documentation/filesystems/proc.txt Tue Nov 28 01:47:38 2000 +++ linux.ac/Documentation/filesystems/proc.txt Tue Apr 10 18:04:02 2001 @@ -49,7 +49,7 @@ the SuSE Linux distribution. As there is no complete documentation for the /proc file system and we've used many freely available sources to write these chapters, it seems only fair to give the work back to the Linux community. -This work is based on the 2.2.* kernel version and the upcomming 2.4.*. I'm +This work is based on the 2.2.* kernel version and the upcoming 2.4.*. I'm afraid it's still far from complete, but we hope it will be useful. As far as we know, it is the first 'all-in-one' document about the /proc file system. It is focused on the Intel x86 hardware, so if you are looking for PPC, ARM, @@ -281,7 +281,7 @@ ERR is incremented in the case of errors in the IO-APIC bus (the bus that connects the CPUs in a SMP system. This means that an error has been detected, -the IO-APIC automatically retry the transmision, so it should not be a big +the IO-APIC automatically retry the transmission, so it should not be a big problem, but you should read the SMP-FAQ. In this context it could be interesting to note the new irq directory in 2.4. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/ramfs.txt linux.ac/Documentation/filesystems/ramfs.txt --- linux.vanilla/Documentation/filesystems/ramfs.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/filesystems/ramfs.txt Tue Apr 3 17:54:28 2001 @@ -0,0 +1,47 @@ + ramfs - An automatically resizing memory based filesystem + + + Ramfs is a file system which keeps all files in RAM. It allows read + and write access. In contrast to RAM disks, which get allocated a + fixed amount of RAM, ramfs grows and shrinks to accommodate the + files it contains. + + You can mount the ramfs with: + mount -t ramfs none /mnt/wherever + + Then just create and use files. When the filesystem is unmounted, all + its contents are lost. + + NOTE! This filesystem is probably most useful not as a real + filesystem, but as an example of how virtual filesystems can be + written. + +Resource limits: + +By default a ramfs will be limited to using half of (physical) memory +for storing file contents, a bit over that when the metadata is +included. The resource usage limits of ramfs can be controlled with +the following mount options: + + maxsize=NNN + Sets the maximum allowed memory usage of the +filesystem to NNN kilobytes. This will be rounded down to a multiple +of the page size. The default is half of physical memory. NB. unlike +most of the other limits, setting this to zero does *not* mean no +limit, but will actually limit the size of the filesystem data to zero +pages. There might be a use for this in some perverse situation. + + maxfilesize=NNN + Sets the maximum size of a single file on the +filesystem to NNN kilobytes. This will be rounded down to a multiple +of the page size. If NNN=0 there is no limit. The default is no limit. + + maxdentries=NNN + Sets the maximum number of directory entries (hard +links) on the filesystem to NNN. If NNN=0 there is no limit. By +default this is set to maxsize/4. + + maxinodes=NNN + Sets the maximum number of inodes (i.e. distinct +files) on the filesystem to NNN. If NNN=0 there is no limit. The +default is no limit (but there can never be more inodes than dentries). diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/vfat.txt linux.ac/Documentation/filesystems/vfat.txt --- linux.vanilla/Documentation/filesystems/vfat.txt Tue Dec 21 22:28:39 1999 +++ linux.ac/Documentation/filesystems/vfat.txt Thu Apr 12 11:47:46 2001 @@ -48,6 +48,9 @@ r: relaxed, case insensitive n: normal, default setting, currently case insensitive +nocase -- Returning with having the 8.3 format alias kept in + the disk. Default, return lowercase letter. + : 0,1,yes,no,true,false TODO diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/i386/boot.txt linux.ac/Documentation/i386/boot.txt --- linux.vanilla/Documentation/i386/boot.txt Fri Jul 28 00:52:08 2000 +++ linux.ac/Documentation/i386/boot.txt Thu Apr 12 11:47:52 2001 @@ -146,9 +146,16 @@ filled out, however: type_of_loader: - If your boot loader has an identifier assigned in - arch/i386/boot/setup.S, enter that value. Otherwise, enter - 0xFF here. + If your boot loader has an assigned id (see table below), enter + 0xTV here, where T is an identifier for the boot loader and V is + a version number. Otherwise, enter 0xFF here. + + Assigned boot loader ids: + 0 LILO + 1 Loadlin + 2 bootsect-loader + 3 SYSLINUX + 4 EtherBoot loadflags, heap_end_ptr: If the protocol version is 2.01 or higher, enter the diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/i810_rng.txt linux.ac/Documentation/i810_rng.txt --- linux.vanilla/Documentation/i810_rng.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/i810_rng.txt Thu Apr 19 22:36:19 2001 @@ -70,6 +70,9 @@ Change history: + Version 0.9.6: + * Internal driver cleanups, prep for 1.0.0 release. + Version 0.9.5: * Rip out entropy injection via timer. It never ever worked, and a better solution (rngd) is now available. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isapnp.txt linux.ac/Documentation/isapnp.txt --- linux.vanilla/Documentation/isapnp.txt Tue Oct 10 01:53:05 2000 +++ linux.ac/Documentation/isapnp.txt Thu Apr 19 22:36:27 2001 @@ -7,14 +7,14 @@ Read commands: -------------- -No comment.. +No comment. Write commands: --------------- -With the write interface you can simply activate or modify the configuration -for ISA Plug & Play devices. It is mainly useable for drivers which has not -use the ISA Plug & Play kernel support yet. +With the write interface you can activate or modify the configuration of +ISA Plug & Play devices. It is mainly useful for drivers which have not +been rewritten to use the ISA Plug & Play kernel support yet. card - select PnP device by vendor identification csn - select PnP device by CSN @@ -33,8 +33,8 @@ Explanation: - variable begins with zero - variable begins with one - - is in format 'PNP0000' - - is in format 'PNP0000' + - is in the standard format 'ABC1234' + - is in the standard format 'ABC1234' Example: @@ -58,38 +58,38 @@ Information for developers ========================== -Finding appropriate device --------------------------- +Finding a device +---------------- extern struct pci_bus *isapnp_find_card(unsigned short vendor, unsigned short device, struct pci_bus *from); -This function finds a ISA PnP card. For the vendor device should -be used ISAPNP_VENDOR(a,b,c) where a,b,c are characters or integers. -For the device number should be used ISAPNP_DEVICE(x) macro where x is -integer value. Both vendor and device numbers can be taken from contents -of the /proc/isapnp file. +This function finds an ISA PnP card. For the vendor argument, the +ISAPNP_VENDOR(a,b,c) macro should be used, where a,b,c are characters or +integers. For the device argument the ISAPNP_DEVICE(x) macro should be +used, where x is an integer value. Both vendor and device arguments +can be taken from contents of the /proc/isapnp file. extern struct pci_dev *isapnp_find_dev(struct pci_bus *card, unsigned short vendor, unsigned short function, struct pci_dev *from); -This function finds the ISA PnP device. If card is NULL, then -the global search mode is used (all devices are used for the searching). -Otherwise only devices which belongs to the specified card are verified. -For the function number can be used ISAPNP_FUNCTION(x) macro which works -similarly as the ISAPNP_DEVICE(x) macro. +This function finds an ISA PnP device. If card is NULL, then the global +search mode is used (all devices are used for the searching). Otherwise +only devices which belong to the specified card are checked. For the +function number the ISAPNP_FUNCTION(x) macro can be used; it works +similarly to the ISAPNP_DEVICE(x) macro. extern int isapnp_probe_cards(const struct isapnp_card_id *ids, - int (*probe)(struct pci_bus *card, - const struct isapnp_card_id *id)); + int (*probe)(struct pci_bus *card, + const struct isapnp_card_id *id)); -This function is a helper for drivers which requires to use more than -one device from an ISA PnP card. For each cards is called the probe -callback with appropriate information. +This function is a helper for drivers which need to use more than +one device from an ISA PnP card. The probe callback is called with +appropriate arguments for each card. Example for ids parameter initialization: @@ -109,13 +109,13 @@ ISAPNP_CARD_TABLE(card_ids); extern int isapnp_probe_devs(const struct isapnp_device_id *ids, - int (*probe)(struct pci_bus *card, - const struct isapnp_device_id *id)); + int (*probe)(struct pci_bus *card, + const struct isapnp_device_id *id)); -This function is a helper for drivers which requires to use one -device from an ISA PnP card. For each matched devices is called the probe -callback with appropriate information. +This function is a helper for drivers which need to use one +device from an ISA PnP card. The probe callback is called with +appropriate arguments for each matched device. Example for ids parameter initialization: @@ -129,25 +129,25 @@ ISA PnP configuration ===================== -There are two ways how can be ISA PnP interface used. +There are two ways in which the ISA PnP interface can be used. -First way is lowlevel ---------------------- +First way: low-level +-------------------- -All ISA PNP configuration registers are accessible via lowlevel +All ISA PNP configuration registers are accessible via the low-level isapnp_(read|write)_(byte|word|dword) functions. The function isapnp_cfg_begin() must be called before any lowlevel function. The function isapnp_cfg_end() must be always called after configuration otherwise the access to the ISA PnP configuration functions will be blocked. -Second way is auto-configuration --------------------------------- +Second way: auto-configuration +------------------------------ -This feature gives to the driver the real power of the ISA PnP code. -Function dev->prepare() initializes the resource members in the device -structure. This structure contains all resources set to auto configuration -values after the initialization. The device driver may modify some resources +This feature gives to the driver the real power of the ISA PnP driver. +The function dev->prepare() initializes the resource members in the device +structure. This structure contains all resources set to auto configuration +values after the initialization. The device driver may modify some resources to skip the auto configuration for a given resource. Once the device structure contains all requested resource values, the function @@ -155,12 +155,12 @@ with the auto configuration value. Function dev->activate() does: - - resources with the auto configuration value are configured - - the auto configuration is created using ISA PnP resource map - - the function writes configuration to ISA PnP configuration registers - - the function returns to the caller actual used resources + - resources with the auto configuration value are configured + - the auto configuration is created using ISA PnP resource map + - the function writes configuration to ISA PnP configuration registers + - the function returns to the caller actual used resources -When the device driver is removing, function dev->deactivate() has to be +When the device driver is removed, function dev->deactivate() has to be called to free all assigned resources. Example (game port initialization) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/joystick-api.txt linux.ac/Documentation/joystick-api.txt --- linux.vanilla/Documentation/joystick-api.txt Fri Jul 28 20:50:51 2000 +++ linux.ac/Documentation/joystick-api.txt Tue Apr 10 18:04:02 2001 @@ -114,7 +114,7 @@ ~~~~~~~~~~~~~~~~~ The time an event was generated is stored in ``js_event.time''. It's a time -in miliseconds since ... well, since sometime in the past. This eases the +in milliseconds since ... well, since sometime in the past. This eases the task of detecting double clicks, figuring out if movement of axis and button presses happened at the same time, and similar. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/kbuild/config-language.txt linux.ac/Documentation/kbuild/config-language.txt --- linux.vanilla/Documentation/kbuild/config-language.txt Sat Aug 5 02:38:44 2000 +++ linux.ac/Documentation/kbuild/config-language.txt Fri Apr 20 14:59:49 2001 @@ -349,7 +349,7 @@ if [ "$CONFIG_ALPHA_GENERIC" = "y" ] then define_bool CONFIG_PCI y - define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y + define_bool CONFIG_ALPHA_BROKEN_IRQ_MASK y fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/kernel-docs.txt linux.ac/Documentation/kernel-docs.txt --- linux.vanilla/Documentation/kernel-docs.txt Wed Aug 23 17:33:09 2000 +++ linux.ac/Documentation/kernel-docs.txt Tue Apr 10 18:04:08 2001 @@ -608,7 +608,7 @@ produced during the week. Published every Thursday. * Name: "Kernel Traffic" - URL: http://kt.linuxcare.com + URL: http://kt.zork.net Keywords: linux-kernel mailing list, weekly kernel news. Description: Weekly newsletter covering the most relevant discussions of the linux-kernel mailing list. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/kernel-parameters.txt linux.ac/Documentation/kernel-parameters.txt --- linux.vanilla/Documentation/kernel-parameters.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/kernel-parameters.txt Thu Apr 19 22:36:27 2001 @@ -22,6 +22,7 @@ HW Appropriate hardware is enabled. IA-32 IA-32 aka i386 architecture is enabled. IA-64 IA-64 architecture is enabled. + ISAPNP ISA PnP code is enabled. ISDN Appropriate ISDN support is enabled. JOY Appropriate joystick support is enabled. LP Printer support is enabled. @@ -246,6 +247,18 @@ ip= [PNP] + isapnp= [ISAPNP] Specify RDP, reset, pci_scan and verbosity. + + isapnp_reserve_irq= [ISAPNP] Exclude IRQs for the autoconfiguration. + + isapnp_reserve_dma= [ISAPNP] Exclude DMAs for the autoconfiguration. + + isapnp_reserve_io= [ISAPNP] Exclude I/O ports for the autoconfiguration. + Ranges are in pairs (I/O port base and size). + + isapnp_reserve_mem= [ISAPNP] Exclude memory regions for the autoconfiguration. + Ranges are in pairs (memory base and size). + isp16= [HW,CD] iucv= [HW,NET] @@ -361,6 +374,8 @@ nohlt [BUGS=ARM] no-hlt [BUGS=ix86] + + noisapnp [ISAPNP] Disables ISA PnP code. noinitrd [RAM] Tells the kernel not to load any configured initial RAM disk. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/memory.txt linux.ac/Documentation/memory.txt --- linux.vanilla/Documentation/memory.txt Tue Dec 22 16:31:07 1998 +++ linux.ac/Documentation/memory.txt Tue Apr 3 17:54:28 2001 @@ -37,7 +37,7 @@ * Not overclocking your CPU. * Having the memory tested in a memory tester or exchanged - with the vendor. + with the vendor. Consider testing it with memtest86 yourself. * Exchanging your CPU, cache, or motherboard for one that works. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/mips/GT64120.README linux.ac/Documentation/mips/GT64120.README --- linux.vanilla/Documentation/mips/GT64120.README Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/mips/GT64120.README Sun Apr 22 01:15:13 2001 @@ -0,0 +1,65 @@ +README for arch/mips/gt64120 directory and subdirectories + +Jun Sun, jsun@mvista.com or jsun@junsun.net +01/27, 2001 + +MOTIVATION +---------- + +Many MIPS boards share the same system controller (or CPU companian chip), +such as GT-64120. It is highly desirable to let these boards share +the same controller code instead of duplicating them. + +This directory is meant to hold all MIPS boards that use GT-64120 or GT-64120A. + + +HOW TO ADD A BOARD +------------------ + +. Create a subdirectory include/asm/gt64120/. + +. Create a file called gt64120_dep.h under that directory. + +. Modify include/asm/gt64120/gt64120.h file to include the new gt64120_dep.h + based on config options. The board-dep section is at the end of + include/asm/gt64120/gt64120.h file. There you can find all required + definitions include/asm/gt64120//gt64120_dep.h file must supply. + +. Create a subdirectory arch/mips/gt64120/ directory to hold + board specific routines. + +. The GT-64120 common code is supplied under arch/mips/gt64120/common directory. + It includes: + 1) arch/mips/gt64120/pci.c - + common PCI routine, include the top-level pcibios_init() + 2) arch/mips/gt64120/irq.c - + common IRQ routine, include the top-level do_IRQ() + [This part really belongs to arch/mips/kernel. jsun] + 3) arch/mips/gt64120/gt_irq.c - + common IRQ routines for GT-64120 chip. Currently it only handles + the timer interrupt. + +. Board-specific routines are supplied under arch/mips/gt64120/ dir. + 1) arch/mips/gt64120//pci.c - it provides bus fixup routine + 2) arch/mips/gt64120//irq.c - it provides enable/disable irqs + and board irq setup routine (irq_setup) + 3) arch/mips/gt64120//int-handler.S - + The first-level interrupt dispatching routine. + 4) a bunch of other "normal" stuff (setup, prom, dbg_io, reset, etc) + +. Follow other "normal" procedure to modify configuration files, etc. + + +TO-DO LIST +---------- + +. Expand arch/mips/gt64120/gt_irq.c to handle all GT-64120 interrupts. + We probably need to introduce GT_IRQ_BASE in board-dep header file, + which is used the starting irq_nr for all GT irqs. + + A function, gt64120_handle_irq(), will be added so that the first-level + irq dispatcher will call this function if it detects an interrupt + from GT-64120. + +. More support for GT-64120 PCI features (2nd PCI bus, perhaps) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/mips/time.README linux.ac/Documentation/mips/time.README --- linux.vanilla/Documentation/mips/time.README Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/mips/time.README Sun Apr 22 01:15:13 2001 @@ -0,0 +1,161 @@ +README for MIPS time services + +Jun Sun +jsun@mvista.com or jsun@junsun.net + + +ABOUT +----- +This file describes the new arch/mips/kernel/time.c, related files and the +services they provide. + +If you are short in patience and just want to know how to use time.c for a +new board or convert an existing board, go to the last section. + + +FILES, COMPATABILITY AND CONFIGS +--------------------------------- + +The old arch/mips/kernel/time.c is renamed to old-time.c. + +A new time.c is put there, together with include/asm-mips/time.h. + +Two configs variables are introduced, CONFIG_OLD_TIME_C and CONFIG_NEW_TIME_C. +So we allow boards using + + 1) old time.c (CONFIG_OLD_TIME_C) + 2) new time.c (CONFIG_NEW_TIME_C) + 3) neither (their own private time.c) + +However, it is expected every board will move to the new time.c in the near +future. + + +WHAT THE NEW CODE PROVIDES? +--------------------------- + +The new time code provide the following services: + + a) Implements functions required by Linux common code: + time_init + do_gettimeofday + do_settimeofday + + b) provides an abstraction of RTC and null RTC implementation as default. + extern unsigned long (*rtc_get_time)(void); + extern int (*rtc_set_time)(unsigned long); + + c) a set of gettimeoffset functions for different CPUs and different + needs. + + d) high-level and low-level timer interrupt routines where the timer + interrupt source may or may not be the CPU timer. The high-level + routine is dispatched through do_IRQ() while the low-level is + dispatched in assemably code (usually int-handler.S) + + +WHAT THE NEW CODE REQUIRES? +--------------------------- + +For the new code to work properly, each board implementation needs to supply +the following functions or values: + + a) board_time_init - a function pointer. Invoked at the beginnig of + time_init(). It is optional. + 1. (optional) set up RTC routines + 2. (optional) calibrate and set the mips_counter_frequency + + b) board_timer_setup - a function pointer. Invoked at the end of time_init() + 1. (optional) over-ride any decisions made in time_init() + 2. set up the irqaction for timer interrupt. + 3. enable the timer interrupt + + c) (optional) board-specific RTC routines. + + d) (optional) mips_counter_frequency - It must be definied if the board + is using CPU counter for timer interrupt or it is using fixed rate + gettimeoffset(). + + +PORTING GUIDE +------------- + +Step 1: decide how you like to implement the time services. + + a) does this board have a RTC? If yes, implement the two RTC funcs. + + b) does the CPU have counter/compare registers? + + If the answer is no, you need a timer to provide the timer interrupt + at 100 HZ speed. + + You cannot use the fast gettimeoffset functions, i.e., + + unsigned long fixed_rate_gettimeoffset(void); + unsigned long calibrate_div32_gettimeoffset(void); + unsigned long calibrate_div64_gettimeoffset(void); + + You can use null_gettimeoffset() will gives the same time resolution as + jiffy. Or you can implement your own gettimeoffset (probably based on + some ad hoc hardware on your machine.) + + c) The following sub steps assume your CPU has counter register. + Do you plan to use the CPU counter register as the timer interrupt + or use an exnternal timer? + + In order to CPU counter register as the timer interrupt source, you must + know the counter speed (mips_counter_frequency). It is usually the + same as the CPU speed (Or it is ALWAYS the same?) + + d) decide on whether you want to use high-level or low-level timer + interrupt routines. The low-level one is presumably faster, but should + not make too mcuh difference. + + +Step 2: the machine setup() function + + If you supply board_time_init(), set the function poointer. + + Set the function pointer board_timer_setup() (mandatory) + + +Step 3: implement rtc routines, board_time_init() and board_timer_setup() + if needed. + + board_time_init() - + a) (optional) set up RTC routines, + b) (optional) calibrate and set the mips_counter_frequency + (only needed if you intended to use fixed_rate_gettimeoffset + or use cpu counter as timer interrupt source) + + board_timer_setup() - + a) (optional) over-write any choices made above by time_init(). + b) machine specific code should setup the timer irqaction. + c) enable the timer interrupt + + + If the RTC chip is a common chip, I suggest the routines are put under + arch/mips/libs. For example, for DS1386 chip, one would create + rtc-ds1386.c under arch/mips/lib directory. Add the following line to + the arch/mips/lib/Makefile: + + obj-$(CONFIG_DDB5476) += rtc-ds1386.o + +Step 4: if you are using low-level timer interrupt, change your interrupt + dispathcing code to check for timer interrupt and jump to + ll_timer_interrupt() directly if one is detected. + +Step 5: Modify arch/mips/config.in and add CONFIG_NEW_TIME_C to your machine. + Modify the appropriate defconfig if applicable. + +Final notes: + +For some tricky cases, you may need to add your own wrapper functions +for some of the functions in time.c. + +For example, you may define your own timer interrupt routine, which does +its own processing and in turn calls timer_interrupt(). + +You can also over-ride any of the built-in functions (gettimeoffset, +RTC routines and/or timer interrupt routine). + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/mtrr.txt linux.ac/Documentation/mtrr.txt --- linux.vanilla/Documentation/mtrr.txt Fri Jul 28 20:50:51 2000 +++ linux.ac/Documentation/mtrr.txt Thu Apr 12 11:48:05 2001 @@ -16,10 +16,13 @@ these, the ARRs are used to emulate the MTRRs. The AMD K6-2 (stepping 8 and above) and K6-3 processors have two - MTRRs. These are supported. + MTRRs. These are supported. The AMD Athlon family provide 8 Intel + style MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These are supported. + + The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs. The CONFIG_MTRR option creates a /proc/mtrr file which may be used to manipulate your MTRRs. Typically the X server should use diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/8139too.txt linux.ac/Documentation/networking/8139too.txt --- linux.vanilla/Documentation/networking/8139too.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/networking/8139too.txt Thu Apr 19 22:36:36 2001 @@ -185,6 +185,24 @@ Change History -------------- +Version 0.9.16 - April 14, 2001 + +* Complete MMIO audit, disable read-after-every-write +* Update Rx interrupt handling +* Enable Early Rx thresholds, highly recommended to reduce + Rx FIFO overflow +* Make 8129 support conditional +* Support for new 2.4.3 kernel APIs +* More correct PIO/MMIO PCI BAR region size checking +* Add check for totally dead/missing hardware +* Disable media timer code to "set full duplex" +* s/spin_lock_irq/spin_lock_irqsave/ +* Only set AcceptMulticast if more than one mc address +* Only set rx_mode if changed, in set_rx_mode +* Only suspend/resume if interface is up +* Always print out version upon module load, even if no devices found + + Version 0.9.15 - February 20, 2001 * Call pci_enable_device to wake up/assign resource to device, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/TODO linux.ac/Documentation/networking/TODO --- linux.vanilla/Documentation/networking/TODO Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/TODO Thu Apr 19 22:36:36 2001 @@ -0,0 +1,25 @@ +To-do items for network drivers +------------------------------- + +* Move ethernet crc routine to generic code + +* (for 2.5) Integrate Jamal Hadi Salim's netdev Rx polling API change + +* Audit all net drivers to make sure magic packet / wake-on-lan / + similar features are disabled in the driver by default. + +* Audit all net drivers to make sure the module always prints out a + version string when loaded as a module, but only prints a version + string when built into the kernel if a device is detected. + +* Add ETHTOOL_GDRVINFO ioctl support to all ethernet drivers. + + + +To-do items to consider for network drivers +------------------------------------------- +* Make a single function which handles the ethtool ioctl for + most MII-compatible devices? Ideally the driver would pass function + pointers to its existing mdio_{read,write} functions when calling the + generic ioctl handler. + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/comx.txt linux.ac/Documentation/networking/comx.txt --- linux.vanilla/Documentation/networking/comx.txt Fri Jul 28 20:50:51 2000 +++ linux.ac/Documentation/networking/comx.txt Tue Apr 10 18:04:08 2001 @@ -162,7 +162,7 @@ some restricions in order to be able to use non-async lines too. If configured, this driver can use Van Jacobson TCP header compression (you'll need the slhc.o module for this). -Additionaly to use this protocol, enable async ppp in your kernel config, and +Additionally to use this protocol, enable async ppp in your kernel config, and create the comx device special files in /dev. They're character special files with major 88, and their names must be the same as their network interface counterparts (i.e /dev/comx0 with minor 0 corresponds interface comx0 and so diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/olympic.txt linux.ac/Documentation/networking/olympic.txt --- linux.vanilla/Documentation/networking/olympic.txt Fri Jul 28 20:50:51 2000 +++ linux.ac/Documentation/networking/olympic.txt Thu Apr 19 22:36:42 2001 @@ -3,18 +3,21 @@ Release 0.2.0 - Release June 8th 1999 Peter De Schrijver & Mike Phillips - +Release 0.9.C - Release + April 18th 2001 Mike Phillips Thanks: Erik De Cock, Adrian Bridgett and Frank Fiene for their -patience and testing. -Paul Norton without whose tr.c code we would have had -a lot more work to do. +patience and testing. +Donald Champion for the cardbus support +Kyle Lucke for the dma api changes. +Jonathon Bitner for hardware support. +Everybody on linux-tr for their continued support. Options: -The driver accepts three options: ringspeed, pkt_buf_sz, and -message_level. +The driver accepts four options: ringspeed, pkt_buf_sz, +message_level and network_monitor. These options can be specified differently for each card found. @@ -40,6 +43,17 @@ value will display all soft messages as well. NB This does not turn debugging messages on, that must be done by modified the source code. +network_monitor: Any non-zero value will provide a quasi network monitoring +mode. All unexpected MAC frames (beaconing etc.) will be received +by the driver and the source and destination addresses printed. +Also an entry will be added in /proc/net called olympic_tr%d, where tr%d +is the registered device name, i.e tr0, tr1, etc. This displays low +level information about the configuration of the ring and the adapter. +This feature has been designed for network administrators to assist in +the diagnosis of network / ring problems. (This used to OLYMPIC_NETWORK_MONITOR, +but has now changed to allow each adapter to be configured differently and +to alleviate the necessity to re-compile olympic to turn the option on). + Multi-card: The driver will detect multiple cards and will work with shared interrupts, @@ -60,16 +74,6 @@ building routers, gateway's etc, you could start to use a lot of memory real fast. -Network Monitor Mode: - -By modifying the #define OLYMPIC_NETWORK_MONITOR from 0 to 1 in the -source code the driver will implement a quasi network monitoring -mode. All unexpected MAC frames (beaconing etc.) will be received -by the driver and the source and destination addresses printed. -Also an entry will be added in /proc/net called olympic_tr. This -displays low level information about the configuration of the ring and -the adapter. This feature has been designed for network administrators -to assist in the diagnosis of network / ring problems. 6/8/99 Peter De Schrijver and Mike Phillips diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/wan-router.txt linux.ac/Documentation/networking/wan-router.txt --- linux.vanilla/Documentation/networking/wan-router.txt Fri Jul 28 20:50:52 2000 +++ linux.ac/Documentation/networking/wan-router.txt Sat Apr 14 01:14:20 2001 @@ -1,27 +1,12 @@ ------------------------------------------------------------------------------ -WAN Router for Linux Operating System +Linux WAN Router Utilities Package ------------------------------------------------------------------------------ -Version 2.1.1 - Nov 08, 1999 -Version 2.0.8 - Nov 02, 1999 -Version 2.0.7 - Aug 26, 1999 -Version 2.0.6 - Aug 17, 1999 -Version 2.0.5 - Aug 12, 1999 -Version 2.0.4 - Nov 26, 1998 -Version 2.0.3 - Aug 25, 1998 -Version 2.0.2 - Dec 09, 1997 -Version 2.0.1 - Nov 28, 1997 -Version 2.0.0 - Nov 06, 1997 -Version 1.0.3 - June 3, 1997 -Version 1.0.1 - January 30, 1997 +Version 2.2.1 +Mar 28, 2001 Author: Nenad Corbic -Copyright (c) 1995-1999 Sangoma Technologies Inc. +Copyright (c) 1995-2001 Sangoma Technologies Inc. ------------------------------------------------------------------------------ - -WARNING: This Version of WANPIPE supports only the S508 and S508/FT1 cards. -IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR -AN UPGRADE. ONLY THE BiSYNC STREAMING CODE IS SUPPORTED ON S502E/S503 cards. - INTRODUCTION Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) @@ -41,7 +26,7 @@ Unix-like operating system anyway). With a number of relatively inexpensive WAN interface cards available on the market, a perfectly usable router can be built for less than half a price of an external router. Yet a Linux box -acting as a router can still be used for other purposes, such as firewalling, +acting as a router can still be used for other purposes, such as fire-walling, running FTP, WWW or DNS server, etc. This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux @@ -87,15 +72,28 @@ To ba able to use the Linux WAN Router you will also need a WAN Tools package available from - ftp.sangoma.com/pub/linux/vX.Y.Z/wantools-X.Y.Z.tgz - or - ftp.sangoma.com/pub/linux/vX.Y.Z/wanpipe-X.Y.Z.tgz + ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz + +where vX.Y.Z represent the wanpipe version number. + +For technical questions and/or comments please e-mail to ncorbic@sangoma.com. +For general inquiries please contact Sangoma Technologies Inc. by -where vX.Y.Z represent the Linux kernel version number. + Hotline: 1-800-388-2475 (USA and Canada, toll free) + Phone: (905) 474-1990 ext: 106 + Fax: (905) 474-9223 + E-mail: dm@sangoma.com (David Mandelstam) + WWW: http://www.sangoma.com -For technical questions and/or comments regarding this product please e-mail -to jaspreet@sangoma.com or dm@sangoma.com. +INSTALLATION + +Please read the WanpipeForLinux.pdf manual on how to +install the WANPIPE tools and drivers properly. + + +After installing wanpipe package: /usr/local/wanrouter/doc. +On the ftp.sangoma.com : /linux/current_wanpipe/doc COPYRIGHT AND LICENSING INFORMATION @@ -114,120 +112,511 @@ -ACKNOWLEDGMENTS +ACKNOWLEDGEMENTS This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed -by Sangoma Technologies Inc. for Linux 1.2.x. Release of Linux 2.0 in summer -1996 commanded adequate changes to the WANPIPE code to take full advantage of -new Linux features. Instead of continuing developing proprietary interface -specific to Sangoma WAN cards, we decided to put all hardware-independent code -into a separate module and define two levels of interfaces - one for user- -level applications and another for kernel-level WAN drivers. +by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE +together with the next major release of Linux kernel in summer 1996 commanded +adequate changes to the WANPIPE code to take full advantage of new Linux +features. + +Instead of continuing developing proprietary interface tied to Sangoma WAN +cards, we decided to separate all hardware-independent code into a separate +module and defined two levels of interfaces - one for user-level applications +and another for kernel-level WAN drivers. WANPIPE is now implemented as a +WAN driver compliant with the WAN Link Driver interface. Also a general +purpose WAN configuration utility and a set of shell scripts was developed to +support WAN router at the user level. Many useful ideas concerning hardware-independent interface implementation were given by Mike McLagan and his implementation of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). +With the new implementation of the APIs being incorporated into the WANPIPE, +a special thank goes to Alan Cox in providing insight into BSD sockets. + Special thanks to all the WANPIPE users who performed field-testing, reported bugs and made valuable comments and suggestions that help us to improve this product. +NEW IN THIS RELEASE + + o Updated the WANCFG utility + Calls the pppconfig to configure the PPPD + for async connections. + + o Added the PPPCONFIG utility + Used to configure the PPPD dameon for the + WANPIPE Async PPP and standard serial port. + The wancfg calls the pppconfig to configure + the pppd. + + o Fixed the PCI autodetect feature. + The SLOT 0 was used as an autodetect option + however, some high end PC's slot numbers start + from 0. + + o This release has been tested with the new backupd + daemon release. + + +PRODUCT COMPONENTS AND RELATED FILES + +/etc: (or user defined) + wanpipe1.conf default router configuration file + +/lib/modules/X.Y.Z/misc: + wanrouter.o router kernel loadable module + af_wanpipe.o wanpipe api socket module + +/lib/modules/X.Y.Z/net: + sdladrv.o Sangoma SDLA support module + wanpipe.o Sangoma WANPIPE(tm) driver module + +/proc/net/wanrouter + Config reads current router configuration + Status reads current router status + {name} reads WAN driver statistics + +/usr/sbin: + wanrouter wanrouter start-up script + wanconfig wanrouter configuration utility + sdladump WANPIPE adapter memory dump utility + fpipemon Monitor for Frame Relay + cpipemon Monitor for Cisco HDLC + ppipemon Monitor for PPP + xpipemon Monitor for X25 + wpkbdmon WANPIPE keyboard led monitor/debugger + +/usr/local/wanrouter: + README this file + COPYING GNU General Public License + Setup installation script + Filelist distribution definition file + wanrouter.rc meta-configuration file + (used by the Setup and wanrouter script) + +/usr/local/wanrouter/doc: + wanpipeForLinux.pdf WAN Router User's Manual + +/usr/local/wanrouter/patches: + wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13. + wanrouter-v2214.gz patch for Linux kernel 2.2.14. + wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17. + wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up. + wanrouter-v240.gz patch for Linux kernel 2.4.0. + wanrouter-v242.gz patch for Linux kernel 2.4.2 and up. + wanrouter-v2034.gz patch for Linux kernel 2.0.34 + wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up. + +/usr/local/wanrouter/patches/kdrivers: + Sources of the latest WANPIPE device drivers. + These are used to UPGRADE the linux kernel to the newest + version if the kernel source has already been pathced with + WANPIPE drivers. + +/usr/local/wanrouter/samples: + interface sample interface configuration file + wanpipe1.cpri CHDLC primary port + wanpipe2.csec CHDLC secondary port + wanpipe1.fr Frame Relay protocol + wanpipe1.ppp PPP protocol ) + wanpipe1.asy CHDLC ASYNC protocol + wanpipe1.x25 X25 protocol + wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon) + wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon) + wanrouter.rc sample meta-configuration file + +/usr/local/wanrouter/util: + * wan-tools utilities source code + +/usr/local/wanrouter/api/x25: + * x25 api sample programs. +/usr/local/wanrouter/api/chdlc: + * chdlc api sample programs. +/usr/local/wanrouter/api/fr: + * fr api sample programs. +/usr/local/wanrouter/config/wancfg: + wancfg WANPIPE GUI configuration program. + Creates wanpipe#.conf files. +/usr/local/wanrouter/config/cfgft1: + cfgft1 GUI CSU/DSU configuration program. + +/usr/include/linux: + wanrouter.h router API definitions + wanpipe.h WANPIPE API definitions + sdladrv.h SDLA support module API definitions + sdlasfm.h SDLA firmware module definitions + if_wanpipe.h WANPIPE Socket definitions + if_wanpipe_common.h WANPIPE Socket/Driver common definitions. + sdlapci.h WANPIPE PCI definitions + + +/usr/src/linux/net/wanrouter: + * wanrouter source code + +/var/log: + wanrouter wanrouter start-up log (created by the Setup script) + +/var/lock: (or /var/lock/subsys for RedHat) + wanrouter wanrouter lock file (created by the Setup script) + +/usr/local/wanrouter/firmware: + fr514.sfm Frame relay firmware for Sangoma S508/S514 card + cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card + ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards + x25_508.sfm X25 Firmware for Sangoma S508 card. + + REVISION HISTORY -2.1.1 Nov 09, 1999 - New code for S514PCI card - - Completely redesigned drivers - fully tested and optimized. - -2.0.8 Nov 02, 1999 - Fixed up the X25API code. - - Clear call bug fixed.i - - Enabled driver for multi-card - operation. - -2.0.7 Aug 26, 1999 - Merged X25API code into WANPIPE. - - Fixed a memory leak for X25API - - Updated the X25API code for 2.2.X kernels. - - Improved NEM handling. - -2.0.6 Aug 17, 1999 - Kernel patch works for both 2.2.10 and 2.2.11 kernels - - Fixed up 2.0.5 installation bugs - - No functional difference between 2.0.6 and 2.0.5 - -2.0.5 Aug 12, 1999 - NEW PPP, interrupt drive code - - NEW X25 Xpipmon debugger - - Comments added to setup scripts - - Numerous bug fixes - -2.0.4 Nov 26, 1998 - NEW Cisco Dual Port support. - - NEW support for BiSync Streaming API. - - NEW support for HDLC (LAPB) API. - - WANPIPE provides an API for application - development using the BSD socket interface. - -2.0.3 Aug 25, 1998 - NEW support for Cisco HDLC, with cpipemon - utility for monitoring - - CIR support for Frame-relay - - Support for PAP and CHAP for ppp has been - implemented - - Dynamic IP assignment for PPP - - Multiple channel IPX support for Frame-relay - and X25 - - Inverse Arp support for Frame-relay - - FT1 Configuration utility for linux - - Man Pages for router.conf, router, sdladump, - cfgft1, fpipemon, ppipemon and cpipemon - -2.0.2 Dev 09, 1997 - Implemented PAP and CHAP for ppp. - -2.0.1 Nov 28, 1997 - Protection of "enable_irq()" while - "disable_irq()" has been enabled from any other - routine (for Frame Relay, PPP and X25). - - Added additional Stats for Fpipemon and Ppipemon - - Improved Load Sharing for multiple boards. - -2.0.0 Nov 07, 1997 - Implemented protection of RACE conditions by - critical flags for FRAME RELAY and PPP. - - DLCI List interrupt mode implemented. - - IPX support in FRAME RELAY and PPP. - - IPX Server Support (MARS) - - More driver specific stats included in FPIPEMON - and PIPEMON. - -1.0.5 July 28, 1997 - Configurable T391,T392,N391,N392,N393 for Frame - Relay in router.conf. - - Configurable Memory Address through router.conf - for Frame Relay, PPP and X.25. (commenting this - out enables auto-detection). - - Fixed freeing up received buffers using kfree() - for Frame Relay and X.25. - - Protect sdla_peek() by calling save_flags(), - cli() and restore_flags(). - - Changed number of Trace elements from 32 to 20 - - Added DLCI specific data monitoring in FPIPEMON. - -1.0.4 July 10, 1997 - S508/FT1 monitoring capability in fpipemon and - ppipemon utilities. - - Configurable TTL for UDP packets. - - Multicast and Broadcast IP source addresses are - silently discarded. - -1.0.3 June 3, 1997 - - UDP port for multiple boards (Frame relay, PPP) - Continuous Transmission of Configure Request - - Packet for PPP (this support is only added for - 508 cards) - - Connection Timeout for PPP changed from 900 to 0 - - Flow Control for multiple boards and multiple - channels (Frame Relay) - -1.0.1 January 30, 1997 +1.0.0 December 31, 1996 Initial version + +1.0.1 January 30, 1997 Status and statistics can be read via /proc + filesystem entries. + +1.0.2 April 30, 1997 Added UDP management via monitors. + +1.0.3 June 3, 1997 UDP management for multiple boards using Frame + Relay and PPP + Enabled continuous transmission of Configure + Request Packet for PPP (for 508 only) + Connection Timeout for PPP changed from 900 to 0 + Flow Control Problem fixed for Frame Relay + +1.0.4 July 10, 1997 S508/FT1 monitoring capability in fpipemon and + ppipemon utilities. + Configurable TTL for UDP packets. + Multicast and Broadcast IP source addresses are + silently discarded. + +1.0.5 July 28, 1997 Configurable T391,T392,N391,N392,N393 for Frame + Relay in router.conf. + Configurable Memory Address through router.conf + for Frame Relay, PPP and X.25. (commenting this + out enables auto-detection). + Fixed freeing up received buffers using kfree() + for Frame Relay and X.25. + Protect sdla_peek() by calling save_flags(), + cli() and restore_flags(). + Changed number of Trace elements from 32 to 20 + Added DLCI specific data monitoring in FPIPEMON. +2.0.0 Nov 07, 1997 Implemented protection of RACE conditions by + critical flags for FRAME RELAY and PPP. + DLCI List interrupt mode implemented. + IPX support in FRAME RELAY and PPP. + IPX Server Support (MARS) + More driver specific stats included in FPIPEMON + and PIPEMON. + +2.0.1 Nov 28, 1997 Bug Fixes for version 2.0.0. + Protection of "enable_irq()" while + "disable_irq()" has been enabled from any other + routine (for Frame Relay, PPP and X25). + Added additional Stats for Fpipemon and Ppipemon + Improved Load Sharing for multiple boards + +2.0.2 Dec 09, 1997 Support for PAP and CHAP for ppp has been + implemented. + +2.0.3 Aug 15, 1998 New release supporting Cisco HDLC, CIR for Frame + relay, Dynamic IP assignment for PPP and Inverse + Arp support for Frame-relay. Man Pages are + included for better support and a new utility + for configuring FT1 cards. + +2.0.4 Dec 09, 1998 Dual Port support for Cisco HDLC. + Support for HDLC (LAPB) API. + Supports BiSync Streaming code for S502E + and S503 cards. + Support for Streaming HDLC API. + Provides a BSD socket interface for + creating applications using BiSync + streaming. + +2.0.5 Aug 04, 1999 CHDLC initializatin bug fix. + PPP interrupt driven driver: + Fix to the PPP line hangup problem. + New PPP firmware + Added comments to the startup SYSTEM ERROR messages + Xpipemon debugging application for the X25 protocol + New USER_MANUAL.txt + Fixed the odd boundary 4byte writes to the board. + BiSync Streaming code has been taken out. + Available as a patch. + Streaming HDLC API has been taken out. + Available as a patch. + +2.0.6 Aug 17, 1999 Increased debugging in statup scripts + Fixed insallation bugs from 2.0.5 + Kernel patch works for both 2.2.10 and 2.2.11 kernels. + There is no functional difference between the two packages + +2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE. + o Fixed a memeory leak for X25API + o Updated the X25API code for 2.2.X kernels. + o Improved NEM handling. + +2.1.0 Oct 25, 1999 o New code for S514 PCI Card + o New CHDLC and Frame Relay drivers + o PPP and X25 are not supported in this release + +2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards + +2.1.3 Apr 06, 2000 o Socket based x25api + o Socket based chdlc api + o Socket based fr api + o Dual Port Receive only CHDLC support. + o Asynchronous CHDLC support (Secondary Port) + o cfgft1 GUI csu/dsu configurator + o wancfg GUI configuration file + configurator. + o Architectual directory changes. + +beta-2.1.4 Jul 2000 o Dynamic interface configuration: + Network interfaces reflect the state + of protocol layer. If the protocol becomes + disconnected, driver will bring down + the interface. Once the protocol reconnects + the interface will be brought up. + + Note: This option is turned off by default. + + o Dynamic wanrouter setup using 'wanconfig': + wanconfig utility can be used to + shutdown,restart,start or reconfigure + a virtual circuit dynamically. + + Frame Relay: Each DLCI can be: + created,stopped,restarted and reconfigured + dynamically using wanconfig. + + ex: wanconfig card wanpipe1 dev wp1_fr16 up + + o Wanrouter startup via command line arguments: + wanconfig also supports wanrouter startup via command line + arguments. Thus, there is no need to create a wanpipe#.conf + configuration file. + + o Socket based x25api update/bug fixes. + Added support for LCN numbers greater than 255. + Option to pass up modem messages. + Provided a PCI IRQ check, so a single S514 + card is guaranteed to have a non-sharing interrupt. + + o Fixes to the wancfg utility. + o New FT1 debugging support via *pipemon utilities. + o Frame Relay ARP support Enabled. + +beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix. + o Added the Multi-Port PPP + Updated utilites for the Multi-Port PPP. + +2.1.4 Aut 2000 + o In X25API: + Maximum packet an application can send + to the driver has been extended to 4096 bytes. + + Fixed the x25 startup bug. Enable + communications only after all interfaces + come up. HIGH SVC/PVC is used to calculate + the number of channels. + Enable protocol only after all interfaces + are enabled. + + o Added an extra state to the FT1 config, kernel module. + o Updated the pipemon debuggers. + + o Blocked the Multi-Port PPP from running on kernels + 2.2.16 or greater, due to syncppp kernel module + change. + +beta1-2.1.5 Nov 15 2000 + o Fixed the MulitPort PPP Support for kernels 2.2.16 and above. + 2.2.X kernels only + + o Secured the driver UDP debugging calls + - All illegal netowrk debugging calls are reported to + the log. + - Defined a set of allowed commands, all other denied. + + o Cpipemon + - Added set FT1 commands to the cpipemon. Thus CSU/DSU + configuraiton can be performed using cpipemon. + All systems that cannot run cfgft1 GUI utility should + use cpipemon to configure the on board CSU/DSU. + + + o Keyboard Led Monitor/Debugger + - A new utilty /usr/sbin/wpkbdmon uses keyboard leds + to convey operatinal statistic information of the + Sangoma WANPIPE cards. + NUM_LOCK = Line State (On=connected, Off=disconnected) + CAPS_LOCK = Tx data (On=transmitting, Off=no tx data) + SCROLL_LOCK = Rx data (On=receiving, Off=no rx data + + o Hardware probe on module load and dynamic device allocation + - During WANPIPE module load, all Sangoma cards are probed + and found information is printed in the /var/log/messages. + - If no cards are found, the module load fails. + - Appropriate number of devices are dynamically loaded + based on the number of Sangoma cards found. + + Note: The kernel configuraiton option + CONFIG_WANPIPE_CARDS has been taken out. + + o Fixed the Frame Relay and Chdlc network interfaces so they are + compatible with libpcap libraries. Meaning, tcpdump, snort, + ethereal, and all other packet sniffers and debuggers work on + all WANPIPE netowrk interfaces. + - Set the network interface encoding type to ARPHRD_PPP. + This tell the sniffers that data obtained from the + network interface is in pure IP format. + Fix for 2.2.X kernels only. + + o True interface encoding option for Frame Relay and CHDLC + - The above fix sets the network interface encoding + type to ARPHRD_PPP, however some customers use + the encoding interface type to determine the + protocol running. Therefore, the TURE ENCODING + option will set the interface type back to the + original value. + + NOTE: If this option is used with Frame Relay and CHDLC + libpcap library support will be broken. + i.e. tcpdump will not work. + Fix for 2.2.x Kernels only. + + o Ethernet Bridgind over Frame Relay + - The Frame Relay bridging has been developed by + Kristian Hoffmann and Mark Wells. + - The Linux kernel bridge is used to send ethernet + data over the frame relay links. + For 2.2.X Kernels only. + + o Added extensive 2.0.X support. Most new features of + 2.1.5 for protocols Frame Relay, PPP and CHDLC are + supported under 2.0.X kernels. + +beta1-2.2.0 Dec 30 2000 + o Updated drivers for 2.4.X kernels. + o Updated drivers for SMP support. + o X25API is now able to share PCI interrupts. + o Took out a general polling routine that was used + only by X25API. + o Added appropriate locks to the dynamic reconfiguration + code. + o Fixed a bug in the keyboard debug monitor. + +beta2-2.2.0 Jan 8 2001 + o Patches for 2.4.0 kernel + o Patches for 2.2.18 kernel + o Minor updates to PPP and CHLDC drivers. + Note: No functinal difference. + +beta3-2.2.9 Jan 10 2001 + o I missed the 2.2.18 kernel patches in beta2-2.2.0 + release. They are included in this release. + +Stable Release +2.2.0 Feb 01 2001 + o Bug fix in wancfg GUI configurator. + The edit function didn't work properly. + + +bata1-2.2.1 Feb 09 2001 + o WANPIPE TTY Driver emulation. + Two modes of operation Sync and Async. + Sync: Using the PPPD daemon, kernel SyncPPP layer + and the Wanpipe sync TTY driver: a PPP protocol + connection can be established via Sangoma adapter, over + a T1 leased line. + + The 2.4.0 kernel PPP layer supports MULTILINK + protocol, that can be used to bundle any number of Sangoma + adapters (T1 lines) into one, under a single IP address. + Thus, efficiently obtaining multiple T1 throughput. + + NOTE: The remote side must also implement MULTILINK PPP + protocol. + + Async:Using the PPPD daemon, kernel AsyncPPP layer + and the WANPIPE async TTY driver: a PPP protocol + connection can be established via Sangoma adapter and + a modem, over a telephone line. + + Thus, the WANPIPE async TTY driver simulates a serial + TTY driver that would normally be used to interface the + MODEM to the linux kernel. + + o WANPIPE PPP Backup Utility + This utility will monitor the state of the PPP T1 line. + In case of failure, a dial up connection will be established + via pppd daemon, ether via a serial tty driver (serial port), + or a WANPIPE async TTY driver (in case serial port is unavailable). + + Furthermore, while in dial up mode, the primary PPP T1 link + will be monitored for signs of life. + + If the PPP T1 link comes back to life, the dial up connection + will be shutdown and T1 line re-established. + + + o New Setup installation script. + Option to UPGRADE device drivers if the kernel source has + already been patched with WANPIPE. + + Option to COMPILE WANPIPE modules against the currently + running kernel, thus no need for manual kernel and module + re-compilatin. + + o Updates and Bug Fixes to wancfg utility. + +bata2-2.2.1 Feb 20 2001 + + o Bug fixes to the CHDLC device drivers. + The driver had compilation problmes under kernels + 2.2.14 or lower. + + o Bug fixes to the Setup installation script. + The device drivers compilation options didn't work + properly. + + o Update to the wpbackupd daemon. + Optimized the cross-over times, between the primary + link and the backup dialup. + +beta3-2.2.1 Mar 02 2001 + o Patches for 2.4.2 kernel. + + o Bug fixes to util/ make files. + o Bug fixes to the Setup installation script. + + o Took out the backupd support and made it into + as separate package. + +beta4-2.2.1 Mar 12 2001 + + o Fix to the Frame Relay Device driver. + IPSAC sends a packet of zero length + header to the frame relay driver. The + driver tries to push its own 2 byte header + into the packet, which causes the driver to + crash. + + o Fix the WANPIPE re-configuration code. + Bug was found by trying to run the cfgft1 while the + interface was already running. + + o Updates to cfgft1. + Writes a wanpipe#.cfgft1 configuration file + once the CSU/DSU is configured. This file can + holds the current CSU/DSU configuration. + - - Implemented user-readable status and statistics - via /proc filesystem -1.0.0 December 31, 1996 +>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - Initial version ->>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/wanpipe.txt linux.ac/Documentation/networking/wanpipe.txt --- linux.vanilla/Documentation/networking/wanpipe.txt Fri Jul 28 20:50:52 2000 +++ linux.ac/Documentation/networking/wanpipe.txt Sat Apr 14 01:14:20 2001 @@ -1,32 +1,100 @@ ------------------------------------------------------------------------------ Linux WAN Router Utilities Package ------------------------------------------------------------------------------ -Version 2.1.1 -Nov 08, 1999 +Version 2.2.1 +Mar 28, 2001 Author: Nenad Corbic -Copyright (c) 1995-1999 Sangoma Technologies Inc. +Copyright (c) 1995-2001 Sangoma Technologies Inc. ------------------------------------------------------------------------------ INTRODUCTION -This is a set of utilities and shell scripts you need in order to be able to -use Linux kernel-level WAN Router. Please read WAN Router User's manual -(router.txt) and WANPIPE driver documentation found in /usr/lib/router/doc -directory for installation and configuration instructions. +Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) +and/or stand-alone hosts over vast distances with data transfer rates +significantly higher than those achievable with commonly used dial-up +connections. + +Usually an external device called `WAN router' sitting on your local network +or connected to your machine's serial port provides physical connection to +WAN. Although router's job may be as simple as taking your local network +traffic, converting it to WAN format and piping it through the WAN link, these +devices are notoriously expensive, with prices as much as 2 - 5 times higher +then the price of a typical PC box. + +Alternatively, considering robustness and multitasking capabilities of Linux, +an internal router can be built (most routers use some sort of stripped down +Unix-like operating system anyway). With a number of relatively inexpensive WAN +interface cards available on the market, a perfectly usable router can be +built for less than half a price of an external router. Yet a Linux box +acting as a router can still be used for other purposes, such as fire-walling, +running FTP, WWW or DNS server, etc. + +This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux +operating system and provides generic hardware-independent services for such +drivers. Why can existing Linux network device interface not be used for +this purpose? Well, it can. However, there are a few key differences between +a typical network interface (e.g. Ethernet) and a WAN link. + +Many WAN protocols, such as X.25 and frame relay, allow for multiple logical +connections (known as `virtual circuits' in X.25 terminology) over a single +physical link. Each such virtual circuit may (and almost always does) lead +to a different geographical location and, therefore, different network. As a +result, it is the virtual circuit, not the physical link, that represents a +route and, therefore, a network interface in Linux terms. + +To further complicate things, virtual circuits are usually volatile in nature +(excluding so called `permanent' virtual circuits or PVCs). With almost no +time required to set up and tear down a virtual circuit, it is highly desirable +to implement on-demand connections in order to minimize network charges. So +unlike a typical network driver, the WAN driver must be able to handle multiple +network interfaces and cope as multiple virtual circuits come into existence +and go away dynamically. + +Last, but not least, WAN configuration is much more complex than that of say +Ethernet and may well amount to several dozens of parameters. Some of them +are "link-wide" while others are virtual circuit-specific. The same holds +true for WAN statistics which is by far more extensive and extremely useful +when troubleshooting WAN connections. Extending the ifconfig utility to suit +these needs may be possible, but does not seem quite reasonable. Therefore, a +WAN configuration utility and corresponding application programmer's interface +is needed for this purpose. + +Most of these problems are taken care of by this module. Its goal is to +provide a user with more-or-less standard look and feel for all WAN devices and +assist a WAN device driver writer by providing common services, such as: + + o User-level interface via /proc file system + o Centralized configuration + o Device management (setup, shutdown, etc.) + o Network interface management (dynamic creation/destruction) + o Protocol encapsulation/decapsulation -You can find the latest version of this software in /pub/linux directory on -Sangoma Technologies' anonymous FTP server (ftp.sangoma.com). +To ba able to use the Linux WAN Router you will also need a WAN Tools package +available from + + ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz + +where vX.Y.Z represent the wanpipe version number. For technical questions and/or comments please e-mail to ncorbic@sangoma.com. For general inquiries please contact Sangoma Technologies Inc. by Hotline: 1-800-388-2475 (USA and Canada, toll free) - Phone: (905) 474-1990 + Phone: (905) 474-1990 ext: 106 Fax: (905) 474-9223 E-mail: dm@sangoma.com (David Mandelstam) WWW: http://www.sangoma.com +INSTALLATION + +Please read the WanpipeForLinux.pdf manual on how to +install the WANPIPE tools and drivers properly. + + +After installing wanpipe package: /usr/local/wanrouter/doc. +On the ftp.sangoma.com : /linux/current_wanpipe/doc + COPYRIGHT AND LICENSING INFORMATION @@ -47,7 +115,7 @@ ACKNOWLEDGEMENTS This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed -by Sangoma Technologies Inc. for Linux 2.2.x. Success of the WANPIPE +by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE together with the next major release of Linux kernel in summer 1996 commanded adequate changes to the WANPIPE code to take full advantage of new Linux features. @@ -75,22 +143,33 @@ NEW IN THIS RELEASE -o Renamed startup script to wanrouter -o Option to turn off/on each router - separately -o New source directory /usr/lib/wanrouter -o New PPP driver -o X25 is not supported in this release + o Updated the WANCFG utility + Calls the pppconfig to configure the PPPD + for async connections. + + o Added the PPPCONFIG utility + Used to configure the PPPD dameon for the + WANPIPE Async PPP and standard serial port. + The wancfg calls the pppconfig to configure + the pppd. + + o Fixed the PCI autodetect feature. + The SLOT 0 was used as an autodetect option + however, some high end PC's slot numbers start + from 0. + o This release has been tested with the new backupd + daemon release. + PRODUCT COMPONENTS AND RELATED FILES -/etc: +/etc: (or user defined) wanpipe1.conf default router configuration file - wanrouter.rc meta-configuration file (used by the Setup script) /lib/modules/X.Y.Z/misc: wanrouter.o router kernel loadable module + af_wanpipe.o wanpipe api socket module /lib/modules/X.Y.Z/net: sdladrv.o Sangoma SDLA support module @@ -102,64 +181,93 @@ {name} reads WAN driver statistics /usr/sbin: - wanrouter router start-up script - wanconfig router configuration utility + wanrouter wanrouter start-up script + wanconfig wanrouter configuration utility sdladump WANPIPE adapter memory dump utility fpipemon Monitor for Frame Relay cpipemon Monitor for Cisco HDLC + ppipemon Monitor for PPP + xpipemon Monitor for X25 + wpkbdmon WANPIPE keyboard led monitor/debugger -/usr/lib/wanrouter: +/usr/local/wanrouter: README this file COPYING GNU General Public License Setup installation script - Configure configuration script Filelist distribution definition file + wanrouter.rc meta-configuration file + (used by the Setup and wanrouter script) -/usr/lib/wanrouter/doc: - WANPIPE_USER_MANUAL.txt WAN Router User's Manual - WANPIPE_CONFIG.txt WAN Configuration Manual - -/usr/lib/wanrouter/interfaces: - * interface configuration files (TCP/IP configuration) - -/usr/lib/wanrouter/patches: - wanrouter-22.gz patch for Linux kernel 2.2.10 and 2.2.11 - (compatible for all 2.2.X kernels) - wanrouter-20.gz patch for Linux kernel 2.0.36 +/usr/local/wanrouter/doc: + wanpipeForLinux.pdf WAN Router User's Manual - Fix_2.2.11.gz patch to fix the 2.2.11 kernel so other patches - can be applied properly. +/usr/local/wanrouter/patches: + wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13. + wanrouter-v2214.gz patch for Linux kernel 2.2.14. + wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17. + wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up. + wanrouter-v240.gz patch for Linux kernel 2.4.0. + wanrouter-v242.gz patch for Linux kernel 2.4.2 and up. + wanrouter-v2034.gz patch for Linux kernel 2.0.34 + wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up. + +/usr/local/wanrouter/patches/kdrivers: + Sources of the latest WANPIPE device drivers. + These are used to UPGRADE the linux kernel to the newest + version if the kernel source has already been pathced with + WANPIPE drivers. -/usr/lib/wanrouter/samples: +/usr/local/wanrouter/samples: interface sample interface configuration file wanpipe1.cpri CHDLC primary port wanpipe2.csec CHDLC secondary port wanpipe1.fr Frame Relay protocol wanpipe1.ppp PPP protocol ) + wanpipe1.asy CHDLC ASYNC protocol + wanpipe1.x25 X25 protocol + wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon) + wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon) wanrouter.rc sample meta-configuration file -/usr/lib/wanrouter/src: - * wan-tools source code +/usr/local/wanrouter/util: + * wan-tools utilities source code + +/usr/local/wanrouter/api/x25: + * x25 api sample programs. +/usr/local/wanrouter/api/chdlc: + * chdlc api sample programs. +/usr/local/wanrouter/api/fr: + * fr api sample programs. +/usr/local/wanrouter/config/wancfg: + wancfg WANPIPE GUI configuration program. + Creates wanpipe#.conf files. +/usr/local/wanrouter/config/cfgft1: + cfgft1 GUI CSU/DSU configuration program. /usr/include/linux: wanrouter.h router API definitions wanpipe.h WANPIPE API definitions sdladrv.h SDLA support module API definitions sdlasfm.h SDLA firmware module definitions + if_wanpipe.h WANPIPE Socket definitions + if_wanpipe_common.h WANPIPE Socket/Driver common definitions. + sdlapci.h WANPIPE PCI definitions + -/usr/src/linux/net/router: - * router source code +/usr/src/linux/net/wanrouter: + * wanrouter source code /var/log: - wanrouter router start-up log (created by the Setup script) + wanrouter wanrouter start-up log (created by the Setup script) -/var/lock: - wanrouter router lock file (created by the Setup script) +/var/lock: (or /var/lock/subsys for RedHat) + wanrouter wanrouter lock file (created by the Setup script) -/usr/lib/wanrouter/wanpipe: +/usr/local/wanrouter/firmware: fr514.sfm Frame relay firmware for Sangoma S508/S514 card cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards + x25_508.sfm X25 Firmware for Sangoma S508 card. REVISION HISTORY @@ -228,7 +336,7 @@ creating applications using BiSync streaming. -2.0.5 Aug 04, 1999 CHDLC initialization bug fix. +2.0.5 Aug 04, 1999 CHDLC initializatin bug fix. PPP interrupt driven driver: Fix to the PPP line hangup problem. New PPP firmware @@ -241,17 +349,274 @@ Streaming HDLC API has been taken out. Available as a patch. -2.0.6 Aug 17, 1999 Increased debugging in startup scripts - Fixed installation bugs from 2.0.5 +2.0.6 Aug 17, 1999 Increased debugging in statup scripts + Fixed insallation bugs from 2.0.5 Kernel patch works for both 2.2.10 and 2.2.11 kernels. There is no functional difference between the two packages 2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE. - o Fixed a memory leak for X25API + o Fixed a memeory leak for X25API o Updated the X25API code for 2.2.X kernels. o Improved NEM handling. 2.1.0 Oct 25, 1999 o New code for S514 PCI Card o New CHDLC and Frame Relay drivers o PPP and X25 are not supported in this release + +2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards + +2.1.3 Apr 06, 2000 o Socket based x25api + o Socket based chdlc api + o Socket based fr api + o Dual Port Receive only CHDLC support. + o Asynchronous CHDLC support (Secondary Port) + o cfgft1 GUI csu/dsu configurator + o wancfg GUI configuration file + configurator. + o Architectual directory changes. + +beta-2.1.4 Jul 2000 o Dynamic interface configuration: + Network interfaces reflect the state + of protocol layer. If the protocol becomes + disconnected, driver will bring down + the interface. Once the protocol reconnects + the interface will be brought up. + + Note: This option is turned off by default. + + o Dynamic wanrouter setup using 'wanconfig': + wanconfig utility can be used to + shutdown,restart,start or reconfigure + a virtual circuit dynamically. + + Frame Relay: Each DLCI can be: + created,stopped,restarted and reconfigured + dynamically using wanconfig. + + ex: wanconfig card wanpipe1 dev wp1_fr16 up + + o Wanrouter startup via command line arguments: + wanconfig also supports wanrouter startup via command line + arguments. Thus, there is no need to create a wanpipe#.conf + configuration file. + + o Socket based x25api update/bug fixes. + Added support for LCN numbers greater than 255. + Option to pass up modem messages. + Provided a PCI IRQ check, so a single S514 + card is guaranteed to have a non-sharing interrupt. + + o Fixes to the wancfg utility. + o New FT1 debugging support via *pipemon utilities. + o Frame Relay ARP support Enabled. + +beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix. + o Added the Multi-Port PPP + Updated utilites for the Multi-Port PPP. + +2.1.4 Aut 2000 + o In X25API: + Maximum packet an application can send + to the driver has been extended to 4096 bytes. + + Fixed the x25 startup bug. Enable + communications only after all interfaces + come up. HIGH SVC/PVC is used to calculate + the number of channels. + Enable protocol only after all interfaces + are enabled. + + o Added an extra state to the FT1 config, kernel module. + o Updated the pipemon debuggers. + + o Blocked the Multi-Port PPP from running on kernels + 2.2.16 or greater, due to syncppp kernel module + change. + +beta1-2.1.5 Nov 15 2000 + o Fixed the MulitPort PPP Support for kernels 2.2.16 and above. + 2.2.X kernels only + + o Secured the driver UDP debugging calls + - All illegal netowrk debugging calls are reported to + the log. + - Defined a set of allowed commands, all other denied. + + o Cpipemon + - Added set FT1 commands to the cpipemon. Thus CSU/DSU + configuraiton can be performed using cpipemon. + All systems that cannot run cfgft1 GUI utility should + use cpipemon to configure the on board CSU/DSU. + + + o Keyboard Led Monitor/Debugger + - A new utilty /usr/sbin/wpkbdmon uses keyboard leds + to convey operatinal statistic information of the + Sangoma WANPIPE cards. + NUM_LOCK = Line State (On=connected, Off=disconnected) + CAPS_LOCK = Tx data (On=transmitting, Off=no tx data) + SCROLL_LOCK = Rx data (On=receiving, Off=no rx data + + o Hardware probe on module load and dynamic device allocation + - During WANPIPE module load, all Sangoma cards are probed + and found information is printed in the /var/log/messages. + - If no cards are found, the module load fails. + - Appropriate number of devices are dynamically loaded + based on the number of Sangoma cards found. + + Note: The kernel configuraiton option + CONFIG_WANPIPE_CARDS has been taken out. + + o Fixed the Frame Relay and Chdlc network interfaces so they are + compatible with libpcap libraries. Meaning, tcpdump, snort, + ethereal, and all other packet sniffers and debuggers work on + all WANPIPE netowrk interfaces. + - Set the network interface encoding type to ARPHRD_PPP. + This tell the sniffers that data obtained from the + network interface is in pure IP format. + Fix for 2.2.X kernels only. + + o True interface encoding option for Frame Relay and CHDLC + - The above fix sets the network interface encoding + type to ARPHRD_PPP, however some customers use + the encoding interface type to determine the + protocol running. Therefore, the TURE ENCODING + option will set the interface type back to the + original value. + + NOTE: If this option is used with Frame Relay and CHDLC + libpcap library support will be broken. + i.e. tcpdump will not work. + Fix for 2.2.x Kernels only. + + o Ethernet Bridgind over Frame Relay + - The Frame Relay bridging has been developed by + Kristian Hoffmann and Mark Wells. + - The Linux kernel bridge is used to send ethernet + data over the frame relay links. + For 2.2.X Kernels only. + + o Added extensive 2.0.X support. Most new features of + 2.1.5 for protocols Frame Relay, PPP and CHDLC are + supported under 2.0.X kernels. + +beta1-2.2.0 Dec 30 2000 + o Updated drivers for 2.4.X kernels. + o Updated drivers for SMP support. + o X25API is now able to share PCI interrupts. + o Took out a general polling routine that was used + only by X25API. + o Added appropriate locks to the dynamic reconfiguration + code. + o Fixed a bug in the keyboard debug monitor. + +beta2-2.2.0 Jan 8 2001 + o Patches for 2.4.0 kernel + o Patches for 2.2.18 kernel + o Minor updates to PPP and CHLDC drivers. + Note: No functinal difference. + +beta3-2.2.9 Jan 10 2001 + o I missed the 2.2.18 kernel patches in beta2-2.2.0 + release. They are included in this release. + +Stable Release +2.2.0 Feb 01 2001 + o Bug fix in wancfg GUI configurator. + The edit function didn't work properly. + + +bata1-2.2.1 Feb 09 2001 + o WANPIPE TTY Driver emulation. + Two modes of operation Sync and Async. + Sync: Using the PPPD daemon, kernel SyncPPP layer + and the Wanpipe sync TTY driver: a PPP protocol + connection can be established via Sangoma adapter, over + a T1 leased line. + + The 2.4.0 kernel PPP layer supports MULTILINK + protocol, that can be used to bundle any number of Sangoma + adapters (T1 lines) into one, under a single IP address. + Thus, efficiently obtaining multiple T1 throughput. + + NOTE: The remote side must also implement MULTILINK PPP + protocol. + + Async:Using the PPPD daemon, kernel AsyncPPP layer + and the WANPIPE async TTY driver: a PPP protocol + connection can be established via Sangoma adapter and + a modem, over a telephone line. + + Thus, the WANPIPE async TTY driver simulates a serial + TTY driver that would normally be used to interface the + MODEM to the linux kernel. + + o WANPIPE PPP Backup Utility + This utility will monitor the state of the PPP T1 line. + In case of failure, a dial up connection will be established + via pppd daemon, ether via a serial tty driver (serial port), + or a WANPIPE async TTY driver (in case serial port is unavailable). + + Furthermore, while in dial up mode, the primary PPP T1 link + will be monitored for signs of life. + + If the PPP T1 link comes back to life, the dial up connection + will be shutdown and T1 line re-established. + + + o New Setup installation script. + Option to UPGRADE device drivers if the kernel source has + already been patched with WANPIPE. + + Option to COMPILE WANPIPE modules against the currently + running kernel, thus no need for manual kernel and module + re-compilatin. + + o Updates and Bug Fixes to wancfg utility. + +bata2-2.2.1 Feb 20 2001 + + o Bug fixes to the CHDLC device drivers. + The driver had compilation problmes under kernels + 2.2.14 or lower. + + o Bug fixes to the Setup installation script. + The device drivers compilation options didn't work + properly. + + o Update to the wpbackupd daemon. + Optimized the cross-over times, between the primary + link and the backup dialup. + +beta3-2.2.1 Mar 02 2001 + o Patches for 2.4.2 kernel. + + o Bug fixes to util/ make files. + o Bug fixes to the Setup installation script. + + o Took out the backupd support and made it into + as separate package. + +beta4-2.2.1 Mar 12 2001 + + o Fix to the Frame Relay Device driver. + IPSAC sends a packet of zero length + header to the frame relay driver. The + driver tries to push its own 2 byte header + into the packet, which causes the driver to + crash. + + o Fix the WANPIPE re-configuration code. + Bug was found by trying to run the cfgft1 while the + interface was already running. + + o Updates to cfgft1. + Writes a wanpipe#.cfgft1 configuration file + once the CSU/DSU is configured. This file can + holds the current CSU/DSU configuration. + + + >>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/nmi_watchdog.txt linux.ac/Documentation/nmi_watchdog.txt --- linux.vanilla/Documentation/nmi_watchdog.txt Mon Aug 21 16:57:35 2000 +++ linux.ac/Documentation/nmi_watchdog.txt Tue Apr 3 17:54:28 2001 @@ -1,19 +1,27 @@ -Is your SMP system locking up unpredictably? No keyboard activity, just +Is your ix86 system locking up unpredictably? No keyboard activity, just a frustrating complete hard lockup? Do you want to help us debugging such lockups? If all yes then this document is definitely for you. -on Intel SMP hardware there is a feature that enables us to generate -'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get -executed even if the system is otherwise locked up hard) This can be -used to debug hard kernel lockups. By executing periodic NMI interrupts, -the kernel can monitor whether any CPU has locked up, and print out -debugging messages if so. You can enable/disable the NMI watchdog at boot -time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant -lilo.conf entry: +On Intel and similar ix86 type hardware there is a feature that enables +us to generate 'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt +which get executed even if the system is otherwise locked up hard). +This can be used to debug hard kernel lockups. By executing periodic +NMI interrupts, the kernel can monitor whether any CPU has locked up, +and print out debugging messages if so. You must enable the NMI +watchdog at boot time with the 'nmi_watchdog=n' boot parameter. Eg. +the relevant lilo.conf entry: append="nmi_watchdog=1" +For SMP machines and UP machines with an IO-APIC use nmi_watchdog=1. +For UP machines without an IO-APIC use nmi_watchdog=2, this only works +for some processor types. If in doubt, boot with nmi_watchdog=1 and +check the NMI count in /proc/interrupts; if the count is zero then +reboot with nmi_watchdog=2 and check the NMI count. If it is still +zero then log a problem, you probably have a processor that needs to be +added to the nmi code. + A 'lockup' is the following scenario: if any CPU in the system does not execute the period local timer interrupt for more than 5 seconds, then the NMI handler generates an oops and kills the process. This @@ -24,8 +32,9 @@ cannot even accept NMI interrupts, or the crash has made the kernel unable to print messages. -NOTE: currently the NMI-oopser is enabled unconditionally on x86 SMP -boxes. +NOTE: starting with 2.4.2-ac18 the NMI-oopser is disabled by default, +you have to enable it with a boot time parameter. Prior to 2.4.2-ac18 +the NMI-oopser is enabled unconditionally on x86 SMP boxes. [ feel free to send bug reports, suggestions and patches to Ingo Molnar or the Linux SMP mailing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parisc/00-INDEX linux.ac/Documentation/parisc/00-INDEX --- linux.vanilla/Documentation/parisc/00-INDEX Tue Dec 5 20:29:38 2000 +++ linux.ac/Documentation/parisc/00-INDEX Tue Apr 3 17:54:28 2001 @@ -1,10 +1,8 @@ 00-INDEX - this file. IODC.txt - - Documentation IODC + - Documentation for IODC debugging - some debugging hints for real-mode code -mm - - Documentation on parisc mm status registers - current/planned usage of registers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parisc/mm linux.ac/Documentation/parisc/mm --- linux.vanilla/Documentation/parisc/mm Tue Dec 5 20:29:38 2000 +++ linux.ac/Documentation/parisc/mm Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ - -The current state of Linux/PA-RISC mm is BROKEN. - -Someone needs to sit down and thoroughly rewrite all the cache flushing -macro definitions. Here are some of the problems, followed by what I -think needs to be done about them. - -(1) We're using fdce / fice everywhere. This has to stop (except in -the routines which flush the entire cache). The right instructions to -be using are fdc/fic. - -(2) fdc/fic will throw exceptions if the address they reference isn't -mapped. Therefore we need to check the page is mapped before flushing -(we're guaranteed not to have the page dirty if we don't have a software -mapping for it any longer, right?) - -(3) the flush macros are right now tunnelled down to one routine to flush -the data cache and one routine to flush the insn cache. this is wrong. -we should take hints from how we're called and optimise our routines -accordingly. - -(4) fdc/fic actually take space register arguments. fic takes an 3-bit sr -argument and fdc takes a 2-bit sr argument. right now, there's a lot of -pissing about with %sr1 and all the macros use %sr1. This is crazy. We -normally _know_ what's being referred to, and it's the current task. So -if we want to flush that, just use %sr3. If it happens to be kernel, -use %sr0 for fdc and %sr4 for fic. - -(5) we need to write flush_kernel_dcache_range and use it on kernel -addresses. all the macros are defined to work on the _current task's_ -virtual address space. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parisc/registers linux.ac/Documentation/parisc/registers --- linux.vanilla/Documentation/parisc/registers Tue Dec 5 20:29:38 2000 +++ linux.ac/Documentation/parisc/registers Tue Apr 3 17:54:28 2001 @@ -16,9 +16,9 @@ CR11 as specified by ABI CR14 (interruption vector) initialized to fault_vector CR15 (EIEM) initialized to all ones* -CR16 (Interval Timer) timer interrupt +CR16 (Interval Timer) read for cycle count/write starts Interval Tmr CR17-CR22 interruption parameters -CR23 (EIRR) read for pending interrupts +CR23 (EIRR) read for pending interrupts/write clears bits CR24 (TR 0) Kernel Space Page Directory Pointer CR25 (TR 1) User Space Page Directory Pointer CR26 (TR 2) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/parport.txt linux.ac/Documentation/parport.txt --- linux.vanilla/Documentation/parport.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/parport.txt Tue Apr 10 18:04:17 2001 @@ -174,7 +174,7 @@ peripherals. This is a port-wide setting, i.e. it applies to all devices on a particular port. -timeslice The number of miliseconds that a device driver is +timeslice The number of milliseconds that a device driver is allowed to keep a port claimed for. This is advisory, and driver can ignore it if it must. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/pm.txt linux.ac/Documentation/pm.txt --- linux.vanilla/Documentation/pm.txt Thu Oct 26 22:22:24 2000 +++ linux.ac/Documentation/pm.txt Tue Apr 10 18:04:17 2001 @@ -33,7 +33,7 @@ Go ahead and start both. If ACPI or APM is not available on your system the associated daemon will exit gracefully. - apmd: http://linuxcare.com.au/apm/ + apmd: http://worldvisions.ca/~apenwarr/apmd/ acpid: http://phobos.fs.tum.de/acpi/ Driver Interface diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/rtc.txt linux.ac/Documentation/rtc.txt --- linux.vanilla/Documentation/rtc.txt Thu Jan 4 20:50:17 2001 +++ linux.ac/Documentation/rtc.txt Sun Apr 22 01:36:43 2001 @@ -89,7 +89,7 @@ #include #include -void main(void) { +int main(void) { int i, fd, retval, irqcount = 0; unsigned long tmp, data; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/3270.ChangeLog linux.ac/Documentation/s390/3270.ChangeLog --- linux.vanilla/Documentation/s390/3270.ChangeLog Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/3270.ChangeLog Sat Apr 14 01:14:27 2001 @@ -0,0 +1,15 @@ +ChangeLog for the UTS Global 3270-support patch + +Feb 6, 2001: + * This changelog is new + * tub3270 now supports 3270 console: + Specify y for CONFIG_3270 and y for CONFIG_3270_CONSOLE. + Support for 3215 will not appear if 3270 console support + is chosen. + NOTE: The default is 3270 console support, NOT 3215. + * the components are remodularized: added source modules are + tubttybld.c and tubttyscl.c, for screen-building code and + scroll-timeout code. + * tub3270 source for this (2.4.0) version is #ifdeffed to + build with both 2.4.0 and 2.2.16.2. + * color support and minimal other ESC-sequence support is added. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/3270.txt linux.ac/Documentation/s390/3270.txt --- linux.vanilla/Documentation/s390/3270.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/3270.txt Sat Apr 14 01:14:27 2001 @@ -0,0 +1,280 @@ +IBM 3270 Display System support + +This file describes the driver that supports local channel attachment +of IBM 3270 devices. It consists of three sections: + * Introduction + * Installation + * Operation + + +INTRODUCTION. + +This paper describes installing and operating 3270 devices under +Linux/390. A 3270 device is a block-mode rows-and-columns terminal of +which I'm sure hundreds of millions were sold by IBM and clonemakers +twenty and thirty years ago. + +You may have 3270s in-house and not know it. If you're using the +VM-ESA operating system, define a 3270 to your virtual machine by using +the command "DEF GRAF " This paper presumes you will be +defining four 3270s with the CP/CMS commands + + DEF GRAF 620 + DEF GRAF 621 + DEF GRAF 622 + DEF GRAF 623 + +Your network connection from VM-ESA allows you to use x3270, tn3270, or +another 3270 emulator, started from an xterm window on your PC or +workstation. With the DEF GRAF command, an application such as xterm, +and this Linux-390 3270 driver, you have another way of talking to your +Linux box. + +This paper covers installation of the driver and operation of a +dialed-in x3270. + + +HELP !!! + +The device name of e.g. /dev/3270/tty620 noted below is at variance +with "standard" Linux device names. What should it be? The portion +"/dev/3270" was recommended by H. Peter Anvin, maintainer of the +official Linux major-numbers list; the portion "tty620" was recommended +by me. Please send your thoughts on this issue at least to me at +rbh00@utsglobal.com. Even if you think it's okay as is, please let me +know. Thanks. + + +INSTALLATION. + +You install the driver by installing a patch, doing a kernel build, and +running the configuration script (config3270.sh, in this directory). + +WARNING: If you are using 3270 console support, you must rerun the +configuration script every time you change the console's address (perhaps +by using the condev= parameter in silo's /boot/parmfile). More precisely, +you should rerun the configuration script every time your set of 3270s, +including the console 3270, changes subchannel identifier relative to +one another. ReIPL as soon as possible after running the configuration +script and the resulting /tmp/mkdev3270. + +If you have chosen to make tub3270 a module, you add a line to +/etc/modules.conf. If you are working on a VM virtual machine, you +can use DEF GRAF to define virtual 3270 devices. If you generate 3270 +console support, the driver automatically converts your console at boot +time to a 3270 if it is a 3215. + +In brief, these are the steps: + 1. Install the tub3270 patch + 2. (If a module) add a line to /etc/modules.conf + 3. (If VM) define devices with DEF GRAF + 4. Reboot + 5. Configure + +To test that everything works, assuming VM and x3270, + 1. Bring up an x3270 window. + 2. Use the DIAL command in that window. + 3. You should immediately see a Linux login screen. + +Here are the installation steps in detail: + + 0. Retrieve the patch file via anonymous ftp from + ftp://ftp.utsglobal.com/pub/tub3270. The patch is designed + to apply smoothly to an IBM 2.4.0 system with no other + UTS-Global patches applied. We know of some easily resolvable + conflicts between this and other of our patches. + + 1. Apply the patch. Then do + make oldconfig + (Reply "y" or "m" for CONFIG_3270; if "y", + reply "y" or "n" for CONFIG_3270_CONSOLE) + make dep + make image + make modules + make modules_install + + + 2. (Perform this step only if you have configured tub3270 as a + module.) Add a line to /etc/modules.conf to automatically + load the driver when it's needed. With this line added, + you will see login prompts appear on your 3270s as soon as + boot is complete (or with emulated 3270s, as soon as you dial + into your vm guest using the command "DIAL "). + Since the line-mode major number is 212, the line to add to + /etc/modules.conf should be: + alias char-major-212 tub3270 + + 3. Define graphic devices to your vm guest machine, if you + haven't already. Define them before you reboot (reipl): + DEFINE GRAF 620 + DEFINE GRAF 621 + DEFINE GRAF 622 + DEFINE GRAF 623 + + 4. Reboot. The reboot process scans hardware devices, including + 3270s, and this enables the tub3270 driver once loaded to respond + correctly to the configuration requests of the next step. If + you have chosen 3270 console support, your console now behaves + as a 3270, not a 3215. + + 5. Run the 3270 configuration script config3270. It is + distributed in this same directory, Documentation/s390, as + config3270.sh. Inspect the output script it produces, + /tmp/mkdev3270, and then run that script. This will create the + necessary character special device files and make the necessary + changes to /etc/inittab. Then notify /sbin/init that /etc/inittab + has changed, by issuing the telinit command with the q operand: + cd /usr/src/linux/Documentation/s390 + sh config3270.sh + sh /tmp/mkdev3270 + telinit q + This should be sufficient for your first time. If your 3270 + configuration has changed and you're reusing config3270, you + should follow these steps: + Change 3270 configuration + Reboot + Run config3270 and /tmp/mkdev3270 + Reboot + +Here are the testing steps in detail: + + 1. Bring up an x3270 window, or use an actual hardware 3278 or + 3279, or use the 3270 emulator of your choice. You would be + running the emulator on your PC or workstation. You would use + the command, for example, + x3270 vm-esa-domain-name & + if you wanted a 3278 Model 4 with 43 rows of 80 columns, the + default model number. The driver does not take advantage of + extended attributes. + + The screen you should now see contains a VM logo with input + lines near the bottom. Use TAB to move to the bottom line, + probably labeled "COMMAND ===>". + + 2. Use the DIAL command instead of the LOGIN command to connect + to one of the virtual 3270s you defined with the DEF GRAF + commands: + dial my-vm-guest-name + + 3. You should immediately see a login prompt from your + Linux-390 operating system. If that does not happen, you would + see instead the line "DIALED TO my-vm-guest-name 0620". + + To troubleshoot: do these things. + + A. Is the driver loaded? Use the lsmod command (no operands) + to find out. Probably it isn't. Try loading it manually, with + the command "insmod tub3270". Does that command give error + messages? Ha! There's your problem. + + B. Is the /etc/inittab file modified as in installation step 3 + above? Use the grep command to find out; for instance, issue + "grep 3270 /etc/inittab". Nothing found? There's your + problem! + + C. Are the device special files created, as in installation + step 2 above? Use the ls -l command to find out; for instance, + issue "ls -l /dev/3270/tty620". The output should start with the + letter "c" meaning character device and should contain "212, 1" + just to the left of the device name. No such file? no "c"? + Wrong major number? Wrong minor number? There's your + problem! + + D. Do you get the message + "HCPDIA047E my-vm-guest-name 0620 does not exist"? + If so, you must issue the command "DEF GRAF 620" from your VM + 3215 console and then reboot the system. + + + +OPERATION. + +The driver defines three areas on the 3270 screen: the log area, the +input area, and the status area. + +The log area takes up all but the bottom two lines of the screen. The +driver writes terminal output to it, starting at the top line and going +down. When it fills, the status area changes from "Linux Running" to +"Linux More...". After a scrolling timeout of (default) 5 sec, the +screen clears and more output is written, from the top down. + +The input area extends from the beginning of the second-to-last screen +line to the start of the status area. You type commands in this area +and hit ENTER to execute them. + +The status area initializes to "Linux Running" to give you a warm +fuzzy feeling. When the log area fills up and output awaits, it +changes to "Linux More...". At this time you can do several things or +nothing. If you do nothing, the screen will clear in (default) 5 sec +and more output will appear. You may hit ENTER with nothing typed in +the input area to toggle between "Linux More..." and "Linux Holding", +which indicates no scrolling will occur. (If you hit ENTER with "Linux +Running" and nothing typed, the application receives a newline.) + +You may change the scrolling timeout value. For example, the following +command line: + echo scrolltime=60 > /proc/tty/driver/tty3270 +changes the scrolling timeout value to 60 sec. Set scrolltime to 0 if +you wish to prevent scrolling entirely. + +Other things you may do when the log area fills up are: hit PA2 to +clear the log area and write more output to it, or hit CLEAR to clear +the log area and the input area and write more output to the log area. + +Some of the Program Function (PF) and Program Attention (PA) keys are +preassigned special functions. The ones that are not yield an alarm +when pressed. + +PA1 causes a SIGINT to the currently running application. You may do +the same thing from the input area, by typing "^C" and hitting ENTER. + +PA2 causes the log area to be cleared. If output awaits, it is then +written to the log area. + +PF3 causes an EOF to be received as input by the application. You may +cause an EOF also by typing "^D" and hitting ENTER. + +No PF key is preassigned to cause a job suspension, but you may cause a +job suspension by typing "^Z" and hitting ENTER. You may wish to +assign this function to a PF key. To make PF7 cause job suspension, +execute the command: + echo pf7=^z > /proc/tty/driver/tty3270 + +If the input you type does not end with the two characters "^n", the +driver appends a newline character and sends it to the tty driver; +otherwise the driver strips the "^n" and does not append a newline. +The IBM 3215 driver behaves similarly. + +Pf10 causes the most recent command to be retrieved from the tube's +command stack (default depth 20) and displayed in the input area. You +may hit PF10 again for the next-most-recent command, and so on. A +command is entered into the stack only when the input area is not made +invisible (such as for password entry) and it is not identical to the +current top entry. PF10 rotates backward through the command stack; +PF11 rotates forward. You may assign the backward function to any PF +key (or PA key, for that matter), say, PA3, with the command: + echo -e pa3=\\033k > /proc/tty/driver/tty3270 +This assigns the string ESC-k to PA3. Similarly, the string ESC-j +performs the forward function. (Rationale: In bash with vi-mode line +editing, ESC-k and ESC-j retrieve backward and forward history. +Suggestions welcome.) + +Is a stack size of twenty commands not to your liking? Change it on +the fly. To change to saving the last 100 commands, execute the +command: + echo recallsize=100 > /proc/tty/driver/tty3270 + +Have a command you issue frequently? Assign it to a PF or PA key! Use +the command + echo pf24="mkdir foobar; cd foobar" > /proc/tty/driver/tty3270 +to execute the commands mkdir foobar and cd foobar immediately when you +hit PF24. Want to see the command line first, before you execute it? +Use the -n option of the echo command: + echo -n pf24="mkdir foo; cd foo" > /proc/tty/driver/tty3270 + + + +Happy testing! I welcome any and all comments about this document, the +driver, etc etc. + +Dick Hitt diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/Debugging390.txt linux.ac/Documentation/s390/Debugging390.txt --- linux.vanilla/Documentation/s390/Debugging390.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/Debugging390.txt Thu Apr 12 11:48:05 2001 @@ -0,0 +1,2439 @@ + + Debugging on Linux for s/390 & zSeries + by + Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + Best viewed with fixed width fonts + +Overview of Document: +===================== +This document is intended to give an good overview of how to debug +Linux for s/390 & zSeries it isn't intended as a complete reference & not a +tutorial on the fundamentals of C & assembly, it dosen't go into +390 IO in any detail. It is intended to compliment the documents in the +reference section below & any other worthwhile references you get. + +It is intended like the Enterprise Systems Architecture/390 Reference Summary +to be printed out & used as a quick cheat sheet self help style reference when +problems occur. + +Contents +======== +Register Set +Address Spaces on Intel Linux +Address Spaces on Linux for s/390 & zSeries +The Linux for s/390 & zSeries Kernel Task Structure +Register Usage & Stackframes on Linux for s/390 & zSeries +A sample program with comments +Compiling programs for debugging on Linux for s/390 & zSeries +Figuring out gcc compile errors +Debugging Tools +objdump +strace +Performance Debugging +Debugging under VM +s/390 & zSeries IO Overview +Debugging IO on s/390 & zSeries under VM +GDB on s/390 & zSeries +Stack chaining in gdb by hand +Examining core dumps +ldd +Debugging modules +The proc file system +Starting points for debugging scripting languages etc. +Tools soon to be available +SysRq +References + +Register Set +============ +The current architectures have the following registers. + +16 General propose registers, 32 bit on s/390 64 bit on zSeries, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. + +16 Control registers, 32 bit on s/390 64 bit on zSeries, ( cr0-cr15 kernel usage only ) used for memory managment, +interrupt control,debugging control etc. + +16 Access registers ( ar0-ar15 ) 32 bit on s/390 & zSeries +not used by normal programs but potentially could +be used as temporary storage. Their main purpose is their 1 to 1 +association with general purpose registers and are used in +the kernel for copying data between kernel & user address spaces. +Access register 0 ( & access register 1 on z/Series ( needs 64 bit pointer ) ) +is currently used by the pthread library as a pointer to +the current running threads private area. + +16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating +point format compliant on G5 upwards & a Floating point control reg (FPC) +4 64 bit registers (fp0,fp2,fp4 & fp6) HFP only on older machines. +Note: +Linux (currently) always uses IEEE & emulates G5 IEEE format on older machines, +( provided the kernel is configured for this ). + + +The PSW is the most important register on the machine it +is 64 bit on s/390 & 128 bit on zSeries & serves the roles of +a program counter (pc), condition code register,memory space designator. +In IBM standard notation I am counting bit 0 as the MSB. +It has several advantages over a normal program counter +in that you can change address translation & program counter +in a single instruction. To change address translation, +e.g. switching address translation off requires that you +have a logical=physical mapping for the address you are +currently running at. + + Bit Value +s/390 zSeries +0 0 Reserved ( must be 0 ) otherwise specification exception occurs. + +1 1 Program Event Recording 1 PER enabled, + PER is used to facilititate debugging e.g. single stepping. + +2-4 2-4 Reserved ( must be 0 ). + +5 5 Dynamic address translation 1=DAT on. + +6 6 Input/Output interrupt Mask + +7 7 External interrupt Mask used primarily for interprocessor signalling & + clock interupts. + +8-11 8-11 PSW Key used for complex memory protection mechanism not used under linux + +12 12 1 on s/390 0 on zSeries + +13 13 Machine Check Mask 1=enable machine check interrupts + +14 14 Wait State set this to 1 to stop the processor except for interrupts & give + time to other LPARS used in CPU idle in the kernel to increase overall + usage of processor resources. + +15 15 Problem state ( if set to 1 certain instructions are disabled ) + all linux user programs run with this bit 1 + ( useful info for debugging under VM ). + +16-17 16-17 Address Space Control + + 00 Primary Space Mode when DAT on + The linux kernel currently runs in this mode, CR1 is affiliated with + this mode & points to the primary segment table origin etc. + + 01 Access register mode this mode is used in functions to + copy data between kernel & user space. + + 10 Secondary space mode not used in linux however CR7 the + register affiliated with this mode is & this & normally + CR13=CR7 to allow us to copy data between kernel & user space. + We do this as follows: + We set ar2 to 0 to designate its + affiliated gpr ( gpr2 )to point to primary=kernel space. + We set ar4 to 1 to designate its + affiliated gpr ( gpr4 ) to point to secondary=home=user space + & then essentially do a memcopy(gpr2,gpr4,size) to + copy data between the address spaces, the reason we use home space for the + kernel & don't keep secondary space free is that code will not run in + secondary space. + + 11 Home Space Mode all user programs run in this mode. + it is affiliated with CR13. + +18-19 18-19 Condition codes (CC) + +20 20 Fixed point overflow mask if 1=FPU exceptions for this event + occur ( normally 0 ) + +21 21 Decimal overflow mask if 1=FPU exceptions for this event occur + ( normally 0 ) + +22 22 Exponent underflow mask if 1=FPU exceptions for this event occur + ( normally 0 ) + +23 23 Significance Mask if 1=FPU exceptions for this event occur + ( normally 0 ) + +24-31 24-30 Reserved Must be 0. + + 31 Extended Addressing Mode + 32 Basic Addressing Mode + Used to set addressing mode + PSW 31 PSW 32 + 0 0 24 bit + 0 1 31 bit + 1 1 64 bit + +32 1=31 bit addressing mode 0=24 bit addressing mode (for backward + compatibility ), linux always runs with this bit set to 1 + +33-64 Instruction address. + 33-63 Reserved must be 0 + 64-127 Address + In 24 bits mode bits 64-103=0 bits 104-127 Address + In 31 bits mode bits 64-96=0 bits 97-127 Address + Note: unlike 31 bit mode on s/390 bit 96 must be zero + when loading the address with LPSWE otherwise a + specification exception occurs, LPSW is fully backward + compatible. + + +Prefix Page +----------- +This per cpu memory area is too intimately tied to the processor not to mention. +It exists between the real addresses 0-4096 on the processor & is exchanged +with a page in absolute storage by the set prefix instruction in linux'es startup. +This page different on each processor. +Bytes 0-512 ( 200 hex ) are used by the processor itself for holding such +information as exception indications & entry points for exceptions. +Bytes after 0xc00 hex are used by linux for per processor globals. +The closest thing to this on traditional architectures is the interrupt +vector table. This is a good thing & does simplify some of the kernel coding +however it means that we now cannot catch stray NULL pointers in the +kernel without hard coded checks. + + + +Address Spaces on Intel Linux +============================= + +The traditional Intel Linux is approximately mapped as follows forgive +the ascii art. +0xFFFFFFFF 4GB Himem ***************** + * * + * Kernel Space * + * * + ***************** **************** +User Space Himem (typically 0xC0000000 3GB )* User Stack * * * + ***************** * * + * Shared Libs * * Next Process * + ***************** * to * + * * <== * Run * <== + * User Program * * * + * Data BSS * * * + * Text * * * + * Sections * * * +0x00000000 ***************** **************** + +Now it is easy to see that on Intel it is quite easy to recognise a kernel address +as being one greater than user space himem ( in this case 0xC0000000). +& addresses of less than this are the ones in the current running program on this +processor ( if an smp box ). +If using the virtual machine ( VM ) as a debugger it is quite difficult to +know which user process is running as the address space you are looking at +could be from any process in the run queue. +Thankfully you normally get lucky as address spaces don't overlap that & +you can recognise the code at by cross referencing with a dump made by objdump +( more about that later ). + +The limitation of Intels addressing technique is that the linux +kernel uses a very simple real address to virtual addressing technique +of Real Address=Virtual Address-User Space Himem. +This means that on Intel the kernel linux can typically only address +Himem=0xFFFFFFFF-0xC0000000=1GB & this is all the RAM these machines +can typically use. +They can lower User Himem to 2GB or lower & thus be +able to use 2GB of RAM however this shrinks the maximum size +of User Space from 3GB to 2GB they have a no win limit of 4GB unless +they go to 64 Bit. + + +On 390 our limitations & strengths make us slightly different. +For backward compatibility we are only allowed use 31 bits (2GB) +of our 32 bit addresses,however, we use entirely separate address +spaces for the user & kernel. + +This means we can support 2GB of non Extended RAM, & more +with the Extended memory managment swap device & 64 Bit +when it comes along. + + +Address Spaces on Linux for S390 +================================ + +Our addressing scheme is as follows + + +Himem 0x7fffffff 2GB on s/390 ***************** **************** +2^64 bytes on zSeries * User Stack * * * + ***************** * * + * Shared Libs * * * + ***************** * * + * * * Kernel * + * User Program * * * + * Data BSS * * * + * Text * * * + * Sections * * * +0x00000000 ***************** **************** + +This also means that we need to look at the PSW problem state bit +or the addressing mode to decide whether we are looking at +user or kernel space. + +The Linux for s/390 & zSeries Kernel Task Structure +=================================================== +Each process/thread under Linux for S390 has its own kernel task_struct +defined in linux/include/linux/sched.h +The S390 on initialisation & resuming of a process on a cpu sets +the __LC_KERNEL_STACK variable in the spare prefix area for this cpu +( which we use for per processor globals). + +The kernel stack pointer is intimately tied with the task stucture for +each processor as follows. + + s/390 + ************************ + * 1 page kernel stack * + * ( 4K ) * + ************************ + * 1 page task_struct * + * ( 4K ) * +8K aligned ************************ + + zSeries + ************************ + * 2 page kernel stack * + * ( 8K ) * + ************************ + * 2 page task_struct * + * ( 8K ) * +16K aligned ************************ + +What this means is that we don't need to dedicate any register or global variable +to point to the current running process & can retrieve it with the following +very simple construct for s/390 & one very similar for zSeries. + +static inline struct task_struct * get_current(void) +{ + struct task_struct *current; + __asm__("lhi %0,-8192\n\t" + "nr %0,15" + : "=r" (current) ); + return current; +} + +i.e. just anding the current kernel stack pointer with the mask -8192. +Thankfully because Linux dosen't have support for nested IO interrupts +& our devices have large buffers can survive interrupts being shut for +short amounts of time we don't need a separate stack for interrupts. + + + + +Register Usage & Stackframes on Linux for s/390 & zSeries +========================================================= +Overview: +--------- +This is the code that gcc produces at the top & the bottom of +each function, it usually is fairly consistent & similar from +function to function & if you know its layout you can probalby +make some headway in finding the ultimate cause of a problem +after a crash without a source level debugger. + +Note: To follow stackframes requires a knowledge of C or Pascal & +limited knowledge of one assembly language. + +It should be noted that there are some differences between the +s/390 & zSeries stack layouts as the zSeries stack layout didn't have +to maintain compatibility with older linkage formats. + +Glossary: +--------- +alloca: +This is a built in compiler function for runtime allocation +of extra space on the callers stack which is obviously freed +up on function exit ( e.g. the caller may choose to allocate nothing +of a buffer of 4k if required for temporary purposes ), it generates +very efficent code ( a few cycles ) when compared to alternatives +like malloc. + +automatics: These are local variables on the stack, +i.e they aren't in registers & they aren't static. + +back-chain: +This is a pointer to the stack pointer before entering a +framed functions ( see frameless function ) prologue got by +deferencing the address of the current stack pointer, + i.e. got by accessing the 32 bit value at the stack pointers +current location. + +base-pointer: +This is a pointer to the back of the literal pool which +is an area just behind each procedure used to store constants +in each function. + +call-clobbered: The caller probably needs to save these registers if there +is something of value in them, on the stack or elsewhere before making a +call to another procedure so that it can restore it later. + +epilogue: +The code generated by the compiler to return to the caller. + +frameless-function +A frameless function in Linux for s390 & zSeries is one which doesn't need +more than the register save area ( 96 bytes on s/390, 160 on zSeries ) +given to it by the caller. +A frameless function never: +1) Sets up a back chain. +2) Calls alloca. +3) Calls other normal functions +4) Has automatics. + +GOT-pointer: +This is a pointer to the global-offset-table in ELF +( Executable Linkable Format, Linux'es most common executable format ), +all globals & shared library objects are found using this pointer. + +lazy-binding +ELF shared libraries are typically only loaded when routines in the shared +library are actually first called at runtime. This is lazy binding. + +procedure-linkage-table +This is a table found from the GOT which contains pointers to routines +in other shared libraries which can't be called to by easier means. + +prologue: +The code generated by the compiler to set up the stack frame. + +outgoing-args: +This is extra area allocated on the stack of the calling function if the +parameters for the callee's cannot all be put in registers, the same +area can be reused by each function the caller calls. + +routine-descriptor: +A COFF executable format based concept of a procedure reference +actually being 8 bytes or more as opposed to a simple pointer to the routine. +This is typically defined as follows +Routine Descriptor offset 0=Pointer to Function +Routine Descriptor offset 4=Pointer to Table of Contents +The table of contents/TOC is roughly equivalent to a GOT pointer. +& it means that shared libraries etc. can be shared between several +environments each with their own TOC. + + +static-chain: This is used in nested functions a concept adopted from pascal +by gcc not used in ansi C or C++ ( although quite useful ), basically it +is a pointer used to reference local variables of enclosing functions. +You might come across this stuff once or twice in your lifetime. + +e.g. +The function below should return 11 though gcc may get upset & toss warnings +about unused variables. +int FunctionA(int a) +{ + int b; + FunctionC(int c) + { + b=c+1; + } + FunctionC(10); + return(b); +} + + +s/390 & zSeries Register usage +============================== +r0 used by syscalls/assembly call-clobbered +r1 used by syscalls/assembly call-clobbered +r2 argument 0 / return value 0 call-clobbered +r3 argument 1 / return value 1 (if long long) call-clobbered +r4 argument 2 call-clobbered +r5 argument 3 call-clobbered +r6 argument 5 saved +r7 pointer-to arguments 5 to ... saved +r8 this & that saved +r9 this & that saved +r10 static-chain ( if nested function ) saved +r11 frame-pointer ( if function used alloca ) saved +r12 got-pointer saved +r13 base-pointer saved +r14 return-address saved +r15 stack-pointer saved + +f0 argument 0 / return value ( float/double ) call-clobbered +f2 argument 1 call-clobbered +f4 zSeries argument 2 saved +f6 zSeries argument 3 saved +The remaining floating points +f1,f3,f5 f7-f15 are call-clobbered. + +Notes: +------ +1) The only requirement is that registers which are used +by the callee are saved, e.g. the compiler is perfectly +capible of using r11 for purposes other than a frame a +frame pointer if a frame pointer is not needed. +2) In functions with variable arguments e.g. printf the calling procedure +is identical to one without variable arguments & the same number of +parameters. However, the prologue of this function is somewhat more +hairy owing to it having to move these parameters to the stack to +get va_start, va_arg & va_end to work. +3) Access registers are currently unused by gcc but are used in +the kernel. Possibilities exist to use them at the moment for +temporary storage but it isn't recommended. +4) Only 4 of the floating point registers are used for +parameter passing as older machines such as G3 only have only 4 +& it keeps the stack frame compatible with other compilers. +However with IEEE floating point emulation under linux on the +older machines you are free to use the other 12. +5) A long long or double parameter cannot be have the +first 4 bytes in a register & the second four bytes in the +outgoing args area. It must be purely in the outgoing args +area if crossing this boundary. +6) Floating point parameters are mixed with outgoing args +on the outgoing args area in the order the are passed in as parameters. +7) Floating point arguments 2 & 3 are saved in the outgoing args area for zSeries + + +Stack Frame Layout +------------------ +s/390 zSeries +0 0 back chain ( a 0 here signifies end of back chain ) +4 8 eos ( end of stack, not used on Linux for S390 used in other linkage formats ) +8 16 glue used in other s/390 linkage formats for saved routine descriptors etc. +12 24 glue used in other s/390 linkage formats for saved routine descriptors etc. +16 32 scratch area +20 40 scratch area +24 48 saved r6 of caller function +28 56 saved r7 of caller function +32 64 saved r8 of caller function +36 72 saved r9 of caller function +40 80 saved r10 of caller function +44 88 saved r11 of caller function +48 96 saved r12 of caller function +52 104 saved r13 of caller function +56 112 saved r14 of caller function +60 120 saved r15 of caller function +64 128 saved f4 of caller function +72 132 saved f6 of caller function +80 undefined +96 160 outgoing args passed from caller to callee +96+x 160+x possible stack alignment ( 8 bytes desirable ) +96+x+y 160+x+y alloca space of caller ( if used ) +96+x+y+z 160+x+y+z automatics of caller ( if used ) +0 back-chain + +A sample program with comments. +=============================== + +Comments on the function test +----------------------------- +1) It didn't need to set up a pointer to the constant pool gpr13 as it isn't used +( :-( ). +2) This is a frameless function & no stack is bought. +3) The compiler was clever enough to recognise that it could return the +value in r2 as well as use it for the passed in parameter ( :-) ). +4) The basr ( branch relative & save ) trick works as follows the instruction +has a special case with r0,r0 with some instruction operands is understood as +the literal value 0, some risc architectures also do this ). So now +we are branching to the next address & the address new program counter is +in r13,so now we subtract the size of the function prologue we have executed ++ the size of the literal pool to get to the top of the literal pool +0040037c int test(int b) +{ # Function prologue below + 40037c: 90 de f0 34 stm %r13,%r14,52(%r15) # Save registers r13 & r14 + 400380: 0d d0 basr %r13,%r0 # Set up pointer to constant pool using + 400382: a7 da ff fa ahi %r13,-6 # basr trick + return(5+b); + # Huge main program + 400386: a7 2a 00 05 ahi %r2,5 # add 5 to r2 + + # Function epilogue below + 40038a: 98 de f0 34 lm %r13,%r14,52(%r15) # restore registers r13 & 14 + 40038e: 07 fe br %r14 # return +} + +Comments on the function main +----------------------------- +1) The compiler did this function optimally ( 8-) ) + +Literal pool for main. +400390: ff ff ff ec .long 0xffffffec +main(int argc,char *argv[]) +{ # Function prologue below + 400394: 90 bf f0 2c stm %r11,%r15,44(%r15) # Save necessary registers + 400398: 18 0f lr %r0,%r15 # copy stack pointer to r0 + 40039a: a7 fa ff a0 ahi %r15,-96 # Make area for callee saving + 40039e: 0d d0 basr %r13,%r0 # Set up r13 to point to + 4003a0: a7 da ff f0 ahi %r13,-16 # literal pool + 4003a4: 50 00 f0 00 st %r0,0(%r15) # Save backchain + + return(test(5)); # Main Program Below + 4003a8: 58 e0 d0 00 l %r14,0(%r13) # load relative address of test from + # literal pool + 4003ac: a7 28 00 05 lhi %r2,5 # Set first parameter to 5 + 4003b0: 4d ee d0 00 bas %r14,0(%r14,%r13) # jump to test setting r14 as return + # address using branch & save instruction. + + # Function Epilogue below + 4003b4: 98 bf f0 8c lm %r11,%r15,140(%r15)# Restore necessary registers. + 4003b8: 07 fe br %r14 # return to do program exit +} + + +Compiler updates +---------------- + +main(int argc,char *argv[]) +{ + 4004fc: 90 7f f0 1c stm %r7,%r15,28(%r15) + 400500: a7 d5 00 04 bras %r13,400508 + 400504: 00 40 04 f4 .long 0x004004f4 + # compiler now puts constant pool in code to so it saves an instruction + 400508: 18 0f lr %r0,%r15 + 40050a: a7 fa ff a0 ahi %r15,-96 + 40050e: 50 00 f0 00 st %r0,0(%r15) + return(test(5)); + 400512: 58 10 d0 00 l %r1,0(%r13) + 400516: a7 28 00 05 lhi %r2,5 + 40051a: 0d e1 basr %r14,%r1 + # compiler adds 1 extra instruction to epilogue this is done to + # avoid processor pipeline stalls owing to data dependencies on g5 & + # above as register 14 in the old code was needed directly after being loaded + # by the lm %r11,%r15,140(%r15) for the br %14. + 40051c: 58 40 f0 98 l %r4,152(%r15) + 400520: 98 7f f0 7c lm %r7,%r15,124(%r15) + 400524: 07 f4 br %r4 +} + + +Hartmut ( our compiler developer ) also has been threatening to take out the +stack backchain in optimised code as this also causes pipeline stalls, you +have been warned. + +64 bit zSeries code disassembly +------------------------------- + +If you understand the stuff above you'll understand the stuff +below too so I'll avoid repeating myself & just say that +some of the instructions have g's on the end of them to indicate +they are 64 bit & the stack offsets are a bigger, +the only other difference you'll find between 32 & 64 bit is that +we now use f4 & f6 for floating point arguments on 64 bit. +00000000800005b0 : +int test(int b) +{ + return(5+b); + 800005b0: a7 2a 00 05 ahi %r2,5 + 800005b4: b9 14 00 22 lgfr %r2,%r2 # downcast to integer + 800005b8: 07 fe br %r14 + 800005ba: 07 07 bcr 0,%r7 + + +} + +00000000800005bc
: +main(int argc,char *argv[]) +{ + 800005bc: eb bf f0 58 00 24 stmg %r11,%r15,88(%r15) + 800005c2: b9 04 00 1f lgr %r1,%r15 + 800005c6: a7 fb ff 60 aghi %r15,-160 + 800005ca: e3 10 f0 00 00 24 stg %r1,0(%r15) + return(test(5)); + 800005d0: a7 29 00 05 lghi %r2,5 + # brasl allows jumps > 64k & is overkill here bras would do fune + 800005d4: c0 e5 ff ff ff ee brasl %r14,800005b0 + 800005da: e3 40 f1 10 00 04 lg %r4,272(%r15) + 800005e0: eb bf f0 f8 00 04 lmg %r11,%r15,248(%r15) + 800005e6: 07 f4 br %r4 +} + + + +Compiling programs for debugging on Linux for s/390 & zSeries +============================================================= +-gdwarf2 now works & normal -g debugging works much better now +Thanks to the IBM java compiler developers bug reports. + +This is typically done adding/appending the flags -g to the +CFLAGS & LDFLAGS variables Makefile of the program concerned. + +If using gdb & you would like accurate displays of registers & + stack traces compile without optimisation i.e make sure +that there is no -O2 or similar on the CFLAGS line of the Makefile & +the emitted gcc commands, obviously this will produce worse code +( not advisable for shipment ) but it is an aid to the debugging process. + +This aids debugging because the compiler will copy parameters passed in +in registers onto the stack so backtracing & looking at passed in +parameters will work, however some larger programs which use inline functions +will not compile without optimisation. + +Debugging with optimisation has since much improved after fixing +some bugs, please make sure you are using gdb-5.0 or later developed +after Nov'2000. + +Figuring out gcc compile errors +=============================== +If you are getting a lot of syntax errors compiling a program & the problem +isn't blatantly obvious from the source. +It often helps to just preprocess the file, this is done with the -E +option in gcc. +What this does is that it runs through the very first phase of compilation +( compilation in gcc is done in several stages & gcc calls many programs to +achieve its end result ) with the -E option gcc just calls the gcc preprocessor (cpp). +The c preprocessor does the following, it joins all the files #included together +recursively ( #include files can #include other files ) & also the c file you wish to compile. +It puts a fully qualified path of the #included files in a comment & it +does macro expansion. +This is useful for debugging because +1) You can double check whether the files you expect to be included are the ones +that are being included ( e.g. double check that you aren't going to the i386 asm directory ). +2) Check that macro definitions aren't clashing with typedefs, +3) Check that definitons aren't being used before they are being included. +4) Helps put the line emitting the error under the microscope if it contains macros. + +For convenience the Linux kernel's makefile will do preprocessing automatically for you +by suffixing the file you want built with .i ( instead of .o ) + +e.g. +from the linux directory type +make arch/s390/kernel/signal.i +this will build + +s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -E arch/s390/kernel/signal.c +> arch/s390/kernel/signal.i + +Now look at signal.i you should see something like. + + +# 1 "/home1/barrow/linux/include/asm/types.h" 1 +typedef unsigned short umode_t; +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; + +If instead you are getting errors further down e.g. +unknown instruction:2515 "move.l" or better still unknown instruction:2515 +"Fixme not implemented yet, call Martin" you are probably are attempting to compile some code +meant for another architecture or code that is simply not implemented, with a fixme statement +stuck into the inline assembly code so that the author of the file now knows he has work to do. +To look at the assembly emitted by gcc just before it is about to call gas ( the gnu assembler ) +use the -S option. +Again for your convenience the Linux kernel's Makefile will hold your hand & +do all this donkey work for you also by building the file with the .s suffix. +e.g. +from the Linux directory type +make arch/s390/kernel/signal.s + +s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -S arch/s390/kernel/signal.c +-o arch/s390/kernel/signal.s + + +This will output something like, ( please note the constant pool & the useful comments +in the prologue to give you a hand at interpreting it ). + +.LC54: + .string "misaligned (__u16 *) in __xchg\n" +.LC57: + .string "misaligned (__u32 *) in __xchg\n" +.L$PG1: # Pool sys_sigsuspend +.LC192: + .long -262401 +.LC193: + .long -1 +.LC194: + .long schedule-.L$PG1 +.LC195: + .long do_signal-.L$PG1 + .align 4 +.globl sys_sigsuspend + .type sys_sigsuspend,@function +sys_sigsuspend: +# leaf function 0 +# automatics 16 +# outgoing args 0 +# need frame pointer 0 +# call alloca 0 +# has varargs 0 +# incoming args (stack) 0 +# function length 168 + STM 8,15,32(15) + LR 0,15 + AHI 15,-112 + BASR 13,0 +.L$CO1: AHI 13,.L$PG1-.L$CO1 + ST 0,0(15) + LR 8,2 + N 5,.LC192-.L$PG1(13) + +Adding -g to the above output makes the output even more useful +e.g. typing +make CC:="s390-gcc -g" kernel/sched.s + +which compiles. +s390-gcc -g -D__KERNEL__ -I/home/barrow/linux-2.3/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -S kernel/sched.c -o kernel/sched.s + +also outputs stabs ( debugger ) info, from this info you can find out the +offsets & sizes of various elements in structures. +e.g. the stab for the structure +struct rlimit { + unsigned long rlim_cur; + unsigned long rlim_max; +}; +is +.stabs "rlimit:T(151,2)=s8rlim_cur:(0,5),0,32;rlim_max:(0,5),32,32;;",128,0,0,0 +from this stab you can see that +rlimit_cur starts at bit offset 0 & is 32 bits in size +rlimit_max starts at bit offset 32 & is 32 bits in size. + + +Debugging Tools: +================ + +objdump +======= +This is a tool with many options the most useful being ( if compiled with -g). +objdump --source > + + +The whole kernel can be compiled like this ( Doing this will make a 17MB kernel +& a 200 MB listing ) however you have to strip it before building the image +using the strip command to make it a more reasonable size to boot it. + +A source/assembly mixed dump of the kernel can be done with the line +objdump --source vmlinux > vmlinux.lst +Also if the file isn't compiled -g this will output as much debugging information +as it can ( e.g. function names ), however, this is very slow as it spends lots +of time searching for debugging info, the following self explanitory line should be used +instead if the code isn't compiled -g. +objdump --disassemble-all --syms vmlinux > vmlinux.lst +as it is much faster + +As hard drive space is valuble most of us use the following approach. +1) Look at the emitted psw on the console to find the crash address in the kernel. +2) Look at the file System.map ( in the linux directory ) produced when building +the kernel to find the closest address less than the current PSW to find the +offending function. +3) use grep or similar to search the source tree looking for the source file + with this function if you don't know where it is. +4) rebuild this object file with -g on, as an example suppose the file was +( /arch/s390/kernel/signal.o ) +5) Assuming the file with the erroneous function is signal.c Move to the base of the +Linux source tree. +6) rm /arch/s390/kernel/signal.o +7) make /arch/s390/kernel/signal.o +8) watch the gcc command line emitted +9) type it in again or alernatively cut & paste it on the console adding the -g option. +10) objdump --source arch/s390/kernel/signal.o > signal.lst +This will output the source & the assembly intermixed, as the snippet below shows +This will unfortunately output addresses which aren't the same +as the kernel ones you should be able to get around the mental arithmetic +by playing with the --adjust-vma parameter to objdump. + + + + +extern inline void spin_lock(spinlock_t *lp) +{ + a0: 18 34 lr %r3,%r4 + a2: a7 3a 03 bc ahi %r3,956 + __asm__ __volatile(" lhi 1,-1\n" + a6: a7 18 ff ff lhi %r1,-1 + aa: 1f 00 slr %r0,%r0 + ac: ba 01 30 00 cs %r0,%r1,0(%r3) + b0: a7 44 ff fd jm aa + saveset = current->blocked; + b4: d2 07 f0 68 mvc 104(8,%r15),972(%r4) + b8: 43 cc + return (set->sig[0] & mask) != 0; +} + +6) If debugging under VM go down to that section in the document for more info. + + +I now have a tool which takes the pain out of --adjust-vma +& you are able to do something like +make /arch/s390/kernel/traps.lst +& it automatically generates the correctly relocated entries for +the text segment in traps.lst. +This tool is now standard in linux distro's in scripts/makelst + +strace: +------- +Q. What is it ? +A. It is a tool for intercepting calls to the kernel & logging them +to a file & on the screen. + +Q. What use is it ? +A. You can used it to find out what files a particular program opens. + + + +Example 1 +--------- +If you wanted to know does ping work but didn't have the source +strace ping -c 1 127.0.0.1 +& then look at the man pages for each of the syscalls below, +( In fact this is sometimes easier than looking at some spagetti +source which conditionally compiles for several architectures ) +Not everything that it throws out needs to make sense immeadiately + +Just looking quickly you can see that it is making up a RAW socket +for the ICMP protocol. +Doing an alarm(10) for a 10 second timeout +& doing a gettimeofday call before & after each read to see +how long the replies took, & writing some text to stdout so the user +has an idea what is going on. + +socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3 +getuid() = 0 +setuid(0) = 0 +stat("/usr/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) +stat("/usr/share/locale/libc/C", 0xbffff134) = -1 ENOENT (No such file or directory) +stat("/usr/local/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) +getpid() = 353 +setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0 +setsockopt(3, SOL_SOCKET, SO_RCVBUF, [49152], 4) = 0 +fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(3, 1), ...}) = 0 +mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40008000 +ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0 +write(1, "PING 127.0.0.1 (127.0.0.1): 56 d"..., 42PING 127.0.0.1 (127.0.0.1): 56 data bytes +) = 42 +sigaction(SIGINT, {0x8049ba0, [], SA_RESTART}, {SIG_DFL}) = 0 +sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {SIG_DFL}) = 0 +gettimeofday({948904719, 138951}, NULL) = 0 +sendto(3, "\10\0D\201a\1\0\0\17#\2178\307\36"..., 64, 0, {sin_family=AF_INET, +sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 64 +sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 +sigaction(SIGALRM, {0x8049ba0, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 +alarm(10) = 0 +recvfrom(3, "E\0\0T\0005\0\0@\1|r\177\0\0\1\177"..., 192, 0, +{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 +gettimeofday({948904719, 160224}, NULL) = 0 +recvfrom(3, "E\0\0T\0006\0\0\377\1\275p\177\0"..., 192, 0, +{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 +gettimeofday({948904719, 166952}, NULL) = 0 +write(1, "64 bytes from 127.0.0.1: icmp_se"..., +5764 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=28.0 ms + +Example 2 +--------- +strace passwd 2>&1 | grep open +produces the following output +open("/etc/ld.so.cache", O_RDONLY) = 3 +open("/opt/kde/lib/libc.so.5", O_RDONLY) = -1 ENOENT (No such file or directory) +open("/lib/libc.so.5", O_RDONLY) = 3 +open("/dev", O_RDONLY) = 3 +open("/var/run/utmp", O_RDONLY) = 3 +open("/etc/passwd", O_RDONLY) = 3 +open("/etc/shadow", O_RDONLY) = 3 +open("/etc/login.defs", O_RDONLY) = 4 +open("/dev/tty", O_RDONLY) = 4 + +The 2>&1 is done to redirect stderr to stdout & grep is then filtering this input +through the pipe for each line containing the string open. + + +Example 3 +--------- +Getting sophistocated +telnetd crashes on & I don't know why +Steps +----- +1) Replace the following line in /etc/inetd.conf +telnet stream tcp nowait root /usr/sbin/in.telnetd -h +with +telnet stream tcp nowait root /blah + +2) Create the file /blah with the following contents to start tracing telnetd +#!/bin/bash +/usr/bin/strace -o/t1 -f /usr/sbin/in.telnetd -h +3) chmod 700 /blah to make it executable only to root +4) +killall -HUP inetd +or ps aux | grep inetd +get inetd's process id +& kill -HUP inetd to restart it. + +Important options +----------------- +-o is used to tell strace to output to a file in our case t1 in the root directory +-f is to follow children i.e. +e.g in our case above telnetd will start the login process & subsequently a shell like bash. +You will be able to tell which is which from the process ID's listed on the left hand side +of the strace output. +-p will tell strace to attach to a running process, yup this can be done provided + it isn't being traced or debugged already & you have enough privileges, +the reason 2 processes cannot trace or debug the same program is that strace +becomes the parent process of the one being debugged & processes ( unlike people ) +can have only one parent. + + +However the file /t1 will get big quite quickly +to test it telnet 127.0.0.1 + +now look at what files in.telnetd execve'd +413 execve("/usr/sbin/in.telnetd", ["/usr/sbin/in.telnetd", "-h"], [/* 17 vars */]) = 0 +414 execve("/bin/login", ["/bin/login", "-h", "localhost", "-p"], [/* 2 vars */]) = 0 + +Whey it worked!. + + +Other hints: +------------ +If the program is not very interactive ( i.e. not much keyboard input ) +& is crashing in one architecture but not in another you can do +an strace of both programs under as identical a scenario as you can +on both architectures outputting to a file then. +do a diff of the two traces using the diff program +i.e. +diff output1 output2 +& maybe you'll be able to see where the call paths differed, this +is possibly near the cause of the crash. + +More info +--------- +Look at man pages for strace & the various syscalls +e.g. man strace, man alarm, man socket. + + +Performance Debugging +===================== +gcc is capible of compiling in profiling code just add the -p option +to the CFLAGS, this obviously affects program size & performance. +This can be used by the gprof gnu profiling tool or the +gcov the gnu code coverage tool ( code coverage is a means of testing +code quality by checking if all the code in an executable in exercised by +a tester ). + + +Using top to find out where processes are sleeping in the kernel +---------------------------------------------------------------- +To do this copy the System.map from the root directory where +the linux kernel was built to the /boot directory on your +linux machine. +Start top +Now type fU +You should see a new field called WCHAN which +tells you where each process is sleeping here is a typical output. + + 6:59pm up 41 min, 1 user, load average: 0.00, 0.00, 0.00 +28 processes: 27 sleeping, 1 running, 0 zombie, 0 stopped +CPU states: 0.0% user, 0.1% system, 0.0% nice, 99.8% idle +Mem: 254900K av, 45976K used, 208924K free, 0K shrd, 28636K buff +Swap: 0K av, 0K used, 0K free 8620K cached + + PID USER PRI NI SIZE RSS SHARE WCHAN STAT LIB %CPU %MEM TIME COMMAND + 750 root 12 0 848 848 700 do_select S 0 0.1 0.3 0:00 in.telnetd + 767 root 16 0 1140 1140 964 R 0 0.1 0.4 0:00 top + 1 root 8 0 212 212 180 do_select S 0 0.0 0.0 0:00 init + 2 root 9 0 0 0 0 down_inte SW 0 0.0 0.0 0:00 kmcheck + +The time command +---------------- +Another related command is the time command which gives you an indication +of where a process is spending the majority of its time. +e.g. +time ping -c 5 nc +outputs +real 0m4.054s +user 0m0.010s +sys 0m0.010s + +Debugging under VM +================== + +Notes +----- +Addresses & values in the VM debugger are always hex never decimal +Address ranges are of the format - or . +e.g. The address range 0x2000 to 0x3000 can be described described as +2000-3000 or 2000.1000 + +The VM Debugger is case insensitive. + +VM's strengths are usually other debuggers weaknesses you can get at any resource +no matter how sensitive e.g. memory managment resources,change address translation +in the PSW. For kernel hacking you will reap dividends if you get good at it. + +The VM Debugger displays operators but not operands, probably because some +of it was written when memory was expensive & the programmer was probably proud that +it fitted into 2k of memory & the programmers & didn't want to shock hardcore VM'ers by +changing the interface :-), also the debugger displays useful information on the same line & +the author of the code probably felt that it was a good idea not to go over +the 80 columns on the screen. + +As some of you are probably in a panic now this isn't as unintuitive as it may seem +as the 390 instructions are easy to decode mentally & you can make a good guess at a lot +of them as all the operands are nibble ( half byte aligned ) & if you have an objdump listing +also it is quite easy to follow, if you don't have an objdump listing keep a copy of +the s/390 Reference Summary & look at between pages 2 & 7 or alternatively the +s/390 principles of operation. +e.g. even I can guess that +0001AFF8' LR 180F CC 0 +is a ( load register ) lr r0,r15 + +Also it is very easy to tell the length of a 390 instruction from the 2 most significant +bits in the instruction ( not that this info is really useful except if you are trying to +make sense of a hexdump of code ). +Here is a table +Bits Instruction Length +------------------------------------------ +00 2 Bytes +01 4 Bytes +10 4 Bytes +11 6 Bytes + + + + +The debugger also displays other useful info on the same line such as the +addresses being operated on destination addresses of branches & condition codes. +e.g. +00019736' AHI A7DAFF0E CC 1 +000198BA' BRC A7840004 -> 000198C2' CC 0 +000198CE' STM 900EF068 >> 0FA95E78 CC 2 + + + +Useful VM debugger commands +--------------------------- + +I suppose I'd better mention this before I start +to list the current active traces do +Q TR +there can be a maximum of 255 of these per set +( more about trace sets later ). +To stop traces issue a +TR END. +To delete a particular breakpoint issue +TR DEL + +The PA1 key drops to CP mode so you can issue debugger commands, +Doing alt c (on my 3270 console at least ) clears the screen. +hitting b comes back to the running operating system +from cp mode ( in our case linux ). +It is typically useful to add shortcuts to your profile.exec file +if you have one ( this is roughly equivalent to autoexec.bat in DOS ). +file here are a few from mine. +/* this gives me command history on issuing f12 */ +set pf12 retrieve +/* this continues */ +set pf8 imm b +/* goes to trace set a */ +set pf1 imm tr goto a +/* goes to trace set b */ +set pf2 imm tr goto b +/* goes to trace set c */ +set pf3 imm tr goto c + + + +Instruction Tracing +------------------- +Setting a simple breakpoint +TR I PSWA
+To debug a particular function try +TR I R +TR I on its own will single step. +TR I DATA will trace for particular mnemonics +e.g. +TR I DATA 4D R 0197BC.4000 +will trace for BAS'es ( opcode 4D ) in the range 0197BC.4000 +if you were inclined you could add traces for all branch instructions & +suffix them with the run prefix so you would have a backtrace on screen +when a program crashes. +TR BR will trace branches into or out of an address. +e.g. +TR BR INTO 0 is often quite useful if a program is getting awkward & deciding +to branch to 0 & crashing as this will stop at the address before in jumps to 0. +TR I R
RUN cmd d g +single steps a range of addresses but stays running & +displays the gprs on each step. + + + +Displaying & modifying Registers +-------------------------------- +D G will display all the gprs +Adding a extra G to all the commands is neccessary to access the full 64 bit +content in VM on zSeries obviously this isn't required for access registers +as these are still 32 bit. +e.g. DGG instead of DG +D X will display all the control registers +D AR will display all the access registers +D AR4-7 will display access registers 4 to 7 +CPU ALL D G will display the GRPS of all CPUS in the configuration +D PSW will display the current PSW +st PSW 2000 will put the value 2000 into the PSW & +cause crash your machine. +D PREFIX displays the prefix offset + + +Displaying Memory +----------------- +To display memory mapped using the current PSW's mapping try +D +To make VM display a message each time it hits a particular address & continue try +D I will disassemble/display a range of instructions. +ST addr 32 bit word will store a 32 bit aligned address +D T will display the EBCDIC in an address ( if you are that way inclined ) +D R will display real addresses ( without DAT ) but with prefixing. +There are other complex options to display if you need to get at say home space +but are in primary space the easiest thing to do is to temporarily +modify the PSW to the other addressing mode, display the stuff & then +restore it. + + + +Hints +----- +If you want to issue a debugger command without halting your virtual machine with the +PA1 key try prefixing the command with #CP e.g. +#cp tr i pswa 2000 +also suffixing most debugger commands with RUN will cause them not +to stop just display the mnemonic at the current instruction on the console. +If you have several breakpoints you want to put into your program & +you get fed up of cross referencing with System.map +you can do the following trick for several symbols. +grep do_signal System.map +which emits the following among other things +0001f4e0 T do_signal +now you can do + +TR I PSWA 0001f4e0 cmd msg * do_signal +This sends a message to your own console each time do_signal is entered. +( As an aside I wrote a perl script once which automatically generated a REXX +script with breakpoints on every kernel procedure, this isn't a good idea +because there are thousands of these routines & VM can only set 255 breakpoints +at a time so you nearly had to spend as long pruning the file down as you would +entering the msg's by hand ),however, the trick might be useful for a single object file. +On linux'es 3270 emulator x3270 there is a very useful option under the file ment +Save Screens In File this is very good of keeping a copy of traces. + +From CMS help will give you online help on a particular command. +e.g. +HELP DISPLAY + +Also CP has a file called profile.exec which automatically gets called +on startup of CMS ( like autoexec.bat ), keeping on a DOS analogy session +CP has a feature similar to doskey, it may be useful for you to +use profile.exec to define some keystrokes. +e.g. +SET PF9 IMM B +This does a single step in VM on pressing F8. +SET PF10 ^ +This sets up the ^ key. +which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed directly into some 3270 consoles. +SET PF11 ^- +This types the starting keystrokes for a sysrq see SysRq below. +SET PF12 RETRIEVE +This retrieves command history on pressing F12. + + +Sometimes in VM the display is set up to scroll automatically this +can be very annoying if there are messages you wish to look at +to stop this do +TERM MORE 255 255 +This will nearly stop automatic screen updates, however it will +cause a denial of service if lots of messages go to the 3270 console, +so it would be foolish to use this as the default on a production machine. + + +Tracing particular processes +---------------------------- +The kernels text segment is intentionally at an address in memory that it will +very seldom collide with text segments of user programs ( thanks Martin ), +this simplifies debugging the kernel. +However it is quite common for user processes to have addresses which collide +this can make debugging a particular process under VM painful under normal +circumstances as the process may change when doing a +TR I R
. +Thankfully after reading VM's online help I figured out how to debug +I particular process. + +Your first problem is to find the STD ( segment table designation ) +of the program you wish to debug. +There are several ways you can do this here are a few +1) objdump --syms | grep main +To get the address of main in the program. +tr i pswa
+Start the program, if VM drops to CP on what looks like the entry +point of the main function this is most likely the process you wish to debug. +Now do a D X13 or D XG13 on zSeries. +On 31 bit the STD is bits 1-19 ( the STO segment table origin ) +& 25-31 ( the STL segment table length ) of CR13. +now type +TR I R STD 0.7fffffff +e.g. +TR I R STD 8F32E1FF 0.7fffffff +Another very useful variation is +TR STORE INTO STD
+ + + + +Tracing Program Exceptions +-------------------------- +If you get a crash which says something like +illegal operation or specification exception followed by a register dump +You can restart linux & trace these using the tr prog trace option. + + + +The most common ones you will normally be tracing for is +1=operation exception +2=privileged operation exception +4=protection exception +5=addressing exception +6=specification exception +10=segment translation exception +11=page translation exception + +The full list of these is on page 22 of the current s/390 Reference Summary. +e.g. +tr prog 10 will trace segment translation exceptions. +tr prog on its own will trace all program interruption codes. + +Trace Sets +---------- +On starting VM you are initially in the INITIAL trace set. +You can do a Q TR to verify this. +If you have a complex tracing situation where you wish to wait for instance +till a driver is open before you start tracing IO, but know in your +heart that you are going to have to make several runs through the code till you +have a clue whats going on. + +What you can do is +TR I PSWA +hit b to continue till breakpoint +reach the breakpoint +now do your +TR GOTO B +TR IO 7c08-7c09 inst int run +or whatever the IO channels you wish to trace are & hit b + +To got back to the initial trace set do +TR GOTO INITIAL +& the TR I PSWA will be the only active breakpoint again. + + +Tracing linux syscalls under VM +------------------------------- +Syscalls are implemented on Linux for S390 by the Supervisor call instruction (SVC) there 256 +possibilities of these as the instruction is made up of a 0xA opcode & the second byte being +the syscall number. They are traced using the simple command. +TR SVC +the syscalls are defined in linux/include/asm-s390/unistd.h +e.g. to trace all file opens just do +TR SVC 5 ( as this is the syscall number of open ) + + +SMP Specific commands +--------------------- +To find out how many cpus you have +Q CPUS displays all the CPU's available to your virtual machine +To find the cpu that the current cpu VM debugger commands are being directed at do +Q CPU to change the current cpu cpu VM debugger commands are being directed at do +CPU + +On a SMP guest issue a command to all CPUs try prefixing the command with cpu all. +To issue a command to a particular cpu try cpu e.g. +CPU 01 TR I R 2000.3000 +If you are running on a guest with several cpus & you have a IO related problem +& cannot follow the flow of code but you know it isnt smp related. +from the bash prompt issue +shutdown -h now or halt. +do a Q CPUS to find out how many cpus you have +detach each one of them from cp except cpu 0 +by issueing a +DETACH CPU 01-(number of cpus in configuration) +& boot linux again. +TR SIGP will trace inter processor signal processor instructions. +DEFINE CPU 01-(number in configuration) +will get your guests cpus back. + + +Help for displaying ascii textstrings +------------------------------------- +As textstrings are cannot be displayed in ASCII under the VM debugger ( I love EBDIC too ) I have +written this little program which will convert a command line of hex digits to ascii text +which can be compiled under linux & you can copy the hex digits from your x3270 terminal to +your xterm if you are debugging from a linuxbox. + +This is quite useful when looking at a parameter passed in as a text string +under VM ( unless you are good at decoding ASCII in your head ). + +e.g. consider tracing an open syscall +TR SVC 5 +We have stopped at a breakpoint +000151B0' SVC 0A05 -> 0001909A' CC 0 + +D 20.8 to check the SVC old psw in the prefix area & see was it from userspace +( for the layout of the prefix area consult P18 of the s/390 390 Reference Summary +if you have it available ). +V00000020 070C2000 800151B2 +The problem state bit wasn't set & it's also too early in the boot sequence +for it to be a userspace SVC if it was we would have to temporarily switch the +psw to user space addressing so we could get at the first parameter of the open in +gpr2. +Next do a +D G2 +GPR 2 = 00014CB4 +Now display what gpr2 is pointing to +D 00014CB4.20 +V00014CB4 2F646576 2F636F6E 736F6C65 00001BF5 +V00014CC4 FC00014C B4001001 E0001000 B8070707 +Now copy the text till the first 00 hex ( which is the end of the string +to an xterm & do hex2ascii on it. +hex2ascii 2F646576 2F636F6E 736F6C65 00 +outputs +Decoded Hex:=/ d e v / c o n s o l e 0x00 +We were opening the console device, + +You can compile the code below yourself for practice :-), +/* + * hex2ascii.c + * a useful little tool for converting a hexadecimal command line to ascii + * + * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation. + */ +#include + +int main(int argc,char *argv[]) +{ + int cnt1,cnt2,len,toggle=0; + int startcnt=1; + unsigned char c,hex; + + if(argc>1&&(strcmp(argv[1],"-a")==0)) + startcnt=2; + printf("Decoded Hex:="); + for(cnt1=startcnt;cnt1='0'&&c<='9') + c=c-'0'; + if(c>='A'&&c<='F') + c=c-'A'+10; + if(c>='a'&&c<='F') + c=c-'a'+10; + switch(toggle) + { + case 0: + hex=c<<4; + toggle=1; + break; + case 1: + hex+=c; + if(hex<32||hex>127) + { + if(startcnt==1) + printf("0x%02X ",(int)hex); + else + printf("."); + } + else + { + printf("%c",hex); + if(startcnt==1) + printf(" "); + } + toggle=0; + break; + } + } + } + printf("\n"); +} + + + + +Stack tracing under VM +---------------------- +A basic backtrace +----------------- + +Here are the tricks I use 9 out of 10 times it works pretty well, + +When your backchain reaches a dead end +-------------------------------------- +This can happen when an exception happens in the kernel & the kernel is entered twice +if you reach the NULL pointer at the end of the back chain you should be +able to sniff further back if you follow the following tricks. +1) A kernel address should be easy to recognise since it is in +primary space & the problem state bit isn't set & also +The Hi bit of the address is set. +2) Another backchain should also be easy to recognise since it is an +address pointing to another address approximately 100 bytes or 0x70 hex +behind the current stackpointer. + + +Here is some practice. +boot the kernel & hit PA1 at some random time +d g to display the gprs, this should display something like +GPR 0 = 00000001 00156018 0014359C 00000000 +GPR 4 = 00000001 001B8888 000003E0 00000000 +GPR 8 = 00100080 00100084 00000000 000FE000 +GPR 12 = 00010400 8001B2DC 8001B36A 000FFED8 +Note that GPR14 is a return address but as we are real men we are going to +trace the stack. +display 0x40 bytes after the stack pointer. + +V000FFED8 000FFF38 8001B838 80014C8E 000FFF38 +V000FFEE8 00000000 00000000 000003E0 00000000 +V000FFEF8 00100080 00100084 00000000 000FE000 +V000FFF08 00010400 8001B2DC 8001B36A 000FFED8 + + +Ah now look at whats in sp+56 (sp+0x38) this is 8001B36A our saved r14 if +you look above at our stackframe & also agrees with GPR14. + +now backchain +d 000FFF38.40 +we now are taking the contents of SP to get our first backchain. + +V000FFF38 000FFFA0 00000000 00014995 00147094 +V000FFF48 00147090 001470A0 000003E0 00000000 +V000FFF58 00100080 00100084 00000000 001BF1D0 +V000FFF68 00010400 800149BA 80014CA6 000FFF38 + +This displays a 2nd return address of 80014CA6 + +now do d 000FFFA0.40 for our 3rd backchain + +V000FFFA0 04B52002 0001107F 00000000 00000000 +V000FFFB0 00000000 00000000 FF000000 0001107F +V000FFFC0 00000000 00000000 00000000 00000000 +V000FFFD0 00010400 80010802 8001085A 000FFFA0 + + +our 3rd return address is 8001085A + +as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines +for the sake of optimisation dont set up a backchain. + +now look at System.map to see if the addresses make any sense. + +grep -i 0001b3 System.map +outputs among other things +0001b304 T cpu_idle +so 8001B36A +is cpu_idle+0x66 ( quiet the cpu is asleep, don't wake it ) + + +grep -i 00014 System.map +produces among other things +00014a78 T start_kernel +so 0014CA6 is start_kernel+some hex number I can't add in my head. + +grep -i 00108 System.map +this produces +00010800 T _stext +so 8001085A is _stext+0x5a + +Congrats you've done your first backchain. + + + +s/390 & zSeries IO Overview +=========================== + +I am not going to give a course in 390 IO architecture as this would take me quite a +while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have +the s/390 principles of operation available read this instead. If nothing else you may find a few +useful keywords in here & be able to use them on a web search engine like altavista to find +more useful information. + +Unlike other bus architectures modern 390 systems do their IO using mostly +fibre optics & devices such as tapes & disks can be shared between several mainframes, +also S390 can support upto 65536 devices while a high end PC based system might be choking +with around 64. Here is some of the common IO terminology + +Subchannel: +This is the logical number most IO commands use to talk to an IO device there can be upto +0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM +for simplicity they are allocated contiguously, however on the native hardware they are not +they typically stay consistent between boots provided no new hardware is inserted or removed. +Under Linux for 390 we use these as IRQ's & also when issuing an IO command (CLEAR SUBCHANNEL, +HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCHANNEL & +TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most +important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check +whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel +can have up to 8 channel paths to a device this offers redunancy if one is not available. + + +Device Number: +This number remains static & Is closely tied to the hardware, there are 65536 of these +also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) +& another lsb 8 bits. These remain static even if more devices are inserted or removed +from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided +devices arent inserted or removed. + +Channel Control Words: +CCWS are linked lists of instructions initially pointed to by an operation request block (ORB), +which is initially given to Start Subchannel (SSCH) command along with the subchannel number +for the IO subsystem to process while the CPU continues executing normal code. +These come in two flavours, Format 0 ( 24 bit for backward ) +compatibility & Format 1 ( 31 bit ). These are typically used to issue read & write +( & many other instructions ) they consist of a length field & an absolute address field. +For each IO typically get 1 or 2 interrupts one for channel end ( primary status ) when the +channel is idle & the second for device end ( secondary status ) sometimes you get both +concurrently, you check how the IO went on by issueing a TEST SUBCHANNEL at each interrupt, +from which you receive an Interruption response block (IRB). If you get channel & device end +status in the IRB without channel checks etc. your IO probably went okay. If you didn't you +probably need a doctorto examine the IRB & extended status word etc. +If an error occurs more sophistocated control units have a facitity known as +concurrent sense this means that if an error occurs Extended sense information will +be presented in the Extended status word in the IRB if not you have to issue a +subsequent SENSE CCW command after the test subchannel. + + +TPI( Test pending interrupt) can also be used for polled IO but in multitasking multiprocessor +systems it isn't recommended except for checking special cases ( i.e. non looping checks for +pending IO etc. ). + +Store Subchannel & Modify Subchannel can be used to examine & modify operating characteristics +of a subchannel ( e.g. channel paths ). + +Other IO related Terms: +Sysplex: S390's Clustering Technology +QDIO: S390's new high speed IO architecture to support devices such as gigabit ethernet, +this architecture is also designed to be forward compatible with up & coming 64 bit machines. + + +General Concepts + +Input Output Processors (IOP's) are responsible for communicating between +the mainframe CPU's & the channel & relieve the mainframe CPU's from the +burden of communicating with IO devices directly, this allows the CPU's to +concentrate on data processing. + +IOP's can use one or more links ( known as channel paths ) to talk to each +IO device. It first checks for path availability & chooses an available one, +then starts ( & sometimes terminates IO ). +There are two types of channel path ESCON & the Paralell IO interface. + +IO devices are attached to control units, control units provide the +logic to interface the channel paths & channel path IO protocols to +the IO devices, they can be integrated with the devices or housed separately +& often talk to several similar devices ( typical examples would be raid +controllers or a control unit which connects to 1000 3270 terminals ). + + + +---------------------------------------------------------------+ + | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | + | | CPU | | CPU | | CPU | | CPU | | Main | | Expanded | | + | | | | | | | | | | Memory | | Storage | | + | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | + |---------------------------------------------------------------+ + | IOP | IOP | IOP | + |--------------------------------------------------------------- + | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | + ---------------------------------------------------------------- + || || + || Bus & Tag Channel Path || ESCON + || ====================== || Channel + || || || || Path + +----------+ +----------+ +----------+ + | | | | | | + | CU | | CU | | CU | + | | | | | | + +----------+ +----------+ +----------+ + | | | | | ++----------+ +----------+ +----------+ +----------+ +----------+ +|I/O Device| |I/O Device| |I/O Device| |I/O Device| |I/O Device| ++----------+ +----------+ +----------+ +----------+ +----------+ + CPU = Central Processing Unit + C = Channel + IOP = IP Processor + CU = Control Unit + +The 390 IO systems come in 2 flavours the current 390 machines support both + +The Older 360 & 370 Interface,sometimes called the paralell I/O interface, +sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers +Interface (OEMI). + +This byte wide paralell channel path/bus has parity & data on the "Bus" cable +& control lines on the "Tag" cable. These can operate in byte multiplex mode for +sharing between several slow devices or burst mode & monopolize the channel for the +whole burst. Upto 256 devices can be addressed on one of these cables. These cables are +about one inch in diameter. The maximum unextended length supported by these cables is +125 Meters but this can be extended up to 2km with a fibre optic channel extended +such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however +some really old processors support only transfer rates of 3.0, 2.0 & 1.0 MB/sec. +One of these paths can be daisy chained to up to 8 control units. + + +ESCON if fibre optic it is also called FICON +Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers +for communication at a signaling rate of upto 200 megabits/sec. As 10bits are transferred +for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once +control info & CRC are added. ESCON only operates in burst mode. + +ESCONs typical max cable length is 3km for the led version & 20km for the laser version +known as XDF ( extended distance facility ). This can be further extended by using an +ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is +serial it uses a packet switching architecture the standard Bus & Tag control protocol +is however present within the packets. Upto 256 devices can be attached to each control +unit that uses one of these interfaces. + +Common 390 Devices include: +Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters, +Consoles 3270 & 3215 ( a teletype emulated under linux for a line mode console ). +DASD's direct access storage devices ( otherwise known as hard disks ). +Tape Drives. +CTC ( Channel to Channel Adapters ), +ESCON or Paralell Cables used as a very high speed serial link +between 2 machines. We use 2 cables under linux to do a bi-directional serial link. + + +Debugging IO on s/390 & zSeries under VM +========================================= + +Now we are ready to go on with IO tracing commands under VM + +A few self explanatory queries: +Q OSA +Q CTC +Q DISK +Q DASD + + + + + + +Q OSA on my machine returns +OSA 7C08 ON OSA 7C08 SUBCHANNEL = 0000 +OSA 7C09 ON OSA 7C09 SUBCHANNEL = 0001 +OSA 7C14 ON OSA 7C14 SUBCHANNEL = 0002 +OSA 7C15 ON OSA 7C15 SUBCHANNEL = 0003 + +If you have a guest with certain priviliges you may be able to see devices +which don't belong to you to avoid this do add the option V. +e.g. +Q V OSA + +Now using the device numbers returned by this command we will +Trace the io starting up on the first device 7c08 & 7c09 +In our simplest case we can trace the +start subchannels +like TR SSCH 7C08-7C09 +or the halt subchannels +or TR HSCH 7C08-7C09 +MSCH's ,STSCH's I think you can guess the rest + +Ingo's favourite trick is tracing all the IO's & CCWS & spooling them into the reader of another +VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you + a look at the output. + +1) Spool stdout to VM reader +SP PRT TO (another vm guest ) or * for the local vm guest +2) Fill the reader with the trace +TR IO 7c08-7c09 INST INT CCW PRT RUN +3) Start up linux +i 00c +4) Finish the trace +TR END +5) close the reader +C PRT +6) list reader contents +RDRLIST +7) copy it to linux4's minidisk +RECEIVE / LOG TXT A1 ( replace +8) +filel & press F11 to look at it +You should see someting like. + +00020942' SSCH B2334000 0048813C CC 0 SCH 0000 DEV 7C08 + CPA 000FFDF0 PARM 00E2C9C4 KEY 0 FPI C0 LPM 80 + CCW 000FFDF0 E4200100 00487FE8 0000 E4240100 ........ + IDAL 43D8AFE8 + IDAL 0FB76000 +00020B0A' I/O DEV 7C08 -> 000197BC' SCH 0000 PARM 00E2C9C4 +00021628' TSCH B2354000 >> 00488164 CC 0 SCH 0000 DEV 7C08 + CCWA 000FFDF8 DEV STS 0C SCH STS 00 CNT 00EC + KEY 0 FPI C0 CC 0 CTLS 4007 +00022238' STSCH B2344000 >> 00488108 CC 0 SCH 0000 DEV 7C08 + +If you don't like messing up your readed ( because you possibly booted from it ) +you can alternatively spool it to another readers guest. + + +Other common VM device related commands +--------------------------------------------- +These commands are listed only because they have +been of use to me in the past & may be of use to +you too. For more complete info on each of the commands +use type HELP from CMS. +detaching devices +DET +ATT +attach a device to guest * for your own guest +READY cause VM to issue a fake interrupt. + +The VARY command is normally only available to VM administrators. +VARY ON PATH TO +VARY OFF PATH FROM +This is used to switch on or off channel paths to devices. + +Q CHPID +This displays state of devices using this channel path +D SCHIB +This displays the subchannel information SCHIB block for the device. +this I believe is also only available to administrators. +DEFINE CTC +defines a virtual CTC channel to channel connection +2 need to be defined on each guest for the CTC driver to use. +COUPLE devno userid remote devno +Joins a local virtual device to a remote virtual device +( commonly used for the CTC driver ). + +Building a VM ramdisk under CMS which linux can use +def vfb- +blocksize is commonly 4096 for linux. +Formatting it +format (blksize + +Sharing a disk between multiple guests +LINK userid devno1 devno2 mode password + + + +GDB on S390 +=========== +N.B. if compiling for debugging gdb works better without optimisation +( see Compiling programs for debugging ) + +invocation +---------- +gdb + +Online help +----------- +help: gives help on commands +e.g. +help +help display +Note gdb's online help is very good use it. + + +Assembly +-------- +info registers: displays registers other than floating point. +info all-registers: displays floating points as well. +disassemble: dissassembles +e.g. +disassemble without parameters will disassemble the current function +disassemble $pc $pc+10 + +Viewing & modifying variables +----------------------------- +print or p: displays variable or register +e.g. p/x $sp will display the stack pointer + +display: prints variable or register each time program stops +e.g. +display/x $pc will display the program counter +display argc + +undisplay : undo's display's + +info breakpoints: shows all current breakpoints + +info stack: shows stack back trace ( if this dosent work too well, I'll show you the +stacktrace by hand below ). + +info locals: displays local variables. + +info args: display current procedure arguments. + +set args: will set argc & argv each time the victim program is invoked. + +set =value +set argc=100 +set $pc=0 + + + +Modifying execution +------------------- +step: steps n lines of sourcecode +step steps 1 line. +step 100 steps 100 lines of code. + +next: like step except this will not step into subroutines + +stepi: steps a single machine code instruction. +e.g. stepi 100 + +nexti: steps a single machine code instruction but will not step into subroutines. + +finish: will run until exit of the current routine + +run: (re)starts a program + +cont: continues a program + +quit: exits gdb. + + +breakpoints +------------ + +break +sets a breakpoint +e.g. + +break main + +break *$pc + +break *0x400618 + +heres a really useful one for large programs +rbr +Set a breakpoint for all functions matching REGEXP +e.g. +rbr 390 +will set a breakpoint with all functions with 390 in their name. + +info breakpoints +lists all breakpoints + +delete: delete breakpoint by number or delete them all +e.g. +delete 1 will delete the first breakpoint +delete will delete them all + +watch: This will set a watchpoint ( usually hardware assisted ), +This will watch a variable till it changes +e.g. +watch cnt, will watch the variable cnt till it changes. +As an aside unfortunately gdb's, architecture independent watchpoint code +is inconsistent & not very good, watchpoints usually work but not always. + +info watchpoints: Display currently active watchpoints + +condition: ( another useful one ) +Specify breakpoint number N to break only if COND is true. +Usage is `condition N COND', where N is an integer and COND is an +expression to be evaluated whenever breakpoint N is reached. + + + +User defined functions/macros +----------------------------- +define: ( Note this is very very useful,simple & powerful ) +usage define end + +examples which you should consider putting into .gdbinit in your home directory +define d +stepi +disassemble $pc $pc+10 +end + +define e +nexti +disassemble $pc $pc+10 +end + + +Other hard to classify stuff +---------------------------- +signal n: +sends the victim program a signal. +e.g. signal 3 will send a SIGQUIT. + +info signals: +what gdb does when the victim receives certain signals. + +list: +e.g. +list lists current function source +list 1,10 list first 10 lines of curret file. +list test.c:1,10 + + +directory: +Adds directories to be searched for source if gdb cannot find the source. +(note it is a bit sensititive about slashes ) +e.g. To add the root of the filesystem to the searchpath do +directory // + + +call +This calls a function in the victim program, this is pretty powerful +e.g. +(gdb) call printf("hello world") +outputs: +$1 = 11 + +You might now be thinking that the line above didn't work, something extra had to be done. +(gdb) call fflush(stdout) +hello world$2 = 0 +As an aside the debugger also calls malloc & free under the hood +to make space for the "hello world" string. + + + +hints +----- +1) command completion works just like bash +( if you are a bad typist like me this really helps ) +e.g. hit br & cursor up & down :-). + +2) if you have a debugging problem that takes a few steps to recreate +put the steps into a file called .gdbinit in your current working directory +if you have defined a few extra useful user defined commands put these in +your home directory & they will be read each time gdb is launched. + +A typical .gdbinit file might be. +break main +run +break runtime_exception +cont + + +stack chaining in gdb by hand +----------------------------- +This is done using a the same trick described for VM +p/x (*($sp+56))&0x7fffffff get the first backchain. + +For zSeries do +p/x *($sp+112) i.e. replace 56 with 112 & ignore the &0x7fffffff +in the macros below. + +this outputs +$5 = 0x528f18 +on my machine. +Now you can use +info symbol (*($sp+56))&0x7fffffff +you might see something like. +rl_getc + 36 in section .text telling you what is located at address 0x528f18 +Now do. +p/x (*(*$sp+56))&0x7fffffff +This outputs +$6 = 0x528ed0 +Now do. +info symbol (*(*$sp+56))&0x7fffffff +rl_read_key + 180 in section .text +now do +p/x (*(**$sp+56))&0x7fffffff +& so on. + +Disassembling instructions without debug info +--------------------------------------------- +gdb typically compains if there is a lack of debugging +symbols in the disassemble command with +"No function contains specified address." to get around +this do +x/xi
+e.g. +x/20xi 0x400730 + + + +Note: Remember gdb has history just like bash you don't need to retype the +whole line just use the up & down arrows. + + + +For more info +------------- +From your linuxbox do +man gdb or info gdb. + +core dumps +---------- +What a core dump ?, +A core dump is a file generated by the kernel ( if allowed ) which contains the registers, +& all active pages of the program which has crashed. +From this file gdb will allow you to look at the registers & stack trace & memory of the +program as if it just crashed on your system, it is usually called core & created in the +current working directory. +This is very useful in that a customer can mail a core dump to a technical support department +& the technical support department can reconstruct what happened. +Provided the have an indentical copy of this program with debugging symbols compiled in & +the source base of this build is available. +In short it is far more useful than something like a crash log could ever hope to be. + +In theory all that is missing to restart a core dumped program is a kernel patch which +will do the following. +1) Make a new kernel task structure +2) Reload all the dumped pages back into the kernels memory managment structures. +3) Do the required clock fixups +4) Get all files & network connections for the process back into an identical state ( really difficult ). +5) A few more difficult things I haven't thought of. + + + +Why have I never seen one ?. +Probably because you haven't used the command +ulimit -c unlimited in bash +to allow core dumps, now do +ulimit -a +to verify that the limit was accepted. + +A sample core dump +To create this I'm going to do +ulimit -c unlimited +gdb +to launch gdb (my victim app. ) now be bad & do the following from another +telnet/xterm session to the same machine +ps -aux | grep gdb +kill -SIGSEGV +or alternatively use killall -SIGSEGV gdb if you have the killall command. +Now look at the core dump. +./gdb ./gdb core +Displays the following +GNU gdb 4.18 +Copyright 1998 Free Software Foundation, Inc. +GDB is free software, covered by the GNU General Public License, and you are +welcome to change it and/or distribute copies of it under certain conditions. +Type "show copying" to see the conditions. +There is absolutely no warranty for GDB. Type "show warranty" for details. +This GDB was configured as "s390-ibm-linux"... +Core was generated by `./gdb'. +Program terminated with signal 11, Segmentation fault. +Reading symbols from /usr/lib/libncurses.so.4...done. +Reading symbols from /lib/libm.so.6...done. +Reading symbols from /lib/libc.so.6...done. +Reading symbols from /lib/ld-linux.so.2...done. +#0 0x40126d1a in read () from /lib/libc.so.6 +Setting up the environment for debugging gdb. +Breakpoint 1 at 0x4dc6f8: file utils.c, line 471. +Breakpoint 2 at 0x4d87a4: file top.c, line 2609. +(top-gdb) info stack +#0 0x40126d1a in read () from /lib/libc.so.6 +#1 0x528f26 in rl_getc (stream=0x7ffffde8) at input.c:402 +#2 0x528ed0 in rl_read_key () at input.c:381 +#3 0x5167e6 in readline_internal_char () at readline.c:454 +#4 0x5168ee in readline_internal_charloop () at readline.c:507 +#5 0x51692c in readline_internal () at readline.c:521 +#6 0x5164fe in readline (prompt=0x7ffff810 "\177˙řx\177˙÷Ř\177˙řxŔ") + at readline.c:349 +#7 0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1, + annotation_suffix=0x4d6b44 "prompt") at top.c:2091 +#8 0x4d6cf0 in command_loop () at top.c:1345 +#9 0x4e25bc in main (argc=1, argv=0x7ffffdf4) at main.c:635 + + +LDD +=== +This is a program which lists the shared libraries which a library needs, +Note you also get the relocations of the shared library text segments which +help when using objdump --source. +e.g. + ldd ./gdb +outputs +libncurses.so.4 => /usr/lib/libncurses.so.4 (0x40018000) +libm.so.6 => /lib/libm.so.6 (0x4005e000) +libc.so.6 => /lib/libc.so.6 (0x40084000) +/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) + + +Debugging shared libraries +========================== +Most programs use shared libraries, however it can be very painful +when you single step instruction into a function like printf for the +first time & you end up in functions like _dl_runtime_resolve this is +the ld.so doing lazy binding, lazy binding is a concept in ELF where +shared library functions are not loaded into memory unless they are +actually used, great for saving memory but a pain to debug. +To get around this either relink the program -static or exit gdb type +export LD_BIND_NOW=true this will stop lazy binding & restart the gdb'ing +the program in question. + + + +Debugging modules +================= +As modules are dynamically loaded into the kernel their address can be +anywhere to get around this use the -m option with insmod to emit a load +map which can be piped into a file if required. + +The proc file system +==================== +What is it ?. +It is a filesystem created by the kernel with files which are created on demand +by the kernel if read, or can be used to modify kernel parameters, +it is a powerful concept. + +e.g. + +cat /proc/sys/net/ipv4/ip_forward +On my machine outputs +0 +telling me ip_forwarding is not on to switch it on I can do +echo 1 > /proc/sys/net/ipv4/ip_forward +cat it again +cat /proc/sys/net/ipv4/ip_forward +On my machine now outputs +1 +IP forwarding is on. +There is a lot of useful info in here best found by going in & having a look around, +so I'll take you through some entries I consider important. + +All the processes running on the machine have there own entry defined by +/proc/ +So lets have a look at the init process +cd /proc/1 + +cat cmdline +emits +init [2] + +cd /proc/1/fd +This contains numerical entries of all the open files, +some of these you can cat e.g. stdout (2) + +cat /proc/29/maps +on my machine emits + +00400000-00478000 r-xp 00000000 5f:00 4103 /bin/bash +00478000-0047e000 rw-p 00077000 5f:00 4103 /bin/bash +0047e000-00492000 rwxp 00000000 00:00 0 +40000000-40015000 r-xp 00000000 5f:00 14382 /lib/ld-2.1.2.so +40015000-40016000 rw-p 00014000 5f:00 14382 /lib/ld-2.1.2.so +40016000-40017000 rwxp 00000000 00:00 0 +40017000-40018000 rw-p 00000000 00:00 0 +40018000-4001b000 r-xp 00000000 5f:00 14435 /lib/libtermcap.so.2.0.8 +4001b000-4001c000 rw-p 00002000 5f:00 14435 /lib/libtermcap.so.2.0.8 +4001c000-4010d000 r-xp 00000000 5f:00 14387 /lib/libc-2.1.2.so +4010d000-40111000 rw-p 000f0000 5f:00 14387 /lib/libc-2.1.2.so +40111000-40114000 rw-p 00000000 00:00 0 +40114000-4011e000 r-xp 00000000 5f:00 14408 /lib/libnss_files-2.1.2.so +4011e000-4011f000 rw-p 00009000 5f:00 14408 /lib/libnss_files-2.1.2.so +7fffd000-80000000 rwxp ffffe000 00:00 0 + + +Showing us the shared libraries init uses where they are in memory +& memory access permissions for each virtual memory area. + +/proc/1/cwd is a softlink to the current working directory. +/proc/1/root is the root of the filesystem for this process. + +/proc/1/mem is the current running processes memory which you +can read & write to like a file. +strace uses this sometimes as it is a bit faster than the +rather inefficent ptrace interface for peeking at DATA. + + +cat status + +Name: init +State: S (sleeping) +Pid: 1 +PPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +Groups: +VmSize: 408 kB +VmLck: 0 kB +VmRSS: 208 kB +VmData: 24 kB +VmStk: 8 kB +VmExe: 368 kB +VmLib: 0 kB +SigPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 7fffffffd7f0d8fc +SigCgt: 00000000280b2603 +CapInh: 00000000fffffeff +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff + +User PSW: 070de000 80414146 +task: 004b6000 tss: 004b62d8 ksp: 004b7ca8 pt_regs: 004b7f68 +User GPRS: +00000400 00000000 0000000b 7ffffa90 +00000000 00000000 00000000 0045d9f4 +0045cafc 7ffffa90 7fffff18 0045cb08 +00010400 804039e8 80403af8 7ffff8b0 +User ACRS: +00000000 00000000 00000000 00000000 +00000001 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +Kernel BackChain CallChain BackChain CallChain + 004b7ca8 8002bd0c 004b7d18 8002b92c + 004b7db8 8005cd50 004b7e38 8005d12a + 004b7f08 80019114 +Showing among other things memory usage & status of some signals & +the processes'es registers from the kernel task_structure +as well as a backchain which may be useful if a process crashes +in the kernel for some unknown reason. + +Some driver debugging techniques +================================ +high level debugging network drivers +------------------------------------ +ifconfig is a quite useful command +it gives the current state of network drivers. + +If you suspect your network device driver is dead +one way to check is type +ifconfig +e.g. tr0 +You should see something like +tr0 Link encap:16/4 Mbps Token Ring (New) HWaddr 00:04:AC:20:8E:48 + inet addr:9.164.185.132 Bcast:9.164.191.255 Mask:255.255.224.0 + UP BROADCAST RUNNING MULTICAST MTU:2000 Metric:1 + RX packets:246134 errors:0 dropped:0 overruns:0 frame:0 + TX packets:5 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + +if the device doesn't say up +try +/etc/rc.d/init.d/network start +( this starts the network stack & hopefully calls ifconfig tr0 up ). +ifconfig looks at the output of /proc/net/dev & presents it in a more presentable form +Now ping the device from a machine in the same subnet. +if the RX packets count & TX packets counts don't increment you probably +have problems. +next +cat /proc/net/arp +Do you see any hardware addresses in the cache if not you may have problems. +Next try +ping -c 5 i.e. the Bcast field above in the output of +ifconfig. Do you see any replies from machines other than the local machine +if not you may have problems. also if the TX packets count in ifconfig +hasn't incremented either you have serious problems in your driver +(e.g. the txbusy field of the network device being stuck on ) +or you may have multiple network devices connected. + + +chandev +------- +There is a new device layer for channel devices, some +drivers e.g. lcs are registered with this layer. +If the device uses the channel device layer you'll be +able to find what interupts it uses & the current state +of the device. +See the manpage chandev.8 &type cat /proc/chandev for more info. + + + +Starting points for debugging scripting languages etc. +====================================================== + +bash/sh + +bash -x +e.g. bash -x /usr/bin/bashbug +displays the following lines as it executes them. ++ MACHINE=i586 ++ OS=linux-gnu ++ CC=gcc ++ CFLAGS= -DPROGRAM='bash' -DHOSTTYPE='i586' -DOSTYPE='linux-gnu' -DMACHTYPE='i586-pc-linux-gnu' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./lib -O2 -pipe ++ RELEASE=2.01 ++ PATCHLEVEL=1 ++ RELSTATUS=release ++ MACHTYPE=i586-pc-linux-gnu + +perl -d runs the perlscript in a fully intercative debugger +. +Type 'h' in the debugger for help. + +for debugging java type +jdb another fully interactive gdb style debugger. +& type ? in the debugger for help. + + +Debugging Drivers +================= +Some of our drivers now support a debug logging feature in +/proc/s390dbf see s390dbf.txt in the linux/Documentation directory +for more info. +e.g. +to switch on lcs debugging +echo 5 > /proc/s390dbf/lcs/level +& then after the error occured. +cat /proc/s390dbf/lcs/sprintf >/logfile +the logfile now contains some information which may help +tech support resolve a problem in the field. + +If you have VM look at the chapter Debugging IO on S390 under VM. + + + + +Tools soon to be available +========================== + +Dumptool & Lcrash +----------------- +Michael Holzheu & others here at IBM have a fairly mature port of +SGI's lcrash tool which allows one to look at kernel structures in a +running kernel. + +It also complements a tool called dumptool which dumps all the kernels +memory pages & registers to either a tape or a disk. +This can be used by tech support or an ambitous end user do +post mortem debugging of a machine like gdb core dumps. + +Going into how to use this tool in detail will be explained +in other documentation supplied by IBM & the lcrash homepage +http://oss.sgi.com/projects/lkcd/. + +How they work +------------- +Lcrash is a perfectly normal application +however it requires an additional file. +It is built using a patch to the kernel source base. + + +Debugging a live system it uses /dev/mem +alternatively for post mortem debugging it uses the data +collected by dumptool. + + +Ltrace +------ +We also have a tool called ltrace in our CVS repository +no plans on a delivery date yet. +ltrace is a superset of strace in that it also allows +tracing of shared libraries calls as well as system calls, +man ltrace for more info. + +SysRq +===== +This is now supported by linux for s/390 & zSeries. +To enable it do compile the kernel with +Kernel Hacking -> Magic SysRq Key Enabled +echo "1" > /proc/sys/kernel/sysrq. +On 390 all commands are prefixed with +^- +e.g. +^-t will show tasks. +^-? or some unknown command will display help. +The sysrq key reading is very picky ( I have to type the keys in an + xterm session & paste them into the x3270 console ) +& it may be wise to predefine the keys as described in the VM hints above + +This is particularly useful for syncing disks unmounting & rebooting +if the machine gets partially hung. + +Read Documentation/sysrq.txt for more info + +References: +=========== +Enterprise Systems Architecture Reference Summary +Enterprise Systems Architecture Principles of Operation +Hartmut Penners s390 stack frame sheet. +IBM Mainframe Channel Attachment a technology brief from a CISCO webpage +Various bits of man & info pages of Linux. +Linux & GDB source. +Various info & man pages. +CMS Help on tracing commands. +Linux for s/390 Elf Application Binary Interface +Linux for zSeries Elf Application Binary Interface ( Both Highly Recommended ) +z/Architecture Principles of Operation SA22-7832-00 +Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the +Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05 + + + + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/chandev.8 linux.ac/Documentation/s390/chandev.8 --- linux.vanilla/Documentation/s390/chandev.8 Fri Feb 16 23:53:08 2001 +++ linux.ac/Documentation/s390/chandev.8 Thu Apr 12 11:48:05 2001 @@ -42,8 +42,16 @@ .It Or from the boot command line using the 'chandev=' keyword .El +.Bl -item +.It Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows. /bin/chandev . +The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script. +.It +#!/bin/bash +.It +exec >/dev/console 2>&1 0>&1 +.El e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the parameters would be. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/config3270.sh linux.ac/Documentation/s390/config3270.sh --- linux.vanilla/Documentation/s390/config3270.sh Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/config3270.sh Thu Apr 12 11:48:15 2001 @@ -0,0 +1,66 @@ +#!/bin/sh +# +# config3270 -- Autoconfigure /dev/3270/* and /etc/inittab +# +# Usage: +# config3270 +# +# Output: +# /tmp/mkdev3270 +# +# Operation: +# 1. Run this script +# 2. Run the script it produces: /tmp/mkdev3270 +# 3. Issue "telinit q" or reboot, as appropriate. +# +P=/proc/tty/driver/tty3270 +ROOT= +D=$ROOT/dev +SUBD=3270 +TTY=$SUBD/tty +TUB=$SUBD/tub +SCR=$ROOT/tmp/mkdev3270 +SCRTMP=$SCR.a +GETTYLINE=:2345:respawn:/sbin/mingetty +INITTAB=$ROOT/etc/inittab +NINITTAB=$ROOT/etc/NEWinittab +OINITTAB=$ROOT/etc/OLDinittab +ADDNOTE=\\"# Additional mingettys for the 3270/tty* driver, tub3270 ---\\" + +if ! ls $P > /dev/null 2>&1; then + modprobe tub3270 > /dev/null 2>&1 +fi +ls $P > /dev/null 2>&1 || exit 1 + +# Initialize two files, one for /dev/3270 commands and one +# to replace the /etc/inittab file (old one saved in OLDinittab) +echo "#!/bin/sh" > $SCR || exit 1 +echo " " >> $SCR +echo "# Script built by /sbin/config3270" >> $SCR +echo rm -rf "$D/$SUBD/*" >> $SCR +echo "grep -v $TTY $INITTAB > $NINITTAB" > $SCRTMP || exit 1 +echo "echo $ADDNOTE >> $NINITTAB" >> $SCRTMP +echo mkdir -p $D/$SUBD >> $SCR + +# Now query the tub3270 driver for 3270 device information +# and add appropriate mknod and mingetty lines to our files +echo what=config > $P +while read devno maj min;do + if [ $min = 0 ]; then + fsmaj=$maj + echo mknod $D/$TUB c $fsmaj 0 >> $SCR + echo chmod 666 $D/$TUB >> $SCR + elif [ $maj = CONSOLE ]; then + echo mknod $D/$TUB$devno c $fsmaj $min >> $SCR + else + echo mknod $D/$TTY$devno c $maj $min >>$SCR + echo mknod $D/$TUB$devno c $fsmaj $min >> $SCR + echo "echo t$min$GETTYLINE $TTY$devno >> $NINITTAB" >> $SCRTMP + fi +done < $P + +echo mv $INITTAB $OINITTAB >> $SCRTMP || exit 1 +echo mv $NINITTAB $INITTAB >> $SCRTMP +cat $SCRTMP >> $SCR +rm $SCRTMP +exit 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/s390dbf.txt linux.ac/Documentation/s390/s390dbf.txt --- linux.vanilla/Documentation/s390/s390dbf.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/s390/s390dbf.txt Thu Apr 12 11:48:15 2001 @@ -0,0 +1,558 @@ +S390 Debug Feature +================== + +files: arch/s390/kernel/debug.c + include/asm-s390/debug.h + +Description: +------------ +The goal of this feature is to provide a kernel debug logging API +where log records can be stored efficiently in memory, where each component +(e.g. device drivers) can have one seperate debug log. +One purpose of this is to inspect the debug logs after a production system crash +in order to analyze the reason for the crash. +If the system still runs but only a subcomponent which uses dbf failes, +it is possible to look at the debug logs on a live system via the Linux proc +filesystem. +The debug feature may also very usefull for kernel and driver development. + +Design: +------- +Kernel components (e.g. device drivers) can register themselves at the debug +feature with the function call debug_register(). This function initializes a +debug log for the caller. For each debug log exists a number of debug areas +where exactly one is active at one time. Each debug area consists of contiguous +pages in memory. In the debug areas there are stored debug entries (log records) +which are written by event- and exception-calls. + +An event-call writes the specified debug entry to the active debug +area and updates the log pointer for the active area. If the end +of the active debug area is reached, a wrap around is done (ring buffer) +and the next debug entry will be written at the beginning of the active +debug area. + +An exception-call writes the specified debug entry to the log and +switches to the next debug area. This is done in order to be sure +that the records which describe the origin of the exception are not +overwritten when a wrap around for the current area occurs. + +The debug areas itselve are also ordered in form of a ring buffer. +When an exception is thrown in the last debug area, the following debug +entries are then written again in the very first area. + +There are three versions for the event- and exception-calls: One for +logging raw data, one for text and one for numbers. + +Each debug entry contains the following data: + +- Timestamp +- Cpu-Number of calling task +- Level of debug entry (0...6) +- Return Address to caller +- Flag, if entry is an exception or not + +The debug logs can be inspected in a live system through entries in +the proc-filesystem. Under the path /proc/s390dbf there is +a directory for each registered component, which is named like the +corresponding component. + +The content of the directories are files which represent different views +to the debug log. Each component can decide which views should be +used through registering them with the function debug_register_view(). +Predefined views for hex/ascii, sprintf and raw binary data are provided. +It is also possible to define other views. The content of +a view can be inspected simply by reading the corresponding proc file. + +All debug logs have an an actual debug level (range from 0 to 6). +The default level is 3. Event and Exception functions have a 'level' +parameter. Only debug entries with a level that is lower or equal +than the actual level are written to the log. This means that high +priority log entries should have a low level value whereas low priority +entries should have a high one. +The actual debug level can be changed with the help of the proc-filesystem +through writing a number string "x" to the 'level' proc file which is +provided for every debug log. Debugging can be switched off completely +by using "-" on the 'level' proc file. + +Example: + +> echo "-" > /proc/s390dbf/dasd/level + +Kernel Interfaces: +------------------ + +---------------------------------------------------------------------------- +debug_info_t *debug_register(char *name, int pages_index, int nr_areas, + int buf_size); + +Parameter: name: Name of debug log (e.g. used for proc entry) + pages_index: 2^pages_index pages will be allocated per area + nr_areas: number of debug areas + buf_size: size of data area in each debug entry + +Return Value: Handle for generated debug area + NULL if register failed + +Description: Allocates memory for a debug log + Must not be called within an interrupt handler + +--------------------------------------------------------------------------- +void debug_unregister (debug_info_t * id); + +Parameter: id: handle for debug log + +Return Value: none + +Description: frees memory for a debug log + Must not be called within an interrupt handler + +--------------------------------------------------------------------------- +void debug_set_level (debug_info_t * id, int new_level); + +Parameter: id: handle for debug log + new_level: new debug level + +Return Value: none + +Description: Sets new actual debug level if new_level is valid. +--------------------------------------------------------------------------- +debug_entry_t* debug_event (debug_info_t* id, int level, void* data, + int length); + +Parameter: id: handle for debug log + level: debug level + data: pointer to data for debug entry + length: length of data in bytes + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) + +--------------------------------------------------------------------------- +debug_entry_t* debug_int_event (debug_info_t * id, int level, + unsigned int data); +debug_entry_t* debug_long_event(debug_info_t * id, int level, + unsigned long data); + +Parameter: id: handle for debug log + level: debug level + data: integer value for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) + +--------------------------------------------------------------------------- +debug_entry_t* debug_text_event (debug_info_t * id, int level, + const char* data); + +Parameter: id: handle for debug log + level: debug level + data: string for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry in ascii format to active debug area + (if level <= actual debug level) + +--------------------------------------------------------------------------- +debug_entry_t* debug_sprintf_event (debug_info_t * id, int level, + char* string,...); + +Parameter: id: handle for debug log + level: debug level + string: format string for debug entry + ...: varargs used as in sprintf() + +Return Value: Address of written debug entry + +Description: writes debug entry with format string and varargs (longs) to + active debug area (if level $<=$ actual debug level). + floats and long long datatypes cannot be used as varargs. + +--------------------------------------------------------------------------- + +debug_entry_t* debug_exception (debug_info_t* id, int level, void* data, + int length); + +Parameter: id: handle for debug log + level: debug level + data: pointer to data for debug entry + length: length of data in bytes + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) and switches to next debug area + +--------------------------------------------------------------------------- +debug_entry_t* debug_int_exception (debug_info_t * id, int level, + unsigned int data); +debug_entry_t* debug_long_exception(debug_info_t * id, int level, + unsigned long data); + +Parameter: id: handle for debug log + level: debug level + data: integer value for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry to active debug area (if level <= actual + debug level) and switches to next debug area + +--------------------------------------------------------------------------- +debug_entry_t* debug_text_exception (debug_info_t * id, int level, + const char* data); + +Parameter: id: handle for debug log + level: debug level + data: string for debug entry + +Return Value: Address of written debug entry + +Description: writes debug entry in ascii format to active debug area + (if level <= actual debug level) and switches to next debug + area + +--------------------------------------------------------------------------- +debug_entry_t* debug_sprintf_exception (debug_info_t * id, int level, + char* string,...); + +Parameter: id: handle for debug log + level: debug level + string: format string for debug entry + ...: varargs used as in sprintf() + +Return Value: Address of written debug entry + +Description: writes debug entry with format string and varargs (longs) to + active debug area (if level $<=$ actual debug level) and + switches to next debug area. + floats and long long datatypes cannot be used as varargs. + +--------------------------------------------------------------------------- + +int debug_register_view (debug_info_t * id, struct debug_view *view); + +Parameter: id: handle for debug log + view: pointer to debug view struct + +Return Value: 0 : ok + < 0: Error + +Description: registers new debug view and creates proc dir entry + +--------------------------------------------------------------------------- +int debug_unregister_view (debug_info_t * id, struct debug_view *view); + +Parameter: id: handle for debug log + view: pointer to debug view struct + +Return Value: 0 : ok + < 0: Error + +Description: unregisters debug view and removes proc dir entry + + + +Predefined views: +----------------- + +extern struct debug_view debug_hex_ascii_view; +extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +Examples +-------- + +/* + * hex_ascii- + raw-view Example + */ + +#include +#include + +static debug_info_t* debug_info; + +int init_module(void) +{ + /* register 4 debug areas with one page each and 4 byte data field */ + + debug_info = debug_register ("test", 0, 4, 4 ); + debug_register_view(debug_info,&debug_hex_ascii_view); + debug_register_view(debug_info,&debug_raw_view); + + debug_text_event(debug_info, 4 , "one "); + debug_int_exception(debug_info, 4, 4711); + debug_event(debug_info, 3, &debug_info, 4); + + return 0; +} + +void cleanup_module(void) +{ + debug_unregister (debug_info); +} + +--------------------------------------------------------------------------- + +/* + * sprintf-view Example + */ + +#include +#include + +static debug_info_t* debug_info; + +int init_module(void) +{ + /* register 4 debug areas with one page each and data field for */ + /* format string pointer + 2 varargs (= 3 * sizeof(long)) */ + + debug_info = debug_register ("test", 0, 4, sizeof(long) * 3); + debug_register_view(debug_info,&debug_sprintf_view); + + debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__); + debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info); + + return 0; +} + +void cleanup_module(void) +{ + debug_unregister (debug_info); +} + + + +ProcFS Interface +---------------- +Views to the debug logs can be investigated through reading the corresponding +proc-files: + +Example: + +> ls /proc/s390dbf/dasd +hex_ascii level raw +> cat /proc/s390dbf/dasd/hex_ascii | sort +1 +00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | .... +00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE +00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | .... +00 00974733272:682281 1 * 02 0006ab08 41 4c 4c 43 | EXCP +01 00974733272:682284 2 - 02 0006ab16 45 43 4b 44 | ECKD +01 00974733272:682287 2 - 02 0006ab28 00 00 00 04 | .... +01 00974733272:682289 2 - 02 0006ab3e 00 00 00 20 | ... +01 00974733272:682297 2 - 02 0006ad7e 07 ea 4a 90 | .... +01 00974733272:684384 2 - 00 0006ade6 46 52 45 45 | FREE +01 00974733272:684388 2 - 00 0006adf6 07 ea 4a 90 | .... + +See section about predefined views for explanation of the above output! + +Changing the debug level +------------------------ + +Example: + + +> cat /proc/s390dbf/dasd/level +3 +> echo "5" > /proc/s390dbf/dasd/level +> cat /proc/s390dbf/dasd/level +5 + +lcrash Interface +---------------- +It is planned that the dump analysis tool lcrash gets an additional command +'s390dbf' to display all the debug logs. With this tool it will be possible +to investigate the debug logs on a live system and with a memory dump after +a system crash. + +Investigating raw memory +------------------------ +One last possibility to investigate the debug logs at a live +system and after a system crash is to look at the raw memory +under VM or at the Service Element. +It is possible to find the anker of the debug-logs through +the 'debug_area_first' symbol in the System map. Then one has +to follow the correct pointers of the data-structures defined +in debug.h and find the debug-areas in memory. +Normally modules which use the debug feature will also have +a global variable with the pointer to the debug-logs. Following +this pointer it will also be possible to find the debug logs in +memory. + +For this method it is recommended to use '16 * x + 4' byte (x = 0..n) +for the length of the data field in debug_register() in +order to see the debug entries well formatted. + + +Predefined Views +---------------- + +There are three predefined views: hex_ascii, raw and sprintf. +The hex_ascii view shows the data field in hex and ascii representation +(e.g. '45 43 4b 44 | ECKD'). +The raw view returns a bytestream as the debug areas are stored in memory. + +The sprintf view formats the debug entries in the same way as the sprintf +function would do. The sprintf event/expection fuctions write to the +debug entry a pointer to the format string (size = sizeof(long)) +and for each vararg a long value. So e.g. for a debug entry with a format +string plus two varargs one would need to allocate a (3 * sizeof(long)) +byte data area in the debug_register() function. + + +NOTE: If using the sprintf view do NOT use other event/exception functions +than the sprintf-event and -exception functions. + +The format of the hex_ascii and sprintf view is as follows: +- Number of area +- Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated + Universal Time (UTC), January 1, 1970) +- level of debug entry +- Exception flag (* = Exception) +- Cpu-Number of calling task +- Return Address to caller +- data field + +The format of the raw view is: +- Header as described in debug.h +- datafield + +A typical line of the hex_ascii view will look like the following (first line +is only for explanation and will not be displayed when 'cating' the view): + +area time level exception cpu caller data (hex + ascii) +-------------------------------------------------------------------------- +00 00964419409:440690 1 - 00 88023fe + + +Defining views +-------------- + +Views are specified with the 'debug_view' structure. There are defined +callback functions which are used for reading and writing the proc files: + +struct debug_view { + char name[DEBUG_MAX_PROCF_LEN]; + debug_prolog_proc_t* prolog_proc; + debug_header_proc_t* header_proc; + debug_format_proc_t* format_proc; + debug_input_proc_t* input_proc; + void* private_data; +}; + +where + +typedef int (debug_header_proc_t) (debug_info_t* id, + struct debug_view* view, + int area, + debug_entry_t* entry, + char* out_buf); + +typedef int (debug_format_proc_t) (debug_info_t* id, + struct debug_view* view, char* out_buf, + const char* in_buf); +typedef int (debug_prolog_proc_t) (debug_info_t* id, + struct debug_view* view, + char* out_buf); +typedef int (debug_input_proc_t) (debug_info_t* id, + struct debug_view* view, + struct file* file, const char* user_buf, + size_t in_buf_size, loff_t* offset); + + +The "private_data" member can be used as pointer to view specific data. +It is not used by the debug feature itself. + +The output when reading a debug-proc file is structured like this: + +"prolog_proc output" + +"header_proc output 1" "format_proc output 1" +"header_proc output 2" "format_proc output 2" +"header_proc output 3" "format_proc output 3" +... + +When a view is read from the proc fs, the Debug Feature calls the +'prolog_proc' once for writing the prolog. +Then 'header_proc' and 'format_proc' are called for each +existing debug entry. + +The input_proc can be used to implement functionality when it is written to +the view (e.g. like with 'echo "0" > /proc/s390dbf/dasd/level). + +For header_proc there can be used the default function +debug_dflt_header_fn() which is defined in in debug.h. +and which produces the same header output as the predefined views. +E.g: +00 00964419409:440761 2 - 00 88023ec + +In order to see how to use the callback functions check the implementation +of the default views! + +Example + +#include + +#define UNKNOWNSTR "data: %08x" + +const char* messages[] = +{"This error...........\n", + "That error...........\n", + "Problem..............\n", + "Something went wrong.\n", + "Everything ok........\n", + NULL +}; + +static int debug_test_format_fn( + debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf +) +{ + int i, rc = 0; + + if(id->buf_size >= 4) { + int msg_nr = *((int*)in_buf); + if(msg_nr < sizeof(messages)/sizeof(char*) - 1) + rc += sprintf(out_buf, "%s", messages[msg_nr]); + else + rc += sprintf(out_buf, UNKNOWNSTR, msg_nr); + } + out: + return rc; +} + +struct debug_view debug_test_view = { + "myview", /* name of view */ + NULL, /* no prolog */ + &debug_dflt_header_fn, /* default header for each entry */ + &debug_test_format_fn, /* our own format function */ + NULL, /* no input function */ + NULL /* no private data */ +}; + +===== +test: +===== +debug_info_t *debug_info; +... +debug_info = debug_register ("test", 0, 4, 4 )); +debug_register_view(debug_info, &debug_test_view); +for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i); + +> cat /proc/s390dbf/test/myview +00 00964419734:611402 1 - 00 88042ca This error........... +00 00964419734:611405 1 - 00 88042ca That error........... +00 00964419734:611408 1 - 00 88042ca Problem.............. +00 00964419734:611411 1 - 00 88042ca Something went wrong. +00 00964419734:611414 1 - 00 88042ca Everything ok........ +00 00964419734:611417 1 - 00 88042ca data: 00000005 +00 00964419734:611419 1 - 00 88042ca data: 00000006 +00 00964419734:611422 1 - 00 88042ca data: 00000007 +00 00964419734:611425 1 - 00 88042ca data: 00000008 +00 00964419734:611428 1 - 00 88042ca data: 00000009 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/scsi-generic.txt linux.ac/Documentation/scsi-generic.txt --- linux.vanilla/Documentation/scsi-generic.txt Fri Feb 9 00:32:44 2001 +++ linux.ac/Documentation/scsi-generic.txt Sat Apr 14 01:14:37 2001 @@ -1,6 +1,6 @@ - Notes on Linux's SG driver version 2.1.36 + Notes on Linux's SG driver version 2.1.39 ----------------------------------------- - 20000110 + 20010329 Introduction ============ @@ -12,7 +12,7 @@ amongst other things. These are notes on the Linux SCSI generic packet device driver (sg) -describing version 2.1.36 . The original driver was written by Lawrence +describing version 2.1.39 . The original driver was written by Lawrence Foard and remained in place with minimal changes since circa 1992. Version 2 of this driver remains backward compatible (binary and source **) with the original. It adds scatter gather, command queuing, @@ -23,6 +23,10 @@ at the linux/Documentation directory. The full document can be found at http://www.torque.net/sg/p/scsi-generic_long.txt . +The Linux 2.4 series kernels have now been released. Lk 2.4 contains +an upgraded "version 3" sg driver which is described in a supplementary +document at http://www.torque.net/sg/p/scsi-generic_v3.txt . + The interface and usage of the original sg driver have been documented by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy of the document is version 1.5 dated 7th May 1996. It can found at @@ -41,7 +45,8 @@ The SCSI generic packet device driver (sg) is a character based device. It is one of the four high level device driver in the SCSI sub-system; the others are sd (for direct-access devices - disks), st (for tapes) -and sr (for data cdroms). The other three devices are block devices. +and sr (for data cdroms). Sd and sr are block devices while st (like sg) +is a character device. The unifying layer of the SCSI sub-system is the so-called mid-level. Below that are the "low level" drivers which are the drivers for the @@ -233,13 +238,14 @@ open(const char * filename, int flags) -------------------------------------- The filename should be an 'sg' device such as -/dev/sg[a-z] /dev/sg[0,1,2,...] +/dev/sg[a-z] <<< now deprecated >>> or a symbolic link to one of these. [Devfs has its own sub-directory for -sg devices with entries like: /dev/sg/c1b2t3u4 .] It seems as though SCSI -devices are allocated to sg minor numbers in the same order as they appear -in 'cat /proc/scsi/scsi'. Sg is a "character" based Linux device driver. -This means it has an open/close/read/write/ioctl type interface. +sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .] +It seems as though SCSI devices are allocated to sg minor numbers in the +same order as they appear in 'cat /proc/scsi/scsi'. Sg is a "character" +based Linux device driver. This means it has an open/close/read/write/ioctl +type interface. Flags can be either O_RDONLY or O_RDWR or-ed with either O_EXCL waits for other opens on sg device to be closed before @@ -396,7 +402,7 @@ (which is called 'sg_release()' in the version 2 driver) to facilitate the cleanup mentioned above. -A problem persists in version 2.1.36 if the sg driver is a module and is +A problem persists in version 2.1.39 if the sg driver is a module and is removed while packets are still "in flight". Returns 0 if successful, otherwise -1 implies an error. @@ -595,6 +601,8 @@ do much (may in the future after other issues are resolved). Yields an EBUSY error if the SCSI bus or the associated device is being reset when this ioctl() is called, otherwise returns 0. +N.B. In some recent distributions there is a patch to the SCSI mid level +code that activates this ioctl. Check your distribution. SG_SET_DEBUG +: Assumes 3rd argument is pointing to an int. 0 (default) turns debugging @@ -640,7 +648,7 @@ found, switching to normal blocked io. A working example of this logic is in the sg_scan utility program. -open("/dev/sga", O_RDONLY | O_NONBLOCK) +open("/dev/sg0", O_RDONLY | O_NONBLOCK) /* check device, EBUSY means some other process has O_EXCL lock on it */ /* when the device you want is found then ... */ flags = fcntl(sg_fd, F_GETFL) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/MAD16 linux.ac/Documentation/sound/MAD16 --- linux.vanilla/Documentation/sound/MAD16 Mon Aug 23 18:23:23 1999 +++ linux.ac/Documentation/sound/MAD16 Fri Apr 20 14:59:49 2001 @@ -1,3 +1,5 @@ +(This recipe has been edited to update the configuration symbols.) + From: Shaw Carruthers I have been using mad16 sound for some time now with no problems, current @@ -14,9 +16,9 @@ .config has: CONFIG_SOUND=m -CONFIG_ADLIB=m -CONFIG_MAD16=m -CONFIG_YM3812=m +CONFIG_SOUND_ADLIB=m +CONFIG_SOUND_MAD16=m +CONFIG_SOUND_YM3812=m modules.conf has: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/Opti linux.ac/Documentation/sound/Opti --- linux.vanilla/Documentation/sound/Opti Wed Mar 8 19:37:03 2000 +++ linux.ac/Documentation/sound/Opti Fri Apr 20 14:59:49 2001 @@ -29,21 +29,21 @@ Sound card support should be enabled as a module (chose m). Answer 'm' for these items: - Generic OPL2/OPL3 FM synthesizer support (CONFIG_ADLIB) - Microsoft Sound System support (CONFIG_MSS) - Support for OPTi MAD16 and/or Mozart based cards (CONFIG_MAD16) - FM synthesizer (YM3812/OPL-3) support (CONFIG_YM3812) + Generic OPL2/OPL3 FM synthesizer support (CONFIG_SOUND_ADLIB) + Microsoft Sound System support (CONFIG_SOUND_MSS) + Support for OPTi MAD16 and/or Mozart based cards (CONFIG_SOUND_MAD16) + FM synthesizer (YM3812/OPL-3) support (CONFIG_SOUND_YM3812) The configuration menu may ask for addresses, IRQ lines or DMA channels. If the card is used as a module the module loading options will override these values. For the OPTi 931 you can answer 'n' to: - Support MIDI in older MAD16 based cards (requires SB) (CONFIG_MAD16_OLDCARD) + Support MIDI in older MAD16 based cards (requires SB) (CONFIG_SOUND_MAD16_OLDCARD) If you do need MIDI support in a Mozart or C928 based card you need to answer 'm' to the above question. In that case you will also need to answer 'm' to: - '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SB) + '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SOUND_SB) Go on and compile your kernel and modules. Install the modules. Run depmod -a. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/PAS16 linux.ac/Documentation/sound/PAS16 --- linux.vanilla/Documentation/sound/PAS16 Sun Apr 2 23:38:53 2000 +++ linux.ac/Documentation/sound/PAS16 Thu Apr 12 11:48:29 2001 @@ -1,7 +1,7 @@ Pro Audio Spectrum 16 for 2.3.99 and later ========================================= by Thomas Molina (tmolina@home.com) -last modified 26 Mar 2000 +last modified 3 Mar 2001 Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken from Configure.help, Riccardo Facchetti for stuff from README.OSS, and others whose names I could not find. @@ -48,14 +48,6 @@ if you want to use the SB emulation of PAS16. It's also possible to the emulation if you want to use a true SB card together with PAS16 (there is another question about this that is asked later). - "Sound Blaster support", - - Answer 'y' if you have an original SB card made by Creative Labs - or a full 100% hardware compatible clone (like Thunderboard or - SM Games). If your card was in the list of supported cards (above), - please look at the card specific instructions later in this file - before answering this question. For an unknown card you may answer - 'y' if the card claims to be SB compatible. - Enable this option also with PAS16. "Generic OPL2/OPL3 FM synthesizer support", - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -113,27 +105,13 @@ Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio 16 or Logitech SoundMan 16 sound card. Don't answer Y if you have some other card made by Media Vision or Logitech since they are not - PAS16 compatible. + PAS16 compatible. It is not necessary to enable the separate + Sound Blaster support; it is included in the PAS driver. + If you compile the driver into the kernel, you have to add "pas2=,,,,,,, to the kernel command line. -100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support -CONFIG_SOUND_SB - Answer Y if you have an original Sound Blaster card made by Creative - Labs or a 100% hardware compatible clone (like the Thunderboard or - SM Games). For an unknown card you may answer Y if the card claims - to be Sound Blaster-compatible. The PAS16 has 8-bit Soundblaster - support, so you can answer Y here for it. - - Please read the file Documentation/sound/Soundblaster. - - If you compile the driver into the kernel and don't want to use isapnp, - you have to add "sb=,,," to the kernel command line. - - You can say M here to compile this driver as a module; the module is - called sb.o. - FM Synthesizer (YM3812/OPL-3) support CONFIG_SOUND_YM3812 Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -167,7 +145,7 @@ CONFIG_SOUND_TRACEINIT=y CONFIG_SOUND_DMAP=y CONFIG_SOUND_PAS=y -CONFIG_SOUND_SB=y +CONFIG_SOUND_SB=n CONFIG_SOUND_YM3812=m I have also included the following append line in /etc/lilo.conf: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/PCM1-pro linux.ac/Documentation/sound/PCM1-pro --- linux.vanilla/Documentation/sound/PCM1-pro Tue Apr 13 00:18:27 1999 +++ linux.ac/Documentation/sound/PCM1-pro Thu Jan 1 01:00:00 1970 @@ -1,17 +0,0 @@ -In Documentation/sound/README.OSS was a remark saying noone was sure the -mixer on the PCM1-pro worked with the ACI driver. Well, it does. -I've been using the drivers for the MAD16 and the driver for the mixer -since kernel 2.0.32 with a MiroSound PCM1-pro and it works great. - -I've got it working with the following configuration: - -MAD16 audio I/O base = 530 -MAD16 audio IRQ = 7 -MAD16 Audio DMA = 1 -MAD16 MIDI I/O = 330 -MAD16 MIDI IRQ = 9 - -And I've enabled the ACI mixer (miro PCM12) . - - -Bas van der Linden. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/README.OSS linux.ac/Documentation/sound/README.OSS --- linux.vanilla/Documentation/sound/README.OSS Fri Jul 28 20:50:52 2000 +++ linux.ac/Documentation/sound/README.OSS Thu Apr 12 11:48:29 2001 @@ -17,6 +17,7 @@ document can be still interesting and very helpful. [ File edited 17.01.1999 - Riccardo Facchetti ] +[ Edited miroSOUND section 17.09.2000 - Robert Siemer ] OSS/Free version 3.8 release notes ---------------------------------- @@ -1325,26 +1326,38 @@ miroSOUND --------- -The miroSOUND PCM12 has been used successfully. This card is based on -the MAD16, OPL4, and CS4231A chips and everything said in the section -about MAD16 cards applies here, too. The only major difference between -the PCM12 and other MAD16 cards is that instead of the mixer in the -CS4231 codec a separate mixer controlled by an on-board 80C32 -microcontroller is used. Control of the mixer takes place via the ACI -(miro's audio control interface) protocol that is implemented in a -separate lowlevel driver. Make sure you compile this ACI driver -together with the normal MAD16 support when you use a miroSOUND PCM12 -card. The ACI mixer is controlled by /dev/mixer and the CS4231 mixer -by /dev/mixer2. You usually don't want to change anything on the -CS4231 mixer. - -The miroSOUND PCM12 is capable of full duplex operation (simultaneous -PCM replay and recording), which allows you to implement nice -real-time signal processing audio effect software and network -telephones. The ACI mixer has to be configured into a special "solo" +The miroSOUND PCM1-pro, PCM12 and PCM20 radio has been used +successfully. This card is based on the MAD16, OPL4, and CS4231A chips +and everything said in the section about MAD16 cards applies here, +too. The only major difference between the PCMxx and other MAD16 cards +is that instead of the mixer in the CS4231 codec a separate mixer +controlled by an on-board 80C32 microcontroller is used. Control of +the mixer takes place via the ACI (miro's audio control interface) +protocol that is implemented in a separate lowlevel driver. Make sure +you compile this ACI driver together with the normal MAD16 support +when you use a miroSOUND PCMxx card. The ACI mixer is controlled by +/dev/mixer and the CS4231 mixer by /dev/mixer1 (depends on load +time). Only in special cases you want to change something on the CS4231 +mixer. + +The miroSOUND PCM12 and PCM20 radio is capable of full duplex +operation (simultaneous PCM replay and recording), which allows you to +implement nice real-time signal processing audio effect software and +network telephones. The ACI mixer has to be switched into the "solo" mode for duplex operation in order to avoid feedback caused by the -mixer (input hears output signal). See lowlevel/aci.c for details on -the ioctl() for activating the "solo" mode. +mixer (input hears output signal). You can de-/activate this mode +through toggleing the record button for the wave controller with an +OSS-mixer. + +The PCM20 contains a radio tuner, which is also controlled by +ACI. This radio tuner is supported by the ACI driver together with the +miropcm20.o module. Also the 7-band equalizer is integrated +(limited by the OSS-design). Developement has started and maybe +finished for the RDS decoder on this card, too. You will be able to +read radio text, the program service name, program type and +others. Even the v4l radio module benefits from it with a refined +strength value. See aci.c, radio-miropcm20.c and rds-miropcm20.c for +more details. The following configuration parameters have worked fine for the PCM12 in Markus Kuhn's system, many other configurations might work, too: @@ -1352,13 +1365,8 @@ CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10, DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000. -The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12. -Perhaps the same ACI driver also works for these cards, however this -has never actually been tested. The PCM20 contains a radio tuner, -which is also controlled by ACI. This radio tuner is currently not -supported by the ACI driver, but documentation for it was provided by -miro and ACI tuner support could easily be added if someone is really -interested. +Bas van der Linden is using his PCM1-pro with a configuration that +differs in: CONFIG_MAD16_IRQ=7, CONFIG_MAD16_DMA=1, CONFIG_MAD16_MPU_IRQ=9 Compaq Deskpro XL ----------------- diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/es1370 linux.ac/Documentation/sound/es1370 --- linux.vanilla/Documentation/sound/es1370 Fri Jul 10 22:03:35 1998 +++ linux.ac/Documentation/sound/es1370 Thu Apr 12 11:48:29 2001 @@ -1,3 +1,11 @@ +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -59,4 +67,4 @@ Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/es1371 linux.ac/Documentation/sound/es1371 --- linux.vanilla/Documentation/sound/es1371 Fri Jul 10 22:03:35 1998 +++ linux.ac/Documentation/sound/es1371 Thu Apr 12 11:48:29 2001 @@ -1,3 +1,11 @@ +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -53,4 +61,4 @@ Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/solo1 linux.ac/Documentation/sound/solo1 --- linux.vanilla/Documentation/sound/solo1 Mon Aug 23 19:15:27 1999 +++ linux.ac/Documentation/sound/solo1 Thu Apr 12 11:48:29 2001 @@ -1,3 +1,25 @@ +Recording +--------- + +Recording does not work on the author's card, but there +is at least one report of it working on later silicon. +The chip behaves differently than described in the data sheet, +likely due to a chip bug. Working around this would require +the help of ESS (for example by publishing an errata sheet), +but ESS has not done so so far. + +Also, the chip only supports 24 bit addresses for recording, +which means it cannot work on some Alpha mainboards. + + +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -45,4 +67,4 @@ The card has an OPL compatible FM synthesizer. Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/sonicvibes linux.ac/Documentation/sound/sonicvibes --- linux.vanilla/Documentation/sound/sonicvibes Fri Jul 10 22:03:35 1998 +++ linux.ac/Documentation/sound/sonicvibes Thu Apr 12 11:48:29 2001 @@ -1,3 +1,11 @@ +/proc/sound, /dev/sndstat +------------------------- + +/proc/sound and /dev/sndstat is not supported by the +driver. To find out whether the driver succeeded loading, +check the kernel log (dmesg). + + ALaw/uLaw sample formats ------------------------ @@ -70,4 +78,4 @@ Thomas Sailer -sailer@ife.ee.ethz.ch +t.sailer@alumni.ethz.ch diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sysctl/vm.txt linux.ac/Documentation/sysctl/vm.txt --- linux.vanilla/Documentation/sysctl/vm.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/sysctl/vm.txt Tue Apr 3 17:54:29 2001 @@ -21,6 +21,7 @@ - buffermem - freepages - kswapd +- max_map_count - overcommit_memory - page-cluster - pagecache @@ -171,6 +172,19 @@ and don't use much of it. Look at: mm/mmap.c::vm_enough_memory() for more information. + +============================================================== + +max_map_count: + +This file contains the maximum number of memory map areas a +process may have. Memory map areas are used as a side-effect +of calling malloc, directly by mmap and mprotect, and also +when loading shared libraries. + +While most applications need less than a thousand maps, +certain programs, particularly malloc debuggers, may consume +lots of them, e.g. up to one or two maps per allocation. ============================================================== diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sysrq.txt linux.ac/Documentation/sysrq.txt --- linux.vanilla/Documentation/sysrq.txt Tue Apr 3 17:31:51 2001 +++ linux.ac/Documentation/sysrq.txt Tue Apr 17 15:43:17 2001 @@ -1,26 +1,27 @@ +Linux Magic System Request Key Hacks +Documentation for sysrq.c version 1.15 +Last update: $Date: 2001/01/28 10:15:59 $ - MAGIC SYSRQ KEY DOCUMENTATION v1.32 - ------------------------------------ - [Sat Apr 8 22:15:03 CEST 2000] - -* What is the magic SysRQ key? +* What is the magic SysRq key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It is a 'magical' key combo you can hit which kernel will respond to +It is a 'magical' key combo you can hit which the kernel will respond to regardless of whatever else it is doing, unless it is completely locked up. -* How do I enable the magic SysRQ key? +* How do I enable the magic SysRq key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when -configuring the kernel. This option is only available in 2.1.x or later -kernels. Once you boot the new kernel, you need to enable it manually -using following command: +configuring the kernel. When running on a kernel with SysRq compiled in, it +may be DISABLED at run-time using following command: + + echo "0" > /proc/sys/kernel/sysrq - echo "1" > /proc/sys/kernel/sysrq +Note that previous versions disabled sysrq by default, and you were required +to specifically enable it at run-time. That is not the case any longer. -* How do I use the magic SysRQ key? +* How do I use the magic SysRq key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -On x86 - You press the key combo 'ALT-SysRQ-'. Note - Some - (older?) may not have a key labeled 'SysRQ'. The 'SysRQ' key is +On x86 - You press the key combo 'ALT-SysRq-'. Note - Some + keyboards may not have a key labeled 'SysRq'. The 'SysRq' key is also known as the 'Print Screen' key. On SPARC - You press 'ALT-STOP-', I believe. @@ -32,14 +33,14 @@ On Mac - Press 'Keypad+-F13-' On other - If you know of the key combos for other architectures, please - let me know so I can add them to this section. + let me know so I can add them to this section. * What are the 'command' keys? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'r' - Turns off keyboard raw mode and sets it to XLATE. -'k' - Secure Access Key (SAK) Kills all programs on the current virtual - console. NOTE: See important comments below in SAK section. +'k' - Secure Access Key (SAK) Kills all programs on the current virtual + console. NOTE: See important comments below in SAK section. 'b' - Will immediately reboot the system without syncing or unmounting your disks. @@ -69,8 +70,8 @@ 'l' - Send a SIGKILL to all processes, INCLUDING init. (Your system will be non-functional after this.) -'h' - Will display help ( actually any other key than those listed - above will display help. but 'h' is easy to remember :-) +'h' - Will display help ( actually any other key than those listed + above will display help. but 'h' is easy to remember :-) * Okay, so what can I use them for? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -82,8 +83,8 @@ and thus letting you make sure that the login prompt you see is actually the one from init, not some trojan program. IMPORTANT:In its true form it is not a true SAK like the one in :IMPORTANT -IMPORTATN:c2 compliant systems, and it should be mistook as such. :IMPORTANT - It seems other find it useful as (System Attention Key) which is +IMPORTANT:c2 compliant systems, and it should be mistook as such. :IMPORTANT + It seems other find it useful as (System Attention Key) which is useful when you want to exit a program that will not let you switch consoles. (For example, X or a svgalib program.) @@ -92,7 +93,7 @@ 'S'ync is great when your system is locked up, it allows you to sync your disks and will certainly lessen the chance of data loss and fscking. Note -that the sync hasn't taken place until you see the "OK" and "Done" appear +that the sync hasn't taken place until you see the "OK" and "Done" appear on the screen. (If the kernel is really in strife, you may not ever get the OK or Done message...) @@ -110,30 +111,72 @@ are unable to kill any other way, especially if it's spawning other processes. -* Sometimes SysRQ seems to get 'stuck' after using it, what can I do? +* Sometimes SysRq seems to get 'stuck' after using it, what can I do? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ That happens to me, also. I've found that tapping shift, alt, and control on both sides of the keyboard, and hitting an invalid sysrq sequence again will fix the problem. (ie, something like alt-sysrq-z). Switching to another virtual console (ALT+Fn) and then back again should also help. -* I hit SysRQ, but nothing seems to happen, what's wrong? +* I hit SysRq, but nothing seems to happen, what's wrong? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There are some keyboards that send different scancodes for SysRQ than the -pre-defined 0x54. So if SysRQ doesn't work out of the box for a certain -keyboard, run 'showkey -s' to find out the proper scancode sequence. Then -use 'setkeycodes 84' to define this sequence to the usual SysRQ +There are some keyboards that send different scancodes for SysRq than the +pre-defined 0x54. So if SysRq doesn't work out of the box for a certain +keyboard, run 'showkey -s' to find out the proper scancode sequence. Then +use 'setkeycodes 84' to define this sequence to the usual SysRq code (84 is decimal for 0x54). It's probably best to put this command in a -boot script. Oh, and by the way, you exit 'showkey' by not typing anything +boot script. Oh, and by the way, you exit 'showkey' by not typing anything for ten seconds. +* I want to add SysRQ key events to a module, how does it work? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In order to register a basic function with the table, you must first include +the header 'include/linux/sysrq.h', this will define everything else you need. +Next, you must create a sysrq_key_op struct, and populate it with A) the key +handler function you will use, B) a help_msg string, that will print when SysRQ +prints help, and C) an action_msg string, that will print right before your +handler is called. Your handler must conform to the protoype in 'sysrq.h'. + +After the sysrq_key_op is created, you can call the macro +register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in +sysrq.h, this will register the operation pointed to by 'op_p' at table +key 'key', if that slot in the table is blank. At module unload time, you must +call the macro unregister_sysrq_key(int key, struct sysrq_key_op *op_p), which +will remove the key op pointed to by 'op_p' from the key 'key', if and only if +it is currently registered in that slot. This is in case the slot has been +overwritten since you registered it. + +The Magic SysRQ system works by registering key operations against a key op +lookup table, which is defined in 'drivers/char/sysrq.c'. This key table has +a number of operations registered into it at compile time, but is mutable, +and 4 functions are exported for interface to it: __sysrq_lock_table, +__sysrq_unlock_table, __sysrq_get_key_op, and __sysrq_put_key_op. The +functions __sysrq_swap_key_ops and __sysrq_swap_key_ops_nolock are defined +in the header itself, and the REGISTER and UNREGISTER macros are built fromi +these. More complex (and dangerous!) manipulations of the table are possible +using these functions, but you must be careful to always lock the table before +you read or write from it, and to unlock it again when you are done. (And of +course, to never ever leave an invalid pointer in the table). Null pointers in +the table are always safe :) + +If for some reason you feel the need to call the handle_sysrq function from +within a function called by handle_sysrq, you must be aware that you are in +a lock (you are also in an interupt handler, which means don't sleep!), so +you must call __handle_sysrq_nolock instead. + * I have more questions, who can I ask? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You may feel free to send email to myrdraal@deathsdoor.com, and I will -respond as soon as possible. +respond as soon as possible. -Myrdraal +And I'll answer any questions about the registration system you got, also +responding as soon as possible. + -Crutcher + * Credits ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Written by Mydraal Updated by Adam Sulmicki +Updated by Jeremy M. Dolan 2001/01/28 10:15:59 +Added to by Crutcher Dunnavant diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/video4linux/Zoran linux.ac/Documentation/video4linux/Zoran --- linux.vanilla/Documentation/video4linux/Zoran Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/video4linux/Zoran Tue Apr 3 17:54:29 2001 @@ -0,0 +1,517 @@ +DC10/DC10plus/LML33/Buz Driver for Linux +========================================= + +by Rainer Johanni (for Iomega Buz Driver) + +Adapted for DC10/DC10plus by Wolfgang Scherr + +Further changes for DC10/DC10plus and LML33 cards by +Serguei Miridonov + +Current homepage: http://www.cicese.mx/~mirsev/Linux/DC10plus/ +Current maintainer: Serguei Miridonov + + This is a driver for DC10plus capture cards from Pinnacle Systems + Inc., LML33 cards from Linux Media Labs and Buz from Iomega. + It also works with many old Miro DC10 cards with SAA7110A TV decoder + and ADV7176 TV encoder (please, make sure that your card has these + chips, otherwise the driver will not work). + + The driver is Video4Linux compliant and contains extensions to + provide hardware support for full motion MJPEG compression and + decompression. Since this driver is a derivative from the driver for + Buz Iomega cards written by Dr. Rainer Johanni, + http://www.johanni.de/munich-vision/buz/ they both have compatible + API. I hope that this API will become a part of V4L standard. + +Copyright: This driver is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License. Please, +check http://www.gnu.org/ for details. + +No warranty: This software is provided on AN "AS-IS" basis WITHOUT +WARRANTY OF ANY KIND. YOU USE IT AT YOUR OWN RISK. + + + +CONTENTS +~~~~~~~~ + +Supported Formats +Hardware compression +Compiling and Loading the Driver +Driver Options +Tested applications +Programming interface +Features for testing +Mailing lists +Bug Reports + + +Supported Formats +================= + +Card: DC10/DC10plus LML33/Buz + +TV standard: NTSC/PAL/SECAM(*) NTSC/PAL + +Format: Square pixel CCIR.601 + 640x480 NTSC 720x480 NTSC + 768x576 PAL/SECAM(*) 720x576 PAL + +Frame rates: 30 frames/60 fields per second NTSC + 25 frames/50 fields per second PAL/SECAM(*) + +(*) - SECAM is supported for input only in DC10/DC10plus cards. The +output of the recorded SECAM video stream will be in PAL standard. +Also, please, note that monitoring of the SECAM input signal at the +DC10/DC10plus analog output may not be available. Please, use +appropriate application like XawTV to watch full color SECAM video at +the card input. + +Hardware compression +==================== + +Since the card provides hardware compression, even low end machines can +be successfully used for movie capture and playback. I'm testing the +driver with with 2.2.16 kernel running on 233 MHz Pentium MMX with 64M +RAM on 430TX motherboard and with 10GB IDE drive from Western Digital +Corp. + +On one test run with DC10plus card I've got 0 frames dropped during +about 20 minutes of full motion NTSC (I live in Mexico) video capture +with fully synchronized audio. The command was + + lavrec -fa -in -d1 -l -1 -q30 -w /dos/g/capture/Linux/test%03d.avi + +for recording, and + + lavplay -n128 /dos/g/capture/Linux/test*.avi + +for playback. (See lavtools distribution for more information). + +Typical run of similar test can provide as few as 6-8 dropped frames per +half of an hour. You mileage may vary, though. + +Compiling and Loading the Driver +================================ + +You should run a 2.2.x kernel in order to use this driver. The driver +was also tested with 2.4-test6 kernel, so hopefully it will work +with 2.4 kernels too. + +I would recommend to use only official kernels from www.kernel.org and +its mirrors. Kernels supplied with some Linux distributions may be +patched in some way to meet specific needs of particular Linux +distributor and could be incompatible with this driver. As a driver +maintainer, I am not able to follow every unofficial kernel release, +and no unofficial kernels will be supported. + +Besides the files in this directory, the driver needs the 'videodev' +and the 'i2c' module from the Linux kernel (i2c-old for 2.4 kernels). +In order to get these modules available, enable module support for +VIDEODEV and BTTV (which implies i2c) in your 2.2.x kernel +configuration. You will find these devices in the menu "Character +Devices" in your Kernel Configuration. + +In newer kernels (2.4) instead of BTTV you should enable support for +Iomega Buz cards and for Zoran 36060/36067 chipset. This will include +i2c or i2c-old modules and Buz/LML33 driver. However, instead of +modules for Buz/LML33 driver from the kernel, use modules from _this_ +driver. + +To compile the driver, just type make. + +Before you load the driver you must have a video device at major device +node 81. If you don't have it yet, do the following (as root!): + +cd /dev +mknod video0 c 81 0 +ln -s video0 video + +If you have more than one card, add more nodes in /dev directory: + +mknod video1 c 81 1 +mknod video2 c 81 2 +... + +The driver should operate properly with several cards. It was tested +with one DC10plus and one LML33 cards installed together and the driver +correctly identifies both cards and works with both of them. + +Currently the driver does not support LML33 and Buz cards installed +together in the same system. This will be fixed in future versions. + +Edit the 'update' script if you want to give the driver special options +(see below for options descriptions) and then type (as root) + +./update + +to insert all necessary modules into the kernel. is a list of +cards installed in your system separated by white space. Supported cards +are dc10, dc10plus, lml33, and buz. For example, if you have both dc10plus +and lml33 cards, please type + +./update dc10 lml33 + +If you want to make full use of the Video for Linux _uncompressed_ +grabbing facilities, you must either + +- obtain and install the "big_physarea patch" for your kernel and + set aside the necessary memory during boot time. There seem to be + several versions of this patch against various kernel versions + floating around in the net, you may obtain one e.g. from: + http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You + also have to compile your driver AFTER installing that patch in order + to get it working + + or + +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. + For doing this add an entry in lilo.conf (if you use lilo): + append "mem=xxxM" + or add a line in your linux.par file (if you use loadlin): + mem=xxxM + +The second method is by far easier, however it is dangerous if more +than one driver at a time has the idea to use the memory leftover by +setting the mem=xxx parameter below the actual memory size. + +Read also below how to use this memory! + + + If you use only MJPEG compressed capture provided by the driver, you + should not need large memory areas for DMA. In this case, you will be + able to capture and playback movies with lavtools, however you will + not be able to use capture features of XawTV and other similar + programs (you can still watch video on the screen). + + + +Driver Options +============== + +You are able to customize the behavior of the driver by giving +it some options at start time. + +default_input, default_norm +--------------------------- + +As soon as the driver is loaded, the Buz samples video signals +from one of its input ports and displays it on its output. +The driver uses the Composite Input and the video norm PAL for this. +If you want to change this default behavior, set default_input=1 +(for S-VHS input) or default_norm=1 for NTSC or default_norm=2 +for SECAM (DC10/DC10plus only). + +lock_norm +--------- + +This option was introduced to disable norm (TV standard) change by some +not well behaving programs. For example, if you have some application +which was written by somebody who lives in a country with PAL standard, +this program may not have NTSC option and may always try to set the +driver to PAL. In this case, you may load the driver with +default_norm=1 and lock_norm=1 and the card will be forced to work in +NTSC standard only. + + Options: + + lock_norm=0 default, TV standard change is enabled; + lock_norm=1 TV standard change is disabled but the driver + will not notify the application about any error; + lock_norm=2 TV standard change is disabled and the driver + will notify the program that TV standards other + than set by default_norm=X option are not + supported. + +pass_through +------------ + +When the driver is not in use (device is not opened by any program) and +pass_through=0 (default) the driver will set the TV encoder to produce +color bar signal at the output. If the driver was loaded with +pass_through=1, the color bar will be disabled and input signal will be +sent to the output even if the driver not in use. If you have LML33 card +and wish the color bar signal at the output, you will also need to set +lml33dpath=1 (please, see next section). + +lml33dpath +---------- + +LML33 card normally (lml33dpath=0) connects its output to the input +using analog switch. Additionally, it also allows real-time monitoring +of digitized video using TV monitor connected to the output. This +"digital path" option can be enabled setting lml33dpath=1. In this +mode, the input is connected only to the TV decoder, digital video data +is sent via internal video bus to the TV encoder and resulting analog +signal is sent to the output. This mode could be very useful for testing and +picture adjustment while watching video at the TV monitor connected to +the output. However, because of lack of 75 ohm terminating resistors at +TV decoder input, the signal will suffer serious distortions. + +# These distortions could be eliminated by soldering two 75 ohm resistors +# in LML33 card: in parallel to capacitors C73 and C82 (see schematics of +# H33 board available at www.linuxmedialabs.com and www.zoran.com). Be +# aware, however, that doing so will void card warranty and the card, +# after this change, must always be used with loading option lml33dpath=1. +# +# WARNING: I DID NOT TRY THIS CARD CHANGE YET, THIS IS JUST AN ASSUMPTION +# AND I WILL NOT BE RESPONSIBLE FOR ANY DAMAGE ASSOCIATED WITH THIS +# CHANGE. IF YOU WISH TO TRY IT, DO IT AT YOUR OWN RISK. + +Please, note that DC10/DC10plus cards always use "digital path" for +signal monitoring. Its input and output are both properly terminated +and the digitized signal quality does not depend on the connection of +the output load. + + +v4l_nbufs, v4l_bufsize +---------------------- + +In order to make to make full use of the Video for Linux uncompressed +picture grabbing facilities of the driver (which are needed by many +Video for Linux applications), the driver needs a set of physically +contiguous buffers for grabbing. These parameters determine how many +buffers of which size the driver will allocate at open (the open will +fail if it is unable to do so!). + +These values do not affect the MJPEG grabbing facilities of the driver, +they are needed for uncompressed image grabbing only!!! + +v4l_nbufs is the number of buffers to allocate, a value of 2 (the default) +should be sufficient in almost all cases. Only special applications +(streaming captures) will need more buffers and then mostly the +MJPEG capturing features of the Buz will be more appropriate. +So leave this parameter at it's default unless you know what you do. + +The things for v4l_bufsize are more complicated: v4l_bufsize is set by +default to 128 [KB] which is the maximum amount of physically +contiguous memory Linux is able to allocate without kernel changes. +This is sufficient for grabbing 24 bit color images up to sizes of +approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072). + +In order to be able to capture bigger images you have either to +- obtain and install the "big_physarea patch" and set aside + the necessary memory during boot time or +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. +In that case, useful settings for v4l_bufsize are +- 1296 [Kb] for grabbing 24 bit images of max size 768*576 +- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!) +You may reduce these numbers accordingly if you know you are only +grabbing 720 pixels wide images or NTSC images (max height 480). + +In some cases it may happen that Linux isn't even able to obtain +the default 128 KB buffers. If you don't need uncompressed image +grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4) +in order to be able to open the video device. + +triton, natoma +-------------- + +The driver tries to detect if you have a triton or natoma chipset +in order to take special measures for these chipsets. +If this detection fails but you are sure you have such a chipset, +set the corresponding variable to 1. +This is a very special option and may go away in the future. + + +Tested applications +=================== + + XawTV to watch video on your computer monitor. + + kwintv the same (you might need to use option lock_norm=1). + + lavtools To record and playback AVI or Quicktime files. Note: you + will need patched version, lavtools-1.2p2 to support new + features of this driver. Please visit driver homepage for + more info. + + Broadcast2000 reportedly (I didn't try that) can accept movies recorded + by lavrec in Quicktime format for editing and then edited + movie can be played back by lavplay program. + + MainActor 3.5x also can accept movies recorded by lavrec for editing. + + +The driver can to be used by two programs at the same time +(please, see warning note below regarding this feature). Using XawTV +you can watch what you are recording or playing back with lavtools. +I've tested the following sequence and it worked for me: + +* start xawtv and switch inputs, TV standards, and adjust video + (contrast, saturation, etc.). You may also run your favorite + audio mixer application to adjust audio inputs. + +* run lavrec with options: + + -i (to choose proper input + and TV standard) + + -l -1 (to use audio mixer settings) + + Other lavrec option can be added at your choice. + +* watch the movie in xawtv window while recording it as AVI or + Quicktime file. + +* when recording is finished, run lavplay or xlav and watch your + clip in xawtv window. + +* Note: you should not quit xawtv during recording or playing back. + If you quit xawtv during recording or playback, another lavtools + program will stop and may even crash. + +I'm not sure that the same will work for you. You can try but, +please, be careful. + +WARNING! This is an experimental feature and I'm not sure if it will be +supported in the future. The original driver was not designed to be +used like this and it has no protection against any interference +between two running programs. THEREFORE, IT IS POTENTIALLY DANGEROUS +AND SINCE THE DRIVER OPERATES IN KERNEL SPACE, USING THIS FEATURE MAY +CRASH YOUR ENTIRE SYSTEM. + + +Programming interface +===================== + +This driver should be fully compliant to Video for Linux, so all +tools working with Video for Linux should work with (hopefully) +no problems. + +A description of the Video for Linux programming interface can be found at: +http://roadrunner.swansea.linux.org.uk/v4lapi.shtml + +Besides the Video for Linux interface, the driver has a "proprietary" +interface for accessing the Buz's MJPEG capture and playback facilities. + +For a full description of all members and ioctls see "zoran.h" (used to +be buz.h or dc10.h in previous versions, so, please, update your +programs accordingly). + +The ioctls for that interface are as follows: + +BUZIOC_G_PARAMS +BUZIOC_S_PARAMS + +Get and set the parameters of the buz. The user should always do a +BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default +settings, change what he likes and then make a BUZIOC_S_PARAMS call. + +BUZIOC_REQBUFS + +Before being able to capture/playback, the user has to request +the buffers he is wanting to use. Fill the structure +zoran_requestbuffers with the size (recommended: 256*1024) and +the number (recommended 32 up to 256). There are no such restrictions +as for the Video for Linux buffers, you should LEAVE SUFFICIENT +MEMORY for your system however, else strange things will happen .... +On return, the zoran_requestbuffers structure contains number and +size of the actually allocated buffers. +You should use these numbers for doing a mmap of the buffers +into the user space. +The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap +maps the MJPEG buffer instead of the V4L buffers. + +BUZIOC_QBUF_CAPT +BUZIOC_QBUF_PLAY + +Queue a buffer for capture or playback. The first call also starts +streaming capture. When streaming capture is going on, you may +only queue further buffers or issue syncs until streaming +capture is switched off again with a argument of -1 to +a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl. + +BUZIOC_SYNC + +Issue this ioctl when all buffers are queued. This ioctl will +block until the first buffer becomes free for saving its +data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY). + +BUZIOC_G_STATUS + +Get the status of the input lines (video source connected/norm). +This ioctl may be subject to change. + +For programming example, please, look at lavrec.c and lavplay.c code in +lavtools-1.2p2 package (URL: http://www.cicese.mx/~mirsev/DC10plus/) +and the 'examples' directory in the original Buz driver distribution. + +Additional notes for software developers: + + The driver returns maxwidth and maxheight parameters according to + the current TV standard (norm). Therefore, the software which + communicates with the driver and "asks" for these parameters should + first set the correct norm. Well, it seems logically correct: TV + standard is "more constant" for current country than geometry + settings of a variety of TV capture cards which may work in ITU or + square pixel format. Remember that users now can lock the norm to + avoid any ambiguity. + +Features for testing +==================== + +When loaded, the driver creates a /proc/zoranX entry for each card: +using 'cat /proc/zoran0' for your first card you can see the contents +of ZR36057/67 chip registers. It is also possible to modify the +contents of some registers directly. WARNING: modified contents is not +stored in the driver memory, if you restart any program which uses this +driver or even change position or cause redraw of a window of xawtv or +other program, the original registers contents will be restored by the +driver. However, it can be used to change ZR36067 registers on the fly +for fine tuning and then to include these changes into driver code. +This feature is very limited and still requires some documentation. +However, if you are impatient, look at zoran_procfs.c code and +(IMPORTANT!) read ZR36057/67 manual. To set TopField bit, for example, +you need to type as root: + +echo TopField=1 > /proc/zoranX # change X to 0 for your first card, + # 1 for second and so on... + +If you use this feature and have found some interesting result, please, let +me know. + +Mailing lists +============= + +There are two mailing lists available to discuss application issues and +suggest driver improvements: + +1. A mailing list buz-linux was set up to discuss Iomega Buz driver. +Since this driver is derivative of that driver, you can also post your +questions and suggestions there. Subscribe with a message (with +"subscribe" in the subject) to buz-linux-subscribe@webmages.com. +Unsubscribe with a message (with "unsubscribe" in the subject) to +buz-linux-unsubscribe@webmages.com. The mailing list archive can be +found at http://buz.webmages.com/list/. + +2. Video4Linux mailing list is set for more general discussions related +to uncompressed video capture, V4L and V4L2 API, many Video4Linux +applications, etc. to subscribe to this mailing list, please, visit +https://listman.redhat.com/mailman/listinfo/video4linux-list + +Bug Reports +=========== + +If you have found a bug, please, do the following: + +1. Edit first line of zoran.c file and set DEBUGLEVEL to 3; +2. Recompile the driver and install it running update script + in the driver directory; +3. Run the application(s) which you used when you had found a + suspisious behavior; +4. When application stops, look at you /var/log/messages file + (or whatever file you use to log kernel messages) and copy + all lines related to the driver activity to a separate file + in the same order of their appearence in your log file. +5. Mail a message to with a subject + "Linux DC10(plus)/LML33/Buz driver bug report" with a detailed + description of your problem, kernel version, application name and + attach that file with kernel messages as plain text (please, don't + attach it using base64, uuencode, or any other encoding). + + If you have a Buz card, please, also mail the same message to + Wolfgang Scherr diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/video4linux/w9966.txt linux.ac/Documentation/video4linux/w9966.txt --- linux.vanilla/Documentation/video4linux/w9966.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/video4linux/w9966.txt Tue Apr 3 23:40:38 2001 @@ -0,0 +1,37 @@ + +W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se) + +Ok, after a lot of work in softice, wdasm, reading pdf-files +and trial-and-error work I've finally got everything to work. +Since I needed some vision for a robotics project I borrowed +this camera from a friend and started hacking. Anyway I've +converted my original code from the AVR 8bit RISC C/asm +into a working linux driver. I would really appreciate _any_ +kind of feedback regarding this driver. + +To get it working quickly configure your kernel +to support parport, ieee1284, video4linux, experimental drivers +and w9966 + +If w9966 is statically linked it will perform aggressive probing +for the camera. If built as a module you have more configuration options. + +Options: +modprobe w9966.o pardev=parport0(or whatever) parmode=0 rgb=1(or 0 if + your programs can handle 16bit yuv422, which is faster) + +voila! + +you can also type 'modinfo -p w9966.o' for option usage +(or checkout w9966.c) + +I've only tested it with custom built testprograms and with gqcam. +(you'll need to change the w9966_v4l_ioctl function to report max +dimensions of 200x200 for gqcam to work) + +The slow framerate is due to missing DMA ECP read support in the +parport drivers. I might add EPP support later. + +Good luck! + + /Jakob diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Tue Apr 3 17:31:51 2001 +++ linux.ac/MAINTAINERS Sun Apr 22 01:45:30 2001 @@ -106,6 +106,13 @@ L: linux-net@vger.kernel.org S: Maintained +ACI MIXER DRIVER +P: Robert Siemer +M: Robert.Siemer@gmx.de +L: linux-sound@vger.kernel.org +W: http://www.uni-karlsruhe.de/~Robert.Siemer/Private/ +S: Maintained + ACPI P: Andy Grover M: andrew.grover@intel.com @@ -141,9 +148,9 @@ APM DRIVER P: Stephen Rothwell -M: apm@linuxcare.com.au +M: sfr@canb.auug.org.au L: linux-laptop@vger.kernel.org -W: http://linuxcare.com.au/apm/ +W: http://www.canb.auug.org.au/~sfr/ S: Supported APPLETALK NETWORK LAYER @@ -273,8 +280,10 @@ S: Maintained CONFIGURE.HELP -P: Axel Boldt -M: axel@uni-paderborn.de +P: Steven P. Cole +M: Steven P. Cole +P: Eric S. Raymond +M: Eric S. Raymond S: Maintained COSA/SRP SYNC SERIAL DRIVER @@ -293,6 +302,13 @@ M: jam@acm.org S: Maintained +CRIS PORT +P: Bjorn Wesen +M: bjornw@axis.com +L: dev-etrax@axis.com +W: http://developer.axis.com +S: Maintained + CYBERPRO FB DRIVER P: Russell King M: linux@arm.linux.org.uk @@ -368,7 +384,7 @@ DIRECTORY NOTIFICATION P: Stephen Rothwell -M: sfr@linuxcare.com.au +M: sfr@canb.auug.org.au L: linux-kernel@vger.kernel.org S: Supported @@ -398,6 +414,12 @@ L: dri-devel@lists.sourceforge.net S: Supported +DSCC4 DRIVER +P: François Romieu +M: romieu@cogenit.fr +M: romieu@ensta.fr +S: Maintained + EATA-DMA SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net @@ -490,6 +512,12 @@ W: http://www.icp-vortex.com/ S: Supported +GENERIC HDLC DRIVER, N2 AND C101 DRIVERS +P: Krzysztof Halasa +M: khc@pm.waw.pl +W: http://hq.pm.waw.pl/hdlc/ +S: Maintained + HAYES ESP SERIAL DRIVER P: Andrew J. Robinson M: arobinso@nyx.net @@ -517,25 +545,9 @@ W: http://www.nt.tuwien.ac.at/~kkudielk/Linux/ S: Maintained -KERNEL BUILD (Makefile, Rules.make, scripts/*) -P: Keith Owens -M: kaos@ocs.com.au -P: Michael Elizabeth Chastain -M: mec@shout.net -L: linux-kbuild@torque.net -W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ -S: Maintained - -LOGICAL VOLUME MANAGER -P: Heinz Mauelshagen -M: linux-LVM@EZ-Darmstadt.Telekom.de -L: linux-LVM@msede.com -W: http://linux.msede.com/lvm -S: Maintained - HIPPI P: Jes Sorensen -M: Jes.Sorensen@cern.ch +M: jes@linuxcare.com L: linux-hippi@sunsite.auc.dk S: Maintained @@ -600,7 +612,14 @@ W: http://www.kernel.dk S: Maintained -IDE/ATAPI TAPE/FLOPPY DRIVERS +IDE/ATAPI FLOPPY DRIVERS +P: Paul Bristow +M: Paul Bristow +W: http://paulbristow.net/linux/idefloppy.html +L: linux-kernel@vger.kernel.org +S: Maintained + +IDE/ATAPI TAPE DRIVERS P: Gadi Oxman M: Gadi Oxman L: linux-kernel@vger.kernel.org @@ -702,6 +721,13 @@ W: http://www.developer.axis.com/software/jffs/ S: Maintained +JOURNALLING FLASH FILE SYSTEM V2 (JFFS2) +P: David Woodhouse +M: dwmw2@infradead.org +L: jffs-dev@axis.com +W: http://sources.redhat.com/jffs2/ +S: Maintained + JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@suse.cz @@ -721,6 +747,15 @@ L: autofs@linux.kernel.org S: Maintained +KERNEL BUILD (Makefile, Rules.make, scripts/*) +P: Keith Owens +M: kaos@ocs.com.au +P: Michael Elizabeth Chastain +M: mec@shout.net +L: linux-kbuild@torque.net +W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ +S: Maintained + KERNEL NFSD P: Neil Brown M: neilb@cse.unsw.edu.au @@ -750,14 +785,21 @@ LINUX FOR POWER MACINTOSH P: Paul Mackerras -M: paulus@linuxcare.com +M: paulus@samba.org W: http://www.linuxppc.org/ L: linuxppc-dev@lists.linuxppc.org S: Maintained +LOGICAL VOLUME MANAGER +P: Heinz Mauelshagen +M: linux-LVM@EZ-Darmstadt.Telekom.de +L: linux-LVM@msede.com +W: http://linux.msede.com/lvm +S: Maintained + M68K P: Jes Sorensen -M: Jes.Sorensen@cern.ch +M: jes@linuxcare.com W: http://www.clark.net/pub/lawrencc/linux/index.html L: linux-m68k@lists.linux-m68k.org S: Maintained @@ -775,7 +817,7 @@ W: http://www.tazenda.demon.co.uk/phil/linux-hp S: Maintained -MAESTRO PCI SOUND DRIVER +MAESTRO PCI SOUND DRIVERS P: Zach Brown M: zab@zabbo.net S: Odd Fixes @@ -787,6 +829,12 @@ L: mtd@infradead.org S: Maintained +MICROTEK X6 SCANNER +P: Oliver Neukum +M: drivers@neukum.org +W: http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html +S: Maintained + MIPS P: Ralf Baechle M: ralf@gnu.ai.mit.edu @@ -837,10 +885,14 @@ NETFILTER P: Rusty Russell -M: rusty@linuxcare.com +M: rusty@rustcorp.com.au P: Marc Boucher M: marc@mbsi.ca -W: http://www.samba.org/netfilter/ +P: James Morris +M: jamesm@intercode.com.au +P: Harald Welte +M: laforge@gnumonks.org +W: http://netfilter.samba.org W: http://netfilter.kernelnotes.org W: http://netfilter.filewatcher.org L: netfilter@lists.samba.org @@ -904,8 +956,9 @@ NTFS FILESYSTEM P: Anton Altaparmakov M: aia21@cus.cam.ac.uk +L: linux-ntfs-dev@lists.sourceforge.net L: linux-kernel@vger.kernel.org -S: Odd Fixes +S: Maintained NVIDIA (RIVA) FRAMEBUFFER DRIVER P: Ani Joshi @@ -917,9 +970,9 @@ P: Peter De Shrijver M: p2@ace.ulyssis.sutdent.kuleuven.ac.be P: Mike Phillips -M: phillim@amtrak.com +M: mikep@linuxtr.net L: linux-net@vger.kernel.org -L: linux-tr@emissary.aus-etc.com +L: linux-tr@linuxtr.net W: http://www.linuxtr.net S: Maintained @@ -997,7 +1050,7 @@ PPP PROTOCOL DRIVERS AND COMPRESSORS P: Paul Mackerras -M: paulus@linuxcare.com +M: paulus@samba.org L: linux-ppp@vger.kernel.org S: Maintained @@ -1037,6 +1090,13 @@ L: linux-kernel@vger.kernel.org S: Maintained +REISERFS FILE SYSTEM +P: Hans Reiser +M: reiserfs-dev@namesys.com +L: reiserfs-list@namesys.com +W: http://www.namesys.com +S: Supported + ROSE NETWORK LAYER P: Jean-Paul Roubelat M: jpr@f6fbb.org @@ -1056,6 +1116,14 @@ W: www.rtlinux.org S: Maintained +S390 +P: Martin Schwidefsky +M: schwidefsky@de.ibm.com +M: linux390@de.ibm.com +L: linux-390@vm.marist.edu +W: http://oss.software.ibm.com/developerworks/opensource/linux390 +S: Supported + SA1100 SUPPORT P: Nicolas Pitre M: nico@cam.org @@ -1174,6 +1242,11 @@ W: http://www.stallion.com S: Supported +STARFIRE/DURALAN NETWORK DRIVER +P: Ion Badulescu +M: ionut@cs.columbia.edu +S: Maintained + STARMODE RADIO IP (STRIP) PROTOCOL DRIVER W: http://mosquitonet.Stanford.EDU/strip.html S: Unsupported ? @@ -1302,6 +1375,13 @@ S: Maintained W: http://www.kroah.com/linux-usb/ +USB CDC ETHERNET DRIVER +P: Brad Hards +M: bhards@bigpond.net.au +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB HID/HIDBP/INPUT DRIVERS P: Vojtech Pavlik M: vojtech@suse.cz @@ -1318,6 +1398,13 @@ L: linux-usb-devel@lists.sourceforge.net S: Maintained +USB KAWASAKI LSI DRIVER +P: Brad Hards +M: bhards@bigpond.net.au +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB OHCI DRIVER P: Roman Weissgaerber M: weissg@vienna.at @@ -1357,11 +1444,11 @@ USB SERIAL KEYSPAN DRIVER P: Hugh Blemings -M: hugh@linuxcare.com +M: hugh@misc.nu L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained -W: http://www.linuxcare.com.au/hugh/keyspan.html +W: http://misc.nu/hugh/keyspan/ USB SERIAL DRIVER P: Greg Kroah-Hartman @@ -1401,6 +1488,14 @@ L: linux-usb-devel@lists.sourceforge.net W: http://usb.in.tum.de S: Maintained + +USER-MODE PORT +P: Jeff Dike +M: jdike@karaya.com +L: user-mode-linux-devel@lists.sourceforge.net +L: user-mode-linux-user@lists.sourceforge.net +W: http://user-mode-linux.sourceforge.net +S: Maintained VFAT FILESYSTEM: P: Gordon Chaffee @@ -1430,8 +1525,8 @@ S: Maintained for 2.2 only WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) -P: Jaspreet Singh -M: jaspreet@sangoma.com +P: Nenad Corbic +M: ncorbic@sangoma.com M: dm@sangoma.com W: http://www.sangoma.com S: Supported @@ -1457,6 +1552,12 @@ X86 3-LEVEL PAGING (PAE) SUPPORT P: Ingo Molnar M: mingo@redhat.com +S: Maintained + +YAM DRIVER FOR AX.25 +P: Jean-Paul Roubelat +M: jpr@f6fbb.org +L: linux-hams@vger.kernel.org S: Maintained Z85230 SYNCHRONOUS DRIVER diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Makefile linux.ac/Makefile --- linux.vanilla/Makefile Tue Apr 3 17:31:52 2001 +++ linux.ac/Makefile Sun Apr 22 01:58:41 2001 @@ -1,11 +1,18 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 3 -EXTRAVERSION = +EXTRAVERSION = -ac12 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) -ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) +# SUBARCH tells the usermode build what the underlying arch is. That is set +# first, and if a usermode build is happening, the "ARCH=um" on the command +# line overrides the setting of ARCH below. If a native build is happening, +# then ARCH is assigned, getting whatever value it gets normally, and +# SUBARCH is subsequently ignored. + +SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) +ARCH := $(SUBARCH) CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ @@ -144,7 +151,7 @@ DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o -DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o +DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) @@ -163,7 +170,7 @@ DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o -DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o +DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a DRIVERS-$(CONFIG_VT) += drivers/video/video.o DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a @@ -171,7 +178,7 @@ DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o -DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o +DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o @@ -330,14 +337,14 @@ TAGS: dummy etags `find include/asm-$(ARCH) -name '*.h'` find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a - find $(SUBDIRS) init -name '*.c' | xargs etags -a + find $(SUBDIRS) init -name '*.[ch]' | xargs etags -a # Exuberant ctags works better with -I tags: dummy CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \ ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \ - find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a + find $(SUBDIRS) init -name '*.[ch]' | xargs ctags $$CTAGSF -a ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS @@ -493,7 +500,7 @@ # scripts/mkdep: scripts/mkdep.c - $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c + $(HOSTCC) $(HOSTCFLAGS) -g -o scripts/mkdep scripts/mkdep.c scripts/split-include: scripts/split-include.c $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/REPORTING-BUGS linux.ac/REPORTING-BUGS --- linux.vanilla/REPORTING-BUGS Mon Aug 21 16:57:35 2000 +++ linux.ac/REPORTING-BUGS Tue Apr 10 18:04:40 2001 @@ -25,10 +25,9 @@ overlook things, and easier for the developers to find the pieces of information they're really interested in. Don't feel you have to follow it. - First run the ver_linux script included as scripts/ver_linux or -at It checks out -the version of some important subsystems. Run it with the command -"sh scripts/ver_linux" + First run the ver_linux script included as scripts/ver_linux, which +reports the version of some important subsystems. Run this script with +the command "sh scripts/ver_linux". Use that information to fill in all fields of the bug report form, and post it to the mailing list with a subject of "PROBLEM: count); - - current->state = TASK_UNINTERRUPTIBLE; - wmb(); - add_wait_queue(&sem->wait, &wait); - mb(); - while (atomic_read(&sem->count) < 0) { - schedule(); - set_task_state(current, TASK_UNINTERRUPTIBLE); - } - - remove_wait_queue(&sem->wait, &wait); - current->state = TASK_RUNNING; - - mb(); - count = atomic_dec_return(&sem->count); - if (count <= 0) - goto retry_down; - } else { - /* Waiting on exactly one writer. */ - - current->state = TASK_UNINTERRUPTIBLE; - wmb(); - add_wait_queue(&sem->wait, &wait); - mb(); - - while (!test_and_clear_bit(0, &sem->granted)) { - schedule(); - set_task_state(current, TASK_UNINTERRUPTIBLE); - } - - remove_wait_queue(&sem->wait, &wait); - current->state = TASK_RUNNING; - } -} - -void -__down_write_failed(struct rw_semaphore *sem, int count) -{ - DECLARE_WAITQUEUE(wait, current); - - retry_down: - if (count + RW_LOCK_BIAS < 0) { - /* Waiting on multiple readers and/or writers. */ - - /* Undo the acquisition we started in down_write. */ - atomic_add(RW_LOCK_BIAS, &sem->count); - - current->state = TASK_UNINTERRUPTIBLE; - wmb(); - add_wait_queue_exclusive(&sem->wait, &wait); - mb(); - - while (atomic_read(&sem->count) + RW_LOCK_BIAS < 0) { - schedule(); - set_task_state(current, TASK_UNINTERRUPTIBLE); - } - - remove_wait_queue(&sem->wait, &wait); - current->state = TASK_RUNNING; - - count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (count != 0) - goto retry_down; - } else { - /* Waiting on exactly one writer. */ - - current->state = TASK_UNINTERRUPTIBLE; - wmb(); - add_wait_queue_exclusive(&sem->wait, &wait); - mb(); - - while (!test_and_clear_bit(1, &sem->granted)) { - schedule(); - set_task_state(current, TASK_UNINTERRUPTIBLE); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - current->state = TASK_RUNNING; - - /* If the lock is currently unbiased, awaken the sleepers. - FIXME: This wakes up the readers early in a bit of a - stampede -> bad! */ - count = atomic_read(&sem->count); - if (__builtin_expect(count >= 0, 0)) - wake_up(&sem->wait); - } -} - -void -__rwsem_wake(struct rw_semaphore *sem, int readers) -{ - if (readers) { - if (test_and_set_bit(0, &sem->granted)) - BUG(); - wake_up(&sem->wait); - } else { - if (test_and_set_bit(1, &sem->granted)) - BUG(); - wake_up(&sem->write_bias_wait); - } -} - -void -down_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - __down_read(sem); -#if WAITQUEUE_DEBUG - if (sem->granted & 2) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -void -down_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - __down_write(sem); -#if WAITQUEUE_DEBUG - if (sem->granted & 3) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -void -up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); - if (sem->granted & 2) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -void -up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); - if (sem->granted & 3) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/mm/fault.c linux.ac/arch/alpha/mm/fault.c --- linux.vanilla/arch/alpha/mm/fault.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/alpha/mm/fault.c Tue Apr 3 17:54:29 2001 @@ -24,10 +24,37 @@ #include #include #include +#include #include #include +extern spinlock_t timerlist_lock; +void bust_spinlocks(int yes) +{ + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + spin_lock_init(&global_irq_lock); /* Many serial drivers do __global_cli() */ +#endif + } else { + int loglevel_save = console_loglevel; + unblank_screen(); + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + + + extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); @@ -223,7 +250,7 @@ pgd = current->active_mm->pgd + offset; pgd_k = swapper_pg_dir + offset; - if (!pgd_present(*pgd) && pgd_present(*pgd_k)) { + if (pgd_present(*pgd_k)) { pgd_val(*pgd) = pgd_val(*pgd_k); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/mm/init.c linux.ac/arch/alpha/mm/init.c --- linux.vanilla/arch/alpha/mm/init.c Wed Nov 29 06:43:39 2000 +++ linux.ac/arch/alpha/mm/init.c Wed Apr 18 13:47:12 2001 @@ -32,6 +32,9 @@ #include #include #include +#include + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; @@ -43,20 +46,6 @@ struct pgtable_cache_struct quicklists; #endif -void -__bad_pmd(pgd_t *pgd) -{ - printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, BAD_PAGETABLE); -} - -void -__bad_pte(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); -} - pgd_t * get_pgd_slow(void) { @@ -80,66 +69,26 @@ return ret; } -pmd_t * -get_pmd_slow(pgd_t *pgd, unsigned long offset) -{ - pmd_t *pmd; - - pmd = (pmd_t *) __get_free_page(GFP_KERNEL); - if (pgd_none(*pgd)) { - if (pmd) { - clear_page((void *)pmd); - pgd_set(pgd, pmd); - return pmd + offset; - } - pgd_set(pgd, BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long)pmd); - if (pgd_bad(*pgd)) { - __bad_pmd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + offset; -} - -pte_t * -get_pte_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((void *)pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long)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; + if(pgtable_cache_size > high) { + do { + if(pgd_quicklist) { + free_pgd_slow(get_pgd_fast()); + freed++; + } + if(pmd_quicklist) { + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); + freed++; + } + if(pte_quicklist) { + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; + } + } while(pgtable_cache_size > low); + } + return freed; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/Makefile linux.ac/arch/arm/Makefile --- linux.vanilla/arch/arm/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/Makefile Sat Apr 14 01:15:10 2001 @@ -1,52 +1,36 @@ # # arch/arm/Makefile # -# 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 -# # 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. # -# Copyright (C) 1995-2000 by Russell King +# Copyright (C) 1995-2001 by Russell King LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds GZFLAGS :=-9 CFLAGS +=-fno-common -pipe -ifdef CONFIG_FRAME_POINTER +ifneq ($(CONFIG_NO_FRAME_POINTER),y) CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) endif -ifdef CONFIG_DEBUG_INFO +ifeq ($(CONFIG_DEBUG_INFO),y) CFLAGS +=-g endif -# Ensure this is ld "2.9.4" or later -NEW_LINKER := $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?) - -ifneq ($(NEW_LINKER),0) -dummy:; @echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.' - @echo '*** Please upgrade your binutils to 2.9.5.' - @false -endif - # Select CPU dependent flags. Note that order of declaration is important; # the options further down the list override previous items. # -apcs-$(CONFIG_CPU_26) :=-mapcs-26 -mcpu=arm3 -Os -apcs-$(CONFIG_CPU_32) :=-mapcs-32 +apcs-y := +apcs-$(CONFIG_CPU_26) :=-mcpu=arm3 -Os -arch-$(CONFIG_CPU_32v3) :=-march=armv3 +arch-y := +arch-$(CONFIG_CPU_32v3) :=-march=armv3m arch-$(CONFIG_CPU_32v4) :=-march=armv4 arch-$(CONFIG_CPU_32v5) :=-march=armv5 -proc-$(CONFIG_CPU_32v3) :=-marmv3m -proc-$(CONFIG_CPU_32v4) :=-marmv4 -proc-$(CONFIG_CPU_32v5) :=-marmv5 - +tune-y := tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610 tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi @@ -54,19 +38,27 @@ tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 -CFLAGS += $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -AFLAGS += $(apcs-y) $(proc-y) -mno-fpu +CFLAGS += -mapcs-32 $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float +AFLAGS += -mapcs-32 $(apcs-y) $(arch-y) -mno-fpu LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) ifeq ($(CONFIG_CPU_26),y) PROCESSOR = armo -TEXTADDR = 0x02080000 + ifeq ($(CONFIG_ROM_KERNEL),y) + DATAADDR = 0x02080000 + TEXTADDR = 0x03800000 + LDSCRIPT = arch/arm/vmlinux-armo-rom.lds.in + else + TEXTADDR = 0x02080000 + LDSCRIPT = arch/arm/vmlinux-armo.lds.in + endif endif ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv TEXTADDR = 0xC0008000 +LDSCRIPT = arch/arm/vmlinux-armv.lds.in endif ifeq ($(CONFIG_ARCH_ARCA5K),y) @@ -97,8 +89,13 @@ INCDIR = ebsa285 endif -ifeq ($(CONFIG_ARCH_NEXUSPCI),y) -MACHINE = nexuspci +ifeq ($(CONFIG_ARCH_FTVPCI),y) +MACHINE = ftvpci +INCDIR = nexuspci +endif + +ifeq ($(CONFIG_ARCH_TBOX),y) +MACHINE = tbox endif ifeq ($(CONFIG_ARCH_SHARK),y) @@ -134,6 +131,10 @@ INCDIR := $(MACHINE) endif +ifeq ($(origin DATAADDR), undefined) +DATAADDR := . +endif + # If we have a machine-specific directory, then include it in the build. MACHDIR := arch/arm/mach-$(MACHINE) ifeq ($(MACHDIR),$(wildcard $(MACHDIR))) @@ -143,13 +144,17 @@ HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ arch/arm/kernel/init_task.o -SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe +SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe \ + arch/arm/fastfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) -LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC) +LIBS := arch/arm/lib/lib.a $(LIBS) $(LIBGCC) -ifeq ($(CONFIG_NWFPE),y) +ifeq ($(CONFIG_FPE_NWFPE),y) LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) endif +ifeq ($(CONFIG_FPE_FASTFPE),y) +LIBS := arch/arm/fastfpe/fast-math-emu.o $(LIBS) +endif ifeq ($(CONFIG_ARCH_CLPS7500),y) SUBDIRS += drivers/acorn/char @@ -157,21 +162,13 @@ endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +MAKETOOLS = $(MAKE) -C arch/$(ARCH)/tools # The following is a hack to get 'constants.h' up # to date before starting compilation -$(patsubst %, _dir_%, $(SUBDIRS)) init/main.o init/version.o : \ - include/asm-arm/mach-types.h - -$(patsubst %, _dir_%, $(SUBDIRS)) : constants - -include/asm-arm/mach-types.h: arch/arm/tools/mach-types \ - arch/arm/tools/gen-mach-types - @awk -f arch/arm/tools/gen-mach-types arch/arm/tools/mach-types > $@ - -constants: dummy - @$(MAKE) -C arch/arm/lib constants.h +$(patsubst %,_dir_%, $(SUBDIRS)): maketools +$(patsubst %,_modsubdir_%,$(MOD_DIRS)): maketools symlinks: archsymlinks @@ -181,8 +178,8 @@ vmlinux: arch/arm/vmlinux.lds -arch/arm/vmlinux.lds: arch/arm/vmlinux-$(PROCESSOR).lds.in dummy - @sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@ +arch/arm/vmlinux.lds: $(LDSCRIPT) dummy + @sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@ arch/arm/kernel arch/arm/mm arch/arm/lib: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) @@ -190,17 +187,42 @@ bzImage zImage zinstall Image bootpImage install: vmlinux @$(MAKEBOOT) $@ +CLEAN_FILES += \ + arch/arm/vmlinux.lds + +MRPROPER_FILES += \ + include/asm-arm/arch \ + include/asm-arm/proc \ + include/asm-arm/constants.h* \ + include/asm-arm/mach-types.h + +# We use MRPROPER_FILES and CLEAN_FILES now archmrproper: - $(RM) include/asm-arm/arch include/asm-arm/proc + @/bin/true archclean: @$(MAKEBOOT) clean - $(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds - $(RM) include/asm-arm/mach-types.h -archdep: archsymlinks +archdep: scripts/mkdep archsymlinks + @$(MAKETOOLS) dep @$(MAKEBOOT) dep +maketools: checkbin + @$(MAKETOOLS) all + +# Ensure this is ld "2.9.4" or later +NEW_LINKER := $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?) + +ifneq ($(NEW_LINKER),0) +checkbin: + @echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.' + @echo '*** Please upgrade your binutils to 2.9.5.' + @false +else +checkbin: + @true +endif + # My testing targets (that short circuit a few dependencies) zImg:; @$(MAKEBOOT) zImage Img:; @$(MAKEBOOT) Image @@ -211,15 +233,7 @@ # # Configuration targets. Use these to select a # configuration for your architecture -CFGS= a5k_config ebsa110_config \ - footbridge_config rpc_config \ - brutus_config victor_config \ - empeg_config graphicsclient_config \ - assabet_config lart_config \ - cerf_config lusl7200_config \ - sherman_config pangolin_config - -$(CFGS): +%_config: @( \ CFG=$(@:_config=); \ if [ -f arch/arm/def-configs/$$CFG ]; then \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/Makefile linux.ac/arch/arm/boot/Makefile --- linux.vanilla/arch/arm/boot/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/Makefile Sat Apr 14 01:15:10 2001 @@ -55,8 +55,7 @@ endif ifeq ($(CONFIG_ARCH_NEXUSPCI),y) -ZTEXTADDR = 0x40200000 -ZRELADDR = 0x40008000 +ZTEXTADDR = 0x40008000 endif ifeq ($(CONFIG_ARCH_L7200),y) @@ -72,7 +71,6 @@ ifeq ($(CONFIG_ARCH_P720T),y) ZTEXTADDR = 0xc0018000 -ZRELADDR = 0xc0018000 PARAMS_PHYS = 0xc0000100 INITRD_PHYS = 0xc0400000 INITRD_VIRT = 0xc0400000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/Makefile linux.ac/arch/arm/boot/compressed/Makefile --- linux.vanilla/arch/arm/boot/compressed/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/Makefile Sat Apr 14 01:15:10 2001 @@ -9,7 +9,7 @@ HEAD = head.o OBJS = misc.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) -msoft-float FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c ZLDFLAGS = -p -X -T vmlinux.lds @@ -25,16 +25,24 @@ OBJS += head-netwinder.o endif +ifeq ($(CONFIG_ARCH_SHARK),y) +OBJS += head-shark.o ofw-shark.o +endif + ifeq ($(CONFIG_ARCH_INTEGRATOR),y) OBJS += head-netwinder.o endif -ifeq ($(CONFIG_ARCH_NEXUSPCI),y) -HEAD = head-nexuspci.o +ifeq ($(CONFIG_ARCH_FTVPCI),y) +OBJS += head-ftvpci.o endif ifeq ($(CONFIG_ARCH_L7200),y) OBJS += head-l7200.o +endif + +ifeq ($(CONFIG_ARCH_CLPS7500),y) +HEAD = head-clps7500.o endif ifeq ($(CONFIG_ARCH_P720T),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/head-clps7500.S linux.ac/arch/arm/boot/compressed/head-clps7500.S --- linux.vanilla/arch/arm/boot/compressed/head-clps7500.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/boot/compressed/head-clps7500.S Sat Apr 14 01:15:10 2001 @@ -0,0 +1,87 @@ +/* + * linux/arch/arm/boot/compressed/head.S + * + * Copyright (C) 1999, 2000, 2001 Nexus Electronics Ltd + */ + +#include + + /* There are three different ways the kernel can be + booted on a 7500 system: from Angel (loaded in RAM), from + 16-bit ROM or from 32-bit Flash. Luckily, a single kernel + image does for them all. */ + /* This branch is taken if the CPU memory width matches the + actual device in use. The default at power on is 16 bits + so we must be prepared for a mismatch. */ + .section ".start", #alloc, #execinstr +2: + b 1f + .word 0xffff + .word 0xb632 @ mov r11, #0x03200000 + .word 0xe3a0 + .word 0x0000 @ mov r0, #0 + .word 0xe3a0 + .word 0x0080 @ strb r0, [r11, #0x80] + .word 0xe5cb + .word 0xf000 @ mov pc, #0 + .word 0xe3a0 +1: + adr r1, 2b + teq r1, #0 + bne .Langel + /* This is a direct-from-ROM boot. Copy the kernel into + RAM and run it there. */ + mov r0, #0x30 + mcr p15, 0, r0, c1, c0, 0 + mov r0, #0x13 + msr cpsr, r0 + mov r12, #0x03000000 @ point to LEDs + orr r12, r12, #0x00020000 + orr r12, r12, #0xba00 + mov r0, #0x5500 + str r0, [r12] + mov r0, #0x10000000 + orr r0, r0, #0x8000 + mov r4, r0 + ldr r2, =_end +2: + ldr r3, [r1], #4 + str r3, [r0], #4 + teq r0, r2 + bne 2b + mov r0, #0xff00 + str r0, [r12] +1: + mov r12, #0x03000000 @ point to LEDs + orr r12, r12, #0x00020000 + orr r12, r12, #0xba00 + mov r0, #0xfe00 + str r0, [r12] + + adr lr, 1f + mov r0, #0 + mov r1, #14 /* MACH_TYPE_CLPS7500 */ + mov pc, lr +.Langel: +#ifdef CONFIG_ANGELBOOT + /* Call Angel to switch into SVC mode. */ + mov r0, #0x17 + swi 0x123456 +#endif + /* Ensure all interrupts are off and MMU disabled */ + mrs r0, cpsr + orr r0, r0, #0xc0 + msr cpsr, r0 + + adr lr, 1b + orr lr, lr, #0x10000000 + mov r0, #0x30 @ MMU off + mcr p15, 0, r0, c1, c0, 0 + mov r0, r0 + mov pc, lr + + .ltorg + +1: +/* And the rest */ +#include "head.S" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/head-shark.S linux.ac/arch/arm/boot/compressed/head-shark.S --- linux.vanilla/arch/arm/boot/compressed/head-shark.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/head-shark.S Sat Apr 14 01:15:10 2001 @@ -1,5 +1,5 @@ /* The head-file for the Shark - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz * * Does the following: * - get the memory layout from firmware. This can only be done as long as the mmu @@ -20,8 +20,6 @@ b __beginning -__serial_addr: .long 0xf7eff3f8 - .long 0 @ space __ofw_data: .long 0 @ the number of memory blocks .space 128 @ (startaddr,size) ... .space 128 @ bootargs @@ -31,14 +29,10 @@ mov r0, #0xC0 @ disable irq and fiq mov r1, r0 - mrs r3, cpsr_all + mrs r3, cpsr bic r2, r3, r0 eor r2, r2, r1 - msr cpsr_all, r2 - - ldr r0, __serial_addr @ disable serial interrupt - mov r1, #0 @ hangs the machine, I don t know why. - strb r1, [r0, #0x01] + msr cpsr_c, r2 mov r0, r4 @ get the Memory layout from firmware adr r1, __ofw_data diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/head.S linux.ac/arch/arm/boot/compressed/head.S --- linux.vanilla/arch/arm/boot/compressed/head.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/head.S Sat Apr 14 01:15:10 2001 @@ -87,7 +87,8 @@ b 1f .word 0x016f2818 @ Magic numbers to help the loader - .word start + .word start @ absolute load/run zImage address + .word _edata @ zImage end address 1: mov r7, r1 @ save architecture ID mov r8, #0 @ save r0 #ifdef CONFIG_ANGELBOOT @@ -210,7 +211,7 @@ mov r0, r3 mov r8, r0, lsr #18 mov r8, r8, lsl #18 @ start of RAM - add r9, r8, #0x20000000 @ the maximum RAM size + add r9, r8, #0x10000000 @ a reasonable RAM size mov r1, #0x12 orr r1, r1, #3 << 10 add r2, r3, #16384 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S linux.ac/arch/arm/boot/compressed/ll_char_wr.S --- linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/boot/compressed/ll_char_wr.S Sat Apr 14 01:15:10 2001 @@ -16,7 +16,7 @@ @ Regs: [] = corruptible @ {} = used @ () = do not use -#define __ASSEMBLY__ + #include #include .text diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/ofw-shark.c linux.ac/arch/arm/boot/compressed/ofw-shark.c --- linux.vanilla/arch/arm/boot/compressed/ofw-shark.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/ofw-shark.c Sat Apr 14 01:15:10 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/boot/compressed/ofw-shark.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz * * This file is used to get some basic information * about the memory layout of the shark we are running @@ -11,6 +11,7 @@ #include +#include #include #include @@ -18,7 +19,7 @@ asmlinkage void create_params (unsigned long *buffer) { - /* Is there a better address? Also change in kernel/arch.c */ + /* Is there a better address? Also change in mach-shark/arch.c */ struct param_struct *params = (struct param_struct *) 0x08003000; int j,i,m,k,nr_banks,size; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/boot/compressed/setup-sa1100.S linux.ac/arch/arm/boot/compressed/setup-sa1100.S --- linux.vanilla/arch/arm/boot/compressed/setup-sa1100.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/boot/compressed/setup-sa1100.S Sat Apr 14 01:15:10 2001 @@ -24,6 +24,9 @@ PPC_BASE: .long 0x90060000 #define PPAR 0x08 +IC_BASE: .long 0x90050000 +#define ICMR 0x04 + UART1_BASE: .long 0x80010000 UART3_BASE: .long 0x80050000 #define UTCR0 0x00 @@ -52,6 +55,11 @@ ENTRY(sa1100_setup) mov r3, r0 @ keep machine type in r3 + @ Clear all interrupt sources + ldr r0, IC_BASE + mov r1, #0 + str r1, [r0, #ICMR] + @ Read System Configuration "Register" for Assabet. @ (taken from "Intel StrongARM SA-1110 Microprocessor Development Board @ User's Guide," p.4-9) @@ -87,6 +95,7 @@ @ Initialize UART (if bootloader has not done it yet)... teq r3, #MACH_TYPE_BRUTUS teqne r3, #MACH_TYPE_ASSABET + teqne r3, #MACH_TYPE_GRAPHICSCLIENT bne skip_uart @ UART3 if Assabet is used with Neponset @@ -95,6 +104,11 @@ ldreq r0, UART3_BASE beq uart_init + @ UART3 on GraphicsClient + teq r3, #MACH_TYPE_GRAPHICSCLIENT + ldreq r0, UART3_BASE + beq uart_init + @ At least for Brutus, the UART1 is used through @ the alternate GPIO function... teq r3, #MACH_TYPE_BRUTUS @@ -115,7 +129,8 @@ uart1: ldr r0, UART1_BASE -uart_init: ldr r1, [r0, #UTSR1] +uart_init: +1: ldr r1, [r0, #UTSR1] tst r1, #1<<0 @ TBY bne 1b mov r1, #0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/config.in linux.ac/arch/arm/config.in --- linux.vanilla/arch/arm/config.in Fri Feb 9 19:38:27 2001 +++ linux.ac/arch/arm/config.in Wed Apr 18 13:47:22 2001 @@ -9,6 +9,8 @@ define_bool CONFIG_SBUS n define_bool CONFIG_MCA n define_bool CONFIG_UID16 y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n mainmenu_option next_comment @@ -21,10 +23,8 @@ 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 module symbols' CONFIG_MODVERSIONS - bool ' Kernel module loader' CONFIG_KMOD -fi +dep_bool ' Set version information on all module symbols' CONFIG_MODVERSIONS $CONFIG_MODULES +dep_bool ' Kernel module loader' CONFIG_KMOD $CONFIG_MODULES endmenu @@ -36,71 +36,62 @@ Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ Co-EBSA285 CONFIG_ARCH_CO285 \ EBSA-110 CONFIG_ARCH_EBSA110 \ + LinkUp-L7200 CONFIG_ARCH_L7200 \ FootBridge CONFIG_ARCH_FOOTBRIDGE \ Integrator CONFIG_ARCH_INTEGRATOR \ RiscPC CONFIG_ARCH_RPC \ - SA1100-based CONFIG_ARCH_SA1100" RiscPC - -# the following are placeholders for when they are fully integrated -# LinkUp-L7200 CONFIG_ARCH_L7200 + SA1100-based CONFIG_ARCH_SA1100 \ + CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X" RiscPC mainmenu_option next_comment comment 'Archimedes/A5000 Implementations' -if [ "$CONFIG_ARCH_ARCA5K" = "y" ]; then - # These architectures will be combined. However, until this - # is complete... Note that the ARC will take precidence over - # A5K - comment 'Archimedes/A5000 Implementations (select only ONE)' - - bool ' Archimedes' CONFIG_ARCH_ARC - bool ' A5000' CONFIG_ARCH_A5K -fi +# These architectures will be combined. However, until this +# is complete... Note that the ARC will take precedence over +# A5K +comment 'Archimedes/A5000 Implementations (select only ONE)' +dep_bool ' Archimedes' CONFIG_ARCH_ARC $CONFIG_ARCH_ARCA5K +dep_bool ' A5000' CONFIG_ARCH_A5K $CONFIG_ARCH_ARCA5K endmenu mainmenu_option next_comment comment 'Footbridge Implementations' -if [ "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then - bool ' CATS' CONFIG_ARCH_CATS - bool ' Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER - bool ' EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN - bool ' EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST - bool ' NetWinder' CONFIG_ARCH_NETWINDER -fi +dep_bool ' CATS' CONFIG_ARCH_CATS $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST $CONFIG_ARCH_FOOTBRIDGE +dep_bool ' NetWinder' CONFIG_ARCH_NETWINDER $CONFIG_ARCH_FOOTBRIDGE endmenu mainmenu_option next_comment comment 'SA11x0 Implementations' -if [ "$CONFIG_ARCH_SA1100" = "y" ]; then - - bool ' Assabet' CONFIG_SA1100_ASSABET - if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then - bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET - fi - bool ' Brutus' CONFIG_SA1100_BRUTUS - bool ' CerfBoard' CONFIG_SA1100_CERF - bool ' Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY -# bool ' Empeg' CONFIG_SA1100_EMPEG -# bool ' Itsy' CONFIG_SA1100_ITSY - bool ' LART' CONFIG_SA1100_LART -# bool ' PLEB' CONFIG_SA1100_PLEB - bool ' ThinClient' CONFIG_SA1100_THINCLIENT - bool ' GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT - bool ' nanoEngine' CONFIG_SA1100_NANOENGINE - bool ' Victor' CONFIG_SA1100_VICTOR -# bool ' Tifon' CONFIG_SA1100_TIFON - bool ' XP860' CONFIG_SA1100_XP860 - - # Someday, we'll support this as a general option. - bool ' Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT - - # Determine if SA1111 support is required - if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \ - "$CONFIG_SA1100_XP860" = "y" ]; then - define_bool CONFIG_SA1111 y - fi +dep_bool ' Assabet' CONFIG_SA1100_ASSABET $CONFIG_ARCH_SA1100 +dep_bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET $CONFIG_SA1100_ASSABET +dep_bool ' Brutus' CONFIG_SA1100_BRUTUS $CONFIG_ARCH_SA1100 +dep_bool ' CerfBoard' CONFIG_SA1100_CERF $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY $CONFIG_ARCH_SA1100 +#dep_bool ' Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100 +#dep_bool ' Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100 +dep_bool ' LART' CONFIG_SA1100_LART $CONFIG_ARCH_SA1100 +#dep_bool ' PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100 +dep_bool ' GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100 +dep_bool ' nanoEngine' CONFIG_SA1100_NANOENGINE $CONFIG_ARCH_SA1100 +dep_bool ' Victor' CONFIG_SA1100_VICTOR $CONFIG_ARCH_SA1100 +dep_bool ' Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100 +dep_bool ' XP860' CONFIG_SA1100_XP860 $CONFIG_ARCH_SA1100 +dep_bool ' Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100 + +# Determine if SA1111 support is required +if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \ + "$CONFIG_SA1100_XP860" = "y" ]; then + define_bool CONFIG_SA1111 y fi endmenu +mainmenu_option next_comment +comment 'CLPS711X/EP721X Implementations' +dep_bool ' P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X +endmenu + # Definitions to make life easier if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -147,49 +138,77 @@ comment 'Processor Type' -# Select CPU and optimisation dependent on architecture -if [ "$CONFIG_ARCH_RPC" = "y" ]; then +# Firstly, figure out what processor architecture version we should be using. +if [ "$CONFIG_ARCH_RPC" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then define_bool CONFIG_CPU_32v3 y - bool 'Support ARM610 processor' CONFIG_CPU_ARM6 - bool 'Support ARM710 processor' CONFIG_CPU_ARM7 - bool 'Support StrongARM(R) SA-110 processor' CONFIG_CPU_SA110 +else + define_bool CONFIG_CPU_32v3 n fi -if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_FOOTBRIDGE" = "y" -o \ - "$CONFIG_ARCH_TBOX" = "y" -o \ - "$CONFIG_ARCH_SHARK" = "y" -o \ - "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then +if [ "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_L7200" = "y" ]; then define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_SA110 y +else + define_bool CONFIG_CPU_32v4 n fi + +# Select CPU types depending on the architecture selected. +# We use this to select which CPUs are supported, and to select +# the compiler tuning options. + +# ARM610 +if [ "$CONFIG_ARCH_RPC" = "y" ]; then + bool 'Support ARM610 processor' CONFIG_CPU_ARM610 +else + define_bool CONFIG_CPU_ARM610 n +fi + +# ARM710 if [ "$CONFIG_ARCH_CLPS7500" = "y" ]; then - define_bool CONFIG_CPU_32v3 y - define_bool CONFIG_CPU_ARM7 y + define_bool CONFIG_CPU_ARM710 y +else + if [ "$CONFIG_ARCH_RPC" = "y" ]; then + bool 'Support ARM710 processor' CONFIG_CPU_ARM710 + else + define_bool CONFIG_CPU_ARM710 n + fi fi -if [ "$CONFIG_ARCH_L7200" = "y" ]; then - define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_ARM720 y + +# ARM720T +if [ "$CONFIG_ARCH_CLPS711X" = "y" -o "$CONFIG_ARCH_L7200" = "y" ]; then + define_bool CONFIG_CPU_ARM720T y +else + if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'Support ARM720T processor' CONFIG_CPU_ARM720T + else + define_bool CONFIG_CPU_ARM720T n + fi fi + +# ARM920T if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then - define_bool CONFIG_CPU_32v4 y - bool 'Support ARM720 processor' CONFIG_CPU_ARM720 - bool 'Support ARM920 processor' CONFIG_CPU_ARM920 -# bool 'Support ARM10 processor' CONFIG_CPU_ARM10 -fi -if [ "$CONFIG_ARCH_SA1100" = "y" ]; then - define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_SA1100 y + bool 'Support ARM920T processor' CONFIG_CPU_ARM920T +else + define_bool CONFIG_CPU_ARM920T n fi - -if [ "$CONFIG_CPU_ARM920" = "y" ]; then - bool ' ARM920 CPU idle' CONFIG_CPU_ARM920_CPU_IDLE - bool ' ARM920 I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON - bool ' ARM920 D-Cache on' CONFIG_CPU_ARM920_D_CACHE_ON +if [ "$CONFIG_CPU_ARM920T" = "y" ]; then + bool ' ARM920T CPU idle' CONFIG_CPU_ARM920_CPU_IDLE + bool ' ARM920T I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON + bool ' ARM920T D-Cache on' CONFIG_CPU_ARM920_D_CACHE_ON if [ "$CONFIG_CPU_ARM920_D_CACHE_ON" = "y" ] ; then - bool ' Force write through caches on ARM920' CONFIG_CPU_ARM920_WRITETHROUGH + bool ' Force write through caches on ARM920T' CONFIG_CPU_ARM920_WRITETHROUGH fi fi -#if [ "$CONFIG_CPU_ARM10" = "y" ]; then + +# ARM1020 +#if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then +# bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020 +#else + define_bool CONFIG_CPU_ARM1020 n +#fi +#if [ "$CONFIG_CPU_ARM1020" = "y" ]; then # bool ' ARM10 I-Cache on' CONFIG_CPU_ARM10_I_CACHE_ON # bool ' ARM10 D-Cache on' CONFIG_CPU_ARM10_D_CACHE_ON # if [ "$CONFIG_CPU_ARM10_D_CACHE_ON" = "y" ] ; then @@ -197,6 +216,30 @@ # fi #fi +# SA110 +if [ "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then + define_bool CONFIG_CPU_SA110 y +else + if [ "$CONFIG_ARCH_RPC" = "y" ]; then + bool 'Support StrongARM(R) SA-110 processor' CONFIG_CPU_SA110 + else + define_bool CONFIG_CPU_SA110 n + fi +fi + +# SA1100 +if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + define_bool CONFIG_CPU_SA1100 y +else + define_bool CONFIG_CPU_SA1100 n +fi + +#if [ "$CONFIG_CPU_32" = "y" ]; then +# bool 'Support Thumb instructions' CONFIG_ARM_THUMB +#fi + # Select various configuration options depending on the machine type if [ "$CONFIG_ARCH_SA1100" = "y" ]; then define_bool CONFIG_DISCONTIGMEM y @@ -209,8 +252,12 @@ mainmenu_option next_comment comment 'General setup' +comment 'Please ensure that you have read the help on the next option' +bool 'Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT + # Now handle the bus types -if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ +if [ "$CONFIG_ARCH_FTVPCI" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then define_bool CONFIG_PCI y else @@ -223,21 +270,19 @@ fi if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ - "$CONFIG_ARCH_SHARK" = "y" ]; then + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_EBSA110" = "y" ]; then define_bool CONFIG_ISA y - define_bool CONFIG_ISA_DMA y else define_bool CONFIG_ISA n - define_bool CONFIG_ISA_DMA n fi -# Do we have a PC-type keyboard in this architecture? -if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then - define_bool CONFIG_PC_KEYB y - define_bool CONFIG_PC_KEYMAP y -fi -if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then - define_bool CONFIG_PC_KEYMAP y +if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" ]; then + define_bool CONFIG_ISA_DMA y +else + define_bool CONFIG_ISA_DMA n fi source drivers/pci/Config.in @@ -251,42 +296,44 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -tristate 'NWFPE math emulation' CONFIG_NWFPE +tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE +dep_tristate 'FastFPE math emulation (experimental)' CONFIG_FPE_FASTFPE $CONFIG_EXPERIMENTAL choice 'Kernel core (/proc/kcore) format' \ "ELF CONFIG_KCORE_ELF \ A.OUT CONFIG_KCORE_AOUT" ELF 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 +dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL +dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32 -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Power Management support' CONFIG_PM -fi - -if [ "$CONFIG_CPU_32" = "y" ]; then - tristate 'RISC OS personality' CONFIG_ARTHUR -fi -if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_CLPS7500" = "y" -o \ +if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \ - "$CONFIG_ARCH_CATS" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + "$CONFIG_ARCH_CATS" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" ]; then string 'Default kernel command string' CONFIG_CMDLINE "" fi -if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ - "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_ARCH_EBSA285" = "y" -o \ - "$CONFIG_ARCH_CO285" = "y" -o \ - "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then +if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_FTVPCI" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" ]; then bool 'Timer and CPU usage LEDs' CONFIG_LEDS if [ "$CONFIG_LEDS" = "y" ]; then - if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ - "$CONFIG_ARCH_EBSA285" = "y" -o \ - "$CONFIG_ARCH_CO285" = "y" -o \ - "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" ]; then bool ' Timer LED' CONFIG_LEDS_TIMER bool ' CPU usage LED' CONFIG_LEDS_CPU fi @@ -350,9 +397,13 @@ fi endmenu +if [ "$CONFIG_ARCH_CLPS711X" = "y" ]; then + source drivers/ssi/Config.in +fi + source drivers/ieee1394/Config.in -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in mainmenu_option next_comment comment 'ISDN subsystem' @@ -363,6 +414,11 @@ fi endmenu +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in + source drivers/char/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" -a \ "$CONFIG_BUSMOUSE" = "y" ]; then @@ -373,11 +429,34 @@ fi fi +source drivers/media/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' + # Select the keyboard type for this architecture. + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" ]; then + define_bool CONFIG_PC_KEYB y + fi + if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + define_bool CONFIG_KMI_KEYB y + define_bool CONFIG_KMI_MOUSE y + fi + + # Do we use the PC-type keyboard map? + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" ]; then + define_bool CONFIG_PC_KEYMAP y + fi if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then bool 'VGA text console' CONFIG_VGA_CONSOLE fi @@ -388,6 +467,7 @@ if [ "$CONFIG_ARCH_ACORN" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_PCI" = "y" ]; then mainmenu_option next_comment @@ -408,23 +488,14 @@ # Always compile kernel with framepointer (until 2.4 real comes out) # Bug reports aren't much use without this. -#bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER -define_bool CONFIG_FRAME_POINTER y +bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS bool 'Verbose user fault messages' CONFIG_DEBUG_USER bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -if [ "$CONFIG_CPU_26" = "y" ]; then - bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE -fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - # These options are only for real kernel hackers - # who want to get their hands dirty. - bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL - if [ "$CONFIG_DEBUG_LL" = "y" ]; then - if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT - fi - fi -fi +dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26 +# These options are only for real kernel hackers who want to get their hands dirty. +dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL +dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE +dep_bool ' kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/def-configs/clps7500 linux.ac/arch/arm/def-configs/clps7500 --- linux.vanilla/arch/arm/def-configs/clps7500 Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/def-configs/clps7500 Thu Apr 19 22:11:46 2001 @@ -2,7 +2,9 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_EISA is not set # CONFIG_SBUS is not set +# CONFIG_MCA is not set CONFIG_UID16=y # @@ -23,6 +25,7 @@ CONFIG_ARCH_CLPS7500=y # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_FTVPCI is not set # CONFIG_ARCH_TBOX is not set # CONFIG_ARCH_SHARK is not set @@ -30,22 +33,51 @@ # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set # CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set + +# +# Processor Type +# CONFIG_CPU_32v3=y -CONFIG_CPU_ARM7=y +# CONFIG_CPU_32v4 is not set +# CONFIG_CPU_ARM610 is not set +CONFIG_CPU_ARM710=y +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set # CONFIG_DISCONTIGMEM is not set -# CONFIG_PCI is not set -# CONFIG_ISA is not set -# CONFIG_ISA_DMA is not set # # General setup # +CONFIG_ANGELBOOT=y +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set CONFIG_NET=y @@ -60,7 +92,7 @@ # CONFIG_BINFMT_MISC is not set # CONFIG_PM is not set # CONFIG_ARTHUR is not set -CONFIG_CMDLINE="root=/dev/nfs rw" +CONFIG_CMDLINE="mem=16M root=nfs" # CONFIG_ALIGNMENT_TRAP is not set # @@ -81,34 +113,35 @@ # Memory Technology Devices (MTD) # CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set + +# +# Disk-On-Chip Device Drivers +# # CONFIG_MTD_DOC1000 is not set # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOCPROBE is not set + +# +# RAM/ROM Device Drivers +# # CONFIG_MTD_SLRAM is not set -# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set # CONFIG_MTD_MTDRAM is not set # -# MTD drivers for mapped chips +# Linearly Mapped Flash Device Drivers # # CONFIG_MTD_CFI is not set -# CONFIG_MTD_CFI_INTELEXT is not set -# CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_JEDEC is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set -# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_JEDEC is not set # # Drivers for chip mappings # -# CONFIG_MTD_MIXMEM is not set -# CONFIG_MTD_NORA is not set -# CONFIG_MTD_OCTAGON is not set -# CONFIG_MTD_PNC2000 is not set -# CONFIG_MTD_RPXLITE is not set -# CONFIG_MTD_VMAX is not set # # User modules and translation layers for MTD devices @@ -122,7 +155,6 @@ # Plug and Play configuration # # CONFIG_PNP is not set -# CONFIG_ISAPNP is not set # # Block devices @@ -130,20 +162,12 @@ # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set +CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_BLK_DEV_FLD7500=y +# CONFIG_BLK_DEV_FLD7500 is not set # # Networking options @@ -159,10 +183,8 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -179,6 +201,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -201,6 +224,7 @@ CONFIG_DUMMY=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -213,16 +237,19 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set +CONFIG_NET_PCI=y +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +CONFIG_CS89x0=y +# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set -# CONFIG_SK98LIN is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PLIP is not set @@ -283,10 +310,6 @@ # I2O device support # # CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set # # ISDN subsystem @@ -294,6 +317,11 @@ # CONFIG_ISDN is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# # Character devices # CONFIG_VT=y @@ -305,7 +333,7 @@ CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 CONFIG_PRINTER=y -CONFIG_LP_CONSOLE=y +# CONFIG_LP_CONSOLE is not set # CONFIG_PPDEV is not set # @@ -322,16 +350,38 @@ # # Mice # -# CONFIG_BUSMOUSE is not set +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set CONFIG_MOUSE=y -CONFIG_PSMOUSE=y +# CONFIG_PSMOUSE is not set # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set # # Joysticks # -# CONFIG_JOYSTICK is not set + +# +# Game port support +# + +# +# Gameport joysticks +# + +# +# Serial port support +# + +# +# Serial port joysticks +# + +# +# Parallel port joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -341,11 +391,6 @@ CONFIG_CLPS7500_FLASH=y # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -353,45 +398,38 @@ # CONFIG_DRM is not set # +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# # File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set # # Network File Systems @@ -401,21 +439,10 @@ # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set -# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set # # Partition Types @@ -430,11 +457,14 @@ # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # Console drivers # +CONFIG_PC_KEYB=y +CONFIG_PC_KEYMAP=y # CONFIG_VGA_CONSOLE is not set CONFIG_FB=y @@ -445,15 +475,14 @@ CONFIG_DUMMY_CONSOLE=y CONFIG_FB_ACORN=y # CONFIG_CHRONTEL_7003 is not set -# CONFIG_FB_CYBER2000 is not set # CONFIG_FB_VIRTUAL is not set CONFIG_FBCON_ADVANCED=y -# CONFIG_FBCON_MFB is not set -# CONFIG_FBCON_CFB2 is not set -# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_MFB=y +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y CONFIG_FBCON_CFB8=y -# CONFIG_FBCON_CFB16 is not set -# CONFIG_FBCON_CFB24 is not set +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y # CONFIG_FBCON_CFB32 is not set # CONFIG_FBCON_AFB is not set # CONFIG_FBCON_ILBM is not set @@ -487,4 +516,4 @@ # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL=y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/def-configs/integrator linux.ac/arch/arm/def-configs/integrator --- linux.vanilla/arch/arm/def-configs/integrator Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/def-configs/integrator Thu Apr 19 22:11:46 2001 @@ -25,6 +25,7 @@ # CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_FOOTBRIDGE is not set CONFIG_ARCH_INTEGRATOR=y # CONFIG_ARCH_RPC is not set @@ -56,18 +57,28 @@ # # Processor Type # +# CONFIG_CPU_32v3 is not set CONFIG_CPU_32v4=y -CONFIG_CPU_ARM720=y -CONFIG_CPU_ARM920=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +CONFIG_CPU_ARM720T=y +CONFIG_CPU_ARM920T=y CONFIG_CPU_ARM920_CPU_IDLE=y CONFIG_CPU_ARM920_I_CACHE_ON=y CONFIG_CPU_ARM920_D_CACHE_ON=y # CONFIG_CPU_ARM920_WRITETHROUGH is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set # CONFIG_DISCONTIGMEM is not set # # General setup # + +# +# Please ensure that you have read the help on the next option +# # CONFIG_ANGELBOOT is not set CONFIG_PCI_INTEGRATOR=y CONFIG_PCI=y @@ -103,23 +114,32 @@ # Memory Technology Devices (MTD) # CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set + +# +# Disk-On-Chip Device Drivers +# # CONFIG_MTD_DOC1000 is not set # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOCPROBE is not set + +# +# RAM/ROM Device Drivers +# # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PMC551 is not set # CONFIG_MTD_MTDRAM is not set # -# MTD drivers for mapped chips +# Linearly Mapped Flash Device Drivers # CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_JEDEC is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set +# CONFIG_MTD_JEDEC is not set # CONFIG_MTD_PHYSMAP is not set # @@ -347,6 +367,8 @@ CONFIG_SERIAL_AMBA=y CONFIG_SERIAL_INTEGRATOR=y CONFIG_SERIAL_AMBA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 @@ -403,6 +425,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -457,8 +481,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -475,6 +497,7 @@ # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -503,7 +526,7 @@ # # Kernel hacking # -CONFIG_FRAME_POINTER=y +# CONFIG_NO_FRAME_POINTER is not set CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/defconfig linux.ac/arch/arm/defconfig --- linux.vanilla/arch/arm/defconfig Tue Jun 20 01:59:33 2000 +++ linux.ac/arch/arm/defconfig Thu Apr 19 22:11:46 2001 @@ -2,50 +2,80 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and processor type +# Loadable module support # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -CONFIG_FOOTBRIDGE=y -CONFIG_HOST_FOOTBRIDGE=y -# CONFIG_ADDIN_FOOTBRIDGE is not set -CONFIG_ARCH_EBSA285=y -# CONFIG_ARCH_CATS is not set -CONFIG_ARCH_NETWINDER=y -# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +CONFIG_ARCH_INTEGRATOR=y +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# # CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set -CONFIG_CPU_32v4=y -CONFIG_CPU_SA110=y -CONFIG_PCI=y -CONFIG_PCI_NAMES=y -CONFIG_ISA=y -CONFIG_ISA_DMA=y -# CONFIG_SBUS is not set -# CONFIG_PCMCIA is not set -# CONFIG_ALIGNMENT_TRAP is not set # -# Loadable module support +# Processor Type # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ARM720=y +CONFIG_CPU_ARM920=y +CONFIG_CPU_ARM920_CPU_IDLE=y +CONFIG_CPU_ARM920_I_CACHE_ON=y +CONFIG_CPU_ARM920_D_CACHE_ON=y +# CONFIG_CPU_ARM920_WRITETHROUGH is not set +# CONFIG_DISCONTIGMEM is not set # # General setup # +# CONFIG_ANGELBOOT is not set +CONFIG_PCI_INTEGRATOR=y +CONFIG_PCI=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -56,296 +86,86 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=1f04 mem=32M" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y # # Parallel port support # -CONFIG_PARPORT=y -CONFIG_PARPORT_PC=y -CONFIG_PARPORT_PC_FIFO=y -# CONFIG_PARPORT_PC_SUPERIO is not set -# CONFIG_PARPORT_ARC is not set -# 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_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune" -CONFIG_LEDS=y -CONFIG_LEDS_TIMER=y -# CONFIG_LEDS_CPU is not set +# CONFIG_PARPORT is not set # -# IEEE 1394 (FireWire) support +# Memory Technology Devices (MTD) # -# CONFIG_IEEE1394 is not set +CONFIG_MTD=y +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_MTDRAM is not set # -# I2O device support +# MTD drivers for mapped chips # -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_JEDEC is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_PHYSMAP is not set + +# +# Drivers for chip mappings +# +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_VMAX is not set + +# +# User modules and translation layers for MTD devices +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +CONFIG_MTD_ARM=y # # Plug and Play configuration # -CONFIG_PNP=y -CONFIG_ISAPNP=y +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE=m -CONFIG_PARIDE_PARPORT=y - -# -# Parallel IDE high-level drivers -# -CONFIG_PARIDE_PD=m -CONFIG_PARIDE_PCD=m -CONFIG_PARIDE_PF=m -CONFIG_PARIDE_PT=m -CONFIG_PARIDE_PG=m - -# -# Parallel IDE protocol modules -# -CONFIG_PARIDE_ATEN=m -CONFIG_PARIDE_BPCK=m -CONFIG_PARIDE_COMM=m -CONFIG_PARIDE_DSTR=m -CONFIG_PARIDE_FIT2=m -CONFIG_PARIDE_FIT3=m -CONFIG_PARIDE_EPAT=m -CONFIG_PARIDE_EPIA=m -CONFIG_PARIDE_FRIQ=m -CONFIG_PARIDE_FRPW=m -CONFIG_PARIDE_KBIC=m -CONFIG_PARIDE_KTTI=m -CONFIG_PARIDE_ON20=m -CONFIG_PARIDE_ON26=m +# CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_STRIPED=m +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_INITRD is not set # -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_PRINTER=m -# CONFIG_LP_CONSOLE is not set -# CONFIG_PPDEV is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set -# CONFIG_WDT is not set -CONFIG_SOFT_WATCHDOG=y -# CONFIG_PCWATCHDOG is not set -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_MIXCOMWD is not set -# CONFIG_21285_WATCHDOG is not set -CONFIG_977_WATCHDOG=m -CONFIG_DS1620=y -CONFIG_NWBUTTON=y -CONFIG_NWBUTTON_REBOOT=y -CONFIG_NWFLASH=m -# CONFIG_NVRAM is not set -CONFIG_RTC=y - -# -# Video For Linux -# -CONFIG_VIDEO_DEV=y -# CONFIG_I2C_PARPORT is not set - -# -# Radio Adapters -# -# CONFIG_RADIO_CADET is not set -# CONFIG_RADIO_RTRACK is not set -# CONFIG_RADIO_RTRACK2 is not set -# CONFIG_RADIO_AZTECH is not set -# CONFIG_RADIO_GEMTEK is not set -# CONFIG_RADIO_MIROPCM20 is not set -# CONFIG_RADIO_SF16FMI is not set -# CONFIG_RADIO_TERRATEC is not set -# CONFIG_RADIO_TRUST is not set -# CONFIG_RADIO_TYPHOON is not set -# CONFIG_RADIO_ZOLTRIX is not set - -# -# Video Adapters -# -# CONFIG_VIDEO_PMS is not set -# CONFIG_VIDEO_BWQCAM is not set -# CONFIG_VIDEO_CQCAM is not set -# CONFIG_VIDEO_SAA5249 is not set -# CONFIG_TUNER_3036 is not set -# CONFIG_VIDEO_STRADIS is not set -# CONFIG_VIDEO_ZORAN is not set -# CONFIG_VIDEO_BUZ is not set -# CONFIG_VIDEO_ZR36120 is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set - -# -# USB support -# -CONFIG_USB=m - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -CONFIG_USB_OHCI=m - -# -# Miscellaneous USB options -# -CONFIG_USB_DEVICEFS=y - -# -# USB Devices -# -CONFIG_USB_PRINTER=m -# CONFIG_USB_SCANNER is not set -CONFIG_USB_AUDIO=m -CONFIG_USB_ACM=m -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_CPIA is not set -# CONFIG_USB_IBMCAM is not set -# CONFIG_USB_OV511 is not set -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_USS720 is not set -# CONFIG_USB_DABUSB is not set -# CONFIG_USB_PLUSB is not set -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_DSBR is not set - -# -# USB HID -# -# CONFIG_USB_HID is not set -CONFIG_USB_KBD=m -CONFIG_USB_MOUSE=m -# CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=m -CONFIG_INPUT_MOUSEDEV=m -CONFIG_INPUT_MOUSEDEV_MIX=y -# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -# CONFIG_FB_RIVA is not set -# CONFIG_FB_CLGEN is not set -# CONFIG_FB_PM2 is not set -CONFIG_FB_CYBER2000=y -# CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VIRTUAL is not set -CONFIG_FBCON_ADVANCED=y -# CONFIG_FBCON_MFB is not set -# CONFIG_FBCON_CFB2 is not set -# CONFIG_FBCON_CFB4 is not set -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -# CONFIG_FBCON_CFB32 is not set -# CONFIG_FBCON_AFB is not set -# CONFIG_FBCON_ILBM is not set -# CONFIG_FBCON_IPLAN2P2 is not set -# CONFIG_FBCON_IPLAN2P4 is not set -# CONFIG_FBCON_IPLAN2P8 is not set -# CONFIG_FBCON_MAC is not set -# CONFIG_FBCON_VGA_PLANES is not set -CONFIG_FBCON_VGA=y -# CONFIG_FBCON_HGA is not set -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_SUN12x22 is not set -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -CONFIG_FONT_ACORN_8x8=y - -# # Networking options # -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set +# CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -356,16 +176,10 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -376,10 +190,11 @@ # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -391,16 +206,6 @@ # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -412,68 +217,59 @@ # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -# CONFIG_ARM_AM79C961A is not set -CONFIG_NET_VENDOR_3COM=y -# CONFIG_EL1 is not set -# CONFIG_EL2 is not set -# CONFIG_ELPLUS is not set -# CONFIG_EL16 is not set -# CONFIG_EL3 is not set -# CONFIG_3C515 is not set -CONFIG_VORTEX=y +# CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set +CONFIG_TULIP=y # CONFIG_DE4X5 is not set -CONFIG_TULIP=m # CONFIG_DGRS is not set # CONFIG_DM9102 is not set -# CONFIG_EEPRO100 is not set +CONFIG_EEPRO100=y +CONFIG_EEPRO100_PM=y # CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set -CONFIG_NE2K_PCI=y -# CONFIG_RTL8129 is not set +# CONFIG_ES3210 is not set # CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set # CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -# CONFIG_PPP_SYNC_TTY is not set -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -CONFIG_SLIP_MODE_SLIP6=y +# CONFIG_PPP is not set +# CONFIG_SLIP is not set # # Wireless LAN (non-hamradio) @@ -494,71 +290,21 @@ # CONFIG_WAN is not set # -# ATA/IDE/MFM/RLL support +# Amateur Radio support # -CONFIG_IDE=y +# CONFIG_HAMRADIO is not set # -# IDE, ATA and ATAPI Block devices +# IrDA (infrared) support # -CONFIG_BLK_DEV_IDE=y +# CONFIG_IRDA is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# ATA/IDE/MFM/RLL support # -# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -CONFIG_IDEDISK_MULTI_MODE=y -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_OFFBOARD=y -CONFIG_IDEDMA_PCI_AUTO=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y -# CONFIG_IDEDMA_PCI_WIP is not set -# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_AEC62XX_TUNING is not set -# CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_WDC_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD7409 is not set -# CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set -CONFIG_BLK_DEV_CY82C693=y -# CONFIG_BLK_DEV_CS5530 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_HPT34X_AUTODMA is not set -# CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_OPTI621 is not set -CONFIG_BLK_DEV_PDC202XX=y -# CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set -# CONFIG_BLK_DEV_SIS5513 is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -CONFIG_BLK_DEV_SL82C105=y -# CONFIG_IDE_CHIPSETS is not set -CONFIG_IDEDMA_AUTO=y -CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support @@ -566,72 +312,115 @@ # CONFIG_SCSI is not set # -# Sound +# IEEE 1394 (FireWire) support # -CONFIG_SOUND=m -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_TRIDENT is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -CONFIG_SOUND_OSS=m -# CONFIG_SOUND_TRACEINIT is not set -# CONFIG_SOUND_DMAP is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_ADLIB is not set -# CONFIG_SOUND_ACI_MIXER is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_NM256 is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_PAS is not set -# CONFIG_PAS_JOYSTICK is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_SOFTOSS is not set -CONFIG_SOUND_SB=m -# CONFIG_SOUND_AWE32_SYNTH is not set -# CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_OPL3SA2 is not set -# CONFIG_SOUND_UART6850 is not set -# CONFIG_SOUND_AEDSP16 is not set -# CONFIG_SOUND_VIDC is not set -CONFIG_SOUND_WAVEARTIST=m +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_AMBA=y +CONFIG_SERIAL_INTEGRATOR=y +CONFIG_SERIAL_AMBA_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems # # CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set -CONFIG_ADFS_FS=y +# CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=m +# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y +# CONFIG_RAMFS 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_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set @@ -639,77 +428,77 @@ # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y -CONFIG_NFSD=m +# CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types # CONFIG_PARTITION_ADVANCED=y -CONFIG_ACORN_PARTITION=y -# CONFIG_ACORN_PARTITION_ICS is not set -CONFIG_ACORN_PARTITION_ADFS=y -# CONFIG_ACORN_PARTITION_POWERTEC is not set -# CONFIG_ACORN_PARTITION_RISCIX is not set +# CONFIG_ACORN_PARTITION is not set # CONFIG_OSF_PARTITION is not set # CONFIG_AMIGA_PARTITION is not set # CONFIG_ATARI_PARTITION is not set # CONFIG_MAC_PARTITION 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_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set -CONFIG_NLS=y +# CONFIG_NLS is not set # -# Native Language Support +# Console drivers +# +CONFIG_KMI_KEYB=y +CONFIG_PC_KEYMAP=y +CONFIG_VGA_CONSOLE=y +# CONFIG_FB is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support # -CONFIG_NLS_CODEPAGE_437=m -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -# 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=m -CONFIG_NLS_ISO8859_2=m -# 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_14 is not set -CONFIG_NLS_ISO8859_15=m -# CONFIG_NLS_KOI8_R is not set +# CONFIG_USB is not set # # Kernel hacking @@ -719,4 +508,4 @@ CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL=y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/Makefile linux.ac/arch/arm/kernel/Makefile --- linux.vanilla/arch/arm/kernel/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/kernel/Makefile Sat Apr 14 01:15:10 2001 @@ -13,16 +13,18 @@ AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) +# This is depreciated. O_OBJS_arc = dma-arc.o oldlatches.o O_OBJS_rpc = dma-rpc.o O_OBJS_footbridge = dma-footbridge.o isa.o O_OBJS_l7200 = fiq.o -pci-nexuspci = plx90x0.o +pci-ftvpci = plx90x0.o pci-footbridge = dec21285.o pci-shark = via82c505.o -pci-$(CONFIG_ARCH_NEXUSPCI) += ftv-pci.o +# this is here to allow us to eventually move it out to mach-ftvpci +pci-$(CONFIG_ARCH_FTVPCI) += ftv-pci.o O_TARGET := kernel.o @@ -36,7 +38,7 @@ obj-n := obj- := -export-objs := armksyms.o dma.o ecard.o fiq.o oldlatches.o time.o +export-objs := armksyms.o dma.o ecard.o fiq.o io.o oldlatches.o time.o no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \ $(CONFIG_ARCH_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) @@ -46,16 +48,21 @@ endif obj-$(CONFIG_ARCH_ACORN) += ecard.o fiq.o time-acorn.o +obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o obj-$(CONFIG_MODULES) += armksyms.o obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o $(pci-$(MACHINE)) $(pci-y) +ifneq ($(MACHINE),ebsa110) + obj-y += io.o +endif + all: kernel.o $(HEAD_OBJ) init_task.o include $(TOPDIR)/Rules.make # Spell out some dependencies that `make dep' doesn't spot -entry-armv.o: calls.S ../lib/constants.h -entry-armo.o: calls.S ../lib/constants.h +entry-armv.o: calls.S $(TOPDIR)/include/asm-arm/constants.h +entry-armo.o: calls.S $(TOPDIR)/include/asm-arm/constants.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/arch.c linux.ac/arch/arm/kernel/arch.c --- linux.vanilla/arch/arm/kernel/arch.c Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/arch.c Sat Apr 14 01:15:10 2001 @@ -19,10 +19,9 @@ #include #include -unsigned int vram_size; +extern void genarch_init_irq(void); -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); +unsigned int vram_size; #ifdef CONFIG_ARCH_ACORN @@ -79,6 +78,7 @@ DISABLE_PARPORT(1) FIXUP(fixup_acorn) MAPIO(rpc_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_ARC @@ -86,6 +86,7 @@ MAINTAINER("Dave Gilbert") BOOT_PARAMS(0x0207c000) FIXUP(fixup_acorn) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_A5K @@ -93,11 +94,13 @@ MAINTAINER("Russell King") BOOT_PARAMS(0x0207c000) FIXUP(fixup_acorn) + INITIRQ(genarch_init_irq) MACHINE_END #endif #endif #ifdef CONFIG_ARCH_L7200 +extern void __init l7200_map_io(void); static void __init fixup_l7200(struct machine_desc *desc, struct param_struct *params, @@ -109,34 +112,28 @@ mi->bank[0].node = 0; ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( __phys_to_virt(0xf1000000), 0x00162b0d); -} + setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); + setup_initrd( __phys_to_virt(0xf1000000), 0x005dac7b); -extern void __init l7200_map_io(void); + /* Serial Console COM2 and LCD */ + strcpy( *cmdline, "console=tty0 console=ttyLU1,115200"); + + /* Serial Console COM1 and LCD */ + //strcpy( *cmdline, "console=tty0 console=ttyLU0,115200"); + + /* Console on LCD */ + //strcpy( *cmdline, "console=tty0"); +} -MACHINE_START(L7200, "LinkUp Systems L7200SDB") - MAINTAINER("Steve Hill") +MACHINE_START(L7200, "LinkUp Systems L7200") + MAINTAINER("Steve Hill / Scott McConnell") BOOT_MEM(0xf0000000, 0x80040000, 0xd0000000) FIXUP(fixup_l7200) MAPIO(l7200_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif -#ifdef CONFIG_ARCH_EBSA110 - -extern void __init ebsa110_map_io(void); - -MACHINE_START(EBSA110, "EBSA110") - MAINTAINER("Russell King") - BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) - BOOT_PARAMS(0x00000400) - DISABLE_PARPORT(0) - DISABLE_PARPORT(2) - SOFT_REBOOT - MAPIO(ebsa110_map_io) -MACHINE_END -#endif #ifdef CONFIG_ARCH_NEXUSPCI extern void __init nexuspci_map_io(void); @@ -145,6 +142,7 @@ MAINTAINER("Philip Blundell") BOOT_MEM(0x40000000, 0x10000000, 0xe0000000) MAPIO(nexuspci_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_TBOX @@ -155,21 +153,25 @@ MAINTAINER("Philip Blundell") BOOT_MEM(0x80000000, 0x00400000, 0xe0000000) MAPIO(tbox_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7110 MACHINE_START(CLPS7110, "CL-PS7110") MAINTAINER("Werner Almesberger") + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_ETOILE MACHINE_START(ETOILE, "Etoile") MAINTAINER("Alex de Vries") + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_LACIE_NAS MACHINE_START(LACIE_NAS, "LaCie_NAS") MAINTAINER("Benjamin Herrenschmidt") + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7500 @@ -180,5 +182,6 @@ MAINTAINER("Philip Blundell") BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) MAPIO(clps7500_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/armksyms.c linux.ac/arch/arm/kernel/armksyms.c --- linux.vanilla/arch/arm/kernel/armksyms.c Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/armksyms.c Sat Apr 14 01:15:10 2001 @@ -48,7 +48,6 @@ extern int sys_read(int, char *, int); extern int sys_lseek(int, off_t, int); extern int sys_exit(int); -extern int sys_wait4(int, int *, int, struct rusage *); /* * libgcc functions - functions that are used internally by the @@ -77,15 +76,18 @@ extern void fpundefinstr(void); extern void fp_enter(void); -#define EXPORT_SYMBOL_ALIAS(sym,orig) \ - const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \ - __MODULE_STRING(##sym##); \ - const struct module_symbol __ksymtab_##sym __attribute__((section("__ksymtab"))) = \ +#define EXPORT_SYMBOL_ALIAS(sym,orig) \ + const char __kstrtab_##sym##[] \ + __attribute__((section(".kstrtab"))) = \ + __MODULE_STRING(sym); \ + const struct module_symbol __ksymtab_##sym \ + __attribute__((section("__ksymtab"))) = \ { (unsigned long)&##orig, __kstrtab_##sym }; - /* - * floating point math emulator support. - * These symbols will never change their calling convention... - */ + +/* + * floating point math emulator support. + * These symbols will never change their calling convention... + */ EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter); EXPORT_SYMBOL_ALIAS(fp_printk,printk); EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig); @@ -95,7 +97,9 @@ EXPORT_SYMBOL(ret_from_exception); #endif +#ifdef CONFIG_VT EXPORT_SYMBOL(kd_mksound); +#endif /* platform dependent support */ EXPORT_SYMBOL(dump_thread); @@ -150,8 +154,6 @@ #ifndef CONFIG_NO_PGT_CACHE EXPORT_SYMBOL(quicklists); #endif -EXPORT_SYMBOL(__handle_bad_pmd); -EXPORT_SYMBOL(__handle_bad_pmd_kernel); /* string / mem functions */ EXPORT_SYMBOL_NOVERS(strcpy); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/arthur.c linux.ac/arch/arm/kernel/arthur.c --- linux.vanilla/arch/arm/kernel/arthur.c Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/arthur.c Sat Apr 14 01:15:10 2001 @@ -1,7 +1,9 @@ /* - * Arthur personality + * linux/arch/arm/kernel/arthur.c + * + * Copyright (C) 1998, 1999, 2000 Philip Blundell * - * Copyright (C) 1998, 1999, 2000 Philip Blundell + * Arthur personality */ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/bios32.c linux.ac/arch/arm/kernel/bios32.c --- linux.vanilla/arch/arm/kernel/bios32.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/kernel/bios32.c Sat Apr 14 01:15:10 2001 @@ -307,7 +307,8 @@ * parity line correctly. */ if (dev->vendor == PCI_VENDOR_ID_INTERG && - dev->device == PCI_DEVICE_ID_INTERG_2000) + (dev->device == PCI_DEVICE_ID_INTERG_2000 || + dev->device == PCI_DEVICE_ID_INTERG_2010)) busdata->features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); @@ -394,6 +395,7 @@ extern struct hw_pci netwinder_pci; extern struct hw_pci personal_server_pci; extern struct hw_pci ftv_pci; +extern struct hw_pci shark_pci; extern struct hw_pci integrator_pci; void __init pcibios_init(void) @@ -409,6 +411,12 @@ break; } #endif +#ifdef CONFIG_ARCH_SHARK + if (machine_is_shark()) { + hw_pci = &shark_pci; + break; + } +#endif #ifdef CONFIG_ARCH_CATS if (machine_is_cats()) { hw_pci = &cats_pci; @@ -427,8 +435,8 @@ break; } #endif -#ifdef CONFIG_ARCH_NEXUSPCI - if (machine_is_nexuspci()) { +#ifdef CONFIG_ARCH_FTVPCI + if (machine_is_ftvpci()) { hw_pci = &ftv_pci; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/debug-armv.S linux.ac/arch/arm/kernel/debug-armv.S --- linux.vanilla/arch/arm/kernel/debug-armv.S Mon Sep 18 23:15:24 2000 +++ linux.ac/arch/arm/kernel/debug-armv.S Sat Apr 14 01:16:23 2001 @@ -12,7 +12,6 @@ #include #include #include -#include .text @@ -67,8 +66,31 @@ tst \rd, #0x10 beq 1001b .endm + +#elif defined(CONFIG_ARCH_SHARK) + .macro addruart,rx + mov \rx, #0xe0000000 + orr \rx, \rx, #0x000003f8 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx + mov \rd, #0 +1001: add \rd, \rd, #1 + teq \rd, #0x10000 + bne 1001b + .endm + + .macro waituart,rd,rx + .endm #elif defined(CONFIG_FOOTBRIDGE) + +#include + #ifndef CONFIG_DEBUG_DC21285_PORT /* For NetWinder debugging */ .macro addruart,rx @@ -120,9 +142,12 @@ .macro waituart,rd,rx .endm #endif -#elif defined(CONFIG_ARCH_NEXUSPCI) +#elif defined(CONFIG_ARCH_FTVPCI) .macro addruart,rx - ldr \rx, =0xfff00000 + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + movne \rx, #0xe0000000 + moveq \rx, #0x10000000 .endm .macro senduart,rd,rx @@ -131,8 +156,8 @@ .macro busyuart,rd,rx 1001: ldr \rd, [\rx, #0x4] - tst \rd, #1 << 0 - bne 1001b + tst \rd, #1 << 2 + beq 1001b .endm .macro waituart,rd,rx @@ -164,6 +189,26 @@ bne 1001b .endm +#elif defined(CONFIG_ARCH_CLPS7500) + .macro addruart,rx + mov \rx, #0xe0000000 + orr \rx, \rx, #0x00010000 + orr \rx, \rx, #0x00000be0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x14] + tst \rd, #0x20 + beq 1001b + .endm + #elif defined(CONFIG_ARCH_L7200) .equ io_virt, IO_BASE @@ -174,12 +219,12 @@ tst \rx, #1 @ MMU enabled? moveq \rx, #io_phys @ physical base address movne \rx, #io_virt @ virtual address - add \rx, \rx, #0x00044000 @ Ser1 -@ add \rx, \rx, #0x00045000 @ Ser2 + add \rx, \rx, #0x00044000 @ UART1 +@ add \rx, \rx, #0x00045000 @ UART2 .endm .macro senduart,rd,rx - str \rd, [\rx, #0x0] @ UARTDR1 + str \rd, [\rx, #0x0] @ UARTDR .endm .macro waituart,rd,rx @@ -198,9 +243,6 @@ #include - .equ io_virt, 0xf0000000 + (0x16000000 >> 4) - .equ io_phys, 0x16000000 - .macro addruart,rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? @@ -223,6 +265,41 @@ 1001: ldr \rd, [\rx, #0x18] @ UARTFLG tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy bne 1001b + .endm + +#elif defined(CONFIG_ARCH_CLPS711X) + +#include + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #CLPS7111_PHYS_BASE + movne \rx, #CLPS7111_VIRT_BASE +#ifndef CONFIG_DEBUG_CLPS711X_UART2 + add \rx, \rx, #0x0000 @ UART1 +#else + add \rx, \rx, #0x1000 @ UART2 +#endif + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x0480] @ UARTDR + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x0140] @ SYSFLGx + tst \rd, #1 << 11 @ UBUSYx + bne 1001b + .endm + + .macro busyuart,rd,rx + tst \rx, #0x1000 @ UART2 does not have CTS here + bne 1002f +1001: ldr \rd, [\rx, #0x0140] @ SYSFLGx + tst \rd, #1 << 8 @ CTS + bne 1001b +1002: .endm #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/ecard.c linux.ac/arch/arm/kernel/ecard.c --- linux.vanilla/arch/arm/kernel/ecard.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/arm/kernel/ecard.c Sat Apr 14 01:16:23 2001 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #ifndef CONFIG_ARCH_RPC #define HAVE_EXPMASK @@ -53,7 +55,7 @@ enum req { req_readbytes, - req_reset + req_reset_all }; struct ecard_request { @@ -134,19 +136,14 @@ #define POD_INT_ADDR(x) ((volatile unsigned char *)\ ((BUS_ADDR((x)) - IO_BASE) + IO_START)) -static void -ecard_task_reset(struct ecard_request *req) +static inline void ecard_task_reset(void) { - if (req->ec == NULL) { - ecard_t *ec; + ecard_t *ec; - for (ec = cards; ec; ec = ec->next) - if (ec->loader) - ecard_loader_reset(POD_INT_ADDR(ec->podaddr), - ec->loader); - } else if (req->ec->loader) - ecard_loader_reset(POD_INT_ADDR(req->ec->podaddr), - req->ec->loader); + for (ec = cards; ec; ec = ec->next) + if (ec->loader) + ecard_loader_reset(POD_INT_ADDR(ec->podaddr), + ec->loader); } static void @@ -156,48 +153,47 @@ volatile unsigned char *base_addr = (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr); unsigned int len = req->length; + unsigned int off = req->address; if (req->ec->slot_no == 8) { /* - * The card maintains an index which - * increments the address into a 4096-byte - * page on each access. We need to keep + * The card maintains an index which increments the address + * into a 4096-byte page on each access. We need to keep * track of the counter. */ static unsigned int index; - unsigned int offset, page; - unsigned char byte = 0; /* keep gcc quiet */ - - offset = req->address & 4095; - page = req->address >> 12; + unsigned int page; - if (page > 256) + page = (off >> 12) * 4; + if (page > 256 * 4) return; - page *= 4; + off &= 4095; - if (offset == 0 || index > offset) { - /* - * We need to reset the index counter. - */ + /* + * If we are reading offset 0, or our current index is + * greater than the offset, reset the hardware index counter. + */ + if (off == 0 || index > off) { *base_addr = 0; index = 0; } - while (index <= offset) { + /* + * Increment the hardware index counter until we get to the + * required offset. The read bytes are discarded. + */ + while (index < off) { + unsigned char byte; byte = base_addr[page]; index += 1; } while (len--) { - *buf++ = byte; - if (len) { - byte = base_addr[page]; - index += 1; - } + *buf++ = base_addr[page]; + index += 1; } } else { - unsigned int off = req->address; if (!req->use_loader || !req->ec->loader) { off *= 4; @@ -220,50 +216,30 @@ } +static void ecard_do_request(struct ecard_request *req) +{ + switch (req->req) { + case req_readbytes: + ecard_task_readbytes(req); + break; + + case req_reset_all: + ecard_task_reset(); + break; + } +} + #ifdef CONFIG_CPU_32 static pid_t ecard_pid; static wait_queue_head_t ecard_wait; -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; -} +static DECLARE_MUTEX_LOCKED(ecard_done_sem); /* - * Set up the expansion card - * daemon's environment. + * Set up the expansion card daemon's page tables. */ -static void ecard_init_task(int force) +static void ecard_init_pgtables(struct mm_struct *mm) { /* We want to set up the page tables for the following mapping: * Virtual Physical @@ -279,29 +255,41 @@ pgd_t *src_pgd, *dst_pgd; unsigned int dst_addr = IO_START; - if (!force) - exec_mmap(); - - src_pgd = pgd_offset(current->mm, IO_BASE); - dst_pgd = pgd_offset(current->mm, dst_addr); + src_pgd = pgd_offset(mm, IO_BASE); + dst_pgd = pgd_offset(mm, dst_addr); while (dst_addr < IO_START + IO_SIZE) { *dst_pgd++ = *src_pgd++; dst_addr += PGDIR_SIZE; } - flush_tlb_range(current->mm, IO_START, IO_START + IO_SIZE); - dst_addr = EASI_START; - src_pgd = pgd_offset(current->mm, EASI_BASE); - dst_pgd = pgd_offset(current->mm, dst_addr); + src_pgd = pgd_offset(mm, EASI_BASE); + dst_pgd = pgd_offset(mm, dst_addr); while (dst_addr < EASI_START + EASI_SIZE) { *dst_pgd++ = *src_pgd++; dst_addr += PGDIR_SIZE; } - flush_tlb_range(current->mm, EASI_START, EASI_START + EASI_SIZE); + flush_tlb_range(mm, IO_START, IO_START + IO_SIZE); + flush_tlb_range(mm, EASI_START, EASI_START + EASI_SIZE); +} + +static int ecard_init_mm(void) +{ + struct mm_struct * mm = mm_alloc(); + struct mm_struct *active_mm = current->active_mm; + + if (!mm) + return -ENOMEM; + + current->mm = mm; + current->active_mm = mm; + activate_mm(active_mm, mm); + mmdrop(active_mm); + ecard_init_pgtables(mm); + return 0; } static int @@ -309,22 +297,23 @@ { struct task_struct *tsk = current; - tsk->session = 1; - tsk->pgrp = 1; - /* * We don't want /any/ signals, not even SIGKILL */ sigfillset(&tsk->blocked); sigemptyset(&tsk->pending.signal); recalc_sigpending(tsk); - strcpy(tsk->comm, "kecardd"); + daemonize(); /* - * Set up the environment + * Allocate a mm. We're not a lazy-TLB kernel task since we need + * to set page table entries where the user space would be. Note + * that this also creates the page tables. Failure is not an + * option here. */ - ecard_init_task(0); + if (ecard_init_mm()) + panic("kecardd: unable to alloc mm\n"); while (1) { struct ecard_request *req; @@ -338,16 +327,8 @@ } } while (req == NULL); - switch (req->req) { - case req_readbytes: - ecard_task_readbytes(req); - break; - - case req_reset: - ecard_task_reset(req); - break; - } - wake_up(&ecard_done); + ecard_do_request(req); + up(&ecard_done_sem); } } @@ -357,76 +338,90 @@ * FIXME: The test here is not sufficient to detect if the * kcardd is running. */ -static inline void +static void ecard_call(struct ecard_request *req) { /* - * If we're called from task 0, or from an - * interrupt (will be keyboard interrupt), - * we forcefully set up the memory map, and - * call the loader. We can't schedule, or - * sleep for this call. + * Make sure we have a context that is able to sleep. */ - if ((current == &init_task || in_interrupt()) && - req->req == req_reset && req->ec == NULL) { - ecard_init_task(1); - ecard_task_reset(req); - } else { - if (ecard_pid <= 0) - ecard_pid = kernel_thread(ecard_task, NULL, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (current == &init_task || in_interrupt()) + BUG(); - ecard_req = req; + if (ecard_pid <= 0) + ecard_pid = kernel_thread(ecard_task, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - wake_up(&ecard_wait); + ecard_req = req; + wake_up(&ecard_wait); - sleep_on(&ecard_done); - } + /* + * Now wait for kecardd to run. + */ + down(&ecard_done_sem); } #else /* * On 26-bit processors, we don't need the kcardd thread to access the * expansion card loaders. We do it directly. */ -static inline void -ecard_call(struct ecard_request *req) -{ - if (req->req == req_reset) - ecard_task_reset(req); - else - ecard_task_readbytes(req); -} +#define ecard_call(req) ecard_do_request(req) #endif /* ======================= Mid-level card control ===================== */ + /* - * This is called to reset the loaders for each expansion card on reboot. + * This function is responsible for resetting the expansion cards to a + * sensible state immediately prior to rebooting the system. This function + * has process state (keventd), so we can sleep. + * + * Possible "val" values here: + * SYS_RESTART - restarting system + * SYS_HALT - halting system + * SYS_POWER_OFF - powering down system * - * This is required to make sure that the card is in the correct state - * that RiscOS expects it to be. + * We ignore all calls, unless it is a SYS_RESTART call - power down/halts + * will be followed by a SYS_RESTART if ctrl-alt-del is pressed again. */ -void -ecard_reset(int slot) +static void ecard_reboot(struct notifier_block *me, unsigned long val, void *v) { struct ecard_request req; - req.req = req_reset; + if (val != SYS_RESTART) + return; - if (slot < 0) - req.ec = NULL; - else - req.ec = slot_to_ecard(slot); + /* + * Disable the expansion card interrupt + */ + disable_irq(IRQ_EXPANSIONCARD); + /* + * If we have any expansion card loader code which will handle + * the reset for us, call it now. + */ + req.req = req_reset_all; ecard_call(&req); + /* + * Disable the expansion card interrupt again, just to be sure. + */ + disable_irq(IRQ_EXPANSIONCARD); + + /* + * Finally, reset the expansion card interrupt mask to + * all enable (RISC OS doesn't set this) + */ #ifdef HAS_EXPMASK - if (have_expmask && slot < 0) { - have_expmask |= ~0; - EXPMASK_ENABLE = have_expmask; - } + have_expmask = ~0; + __raw_writeb(have_expmask, EXPMASK_ENABLE); #endif } +static struct notifier_block ecard_reboot_notifier = { + notifier_call: ecard_reboot, +}; + + + static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) { @@ -506,7 +501,7 @@ #ifdef HAS_EXPMASK if (irqnr < 4 && have_expmask) { have_expmask |= 1 << irqnr; - EXPMASK_ENABLE = have_expmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); } #endif } @@ -516,7 +511,7 @@ #ifdef HAS_EXPMASK if (irqnr < 4 && have_expmask) { have_expmask &= ~(1 << irqnr); - EXPMASK_ENABLE = have_expmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); } #endif } @@ -556,7 +551,7 @@ * * They are not meant to be called directly, but via enable/disable_irq. */ -void ecard_enableirq(unsigned int irqnr) +static void ecard_enableirq(unsigned int irqnr) { ecard_t *ec = slot_to_ecard(irqnr - 32); @@ -572,7 +567,7 @@ } } -void ecard_disableirq(unsigned int irqnr) +static void ecard_disableirq(unsigned int irqnr) { ecard_t *ec = slot_to_ecard(irqnr - 32); @@ -717,7 +712,7 @@ const unsigned int statusmask = 15; unsigned int status; - status = EXPMASK_STATUS & statusmask; + status = __raw_readb(EXPMASK_STATUS) & statusmask; if (status) { unsigned int slot; ecard_t *ec; @@ -739,18 +734,21 @@ * otherwise you will lose serial data at high speeds! */ oldexpmask = have_expmask; - EXPMASK_ENABLE = (have_expmask &= priority_masks[slot]); + have_expmask &= priority_masks[slot]; + __raw_writeb(have_expmask, EXPMASK_ENABLE); sti(); do_ecard_IRQ(ec->irq, regs); cli(); - EXPMASK_ENABLE = have_expmask = oldexpmask; - status = EXPMASK_STATUS & statusmask; + have_expmask = oldexpmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); + status = __raw_readb(EXPMASK_STATUS) & statusmask; if (status) goto again; } else { printk(KERN_WARNING "card%d: interrupt from unclaimed " "card???\n", slot); - EXPMASK_ENABLE = (have_expmask &= ~(1 << slot)); + have_expmask &= ~(1 << slot); + __raw_writeb(have_expmask, EXPMASK_ENABLE); } } else printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); @@ -762,10 +760,10 @@ ecard_t *ec; int found; - EXPMASK_ENABLE = 0x00; - EXPMASK_STATUS = 0xff; - found = ((EXPMASK_STATUS & 15) == 0); - EXPMASK_ENABLE = 0xff; + __raw_writeb(0x00, EXPMASK_ENABLE); + __raw_writeb(0xff, EXPMASK_STATUS); + found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; + __raw_writeb(0xff, EXPMASK_ENABLE); if (!found) return; @@ -781,7 +779,7 @@ for (ec = cards; ec; ec = ec->next) have_expmask |= 1 << ec->slot_no; - EXPMASK_ENABLE = have_expmask; + __raw_writeb(have_expmask, EXPMASK_ENABLE); } #else #define ecard_probeirqhw() @@ -830,7 +828,7 @@ } #ifdef IOMD_ECTCR - outb(ectcr, IOMD_ECTCR); + iomd_writeb(ectcr, IOMD_ECTCR); #endif return address; } @@ -910,9 +908,8 @@ int i, rc = -ENOMEM; ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); - if (!ec) - goto nodev; + goto nomem; memset(ec, 0, sizeof(ecard_t)); @@ -969,27 +966,31 @@ if (slot == 8) ec->irq = 11; #endif + /* + * hook the interrupt handlers + */ + if (ec->irq != 0 && ec->irq >= 32) { + irq_desc[ec->irq].mask_ack = ecard_disableirq; + irq_desc[ec->irq].mask = ecard_disableirq; + irq_desc[ec->irq].unmask = ecard_enableirq; + irq_desc[ec->irq].valid = 1; + } + #ifdef CONFIG_ARCH_RPC /* On RiscPC, only first two slots have DMA capability */ if (slot < 2) ec->dma = 2 + slot; #endif -#if 0 /* We don't support FIQs on expansion cards at the moment */ - ec->fiq = 96 + slot; -#endif - - rc = 0; for (ecp = &cards; *ecp; ecp = &(*ecp)->next); *ecp = ec; + slot_to_expcard[slot] = ec; + return 0; nodev: - if (rc && ec) - kfree(ec); - else - slot_to_expcard[slot] = ec; - + kfree(ec); +nomem: return rc; } @@ -1058,9 +1059,13 @@ { int slot; + /* + * Register our reboot notifier + */ + register_reboot_notifier(&ecard_reboot_notifier); + #ifdef CONFIG_CPU_32 init_waitqueue_head(&ecard_wait); - init_waitqueue_head(&ecard_done); #endif printk("Probing expansion cards\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/entry-armv.S linux.ac/arch/arm/kernel/entry-armv.S --- linux.vanilla/arch/arm/kernel/entry-armv.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/kernel/entry-armv.S Sat Apr 14 01:16:23 2001 @@ -89,41 +89,52 @@ .if ioc_base_low orr r4, r4, #ioc_base_low .endif - ldrb \irqstat, [r4, #0x24] @ get high priority first - adr \base, irq_prio_h + ldrb \irqstat, [r4, #IOMD_IRQREQB] @ get high priority first + ldr \base, =irq_prio_h teq \irqstat, #0 #ifdef IOMD_BASE - ldreqb \irqstat, [r4, #0x1f4] @ get dma - adreq \base, irq_prio_d + ldreqb \irqstat, [r4, #IOMD_DMAREQ] @ get dma + addeq \base, \base, #256 @ irq_prio_h table size teqeq \irqstat, #0 + bne 2406f #endif - ldreqb \irqstat, [r4, #0x14] @ get low priority - adreq \base, irq_prio_l - - teq \irqstat, #0 - ldrneb \irqnr, [\base, \irqstat] @ get IRQ number + ldreqb \irqstat, [r4, #IOMD_IRQREQA] @ get low priority + addeq \base, \base, #256 @ irq_prio_d table size + teqeq \irqstat, #0 +#ifdef IOMD_IRQREQC + ldreqb \irqstat, [r4, #IOMD_IRQREQC] + addeq \base, \base, #256 @ irq_prio_l table size + teqeq \irqstat, #0 +#endif +#ifdef IOMD_IRQREQD + ldreqb \irqstat, [r4, #IOMD_IRQREQD] + addeq \base, \base, #256 @ irq_prio_lc table size + teqeq \irqstat, #0 +#endif +2406: ldrneb \irqnr, [\base, \irqstat] @ get IRQ number .endm /* - * Interrupt table (incorporates priority) + * Interrupt table (incorporates priority). Please note that we + * rely on the order of these tables (see above code). */ .macro irq_prio_table -irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 #ifdef IOMD_BASE irq_prio_d: .byte 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 .byte 20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 @@ -142,26 +153,64 @@ .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 #endif -irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 +irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +#ifdef IOMD_IRQREQC +irq_prio_lc: .byte 24,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27 + .byte 28,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27 + .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 + .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 +#endif +#ifdef IOMD_IRQREQD +irq_prio_ld: .byte 40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 + .byte 44,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43 + .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 + .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 +#endif .endm #elif defined(CONFIG_ARCH_EBSA110) +#define IRQ_STAT 0xff000000 /* read */ + .macro disable_fiq .endm @@ -457,7 +506,9 @@ .macro irq_prio_table .endm -#elif defined(CONFIG_ARCH_P720T) +#elif defined(CONFIG_ARCH_CLPS711X) + +#include .macro disable_fiq .endm diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/entry-common.S linux.ac/arch/arm/kernel/entry-common.S --- linux.vanilla/arch/arm/kernel/entry-common.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/kernel/entry-common.S Sat Apr 14 01:16:23 2001 @@ -35,9 +35,7 @@ .align 5 fast_syscall_return: - str r0, [sp, #S_R0 + S_OFF] @ returned r0 -slow_syscall_return: - add sp, sp, #S_OFF + str r0, [sp, #S_R0+S_OFF]! @ returned r0 ret_from_sys_call: @ external entry get_softirq r0 get_current_task r5 @@ -52,6 +50,7 @@ bne ret_reschedule teq r1, #0 @ check for signals blne ret_signal + ret_from_all: restore_user_regs @ internal ret_signal: mov r1, sp @ internal @@ -132,7 +131,8 @@ str ip, [sp, #S_IP + S_OFF] @ trace exit [IP = 1] bl SYMBOL_NAME(syscall_trace) str tip, [sp, #S_IP + S_OFF] - b slow_syscall_return + add sp, sp, #S_OFF + b ret_from_sys_call 2: add r1, sp, #S_OFF tst scno, #0x00f00000 @ is it a Unix SWI? @@ -142,8 +142,9 @@ b SYMBOL_NAME(sys_ni_syscall) @ not private func 3: eor r0, scno, #OS_NUMBER <<20 @ Put OS number back - adrsvc al, lr, slow_syscall_return - b SYMBOL_NAME(deferred) + bl SYMBOL_NAME(deferred) + add sp, sp, #S_OFF + b ret_from_sys_call .align 5 .type __irq_stat, #object diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/fiq.c linux.ac/arch/arm/kernel/fiq.c --- linux.vanilla/arch/arm/kernel/fiq.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/kernel/fiq.c Sat Apr 14 01:16:23 2001 @@ -124,7 +124,7 @@ #ifdef CONFIG_CPU_26 "mov %0, pc bic %1, %0, #0x3 - orr %1, %1, #0x0c000001 + orr %1, %1, %3 teqp %1, #0 @ select FIQ mode mov r0, r0 ldmia %2, {r8 - r14} @@ -133,7 +133,7 @@ #endif #ifdef CONFIG_CPU_32 "mrs %0, cpsr - mov %1, #0xc1 + mov %1, %3 msr cpsr_c, %1 @ select FIQ mode mov r0, r0 ldmia %2, {r8 - r14} @@ -141,7 +141,7 @@ mov r0, r0" #endif : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8) + : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) /* These registers aren't modified by the above code in a way visible to the compiler, but we mark them as clobbers anyway so that GCC won't put any of the input or output operands in @@ -156,7 +156,7 @@ #ifdef CONFIG_CPU_26 "mov %0, pc bic %1, %0, #0x3 - orr %1, %1, #0x0c000001 + orr %1, %1, %3 teqp %1, #0 @ select FIQ mode mov r0, r0 stmia %2, {r8 - r14} @@ -165,7 +165,7 @@ #endif #ifdef CONFIG_CPU_32 "mrs %0, cpsr - mov %1, #0xc1 + mov %1, %3 msr cpsr_c, %1 @ select FIQ mode mov r0, r0 stmia %2, {r8 - r14} @@ -173,7 +173,7 @@ mov r0, r0" #endif : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8) + : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) /* These registers aren't modified by the above code in a way visible to the compiler, but we mark them as clobbers anyway so that GCC won't put any of the input or output operands in diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/head-armo.S linux.ac/arch/arm/kernel/head-armo.S --- linux.vanilla/arch/arm/kernel/head-armo.S Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/head-armo.S Sat Apr 14 01:16:23 2001 @@ -82,9 +82,9 @@ mov r1, #0 str r0, [r1, #4] ldr r0, arm2_id - swp r2, r2, [r1] @ check for swp (ARM2 can't) + swp r2, r2, [r1] @ check for swp (ARM2 cant) ldr r0, arm250_id - mrc 15, 0, r3, c0, c0 @ check for CP#15 (ARM250 can't) + mrc 15, 0, r3, c0, c0 @ check for CP#15 (ARM250 cant) mov r0, r3 continue: mov r2, #0xeb000000 @ Make undef vector loop sub r2, r2, #2 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/head-armv.S linux.ac/arch/arm/kernel/head-armv.S --- linux.vanilla/arch/arm/kernel/head-armv.S Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/head-armv.S Sat Apr 14 01:16:23 2001 @@ -26,7 +26,9 @@ * * Note that swapper_pg_dir is the virtual address of the page tables, and * pgtbl gives us a position-independent reference to these tables. We can - * do this because stext == TEXT_ADDR + * do this because stext == TEXTADDR + * + * swapper_pg_dir, pgtbl and krnladr are all closely related. */ #if (TEXTADDR & 0xffff) != 0x8000 #error TEXTADDR must start at 0xXXXX8000 @@ -35,24 +37,36 @@ .globl SYMBOL_NAME(swapper_pg_dir) .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 - .macro pgtbl, reg + .macro pgtbl, reg, rambase adr \reg, stext sub \reg, \reg, #0x4000 .endm +/* + * Since the page table is closely related to the kernel start address, we + * can convert the page table base address to the base address of the section + * containing both. + */ + .macro krnladr, rd, pgtable, rambase + bic \rd, \pgtable, #0x000ff000 + .endm + +/* + * Kernel startup entry point. + * + * The rules are: + * r0 - should be 0 + * r1 - unique architecture number + * MMU - off + * I-cache - on or off + * D-cache - off + * + * See linux/arch/arm/tools/mach-types for the complete list of numbers + * for r1. + */ .section ".text.init",#alloc,#execinstr .type stext, #function ENTRY(stext) -/* - * Entry point. The general rules are: - * should be called with r0 == 0 - * r1 contains the unique architecture number - * with MMU is off, I-cache may be on or off, D-cache should be off. - * See linux/arch/arm/kernel/arch.c and linux/include/asm-arm/system.h - * for the complete list of numbers for r1. If you require a new number, - * please follow the instructions given towards the end of - * linux/Documentation/arm/README. - */ mov r12, r0 /* * NOTE! Any code which is placed here should be done for one of @@ -115,7 +129,7 @@ #endif mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode - msr cpsr_c, r0 @ and all irqs diabled + msr cpsr_c, r0 @ and all irqs disabled bl __lookup_processor_type teq r10, #0 @ invalid processor? moveq r0, #'p' @ yes, error 'p' @@ -129,6 +143,7 @@ add pc, r10, #12 @ initialise processor @ (return control reg) + .type __switch_data, %object __switch_data: .long __mmap_switched .long SYMBOL_NAME(compat) .long SYMBOL_NAME(__bss_start) @@ -138,6 +153,7 @@ .long SYMBOL_NAME(cr_alignment) .long SYMBOL_NAME(init_task_union)+8192 + .type __ret, %function __ret: ldr lr, __switch_data mcr p15, 0, r0, c1, c0 mov r0, r0 @@ -190,31 +206,37 @@ * r8 = page table flags */ __create_page_tables: - pgtbl r4 + pgtbl r4, r5 @ page table address + + /* + * Clear the 16K level 1 swapper page table + */ mov r0, r4 mov r3, #0 - add r2, r0, #0x4000 @ 16k of page table -1: str r3, [r0], #4 @ Clear page table + add r2, r0, #0x4000 +1: str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 teq r0, r2 bne 1b + /* - * Create identity mapping for first MB of kernel. - * This is marked cacheable and bufferable. - * - * The identity mapping will be removed by paging_init() + * Create identity mapping for first MB of kernel to + * cater for the MMU enable. This identity mapping + * will be removed by paging_init() */ - add r3, r8, r5 @ mmuflags + start of RAM - add r0, r4, r5, lsr #18 - str r3, [r0] @ identity mapping + krnladr r2, r4, r5 @ start of kernel + add r3, r8, r2 @ flags + kernel base + str r3, [r4, r2, lsr #18] @ identity mapping + /* * Now setup the pagetables for our kernel direct * mapped region. We round TEXTADDR down to the * nearest megabyte boundary. */ - add r0, r4, #(TEXTADDR & 0xfff00000) >> 18 @ start of kernel + add r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel + add r0, r0, #(TEXTADDR & 0x00f00000) >> 18 str r3, [r0], #4 @ PAGE_OFFSET + 0MB add r3, r3, #1 << 20 str r3, [r0], #4 @ PAGE_OFFSET + 1MB @@ -223,13 +245,25 @@ add r3, r3, #1 << 20 str r3, [r0], #4 @ PAGE_OFFSET + 3MB + /* + * Ensure that the first section of RAM is present. + * we assume that: + * 1. the RAM is aligned to a 256MB boundary + * 2. the kernel is executing in the same 256MB chunk + * as the start of RAM. + */ + bic r0, r0, #0x0ff00000 >> 18 @ round down + and r2, r5, #0xf0000000 @ round down + add r3, r8, r2 @ flags + rambase + str r3, [r0] + bic r8, r8, #0x0c @ turn off cacheable @ and bufferable bits #ifdef CONFIG_DEBUG_LL /* * Map in IO space for serial debugging. * This allows debug messages to be output - * via a serial before paging_init. + * via a serial console before paging_init. */ add r0, r4, r7 rsb r3, r7, #0x4000 @ PTRS_PER_PGD*sizeof(long) @@ -241,12 +275,13 @@ add r3, r3, #1 << 20 teq r0, r2 bne 1b -#ifdef CONFIG_ARCH_NETWINDER +#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) /* * If we're using the NetWinder, we need to map in * the 16550-type serial port for the debug messages */ - teq r1, #5 + teq r1, #MACH_TYPE_NETWINDER + teqne r1, #MACH_TYPE_CATS bne 1f add r0, r4, #0x3fc0 mov r3, #0x7c000000 @@ -263,13 +298,12 @@ * Similar reasons here - for debug. This is * only for Acorn RiscPC architectures. */ - teq r5, #0 - addne r0, r4, #0x80 @ 02000000 - movne r3, #0x02000000 - orrne r3, r3, r8 - strne r3, [r0] - addne r0, r4, #0x3600 @ d8000000 - strne r3, [r0] + add r0, r4, #0x80 @ 02000000 + mov r3, #0x02000000 + orr r3, r3, r8 + str r3, [r0] + add r0, r4, #0x3600 @ d8000000 + str r3, [r0] #endif mov pc, lr diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/io.c linux.ac/arch/arm/kernel/io.c --- linux.vanilla/arch/arm/kernel/io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/kernel/io.c Sat Apr 14 01:16:23 2001 @@ -0,0 +1,49 @@ +#include +#include + +#include + +/* + * Copy data from IO memory space to "real" memory space. + * This needs to be optimized. + */ +void _memcpy_fromio(void * to, unsigned long from, size_t count) +{ + while (count) { + count--; + *(char *) to = readb(from); + ((char *) to)++; + from++; + } +} + +/* + * Copy data from "real" memory space to IO memory space. + * This needs to be optimized. + */ +void _memcpy_toio(unsigned long to, const void * from, size_t count) +{ + while (count) { + count--; + writeb(*(char *) from, to); + ((char *) from)++; + to++; + } +} + +/* + * "memset" on IO memory space. + * This needs to be optimized. + */ +void _memset_io(unsigned long dst, int c, size_t count) +{ + while (count) { + count--; + writeb(c, dst); + dst++; + } +} + +EXPORT_SYMBOL(_memcpy_fromio); +EXPORT_SYMBOL(_memcpy_toio); +EXPORT_SYMBOL(_memset_io); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/irq-arch.c linux.ac/arch/arm/kernel/irq-arch.c --- linux.vanilla/arch/arm/kernel/irq-arch.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/kernel/irq-arch.c Sat Apr 14 01:16:23 2001 @@ -0,0 +1,41 @@ +/* + * linux/arch/arm/kernel/irq-arch.c + * + * Copyright (C) 1995-2000 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * We contain the architecture-specific parts of interrupt handling + * in this file. In 2.5, it will move into the various arch/arm/mach-* + * directories. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* + * Get architecture specific interrupt handlers + * and interrupt initialisation. + */ +#include + +void __init genarch_init_irq(void) +{ + irq_init_irq(); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/irq.c linux.ac/arch/arm/kernel/irq.c --- linux.vanilla/arch/arm/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/arm/kernel/irq.c Sat Apr 14 01:16:23 2001 @@ -2,7 +2,7 @@ * linux/arch/arm/kernel/irq.c * * Copyright (C) 1992 Linus Torvalds - * Modifications for ARM processor Copyright (C) 1995-1998 Russell King. + * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -29,9 +29,11 @@ #include #include -#include -#include +#include #include +#include + +#include /* pick up fixup_irq definition */ /* * Maximum IRQ count. Currently, this is arbitary. However, it should @@ -42,41 +44,11 @@ */ #define MAX_IRQ_CNT 100000 -spinlock_t irq_controller_lock; - -int setup_arm_irq(int, struct irqaction *); -extern int get_fiq_list(char *); -extern void init_FIQ(void); - -struct irqdesc { - unsigned int nomask : 1; /* IRQ does not mask in IRQ */ - unsigned int enabled : 1; /* IRQ is currently enabled */ - unsigned int triggered: 1; /* IRQ has occurred */ - unsigned int probing : 1; /* IRQ in use for a probe */ - unsigned int probe_ok : 1; /* IRQ can be used for probe */ - unsigned int valid : 1; /* IRQ claimable */ - unsigned int noautoenable : 1; /* don't automatically enable IRQ */ - unsigned int unused :25; - void (*mask_ack)(unsigned int irq); /* Mask and acknowledge IRQ */ - void (*mask)(unsigned int irq); /* Mask IRQ */ - void (*unmask)(unsigned int irq); /* Unmask IRQ */ - struct irqaction *action; - /* - * IRQ lock detection - */ - unsigned int lck_cnt; - unsigned int lck_pc; - unsigned int lck_jif; -}; - -static struct irqdesc irq_desc[NR_IRQS]; static volatile unsigned long irq_err_count; +static spinlock_t irq_controller_lock; -/* - * Get architecture specific interrupt handlers - * and interrupt initialisation. - */ -#include +struct irqdesc irq_desc[NR_IRQS]; +void (*init_arch_irq)(void) __initdata = NULL; /* * Dummy mask/unmask handler @@ -85,6 +57,14 @@ { } +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. + * + * This function may be called - with care - from IRQ context. + */ void disable_irq(unsigned int irq) { unsigned long flags; @@ -95,6 +75,14 @@ spin_unlock_irqrestore(&irq_controller_lock, flags); } +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * + * This function may be called from IRQ context. + */ void enable_irq(unsigned int irq) { unsigned long flags; @@ -271,6 +259,7 @@ int shared = 0; struct irqaction *old, **p; unsigned long flags; + struct irqdesc *desc; /* * Some drivers like serial.c use request_irq() heavily, @@ -292,8 +281,9 @@ /* * The following block of code has to be executed atomically */ + desc = irq_desc + irq; spin_lock_irqsave(&irq_controller_lock, flags); - p = &irq_desc[irq].action; + p = &desc->action; if ((old = *p) != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { @@ -312,11 +302,11 @@ *p = new; if (!shared) { - irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0; - irq_desc[irq].probing = 0; - if (!irq_desc[irq].noautoenable) { - irq_desc[irq].enabled = 1; - irq_desc[irq].unmask(irq); + desc->nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0; + desc->probing = 0; + if (!desc->noautoenable) { + desc->enabled = 1; + desc->unmask(irq); } } @@ -324,13 +314,45 @@ return 0; } +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irq_flags, const char * devname, void *dev_id) { unsigned long retval; struct irqaction *action; - if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler) + if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler || + (irq_flags & SA_SHIRQ && !dev_id)) return -EINVAL; action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -351,6 +373,18 @@ return retval; } +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. + * + * This function may be called from interrupt context. + */ void free_irq(unsigned int irq, void *dev_id) { struct irqaction * action, **p; @@ -486,6 +520,6 @@ irq_desc[irq].unmask = dummy_mask_unmask_irq; } - irq_init_irq(); + init_arch_irq(); init_dma(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/leds-ebsa110.c linux.ac/arch/arm/kernel/leds-ebsa110.c --- linux.vanilla/arch/arm/kernel/leds-ebsa110.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/kernel/leds-ebsa110.c Thu Jan 1 01:00:00 1970 @@ -1,51 +0,0 @@ -/* - * linux/arch/arm/kernel/leds-ebsa110.c - * - * Copyright (C) 1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * EBSA-110 LED control routines. We use the led as follows: - * - * - Red - toggles state every 50 timer interrupts - */ -#include -#include -#include - -#include -#include -#include -#include - -static spinlock_t leds_lock; - -static void ebsa110_leds_event(led_event_t ledevt) -{ - unsigned long flags; - - spin_lock_irqsave(&leds_lock, flags); - - switch(ledevt) { - case led_timer: - *(volatile unsigned char *)0xf2400000 ^= 128; - break; - - default: - break; - } - - spin_unlock_irqrestore(&leds_lock, flags); -} - -static int __init leds_init(void) -{ - if (machine_is_ebsa110()) - leds_event = ebsa110_leds_event; - - return 0; -} - -__initcall(leds_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/oldlatches.c linux.ac/arch/arm/kernel/oldlatches.c --- linux.vanilla/arch/arm/kernel/oldlatches.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/oldlatches.c Sat Apr 14 01:16:23 2001 @@ -59,7 +59,7 @@ } } -initcall(oldlatch_init); +__initcall(oldlatch_init); EXPORT_SYMBOL(oldlatch_aupdate); EXPORT_SYMBOL(oldlatch_bupdate); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/semaphore.c linux.ac/arch/arm/kernel/semaphore.c --- linux.vanilla/arch/arm/kernel/semaphore.c Sun Nov 12 03:02:40 2000 +++ linux.ac/arch/arm/kernel/semaphore.c Wed Apr 18 13:47:22 2001 @@ -165,321 +165,3 @@ spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } - -struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->read_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->write_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* if the lock is currently unbiased, awaken the sleepers - * FIXME: this wakes up the readers early in a bit of a - * stampede -> bad! - */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); - - return sem; -} - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* this takes care of granting the lock */ - __up_op_read(sem, __rwsem_wake); - - add_wait_queue(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -/* Wait for the lock to become unbiased. Since we're - * a writer, we'll make ourselves exclusive. - */ -struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* this takes care of granting the lock */ - __up_op_write(sem, __rwsem_wake); - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to acquire or bias the lock */ - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -/* Called when someone has done an up that transitioned from - * negative to non-negative, meaning that the lock has been - * granted to whomever owned the bias. - */ -struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) -{ - if (xchg(&sem->read_bias_granted, 1)) - BUG(); - wake_up(&sem->wait); - return sem; -} - -struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) -{ - if (xchg(&sem->write_bias_granted, 1)) - BUG(); - wake_up(&sem->write_bias_wait); - return sem; -} - -/* - * 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. - * - * ip contains the semaphore pointer on entry. Save the C-clobbered - * registers (r0 to r3 and lr), but not ip, as we use it as a return - * value in some cases.. - */ -#ifdef CONFIG_CPU_26 -asm(" .section .text.lock, \"ax\" - .align 5 - .globl __down_failed -__down_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __down_interruptible_failed -__down_interruptible_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_interruptible - mov ip, r0 - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __down_trylock_failed -__down_trylock_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_trylock - mov ip, r0 - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __up_wakeup -__up_wakeup: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __up - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __down_read_failed -__down_read_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_read_failed_biased - ldmfd sp!, {r0 - r3, pc}^ -2: bl down_read_failed - mov r1, pc - orr r2, r1, # - teqp r2, #0 - - ldr r3, [r0] - subs r3, r3, #1 - str r3, [r0] - ldmplfd sp!, {r0 - r3, pc}^ - orrcs r1, r1, #0x20000000 @ Set carry - teqp r1, #0 - bcc 2b - b 1b - - .align 5 - .globl __down_write_failed -__down_write_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_write_failed_biased - ldmfd sp!, {r0 - r3, pc}^ -2: bl down_write_failed - mov r1, pc - orr r2, r1, #128 - teqp r2, #0 - - ldr r3, [r0] - subs r3, r3, #"RW_LOCK_BIAS_STR" - str r3, [r0] - ldmeqfd sp!, {r0 - r3, pc}^ - orrcs r1, r1, #0x20000000 @ Set carry - teqp r1, #0 - bcc 2b - b 1b - - .align 5 - .globl __rwsem_wake -__rwsem_wake: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - beq 1f - bl rwsem_wake_readers - ldmfd sp!, {r0 - r3, pc}^ -1: bl rwsem_wake_writer - ldmfd sp!, {r0 - r3, pc}^ - - .previous - "); - -#else -/* 32 bit version */ -asm(" .section .text.lock, \"ax\" - .align 5 - .globl __down_failed -__down_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __down_interruptible_failed -__down_interruptible_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_interruptible - mov ip, r0 - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __down_trylock_failed -__down_trylock_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_trylock - mov ip, r0 - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __up_wakeup -__up_wakeup: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __up - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __down_read_failed -__down_read_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_read_failed_biased - ldmfd sp!, {r0 - r3, pc} -2: bl down_read_failed - mrs r1, cpsr - orr r2, r1, #128 - msr cpsr_c, r2 - ldr r3, [r0] - subs r3, r3, #1 - str r3, [r0] - msr cpsr_c, r1 - ldmplfd sp!, {r0 - r3, pc} - bcc 2b - b 1b - - .align 5 - .globl __down_write_failed -__down_write_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_write_failed_biased - ldmfd sp!, {r0 - r3, pc} -2: bl down_write_failed - mrs r1, cpsr - orr r2, r1, #128 - msr cpsr_c, r2 - ldr r3, [r0] - subs r3, r3, #"RW_LOCK_BIAS_STR" - str r3, [r0] - msr cpsr_c, r1 - ldmeqfd sp!, {r0 - r3, pc} - bcc 2b - b 1b - - .align 5 - .globl __rwsem_wake -__rwsem_wake: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - beq 1f - bl rwsem_wake_readers - ldmfd sp!, {r0 - r3, pc} -1: bl rwsem_wake_writer - ldmfd sp!, {r0 - r3, pc} - - .previous - "); - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/setup.c linux.ac/arch/arm/kernel/setup.c --- linux.vanilla/arch/arm/kernel/setup.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/kernel/setup.c Sat Apr 14 01:16:23 2001 @@ -26,6 +26,7 @@ #include #include +#include #ifndef MEM_SIZE #define MEM_SIZE (16*1024*1024) @@ -35,10 +36,21 @@ #define CONFIG_CMDLINE "" #endif +#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) +char fpe_type[8]; + +static int __init fpe_setup(char *line) +{ + memcpy(fpe_type, line, 8); + return 1; +} + +__setup("fpe=", fpe_setup); +#endif + extern void paging_init(struct meminfo *, struct machine_desc *desc); extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); -extern void disable_hlt(void); extern unsigned long memparse(char *ptr, char **retptr); extern int root_mountflags; extern int _stext, _text, _etext, _edata, _end; @@ -71,9 +83,10 @@ char elf_platform[ELF_PLATFORM_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; +static struct meminfo meminfo __initdata = { 0, }; static struct proc_info_item proc_info; static const char *machine_name; -static char command_line[COMMAND_LINE_SIZE] = { 0, }; +static char command_line[COMMAND_LINE_SIZE]; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; @@ -306,71 +319,222 @@ request_resource(&ioport_resource, &lp2); } +/* + * Tag parsing. + * + * This is the new way of passing data to the kernel at boot time. Rather + * than passing a fixed inflexible structure to the kernel, we pass a list + * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE + * tag for the list to be recognised (to distinguish the tagged list from + * a param_struct). The list is terminated with a zero-length tag (this tag + * is not parsed in any way). + */ +static int __init parse_tag_core(const struct tag *tag) +{ + if ((tag->u.core.flags & 1) == 0) + root_mountflags &= ~MS_RDONLY; + ROOT_DEV = to_kdev_t(tag->u.core.rootdev); + return 0; +} + +static int __init parse_tag_mem32(const struct tag *tag) +{ + if (meminfo.nr_banks >= NR_BANKS) { + printk(KERN_WARNING + "Ignoring memory bank 0x%08x size %dKB\n", + tag->u.mem.start, tag->u.mem.size / 1024); + return -EINVAL; + } + meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start; + meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size; + meminfo.bank[meminfo.nr_banks].node = 0; + meminfo.nr_banks += 1; + + return 0; +} + +static int __init parse_tag_videotext(const struct tag *tag) +{ + screen_info.orig_x = tag->u.videotext.x; + screen_info.orig_y = tag->u.videotext.y; + screen_info.orig_video_page = tag->u.videotext.video_page; + screen_info.orig_video_mode = tag->u.videotext.video_mode; + screen_info.orig_video_cols = tag->u.videotext.video_cols; + screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; + screen_info.orig_video_lines = tag->u.videotext.video_lines; + screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; + screen_info.orig_video_points = tag->u.videotext.video_points; + return 0; +} + +static int __init parse_tag_ramdisk(const struct tag *tag) +{ + setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, + (tag->u.ramdisk.flags & 2) == 0, + tag->u.ramdisk.start, tag->u.ramdisk.size); + return 0; +} + +static int __init parse_tag_initrd(const struct tag *tag) +{ + setup_initrd(tag->u.initrd.start, tag->u.initrd.size); + return 0; +} + +static int __init parse_tag_serialnr(const struct tag *tag) +{ + system_serial_low = tag->u.serialnr.low; + system_serial_high = tag->u.serialnr.high; + return 0; +} + +static int __init parse_tag_revision(const struct tag *tag) +{ + system_rev = tag->u.revision.rev; + return 0; +} + +static int __init parse_tag_cmdline(const struct tag *tag) +{ + strncpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); + default_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + return 0; +} + +/* + * This is the core tag table; these are the tags + * that we recognise for any machine type. + */ +static const struct tagtable core_tagtable[] __init = { + { ATAG_CORE, parse_tag_core }, + { ATAG_MEM, parse_tag_mem32 }, + { ATAG_VIDEOTEXT, parse_tag_videotext }, + { ATAG_RAMDISK, parse_tag_ramdisk }, + { ATAG_INITRD, parse_tag_initrd }, + { ATAG_SERIAL, parse_tag_serialnr }, + { ATAG_REVISION, parse_tag_revision }, + { ATAG_CMDLINE, parse_tag_cmdline } +}; + +/* + * Scan one tag table for this tag, and call its parse function. + */ +static int __init +parse_tag(const struct tagtable *tbl, int size, const struct tag *t) +{ + int i; + + for (i = 0; i < size; i++, tbl++) + if (t->hdr.tag == tbl->tag) { + tbl->parse(t); + break; + } + + return i < size; +} + +/* + * Parse all tags in the list, checking both the global and architecture + * specific tag tables. + */ +static void __init +parse_tags(const struct tagtable *tbl, int size, const struct tag *t) +{ + /* + * The tag list is terminated with a zero-sized tag. Size is + * defined to be in units of 32-bit quantities. + */ + for (; t->hdr.size; t = (struct tag *)((u32 *)t + t->hdr.size)) { + if (parse_tag(core_tagtable, ARRAY_SIZE(core_tagtable), t)) + continue; + + if (tbl && parse_tag(tbl, size, t)) + continue; + + printk(KERN_WARNING + "Ignoring unrecognised tag 0x%08x\n", t->hdr.tag); + } +} + +static void __init parse_params(struct param_struct *params) +{ + if (params->u1.s.page_size != PAGE_SIZE) { + printk(KERN_WARNING "Warning: bad configuration page, " + "trying to continue\n"); + return; + } + + ROOT_DEV = to_kdev_t(params->u1.s.rootdev); + system_rev = params->u1.s.system_rev; + system_serial_low = params->u1.s.system_serial_low; + system_serial_high = params->u1.s.system_serial_high; + + if (params->u1.s.mem_fclk_21285 > 0) + mem_fclk_21285 = params->u1.s.mem_fclk_21285; + + setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0, + (params->u1.s.flags & FLAG_RDPROMPT) == 0, + params->u1.s.rd_start, + params->u1.s.ramdisk_size); + + setup_initrd(params->u1.s.initrd_start, + params->u1.s.initrd_size); + + if (!(params->u1.s.flags & FLAG_READONLY)) + root_mountflags &= ~MS_RDONLY; + + strncpy(default_command_line, params->commandline, COMMAND_LINE_SIZE); + default_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + + if (meminfo.nr_banks == 0) { + meminfo.nr_banks = 1; + meminfo.bank[0].start = PHYS_OFFSET; + meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; + } +} + void __init setup_arch(char **cmdline_p) { struct param_struct *params = NULL; struct machine_desc *mdesc; - struct meminfo meminfo; char *from = default_command_line; - memset(&meminfo, 0, sizeof(meminfo)); - - setup_processor(); - ROOT_DEV = MKDEV(0, 255); + setup_processor(); mdesc = setup_architecture(machine_arch_type); machine_name = mdesc->name; - if (mdesc->broken_hlt) - disable_hlt(); - if (mdesc->soft_reboot) reboot_setup("s"); if (mdesc->param_offset) params = phys_to_virt(mdesc->param_offset); + /* + * Do the machine-specific fixups before we parse the + * parameters or tags. + */ if (mdesc->fixup) mdesc->fixup(mdesc, params, &from, &meminfo); - if (params && params->u1.s.page_size != PAGE_SIZE) { - printk(KERN_WARNING "Warning: bad configuration page, " - "trying to continue\n"); - params = NULL; - } - if (params) { - ROOT_DEV = to_kdev_t(params->u1.s.rootdev); - system_rev = params->u1.s.system_rev; - system_serial_low = params->u1.s.system_serial_low; - system_serial_high = params->u1.s.system_serial_high; - - if (params->u1.s.mem_fclk_21285 > 0) - mem_fclk_21285 = params->u1.s.mem_fclk_21285; - - setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0, - (params->u1.s.flags & FLAG_RDPROMPT) == 0, - params->u1.s.rd_start, - params->u1.s.ramdisk_size); - - setup_initrd(params->u1.s.initrd_start, - params->u1.s.initrd_size); - - if (!(params->u1.s.flags & FLAG_READONLY)) - root_mountflags &= ~MS_RDONLY; + struct tag *tag = (struct tag *)params; - from = params->commandline; + /* + * Is the first tag the CORE tag? This differentiates + * between the tag list and the parameter table. + */ + if (tag->hdr.tag == ATAG_CORE) + parse_tags(mdesc->tagtable, mdesc->tagsize, tag); + else + parse_params(params); } if (meminfo.nr_banks == 0) { meminfo.nr_banks = 1; meminfo.bank[0].start = PHYS_OFFSET; - meminfo.bank[0].node = 0; - if (params) - meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; - else - meminfo.bank[0].size = MEM_SIZE; + meminfo.bank[0].size = MEM_SIZE; } init_mm.start_code = (unsigned long) &_text; @@ -385,6 +549,11 @@ paging_init(&meminfo, mdesc); request_standard_resources(&meminfo, mdesc); + /* + * Set up various architecture-specific pointers + */ + init_arch_irq = mdesc->init_irq; + #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -403,8 +572,8 @@ (int)processor_id & 15, elf_platform); p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n", - (loops_per_sec+2500) / 500000, - ((loops_per_sec+2500) / 5000) % 100); + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); p += sprintf(p, "Hardware\t: %s\n", machine_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/time-acorn.c linux.ac/arch/arm/kernel/time-acorn.c --- linux.vanilla/arch/arm/kernel/time-acorn.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/kernel/time-acorn.c Sat Apr 14 01:16:23 2001 @@ -28,17 +28,17 @@ unsigned int count1, count2, status1, status2; unsigned long offset = 0; - status1 = inb(IOC_IRQREQA); + status1 = ioc_readb(IOC_IRQREQA); barrier (); - outb (0, IOC_T0LATCH); + ioc_writeb (0, IOC_T0LATCH); barrier (); - count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8); + count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); barrier (); - status2 = inb(IOC_IRQREQA); + status2 = ioc_readb(IOC_IRQREQA); barrier (); - outb (0, IOC_T0LATCH); + ioc_writeb (0, IOC_T0LATCH); barrier (); - count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8); + count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); if (count2 < count1) { /* @@ -67,9 +67,9 @@ void __init ioctime_init(void) { - outb(LATCH & 255, IOC_T0LTCHL); - outb(LATCH >> 8, IOC_T0LTCHH); - outb(0, IOC_T0GO); + ioc_writeb(LATCH & 255, IOC_T0LTCHL); + ioc_writeb(LATCH >> 8, IOC_T0LTCHH); + ioc_writeb(0, IOC_T0GO); gettimeoffset = ioctime_gettimeoffset; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/via82c505.c linux.ac/arch/arm/kernel/via82c505.c --- linux.vanilla/arch/arm/kernel/via82c505.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/kernel/via82c505.c Sat Apr 14 01:16:23 2001 @@ -106,8 +106,8 @@ break; case PCI_BASE_ADDRESS_0: if (size_wanted) { - /* 0x00900000 bytes long */ - *value = 0xff700000; + /* 0x00900000 bytes long (0xff700000) */ + *value = 0xff000000; size_wanted = 0; } else { *value = FB_START; @@ -117,7 +117,7 @@ *value = 6; break; default: - *value=0; + *value = 0; } return PCIBIOS_SUCCESSFUL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/Makefile linux.ac/arch/arm/lib/Makefile --- linux.vanilla/arch/arm/lib/Makefile Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/lib/Makefile Sat Apr 14 01:16:23 2001 @@ -17,8 +17,6 @@ obj-m := obj-n := -export-objs := io.o - obj-arc := ecard.o io-acorn.o floppydma.o obj-rpc := ecard.o io-acorn.o floppydma.o obj-clps7500 := io-acorn.o @@ -47,10 +45,6 @@ ifeq ($(PROCESSOR),armo) obj-y += uaccess-armo.o -endif - -ifneq ($(MACHINE),ebsa110) - obj-y += io.o endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/backtrace.S linux.ac/arch/arm/lib/backtrace.S --- linux.vanilla/arch/arm/lib/backtrace.S Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/lib/backtrace.S Sat Apr 14 01:16:23 2001 @@ -26,7 +26,7 @@ ENTRY(c_backtrace) -#ifndef CONFIG_FRAME_POINTER +#ifdef CONFIG_NO_FRAME_POINTER mov pc, lr #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/delay.S linux.ac/arch/arm/lib/delay.S --- linux.vanilla/arch/arm/lib/delay.S Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/lib/delay.S Sat Apr 14 01:16:23 2001 @@ -11,19 +11,26 @@ #include .text -LC0: .word SYMBOL_NAME(loops_per_sec) +LC0: .word SYMBOL_NAME(loops_per_jiffy) +/* + * 0 <= r0 <= 2000 + */ ENTRY(udelay) - mov r2, #0x1000 - orr r2, r2, #0x00c6 + mov r2, #0x6800 + orr r2, r2, #0x00db mul r1, r0, r2 ldr r2, LC0 ldr r2, [r2] mov r1, r1, lsr #11 mov r2, r2, lsr #11 mul r0, r1, r2 - movs r0, r0, lsr #10 + movs r0, r0, lsr #6 RETINSTR(moveq,pc,lr) + +/* + * loops = (r0 * 0x10c6 * 100 * loops_per_jiffie) / 2^32 + */ @ Delay routine ENTRY(__delay) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/io-shark.c linux.ac/arch/arm/lib/io-shark.c --- linux.vanilla/arch/arm/lib/io-shark.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/lib/io-shark.c Sat Apr 14 01:16:23 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/lib/io-shark.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz * * derived from: * linux/arch/arm/lib/io-ebsa.S diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/io.c linux.ac/arch/arm/lib/io.c --- linux.vanilla/arch/arm/lib/io.c Mon Feb 7 01:45:25 2000 +++ linux.ac/arch/arm/lib/io.c Thu Jan 1 01:00:00 1970 @@ -1,50 +0,0 @@ -#include -#include - -#include - -/* - * Copy data from IO memory space to "real" memory space. - * This needs to be optimized. - */ -void _memcpy_fromio(void * to, unsigned long from, size_t count) -{ - while (count) { - count--; - *(char *) to = readb(from); - ((char *) to)++; - from++; - } -} - -/* - * Copy data from "real" memory space to IO memory space. - * This needs to be optimized. - */ -void _memcpy_toio(unsigned long to, const void * from, size_t count) -{ - while (count) { - count--; - writeb(*(char *) from, to); - ((char *) from)++; - to++; - } -} - -/* - * "memset" on IO memory space. - * This needs to be optimized. - */ -void _memset_io(unsigned long dst, int c, size_t count) -{ - while (count) { - count--; - writeb(c, dst); - dst++; - } -} - -EXPORT_SYMBOL(_memcpy_fromio); -EXPORT_SYMBOL(_memcpy_toio); -EXPORT_SYMBOL(_memset_io); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/Makefile linux.ac/arch/arm/mach-ebsa110/Makefile --- linux.vanilla/arch/arm/mach-ebsa110/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/Makefile Sat Apr 14 01:16:46 2001 @@ -0,0 +1,23 @@ +# +# Makefile for the linux 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). + +USE_STANDARD_AS_RULE := true + +O_TARGET := ebsa110.o + +# Object file lists. + +obj-y := arch.o io.o irq.o mm.o time.o +obj-m := +obj-n := +obj- := + +export-objs := io.o + +obj-$(CONFIG_LEDS) += leds.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/arch.c linux.ac/arch/arm/mach-ebsa110/arch.c --- linux.vanilla/arch/arm/mach-ebsa110/arch.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/arch.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,33 @@ +/* + * linux/arch/arm/mach-ebsa110/arch.c + * + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +extern void ebsa110_map_io(void); +extern void ebsa110_init_irq(void); + +MACHINE_START(EBSA110, "EBSA110") + MAINTAINER("Russell King") + BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) + BOOT_PARAMS(0x00000400) + DISABLE_PARPORT(0) + DISABLE_PARPORT(2) + SOFT_REBOOT + MAPIO(ebsa110_map_io) + INITIRQ(ebsa110_init_irq) +MACHINE_END diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/io.c linux.ac/arch/arm/mach-ebsa110/io.c --- linux.vanilla/arch/arm/mach-ebsa110/io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/io.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,320 @@ +/* + * linux/arch/arm/mach-ebsa110/isamem.c + * + * Copyright (C) 2001 Russell King + * + * Perform "ISA" memory and IO accesses. The EBSA110 has some "peculiarities" + * in the way it handles accesses to odd IO ports on 16-bit devices. These + * devices have their D0-D15 lines connected to the processors D0-D15 lines. + * Since they expect all byte IO operations to be performed on D0-D7, and the + * StrongARM expects to transfer the byte to these odd addresses on D8-D15, + * we must use a trick to get the required behaviour. + * + * The trick employed here is to use long word stores to odd address -1. The + * glue logic picks this up as a "trick" access, and asserts the LSB of the + * peripherals address bus, thereby accessing the odd IO port. Meanwhile, the + * StrongARM transfers its data on D0-D7 as expected. + * + * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller + * wiring was screwed in such a way that it had limited memory space access. + * Luckily, the work-around for this is not too horrible. See + * __isamem_convert_addr for the details. + */ +#include +#include +#include +#include + +#include +#include + +static u32 __isamem_convert_addr(void *addr) +{ + u32 ret, a = (u32) addr; + + /* + * The PCMCIA controller is wired up as follows: + * +---------+---------+---------+---------+---------+---------+ + * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1 | | | + * | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 | + * +---------+---------+---------+---------+---------+---------+ + * CPU | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1 | | | + * | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x | + * +---------+---------+---------+---------+---------+---------+ + * + * This means that we can access PCMCIA regions as follows: + * 0x*10000 -> 0x*1ffff + * 0x*70000 -> 0x*7ffff + * 0x*90000 -> 0x*9ffff + * 0x*f0000 -> 0x*fffff + */ + ret = (a & 0xf803fe) << 1; + ret |= (a & 0x03fc00) << 2; + + ret += 0xe8000000; + + if ((a & 0x20000) == (a & 0x40000) >> 1) + return ret; + + BUG(); + return 0; +} + +/* + * read[bwl] and write[bwl] + */ +u8 __readb(void *addr) +{ + u32 ret, a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + ret = __arch_getl(a); + else + ret = __arch_getb(a); + return ret; +} + +u16 __readw(void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + BUG(); + + return __arch_getw(a); +} + +u32 __readl(void *addr) +{ + u32 ret, a = __isamem_convert_addr(addr); + + if ((int)addr & 3) + BUG(); + + ret = __arch_getw(a); + ret |= __arch_getw(a + 4) << 16; + return ret; +} + +EXPORT_SYMBOL(__readb); +EXPORT_SYMBOL(__readw); +EXPORT_SYMBOL(__readl); + +void __writeb(u8 val, void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + __arch_putl(val, a); + else + __arch_putb(val, a); +} + +void __writew(u16 val, void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 1) + BUG(); + + __arch_putw(val, a); +} + +void __writel(u32 val, void *addr) +{ + u32 a = __isamem_convert_addr(addr); + + if ((int)addr & 3) + BUG(); + + __arch_putw(val, a); + __arch_putw(val >> 16, a + 4); +} + +EXPORT_SYMBOL(__writeb); +EXPORT_SYMBOL(__writew); +EXPORT_SYMBOL(__writel); + +#define SUPERIO_PORT(p) \ + (((p) >> 3) == (0x3f8 >> 3) || \ + ((p) >> 3) == (0x2f8 >> 3) || \ + ((p) >> 3) == (0x378 >> 3)) + +u8 __inb(int port) +{ + u32 ret; + + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + ret = __arch_getb(ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + ((port & ~1) << 1); + + /* + * Shame nothing else does + */ + if (port & 1) + ret = __arch_getl(a); + else + ret = __arch_getb(a); + } + return ret; +} + +u16 __inw(int port) +{ + u32 ret; + + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + ret = __arch_getw(ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + ((port & ~1) << 1); + + /* + * Shame nothing else does + */ + if (port & 1) + BUG(); + + ret = __arch_getw(a); + } + return ret; +} + +u32 __inl(int port) +{ + BUG(); +} + +EXPORT_SYMBOL(__inb); +EXPORT_SYMBOL(__inw); +EXPORT_SYMBOL(__inl); + +void __outb(u8 val, int port) +{ + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + __arch_putb(val, ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + ((port & ~1) << 1); + + /* + * Shame nothing else does + */ + if (port & 1) + __arch_putl(val, a); + else + __arch_putb(val, a); + } +} + +void __outw(u16 val, int port) +{ + u32 off; + + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + + } + __arch_putw(val, ISAIO_BASE + off); +} + +void __outl(u32 val, int port) +{ + BUG(); +} + +EXPORT_SYMBOL(__outb); +EXPORT_SYMBOL(__outw); +EXPORT_SYMBOL(__outl); + +extern void __arch_writesb(unsigned long virt, const void *from, int len); +extern void __arch_writesw(unsigned long virt, const void *from, int len); +extern void __arch_writesl(unsigned long virt, const void *from, int len); +extern void __arch_readsb(unsigned long virt, void *from, int len); +extern void __arch_readsw(unsigned long virt, void *from, int len); +extern void __arch_readsl(unsigned long virt, void *from, int len); + +void outsb(unsigned int port, const void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_writesb(ISAIO_BASE + off, from, len); +} + +void insb(unsigned int port, void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_readsb(ISAIO_BASE + off, from, len); +} + +void outsw(unsigned int port, const void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_writesw(ISAIO_BASE + off, from, len); +} + +void insw(unsigned int port, void *from, int len) +{ + u32 off; + + if (SUPERIO_PORT(port)) + off = port << 2; + else { + off = (port & ~1) << 1; + if (port & 1) + BUG(); + } + + __arch_readsw(ISAIO_BASE + off, from, len); +} + +void outsl(unsigned int port, const void *from, int len) +{ + panic("outsl not supported on this architecture"); +} + +void insl(unsigned int port, void *from, int len) +{ + panic("insl not supported on this architecture"); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/irq.c linux.ac/arch/arm/mach-ebsa110/irq.c --- linux.vanilla/arch/arm/mach-ebsa110/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/irq.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/mach-ebsa110/irq.c + * + * Copyright (C) 1996-1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 22-08-1998 RMK Restructured IRQ routines + */ +#include + +#include +#include +#include +#include +#include + +#include "hardware.h" + +static void ebsa110_mask_irq(unsigned int irq) +{ + __raw_writeb(1 << irq, IRQ_MCLR); +} + +static void ebsa110_unmask_irq(unsigned int irq) +{ + __raw_writeb(1 << irq, IRQ_MSET); +} + +void __init ebsa110_init_irq(void) +{ + unsigned long flags; + int irq; + + save_flags_cli (flags); + __raw_writeb(0xff, IRQ_MCLR); + __raw_writeb(0x55, IRQ_MSET); + __raw_writeb(0x00, IRQ_MSET); + if (__raw_readb(IRQ_MASK) != 0x55) + while (1); + __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */ + restore_flags (flags); + + for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = ebsa110_mask_irq; + irq_desc[irq].mask = ebsa110_mask_irq; + irq_desc[irq].unmask = ebsa110_unmask_irq; + } +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/leds.c linux.ac/arch/arm/mach-ebsa110/leds.c --- linux.vanilla/arch/arm/mach-ebsa110/leds.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/leds.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,51 @@ +/* + * linux/arch/arm/mach-ebsa110/leds.c + * + * Copyright (C) 1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * EBSA-110 LED control routines. We use the led as follows: + * + * - Red - toggles state every 50 timer interrupts + */ +#include +#include +#include + +#include +#include +#include +#include + +static spinlock_t leds_lock; + +static void ebsa110_leds_event(led_event_t ledevt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch(ledevt) { + case led_timer: + *(volatile unsigned char *)SOFT_BASE ^= 128; + break; + + default: + break; + } + + spin_unlock_irqrestore(&leds_lock, flags); +} + +static int __init leds_init(void) +{ + if (machine_is_ebsa110()) + leds_event = ebsa110_leds_event; + + return 0; +} + +__initcall(leds_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/mm.c linux.ac/arch/arm/mach-ebsa110/mm.c --- linux.vanilla/arch/arm/mach-ebsa110/mm.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/mm.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-ebsa110/mm.c + * + * Copyright (C) 1998-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Extra MM routines for the EBSA-110 architecture + */ +#include +#include + +#include +#include +#include + +#include + +#include "hardware.h" + +static struct map_desc ebsa110_io_desc[] __initdata = { + /* + * sparse external-decode ISAIO space + */ + { IRQ_STAT, TRICK4_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_STAT/IRQ_MCLR */ + { IRQ_MASK, TRICK3_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_MASK/IRQ_MSET */ + { SOFT_BASE, TRICK1_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* SOFT_BASE */ + { PIT_BASE, TRICK0_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* PIT_BASE */ + + /* + * self-decode ISAIO space + */ + { ISAIO_BASE, ISAIO_PHYS, ISAIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init ebsa110_map_io(void) +{ + iotable_init(ebsa110_io_desc); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-ebsa110/time.c linux.ac/arch/arm/mach-ebsa110/time.c --- linux.vanilla/arch/arm/mach-ebsa110/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-ebsa110/time.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,113 @@ +/* + * linux/arch/arm/mach-ebsa110/time.c + * + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include + +#define PIT_CTRL (PIT_BASE + 0x0d) +#define PIT_T2 (PIT_BASE + 0x09) +#define PIT_T1 (PIT_BASE + 0x05) +#define PIT_T0 (PIT_BASE + 0x01) + +/* + * This is the rate at which your MCLK signal toggles (in Hz) + * This was measured on a 10 digit frequency counter sampling + * over 1 second. + */ +#define MCLK 47894000 + +/* + * This is the rate at which the PIT timers get clocked + */ +#define CLKBY7 (MCLK / 7) + +/* + * If CLKBY7 is larger than this, then we must do software + * division of the timer interrupt. + */ +#if CLKBY7 > 6553500 +#define DIVISOR 2 +#else +#define DIVISOR 1 +#endif + +/* + * This is the counter value + */ +#define COUNT ((CLKBY7 + (DIVISOR * HZ / 2)) / (DIVISOR * HZ)) + +extern unsigned long (*gettimeoffset)(void); + +static unsigned long divisor; + +/* + * Get the time offset from the system PIT. Note that if we have missed an + * interrupt, then the PIT counter will roll over (ie, be negative). + * This actually works out to be convenient. + */ +static unsigned long ebsa110_gettimeoffset(void) +{ + unsigned long offset, count; + + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + /* + * If count > COUNT, make the number negative. + */ + if (count > COUNT) + count |= 0xffff0000; + + offset = COUNT * (DIVISOR - divisor); + offset -= count; + + /* + * `offset' is in units of timer counts. Convert + * offset to units of microseconds. + */ + offset = offset * (1000000 / HZ) / (COUNT * DIVISOR); + + return offset; +} + +int ebsa110_reset_timer(void) +{ + u32 count; + + /* latch and read timer 1 */ + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + count += COUNT; + + __raw_writeb(count & 0xff, PIT_T1); + __raw_writeb(count >> 8, PIT_T1); + + if (divisor == 0) + divisor = DIVISOR; + divisor -= 1; + return divisor; +} + +void __init ebsa110_setup_timer(void) +{ + /* + * Timer 1, mode 2, LSB/MSB + */ + __raw_writeb(0x70, PIT_CTRL); + __raw_writeb(COUNT & 0xff, PIT_T1); + __raw_writeb(COUNT >> 8, PIT_T1); + divisor = DIVISOR - 1; + + gettimeoffset = ebsa110_gettimeoffset; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/Makefile linux.ac/arch/arm/mach-footbridge/Makefile --- linux.vanilla/arch/arm/mach-footbridge/Makefile Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-footbridge/Makefile Sat Apr 14 01:16:46 2001 @@ -5,42 +5,32 @@ # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). +USE_STANDARD_AS_RULE := true + O_TARGET := footbridge.o # Object file lists. -obj-y := arch.o #dma.o mm.o +obj-y := arch.o irq.o mm.o #dma.o obj-m := obj-n := obj- := export-objs := netwinder-hw.o -ifeq ($(CONFIG_PCI),y) -obj-$(CONFIG_ARCH_CATS) += cats-pci.o -obj-$(CONFIG_ARCH_EBSA285) += ebsa285-pci.o -obj-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o -obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o -endif - -ifeq ($(CONFIG_LEDS),y) -obj-$(CONFIG_ARCH_CO285) += ebsa285-leds.o -obj-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o -obj-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o -endif +pci-$(CONFIG_ARCH_CATS) += cats-pci.o +pci-$(CONFIG_ARCH_EBSA285) += ebsa285-pci.o +pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o +pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o + +leds-$(CONFIG_ARCH_CO285) += ebsa285-leds.o +leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o +leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o obj-$(CONFIG_ARCH_CATS) += cats-hw.o obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o -# Files that are both resident and modular; remove from modular. - -obj-m := $(filter-out $(obj-y), $(obj-m)) - -# Translate to Rules.make lists. - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +obj-$(CONFIG_PCI) +=$(pci-y) +obj-$(CONFIG_LEDS) +=$(leds-y) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/arch.c linux.ac/arch/arm/mach-footbridge/arch.c --- linux.vanilla/arch/arm/mach-footbridge/arch.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-footbridge/arch.c Sat Apr 14 01:16:46 2001 @@ -19,9 +19,8 @@ #include -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); -extern void __init footbridge_map_io(void); +extern void footbridge_map_io(void); +extern void footbridge_init_irq(void); #ifdef CONFIG_ARCH_EBSA285 @@ -42,6 +41,7 @@ VIDEO(0x000a0000, 0x000bffff) FIXUP(fixup_ebsa285) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -91,6 +91,7 @@ DISABLE_PARPORT(2) FIXUP(fixup_netwinder) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -111,9 +112,11 @@ MACHINE_START(CATS, "Chalice-CATS") MAINTAINER("Philip Blundell") BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) SOFT_REBOOT FIXUP(fixup_cats) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -139,6 +142,7 @@ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000) FIXUP(fixup_coebsa285) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif @@ -148,5 +152,6 @@ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) BOOT_PARAMS(0x00000100) MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) MACHINE_END #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/irq.c linux.ac/arch/arm/mach-footbridge/irq.c --- linux.vanilla/arch/arm/mach-footbridge/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-footbridge/irq.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,223 @@ +/* + * linux/arch/arm/mach-footbridge/irq.c + * + * Copyright (C) 1996-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 22-Aug-1998 RMK Restructured IRQ routines + * 03-Sep-1998 PJB Merged CATS support + * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder + * 26-Jan-1999 PJB Don't use IACK on CATS + * 16-Mar-1999 RMK Added autodetect of ISA PICs + */ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* + * Footbridge IRQ translation table + * Converts from our IRQ numbers into FootBridge masks + */ +static const int fb_irq_mask[] = { + IRQ_MASK_UART_RX, /* 0 */ + IRQ_MASK_UART_TX, /* 1 */ + IRQ_MASK_TIMER1, /* 2 */ + IRQ_MASK_TIMER2, /* 3 */ + IRQ_MASK_TIMER3, /* 4 */ + IRQ_MASK_IN0, /* 5 */ + IRQ_MASK_IN1, /* 6 */ + IRQ_MASK_IN2, /* 7 */ + IRQ_MASK_IN3, /* 8 */ + IRQ_MASK_DOORBELLHOST, /* 9 */ + IRQ_MASK_DMA1, /* 10 */ + IRQ_MASK_DMA2, /* 11 */ + IRQ_MASK_PCI, /* 12 */ + IRQ_MASK_SDRAMPARITY, /* 13 */ + IRQ_MASK_I2OINPOST, /* 14 */ + IRQ_MASK_PCI_ABORT, /* 15 */ + IRQ_MASK_PCI_SERR, /* 16 */ + IRQ_MASK_DISCARD_TIMER, /* 17 */ + IRQ_MASK_PCI_DPERR, /* 18 */ + IRQ_MASK_PCI_PERR, /* 19 */ +}; + +static void fb_mask_irq(unsigned int irq) +{ + *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(irq)]; +} + +static void fb_unmask_irq(unsigned int irq) +{ + *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)]; +} + +static void __init __fb_init_irq(void) +{ + int irq; + + /* + * setup DC21285 IRQs + */ + *CSR_IRQ_DISABLE = -1; + *CSR_FIQ_DISABLE = -1; + + for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = fb_mask_irq; + irq_desc[irq].mask = fb_mask_irq; + irq_desc[irq].unmask = fb_unmask_irq; + } +} + +extern int isa_irq; + +static void isa_mask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); +} + +static void isa_mask_ack_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); + outb(0x20, PIC_LO); +} + +static void isa_unmask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); +} + +static void isa_mask_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); +} + +static void isa_mask_ack_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); + outb(0x62, PIC_LO); + outb(0x20, PIC_HI); +} + +static void isa_unmask_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); +} + +static void no_action(int irq, void *dev_id, struct pt_regs *regs) +{ +} + +static struct irqaction irq_cascade = { handler: no_action, name: "cascade", }; +static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; +static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; + +static void __init isa_init_irq(int irq) +{ + /* + * Setup, and then probe for an ISA PIC + * If the PIC is not there, then we + * ignore the PIC. + */ + outb(0x11, PIC_LO); + outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ + outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ + outb(0x01, PIC_MASK_LO); /* x86 */ + outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ + + outb(0x11, PIC_HI); + outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ + outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ + outb(0x01, PIC_MASK_HI); /* x86 */ + outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ + + outb(0x0b, PIC_LO); + outb(0x0b, PIC_HI); + + if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { + outb(0xff, PIC_MASK_LO);/* mask all IRQs */ + outb(0xff, PIC_MASK_HI);/* mask all IRQs */ + isa_irq = irq; + } else + isa_irq = -1; + + if (isa_irq != -1) { + for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = isa_mask_ack_pic_lo_irq; + irq_desc[irq].mask = isa_mask_pic_lo_irq; + irq_desc[irq].unmask = isa_unmask_pic_lo_irq; + } + + for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = isa_mask_ack_pic_hi_irq; + irq_desc[irq].mask = isa_mask_pic_hi_irq; + irq_desc[irq].unmask = isa_unmask_pic_hi_irq; + } + + request_resource(&ioport_resource, &pic1_resource); + request_resource(&ioport_resource, &pic2_resource); + setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade); + setup_arm_irq(isa_irq, &irq_cascade); + + /* + * On the NetWinder, don't automatically + * enable ISA IRQ11 when it is requested. + * There appears to be a missing pull-up + * resistor on this line. + */ + if (machine_is_netwinder()) + irq_desc[_ISA_IRQ(11)].noautoenable = 1; + } +} + +void __init footbridge_init_irq(void) +{ + __fb_init_irq(); + + if (!footbridge_cfn_mode()) + return; + + if (machine_is_ebsa285()) + /* The following is dependent on which slot + * you plug the Southbridge card into. We + * currently assume that you plug it into + * the right-hand most slot. + */ + isa_init_irq(IRQ_PCI); + + if (machine_is_cats()) + isa_init_irq(IRQ_IN2); + + if (machine_is_netwinder()) + isa_init_irq(IRQ_IN3); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-footbridge/mm.c linux.ac/arch/arm/mach-footbridge/mm.c --- linux.vanilla/arch/arm/mach-footbridge/mm.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-footbridge/mm.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,117 @@ +/* + * linux/arch/arm/mach-footbridge/mm.c + * + * Copyright (C) 1998-2000 Russell King, Dave Gilbert. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Extra MM routines for the EBSA285 architecture + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* + * Common mapping for all systems. Note that the outbound write flush is + * commented out since there is a "No Fix" problem with it. Not mapping + * it means that we have extra bullet protection on our feet. + */ +static struct map_desc fb_common_io_desc[] __initdata = { + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +/* + * The mapping when the footbridge is in host mode. We don't map any of + * this when we are in add-in mode. + */ +static struct map_desc ebsa285_host_io_desc[] __initdata = { +#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, +#endif + LAST_DESC +}; + +/* + * The CO-ebsa285 mapping. + */ +static struct map_desc co285_io_desc[] __initdata = { +#ifdef CONFIG_ARCH_CO285 + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, +#endif + LAST_DESC +}; + +void __init footbridge_map_io(void) +{ + struct map_desc *desc = NULL; + + /* + * Set up the common mapping first; we need this to + * determine whether we're in host mode or not. + */ + iotable_init(fb_common_io_desc); + + /* + * Now, work out what we've got to map in addition on this + * platform. + */ + if (machine_is_co285()) + desc = co285_io_desc; + else if (footbridge_cfn_mode()) + desc = ebsa285_host_io_desc; + + if (desc) + iotable_init(desc); +} + +#ifdef CONFIG_FOOTBRIDGE_ADDIN + +/* + * These two functions convert virtual addresses to PCI addresses and PCI + * addresses to virtual addresses. Note that it is only legal to use these + * on memory obtained via get_free_page or kmalloc. + */ +unsigned long __virt_to_bus(unsigned long res) +{ +#ifdef CONFIG_DEBUG_ERRORS + if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { + printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res); + __backtrace(); + } +#endif + return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); +} + +unsigned long __bus_to_virt(unsigned long res) +{ + res -= (*CSR_PCISDRAMBASE & 0xfffffff0); + res += PAGE_OFFSET; + +#ifdef CONFIG_DEBUG_ERRORS + if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { + printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res); + __backtrace(); + } +#endif + return res; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/Makefile linux.ac/arch/arm/mach-sa1100/Makefile --- linux.vanilla/arch/arm/mach-sa1100/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mach-sa1100/Makefile Sat Apr 14 01:16:46 2001 @@ -11,13 +11,14 @@ # Object file lists. -obj-y := arch.o hw.o #dma.o mm.o +obj-y := arch.o hw.o dma-sa1100.o # mm.o obj-m := obj-n := obj- := -export-objs := hw.o leds.o +export-objs := dma-sa1100.o dma-sa1111.o hw.o leds.o obj-$(CONFIG_LEDS) += leds.o +obj-$(CONFIG_SA1111) += dma-sa1111.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/arch.c linux.ac/arch/arm/mach-sa1100/arch.c --- linux.vanilla/arch/arm/mach-sa1100/arch.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mach-sa1100/arch.c Sat Apr 14 01:16:46 2001 @@ -19,8 +19,23 @@ #include -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); +extern void genarch_init_irq(void); + + +static void sa1100_power_off(void) +{ + mdelay(100); + cli(); + /* disable internal oscillator, float CS lines */ + PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS); + /* set lowest clock */ + PPCR = 0; + /* set all GPIOs to input mode */ + GPDR = 0; + /* enter sleep mode */ + PMCR = PMCR_SF; +} + static void victor_power_off(void) { @@ -47,10 +62,13 @@ mi->bank[__nr].start = (__start), \ mi->bank[__nr].size = (__size), \ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) + static void __init fixup_sa1100(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { + pm_power_off = sa1100_power_off; + if (machine_is_assabet()) { /* * On Assabet, we must probe for the Neponset board *before* @@ -82,6 +100,16 @@ setup_initrd( 0xc0800000, 3*1024*1024 ); } + else if (machine_is_pangolin()) { + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + SET_BANK( 1, 0xc8000000, 32*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 16384 ); + setup_initrd( 0xc0800000, 9*1024*1024 ); + } + else if (machine_is_brutus()) { SET_BANK( 0, 0xc0000000, 4*1024*1024 ); SET_BANK( 1, 0xc8000000, 4*1024*1024 ); @@ -133,7 +161,7 @@ setup_initrd(0xc0400000, 4*1024*1024); } - else if (machine_is_thinclient() || machine_is_graphicsclient()) { + else if (machine_is_graphicsclient()) { SET_BANK( 0, 0xc0000000, 16*1024*1024 ); mi->nr_banks = 1; @@ -154,15 +182,6 @@ if( *((char*)0xc0000100) ) *cmdline = ((char *)0xc0000100); } - else if (machine_is_tifon()) { - SET_BANK( 0, 0xc0000000, 16*1024*1024 ); - SET_BANK( 1, 0xc8000000, 16*1024*1024 ); - mi->nr_banks = 2; - - ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0); - setup_ramdisk(1, 0, 0, 4096); - setup_initrd( 0xd0000000 + 0x1100004, 0x140000 ); - } else if (machine_is_victor()) { SET_BANK( 0, 0xc0000000, 4*1024*1024 ); @@ -180,6 +199,16 @@ pm_power_off = victor_power_off; } + else if (machine_is_sherman()) { + SET_BANK( 0, 0xc0000000, 64*1024*1024 ); + SET_BANK( 1, 0xc8000000, 64*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV( 60, 2 ); + setup_ramdisk( 1, 0, 0, 8192 ); +// setup_initrd( 0xc0400000, 8*1024*1024 ); +} + else if (machine_is_xp860()) { SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; @@ -193,6 +222,15 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_PANGOLIN +MACHINE_START(PANGOLIN, "Dialogue-Pangolin") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_BITSY @@ -201,6 +239,7 @@ BOOT_PARAMS(0xc0000100) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_BRUTUS @@ -208,6 +247,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_CERF @@ -216,6 +256,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_EMPEG @@ -223,6 +264,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT @@ -230,14 +272,16 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_ITSY MACHINE_START(ITSY, "Compaq Itsy") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - BOOT_PARAMS(0xc0000100 + BOOT_PARAMS(0xc0000100) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_LART @@ -245,6 +289,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_NANOENGINE @@ -252,6 +297,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_PLEB @@ -259,20 +305,7 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_THINCLIENT -MACHINE_START(THINCLIENT, "ADS ThinClient") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) - MAPIO(sa1100_map_io) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_TIFON -MACHINE_START(TIFON, "Tifon") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) - MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_VICTOR @@ -280,6 +313,15 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_SHERMAN +MACHINE_START(SHERMAN, "Blazie Engineering Sherman") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif #ifdef CONFIG_SA1100_XP860 @@ -287,5 +329,6 @@ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MAPIO(sa1100_map_io) + INITIRQ(genarch_init_irq) MACHINE_END #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/dma-sa1100.c linux.ac/arch/arm/mach-sa1100/dma-sa1100.c --- linux.vanilla/arch/arm/mach-sa1100/dma-sa1100.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-sa1100/dma-sa1100.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,538 @@ +/* + * arch/arm/kernel/dma-sa1100.c + * + * Support functions for the SA11x0 internal DMA channels. + * (see also Documentation/arm/SA1100/DMA) + * + * Copyright (C) 2000 Nicolas Pitre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK( s, arg... ) printk( "dma<%s>: " s, dma->device_id , ##arg ) +#else +#define DPRINTK( x... ) +#endif + + +/* + * Maximum physical DMA buffer size + */ +#define MAX_DMA_SIZE 0x1fff +#define MAX_DMA_ORDER 12 + + +/* + * DMA control register structure + */ +typedef struct { + volatile u_long DDAR; + volatile u_long SetDCSR; + volatile u_long ClrDCSR; + volatile u_long RdDCSR; + volatile dma_addr_t DBSA; + volatile u_long DBTA; + volatile dma_addr_t DBSB; + volatile u_long DBTB; +} dma_regs_t; + + +/* + * DMA buffer structure + */ +struct dma_buf_s { + int size; /* buffer size */ + dma_addr_t dma_start; /* starting DMA address */ + dma_addr_t dma_ptr; /* current DMA pointer position */ + int ref; /* number of DMA references */ + void *id; /* to identify buffer from outside */ + struct dma_buf_s *next; /* next buffer to process */ +}; + + +#include "dma.h" + +sa1100_dma_t dma_chan[MAX_SA1100_DMA_CHANNELS]; + + +/* + * DMA processing... + */ + +static inline int start_sa1100_dma(sa1100_dma_t * dma, dma_addr_t dma_ptr, int size) +{ + dma_regs_t *regs = dma->regs; + int status; + int use_bufa; + + status = regs->RdDCSR; + + /* If both DMA buffers are started, there's nothing else we can do. */ + if ((status & DCSR_STRTA) && (status & DCSR_STRTB)) { + DPRINTK("start: st %#x busy\n", status); + return -EBUSY; + } + + use_bufa = (((status & DCSR_BIU) && (status & DCSR_STRTB)) || + (!(status & DCSR_BIU) && !(status & DCSR_STRTA))); + if (use_bufa) { + regs->ClrDCSR = DCSR_DONEA | DCSR_STRTA; + regs->DBSA = dma_ptr; + regs->DBTA = size; + regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN; + DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size); + } else { + regs->ClrDCSR = DCSR_DONEB | DCSR_STRTB; + regs->DBSB = dma_ptr; + regs->DBTB = size; + regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN; + DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size); + } + + return 0; +} + + +static int start_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, int size) +{ + if (channel_is_sa1111_sac(dma - dma_chan)) + return start_sa1111_sac_dma(dma, dma_ptr, size); + return start_sa1100_dma(dma, dma_ptr, size); +} + + +/* This must be called with IRQ disabled */ +static void process_dma(sa1100_dma_t * dma) +{ + dma_buf_t *buf; + int chunksize; + + for (;;) { + buf = dma->tail; + + if (!buf) { + /* no more data available */ + DPRINTK("process: no more buf (dma %s)\n", + dma->curr ? "active" : "inactive"); + /* + * Some devices may require DMA still sending data + * at any time for clock reference, etc. + * Note: if there is still a data buffer being + * processed then the ref count is negative. This + * allows for the DMA termination to be accounted in + * the proper order. + */ + if (dma->spin_size && dma->spin_ref >= 0) { + chunksize = dma->spin_size; + if (chunksize > MAX_DMA_SIZE) + chunksize = (1 << MAX_DMA_ORDER); + while (start_dma(dma, dma->spin_addr, chunksize) == 0) + dma->spin_ref++; + if (dma->curr != NULL) + dma->spin_ref = -dma->spin_ref; + } + break; + } + + /* + * Let's try to start DMA on the current buffer. + * If DMA is busy then we break here. + */ + chunksize = buf->size; + if (chunksize > MAX_DMA_SIZE) + chunksize = (1 << MAX_DMA_ORDER); + DPRINTK("process: b=%#x s=%d\n", (int) buf->id, buf->size); + if (start_dma(dma, buf->dma_ptr, chunksize) != 0) + break; + dma->active = 1; + if (!dma->curr) + dma->curr = buf; + buf->ref++; + buf->dma_ptr += chunksize; + buf->size -= chunksize; + if (buf->size == 0) { + /* current buffer is done: move tail to the next one */ + dma->tail = buf->next; + DPRINTK("process: next b=%#x\n", (int) dma->tail); + } + } +} + + +/* This must be called with IRQ disabled */ +void sa1100_dma_done (sa1100_dma_t *dma) +{ + dma_buf_t *buf = dma->curr; + + if (dma->spin_ref > 0) { + dma->spin_ref--; + } else if (buf) { + buf->ref--; + if (buf->ref == 0 && buf->size == 0) { + /* + * Current buffer is done. + * Move current reference to the next one and send + * the processed buffer to the callback function, + * then discard it. + */ + DPRINTK("IRQ: buf done\n"); + dma->curr = buf->next; + if (dma->curr == NULL) + dma->spin_ref = -dma->spin_ref; + if (dma->head == buf) + dma->head = NULL; + buf->size = buf->dma_ptr - buf->dma_start; + if (dma->callback) + dma->callback(buf->id, buf->size); + kfree(buf); + } + } + + process_dma(dma); +} + + +static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + sa1100_dma_t *dma = (sa1100_dma_t *) dev_id; + int status = dma->regs->RdDCSR; + + DPRINTK("IRQ: b=%#x st=%#x\n", (int) dma->curr->id, status); + + dma->regs->ClrDCSR = DCSR_ERROR | DCSR_DONEA | DCSR_DONEB; + if (!(status & (DCSR_DONEA | DCSR_DONEB))) + return; + + sa1100_dma_done (dma); +} + + +/* + * DMA interface functions + */ + +/* + * Get dma list + * for /proc/dma + */ +int sa1100_get_dma_list(char *buf) +{ + int i, len = 0; + + for (i = 0; i < MAX_SA1100_DMA_CHANNELS; i++) { + if (dma_chan[i].lock) + len += sprintf(buf + len, "%2d: %s\n", + i, dma_chan[i].device_id); + } + return len; +} + +int sa1100_request_dma(dmach_t * channel, const char *device_id) +{ + sa1100_dma_t *dma = NULL; + dma_regs_t *regs; + int ch, err; + + *channel = -1; /* to be sure we catch the freeing of a misregistered channel */ + + for (ch = 0; ch < SA1100_DMA_CHANNELS; ch++) { + dma = &dma_chan[ch]; + if (xchg(&dma->lock, 1) == 0) + break; + } + if (ch >= SA1100_DMA_CHANNELS) { + printk(KERN_ERR "%s: no free DMA channel available\n", + device_id); + return -EBUSY; + } + + err = request_irq(dma->irq, dma_irq_handler, SA_INTERRUPT, + device_id, (void *) dma); + if (err) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel %d\n", + device_id, dma->irq, ch); + dma->lock = 0; + return err; + } + + *channel = ch; + dma->device_id = device_id; + dma->callback = NULL; + dma->spin_size = 0; + + regs = dma->regs; + regs->ClrDCSR = + (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | + DCSR_IE | DCSR_ERROR | DCSR_RUN); + regs->DDAR = 0; + + DPRINTK("requested\n"); + return 0; +} + + +int sa1100_dma_set_callback(dmach_t channel, dma_callback_t cb) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + + dma->callback = cb; + DPRINTK("cb = %p\n", cb); + return 0; +} + + +int sa1100_dma_set_device(dmach_t channel, dma_device_t device) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + + if (dma->ready) + return -EINVAL; + + regs->ClrDCSR = DCSR_STRTA | DCSR_STRTB | DCSR_IE | DCSR_RUN; + regs->DDAR = device; + DPRINTK("DDAR = %#x\n", device); + dma->ready = 1; + return 0; +} + + +int sa1100_dma_set_spin(dmach_t channel, dma_addr_t addr, int size) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + int flags; + + if (channel >= SA1100_DMA_CHANNELS) + return -EINVAL; + + DPRINTK("set spin %d at %#x\n", size, addr); + local_irq_save(flags); + dma->spin_addr = addr; + dma->spin_size = size; + if (size) + process_dma(dma); + local_irq_restore(flags); + return 0; +} + + +int sa1100_dma_queue_buffer(dmach_t channel, void *buf_id, + dma_addr_t data, int size) +{ + sa1100_dma_t *dma; + dma_buf_t *buf; + int flags; + + dma = &dma_chan[channel]; + if (!dma->ready) + return -EINVAL; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return -ENOMEM; + + buf->next = NULL; + buf->ref = 0; + buf->dma_ptr = buf->dma_start = data; + buf->size = size; + buf->id = buf_id; + DPRINTK("queueing b=%#x a=%#x s=%d\n", (int) buf_id, data, size); + + local_irq_save(flags); + if (dma->head) + dma->head->next = buf; + dma->head = buf; + if (!dma->tail) + dma->tail = buf; + process_dma(dma); + local_irq_restore(flags); + + return 0; +} + + +int sa1100_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + int flags, ret; + + if (channel_is_sa1111_sac(channel)) + return sa1111_dma_get_current(channel, buf_id, addr); + + local_irq_save(flags); + if (dma->curr && dma->spin_ref <= 0) { + dma_buf_t *buf = dma->curr; + int status, using_bufa; + + status = regs->RdDCSR; + /* + * If we got here, that's because there is, or recently was, a + * buffer being processed. We must determine whether buffer + * A or B is active. Two possibilities: either we are + * in the middle of a buffer, or the DMA controller just + * switched to the next toggle but the interrupt hasn't been + * serviced yet. The former case is straight forward. In + * the later case, we'll do like if DMA is just at the end + * of the previous toggle since all registers haven't been + * reset yet. This goes around the edge case and since we're + * always a little behind anyways it shouldn't make a big + * difference. If DMA has been stopped prior calling this + * then the position is always exact. + */ + using_bufa = ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) || + ( (status & DCSR_BIU) && !(status & DCSR_STRTB))); + if (buf_id) + *buf_id = buf->id; + *addr = (using_bufa) ? regs->DBSA : regs->DBSB; + /* + * Clamp funky pointers sometimes returned by the hardware + * on completed DMA transfers + */ + if (*addr < buf->dma_start || + *addr > buf->dma_ptr) + *addr = buf->dma_ptr; + DPRINTK("curr_pos: b=%#x a=%#x\n", (int)dma->curr->id, *addr); + ret = 0; + } else { + if (buf_id) + *buf_id = NULL; + *addr = 0; + DPRINTK("curr_pos: spinning\n"); + ret = -ENXIO; + } + local_irq_restore(flags); + return ret; +} + + +int sa1100_dma_stop(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + + if (channel_is_sa1111_sac(channel)) + return sa1111_dma_stop(channel); + + regs->ClrDCSR = DCSR_RUN | DCSR_IE; + return 0; +} + + +int sa1100_dma_resume(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma_regs_t *regs = dma->regs; + + if (channel_is_sa1111_sac(channel)) + return sa1111_dma_resume(channel); + + regs->SetDCSR = DCSR_RUN | DCSR_IE; + return 0; +} + + +int sa1100_dma_flush_all(dmach_t channel) +{ + sa1100_dma_t *dma; + dma_buf_t *buf, *next_buf; + int flags; + + dma = &dma_chan[channel]; + local_irq_save(flags); + if (channel_is_sa1111_sac(channel)) + sa1111_reset_sac_dma(channel); + else + dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE; + buf = dma->curr; + if (!buf) + buf = dma->tail; + dma->head = dma->tail = dma->curr = NULL; + dma->active = 0; + dma->spin_ref = 0; + if (dma->spin_size) + process_dma(dma); + local_irq_restore(flags); + while (buf) { + next_buf = buf->next; + kfree(buf); + buf = next_buf; + } + DPRINTK("flushed\n"); + return 0; +} + + +void sa1100_free_dma(dmach_t channel) +{ + sa1100_dma_t *dma; + + if ((unsigned) channel >= MAX_SA1100_DMA_CHANNELS) + return; + + dma = &dma_chan[channel]; + if (!dma->lock) { + printk(KERN_ERR "Trying to free free DMA%d\n", channel); + return; + } + + sa1100_dma_set_spin(channel, 0, 0); + sa1100_dma_flush_all(channel); + dma->ready = 0; + + if (channel_is_sa1111_sac(channel)) { + sa1111_cleanup_sac_dma(channel); + } else { + free_irq(IRQ_DMA0 + channel, (void *) dma); + } + dma->lock = 0; + + DPRINTK("freed\n"); +} + + +EXPORT_SYMBOL(sa1100_request_dma); +EXPORT_SYMBOL(sa1100_dma_set_callback); +EXPORT_SYMBOL(sa1100_dma_set_device); +EXPORT_SYMBOL(sa1100_dma_set_spin); +EXPORT_SYMBOL(sa1100_dma_queue_buffer); +EXPORT_SYMBOL(sa1100_dma_get_current); +EXPORT_SYMBOL(sa1100_dma_stop); +EXPORT_SYMBOL(sa1100_dma_resume); +EXPORT_SYMBOL(sa1100_dma_flush_all); +EXPORT_SYMBOL(sa1100_free_dma); + + +static int __init sa1100_init_dma(void) +{ + int channel; + for (channel = 0; channel < SA1100_DMA_CHANNELS; channel++) { + dma_chan[channel].regs = + (dma_regs_t *) io_p2v(_DDAR(channel)); + dma_chan[channel].irq = IRQ_DMA0 + channel; + } + return 0; +} + +__initcall(sa1100_init_dma); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/dma-sa1111.c linux.ac/arch/arm/mach-sa1100/dma-sa1111.c --- linux.vanilla/arch/arm/mach-sa1100/dma-sa1111.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-sa1100/dma-sa1111.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,346 @@ +/* + * linux/arch/arm/mach-sa1100/dma-sa1111.c + * + * Copyright (C) 2000 John Dorsey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 4 September 2000 - created. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +// #define DEBUG +#ifdef DEBUG +#define DPRINTK( s, arg... ) printk( "dma<%s>: " s, dma->device_id , ##arg ) +#else +#define DPRINTK( x... ) +#endif + + +/* + * Control register structure for the SA1111 SAC DMA + */ + +typedef struct { + volatile u_long SAD_CS; + volatile dma_addr_t SAD_SA; + volatile u_long SAD_CA; + volatile dma_addr_t SAD_SB; + volatile u_long SAD_CB; +} dma_regs_t; + +#include "dma.h" + + +void sa1111_reset_sac_dma(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + dma->regs->SAD_CS = 0; + mdelay(1); + dma->dma_a = dma->dma_b = 0; +} + + +int start_sa1111_sac_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, size_t size) +{ + dma_regs_t *sac_regs = dma->regs; + + DPRINTK(" SAC DMA %cCS %02x at %08x (%d)\n", + (sac_regs==&SADTCS)?'T':'R', sac_regs->SAD_CS, dma_ptr, size); + + /* The minimum transfer length requirement has not yet been + * verified: + */ + if( size < SA1111_SAC_DMA_MIN_XFER ) + printk(KERN_WARNING "Warning: SAC xfers below %u bytes may be buggy!" + " (%u bytes)\n", SA1111_SAC_DMA_MIN_XFER, size); + + if( dma->dma_a && dma->dma_b ){ + DPRINTK(" neither engine available! (A %d, B %d)\n", + dma->dma_a, dma->dma_b); + return -1; + } + + if( sa1111_check_dma_bug(dma_ptr) ) + printk(KERN_WARNING "Warning: DMA address %08x is buggy!\n", + dma_ptr); + + if( (dma->last_dma || dma->dma_b) && dma->dma_a == 0 ){ + if( sac_regs->SAD_CS & SAD_CS_DBDB ){ + DPRINTK(" awaiting \"done B\" interrupt, not starting\n"); + return -1; + } + sac_regs->SAD_SA = SA1111_DMA_ADDR((u_int)dma_ptr); + sac_regs->SAD_CA = size; + sac_regs->SAD_CS = SAD_CS_DSTA | SAD_CS_DEN; + ++dma->dma_a; + DPRINTK(" with A [%02lx %08lx %04lx]\n", sac_regs->SAD_CS, + sac_regs->SAD_SA, sac_regs->SAD_CA); + } else { + if( sac_regs->SAD_CS & SAD_CS_DBDA ){ + DPRINTK(" awaiting \"done A\" interrupt, not starting\n"); + return -1; + } + sac_regs->SAD_SB = SA1111_DMA_ADDR((u_int)dma_ptr); + sac_regs->SAD_CB = size; + sac_regs->SAD_CS = SAD_CS_DSTB | SAD_CS_DEN; + ++dma->dma_b; + DPRINTK(" with B [%02lx %08lx %04lx]\n", sac_regs->SAD_CS, + sac_regs->SAD_SB, sac_regs->SAD_CB); + } + + /* Additional delay to avoid DMA engine lockup during record: */ + if( sac_regs == (dma_regs_t*)&SADRCS ) + mdelay(1); /* NP : wouuuh! ugly... */ + + return 0; +} + + +static void sa1111_sac_dma_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + sa1100_dma_t *dma = (sa1100_dma_t *) dev_id; + + DPRINTK("irq %d, last DMA serviced was %c, CS %02x\n", irq, + dma->last_dma?'B':'A', dma->regs->SAD_CS); + + /* Occasionally, one of the DMA engines (A or B) will + * lock up. We try to deal with this by quietly kicking + * the control register for the afflicted transfer + * direction. + * + * Note for the debugging-inclined: we currently aren't + * properly flushing the DMA engines during channel + * shutdown. A slight hiccup at the beginning of playback + * after a channel has been stopped can be heard as + * evidence of this. Programmatically, this shows up + * as either a locked engine, or a spurious interrupt. -jd + */ + + if(irq==AUDXMTDMADONEA || irq==AUDRCVDMADONEA){ + + if(dma->last_dma == 0){ + DPRINTK("DMA B has locked up!\n"); + dma->regs->SAD_CS = 0; + mdelay(1); + dma->dma_a = dma->dma_b = 0; + } else { + if(dma->dma_a == 0) + DPRINTK("spurious SAC IRQ %d\n", irq); + else { + --dma->dma_a; + + /* Servicing the SAC DMA engines too quickly + * after they issue a DONE interrupt causes + * them to lock up. + */ + if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB) + mdelay(1); + } + } + + dma->regs->SAD_CS = SAD_CS_DBDA | SAD_CS_DEN; /* w1c */ + dma->last_dma = 0; + + } else { + + if(dma->last_dma == 1){ + DPRINTK("DMA A has locked up!\n"); + dma->regs->SAD_CS = 0; + mdelay(1); + dma->dma_a = dma->dma_b = 0; + } else { + if(dma->dma_b == 0) + DPRINTK("spurious SAC IRQ %d\n", irq); + else { + --dma->dma_b; + + /* See lock-up note above. */ + if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB) + mdelay(1); + } + } + + dma->regs->SAD_CS = SAD_CS_DBDB | SAD_CS_DEN; /* w1c */ + dma->last_dma = 1; + + } + + /* NP: maybe this shouldn't be called in all cases? */ + sa1100_dma_done (dma); +} + + +int sa1111_sac_request_dma(dmach_t *channel, const char *device_id, + unsigned int direction) +{ + sa1100_dma_t *dma = NULL; + int ch, irq, err; + + *channel = -1; /* to be sure we catch the freeing of a misregistered channel */ + + ch = SA1111_SAC_DMA_BASE + direction; + + if (!channel_is_sa1111_sac(ch)) { + printk(KERN_ERR "%s: invalid SA-1111 SAC DMA channel (%d)\n", + device_id, ch); + return -1; + } + + dma = &dma_chan[ch]; + + if (xchg(&dma->lock, 1) == 1) { + printk(KERN_ERR "%s: SA-1111 SAC DMA channel %d in use\n", + device_id, ch); + return -EBUSY; + } + + irq = AUDXMTDMADONEA + direction; + err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT, + device_id, (void *) dma); + if (err) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel %d (A)\n", + device_id, irq, ch); + dma->lock = 0; + return err; + } + + irq = AUDXMTDMADONEB + direction; + err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT, + device_id, (void *) dma); + if (err) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel %d (B)\n", + device_id, irq, ch); + dma->lock = 0; + return err; + } + + *channel = ch; + dma->device_id = device_id; + dma->callback = NULL; + dma->spin_size = 0; + dma->ready = 1; + + return 0; +} + + +/* FIXME: need to complete the three following functions */ + +int sa1111_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr) +{ + return -ENOSYS; +} + +int sa1111_dma_stop(dmach_t channel) +{ + return 0; +} + +int sa1111_dma_resume(dmach_t channel) +{ + return 0; +} + + +void sa1111_cleanup_sac_dma(dmach_t channel) +{ + sa1100_dma_t *dma = &dma_chan[channel]; + free_irq(AUDXMTDMADONEA + (channel - SA1111_SAC_DMA_BASE), (void*) dma); + free_irq(AUDXMTDMADONEB + (channel - SA1111_SAC_DMA_BASE), (void*) dma); +} + + +/* According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), errata #7, there is a + * significant bug in Serial Audio Controller DMA. If the SAC is + * accessing a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + */ +int sa1111_check_dma_bug(dma_addr_t addr){ + unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr); + + /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + if(machine_is_assabet() && addr >= _DRAMBnk1) + return -1; + + /* The bug only applies to buffers located more than one megabyte + * above the start of the target bank: + */ + if(physaddr<(1<<20)) + return 0; + + switch(FExtr(SMCR, SMCR_DRAC)){ + case 01: /* 10 row + bank address bits, A<20> must not be set */ + if(physaddr & (1<<20)) + return -1; + break; + case 02: /* 11 row + bank address bits, A<23> must not be set */ + if(physaddr & (1<<23)) + return -1; + break; + case 03: /* 12 row + bank address bits, A<24> must not be set */ + if(physaddr & (1<<24)) + return -1; + break; + case 04: /* 13 row + bank address bits, A<25> must not be set */ + if(physaddr & (1<<25)) + return -1; + break; + case 05: /* 14 row + bank address bits, A<20> must not be set */ + if(physaddr & (1<<20)) + return -1; + break; + case 06: /* 15 row + bank address bits, A<20> must not be set */ + if(physaddr & (1<<20)) + return -1; + break; + default: + printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%o\n", + __FUNCTION__, FExtr(SMCR, SMCR_DRAC)); + return -1; + } + + return 0; +} + + +EXPORT_SYMBOL(sa1111_sac_request_dma); +EXPORT_SYMBOL(sa1111_check_dma_bug); + + +static void __init sa1111_init_sac_dma(void) +{ + int channel = SA1111_SAC_DMA_BASE; + dma_chan[channel++].regs = (dma_regs_t *) &SADTCS; + dma_chan[channel++].regs = (dma_regs_t *) &SADRCS; +} + +__initcall(sa1111_init_sac_dma); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-sa1100/dma.h linux.ac/arch/arm/mach-sa1100/dma.h --- linux.vanilla/arch/arm/mach-sa1100/dma.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-sa1100/dma.h Sat Apr 14 01:16:46 2001 @@ -0,0 +1,56 @@ +/* + * Definitions shared between dma-sa1100.c and dma-sa1111.c + * (C) 2000 Nicolas Pitre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +/* + * DMA channel structure. + */ + +typedef struct dma_buf_s dma_buf_t; + +typedef struct { + unsigned int lock; /* Device is allocated */ + const char *device_id; /* Device name */ + dma_buf_t *head; /* where to insert buffers */ + dma_buf_t *tail; /* where to remove buffers */ + dma_buf_t *curr; /* buffer currently DMA'ed */ + int ready; /* 1 if DMA can occur */ + int active; /* 1 if DMA is actually processing data */ + dma_regs_t *regs; /* points to appropriate DMA registers */ + int irq; /* IRQ used by the channel */ + dma_callback_t callback; /* ... to call when buffers are done */ + int spin_size; /* > 0 when DMA should spin when no more buffer */ + dma_addr_t spin_addr; /* DMA address to spin onto */ + int spin_ref; /* number of spinning references */ +#ifdef CONFIG_SA1111 + int dma_a, dma_b, last_dma; /* SA-1111 specific */ +#endif +} sa1100_dma_t; + +extern sa1100_dma_t dma_chan[MAX_SA1100_DMA_CHANNELS]; + + +int start_sa1111_sac_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, size_t size); +int sa1111_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr); +int sa1111_dma_stop(dmach_t channel); +int sa1111_dma_resume(dmach_t channel); +void sa1111_reset_sac_dma(dmach_t channel); +void sa1111_cleanup_sac_dma(dmach_t channel); + +void sa1100_dma_done (sa1100_dma_t *dma); + + +#ifdef CONFIG_SA1111 +#define channel_is_sa1111_sac(ch) \ + ((ch) >= SA1111_SAC_DMA_BASE && \ + (ch) < SA1111_SAC_DMA_BASE + SA1111_SAC_DMA_CHANNELS) +#else +#define channel_is_sa1111_sac(ch) (0) +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/Makefile linux.ac/arch/arm/mach-shark/Makefile --- linux.vanilla/arch/arm/mach-shark/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mach-shark/Makefile Sat Apr 14 01:16:46 2001 @@ -18,6 +18,6 @@ export-objs := -#obj-$(CONFIG_LEDS) += leds.o +obj-$(CONFIG_LEDS) += leds.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/arch.c linux.ac/arch/arm/mach-shark/arch.c --- linux.vanilla/arch/arm/mach-shark/arch.c Tue Sep 19 16:31:53 2000 +++ linux.ac/arch/arm/mach-shark/arch.c Sat Apr 14 01:16:46 2001 @@ -18,14 +18,31 @@ #include -extern void setup_initrd(unsigned int start, unsigned int size); -extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); -extern void __init footbridge_map_io(void); -extern void __init shark_map_io(void); +static void __init +fixup_shark(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) { + int i; + + mi->nr_banks=0; + for (i=0;iu1.s.pages_in_bank[i] != 0) { + mi->nr_banks++; + mi->bank[i].node = 0; + mi->bank[i].start = params->u1.s.pages_in_bank[i] & 0xffff0000; + mi->bank[i].size = (params->u1.s.pages_in_bank[i] & 0xffff)*PAGE_SIZE; + params->u1.s.pages_in_bank[i] &= 0xffff; + } + } +} + +extern void shark_map_io(void); +extern void genarch_init_irq(void); MACHINE_START(SHARK, "Shark") MAINTAINER("Alexander Schulz") BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) - VIDEO(0x06000000, 0x061fffff) + BOOT_PARAMS(0x08003000) + FIXUP(fixup_shark) MAPIO(shark_map_io) + INITIRQ(genarch_init_irq) MACHINE_END diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/dma.c linux.ac/arch/arm/mach-shark/dma.c --- linux.vanilla/arch/arm/mach-shark/dma.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-shark/dma.c Sat Apr 14 01:16:46 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-shark/dma.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz * * derived from: * arch/arm/kernel/dma-ebsa285.c diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/leds.c linux.ac/arch/arm/mach-shark/leds.c --- linux.vanilla/arch/arm/mach-shark/leds.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/arm/mach-shark/leds.c Sat Apr 14 01:16:46 2001 @@ -0,0 +1,163 @@ +/* + * arch/arm/kernel/leds-shark.c + * by Alexander Schulz + * + * derived from: + * arch/arm/kernel/leds-footbridge.c + * Copyright (C) 1998-1999 Russell King + * + * DIGITAL Shark LED control routines. + * + * The leds use is as follows: + * - Green front - toggles state every 50 timer interrupts + * - Amber front - Unused, this is a dual color led (Amber/Green) + * - Amber back - On if system is not idle + * + * Changelog: + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 +static char led_state; +static short hw_led_state; +static short saved_state; + +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; + +short sequoia_read(int addr) { + outw(addr,0x24); + return inw(0x26); +} + +void sequoia_write(short value,short addr) { + outw(addr,0x24); + outw(value,0x26); +} + +static void sequoia_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + hw_led_state = sequoia_read(0x09); + + switch (evt) { + case led_start: + hw_led_state |= SEQUOIA_LED_GREEN; + hw_led_state |= SEQUOIA_LED_AMBER; +#ifdef CONFIG_LEDS_CPU + hw_led_state |= SEQUOIA_LED_BACK; +#else + hw_led_state &= ~SEQUOIA_LED_BACK; +#endif + led_state |= LED_STATE_ENABLED; + break; + + case led_stop: + hw_led_state &= ~SEQUOIA_LED_BACK; + hw_led_state |= SEQUOIA_LED_GREEN; + hw_led_state |= SEQUOIA_LED_AMBER; + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + saved_state = hw_led_state; + hw_led_state &= ~SEQUOIA_LED_BACK; + hw_led_state |= SEQUOIA_LED_GREEN; + hw_led_state |= SEQUOIA_LED_AMBER; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = saved_state; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= SEQUOIA_LED_GREEN; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~SEQUOIA_LED_BACK; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= SEQUOIA_LED_BACK; + break; +#endif + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~SEQUOIA_LED_GREEN; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= SEQUOIA_LED_GREEN; + break; + + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~SEQUOIA_LED_AMBER; + break; + + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= SEQUOIA_LED_AMBER; + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= SEQUOIA_LED_BACK; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~SEQUOIA_LED_BACK; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + sequoia_write(hw_led_state,0x09); + + spin_unlock_irqrestore(&leds_lock, flags); +} + +static int __init leds_init(void) +{ + extern void (*leds_event)(led_event_t); + short temp; + + leds_event = sequoia_leds_event; + + /* Make LEDs independent of power-state */ + request_region(0x24,4,"sequoia"); + temp = sequoia_read(0x09); + temp |= 1<<10; + sequoia_write(temp,0x09); + leds_event(led_start); + return 0; +} + +__initcall(leds_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mach-shark/mm.c linux.ac/arch/arm/mach-shark/mm.c --- linux.vanilla/arch/arm/mach-shark/mm.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mach-shark/mm.c Sat Apr 14 01:16:46 2001 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-shark/mm.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,8 +19,6 @@ static struct map_desc shark_io_desc[] __initdata = { { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - { FB_BASE , FB_START , FB_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - { FBREG_BASE , FBREG_START , FBREG_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, LAST_DESC }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/Makefile linux.ac/arch/arm/mm/Makefile --- linux.vanilla/arch/arm/mm/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/Makefile Sat Apr 14 01:16:46 2001 @@ -13,13 +13,22 @@ # Object file lists. -obj-y := extable.o fault-common.o fault-$(PROCESSOR).o init.o \ - mm-$(PROCESSOR).o small_page.o +obj-y := init.o obj-m := obj-n := obj- := export-objs := proc-syms.o +cpu32-y := consistent.o fault-armv.o ioremap.o mm-armv.o +cpu32-$(CONFIG_MODULES) += proc-syms.o + +obj-y += extable.o fault-common.o +obj-$(CONFIG_CPU_26) += fault-armo.o mm-armo.o small_page.o +obj-$(CONFIG_CPU_32) += $(cpu32-y) + +obj-$(CONFIG_DISCONTIGMEM) += discontig.o + +# Select the processor-specific files p-$(CONFIG_CPU_26) += proc-arm2,3.o p-$(CONFIG_CPU_ARM610) += proc-arm6,7.o p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o @@ -29,11 +38,6 @@ p-$(CONFIG_CPU_SA110) += proc-sa110.o p-$(CONFIG_CPU_SA1100) += proc-sa110.o -obj-$(CONFIG_CPU_32) += consistent.o ioremap.o -ifeq ($(CONFIG_CPU_32),y) -obj-$(CONFIG_MODULES) += proc-syms.o -endif - # Integrator follows "new style" # Soon, others will do too, and we can get rid of this MMMACH := mm-$(MACHINE).c @@ -46,10 +50,4 @@ include $(TOPDIR)/Rules.make # Special dependencies -proc-arm2,3.o: ../lib/constants.h -proc-arm6,7.o: ../lib/constants.h -proc-arm720.o: ../lib/constants.h -proc-arm920.o: ../lib/constants.h -proc-arm10.o: ../lib/constants.h -proc-sa110.o: ../lib/constants.h - +$(p-y): $(TOPDIR)/include/asm-arm/constants.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/consistent.c linux.ac/arch/arm/mm/consistent.c --- linux.vanilla/arch/arm/mm/consistent.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/consistent.c Sat Apr 14 01:16:46 2001 @@ -34,9 +34,9 @@ */ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) { - int order; - unsigned long page; - void *ret; + struct page *page, *end, *free; + unsigned long order; + void *ret, *virt; if (in_interrupt()) BUG(); @@ -44,37 +44,47 @@ size = PAGE_ALIGN(size); order = get_order(size); - page = __get_free_pages(gfp, order); + page = alloc_pages(gfp, order); if (!page) goto no_page; - ret = __ioremap(virt_to_phys((void *)page), size, 0); - if (ret) { - /* free wasted pages */ - unsigned long end; - - /* - * we need to ensure that there are no - * cachelines in use, or worse dirty in - * this area. - */ - invalidate_dcache_range(page, page + size); - invalidate_dcache_range((unsigned long)ret, (unsigned long)ret + size); - - *dma_handle = __virt_to_bus(page); - - end = page + (PAGE_SIZE << order); - page += size; - while (page < end) { - free_page(page); - page += PAGE_SIZE; - } - return ret; + /* + * We could do with a page_to_phys and page_to_bus here. + */ + virt = page_address(page); + *dma_handle = virt_to_bus(virt); + ret = __ioremap(virt_to_phys(virt), size, 0); + if (!ret) + goto no_remap; + +#if 0 /* ioremap_does_flush_cache_all */ + /* + * we need to ensure that there are no cachelines in use, or + * worse dirty in this area. Really, we don't need to do + * this since __ioremap does a flush_cache_all() anyway. --rmk + */ + invalidate_dcache_range(virt, virt + size); +#endif + + /* + * free wasted pages. We skip the first page since + * we know that it will have count = 1 and won't + * require freeing. + */ + page = virt_to_page(virt); + free = page + (size >> PAGE_SHIFT); + end = page + (1 << order); + + while (++page < end) { + set_page_count(page, 1); + if (page >= free) + __free_page(page); } + return ret; - free_pages(page, order); +no_remap: + __free_pages(page, order); no_page: - BUG(); return NULL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/fault-armv.c linux.ac/arch/arm/mm/fault-armv.c --- linux.vanilla/arch/arm/mm/fault-armv.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/fault-armv.c Sat Apr 14 01:16:46 2001 @@ -2,7 +2,7 @@ * linux/arch/arm/mm/fault-armv.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995-1999 Russell King + * Modifications for ARM processor (c) 1995-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -29,7 +29,13 @@ extern void die_if_kernel(const char *str, struct pt_regs *regs, int err); extern void show_pte(struct mm_struct *mm, unsigned long addr); -extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs); +extern int do_page_fault(unsigned long addr, int error_code, + struct pt_regs *regs); +extern int do_translation_fault(unsigned long addr, int error_code, + struct pt_regs *regs); +extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm, + unsigned long addr, int error_code, + struct pt_regs *regs); #ifdef CONFIG_ALIGNMENT_TRAP /* @@ -37,12 +43,11 @@ * /proc/sys/debug/alignment, modified and integrated into * Linux 2.1 by Russell King * + * Speed optimisations and better fault handling by Russell King. + * * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet. Also, * it seems to give a severe performance impact (1 abort/ms - NW runs at * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS. - * - * IMHO, I don't think that the trap handler is advantageous on ARM6,7 - * processors (they'll run like an ARM3). We'll see. */ #define CODING_BITS(i) (i & 0x0e000000) @@ -115,91 +120,323 @@ __initcall(alignment_init); #endif /* CONFIG_SYSCTL */ +union offset_union { + unsigned long un; + signed long sn; +}; + +#define TYPE_ERROR 0 +#define TYPE_FAULT 1 +#define TYPE_LDST 2 +#define TYPE_DONE 3 + +#define get8_unaligned_check(val,addr,err) \ + __asm__( \ + "1: ldrb %1, [%2]\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %0, #1\n" \ + " b 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (val), "=r" (addr) \ + : "0" (err), "2" (addr)) + +#define get8t_unaligned_check(val,addr,err) \ + __asm__( \ + "1: ldrbt %1, [%2]\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %0, #1\n" \ + " b 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (val), "=r" (addr) \ + : "0" (err), "2" (addr)) + +#define get16_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + get8_unaligned_check(val,a,err); \ + get8_unaligned_check(v,a,err); \ + val |= v << 8; \ + if (err) \ + goto fault; \ + } while (0) + +#define put16_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v = val, a = addr; \ + __asm__( \ + "1: strb %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "2: strb %1, [%2]\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "4: mov %0, #1\n" \ + " b 3b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 4b\n" \ + " .long 2b, 4b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (v), "=&r" (a) \ + : "0" (err), "1" (v), "2" (a)); \ + if (err) \ + goto fault; \ + } while (0) + +#define __put32_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v = val, a = addr; \ + __asm__( \ + "1: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "2: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "3: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "4: "ins" %1, [%2]\n" \ + "5:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "6: mov %0, #1\n" \ + " b 5b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 6b\n" \ + " .long 2b, 6b\n" \ + " .long 3b, 6b\n" \ + " .long 4b, 6b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (v), "=&r" (a) \ + : "0" (err), "1" (v), "2" (a)); \ + if (err) \ + goto fault; \ + } while (0) + +#define get32_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + get8_unaligned_check(val,a,err); \ + get8_unaligned_check(v,a,err); \ + val |= v << 8; \ + get8_unaligned_check(v,a,err); \ + val |= v << 16; \ + get8_unaligned_check(v,a,err); \ + val |= v << 24; \ + if (err) \ + goto fault; \ + } while (0) + +#define put32_unaligned_check(val,addr) \ + __put32_unaligned_check("strb", val, addr) + +#define get32t_unaligned_check(val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + get8t_unaligned_check(val,a,err); \ + get8t_unaligned_check(v,a,err); \ + val |= v << 8; \ + get8t_unaligned_check(v,a,err); \ + val |= v << 16; \ + get8t_unaligned_check(v,a,err); \ + val |= v << 24; \ + if (err) \ + goto fault; \ + } while (0) + +#define put32t_unaligned_check(val,addr) \ + __put32_unaligned_check("strbt", val, addr) + +static void +do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset) +{ + if (!LDST_U_BIT(instr)) + offset.un = -offset.un; + + if (!LDST_P_BIT(instr)) + addr += offset.un; + + if (!LDST_P_BIT(instr) || LDST_W_BIT(instr)) + regs->uregs[RN_BITS(instr)] = addr; +} + static int -do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) +do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) { - unsigned int instr, rd, rn, correction, nr_regs, regbits; - unsigned long eaddr; - union { unsigned long un; signed long sn; } offset; + unsigned int rd = RD_BITS(instr); - if (user_mode(regs)) { - set_cr(cr_no_alignment); - ai_user += 1; - return 0; - } + if ((instr & 0x01f00ff0) == 0x01000090) + goto swp; - ai_sys += 1; + if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0) + goto bad; + + ai_half += 1; + + if (LDST_L_BIT(instr)) { + unsigned long val; + get16_unaligned_check(val, addr); + + /* signed half-word? */ + if (instr & 0x40) + val = (signed long)((signed short) val); + + regs->uregs[rd] = val; + } else + put16_unaligned_check(regs->uregs[rd], addr); + + return TYPE_LDST; + +swp: + printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); +bad: + return TYPE_ERROR; + +fault: + return TYPE_FAULT; +} + +static int +do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd = RD_BITS(instr); + + ai_word += 1; + + if (!LDST_P_BIT(instr) && LDST_W_BIT(instr)) + goto trans; + + if (LDST_L_BIT(instr)) + get32_unaligned_check(regs->uregs[rd], addr); + else + put32_unaligned_check(regs->uregs[rd], addr); + return TYPE_LDST; + +trans: + if (LDST_L_BIT(instr)) + get32t_unaligned_check(regs->uregs[rd], addr); + else + put32t_unaligned_check(regs->uregs[rd], addr); + return TYPE_LDST; + +fault: + return TYPE_FAULT; +} + +static int +do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd, rn, correction, nr_regs, regbits; + unsigned long eaddr; - instr = *(unsigned long *)instruction_pointer(regs); correction = 4; /* sometimes 8 on ARMv3 */ - regs->ARM_pc += correction + 4; + regs->ARM_pc += correction; rd = RD_BITS(instr); rn = RN_BITS(instr); eaddr = regs->uregs[rn]; - switch(CODING_BITS(instr)) { - case 0x00000000: - if ((instr & 0x0ff00ff0) == 0x01000090) { - ai_skipped += 1; - printk(KERN_ERR "Unaligned trap: not handling swp instruction\n"); - return 1; - } + if (LDM_S_BIT(instr)) + goto bad; - if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) { - ai_half += 1; - if (LDSTH_I_BIT(instr)) - offset.un = (instr & 0xf00) >> 4 | (instr & 15); - else - offset.un = regs->uregs[RM_BITS(instr)]; - - if (LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - } + ai_multi += 1; + + for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1) + nr_regs += 4; - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) - printk(KERN_ERR "LDRHSTRH: PC = %08lx, instr = %08x, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); - - if (LDST_L_BIT(instr)) - regs->uregs[rd] = get_unaligned((unsigned short *)eaddr); - else - put_unaligned(regs->uregs[rd], (unsigned short *)eaddr); - - /* signed half-word? */ - if (instr & 0x40) - regs->uregs[rd] = (long)((short) regs->uregs[rd]); - - if (!LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - regs->uregs[rn] = eaddr; - } else if (LDST_W_BIT(instr)) - regs->uregs[rn] = eaddr; - break; + if (!LDST_U_BIT(instr)) + eaddr -= nr_regs; + + /* + * This is a "hint" - we already have eaddr worked out by the + * processor for us. + */ + if (addr != eaddr) + printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, " + "addr = %08lx, eaddr = %08lx\n", + instruction_pointer(regs), instr, addr, eaddr); + + if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) || + (LDST_U_BIT(instr) && LDST_P_BIT(instr))) + eaddr += 4; + + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + get32_unaligned_check(regs->uregs[rd], eaddr); + if (rd == 15) + correction = 0; + } else + put32_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; } - default: - ai_skipped += 1; - panic("Alignment trap: not handling instruction %08X at %08lX", - instr, regs->ARM_pc - correction - 4); + if (LDST_W_BIT(instr)) { + if (LDST_P_BIT(instr) && !LDST_U_BIT(instr)) + eaddr -= nr_regs; + else if (LDST_P_BIT(instr)) + eaddr -= 4; + else if (!LDST_U_BIT(instr)) + eaddr -= 4 + nr_regs; + regs->uregs[rn] = eaddr; + } + regs->ARM_pc -= correction; + return TYPE_DONE; + +fault: + return TYPE_FAULT; + +bad: + printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); + return TYPE_ERROR; +} + +static int +do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) +{ + union offset_union offset; + unsigned long instr, instrptr; + int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); + unsigned int type; + + if (user_mode(regs)) + goto user; + + ai_sys += 1; + + instrptr = instruction_pointer(regs); + instr = *(unsigned long *)instrptr; + + regs->ARM_pc += 4; + + switch (CODING_BITS(instr)) { + case 0x00000000: /* ldrh or strh */ + if (LDSTH_I_BIT(instr)) + offset.un = (instr & 0xf00) >> 4 | (instr & 15); + else + offset.un = regs->uregs[RM_BITS(instr)]; + handler = do_alignment_ldrhstrh; break; - case 0x04000000: + case 0x04000000: /* ldr or str immediate */ offset.un = OFFSET_BITS(instr); - goto ldr_str; + handler = do_alignment_ldrstr; + break; - case 0x06000000: + case 0x06000000: /* ldr or str register */ offset.un = regs->uregs[RM_BITS(instr)]; if (IS_SHIFT(instr)) { @@ -229,97 +466,49 @@ break; } } - - ldr_str: - ai_word += 1; - if (LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - } else { - if (LDST_W_BIT(instr)) { - printk(KERN_ERR "Not handling ldrt/strt correctly\n"); - return 1; - } - } - - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) - printk(KERN_ERR "LDRSTR: PC = %08lx, instr = %08x, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); - - if (LDST_L_BIT(instr)) { - regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); - if (rd == 15) - correction = 0; - } else - put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); - - if (!LDST_P_BIT(instr)) { - if (LDST_U_BIT(instr)) - eaddr += offset.un; - else - eaddr -= offset.un; - - regs->uregs[rn] = eaddr; - } else if (LDST_W_BIT(instr)) - regs->uregs[rn] = eaddr; + handler = do_alignment_ldrstr; break; - case 0x08000000: - if (LDM_S_BIT(instr)) - panic("Alignment trap: not handling LDM with s-bit\n"); - ai_multi += 1; - - for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1) - nr_regs += 4; + case 0x08000000: /* ldm or stm */ + handler = do_alignment_ldmstm; + break; - if (!LDST_U_BIT(instr)) - eaddr -= nr_regs; + default: + goto bad; + } - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) - printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08x, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); + type = handler(addr, instr, regs); - if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) || - (LDST_U_BIT(instr) && LDST_P_BIT(instr))) - eaddr += 4; + if (type == TYPE_ERROR || type == TYPE_FAULT) + goto bad_or_fault; - for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) - if (regbits & 1) { - if (LDST_L_BIT(instr)) { - regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); - if (rd == 15) - correction = 0; - } else - put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); - eaddr += 4; - } + if (type == TYPE_LDST) + do_alignment_finish_ldst(addr, instr, regs, offset); - if (LDST_W_BIT(instr)) { - if (LDST_P_BIT(instr) && !LDST_U_BIT(instr)) - eaddr -= nr_regs; - else if (LDST_P_BIT(instr)) - eaddr -= 4; - else if (!LDST_U_BIT(instr)) - eaddr -= 4 + nr_regs; - regs->uregs[rn] = eaddr; - } - break; - } + return 0; - regs->ARM_pc -= correction; +bad_or_fault: + if (type == TYPE_ERROR) + goto bad; + regs->ARM_pc -= 4; + /* + * We got a fault - fix it up, or die. + */ + do_bad_area(current, current->mm, addr, error_code, regs); + return 0; +bad: + /* + * Oops, we didn't handle the instruction. + */ + printk(KERN_ERR "Alignment trap: not handling instruction " + "%08lx at [<%08lx>]", instr, instrptr); + ai_skipped += 1; + return 1; + +user: + set_cr(cr_no_alignment); + ai_user += 1; return 0; } @@ -332,35 +521,13 @@ /* * Some section permission faults need to be handled gracefully, for * instance, when they happen due to a __{get,put}_user during an oops). - * In this case, we should return an error to the __{get,put}_user caller - * instead of causing another oops. We should also fixup this fault as - * the user could pass a pointer to a section to the kernel. */ static int do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) { - unsigned long fixup; - - if (user_mode(regs)) { -#ifdef CONFIG_DEBUG_USER - printk("%s: permission fault on section, " - "address=0x%08lx, code %d\n", - current->comm, addr, error_code); -#endif - goto fail; - } - - fixup = search_exception_table(instruction_pointer(regs)); - if (fixup != 0) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); -#endif - regs->ARM_pc = fixup; - return 0; - } -fail: - return 1; /* not fixed up */ + struct task_struct *tsk = current; + do_bad_area(tsk, tsk->active_mm, addr, error_code, regs); + return 0; } static const struct fsr_info { @@ -369,17 +536,17 @@ char *name; } fsr_info[] = { { NULL, SIGSEGV, "vector exception" }, - { do_alignment, SIGBUS, "alignment exception" }, + { do_alignment, SIGILL, "alignment exception" }, { NULL, SIGKILL, "terminal exception" }, - { do_alignment, SIGBUS, "alignment exception" }, + { do_alignment, SIGILL, "alignment exception" }, { NULL, SIGBUS, "external abort on linefetch" }, - { do_page_fault, SIGSEGV, "page fault" }, + { do_translation_fault, SIGSEGV, "section translation fault" }, { NULL, SIGBUS, "external abort on linefetch" }, - { do_page_fault, SIGSEGV, "page fault" }, + { do_page_fault, SIGSEGV, "page translation fault" }, { NULL, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "domain fault" }, + { NULL, SIGSEGV, "section domain fault" }, { NULL, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "domain fault" }, + { NULL, SIGSEGV, "page domain fault" }, { NULL, SIGBUS, "external abort on translation" }, { do_sect_fault, SIGSEGV, "section permission fault" }, { NULL, SIGBUS, "external abort on translation" }, @@ -398,7 +565,7 @@ if (addr == regs->ARM_pc) goto sa1_weirdness; #endif -#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP) +#if defined(CONFIG_CPU_ARM720) && defined(CONFIG_ALIGNMENT_TRAP) if (addr & 3 && (fsr & 13) != 1) goto arm720_weirdness; #endif @@ -410,7 +577,6 @@ return; bad: force_sig(inf->sig, current); - printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n", inf->name, fsr, addr); show_pte(current->mm, addr); @@ -431,7 +597,7 @@ goto bad; return; #endif -#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP) +#if defined(CONFIG_CPU_ARM720) && defined(CONFIG_ALIGNMENT_TRAP) arm720_weirdness: if (!user_mode(regs)) { unsigned long instr; @@ -462,6 +628,6 @@ asmlinkage int do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { - do_page_fault(addr, 0, regs); + do_translation_fault(addr, 0, regs); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/fault-common.c linux.ac/arch/arm/mm/fault-common.c --- linux.vanilla/arch/arm/mm/fault-common.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mm/fault-common.c Sat Apr 14 01:16:46 2001 @@ -2,7 +2,7 @@ * linux/arch/arm/mm/fault-common.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995-1999 Russell King + * Modifications for ARM processor (c) 1995-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -93,8 +93,82 @@ printk("\n"); } +/* + * Oops. The kernel tried to access some page that wasn't present. + */ +static void +__do_kernel_fault(struct mm_struct *mm, unsigned long addr, int error_code, + struct pt_regs *regs) +{ + unsigned long fixup; + + /* + * Are we prepared to handle this kernel fault? + */ + if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { +#ifdef DEBUG + printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", + tsk->comm, regs->ARM_pc, addr, fixup); +#endif + regs->ARM_pc = fixup; + return; + } + + /* + * No handler, we'll have to terminate things with extreme prejudice. + */ + printk(KERN_ALERT + "Unable to handle kernel %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "paging request", addr); + + show_pte(mm, addr); + die("Oops", regs, error_code); + do_exit(SIGKILL); +} + +/* + * Something tried to access memory that isn't in our memory map.. + * User mode accesses just cause a SIGSEGV + */ +static void +__do_user_fault(struct task_struct *tsk, unsigned long addr, int error_code, + int code, struct pt_regs *regs) +{ + struct siginfo si; + +#ifdef CONFIG_DEBUG_USER + printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " + "lr=0x%08lx (bad address=0x%08lx, code %d)\n", + tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code); +#endif + + tsk->thread.address = addr; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = code; + si.si_addr = (void *)addr; + force_sig_info(SIGSEGV, &si, tsk); +} + +void +do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, + int error_code, struct pt_regs *regs) +{ + /* + * If we are in kernel mode at this point, we + * have no context to handle this fault with. + */ + if (user_mode(regs)) + __do_user_fault(tsk, addr, error_code, SEGV_MAPERR, regs); + else + __do_kernel_fault(mm, addr, error_code, regs); +} + static int -__do_page_fault(struct mm_struct *mm, unsigned long addr, int mode, +__do_page_fault(struct mm_struct *mm, unsigned long addr, int error_code, struct task_struct *tsk) { struct vm_area_struct *vma; @@ -112,7 +186,7 @@ * memory access, so we can handle it. */ good_area: - if (READ_FAULT(mode)) /* read? */ + if (READ_FAULT(error_code)) /* read? */ mask = VM_READ|VM_EXEC; else mask = VM_WRITE; @@ -127,7 +201,7 @@ * than endlessly redo the fault. */ survive: - fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(mode)); + fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(error_code)); /* * Handle the "normal" cases first - successful and sigbus @@ -161,62 +235,16 @@ return fault; } -static int __do_vmalloc_fault(unsigned long addr, struct mm_struct *mm) -{ - /* Synchronise this task's top level page-table - * with the 'reference' page table. - */ - int offset = __pgd_offset(addr); - pgd_t *pgd, *pgd_k; - pmd_t *pmd, *pmd_k; - - pgd_k = init_mm.pgd + offset; - if (!pgd_present(*pgd_k)) - goto bad_area; - - pgd = mm->pgd + offset; -#if 0 /* note that we are two-level */ - if (!pgd_present(*pgd)) - set_pgd(pgd, *pgd_k); -#endif - - pmd_k = pmd_offset(pgd_k, addr); - if (pmd_none(*pmd_k)) - goto bad_area; - - pmd = pmd_offset(pgd, addr); - if (!pmd_none(*pmd)) - goto bad_area; - set_pmd(pmd, *pmd_k); - return 1; - -bad_area: - return -2; -} - -int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) +int do_page_fault(unsigned long addr, int error_code, struct pt_regs *regs) { struct task_struct *tsk; struct mm_struct *mm; - unsigned long fixup; int fault; tsk = current; mm = tsk->mm; /* - * We fault-in kernel-space virtual memory on-demand. The - * 'reference' page table is init_mm.pgd. - * - * NOTE! We MUST NOT take any locks for this case. We may - * be in an interrupt or a critical region, and should - * only copy the information from the master page table, - * nothing more. - */ - if (addr >= TASK_SIZE) - goto vmalloc_fault; - - /* * If we're in an interrupt or have no user * context, we must not take the fault.. */ @@ -224,10 +252,9 @@ goto no_context; down_read(&mm->mmap_sem); - fault = __do_page_fault(mm, addr, mode, tsk); + fault = __do_page_fault(mm, addr, error_code, tsk); up_read(&mm->mmap_sem); -ret: /* * Handle the "normal" case first */ @@ -255,28 +282,9 @@ */ printk("VM: killing process %s\n", tsk->comm); do_exit(SIGKILL); - } else { - /* - * Something tried to access memory that isn't in our memory map.. - * User mode accesses just cause a SIGSEGV - */ - struct siginfo si; - -#ifdef CONFIG_DEBUG_USER - printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " - "lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); -#endif - - tsk->thread.address = addr; - tsk->thread.error_code = mode; - tsk->thread.trap_no = 14; - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = fault == -1 ? SEGV_ACCERR : SEGV_MAPERR; - si.si_addr = (void *)addr; - force_sig_info(SIGSEGV, &si, tsk); - } + } else + __do_user_fault(tsk, addr, error_code, fault == -1 ? + SEGV_ACCERR : SEGV_MAPERR, regs); return 0; @@ -290,7 +298,7 @@ * or user mode. */ tsk->thread.address = addr; - tsk->thread.error_code = mode; + tsk->thread.error_code = error_code; tsk->thread.trap_no = 14; force_sig(SIGBUS, tsk); @@ -299,32 +307,64 @@ return 0; no_context: - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); + __do_kernel_fault(mm, addr, error_code, regs); + return 0; +} + +/* + * First Level Translation Fault Handler + * + * We enter here because the first level page table doesn't contain + * a valid entry for the address. + * + * If the address is in kernel space (>= TASK_SIZE), then we are + * probably faulting in the vmalloc() area. + * + * If the init_task's first level page tables contains the relevant + * entry, we copy the it to this task. If not, we send the process + * a signal, fixup the exception, or oops the kernel. + * + * NOTE! We MUST NOT take any locks for this case. We may be in an + * interrupt or a critical region, and should only copy the information + * from the master page table, nothing more. + */ +int do_translation_fault(unsigned long addr, int error_code, struct pt_regs *regs) +{ + struct task_struct *tsk; + struct mm_struct *mm; + int offset; + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + + if (addr < TASK_SIZE) + return do_page_fault(addr, error_code, regs); + + tsk = current; + mm = tsk->active_mm; + + offset = __pgd_offset(addr); + + pgd_k = init_mm.pgd + offset; + pgd = mm->pgd + offset; + + if (pgd_none(*pgd_k)) + goto bad_area; + +#if 0 /* note that we are two-level */ + if (!pgd_present(*pgd)) + set_pgd(pgd, *pgd_k); #endif - regs->ARM_pc = fixup; - return 0; - } - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - printk(KERN_ALERT - "Unable to handle kernel %s at virtual address %08lx\n", - (addr < PAGE_SIZE) ? "NULL pointer dereference" : - "paging request", addr); + pmd_k = pmd_offset(pgd_k, addr); + pmd = pmd_offset(pgd, addr); - show_pte(mm, addr); - die("Oops", regs, mode); - do_exit(SIGKILL); + if (pmd_none(*pmd_k)) + goto bad_area; + set_pmd(pmd, *pmd_k); return 0; -vmalloc_fault: - fault = __do_vmalloc_fault(addr, mm); - goto ret; +bad_area: + do_bad_area(tsk, mm, addr, error_code, regs); + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/init.c linux.ac/arch/arm/mm/init.c --- linux.vanilla/arch/arm/mm/init.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/init.c Sat Apr 14 01:16:46 2001 @@ -33,6 +33,9 @@ #include #include +#include + +mmu_gather_t mmu_gathers[NR_CPUS]; #ifndef CONFIG_DISCONTIGMEM #define NR_NODES 1 @@ -59,52 +62,10 @@ static struct meminfo meminfo __initdata = { 0, }; /* - * empty_bad_page is the page that is used for page faults when - * linux is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode - * unused etc.. - * - * empty_bad_pte_table is the accompanying page-table: it is - * initialized to point to BAD_PAGE entries. - * * empty_zero_page is a special page that is used for * zero-initialized data and COW. */ struct page *empty_zero_page; -struct page *empty_bad_page; -pte_t *empty_bad_pte_table; - -pte_t *get_bad_pte_table(void) -{ - pte_t v; - int i; - - v = pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED)); - - for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(empty_bad_pte_table + i, v); - - return empty_bad_pte_table; -} - -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table())); -} #ifndef CONFIG_NO_PGT_CACHE struct pgtable_cache_struct quicklists; @@ -120,12 +81,12 @@ freed++; } if(pmd_quicklist) { - free_pmd_slow(get_pmd_fast()); + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); freed++; } if(pte_quicklist) { - free_pte_slow(get_pte_fast()); - freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; } } while(pgtable_cache_size > low); } @@ -514,18 +475,15 @@ */ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) { - void *zero_page, *bad_page, *bad_table; + void *zero_page; int node; memcpy(&meminfo, mi, sizeof(meminfo)); /* - * allocate what we need for the bad pages. - * note that we count on this going ok. + * allocate the zero page. Note that we count on this going ok. */ zero_page = alloc_bootmem_low_pages(PAGE_SIZE); - bad_page = alloc_bootmem_low_pages(PAGE_SIZE); - bad_table = alloc_bootmem_low_pages(TABLE_SIZE); /* * initialise the page tables. @@ -586,11 +544,7 @@ * the mem_map is initialised */ memzero(zero_page, PAGE_SIZE); - memzero(bad_page, PAGE_SIZE); - empty_zero_page = virt_to_page(zero_page); - empty_bad_page = virt_to_page(bad_page); - empty_bad_pte_table = ((pte_t *)bad_table) + TABLE_OFFSET; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/ioremap.c linux.ac/arch/arm/mm/ioremap.c --- linux.vanilla/arch/arm/mm/ioremap.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/ioremap.c Sat Apr 14 01:16:46 2001 @@ -44,14 +44,18 @@ end = address + size; if (end > PMD_SIZE) end = PMD_SIZE; + if (address >= end) + BUG(); do { - if (!pte_none(*pte)) + if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); + BUG(); + } set_pte(pte, mk_pte_phys(phys_addr, pgprot)); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; - } while (address < end); + } while (address && (address < end)); } static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, @@ -67,40 +71,50 @@ end = PGDIR_SIZE; phys_addr -= address; + if (address >= end) + BUG(); + pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, pgprot); address = (address + PMD_SIZE) & PMD_MASK; pmd++; - } while (address < end); + } while (address && (address < end)); return 0; } static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; 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 (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) - return -ENOMEM; - set_pgdir(address, *dir); + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; - } + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); - return 0; + return error; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-armo.c linux.ac/arch/arm/mm/mm-armo.c --- linux.vanilla/arch/arm/mm/mm-armo.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-armo.c Sat Apr 14 01:16:46 2001 @@ -22,120 +22,98 @@ #include #define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) -#define PGD_TABLE_SIZE (PTRS_PER_PGD * BYTES_PER_PTR) +kmem_cache_t *pte_cache, *pgd_cache; int page_nr; -extern unsigned long get_page_2k(int prio); -extern void free_page_2k(unsigned long); -extern pte_t *get_bad_pte_table(void); - /* * Allocate a page table. Note that we place the MEMC * table before the page directory. This means we can * easily get to both tightly-associated data structures * with a single pointer. - * - * We actually only need 1152 bytes, 896 bytes is wasted. - * We could try to fit 7 PTEs into that slot somehow. */ -static inline void *alloc_pgd_table(int priority) +static inline pgd_t *alloc_pgd_table(int priority) { - unsigned long pg2k; + void *pg2k = kmem_cache_alloc(pgd_cache, GFP_KERNEL); - pg2k = get_page_2k(priority); if (pg2k) pg2k += MEMC_TABLE_SIZE; - return (void *)pg2k; + return (pgd_t *)pg2k; } void free_pgd_slow(pgd_t *pgd) { unsigned long tbl = (unsigned long)pgd; + /* + * CHECKME: are we leaking pte tables here??? + */ + tbl -= MEMC_TABLE_SIZE; - free_page_2k(tbl); + + kmem_cache_free(pgd_cache, (void *)tbl); } -/* - * FIXME: the following over-allocates by 1600% - */ -static inline void *alloc_pte_table(int size, int prio) +pgd_t *get_pgd_slow(struct mm_struct *mm) { - if (size != 128) - printk("invalid table size\n"); - return (void *)get_page_2k(prio); -} - -void free_pte_slow(pte_t *pte) -{ - unsigned long tbl = (unsigned long)pte; - free_page_2k(tbl); -} - -pgd_t *get_pgd_slow(void) -{ - pgd_t *pgd = (pgd_t *)alloc_pgd_table(GFP_KERNEL); - pmd_t *new_pmd; - - if (pgd) { - pgd_t *init = pgd_offset(&init_mm, 0); - - memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - - /* - * On ARM, first page must always be allocated - */ - if (!pmd_alloc(pgd, 0)) - goto nomem; - else { - pmd_t *old_pmd = pmd_offset(init, 0); - new_pmd = pmd_offset(pgd, 0); - - if (!pte_alloc(new_pmd, 0)) - goto nomem_pmd; - else { - pte_t *new_pte = pte_offset(new_pmd, 0); - pte_t *old_pte = pte_offset(old_pmd, 0); - - set_pte (new_pte, *old_pte); - } - } - /* update MEMC tables */ - cpu_memc_update_all(pgd); - } - return pgd; + pgd_t *new_pgd, *init_pgd; + pmd_t *new_pmd, *init_pmd; + pte_t *new_pte, *init_pte; + + new_pgd = alloc_pgd_table(GFP_KERNEL); + if (!new_pgd) + goto no_pgd; + + /* + * This lock is here just to satisfy pmd_alloc and pte_lock + */ + spin_lock(&mm->page_table_lock); + + /* + * On ARM, first page must always be allocated since it contains + * the machine vectors. + */ + new_pmd = pmd_alloc(mm, new_pgd, 0); + if (!new_pmd) + goto no_pmd; -nomem_pmd: + new_pte = pte_alloc(mm, new_pmd, 0); + if (!new_pte) + goto no_pte; + + init_pgd = pgd_offset_k(0); + init_pmd = pmd_offset(init_pgd, 0); + init_pte = pte_offset(init_pmd, 0); + + set_pte(new_pte, *init_pte); + + /* + * most of the page table entries are zeroed + * wne the table is created. + */ + memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + + spin_unlock(&mm->page_table_lock); + + /* update MEMC tables */ + cpu_memc_update_all(new_pgd); + return new_pgd; + +no_pte: + spin_unlock(&mm->page_table_lock); pmd_free(new_pmd); -nomem: - free_pgd_slow(pgd); + free_pgd_slow(new_pgd); return NULL; -} -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; +no_pmd: + spin_unlock(&mm->page_table_lock); + free_pgd_slow(new_pgd); + return NULL; - pte = (pte_t *)alloc_pte_table(PTRS_PER_PTE * sizeof(pte_t), GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, PTRS_PER_PTE * sizeof(pte_t)); - set_pmd(pmd, mk_user_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); - return NULL; - } - free_pte_slow(pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; +no_pgd: + return NULL; } /* @@ -160,7 +138,7 @@ pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY); - set_pmd(pmd_offset(swapper_pg_dir, 0), mk_kernel_pmd(pte)); + pmd_populate(&init_mm, pmd_offset(swapper_pg_dir, 0), pte); for (i = 1; i < PTRS_PER_PGD; i++) pgd_val(swapper_pg_dir[i]) = 0; @@ -176,4 +154,31 @@ */ void __init create_memmap_holes(struct meminfo *mi) { +} + +static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +{ + memzero(pte, sizeof(pte_t) * PTRS_PER_PTE); +} + +static void pgd_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +{ + pgd_t *pgd = (pte + MEMC_TABLE_SIZE); + + memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t)); +} + +void __init pgtable_cache_init(void) +{ + pte_cache = kmem_cache_create("pte-cache", + sizeof(pte_t) * PTRS_PER_PTE, + 0, 0, pte_cache_ctor, NULL); + if (!pte_cache) + BUG(); + + pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE + + sizeof(pgd_t) * PTRS_PER_PGD, + 0, 0, pgd_cache_ctor, NULL); + if (!pgd_cache) + BUG(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-armv.c linux.ac/arch/arm/mm/mm-armv.c --- linux.vanilla/arch/arm/mm/mm-armv.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/mm/mm-armv.c Sat Apr 14 01:16:46 2001 @@ -22,12 +22,6 @@ #include -unsigned long *valid_addr_bitmap; - -extern unsigned long get_page_2k(int priority); -extern void free_page_2k(unsigned long page); -extern pte_t *get_bad_pte_table(void); - /* * These are useful for identifing cache coherency * problems by allowing the cache or the cache and @@ -73,47 +67,68 @@ /* * need to get a 16k page for level 1 */ -pgd_t *get_pgd_slow(void) +pgd_t *get_pgd_slow(struct mm_struct *mm) { - pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2); - pmd_t *new_pmd; + pgd_t *new_pgd, *init_pgd; + pmd_t *new_pmd, *init_pmd; + pte_t *new_pte, *init_pte; + + new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2); + if (!new_pgd) + goto no_pgd; + + memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); + + /* + * This lock is here just to satisfy pmd_alloc and pte_lock + */ + spin_lock(&mm->page_table_lock); - if (pgd) { - pgd_t *init = pgd_offset_k(0); + /* + * On ARM, first page must always be allocated since it contains + * the machine vectors. + */ + new_pmd = pmd_alloc(mm, new_pgd, 0); + if (!new_pmd) + goto no_pmd; + + new_pte = pte_alloc(mm, new_pmd, 0); + if (!new_pte) + goto no_pte; + + init_pgd = pgd_offset_k(0); + init_pmd = pmd_offset(init_pgd, 0); + init_pte = pte_offset(init_pmd, 0); - memzero(pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); - memcpy(pgd + FIRST_KERNEL_PGD_NR, init + FIRST_KERNEL_PGD_NR, + set_pte(new_pte, *init_pte); + + /* + * Copy over the kernel and IO PGD entries + */ + memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); - /* - * FIXME: this should not be necessary - */ - clean_cache_area(pgd, PTRS_PER_PGD * sizeof(pgd_t)); - /* - * On ARM, first page must always be allocated - */ - if (!pmd_alloc(pgd, 0)) - goto nomem; - else { - pmd_t *old_pmd = pmd_offset(init, 0); - new_pmd = pmd_offset(pgd, 0); - - if (!pte_alloc(new_pmd, 0)) - goto nomem_pmd; - else { - pte_t *new_pte = pte_offset(new_pmd, 0); - pte_t *old_pte = pte_offset(old_pmd, 0); + spin_unlock(&mm->page_table_lock); - set_pte(new_pte, *old_pte); - } - } - } - return pgd; + /* + * FIXME: this should not be necessary + */ + clean_cache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); + + return new_pgd; -nomem_pmd: +no_pte: + spin_unlock(&mm->page_table_lock); pmd_free(new_pmd); -nomem: - free_pages((unsigned long)pgd, 2); + free_pages((unsigned long)new_pgd, 2); + return NULL; + +no_pmd: + spin_unlock(&mm->page_table_lock); + free_pages((unsigned long)new_pgd, 2); + return NULL; + +no_pgd: return NULL; } @@ -142,59 +157,6 @@ free_pages((unsigned long) pgd, 2); } -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *)get_page_2k(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); - clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); - pte += PTRS_PER_PTE; - set_pmd(pmd, mk_user_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); - return NULL; - } - free_page_2k((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *)get_page_2k(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); - clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); - pte += PTRS_PER_PTE; - set_pmd(pmd, mk_kernel_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table())); - return NULL; - } - free_page_2k((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -void free_pte_slow(pte_t *pte) -{ - free_page_2k((unsigned long)(pte - PTRS_PER_PTE)); -} - /* * Create a SECTION PGD between VIRT and PHYS in domain * DOMAIN with protection PROT @@ -481,4 +443,42 @@ for (node = 0; node < numnodes; node++) free_unused_memmap_node(node, mi); +} + +/* + * PTE table allocation cache. + * + * This is a move away from our custom 2K page allocator. We now use the + * slab cache to keep track of these objects. + * + * With this, it is questionable as to whether the PGT cache gains us + * anything. We may be better off dropping the PTE stuff from our PGT + * cache implementation. + */ +kmem_cache_t *pte_cache; + +/* + * The constructor gets called for each object within the cache when the + * cache page is created. Note that if slab tries to misalign the blocks, + * we BUG() loudly. + */ +static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +{ + unsigned long block = (unsigned long)pte; + + if (block & 2047) + BUG(); + + memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); + cpu_cache_clean_invalidate_range(block, block + + PTRS_PER_PTE * sizeof(pte_t), 0); +} + +void __init pgtable_cache_init(void) +{ + pte_cache = kmem_cache_create("pte-cache", + 2 * PTRS_PER_PTE * sizeof(pte_t), 0, 0, + pte_cache_ctor, NULL); + if (!pte_cache) + BUG(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-clps7500.c linux.ac/arch/arm/mm/mm-clps7500.c --- linux.vanilla/arch/arm/mm/mm-clps7500.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-clps7500.c Sat Apr 14 01:16:46 2001 @@ -6,6 +6,7 @@ * * Extra MM routines for CL7500 architecture */ +#include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-ebsa110.c linux.ac/arch/arm/mm/mm-ebsa110.c --- linux.vanilla/arch/arm/mm/mm-ebsa110.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-ebsa110.c Thu Jan 1 01:00:00 1970 @@ -1,30 +0,0 @@ -/* - * linux/arch/arm/mm/mm-ebsa110.c - * - * Copyright (C) 1998-1999 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Extra MM routines for the EBSA-110 architecture - */ -#include -#include - -#include -#include -#include - -#include - -static struct map_desc ebsa110_io_desc[] __initdata = { - { IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - LAST_DESC -}; - -void __init ebsa110_map_io(void) -{ - iotable_init(ebsa110_io_desc); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-footbridge.c linux.ac/arch/arm/mm/mm-footbridge.c --- linux.vanilla/arch/arm/mm/mm-footbridge.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-footbridge.c Thu Jan 1 01:00:00 1970 @@ -1,117 +0,0 @@ -/* - * linux/arch/arm/mm/mm-footbridge.c - * - * Copyright (C) 1998-2000 Russell King, Dave Gilbert. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Extra MM routines for the EBSA285 architecture - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -/* - * Common mapping for all systems. Note that the outbound write flush is - * commented out since there is a "No Fix" problem with it. Not mapping - * it means that we have extra bullet protection on our feet. - */ -static struct map_desc fb_common_io_desc[] __initdata = { - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - LAST_DESC -}; - -/* - * The mapping when the footbridge is in host mode. We don't map any of - * this when we are in add-in mode. - */ -static struct map_desc ebsa285_host_io_desc[] __initdata = { -#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, -#endif - LAST_DESC -}; - -/* - * The CO-ebsa285 mapping. - */ -static struct map_desc co285_io_desc[] __initdata = { -#ifdef CONFIG_ARCH_CO285 - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, -#endif - LAST_DESC -}; - -void __init footbridge_map_io(void) -{ - struct map_desc *desc = NULL; - - /* - * Set up the common mapping first; we need this to - * determine whether we're in host mode or not. - */ - iotable_init(fb_common_io_desc); - - /* - * Now, work out what we've got to map in addition on this - * platform. - */ - if (machine_is_co285()) - desc = co285_io_desc; - else if (footbridge_cfn_mode()) - desc = ebsa285_host_io_desc; - - if (desc) - iotable_init(desc); -} - -#ifdef CONFIG_FOOTBRIDGE_ADDIN - -/* - * These two functions convert virtual addresses to PCI addresses and PCI - * addresses to virtual addresses. Note that it is only legal to use these - * on memory obtained via get_free_page or kmalloc. - */ -unsigned long __virt_to_bus(unsigned long res) -{ -#ifdef CONFIG_DEBUG_ERRORS - if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res); - __backtrace(); - } -#endif - return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); -} - -unsigned long __bus_to_virt(unsigned long res) -{ - res -= (*CSR_PCISDRAMBASE & 0xfffffff0); - res += PAGE_OFFSET; - -#ifdef CONFIG_DEBUG_ERRORS - if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res); - __backtrace(); - } -#endif - return res; -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-l7200.c linux.ac/arch/arm/mm/mm-l7200.c --- linux.vanilla/arch/arm/mm/mm-l7200.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/mm-l7200.c Sat Apr 14 01:16:46 2001 @@ -17,6 +17,9 @@ static struct map_desc l7200_io_desc[] __initdata = { { IO_BASE, IO_START, IO_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, { IO_BASE_2, IO_START_2, IO_SIZE_2, DOMAIN_IO, 0, 1 ,0 ,0}, + { AUX_BASE, AUX_START, AUX_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, + { FLASH1_BASE, FLASH1_START, FLASH1_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, + { FLASH2_BASE, FLASH2_START, FLASH2_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, LAST_DESC }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/mm-sa1100.c linux.ac/arch/arm/mm/mm-sa1100.c --- linux.vanilla/arch/arm/mm/mm-sa1100.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mm/mm-sa1100.c Sat Apr 14 01:16:46 2001 @@ -15,9 +15,8 @@ * */ #include -#include +#include #include -#include #include #include @@ -109,22 +108,9 @@ LAST_DESC }; -static struct map_desc thinclient_io_desc[] __initdata = { -#ifdef CONFIG_SA1100_THINCLIENT -#if 0 - { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */ -#else - { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */ -#endif - { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ -#endif - LAST_DESC -}; - -static struct map_desc tifon_io_desc[] __initdata = { -#ifdef CONFIG_SA1100_TIFON - { 0xe8000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xe8800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */ +static struct map_desc sherman_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_SHERMAN + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash*/ #endif LAST_DESC }; @@ -138,9 +124,16 @@ static struct map_desc xp860_io_desc[] __initdata = { #ifdef CONFIG_SA1100_XP860 - { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */ + { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ +#endif + LAST_DESC +}; + +static struct map_desc pangolin_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_PANGOLIN + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ #endif LAST_DESC }; @@ -153,8 +146,6 @@ if (machine_is_assabet()) desc = assabet_io_desc; - else if (machine_is_nanoengine()) - desc = nanoengine_io_desc; else if (machine_is_bitsy()) desc = bitsy_io_desc; else if (machine_is_cerf()) @@ -165,38 +156,21 @@ desc = graphicsclient_io_desc; else if (machine_is_lart()) desc = lart_io_desc; - else if (machine_is_thinclient()) - desc = thinclient_io_desc; - else if (machine_is_tifon()) - desc = tifon_io_desc; + else if (machine_is_nanoengine()) + desc = nanoengine_io_desc; + else if (machine_is_sherman()) + desc = sherman_io_desc; else if (machine_is_victor()) desc = victor_io_desc; else if (machine_is_xp860()) desc = xp860_io_desc; + else if (machine_is_pangolin()) + desc = pangolin_io_desc; if (desc) iotable_init(desc); } - -#ifdef CONFIG_DISCONTIGMEM - -/* - * Our node_data structure for discontigous memory. - * There is 4 possible nodes i.e. the 4 SA1100 RAM banks. - */ - -static bootmem_data_t node_bootmem_data[4]; - -pg_data_t sa1100_node_data[4] = -{ { bdata: &node_bootmem_data[0] }, - { bdata: &node_bootmem_data[1] }, - { bdata: &node_bootmem_data[2] }, - { bdata: &node_bootmem_data[3] } }; - -#endif - - /* * On Assabet, we must probe for the Neponset board *before* paging_init() * has occurred to actually determine the amount of RAM available. To do so, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/proc-sa110.S linux.ac/arch/arm/mm/proc-sa110.S --- linux.vanilla/arch/arm/mm/proc-sa110.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/mm/proc-sa110.S Sat Apr 14 01:16:46 2001 @@ -556,7 +556,7 @@ mov pc, lr /* - * cpu_sa110_arm920_set_pte(ptep, pte) + * cpu_sa110_set_pte(ptep, pte) * * Set a PTE and flush it out */ @@ -737,7 +737,7 @@ b __sa110_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa110_info .long sa110_processor_functions .size __sa110_proc_info, . - __sa110_proc_info @@ -750,7 +750,7 @@ b __sa1100_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa1100_info .long sa1100_processor_functions .size __sa1100_proc_info, . - __sa1100_proc_info @@ -763,7 +763,7 @@ b __sa1100_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa1110_info .long sa1100_processor_functions .size __sa1110_proc_info, . - __sa1110_proc_info diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/mm/small_page.c linux.ac/arch/arm/mm/small_page.c --- linux.vanilla/arch/arm/mm/small_page.c Mon Sep 18 23:15:25 2000 +++ linux.ac/arch/arm/mm/small_page.c Sat Apr 14 01:16:46 2001 @@ -202,17 +202,6 @@ printk("Trying to free free small page from %p\n", __builtin_return_address(0)); } -unsigned long get_page_2k(int priority) -{ - return __get_small_page(priority, orders+0); -} - -void free_page_2k(unsigned long spage) -{ - __free_small_page(spage, orders+0); -} - -#if PAGE_SIZE > 8192 unsigned long get_page_8k(int priority) { return __get_small_page(priority, orders+1); @@ -222,4 +211,3 @@ { __free_small_page(spage, orders+1); } -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/Makefile linux.ac/arch/arm/nwfpe/Makefile --- linux.vanilla/arch/arm/nwfpe/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/arm/nwfpe/Makefile Thu Apr 12 11:48:52 2001 @@ -1,7 +1,7 @@ # # linux/arch/arm/nwfpe/Makefile # -# Copyright (C) 1998, 1999 Philip Blundell +# Copyright (C) 1998, 1999, 2001 Philip Blundell # USE_STANDARD_AS_RULE := true @@ -14,7 +14,7 @@ list-multi := nwfpe.o -obj-$(CONFIG_NWFPE) += nwfpe.o +obj-$(CONFIG_FPE_NWFPE) += nwfpe.o nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ fpmodule.o fpopcode.o softfloat.o \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/config.h linux.ac/arch/arm/nwfpe/config.h --- linux.vanilla/arch/arm/nwfpe/config.h Tue Aug 31 02:15:19 1999 +++ linux.ac/arch/arm/nwfpe/config.h Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ -/* - NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 - - 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 - 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. -*/ - -#ifndef __CONFIG_H__ -#define __CONFIG_H__ - -#if 1 -#define C_SYMBOL_NAME(foo) foo -#else -#define C_SYMBOL_NAME(foo) _##foo -#endif - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/double_cpdo.c linux.ac/arch/arm/nwfpe/double_cpdo.c --- linux.vanilla/arch/arm/nwfpe/double_cpdo.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/double_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough @@ -22,10 +22,6 @@ #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" - -extern FPA11 *fpa11; - -float64 getDoubleConstant(unsigned int); float64 float64_exp(float64 Fm); float64 float64_ln(float64 Fm); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/entry.S linux.ac/arch/arm/nwfpe/entry.S --- linux.vanilla/arch/arm/nwfpe/entry.S Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/entry.S Thu Apr 12 11:48:52 2001 @@ -1,7 +1,7 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 - (c) Philip Blundell 1998-1999 + (c) Rebel.COM, 1998 + (c) 1998, 1999 Philip Blundell Direct questions, comments to Scott Bambrough @@ -86,7 +86,7 @@ ldr r5, [r4, #60] @ get contents of PC; sub r8, r5, #4 -.Lx2: ldrt r0, [r8], #0 @ get actual instruction into r0 +.Lx2: ldrt r0, [r8] @ get actual instruction into r0 emulate: bl EmulateAll @ emulate the instruction cmp r0, #0 @ was emulation successful @@ -115,15 +115,17 @@ mov r0, r6 @ prepare for EmulateAll() b emulate @ if r0 != 0, goto EmulateAll - @ We need to be prepared for the instruction at .Lx1 or .Lx2 - @ to fault. + @ We need to be prepared for the instructions at .Lx1 and .Lx2 + @ to fault. Emit the appropriate exception gunk to fix things up. + @ ??? For some reason, faults can happen at .Lx2 even with a + @ plain LDR instruction. Weird, but it seems harmless. .section .fixup,"ax" - .align -.Lfix: mov pc, r9 + .align 2 +.Lfix: mov pc, r9 @ let the user eat segfaults .previous .section __ex_table,"a" - .align 3 - .long .Lx2, .Lfix + .align 3 .long .Lx1, .Lfix + .long .Lx2, .Lfix .previous diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/entry26.S linux.ac/arch/arm/nwfpe/entry26.S --- linux.vanilla/arch/arm/nwfpe/entry26.S Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/nwfpe/entry26.S Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.COM, 1998 (c) Philip Blundell 1998-1999 Direct questions, comments to Scott Bambrough @@ -84,7 +84,7 @@ beq fpundefinstr @ no, return failure next: - ldrt r6, [r5], #4 @ get the next instruction and +.Lx1: ldrt r6, [r5], #4 @ get the next instruction and @ increment PC and r2, r6, #0x0F000000 @ test for FP insns @@ -110,3 +110,13 @@ adr lr, 1b orr lr, lr, #3 b EmulateAll @ if r0 != 0, goto EmulateAll + +.Lret: b ret_from_exception @ let the user eat segfaults + + @ We need to be prepared for the instruction at .Lx1 to fault. + @ Emit the appropriate exception gunk to fix things up. + .section __ex_table,"a" + .align 3 + .long .Lx1 + ldr lr, [lr, $(.Lret - .Lx1)/4] + .previous diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/extended_cpdo.c linux.ac/arch/arm/nwfpe/extended_cpdo.c --- linux.vanilla/arch/arm/nwfpe/extended_cpdo.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/extended_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough @@ -22,8 +22,6 @@ #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" - -floatx80 getExtendedConstant(unsigned int); floatx80 floatx80_exp(floatx80 Fm); floatx80 floatx80_ln(floatx80 Fm); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11.c linux.ac/arch/arm/nwfpe/fpa11.c --- linux.vanilla/arch/arm/nwfpe/fpa11.c Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpa11.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough @@ -46,8 +46,8 @@ fpa11->fType[i] = typeNone; } - /* FPSR: set system id to FP_EMULATOR, clear all other bits */ - fpa11->fpsr = FP_EMULATOR; + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ + fpa11->fpsr = FP_EMULATOR | BIT_AC; /* FPCR: set SB, AB and DA bits, clear all others */ #if MAINTAIN_FPCR diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11.inl linux.ac/arch/arm/nwfpe/fpa11.inl --- linux.vanilla/arch/arm/nwfpe/fpa11.inl Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpa11.inl Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c linux.ac/arch/arm/nwfpe/fpa11_cpdo.c --- linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/fpa11_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c linux.ac/arch/arm/nwfpe/fpa11_cprt.c --- linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/fpa11_cprt.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 (c) Philip Blundell, 1999 Direct questions, comments to Scott Bambrough diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpmodule.c linux.ac/arch/arm/nwfpe/fpmodule.c --- linux.vanilla/arch/arm/nwfpe/fpmodule.c Tue Nov 28 01:07:59 2000 +++ linux.ac/arch/arm/nwfpe/fpmodule.c Thu Apr 12 11:48:52 2001 @@ -55,6 +55,8 @@ #else #define fp_send_sig send_sig #define kern_fp_enter fp_enter + +extern char fpe_type[]; #endif /* kernel function prototypes required */ @@ -72,24 +74,45 @@ /* Address of user registers on the kernel stack. */ unsigned int *userRegisters; -int __init fpe_init(void) +#ifdef MODULE +/* + * Return 0 if we can be unloaded. This can only happen if + * kern_fp_enter is still pointing at nwfpe_enter + */ +static int fpe_unload(void) +{ + return (kern_fp_enter == nwfpe_enter) ? 0 : 1; +} +#endif + +static int __init fpe_init(void) { - if (sizeof(FPA11) > sizeof(union fp_state)) + if (sizeof(FPA11) > sizeof(union fp_state)) { printk(KERN_ERR "nwfpe: bad structure size\n"); - else { - /* Display title, version and copyright information. */ - printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " - "(c) 1998-1999 Rebel.com\n"); - - /* Save pointer to the old FP handler and then patch ourselves in */ - orig_fp_enter = kern_fp_enter; - kern_fp_enter = nwfpe_enter; + return -EINVAL; } +#ifdef MODULE + if (!mod_member_present(&__this_module, can_unload)) + return -EINVAL; + __this_module.can_unload = fpe_unload; +#else + if (fpe_type[0] && strcmp(fpe_type, "nwfpe")) + return 0; +#endif + + /* Display title, version and copyright information. */ + printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " + "(c) 1998-1999 Rebel.com\n"); + + /* Save pointer to the old FP handler and then patch ourselves in */ + orig_fp_enter = kern_fp_enter; + kern_fp_enter = nwfpe_enter; + return 0; } -void __exit fpe_exit(void) +static void __exit fpe_exit(void) { /* Restore the values we saved earlier. */ kern_fp_enter = orig_fp_enter; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpmodule.inl linux.ac/arch/arm/nwfpe/fpmodule.inl --- linux.vanilla/arch/arm/nwfpe/fpmodule.inl Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpmodule.inl Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* - NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpopcode.c linux.ac/arch/arm/nwfpe/fpopcode.c --- linux.vanilla/arch/arm/nwfpe/fpopcode.c Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/fpopcode.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough @@ -26,7 +26,7 @@ #include "fpmodule.h" #include "fpmodule.inl" -static floatx80 floatx80Constant[] = { +const floatx80 floatx80Constant[] = { { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ @@ -37,7 +37,7 @@ { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ }; -static float64 float64Constant[] = { +const float64 float64Constant[] = { 0x0000000000000000ULL, /* double 0.0 */ 0x3ff0000000000000ULL, /* double 1.0 */ 0x4000000000000000ULL, /* double 2.0 */ @@ -48,7 +48,7 @@ 0x4024000000000000ULL /* double 10.0 */ }; -static float32 float32Constant[] = { +const float32 float32Constant[] = { 0x00000000, /* single 0.0 */ 0x3f800000, /* single 1.0 */ 0x40000000, /* single 2.0 */ @@ -59,21 +59,6 @@ 0x41200000 /* single 10.0 */ }; -floatx80 getExtendedConstant(const unsigned int nIndex) -{ - return floatx80Constant[nIndex]; -} - -float64 getDoubleConstant(const unsigned int nIndex) -{ - return float64Constant[nIndex]; -} - -float32 getSingleConstant(const unsigned int nIndex) -{ - return float32Constant[nIndex]; -} - unsigned int getTransferLength(const unsigned int opcode) { unsigned int nRc; @@ -135,10 +120,10 @@ return(nRc); } -/* contition code lookup table +/* condition code lookup table index into the table is test code: EQ, NE, ... LT, GT, AL, NV bit position in short is condition code: NZCV */ -unsigned short aCC[16] = { +static const unsigned short aCC[16] = { 0xF0F0, // EQ == Z set 0x0F0F, // NE 0xCCCC, // CS == C set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/fpopcode.h linux.ac/arch/arm/nwfpe/fpopcode.h --- linux.vanilla/arch/arm/nwfpe/fpopcode.h Tue Aug 31 02:15:19 1999 +++ linux.ac/arch/arm/nwfpe/fpopcode.h Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough @@ -366,11 +366,25 @@ /* Get the rounding mode from the opcode. */ #define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) -float32 getSingleConstant(const unsigned int nIndex); -float64 getDoubleConstant(const unsigned int nIndex); -floatx80 getExtendedConstant(const unsigned int nIndex); +static inline const floatx80 getExtendedConstant(const unsigned int nIndex) +{ + extern const floatx80 floatx80Constant[]; + return floatx80Constant[nIndex]; +} + +static inline const float64 getDoubleConstant(const unsigned int nIndex) +{ + extern const float64 float64Constant[]; + return float64Constant[nIndex]; +} + +static inline const float32 getSingleConstant(const unsigned int nIndex) +{ + extern const float32 float32Constant[]; + return float32Constant[nIndex]; +} -unsigned int getRegisterCount(const unsigned int opcode); -unsigned int getDestinationSize(const unsigned int opcode); +extern unsigned int getRegisterCount(const unsigned int opcode); +extern unsigned int getDestinationSize(const unsigned int opcode); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/nwfpe/single_cpdo.c linux.ac/arch/arm/nwfpe/single_cpdo.c --- linux.vanilla/arch/arm/nwfpe/single_cpdo.c Thu Oct 21 00:29:08 1999 +++ linux.ac/arch/arm/nwfpe/single_cpdo.c Thu Apr 12 11:48:52 2001 @@ -1,6 +1,6 @@ /* NetWinder Floating Point Emulator - (c) Rebel.com, 1998-1999 + (c) Rebel.COM, 1998,1999 Direct questions, comments to Scott Bambrough @@ -22,8 +22,6 @@ #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" - -float32 getSingleConstant(unsigned int); float32 float32_exp(float32 Fm); float32 float32_ln(float32 Fm); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/tools/getconstants.c linux.ac/arch/arm/tools/getconstants.c --- linux.vanilla/arch/arm/tools/getconstants.c Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/tools/getconstants.c Thu Apr 12 11:48:52 2001 @@ -14,14 +14,8 @@ #include #include -/* - * Make sure that the compiler and target are compatible - */ -#if (defined(__APCS_32__) && defined(CONFIG_CPU_26)) -#error Your compiler targets APCS-32 but this kernel requires APCS-26. -#endif -#if (defined(__APCS_26__) && defined(CONFIG_CPU_32)) -#error Your compiler targets APCS-26 but this kernel requires APCS-32. +#ifndef __APCS_32__ +#error APCS-32 required #endif #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/tools/mach-types linux.ac/arch/arm/tools/mach-types --- linux.vanilla/arch/arm/tools/mach-types Tue Apr 3 17:31:52 2001 +++ linux.ac/arch/arm/tools/mach-types Thu Apr 12 11:48:52 2001 @@ -1,10 +1,12 @@ # Database of machine macros and numbers # +# This file is linux/arch/arm/tools/mach-types +# # Please do not send patches to this file; it is automatically generated! # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Fri Feb 9 22:27:32 2001 +# Last update: Sat Apr 7 09:45:09 2001 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -35,7 +37,7 @@ assabet SA1100_ASSABET ASSABET 25 victor SA1100_VICTOR VICTOR 26 lart SA1100_LART LART 27 -ranger ARCH_RANGER RANGER 28 +ranger SA1100_RANGER RANGER 28 graphicsclient SA1100_GRAPHICSCLIENT GRAPHICSCLIENT 29 xp860 SA1100_XP860 XP860 30 cerf SA1100_CERF CERF 31 @@ -48,7 +50,7 @@ netport SA1100_NETPORT NETPORT 38 pangolin SA1100_PANGOLIN PANGOLIN 39 yopy SA1100_YOPY YOPY 40 -coolidge SA1100_COOLIDGE coolidge 41 +coolidge SA1100_COOLIDGE COOLIDGE 41 huw_webpanel SA1100_HUW_WEBPANEL HUW_WEBPANEL 42 spotme ARCH_SPOTME SPOTME 43 freebird ARCH_FREEBIRD FREEBIRD 44 @@ -65,6 +67,16 @@ webpal ARCH_WEBPAL WEBPAL 55 linpda SA1100_LINPDA LINPDA 56 anakin ARCH_ANAKIN ANAKIN 57 +mvi SA1100_MVI MVI 58 +jupiter SA1100_JUPITER JUPITER 59 +psionw ARCH_PSIONW PSIONW 60 +aln SA1100_ALN ALN 61 +camelot ARCH_CAMELOT CAMELOT 62 +gds2200 SA1100_GDS2200 GDS2200 63 +psion_series7 SA1100_PSION_SERIES7 PSION_SERIES7 64 +xfile SA1100_XFILE XFILE 65 +accelent_ep9312 ARCH_ACCELENT_EP9312 ACCELENT_EP9312 66 +ic200 ARCH_IC200 IC200 67 # The following are unallocated empeg SA1100_EMPEG EMPEG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/Makefile linux.ac/arch/cris/Makefile --- linux.vanilla/arch/cris/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/Makefile Thu Apr 19 14:13:35 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.11 2000/11/27 17:58:30 bjornw Exp $ +# $Id: Makefile,v 1.18 2001/04/17 13:58:38 orjanf Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -25,8 +25,8 @@ # regenerating stuff (even for incremental linking of subsystems!) is # even more nauseating. LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \ - sed -e s/@ETRAX_DRAM_BASE@/0x$(ETRAX_DRAM_BASE)/ \ - -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \ + sed -e s/@CONFIG_ETRAX_DRAM_VIRTUAL_BASE@/0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE)/ \ + -e s/@CONFIG_ETRAX_DRAM_SIZE_M@/$(CONFIG_ETRAX_DRAM_SIZE)/ \ < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \ else true; \ fi && $(CROSS_COMPILE)ld -mcriself @@ -42,14 +42,14 @@ CFLAGS := $(CFLAGS) -march=v10 -fno-strict-aliasing -pipe -D__linux__ -ifdef CONFIG_KGDB +ifdef CONFIG_ETRAX_KGDB CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g CFLAGS += -fno-omit-frame-pointer endif HEAD := arch/cris/kernel/head.o -SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers +SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers arch/cris/boot/rescue CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC) @@ -76,10 +76,18 @@ cramfs: ## cramfs - Creates a cramfs image - mkcramfs -p 8192 root cramfs.img + mkcramfs -b 8192 -m romfs_meta.txt root cramfs.img cat vmlinux.bin cramfs.img >timage -zImage: vmlinux +clinux: vmlinux.bin decompress.bin rescue.bin + +decompress.bin: dummy + @make -C arch/cris/boot/compressed decompress.bin + +rescue.bin: dummy + @make -C arch/cris/boot/rescue rescue.bin + +zImage: vmlinux.bin ## zImage - Compressed kernel (gzip) @$(MAKEBOOT) zImage diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/Makefile linux.ac/arch/cris/boot/compressed/Makefile --- linux.vanilla/arch/cris/boot/compressed/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/boot/compressed/Makefile Thu Apr 19 14:13:35 2001 @@ -16,12 +16,15 @@ all: vmlinuz -vmlinuz: piggy.img $(OBJECTS) - $(LD) -mcriself -T decompress.ld -o decompress.o $(OBJECTS) +decompress.bin: $(OBJECTS) + $(LD) -T decompress.ld -o decompress.o $(OBJECTS) $(OBJCOPY) -O binary --remove-section=.bss decompress.o decompress.bin # save it for mkprod in the topdir. cp decompress.bin $(TOPDIR) - cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz + + +vmlinuz: piggy.img decompress.bin + cat decompress.bin piggy.img > vmlinuz rm -f piggy.img head.o: head.S diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/decompress.ld linux.ac/arch/cris/boot/compressed/decompress.ld --- linux.vanilla/arch/cris/boot/compressed/decompress.ld Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/boot/compressed/decompress.ld Tue Apr 10 18:04:53 2001 @@ -1,3 +1,5 @@ +OUTPUT_FORMAT(elf32-us-cris) + MEMORY { dram : ORIGIN = 0x40700000, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/head.S linux.ac/arch/cris/boot/compressed/head.S --- linux.vanilla/arch/cris/boot/compressed/head.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/boot/compressed/head.S Thu Apr 19 14:13:35 2001 @@ -1,7 +1,7 @@ /* - * arch/etrax100/boot/compressed/head.S + * arch/cris/boot/compressed/head.S * - * Copyright (C) 1999 Axis Communications AB + * Copyright (C) 1999, 2001 Axis Communications AB * * Code that sets up the DRAM registers, calls the * decompressor to unpack the piggybacked kernel, and jumps. @@ -12,6 +12,8 @@ #define ASSEMBLER_MACROS_ONLY #include +#define RAM_INIT_MAGIC 0x56902387 + ;; Exported symbols .globl _input_data @@ -22,23 +24,29 @@ nop di -#ifndef CONFIG_SVINTO_SIM - - ;; We need to setup the bus registers before we start using the DRAM +;; We need to initialze DRAM registers before we start using the DRAM + + cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? + beq dram_init_finished + nop + +#include "../../lib/dram_init.S" + +dram_init_finished: + + ;; Initiate the PA and PB ports - move.d DEF_R_WAITSTATES, r0 - move.d r0, [R_WAITSTATES] + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] - move.d DEF_R_BUS_CONFIG, r0 - move.d r0, [R_BUS_CONFIG] - - move.d DEF_R_DRAM_CONFIG, r0 - move.d r0, [R_DRAM_CONFIG] + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] - move.d DEF_R_DRAM_TIMING, r0 - move.d r0, [R_DRAM_TIMING] + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 + move.b r0, [R_PORT_PB_DATA] -#endif + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] ;; Setup the stack to a suitably high address. ;; We assume 8 MB is the minimum DRAM in an eLinux @@ -70,6 +78,7 @@ move.d r5, [_input_data] ; for the decompressor + ;; Clear the decompressors BSS (between _edata and _end) moveq 0, r0 @@ -81,20 +90,22 @@ nop ;; Do the decompression and save compressed size in _inptr - - jsr _decompress_kernel - ;; Put start address of cramfs in r9 so the kernel can use it + jsr _decompress_kernel + + ;; Put start address of root partition in r9 so the kernel can use it ;; when mounting from flash move.d [_input_data], r9 ; flash address of compressed kernel add.d [_inptr], r9 ; size of compressed kernel - + ;; Enter the decompressed kernel - + move.d RAM_INIT_MAGIC, r8 ; Tell kernel that DRAM is initialized jump 0x40004000 ; kernel is linked to this address .data _input_data: .dword 0 ; used by the decompressor + +#include "../../lib/hw_settings.S" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/compressed/misc.c linux.ac/arch/cris/boot/compressed/misc.c --- linux.vanilla/arch/cris/boot/compressed/misc.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/boot/compressed/misc.c Thu Apr 19 14:13:35 2001 @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.3 2001/01/17 15:54:18 jonashg Exp $ + * $Id: misc.c,v 1.6 2001/04/09 10:00:21 starvik Exp $ * * This is a collection of several routines from gzip-1.0.3 * adapted for Linux. @@ -13,7 +13,7 @@ */ /* where the piggybacked kernel image expects itself to live. - * it is the same address we use when we network load an uncompressed + * it is the same adress we use when we network load an uncompressed * image into DRAM, and it is the address the kernel is linked to live * at by etrax100.ld. */ @@ -21,6 +21,7 @@ #define KERNEL_LOAD_ADR 0x40004000 #include + #include #include @@ -143,21 +144,21 @@ static void puts(const char *s) { -#ifndef CONFIG_DEBUG_PORT_NULL +#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL while(*s) { -#ifdef CONFIG_DEBUG_PORT0 +#ifdef CONFIG_ETRAX_DEBUG_PORT0 while(!(*R_SERIAL0_STATUS & (1 << 5))) ; *R_SERIAL0_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 while(!(*R_SERIAL1_STATUS & (1 << 5))) ; *R_SERIAL1_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 while(!(*R_SERIAL2_STATUS & (1 << 5))) ; *R_SERIAL2_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 while(!(*R_SERIAL3_STATUS & (1 << 5))) ; *R_SERIAL3_TR_DATA = *s++; #endif @@ -227,33 +228,45 @@ void decompress_kernel() { + char revision; + /* input_data is set in head.S */ inbuf = input_data; -#ifdef CONFIG_DEBUG_PORT0 +#ifdef CONFIG_ETRAX_DEBUG_PORT0 *R_SERIAL0_XOFF = 0; *R_SERIAL0_BAUD = 0x99; *R_SERIAL0_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 *R_SERIAL1_XOFF = 0; *R_SERIAL1_BAUD = 0x99; *R_SERIAL1_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 + *R_GEN_CONFIG = 0x08; *R_SERIAL2_XOFF = 0; *R_SERIAL2_BAUD = 0x99; *R_SERIAL2_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 + *R_GEN_CONFIG = 0x100; *R_SERIAL3_XOFF = 0; *R_SERIAL3_BAUD = 0x99; *R_SERIAL3_TR_CTRL = 0x40; #endif - + setup_normal_output_buffer(); makecrc(); + + __asm__ volatile ("move vr,%0" : "=rm" (revision)); + if (revision < 10) + { + puts("You need an ETRAX 100LX to run linux 2.4\n"); + while(1); + } + puts("Uncompressing Linux...\n"); gunzip(); puts("Done. Now booting the kernel.\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/Makefile linux.ac/arch/cris/boot/rescue/Makefile --- linux.vanilla/arch/cris/boot/rescue/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/Makefile Tue Apr 10 18:04:53 2001 @@ -0,0 +1,50 @@ +# +# Makefile for rescue code +# +ifndef TOPDIR +TOPDIR = ../../../.. +endif +CC = gcc-cris -I $(TOPDIR)/include +CFLAGS = -O2 +LD = ld-cris +OBJCOPY = objcopy-cris + +all: rescue.bin testrescue.bin kimagerescue.bin + +rescue: rescue.bin + # do nothing + +rescue.bin: head.o + $(LD) -T rescue.ld -o rescue.o head.o + $(OBJCOPY) -O binary --remove-section=.bss rescue.o rescue.bin + cp rescue.bin $(TOPDIR) + +testrescue.bin: testrescue.o + $(OBJCOPY) -O binary --remove-section=.bss testrescue.o tr.bin +# Pad it to 784 bytes + dd if=/dev/zero of=tmp2423 bs=1 count=784 + cat tr.bin tmp2423 >testrescue_tmp.bin + dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784 + rm tr.bin tmp2423 testrescue_tmp.bin + +kimagerescue.bin: kimagerescue.o + $(OBJCOPY) -O binary --remove-section=.bss kimagerescue.o ktr.bin +# Pad it to 784 bytes, that's what the rescue loader expects + dd if=/dev/zero of=tmp2423 bs=1 count=784 + cat ktr.bin tmp2423 >kimagerescue_tmp.bin + dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784 + rm ktr.bin tmp2423 kimagerescue_tmp.bin + +head.o: head.S + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +testrescue.o: testrescue.S + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +kimagerescue.o: kimagerescue.S + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +clean: + rm -f *.o *.bin + +fastdep: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/head.S linux.ac/arch/cris/boot/rescue/head.S --- linux.vanilla/arch/cris/boot/rescue/head.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/head.S Thu Apr 19 14:13:35 2001 @@ -0,0 +1,327 @@ +/* $Id: head.S,v 1.7 2001/04/18 12:05:07 bjornw Exp $ + * + * Rescue code, made to reside at the beginning of the + * flash-memory. when it starts, it checks a partition + * table at the first sector after the rescue sector. + * the partition table was generated by the product builder + * script and contains offsets, lengths, types and checksums + * for each partition that this code should check. + * + * If any of the checksums fail, we assume the flash is so + * corrupt that we cant use it to boot into the ftp flash + * loader, and instead we initialize the serial port to + * receive a flash-loader and new flash image. we dont include + * any flash code here, but just accept a certain amount of + * bytes from the serial port and jump into it. the downloaded + * code is put in the cache. + * + * The partitiontable is designed so that it is transparent to + * code execution - it has a relative branch opcode in the + * beginning that jumps over it. each entry contains extra + * data so we can add stuff later. + * + * Partition table format: + * + * Code transparency: + * + * 2 bytes [opcode 'nop'] + * 2 bytes [opcode 'di'] + * 4 bytes [opcode 'ba ', 8-bit or 16-bit version] + * 2 bytes [opcode 'nop', delay slot] + * + * Table validation (at +10): + * + * 2 bytes [magic/version word for partitiontable - 0xef, 0xbe] + * 2 bytes [length of all entries plus the end marker] + * 4 bytes [checksum for the partitiontable itself] + * + * Entries, each with the following format, last has offset -1: + * + * 4 bytes [offset in bytes, from start of flash] + * 4 bytes [length in bytes of partition] + * 4 bytes [checksum, simple longword sum] + * 2 bytes [partition type] + * 2 bytes [flags, only bit 0 used, ro/rw = 1/0] + * 16 bytes [reserved for future use] + * + * End marker + * + * 4 bytes [-1] + * + * 10 bytes [0, padding] + * + * Bit 0 in flags signifies RW or RO. The rescue code only bothers + * to check the checksum for RO partitions, since the others will + * change its data without updating the checksums. A 1 in bit 0 + * means RO, 0 means RW. That way, it is possible to set a partition + * in RO mode initially, and later mark it as RW, since you can always + * write 0's to the flash. + * + * During the wait for serial input, the status LED will flash so the + * user knows something went wrong. + * + * Copyright (C) 1999,2001 Axis Communications AB + */ + +#include +#define ASSEMBLER_MACROS_ONLY +#include + + ;; The partitiontable is looked for at the first sector after the boot + ;; sector. Sector size is 65536 bytes in all flashes we use. + +#define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR +#define PTABLE_MAGIC 0xbeef + + ;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0. + ;; That is not where we put our downloaded serial boot-code. The length is + ;; enough for downloading code that loads the rest of itself (after + ;; having setup the DRAM etc). It is the same length as the on-chip + ;; ROM loads, so the same host loader can be used to load a rescued + ;; product as well as one booted through the Etrax serial boot code. + +#define CODE_START 0x40000000 +#define CODE_LENGTH 784 + +#ifdef CONFIG_ETRAX_RESCUE_SER0 +#define SERXOFF R_SERIAL0_XOFF +#define SERBAUD R_SERIAL0_BAUD +#define SERRECC R_SERIAL0_REC_CTRL +#define SERRDAT R_SERIAL0_REC_DATA +#define SERSTAT R_SERIAL0_STATUS +#endif +#ifdef CONFIG_ETRAX_RESCUE_SER1 +#define SERXOFF R_SERIAL1_XOFF +#define SERBAUD R_SERIAL1_BAUD +#define SERRECC R_SERIAL1_REC_CTRL +#define SERRDAT R_SERIAL1_REC_DATA +#define SERSTAT R_SERIAL1_STATUS +#endif +#ifdef CONFIG_ETRAX_RESCUE_SER2 +#define SERXOFF R_SERIAL2_XOFF +#define SERBAUD R_SERIAL2_BAUD +#define SERRECC R_SERIAL2_REC_CTRL +#define SERRDAT R_SERIAL2_REC_DATA +#define SERSTAT R_SERIAL2_STATUS +#endif +#ifdef CONFIG_ETRAX_RESCUE_SER3 +#define SERXOFF R_SERIAL3_XOFF +#define SERBAUD R_SERIAL3_BAUD +#define SERRECC R_SERIAL3_REC_CTRL +#define SERRDAT R_SERIAL3_REC_DATA +#define SERSTAT R_SERIAL3_STATUS +#endif + +#define NOP_DI 0xf025050f +#define RAM_INIT_MAGIC 0x56902387 + + .text + + ;; This is the entry point of the rescue code + ;; 0x80000000 if loaded in flash (as it should be) + ;; since etrax actually starts at address 2 when booting from flash, we + ;; put a nop (2 bytes) here first so we dont accidentally skip the di + + nop + di + + jump in_cache ; enter cached area instead +in_cache: + + ;; first put a jump test to give a possibility of upgrading the rescue code + ;; without erasing/reflashing the sector. we put a longword of -1 here and if + ;; its not -1, we jump using the value as jump target. since we can always + ;; change 1's to 0's without erasing the sector, it is possible to add new + ;; code after this and altering the jumptarget in an upgrade. + +jtcd: move.d [jumptarget], r0 + cmp.d 0xffffffff, r0 + beq no_newjump + nop + + jump [r0] + +jumptarget: + .dword 0xffffffff ; can be overwritten later to insert new code + +no_newjump: + ;; We need to setup the bus registers before we start using the DRAM +#include "../../lib/dram_init.S" + + ;; we now should go through the checksum-table and check the listed + ;; partitions for errors. + + move.d PTABLE_START, r3 + move.d [r3], r0 + cmp.d NOP_DI, r0 ; make sure the nop/di is there... + bne do_rescue + nop + + ;; skip the code transparency block (10 bytes). + + addq 10, r3 + + ;; check for correct magic + + move.w [r3+], r0 + cmp.w PTABLE_MAGIC, r0 + bne do_rescue ; didn't recognize - trig rescue + nop + + ;; check for correct ptable checksum + + movu.w [r3+], r2 ; ptable length + move.d r2, r8 ; save for later, length of total ptable + addq 28, r8 ; account for the rest + move.d [r3+], r4 ; ptable checksum + move.d r3, r1 + jsr checksum ; r1 source, r2 length, returns in r0 + + cmp.d r0, r4 + bne do_rescue ; didn't match - trig rescue + nop + + ;; ptable is ok. validate each entry. + + moveq -1, r7 + +ploop: move.d [r3+], r1 ; partition offset (from ptable start) + bne notfirst ; check if its the partition containing ptable + nop ; yes.. + move.d r8, r1 ; for its checksum check, skip the ptable + move.d [r3+], r2 ; partition length + sub.d r8, r2 ; minus the ptable length + ba bosse + nop +notfirst: + cmp.d -1, r1 ; the end of the ptable ? + beq flash_ok ; if so, the flash is validated + move.d [r3+], r2 ; partition length +bosse: move.d [r3+], r5 ; checksum + move.d [r3+], r4 ; type and flags + addq 16, r3 ; skip the reserved bytes + btstq 16, r4 ; check ro flag + bpl ploop ; rw partition, skip validation + nop + btstq 17, r4 ; check bootable flag + bpl 1f + nop + move.d r1, r7 ; remember boot partition offset +1: + + add.d PTABLE_START, r1 + + jsr checksum ; checksum the partition + + cmp.d r0, r5 + beq ploop ; checksums matched, go to next entry + nop + + ;; otherwise fall through to the rescue code. + +do_rescue: + ;; setup port PA and PB default initial directions and data + ;; (so we can flash LEDs, and so that DTR and others are set) + + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] + + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 + move.b r0, [R_PORT_PB_DATA] + + ;; setup the serial port at 115200 baud + + moveq 0, r0 + move.d r0, [SERXOFF] + + move.b 0x99, r0 + move.b r0, [SERBAUD] ; 115.2kbaud for both transmit and receive + + move.b 0x40, r0 ; rec enable + move.b r0, [SERRECC] + + moveq 0, r1 ; "timer" to clock out a LED red flash + move.d CODE_START, r3 ; destination counter + movu.w CODE_LENGTH, r4 ; length + +wait_ser: + addq 1, r1 +#ifndef CONFIG_ETRAX_NO_LEDS +#ifdef CONFIG_ETRAX_PA_LEDS + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2 +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2 +#endif + move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 + btstq 16, r1 + bpl 1f + nop + or.d r0, r2 ; set bit + ba 2f + nop +1: not r0 ; clear bit + and.d r0, r2 +2: +#ifdef CONFIG_ETRAX_PA_LEDS + move.b r2, [R_PORT_PA_DATA] +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b r2, [R_PORT_PB_DATA] +#endif +#ifdef CONFIG_ETRAX_90000000_LEDS + move.b r2, [0x90000000] +#endif +#endif + + ;; check if we got something on the serial port + + move.b [SERSTAT], r0 + btstq 0, r0 ; data_avail + bpl wait_ser + nop + + ;; got something - copy the byte and loop + + move.b [SERRDAT], r0 + move.b r0, [r3+] + + subq 1, r4 ; decrease length + bne wait_ser + nop + + ;; jump into downloaded code + + move.d RAM_INIT_MAGIC, r8 ; Tell next product that DRAM is initialized + jump CODE_START + +flash_ok: + ;; check r7, which contains either -1 or the partition to boot from + + cmp.d -1, r7 + bne 1f + nop + move.d PTABLE_START, r7; otherwise use the ptable start +1: + move.d RAM_INIT_MAGIC, r8 ; Tell next product that DRAM is initialized + jump r7 ; boot! + + + ;; Helper subroutines + + ;; Will checksum by simple addition + ;; r1 - source + ;; r2 - length in bytes + ;; result will be in r0 +checksum: + moveq 0, r0 +1: addu.b [r1+], r0 + subq 1, r2 + bne 1b + nop + ret + nop diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/kimagerescue.S linux.ac/arch/cris/boot/rescue/kimagerescue.S --- linux.vanilla/arch/cris/boot/rescue/kimagerescue.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/kimagerescue.S Thu Apr 19 14:13:35 2001 @@ -0,0 +1,144 @@ +/* $Id: kimagerescue.S,v 1.4 2001/04/18 12:04:46 bjornw Exp $ + * + * Rescue code to be prepended on a kimage and copied to the + * rescue serial port. + * This is called from the rescue code, it will copy received data to + * 4004000 and after a timeout jump to it. + */ + +#include +#define ASSEMBLER_MACROS_ONLY +#include + +#define CODE_START 0x40004000 +#define CODE_LENGTH 784 +#define TIMEOUT_VALUE 1000 + + +#ifdef CONFIG_ETRAX_RESCUE_SER0 +#define SERXOFF R_SERIAL0_XOFF +#define SERBAUD R_SERIAL0_BAUD +#define SERRECC R_SERIAL0_REC_CTRL +#define SERRDAT R_SERIAL0_REC_DATA +#define SERSTAT R_SERIAL0_STATUS +#endif +#ifdef CONFIG_ETRAX_RESCUE_SER1 +#define SERXOFF R_SERIAL1_XOFF +#define SERBAUD R_SERIAL1_BAUD +#define SERRECC R_SERIAL1_REC_CTRL +#define SERRDAT R_SERIAL1_REC_DATA +#define SERSTAT R_SERIAL1_STATUS +#endif +#ifdef CONFIG_ETRAX_RESCUE_SER2 +#define SERXOFF R_SERIAL2_XOFF +#define SERBAUD R_SERIAL2_BAUD +#define SERRECC R_SERIAL2_REC_CTRL +#define SERRDAT R_SERIAL2_REC_DATA +#define SERSTAT R_SERIAL2_STATUS +#endif +#ifdef CONFIG_ETRAX_RESCUE_SER3 +#define SERXOFF R_SERIAL3_XOFF +#define SERBAUD R_SERIAL3_BAUD +#define SERRECC R_SERIAL3_REC_CTRL +#define SERRDAT R_SERIAL3_REC_DATA +#define SERSTAT R_SERIAL3_STATUS +#endif + + .text + ;; This is the entry point of the rescue code + ;; 0x80000000 if loaded in flash (as it should be) + ;; since etrax actually starts at address 2 when booting from flash, we + ;; put a nop (2 bytes) here first so we dont accidentally skip the di + + nop + di +#ifndef CONFIG_SVINTO_SIM + ;; setup port PA and PB default initial directions and data + ;; (so we can flash LEDs, and so that DTR and others are set) + + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] + + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 + move.b r0, [R_PORT_PB_DATA] + + ;; We need to setup the bus registers before we start using the DRAM +#include "../../lib/dram_init.S" + +#endif + ;; Setup the stack to a suitably high address. + ;; We assume 8 MB is the minimum DRAM in an eLinux + ;; product and put the sp at the top for now. + + move.d 0x40800000, sp + + ;; setup the serial port at 115200 baud + + moveq 0, r0 + move.d r0, [SERXOFF] + + move.b 0x99, r0 + move.b r0, [SERBAUD] ; 115.2kbaud for both transmit and receive + + move.b 0x40, r0 ; rec enable + move.b r0, [SERRECC] + + + moveq 0, r1 ; "timer" to clock out a LED red flash + move.d CODE_START, r3 ; destination counter + move.d CODE_LENGTH, r4 ; length + move.d TIMEOUT_VALUE, r5 ; "timeout" until jump + +wait_ser: + addq 1, r1 + subq 1, r5 ; decrease timeout + beq jump_start ; timed out + nop +#ifndef CONFIG_ETRAX_NO_LEDS +#ifdef CONFIG_ETRAX_PA_LEDS + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2 +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2 +#endif + move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 + btstq 16, r1 + bpl 1f + nop + or.d r0, r2 ; set bit + ba 2f + nop +1: not r0 ; clear bit + and.d r0, r2 +2: +#ifdef CONFIG_ETRAX_PA_LEDS + move.b r2, [R_PORT_PA_DATA] +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b r2, [R_PORT_PB_DATA] +#endif +#endif + + ;; check if we got something on the serial port + + move.b [SERSTAT], r0 + btstq 0, r0 ; data_avail + bpl wait_ser + nop + + ;; got something - copy the byte and loop + + move.b [SERRDAT], r0 + move.b r0, [r3+] + move.d TIMEOUT_VALUE, r5 ; reset "timeout" + subq 1, r4 ; decrease length + bne wait_ser + nop +jump_start: + ;; jump into downloaded code + + jump CODE_START diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/rescue.ld linux.ac/arch/cris/boot/rescue/rescue.ld --- linux.vanilla/arch/cris/boot/rescue/rescue.ld Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/rescue.ld Tue Apr 10 18:04:53 2001 @@ -0,0 +1,20 @@ +MEMORY + { + flash : ORIGIN = 0x00000000, + LENGTH = 0x00100000 + } + +SECTIONS +{ + .text : + { + _stext = . ; + *(.text) + _etext = . ; + } > flash + .data : + { + *(.data) + _edata = . ; + } > flash +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/rescue/testrescue.S linux.ac/arch/cris/boot/rescue/testrescue.S --- linux.vanilla/arch/cris/boot/rescue/testrescue.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/rescue/testrescue.S Thu Apr 19 14:13:35 2001 @@ -0,0 +1,26 @@ +/* $Id: testrescue.S,v 1.2 2001/04/18 12:05:07 bjornw Exp $ + * + * Simple testcode to download by the rescue block. + * Just lits some LEDs to show it was downloaded correctly. + * + * Copyright (C) 1999 Axis Communications AB + */ + +#define ASSEMBLER_MACROS_ONLY +#include + + .text + + nop + nop + moveq -1, r2 + move.b r2, [R_PORT_PA_DIR] + moveq 0, r2 + move.b r2, [R_PORT_PA_DATA] + +endless: + nop + ba endless + nop + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/boot/tools/build.c linux.ac/arch/cris/boot/tools/build.c --- linux.vanilla/arch/cris/boot/tools/build.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/boot/tools/build.c Thu Apr 19 14:13:35 2001 @@ -0,0 +1,289 @@ +/* + * linux/tools/build.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest + * - setup: 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * Cross compiling fixes by Gertjan van Wingerde, July 1996 + */ + +#include /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include +#include +#include +#include + +#define MINIX_HEADER 32 + +#define N_MAGIC_OFFSET 1024 +#ifndef __BFD__ +static int GCC_HEADER = sizeof(struct exec); +#endif + +#ifdef __BIG_KERNEL__ +#define SYS_SIZE 0xffff +#else +#define SYS_SIZE DEF_SYSSIZE +#endif + +#define DEFAULT_MAJOR_ROOT 0 +#define DEFAULT_MINOR_ROOT 0 + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +typedef union { + int i; + long l; + short s[2]; + char b[4]; +} conv; + +long intel_long(long l) +{ + conv t; + + t.b[0] = l & 0xff; l >>= 8; + t.b[1] = l & 0xff; l >>= 8; + t.b[2] = l & 0xff; l >>= 8; + t.b[3] = l & 0xff; l >>= 8; + return t.l; +} + +int intel_int(int i) +{ + conv t; + + t.b[0] = i & 0xff; i >>= 8; + t.b[1] = i & 0xff; i >>= 8; + t.b[2] = i & 0xff; i >>= 8; + t.b[3] = i & 0xff; i >>= 8; + return t.i; +} + +short intel_short(short l) +{ + conv t; + + t.b[0] = l & 0xff; l >>= 8; + t.b[1] = l & 0xff; l >>= 8; + return t.s[0]; +} + +void die(const char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id,sz,tmp_int; + unsigned long sys_size, tmp_long; + char buf[1024]; +#ifndef __BFD__ + struct exec *ex = (struct exec *)buf; +#endif + char major_root, minor_root; + struct stat sb; + unsigned char setup_sectors; + + if ((argc < 4) || (argc > 5)) + usage(); + if (argc > 4) { + if (!strcmp(argv[4], "CURRENT")) { + if (stat("/", &sb)) { + perror("/"); + die("Couldn't stat /"); + } + major_root = major(sb.st_dev); + minor_root = minor(sb.st_dev); + } else if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = major(sb.st_rdev); + minor_root = minor(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + for (i=0;i0 ; i+=c ) +#ifdef __BIG_KERNEL__ + { + if (!i) { + /* Working with memcpy because of alignment constraints + on Sparc - Gertjan */ + memcpy(&tmp_long, &buf[2], sizeof(long)); + if (tmp_long != intel_long(0x53726448) ) + die("Wrong magic in loader header of 'setup'"); + memcpy(&tmp_int, &buf[6], sizeof(int)); + if (tmp_int < intel_int(0x200)) + die("Wrong version of loader header of 'setup'"); + buf[0x11] = 1; /* LOADED_HIGH */ + tmp_long = intel_long(0x100000); + memcpy(&buf[0x14], &tmp_long, sizeof(long)); /* code32_start */ + } +#endif + if (write(1,buf,c)!=c) + die("Write call failed"); +#ifdef __BIG_KERNEL__ + } +#endif + if (c != 0) + die("read-error on 'setup'"); + close (id); + setup_sectors = (unsigned char)((i + 511) / 512); + /* for compatibility with LILO */ + if (setup_sectors < SETUP_SECTS) + setup_sectors = SETUP_SECTS; + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); +#ifndef __BFD__ + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (N_MAGIC(*ex) == ZMAGIC) { + GCC_HEADER = N_MAGIC_OFFSET; + lseek(id, GCC_HEADER, SEEK_SET); + } else if (N_MAGIC(*ex) != QMAGIC) + die("Non-GCC header of 'system'"); + fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss)\n", + (ex->a_text+ex->a_data+ex->a_bss)/1024, + ex->a_text /1024, + ex->a_data /1024, + ex->a_bss /1024); + sz = N_SYMOFF(*ex) - GCC_HEADER + 4; +#else + if (fstat (id, &sb)) { + perror ("fstat"); + die ("Unable to stat 'system'"); + } + sz = sb.st_size; + fprintf (stderr, "System is %d kB\n", sz/1024); +#endif + sys_size = (sz + 15) / 16; + if (sys_size > SYS_SIZE) + die("System is too big"); + while (sz > 0) { + int l, n; + + l = sz; + if (l > sizeof(buf)) + l = sizeof(buf); + if ((n=read(id, buf, l)) != l) { + if (n == -1) + perror(argv[1]); + else + fprintf(stderr, "Unexpected EOF\n"); + die("Can't read 'system'"); + } + if (write(1, buf, l) != l) + die("Write failed"); + sz -= l; + } + close(id); + if (lseek(1, 497, 0) == 497) { + if (write(1, &setup_sectors, 1) != 1) + die("Write of setup sectors failed"); + } + if (lseek(1,500,0) == 500) { + buf[0] = (sys_size & 0xff); + buf[1] = ((sys_size >> 8) & 0xff); + if (write(1, buf, 2) != 2) + die("Write failed"); + } + return(0); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/config.in linux.ac/arch/cris/config.in --- linux.vanilla/arch/cris/config.in Fri Feb 16 23:53:08 2001 +++ linux.ac/arch/cris/config.in Thu Apr 19 14:13:36 2001 @@ -5,6 +5,8 @@ mainmenu_name "Linux/CRIS Kernel Configuration" define_bool CONFIG_UID16 y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n mainmenu_option next_comment comment 'Code maturity level options' @@ -22,38 +24,37 @@ tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi -bool 'Use kernel gdb debugger' CONFIG_KGDB +bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG -bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE - -bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG - endmenu mainmenu_option next_comment comment 'Hardware setup' choice 'Processor type' \ - "Etrax-100-LX CONFIG_ETRAX100LX \ - Etrax-100-LX-for-xsim-simulator CONFIG_SVINTO_SIM" Etrax-100-LX + "Etrax-100-LX-v1 CONFIG_ETRAX100LX \ + Etrax-100-LX-v2 CONFIG_ETRAX100LX_V2 \ + Etrax-100-LX-for-xsim-simulator CONFIG_SVINTO_SIM" Etrax-100-LX-v1 # For both LX version 1 and the current simulator we enable the low VM mapping -# Later when LX version 2 and above exist, this should be done with an if -define_bool CONFIG_CRIS_LOW_MAP y +if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then + define_bool CONFIG_CRIS_LOW_MAP y + define_hex CONFIG_ETRAX_DRAM_VIRTUAL_BASE 60000000 +else + define_hex CONFIG_ETRAX_DRAM_VIRTUAL_BASE c0000000 +fi -hex 'DRAM base (hex)' ETRAX_DRAM_BASE 40000000 -int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8 +int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8 -int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2 int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2 choice 'Product LED port' \ "Port-PA-LEDs CONFIG_ETRAX_PA_LEDS \ Port-PB-LEDs CONFIG_ETRAX_PB_LEDS \ - Mem-0x90000000-LEDs CONFIG_ETRAX_90000000_LEDS \ + Port-CSP0-LEDs CONFIG_ETRAX_CSP0_LEDS \ None CONFIG_ETRAX_NO_LEDS" Port-PA-LEDs if [ "$CONFIG_ETRAX_NO_LEDS" != "y" ]; then @@ -65,41 +66,56 @@ int ' Third red LED bit' CONFIG_ETRAX_LED3G 2 fi -choice 'Product debug-port' \ - "Serial-0 CONFIG_DEBUG_PORT0 \ - Serial-1 CONFIG_DEBUG_PORT1 \ - Serial-2 CONFIG_DEBUG_PORT2 \ - Serial-3 CONFIG_DEBUG_PORT3" Serial-0 - -hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6 -hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104 -hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040 -hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611 -hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c -hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00 -hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00 -hex 'R_PORT_PB_DIR' DEF_R_PORT_PB_DIR 00 -hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff +if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then + int ' Fourth red LED bit' CONFIG_ETRAX_LED4R 2 + int ' Fourth green LED bit' CONFIG_ETRAX_LED4G 2 + int ' Fifth red LED bit' CONFIG_ETRAX_LED5R 2 + int ' Fifth green LED bit' CONFIG_ETRAX_LED5G 2 + int ' Sixth red LED bit' CONFIG_ETRAX_LED6R 2 + int ' Sixth green LED bit' CONFIG_ETRAX_LED6G 2 + int ' Seventh red LED bit' CONFIG_ETRAX_LED7R 2 + int ' Seventh green LED bit' CONFIG_ETRAX_LED7G 2 + int ' Eigth yellow LED bit' CONFIG_ETRAX_LED8Y 2 + int ' Ninth yellow LED bit' CONFIG_ETRAX_LED9Y 2 + int ' Tenth yellow LED bit' CONFIG_ETRAX_LED10Y 2 + int ' Eleventh yellow LED bit' CONFIG_ETRAX_LED11Y 2 + int ' Twelfth red LED bit' CONFIG_ETRAX_LED12R 2 +fi -endmenu +choice 'Product debug-port' \ + "Serial-0 CONFIG_ETRAX_DEBUG_PORT0 \ + Serial-1 CONFIG_ETRAX_DEBUG_PORT1 \ + Serial-2 CONFIG_ETRAX_DEBUG_PORT2 \ + Serial-3 CONFIG_ETRAX_DEBUG_PORT3 \ + disabled CONFIG_ETRAX_DEBUG_PORT_NULL" Serial-0 + +choice 'Product rescue-port' \ + "Serial-0 CONFIG_ETRAX_RESCUE_SER0 \ + Serial-1 CONFIG_ETRAX_RESCUE_SER1 \ + Serial-2 CONFIG_ETRAX_RESCUE_SER2 \ + Serial-3 CONFIG_ETRAX_RESCUE_SER3" Serial-0 + +hex 'R_WAITSTATES' CONFIG_ETRAX_DEF_R_WAITSTATES 95a6 +hex 'R_BUS_CONFIG' CONFIG_ETRAX_DEF_R_BUS_CONFIG 104 + +bool 'SDRAM support' CONFIG_ETRAX_SDRAM n +if [ "$CONFIG_ETRAX_SDRAM" = "n" ]; then + hex 'R_DRAM_CONFIG' CONFIG_ETRAX_DEF_R_DRAM_CONFIG 1a200040 + hex 'R_DRAM_TIMING' CONFIG_ETRAX_DEF_R_DRAM_TIMING 5611 +fi -# only configure IP numbers if the kernel ifconfig/route setup is enabled +if [ "$CONFIG_ETRAX_SDRAM" = "y" ]; then + hex 'R_SDRAM_CONFIG' CONFIG_ETRAX_DEF_R_SDRAM_CONFIG d2fa7878 + hex 'R_SDRAM_TIMING' CONFIG_ETRAX_DEF_R_SDRAM_TIMING 80004801 +fi -if [ "$CONFIG_KERNEL_IFCONFIG" = "y" ]; then - mainmenu_option next_comment - comment 'IP address selection' - - comment 'All addresses are in hexadecimal form without 0x prefix' - - hex 'IP address' ELTEST_IPADR ab1005af - hex 'Network' ELTEST_NETWORK ab100000 - hex 'Netmask' ELTEST_NETMASK ffff0000 - hex 'Broadcast' ELTEST_BROADCAST ab10ffff - hex 'Gateway' ELTEST_GATEWAY ab100101 - hwaddr 'Ethernet address' ELTEST_ETHADR 00408ccd0000 +hex 'R_PORT_PA_DIR' CONFIG_ETRAX_DEF_R_PORT_PA_DIR 1c +hex 'R_PORT_PA_DATA' CONFIG_ETRAX_DEF_R_PORT_PA_DATA 00 +hex 'R_PORT_PB_CONFIG' CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG 00 +hex 'R_PORT_PB_DIR' CONFIG_ETRAX_DEF_R_PORT_PB_DIR 00 +hex 'R_PORT_PB_DATA' CONFIG_ETRAX_DEF_R_PORT_PB_DATA ff - endmenu -fi +endmenu # bring in Etrax built-in drivers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/cris.ld linux.ac/arch/cris/cris.ld --- linux.vanilla/arch/cris/cris.ld Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/cris.ld Thu Apr 19 14:13:36 2001 @@ -1,13 +1,16 @@ /* ld script to make the Linux/CRIS kernel * Authors: Bjorn Wesen (bjornw@axis.com) * - * For now, on Etrax-100 LX, the DRAM starts virtually at 0x6. Normally - * it should be at 0xc. + * It is VERY DANGEROUS to fiddle around with the symbols in this + * script. It is for example quite vital that all generated sections + * that are used are actually named here, otherwise the linker will + * put them at the end, where the init stuff is which is FREED after + * the kernel has booted. */ SECTIONS { - . = 0x60000000; /* DRAM starts virtually at 0x60000000 */ + . = @CONFIG_ETRAX_DRAM_VIRTUAL_BASE@; _dram_start = .; _ibr_start = .; . = . + 0x4000; /* see head.S and pages reserved at the start */ @@ -21,6 +24,7 @@ *(.fixup) *(.text.__*) *(.rodata) + *(.rodata.__*) } . = ALIGN(4); /* Exception table */ @@ -77,5 +81,5 @@ *(.exitcall.exit) } - _dram_end = 0x60000000 + @ETRAX_DRAM_SIZE_M@*1024*1024; + _dram_end = _dram_start + @CONFIG_ETRAX_DRAM_SIZE_M@*1024*1024; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/defconfig linux.ac/arch/cris/defconfig --- linux.vanilla/arch/cris/defconfig Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/defconfig Thu Apr 19 14:13:36 2001 @@ -15,19 +15,20 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_JAVA is not set -# CONFIG_KGDB is not set +# CONFIG_ETRAX_KGDB is not set # CONFIG_ETRAX_WATCHDOG is not set -CONFIG_USE_SERIAL_CONSOLE=y -# CONFIG_KERNEL_IFCONFIG is not set # # Hardware setup # CONFIG_ETRAX100LX=y +# CONFIG_ETRAX100LX_V2 is not set # CONFIG_SVINTO_SIM is not set CONFIG_CRIS_LOW_MAP=y -ETRAX_DRAM_BASE=40000000 -ETRAX_DRAM_SIZE=8 +CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 +CONFIG_ETRAX_DRAM_SIZE=8 +CONFIG_ETRAX_FLASH_LENGTH=2 +CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_PA_LEDS=y # CONFIG_ETRAX_PB_LEDS is not set # CONFIG_ETRAX_90000000_LEDS is not set @@ -36,19 +37,24 @@ CONFIG_ETRAX_LED1R=2 CONFIG_ETRAX_LED2G=2 CONFIG_ETRAX_LED2R=2 -CONFIG_DEBUG_PORT0=y -# CONFIG_DEBUG_PORT1 is not set -# CONFIG_DEBUG_PORT2 is not set -# CONFIG_DEBUG_PORT3 is not set -DEF_R_WAITSTATES=95a6 -DEF_R_BUS_CONFIG=104 -DEF_R_DRAM_CONFIG=1a200040 -DEF_R_DRAM_TIMING=5611 -DEF_R_PORT_PA_DIR=1d -DEF_R_PORT_PA_DATA=f0 -DEF_R_PORT_PB_CONFIG=00 -DEF_R_PORT_PB_DIR=1e -DEF_R_PORT_PB_DATA=f3 +CONFIG_ETRAX_DEBUG_PORT0=y +# CONFIG_ETRAX_DEBUG_PORT1 is not set +# CONFIG_ETRAX_DEBUG_PORT2 is not set +# CONFIG_ETRAX_DEBUG_PORT3 is not set +CONFIG_ETRAX_RESCUE_SER0=y +# CONFIG_ETRAX_RESCUE_SER1 is not set +# CONFIG_ETRAX_RESCUE_SER2 is not set +# CONFIG_ETRAX_RESCUE_SER3 is not set +CONFIG_ETRAX_DEF_R_WAITSTATES=95a6 +CONFIG_ETRAX_DEF_R_BUS_CONFIG=104 +# CONFIG_ETRAX_SDRAM is not set +CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040 +CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611 +CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d +CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0 +CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 +CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e +CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 # # Drivers for Etrax built-in interfaces @@ -56,6 +62,82 @@ CONFIG_ETRAX_ETHERNET=y CONFIG_NET_ETHERNET=y CONFIG_ETRAX_SERIAL=y +# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set +CONFIG_ETRAX_SERIAL_PORT1=y +# CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set +# CONFIG_ETRAX_SERIAL_PORT2 is not set +# CONFIG_ETRAX_SERIAL_PORT3 is not set +# CONFIG_ETRAX_RS485 is not set +# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set +# CONFIG_ETRAX_IDE is not set +CONFIG_ETRAX_AXISFLASHMAP=y +CONFIG_MTD=y +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_AMDSTD=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_ETRAX_I2C=y +CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y +CONFIG_ETRAX_GPIO=y +CONFIG_ETRAX_PA_BUTTON_BITMASK=02 +CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF +CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF +# CONFIG_ETRAX_USB_HOST is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_GEOMETRY is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_AMDSTD=y +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_SBC_MEDIAGX is not set +# CONFIG_MTD_ELAN_104NC is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_CSTM_CFI_JEDEC is not set +# CONFIG_MTD_JEDEC is not set +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_VMAX is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_SPIA is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices @@ -90,10 +172,6 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set - -# -# -# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -101,6 +179,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -112,11 +191,61 @@ # CONFIG_NET_SCHED is not set # +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# IDE, ATA and ATAPI Block devices +# +# CONFIG_BLK_DEV_IDE is not set +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_IDEDISK is not set +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set + +# # SCSI support # # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -177,6 +306,16 @@ # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -187,6 +326,60 @@ # CONFIG_CD_NO_IDESCSI is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# # File systems # # CONFIG_QUOTA is not set @@ -259,59 +452,14 @@ # CONFIG_NLS is not set # -# Character devices -# -# CONFIG_VT is not set -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver +# Sound # -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set +# CONFIG_SOUND is not set # -# Sound +# USB support # -# CONFIG_SOUND is not set +# CONFIG_USB is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/Config.in linux.ac/arch/cris/drivers/Config.in --- linux.vanilla/arch/cris/drivers/Config.in Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/Config.in Thu Apr 19 14:13:36 2001 @@ -1,16 +1,89 @@ mainmenu_option next_comment -comment 'Drivers for Etrax built-in interfaces' +comment 'Drivers for ETRAX 100LX built-in interfaces' -bool 'Ethernet support' CONFIG_ETRAX_ETHERNET y +bool 'Ethernet support' CONFIG_ETRAX_ETHERNET if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then # this is just so that the user does not have to go into the # normal ethernet driver section just to enable ethernetworking define_bool CONFIG_NET_ETHERNET y +else + define_bool CONFIG_NET_ETHERNET n fi -bool 'Serial-port support' CONFIG_ETRAX_SERIAL y +bool 'Serial-port support' CONFIG_ETRAX_SERIAL +if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then + comment ' Port 0 is always enabled' + bool ' Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB + if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" ]; then + int ' Ser0 DTR on PB bit' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4 + int ' Ser0 RI on PB bit' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5 + int ' Ser0 DSR on PB bit' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6 + int ' Ser0 CD on PB bit' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7 + fi + + bool ' Serial port 1 enabled' CONFIG_ETRAX_SERIAL_PORT1 + if [ "$CONFIG_ETRAX_SERIAL_PORT1" = "y" ]; then + bool ' Ser1 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB + if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then + int ' Ser1 DTR on PB bit' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4 + int ' Ser1 RI on PB bit' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5 + int ' Ser1 DSR on PB bit' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6 + int ' Ser1 CD on PB bit' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7 + fi + fi + if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -a \ + "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then + comment 'Make sure you dont have the same PB bits more than once!' + fi + bool ' Serial port 2 enabled' CONFIG_ETRAX_SERIAL_PORT2 + if [ "$CONFIG_ETRAX_SERIAL_PORT2" = "y" ]; then + bool ' Ser2 DTR, RI, DSR, CD on PA' CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA + if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" ]; then + int ' Ser2 DTR on PA bit' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4 + int ' Ser2 RI on PA bit' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5 + int ' Ser2 DSR on PA bit' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6 + int ' Ser2 CD on PA bit' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7 + fi + fi + bool ' Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3 + bool ' RS-485 support' CONFIG_ETRAX_RS485 + if [ "$CONFIG_ETRAX_RS485" = "y" ]; then + bool ' RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA + if [ "$CONFIG_ETRAX_RS485_ON_PA" = "y" ]; then + int ' RS-485 mode on PA bit' CONFIG_ETRAX_RS485_ON_PA_BIT 3 + fi + bool ' Disable serial receiver' CONFIG_ETRAX_RS485_DISABLE_RECEIVER + fi +fi + +bool 'Synchronous serial port support' CONFIG_ETRAX_SYNCHRONOUS_SERIAL +if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL" = "y" ]; then + bool ' Synchronous serial port 0 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0 + if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0" = "y" ]; then + bool ' Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA + fi + bool ' Synchronous serial port 1 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1 + if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1" = "y" ]; then + bool ' Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA + fi +fi + +bool 'Parallel port support' CONFIG_ETRAX_PARPORT +if [ "$CONFIG_ETRAX_PARPORT" = "y" ]; then + bool ' Parallel port 0 enabled' CONFIG_ETRAX_PARALLEL_PORT0 + bool ' Parallel port 1 enabled' CONFIG_ETRAX_PARALLEL_PORT1 +# here we define the CONFIG_'s necessary to enable parallel port support + define_tristate CONFIG_PARPORT y + define_bool CONFIG_PARPORT_1284 y + define_tristate CONFIG_PRINTER y +else + define_tristate CONFIG_PARPORT n + define_bool CONFIG_PARPORT_1284 n + define_tristate CONFIG_PRINTER n +fi -bool 'ATA/IDE support' CONFIG_ETRAX_IDE n + +bool 'ATA/IDE support' CONFIG_ETRAX_IDE if [ "$CONFIG_ETRAX_IDE" = "y" ]; then # here we should add the CONFIG_'s necessary to enable the basic @@ -25,16 +98,22 @@ define_bool CONFIG_BLK_DEV_IDEDMA y define_bool CONFIG_DMA_NONPCI y - + + int 'Delay for drives to regain consciousness' CONFIG_IDE_DELAY 15 + choice 'IDE reset pin' \ "Port_PB_Bit_7 CONFIG_ETRAX_IDE_PB7_RESET\ Port_G_Bit_27 CONFIG_ETRAX_IDE_G27_RESET\ - Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7 + Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET\ + Port_CSP0_Bit_08 CONFIG_ETRAX_IDE_CSP0_8_RESET" Port_PB_Bit_7 +else + define_bool CONFIG_IDE n fi -bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP n +bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then + int ' Byte-offset of partition table sector' CONFIG_ETRAX_PTABLE_SECTOR 65536 # here we define the CONFIG_'s necessary to enable MTD support # for the flash define_bool CONFIG_MTD y @@ -43,7 +122,58 @@ define_bool CONFIG_MTD_CFI_INTELEXT n define_bool CONFIG_MTD_CFI_AMDSTD y + define_bool CONFIG_MTD_AMDSTD y + define_bool CONFIG_MTD_CHAR y + define_bool CONFIG_MTD_BLOCK y +fi + +bool 'I2C support' CONFIG_ETRAX_I2C +if [ "$CONFIG_ETRAX_I2C" = "y" ]; then +# this is true for most products since PB-I2C seems to be somewhat +# flawed.. + bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C +fi + +bool 'I2C EEPROM (non-volatile RAM) support' CONFIG_ETRAX_I2C_EEPROM +if [ "$CONFIG_ETRAX_I2C_EEPROM" = "y" ]; then + choice ' EEPROM size' \ + "Probed CONFIG_ETRAX_I2C_EEPROM_PROBE \ + 2kB CONFIG_ETRAX_I2C_EEPROM_2KB \ + 8kB CONFIG_ETRAX_I2C_EEPROM_8KB \ + 16kB CONFIG_ETRAX_I2C_EEPROM_16KB" Probed +fi + +bool 'GPIO support' CONFIG_ETRAX_GPIO +if [ "$CONFIG_ETRAX_GPIO" = "y" ]; then + hex ' PA-buttons bitmask' CONFIG_ETRAX_PA_BUTTON_BITMASK 02 + hex ' PA user changeable dir mask' CONFIG_ETRAX_PA_CHANGEABLE_DIR 00 + hex ' PA user changeable bits mask' CONFIG_ETRAX_PA_CHANGEABLE_BITS FF + hex ' PB user changeable dir mask' CONFIG_ETRAX_PB_CHANGEABLE_DIR 00 + hex ' PB user changeable bits mask' CONFIG_ETRAX_PB_CHANGEABLE_BITS FF +fi + +bool 'ARTPEC-1 support' CONFIG_JULIETTE + +if [ "$CONFIG_JULIETTE" = "y" ]; then + source arch/cris/drivers/juliette/Config.in +fi + +bool 'USB host' CONFIG_ETRAX_USB_HOST +if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then + define_bool CONFIG_USB y + bool ' USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 + bool ' USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 +else + define_bool CONFIG_USB n +fi + +bool 'DS1302 Real Time Clock support' CONFIG_ETRAX_DS1302 +if [ "$CONFIG_ETRAX_DS1302" = "y" ]; then + bool ' DS1302 RST on Generic Port' CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + int ' DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2 + int ' DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1 + int ' DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0 fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/Makefile linux.ac/arch/cris/drivers/Makefile --- linux.vanilla/arch/cris/drivers/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/Makefile Thu Apr 19 14:13:36 2001 @@ -6,9 +6,19 @@ obj-y := -obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o -obj-$(CONFIG_ETRAX_SERIAL) += serial.o -obj-$(CONFIG_ETRAX_IDE) += ide.o -obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o + +obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o +obj-$(CONFIG_ETRAX_SERIAL) += serial.o +obj-$(CONFIG_ETRAX_IDE) += ide.o +obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o +obj-$(CONFIG_ETRAX_I2C) += i2c.o +obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o +obj-$(CONFIG_ETRAX_GPIO) += gpio.o +obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o +obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o +obj-$(CONFIG_ETRAX_PARPORT) += parport.o +obj-$(CONFIG_ETRAX_DS1302) += ds1302.o + + include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/axisflashmap.c linux.ac/arch/cris/drivers/axisflashmap.c --- linux.vanilla/arch/cris/drivers/axisflashmap.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/axisflashmap.c Thu Apr 19 14:13:36 2001 @@ -11,6 +11,26 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.7 2001/04/05 13:41:46 markusl + * Updated according to review remarks + * + * Revision 1.6 2001/03/07 09:21:21 bjornw + * No need to waste .data + * + * Revision 1.5 2001/03/06 16:27:01 jonashg + * Probe the entire flash area for flash devices. + * + * Revision 1.4 2001/02/23 12:47:15 bjornw + * Uncached flash in LOW_MAP moved from 0xe to 0x8 + * + * Revision 1.3 2001/02/16 12:11:45 jonashg + * MTD driver amd_flash is now included in MTD CVS repository. + * (It's now in drivers/mtd). + * + * Revision 1.2 2001/02/09 11:12:22 jonashg + * Support for AMD compatible non-CFI flash chips. + * Only tested with Toshiba TC58FVT160 so far. + * * Revision 1.1 2001/01/12 17:01:18 bjornw * * Added axisflashmap.c, a physical mapping for MTD that reads and understands * Axis partition-table format. @@ -31,7 +51,7 @@ #include #ifdef CONFIG_CRIS_LOW_MAP -#define FLASH_UNCACHED_ADDR KSEG_E +#define FLASH_UNCACHED_ADDR KSEG_8 #define FLASH_CACHED_ADDR KSEG_5 #else #define FLASH_UNCACHED_ADDR KSEG_E @@ -39,19 +59,13 @@ #endif /* - * WINDOW_SIZE is the total size where the flash chips are mapped, - * my guess is that this can be the total memory area even if there - * are many flash chips inside the area or if they are not all mounted. - * So possibly we can get rid of the CONFIG_ here and just write something - * like 32 MB always. - */ - -#define WINDOW_SIZE (CONFIG_ETRAX_FLASH_LENGTH * 1024 * 1024) - -/* Byte-offset where the partition-table is placed in the first chip + * WINDOW_SIZE is the total size where the flash chips may be mapped. + * MTD probes should find all devices there and it does not matter + * if there are unmapped gaps or aliases (mirrors of flash devices). + * The MTD probes will ignore them. */ -#define PTABLE_SECTOR 65536 +#define WINDOW_SIZE (128 * 1024 * 1024) /* * Map driver @@ -59,8 +73,6 @@ * Ok this is the scoop - we need to access the flash both with and without * the cache - without when doing all the fancy flash interfacing, and with * when we do actual copying because otherwise it will be slow like molasses. - * I hope this works the way it's intended, so that there won't be any cases - * of non-synchronicity because of the different access modes below... */ static __u8 flash_read8(struct map_info *map, unsigned long ofs) @@ -99,12 +111,6 @@ *(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d; } -static void flash_copy_to(struct map_info *map, unsigned long to, - const void *from, ssize_t len) -{ - memcpy((void *)(FLASH_CACHED_ADDR + to), from, len); -} - static struct map_info axis_map = { name: "Axis flash", size: WINDOW_SIZE, @@ -116,7 +122,6 @@ write8: flash_write8, write16: flash_write16, write32: flash_write32, - copy_to: flash_copy_to }; /* If no partition-table was found, we use this default-set. @@ -128,18 +133,18 @@ static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { { name: "boot firmware", - size: PTABLE_SECTOR, + size: CONFIG_ETRAX_PTABLE_SECTOR, offset: 0 }, { name: "kernel", size: 0x1a0000, - offset: PTABLE_SECTOR + offset: CONFIG_ETRAX_PTABLE_SECTOR }, { name: "filesystem", size: 0x50000, - offset: (0x1a0000 + PTABLE_SECTOR) + offset: (0x1a0000 + CONFIG_ETRAX_PTABLE_SECTOR) } }; @@ -203,10 +208,16 @@ printk(KERN_NOTICE "Axis flash mapping: %x at %x\n", WINDOW_SIZE, FLASH_CACHED_ADDR); - mymtd = do_cfi_probe(&axis_map); + mymtd = (struct mtd_info *)do_cfi_probe(&axis_map); + +#ifdef CONFIG_MTD_AMDSTD + if (!mymtd) { + mymtd = (struct mtd_info *)do_amd_flash_probe(&axis_map); + } +#endif if(!mymtd) { - printk("cfi_probe erred %d\n", mymtd); + printk("%s: No flash chip found!\n", axis_map.name); return -ENXIO; } @@ -218,18 +229,16 @@ * now at least. */ - ptable_head = FLASH_CACHED_ADDR + PTABLE_SECTOR + PARTITION_TABLE_OFFSET; + ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + + CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); pidx++; /* first partition is always set to the default */ if ((ptable_head->magic == PARTITION_TABLE_MAGIC) - && (ptable_head->size - < (MAX_PARTITIONS - * sizeof(struct partitiontable_entry) + 4)) - && (*(unsigned long*) - ((void*)ptable_head - + sizeof(*ptable_head) - + ptable_head->size - 4) - == PARTITIONTABLE_END_MARKER)) { + && (ptable_head->size < + (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + 4)) + && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + + ptable_head->size - 4) + == PARTITIONTABLE_END_MARKER)) { /* Looks like a start, sane length and end of a * partition table, lets check csum etc. */ @@ -238,7 +247,7 @@ (struct partitiontable_entry *) ((unsigned long)ptable_head + sizeof(*ptable_head) + ptable_head->size); - unsigned long offset = PTABLE_SECTOR; + unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; unsigned char *p; unsigned long csum = 0; @@ -275,16 +284,7 @@ && ptable->offset != 0xffffffff && ptable < max_addr && pidx < MAX_PARTITIONS) { -#if 0 - /* wait with multi-chip support until we know - * how mtd detects multiple chips - */ - if ((offset + ptable->offset) >= chips[0].size) { - partitions[pidx].start - = offset + chips[1].start - + ptable->offset - chips[0].size; - } -#endif + axis_partitions[pidx].offset = offset + ptable->offset; axis_partitions[pidx].size = ptable->size; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/ds1302.c linux.ac/arch/cris/drivers/ds1302.c --- linux.vanilla/arch/cris/drivers/ds1302.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/ds1302.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,488 @@ +/*!*************************************************************************** +*! +*! FILE NAME : ds1302.c +*! +*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O +*! +*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status +*! +*! $Log: ds1302.c,v $ +*! Revision 1.3 2001/03/26 16:03:06 bjornw +*! Needs linux/config.h +*! +*! Revision 1.2 2001/03/20 19:42:00 bjornw +*! Use the ETRAX prefix on the DS1302 options +*! +*! Revision 1.1 2001/03/20 09:13:50 magnusmn +*! Linux 2.4 port +*! +*! Revision 1.10 2000/07/05 15:38:23 bjornw +*! Dont update kernel time when a RTC_SET_TIME is done +*! +*! Revision 1.9 2000/03/02 15:42:59 macce +*! * Hack to make RTC work on all 2100/2400 +*! +*! Revision 1.8 2000/02/23 16:59:18 torbjore +*! added setup of R_GEN_CONFIG when RTC is connected to the generic port. +*! +*! Revision 1.7 2000/01/17 15:51:43 johana +*! Added RTC_SET_CHARGE ioctl to enable trickle charger. +*! +*! Revision 1.6 1999/10/27 13:19:47 bjornw +*! Added update_xtime_from_cmos which reads back the updated RTC into the kernel. +*! /dev/rtc calls it now. +*! +*! Revision 1.5 1999/10/27 12:39:37 bjornw +*! Disabled superuser check. Anyone can now set the time. +*! +*! Revision 1.4 1999/09/02 13:27:46 pkj +*! Added shadow for R_PORT_PB_CONFIG. +*! Renamed port_g_shadow to port_g_data_shadow. +*! +*! Revision 1.3 1999/09/02 08:28:06 pkj +*! Made it possible to select either port PB or the generic port for the RST +*! signal line to the DS1302 RTC. +*! Also make sure the RST bit is configured as output on Port PB (if used). +*! +*! Revision 1.2 1999/09/01 14:47:20 bjornw +*! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read +*! and set the date. Register as major 121. +*! +*! Revision 1.1 1999/09/01 09:45:29 bjornw +*! Implemented a DS1302 RTC driver. +*! +*! +*! --------------------------------------------------------------------------- +*! +*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! +*! $Id: ds1302.c,v 1.3 2001/03/26 16:03:06 bjornw Exp $ +*! +*!***************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define RTC_MAJOR_NR 121 /* local major, change later */ + +/* The DS1302 might be connected to different bits on different products. + * It has three signals - SDA, SCL and RST. RST and SCL are always outputs, + * but SDA can have a selected direction. + * For now, only PORT_PB is hardcoded. + */ + +/* The RST bit may be on either the Generic Port or Port PB */ +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT +#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#define TK_RST_DIR(x) +#else +#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#endif + + +#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) +#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) + +#define TK_SDA_IN() ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1) +/* 1 is out, 0 is in */ +#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) +#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) + + +/* + * The reason for tempudelay and not udelay is that loops_per_usec + * (used in udelay) is not set when functions here are called from time.c + */ + +static void tempudelay(int time) +{ + int i; + for(i = 0; i < time * 10000; i++); +} + + +/* send 8 bits */ +static void +out_byte(int x) +{ + int i; + TK_SDA_DIR(1); + for (i = 8; i--;) { + /* the chip latches incoming bits on the rising edge of SCL */ + TK_SCL_OUT(0); + TK_SDA_OUT(x & 1); + tempudelay(1); + TK_SCL_OUT(1); + tempudelay(1); + x >>= 1; + } + TK_SDA_DIR(0); +} + +static unsigned char +in_byte(void) +{ + unsigned char x = 0; + int i; + + /* Read byte. Bits come LSB first, on the falling edge of SCL. + * Assume SDA is in input direction already + */ + TK_SDA_DIR(0); + + for (i = 8; i--;) { + TK_SCL_OUT(0); + tempudelay(1); + x >>= 1; + x |= (TK_SDA_IN() << 7); + TK_SCL_OUT(1); + tempudelay(1); + } + + return x; +} + +/* prepares for a transaction by de-activating RST (active-low) */ + +static void +start(void) +{ + TK_SCL_OUT(0); + tempudelay(1); + TK_RST_OUT(0); + tempudelay(5); + TK_RST_OUT(1); +} + +/* ends a transaction by taking RST active again */ + +static void +stop(void) +{ + tempudelay(2); + TK_RST_OUT(0); +} + +/* enable writing */ + +static void +ds1302_wenable(void) +{ + start(); + out_byte(0x8e); /* Write control register */ + out_byte(0x00); /* Disable write protect bit 7 = 0 */ + stop(); +} + +/* disable writing */ + +static void +ds1302_wdisable(void) +{ + start(); + out_byte(0x8e); /* Write control register */ + out_byte(0x80); /* Disable write protect bit 7 = 0 */ + stop(); +} + +/* probe for the chip by writing something to its RAM and try reading it back */ + +static int +ds1302_probe(void) +{ + int retval, res; + + TK_RST_DIR(1); + TK_SCL_DIR(1); + TK_SDA_DIR(0); + + /* try to talk to timekeeper */ + + ds1302_wenable(); + start(); + out_byte(0xc0); /* write RAM byte 0 */ + out_byte(0x42); /* write something magic */ + start(); + out_byte(0xc1); /* read RAM byte 0 */ + + if((res = in_byte()) == 0x42) { + char buf[100]; + stop(); + ds1302_wdisable(); + printk("DS1302 RTC found.\n"); + printk("SDA, SCL, RST on PB%i, PB%i, %s%i\n", + CONFIG_ETRAX_DS1302_SDABIT, + CONFIG_ETRAX_DS1302_SCLBIT, +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + "GENIO", +#else + "PB", +#endif + CONFIG_ETRAX_DS1302_RSTBIT + ); + get_rtc_status(buf); + printk(buf); + retval = 1; + } else { + stop(); + printk("DS1302 RTC not found.\n"); + retval = 0; + } + + return retval; +} + + +/* read a byte from the selected register in the DS1302 */ + +unsigned char +ds1302_readreg(int reg) +{ + unsigned char x; + + start(); + out_byte(0x81 | (reg << 1)); /* Read register */ + x = in_byte(); + stop(); + + return x; +} + +/* write a byte to the selected register */ + +void +ds1302_writereg(int reg, unsigned char val) +{ + ds1302_wenable(); + start(); + out_byte(0x80 | (reg << 1)); /* Write register */ + out_byte(val); + stop(); + ds1302_wdisable(); +} + +void +get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); + rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); + rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); + rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); + rtc_tm->tm_year = CMOS_READ(RTC_YEAR); + + restore_flags(flags); + + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + + if (rtc_tm->tm_year <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +static unsigned char days_in_mo[] = + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date) */ + +static int +rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned long flags; + + switch(cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + struct rtc_time rtc_tm; + + get_rtc_time(&rtc_tm); + if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) + return -EFAULT; + return 0; + } + + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control, save_freq_select; + unsigned int yrs; +#if 0 + if (!suser()) + return -EACCES; +#endif + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + + if ((yrs < 1970) || (yrs > 2069)) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if (yrs >= 2000) + yrs -= 2000; /* RTC (0, 1, ... 69) */ + else + yrs -= 1900; /* RTC (70, 71, ... 99) */ + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + save_flags(flags); + cli(); + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + restore_flags(flags); + + /* notice that at this point, the RTC is updated but the kernel + * is still running with the old time. you need to set that + * separately with settimeofday or adjtimex. + */ + return 0; + } + + case RTC_SET_CHARGE: /* Set the RTC TRICKLE CHARGE register */ + { + int tcs_val; + unsigned char save_control, save_freq_select; +#if 0 + if (!suser()) + return -EACCES; +#endif + + if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) + return -EFAULT; + + tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); + ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +/* + * Info exported via "/proc/rtc". + */ + +int +get_rtc_status(char *buf) +{ + char *p; + struct rtc_time tm; + + p = buf; + + get_rtc_time(&tm); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + + return p - buf; +} + + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + ioctl: rtc_ioctl, +}; + +/* just probe for the RTC and register the device to handle the ioctl needed */ + +int +ds1302_init(void) +{ + + /* Ugly hack to handle both 2100 and 2400 hardware. + Remove... + */ + if(!ds1302_probe()) { +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + /* + * Make sure that R_GEN_CONFIG is + * setup correct. + */ + genconfig_shadow = ( (genconfig_shadow & ~IO_MASK(R_GEN_CONFIG, ata) ) | + ( IO_STATE( R_GEN_CONFIG, ata, select ) ) ); + *R_GEN_CONFIG = genconfig_shadow; + if(!ds1302_probe()) + return -1; +#else + return -1; +#endif + } + + if (register_chrdev(RTC_MAJOR_NR, "rtc", &rtc_fops)) { + printk("unable to get major %d for rtc\n", RTC_MAJOR_NR); + return -1; + } + return 0; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/eeprom.c linux.ac/arch/cris/drivers/eeprom.c --- linux.vanilla/arch/cris/drivers/eeprom.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/eeprom.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,1161 @@ +/*!************************************************************************** +*! +*! FILE NAME: e100eeprom.c +*! +*! DESCRIPTION: Implements an interface for i2c compatible eeproms to run +*! under linux. +*! Supports 2k, 8k(?) and 16k +*! Uses adaptive timing adjustents by Johan.Adolfsson@axis.com +*! Probing results: +*! 8k or not is detected (the assumes 2k or 16k) +*! 2k or 16k detected using test reads and writes. +*! +*! FUNCTIONS: +*! +*! (Exported) +*! eeprom_init() +*! +*! (Local) +*! +*! eeprom_open() +*! eeprom_lseek() +*! eeprom_read() +*! eeprom_write() +*! eeprom_close() +*! eeprom_address() +*! eeprom_disable_write_protect() +*! +*! +*! $Id: eeprom.c,v 1.3 2001/03/19 16:04:46 markusl Exp $ +*! +*!------------------------------------------------------------------------ +*! HISTORY +*! +*! DATE NAME CHANGES +*! ---- ---- ------- +*! Aug 28 1999 Edgar Iglesias Initial Version +*! Aug 31 1999 Edgar Iglesias Allow simultaneous users. +*! Sep 03 1999 Edgar Iglesias Updated probe. +*! Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*! in the spin-lock. +*! +*! $Log: eeprom.c,v $ +*! Revision 1.3 2001/03/19 16:04:46 markusl +*! Fixed init of fops struct +*! +*! Revision 1.2 2001/03/19 10:35:07 markusl +*! 2.4 port of eeprom driver +*! +*! Revision 1.8 2000/05/18 10:42:25 edgar +*! Make sure to end write cycle on _every_ write +*! +*! Revision 1.7 2000/01/17 17:41:01 johana +*! Adjusted probing and return -ENOSPC when writing outside EEPROM +*! +*! Revision 1.6 2000/01/17 15:50:36 johana +*! Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?) +*! EEPROMs +*! +*! Revision 1.5 1999/09/03 15:07:37 edgar +*! Added bail-out check to the spinlock +*! +*! Revision 1.4 1999/09/03 12:11:17 bjornw +*! Proper atomicity (need to use spinlocks, not if's). users -> busy. +*! +*! +*! (c) 1999 Axis Communications AB, Lund, Sweden +*!**************************************************************************/ + +/********************** INCLUDE FILES SECTION ******************************/ + +#include +#include +#include +#include +#include +#include +#include "i2c.h" + +/********************** CONSTANT AND MACRO SECTION *************************/ +#define D(x) + +/* If we should use adaptive timing or not: */ +//#define EEPROM_ADAPTIVE_TIMING + +#define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */ +#define EEPROM_MINOR_NR 0 + +#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */ +/* + * this one defines how many times to try when eeprom fails. + */ +#define EEPROM_RETRIES 10 + +#define EEPROM_2KB (2 * 1024) +/*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */ +#define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */ +#define EEPROM_16KB (16 * 1024) + +#define i2c_delay(x) udelay(x) + +/********************** TYPE DEFINITION SECTION ****************************/ + +/* + * This structure describes the attached eeprom chip. + * The values are probed for. + */ + +struct eeprom_type +{ + unsigned long size; + unsigned long sequential_write_pagesize; + unsigned char select_cmd; + unsigned long usec_delay_writecycles; /* Min time between write cycles (up to 10ms for some models) */ + unsigned long int usec_delay_step; /* For adaptive algorithm */ + int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */ + + /* this one is to keep the read/write operations atomic */ + wait_queue_head_t wait_q; + int busy; + int retry_cnt_addr; /* Used to keep track of number of retries for + adaptive timing adjustments */ + int retry_cnt_read; + + + +}; + +/********************** LOCAL FUNCTION DECLARATION SECTION *****************/ + +static int eeprom_open (struct inode * inode, struct file * file); +static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig); +static ssize_t eeprom_read (struct file * file, char * buf, size_t count, loff_t *off); +static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off); +static int eeprom_close(struct inode * inode, struct file * file); + +static int eeprom_address(unsigned long addr); +static int read_from_eeprom(char * buf, int count); +static int eeprom_write_buf(unsigned long int addr, + const char * buf, int count); +static int eeprom_read_buf(unsigned long addr, + char * buf, int count); + +static void eeprom_disable_write_protect(void); + + +/********************** GLOBAL VARIABLE DECLARATION SECTION ****************/ + +/********************** LOCAL VARIABLE DECLARATION SECTION *****************/ + +/* chip description */ +static struct eeprom_type eeprom; + +/* + * This is the exported file-operations structure + * for this device. + */ + +struct file_operations eeprom_fops = +{ + llseek: eeprom_lseek, + read: eeprom_read, + write: eeprom_write, + open: eeprom_open, + release: eeprom_close +}; + +/********************** FUNCTION DEFINITION SECTION ************************/ + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_init +*# +*# PARAMETERS : none +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : eeprom init call. Probes for different eeprom models. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Updated probing. Added forced values. +*# +*#**************************************************************************/ + +int __init eeprom_init(void) +{ + init_waitqueue_head(&eeprom.wait_q); + eeprom.busy = 0; + +#if CONFIG_ETRAX_I2C_EEPROM_PROBE +#define EETEXT "Found" +#else +#define EETEXT "Assuming" +#endif + if (register_chrdev(EEPROM_MAJOR_NR, "mem", &eeprom_fops)) + { + printk("unable to get major %d for eeprom device\n", EEPROM_MAJOR_NR); + return -1; + } + + printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n"); + + /* + * Note: Most of this probing method was taken from the printserver (5470e) + * codebase. It did not contain a way of finding the 16Kb chips + * (M24128 or variants). The method used here might not work + * for all models. If you encounter problems the easiest way + * is probably to define your model within #ifdef's, and hard- + * code it. + * + */ + + eeprom.size = 0; + eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/ + eeprom.usec_delay_step = 128; + eeprom.adapt_state = 0; + +#if CONFIG_ETRAX_I2C_EEPROM_PROBE + i2c_start(); + i2c_outbyte(0x80); + if(!i2c_getack()) + { + /* It's not 8k.. */ + int success = 0; + unsigned char buf_2k_start[16]; + + /* Im not sure this will work... :) */ + /* assume 2Kb, if failure go for 16Kb */ + /* Test with 16kB settings.. */ + /* If it's a 2kB EEPROM and we address it outside it's range + * it will mirror the address space: + * 1. We read two locations (that are mirrored), + * if the content differs * it's a 16kB EEPROM. + * 2. if it doesn't differ - write diferent value to one of the locations, + * check the other - if content still is the same it's a 2k EEPROM, + * restore original data. + * + */ +#define LOC1 8 +#define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */ + + /* 2k settings */ + i2c_stop(); + eeprom.size = EEPROM_2KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 16; + if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 ) + { + D(printk("2k start: '%16.16s'\n", buf_2k_start)); + } + else + { + printk("Failed to read in 2k mode!\n"); + } + + /* 16k settings */ + eeprom.size = EEPROM_16KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 64; + + { + unsigned char loc1[4], loc2[4], tmp[4]; + if( eeprom_read_buf(LOC2, loc2, 4) == 4) + { + if( eeprom_read_buf(LOC1, loc1, 4) == 4) + { + D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); +#if 0 + if (memcmp(loc1, loc2, 4) != 0 ) + { + /* It's 16k */ + printk("16k detected in step 1\n"); + eeprom.size = EEPROM_16KB; + success = 1; + } + else +#endif + { + /* Do step 2 check */ + /* Invert value */ + loc1[0] = ~loc1[0]; + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + /* If 2k EEPROM this write will actually write 10 bytes + * from pos 0 + */ + D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); + if( eeprom_read_buf(LOC1, tmp, 4) == 4) + { + D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n", + LOC1, loc1, tmp)); + if (memcmp(loc1, tmp, 4) != 0 ) + { + printk("read and write differs! Not 16kB\n"); + loc1[0] = ~loc1[0]; + + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + + } + i2c_stop(); + /* Go to 2k mode and write original data */ + eeprom.size = EEPROM_2KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 16; + if( eeprom_write_buf(0, buf_2k_start, 16) == 16) + { + } + else + { + printk("Failed to write back 2k start!\n"); + } + + eeprom.size = EEPROM_2KB; + } + } + + if(!success) + { + if( eeprom_read_buf(LOC2, loc2, 1) == 1) + { + D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); + if (memcmp(loc1, loc2, 4) == 0 ) + { + /* Data the same, must be mirrored -> 2k */ + /* Restore data */ + printk("2k detected in step 2\n"); + loc1[0] = ~loc1[0]; + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + + } + + eeprom.size = EEPROM_2KB; + } + else + { + printk("16k detected in step 2\n"); + loc1[0] = ~loc1[0]; + /* Data differs, assume 16k */ + /* Restore data */ + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 16k failed during probe EEPROM might be corrupt!\n"); + } + + eeprom.size = EEPROM_16KB; + } + } + } + } + } /* read LOC1 */ + } /* address LOC1 */ + if (!success) + { + printk("eeprom: Probing failed!, using 2KB!\n"); + eeprom.size = EEPROM_2KB; + } + } /* read */ + } + } + else + { + i2c_outbyte(0x00); + if(!i2c_getack()) + { + /* No 8k */ + eeprom.size = EEPROM_2KB; + } + else + { + i2c_start(); + i2c_outbyte(0x81); + if (!i2c_getack()) + { + eeprom.size = EEPROM_2KB; + } + else + { + /* It's a 8kB */ + i2c_inbyte(); + eeprom.size = EEPROM_8KB; + } + } + } + i2c_stop(); +#elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB) + eeprom.size = EEPROM_16KB; +#elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB) + eeprom.size = EEPROM_8KB; +#elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB) + eeprom.size = EEPROM_2KB; +#endif + + switch(eeprom.size) + { + case (EEPROM_2KB): + printk("e100eeprom: " EETEXT " i2c compatible 2Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 16; + eeprom.select_cmd = 0xA0; + break; + case (EEPROM_8KB): + printk("e100eeprom: " EETEXT " i2c compatible 8Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 16; + eeprom.select_cmd = 0x80; + break; + case (EEPROM_16KB): + printk("e100eeprom: " EETEXT " i2c compatible 16Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 64; + eeprom.select_cmd = 0xA0; + break; + default: + eeprom.size = 0; + printk("e100eeprom: Did not find a supported eeprom\n"); + break; + } + + + + eeprom_disable_write_protect(); + + return 0; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_open +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Opens the device. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Removed users check. +*# +*#**************************************************************************/ + +static int eeprom_open(struct inode * inode, struct file * file) +{ + + if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR) + return -ENXIO; + if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR) + return -ENXIO; + + if( eeprom.size > 0 ) + { + /* OK */ + return 0; + } + + /* No EEprom found */ + return -EFAULT; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_lseek +*# +*# PARAMETERS : file : Pointer to the file +*# offset : The offset (in bytes) +*# orig : look at the note +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Changes the current file position. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Return -EOVERFLOW when beyond eeprom size. +*# +*#**************************************************************************/ + +static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig) +{ +/* + * orig 0: position from begning of eeprom + * orig 1: relative from current position + * orig 2: position from last eeprom address + */ + + switch (orig) + { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + break; + case 2: + file->f_pos = eeprom.size - offset; + break; + default: + return -EINVAL; + } + + /* truncate position */ + if (file->f_pos < 0) + { + file->f_pos = 0; + return(-EOVERFLOW); + } + + if (file->f_pos >= eeprom.size) + { + file->f_pos = eeprom.size - 1; + return(-EOVERFLOW); + } + + return ( file->f_pos ); +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_read +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# buf : Destination buffer +*# count : max nr bytes to read +*# +*# RETURNS : number of read bytes. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Reads data from eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 17 2000 Johan Adolfsson Initial version +*# +*#**************************************************************************/ +static int eeprom_read_buf(unsigned long addr, + char * buf, int count) +{ + struct file f; + + f.f_pos = addr; + return eeprom_read(&f, buf, count, &addr); +} + + + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_read +*# +*# PARAMETERS : file : Pointer to the file +*# buf : Destination buffer +*# count : max nr bytes to read +*# +*# RETURNS : number of read bytes. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Reads data from eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues +*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*# in the spin-lock. +*# +*#**************************************************************************/ + +static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) +{ + int i, read=0; + unsigned long p = file->f_pos; + + unsigned char page; + + if(p >= eeprom.size) /* Address i 0 - (size-1) */ + { + return -EFAULT; + } + + while(eeprom.busy) + { + interruptible_sleep_on(&eeprom.wait_q); + + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; + + } + eeprom.busy++; + + page = (unsigned char) (p >> 8); + + if(!eeprom_address(p)) + { + printk("eeprom: Read failed to address the eeprom: " + "0x%08X (%i) page: %i\n", p, p, page); + i2c_stop(); + + /* don't forget to wake them up */ + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return -EFAULT; + } + + if( (p + count) > eeprom.size) + { + /* truncate count */ + count = eeprom.size - p; + } + + /* stop dummy write op and initiate the read op */ + i2c_start(); + + /* special case for small eeproms */ + if(eeprom.size < EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) ); + } + + /* go on with the actual read */ + read = read_from_eeprom( buf, count); + + if(read > 0) + { + file->f_pos += read; + } + + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return read; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_write_buf +*# +*# PARAMETERS : addr : Address to write to +*# buf : Data buffer to write from +*# count : number bytes to write +*# +*# RETURNS : number of bytes actualy written. +*# +*# SIDE EFFECTS : None +*# +*# DESCRIPTION : Writes data to eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 17 2000 Johan Adolfsson Initial vesion +*# +*#**************************************************************************/ +static int eeprom_write_buf(unsigned long int addr, + const char * buf, int count) +{ + struct file f; + + f.f_pos = addr; + + return eeprom_write(&f, buf, count, &addr); +} + + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_write +*# +*# PARAMETERS : file : Pointer to the file +*# buf : Data buffer to write from +*# count : number bytes to write +*# +*# RETURNS : number of bytes actualy written. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Writes data to eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues +*# Sep 03 1999 Edgar Iglesias Moved the actual reading to read_from_eeprom +*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*# in the spin-lock. +*# May 18 2000 Edgar Iglesias Make sure to end write cycle after every write. +*# +*#**************************************************************************/ + +static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, + loff_t *off) +{ + int i, written, restart=1; + unsigned long p; + + while(eeprom.busy) + { + interruptible_sleep_on(&eeprom.wait_q); + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; + } + eeprom.busy++; + for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) + { + restart = 0; + written = 0; + p = file->f_pos; + + + while( (written < count) && (p < eeprom.size)) + { + /* address the eeprom */ + if(!eeprom_address(p)) + { + printk("eeprom: Write failed to address the eeprom: 0x%08X (%i) \n", + p, p); + i2c_stop(); + + /* don't forget to wake them up */ + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return -EFAULT; + } +#ifdef EEPROM_ADAPTIVE_TIMING + /* Adaptive algorithm to adjust timing */ + if (eeprom.retry_cnt_addr > 0) + { + /* To Low now */ + D(printk(">D=%i d=%i\n", + eeprom.usec_delay_writecycles, eeprom.usec_delay_step)); + + if (eeprom.usec_delay_step < 4) + { + eeprom.usec_delay_step++; + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + } + else + { + + if (eeprom.adapt_state > 0) + { + /* To Low before */ + eeprom.usec_delay_step *= 2; + if (eeprom.usec_delay_step > 2) + { + eeprom.usec_delay_step--; + } + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + } + else if (eeprom.adapt_state < 0) + { + /* To High before (toggle dir) */ + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + if (eeprom.usec_delay_step > 1) + { + eeprom.usec_delay_step /= 2; + eeprom.usec_delay_step--; + } + } + } + + eeprom.adapt_state = 1; + } + else + { + /* To High (or good) now */ + D(printk(" 1) + { + if (eeprom.usec_delay_step > 0) + { + eeprom.usec_delay_step *= 2; + eeprom.usec_delay_step--; + } + + if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) + { + eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; + } + } + } + else if (eeprom.adapt_state > 0) + { + /* To Low before (toggle dir) */ + if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) + { + eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; + } + if (eeprom.usec_delay_step > 1) + { + eeprom.usec_delay_step /= 2; + eeprom.usec_delay_step--; + } + + eeprom.adapt_state = -1; + } + + if (eeprom.adapt_state > -100) + { + eeprom.adapt_state--; + } + else + { + /* Restart adaption */ + D(printk("#Restart\n")); + eeprom.usec_delay_step++; + } + } +#endif /* EEPROM_ADAPTIVE_TIMING */ + /* write until we hit a page boundary or count */ + do + { + i2c_outbyte(buf[written]); + if(!i2c_getack()) + { + restart=1; + printk("eeprom: write error, retrying. %d\n", i); + i2c_stop(); + break; + } + written++; + p++; + } while( written < count && ( p % eeprom.sequential_write_pagesize )); + + /* end write cycle */ + i2c_stop(); + i2c_delay(eeprom.usec_delay_writecycles); + } /* while */ + } /* for */ + + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + if (written == 0 && file->f_pos >= eeprom.size){ + return -ENOSPC; + } + file->f_pos += written; + return written; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_close +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# +*# RETURNS : nothing +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Closes the device. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Removed eeprom.users stuff. +*# +*#**************************************************************************/ + +static int eeprom_close(struct inode * inode, struct file * file) +{ + /* do nothing for now */ + return 0; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_address +*# +*# PARAMETERS : addr : Address to be given to eeprom +*# +*# RETURNS : 1 if OK, 0 if failure. +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Sets the current address of the eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Corrected typo. +*# +*#**************************************************************************/ + +static int eeprom_address(unsigned long addr) +{ + int i, j; + unsigned char page, offset; + + page = (unsigned char) (addr >> 8); + offset = (unsigned char) addr; + + for(i = 0; i < EEPROM_RETRIES; i++) + { + /* start a dummy write for addressing */ + i2c_start(); + + if(eeprom.size == EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd ); + i2c_getack(); + i2c_outbyte(page); + } + else + { + i2c_outbyte( eeprom.select_cmd | (page << 1) ); + } + if(!i2c_getack()) + { + /* retry */ + i2c_stop(); + /* Must have a delay here.. 500 works, >50, 100->works 5th time*/ + i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i); + /* The chip needs up to 10 ms from write stop to next start */ + + } + else + { + i2c_outbyte(offset); + + if(!i2c_getack()) + { + /* retry */ + i2c_stop(); + } + else + break; + } + } + + + eeprom.retry_cnt_addr = i; + D(printk("%i\n", eeprom.retry_cnt_addr)); + if(eeprom.retry_cnt_addr == EEPROM_RETRIES) + { + /* failed */ + return 0; + } + return 1; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: read_from_eeprom +*# +*# PARAMETERS : buf : Destination buffer. +*# count : Number of bytes to read. +*# +*# RETURNS : number of read bytes or -EFAULT. +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Reads from current adress. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Sep 03 1999 Edgar Iglesias Initial version +*# +*#**************************************************************************/ + +static int read_from_eeprom(char * buf, int count) +{ + int i, read=0; + + for(i = 0; i < EEPROM_RETRIES; i++) + { + if(eeprom.size == EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd | 1 ); + } + + if(i2c_getack()); + { + break; + } + } + + if(i == EEPROM_RETRIES) + { + printk("eeprom: failed to read from eeprom\n"); + i2c_stop(); + + return -EFAULT; + } + + while( (read < count)) + { + buf[read++] = i2c_inbyte(); + + /* + * make sure we don't ack last byte or you will get very strange + * results! + */ + if(read < count) + { + i2c_sendack(); + } + } + + /* stop the operation */ + i2c_stop(); + + return read; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_disable_write_protect +*# +*# PARAMETERS : None +*# +*# RETURNS : Nothing +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Disables write protection if applicable +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 14 2000 Johan Adolfsson Initial version (from PS pareerom.c) +*# +*#**************************************************************************/ +#define DBP_SAVE(x) +#define ax_printf printk +static void eeprom_disable_write_protect(void) +{ + /* Disable write protect */ + if (eeprom.size == EEPROM_8KB) + { + /* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 2\n")); + } + i2c_outbyte(0x02); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 3\n")); + } + i2c_stop(); + + i2c_delay(1000); + + /* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 55\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 52\n")); + } + i2c_outbyte(0x06); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 53\n")); + } + i2c_stop(); + + /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh*/ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 56\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 57\n")); + } + i2c_outbyte(0x06); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 58\n")); + } + i2c_stop(); + + /* Write protect disabled */ + } +} + +module_init(eeprom_init); + +/********************** END OF FILE e100eeprom.c *****************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/ethernet.c linux.ac/arch/cris/drivers/ethernet.c --- linux.vanilla/arch/cris/drivers/ethernet.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/drivers/ethernet.c Thu Apr 19 14:13:36 2001 @@ -1,12 +1,38 @@ -/* $Id: ethernet.c,v 1.5 2000/11/29 17:22:22 bjornw Exp $ +/* $Id: ethernet.c,v 1.12 2001/04/05 11:43:11 tobiasa Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * - * Copyright (c) 1998-2000 Axis Communications AB. + * Copyright (c) 1998-2001 Axis Communications AB. * * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.12 2001/04/05 11:43:11 tobiasa + * Check dev before panic. + * + * Revision 1.11 2001/04/04 11:21:05 markusl + * Updated according to review remarks + * + * Revision 1.10 2001/03/26 16:03:06 bjornw + * Needs linux/config.h + * + * Revision 1.9 2001/03/19 14:47:48 pkj + * * Make sure there is always a pause after the network LEDs are + * changed so they will not look constantly lit during heavy traffic. + * * Always use HZ when setting times relative to jiffies. + * * Use LED_NETWORK_SET() when setting the network LEDs. + * + * Revision 1.8 2001/02/27 13:52:48 bjornw + * malloc.h -> slab.h + * + * Revision 1.7 2001/02/23 13:46:38 bjornw + * Spellling check + * + * Revision 1.6 2001/01/26 15:21:04 starvik + * Don't disable interrupts while reading MDIO registers (MDIO is slow) + * Corrected promiscuous mode + * Improved deallocation of IRQs ("ifconfig eth0 down" now works) + * * Revision 1.5 2000/11/29 17:22:22 bjornw * Get rid of the udword types legacy stuff * @@ -29,23 +55,22 @@ * */ +#include + #include #include #include +#include #include #include #include #include #include #include -#include +#include #include -#include -#include #include -#include -#include #include #include @@ -53,12 +78,18 @@ #include #include -#include +#include /* DMA and register descriptions */ +#include /* LED_* I/O functions */ +#include +#include +#include //#define ETHDEBUG - #define D(x) +#define ETH_TX_DMA 0 +#define ETH_RX_DMA 1 + /* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels @@ -115,12 +146,12 @@ #define MDIO_PHYS_ADDR 0x0 /* Network flash constants */ -#define NET_FLASH_TIME 2 /* 20 ms */ -#define NET_LINK_UP_CHECK_INTERVAL 200 /* 2 s */ +#define NET_FLASH_TIME (HZ/50) /* 20 ms */ +#define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ +#define NET_LINK_UP_CHECK_INTERVAL (2*HZ) /* 2 s */ -/* RX_DESC_BUF_SIZE should be a multiple of four to avoid the buffer - * alignment bug in Etrax 100 release 1 - */ +#define NO_NETWORK_ACTIVITY 0 +#define NETWORK_ACTIVITY 1 #define RX_DESC_BUF_SIZE 256 #define NBR_OF_RX_DESC (RX_BUF_SIZE / \ @@ -135,8 +166,8 @@ static unsigned char RxBuf[RX_BUF_SIZE]; -static etrax_dma_descr RxDescList[NBR_OF_RX_DESC]; -static etrax_dma_descr TxDesc; +static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); +static etrax_dma_descr TxDesc __attribute__ ((aligned(4))); static struct sk_buff *tx_skb; @@ -144,8 +175,8 @@ static struct timer_list speed_timer; static struct timer_list clear_led_timer; static int current_speed; -static int led_clear_time; -static int nolink; +static int led_next_time; +static int led_active; /* Index to functions, as function prototypes. */ @@ -173,6 +204,7 @@ static void e100_reset_tranceiver(void); static void e100_clear_network_leds(unsigned long dummy); +static void e100_set_network_leds(int active); #define tx_done(dev) (*R_DMA_CH0_CMD == 0) @@ -190,7 +222,7 @@ int i; int anOffset = 0; - printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB\n"); + printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n"); dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ @@ -201,6 +233,8 @@ if (!dev) { printk("dev == NULL. Should this happen?\n"); dev = init_etherdev(dev, sizeof(struct net_local)); + if (!dev) + panic("init_etherdev failed\n"); } /* setup generic handlers and stuff in the dev struct */ @@ -261,13 +295,12 @@ /* Initialize speed indicator stuff. */ - nolink = 0; current_speed = 10; speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.function = e100_check_speed; add_timer(&speed_timer); clear_led_timer.function = e100_clear_network_leds; - clear_led_timer.expires = jiffies + 10; + clear_led_timer.expires = jiffies + HZ/10; add_timer(&clear_led_timer); return 0; @@ -334,8 +367,17 @@ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); - *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ - *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + *R_IRQ_MASK0_CLR = + IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); + + /* clear dma0 and 1 eop and descr irq masks */ + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Reset and wait for the DMA channels */ @@ -372,17 +414,17 @@ * and clean up on failure. */ - if(request_dma(0, cardname)) { + if(request_dma(ETH_TX_DMA, cardname)) { goto grace_exit; } - if(request_dma(1, cardname)) { + if(request_dma(ETH_RX_DMA, cardname)) { grace_exit: /* this will cause some 'trying to free free irq' but what the heck... */ - free_dma(0); - free_irq(NETWORK_DMARX_IRQ, NULL); - free_irq(NETWORK_DMATX_IRQ, NULL); - free_irq(NETWORK_STATUS_IRQ, NULL); + free_dma(ETH_TX_DMA); + free_irq(NETWORK_DMARX_IRQ, (void *)dev); + free_irq(NETWORK_DMATX_IRQ, (void *)dev); + free_irq(NETWORK_STATUS_IRQ, (void *)dev); return -EAGAIN; } @@ -455,21 +497,19 @@ e100_check_speed(unsigned long dummy) { unsigned long data; + int old_speed = current_speed; + data = e100_get_mdio_reg(MDIO_BASE_STATUS_REG); if (!(data & MDIO_LINK_UP_MASK)) { - nolink = 1; - LED_NETWORK_TX_SET(1); /* Make it red, link is down. */ + current_speed = 0; } else { - nolink = 0; - LED_NETWORK_TX_SET(0); /* Link is up again, clear red LED. */ data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); - if (data & MDIO_SPEED) { - current_speed = 100; - } else { - current_speed = 10; - } + current_speed = (data & MDIO_SPEED ? 100 : 10); } + if (old_speed != current_speed) + e100_set_network_leds(NO_NETWORK_ACTIVITY); + /* Reinitialize the timer. */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; add_timer(&speed_timer); @@ -483,9 +523,6 @@ unsigned short data; /* Data read from MDIO */ int bitCounter; - save_flags(flags); - cli(); - /* Start of frame, OP Code, Physical Address, Register Address */ cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (MDIO_PHYS_ADDR << 7) | (reg_num << 2); @@ -498,8 +535,7 @@ for(bitCounter=15; bitCounter>=0 ; bitCounter--) { data |= (e100_receive_mdio_bit() << bitCounter); } - - restore_flags(flags); + return data; } @@ -527,23 +563,26 @@ static void e100_send_mdio_bit(unsigned char bit) { - volatile int i; - *R_NETWORK_MGM_CTRL = 2 | bit&1; - for (i=40; i; i--); - *R_NETWORK_MGM_CTRL = 6 | bit&1; - for (i=40; i; i--); + *R_NETWORK_MGM_CTRL = + IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | + IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); + udelay(1); + *R_NETWORK_MGM_CTRL = + IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | + IO_MASK(R_NETWORK_MGM_CTRL, mdck) | + IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); + udelay(1); } static unsigned char e100_receive_mdio_bit() { unsigned char bit; - volatile int i; *R_NETWORK_MGM_CTRL = 0; - bit = *R_NETWORK_STAT & 1; - for (i=40; i; i--); - *R_NETWORK_MGM_CTRL = 4; - for (i=40; i; i--); + bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT); + udelay(1); + *R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck); + udelay(1); return bit; } @@ -555,22 +594,17 @@ unsigned short data; int bitCounter; - save_flags(flags); - cli(); - data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2); - e100_send_mdio_cmd(cmd, 0); + e100_send_mdio_cmd(cmd, 1); data |= 0x8000; for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) { e100_send_mdio_bit(GET_BIT(bitCounter, data)); } - - restore_flags(flags); } /* Called by upper layers if they decide it took too long to complete @@ -654,8 +688,8 @@ { struct net_device *dev = (struct net_device *)dev_id; unsigned long irqbits = *R_IRQ_MASK2_RD; - - if(irqbits & (1U << 3)) { + + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ @@ -669,10 +703,15 @@ */ e100_rx(dev); ((struct net_local *)dev->priv)->stats.rx_packets++; - *R_DMA_CH1_CMD = 3; /* restart/continue on the channel, for safety */ - *R_DMA_CH1_CLR_INTR = 3; /* clear dma channel 1 eop/descr irq bits */ - /* now, we might have gotten another packet so we have to loop back - and check if so */ + /* restart/continue on the channel, for safety */ + *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart); + /* clear dma channel 1 eop/descr irq bits */ + *R_DMA_CH1_CLR_INTR = + IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do); + + /* now, we might have gotten another packet + so we have to loop back and check if so */ } } } @@ -690,8 +729,9 @@ unsigned long irqbits = *R_IRQ_MASK2_RD; struct net_local *np = (struct net_local *)dev->priv; - if(irqbits & 2) { /* check for a dma0_eop interrupt */ - + /* check for a dma0_eop interrupt */ + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { + /* This protects us from concurrent execution of * our dev->hard_start_xmit function above. */ @@ -725,12 +765,14 @@ struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK0_RD; - if(irqbits & (1 << 19)) { /* check for overrun irq */ + /* check for overrun irq */ + if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { update_rx_stats(&np->stats); /* this will ack the irq */ D(printk("ethernet receiver overrun!\n")); } - if(irqbits & (1 << 17)) { /* check for excessive collision irq */ - *R_NETWORK_TR_CTRL = 1 << 8; /* clear the interrupt */ + /* check for excessive collision irq */ + if(irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { + *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); } @@ -744,23 +786,19 @@ struct sk_buff *skb; int length=0; int i; + struct net_local *np = (struct net_local *)dev->priv; struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; unsigned char *skb_data_ptr; - /* light the network rx packet depending on the current speed. - ** But only if link has been detected. - */ - if (!nolink) - if (current_speed == 10) { - LED_NETWORK_TX_SET(1); - LED_NETWORK_RX_SET(1); - } else - LED_NETWORK_RX_SET(1); - - /* Set the earliest time we may clear the LED */ + if (!led_active && jiffies > led_next_time) { + /* light the network leds depending on the current speed. */ + e100_set_network_leds(NETWORK_ACTIVITY); + + /* Set the earliest time we may clear the LED */ + led_next_time = jiffies + NET_FLASH_TIME; + led_active = 1; + } - led_clear_time = jiffies + NET_FLASH_TIME; - /* If the packet is broken down in many small packages then merge * count how much space we will need to alloc with skb_alloc() for * it to fit. @@ -788,6 +826,7 @@ skb = dev_alloc_skb(length - ETHER_HEAD_LEN); if (!skb) { + np->stats.rx_errors++; printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); return; @@ -796,7 +835,7 @@ skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ -#if 0 +#ifdef ETHDEBUG printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", skb->head, skb->data, skb->tail, skb->end); printk("copying packet to 0x%x.\n", skb_data_ptr); @@ -847,9 +886,17 @@ *R_NETWORK_GEN_CONFIG = IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); - - *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ - *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + + *R_IRQ_MASK0_CLR = + IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); + + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Stop the receiver and the transmitter */ @@ -858,12 +905,12 @@ /* Flush the Tx and disable Rx here. */ - free_irq(NETWORK_DMARX_IRQ, NULL); - free_irq(NETWORK_DMATX_IRQ, NULL); - free_irq(NETWORK_STATUS_IRQ, NULL); + free_irq(NETWORK_DMARX_IRQ, (void *)dev); + free_irq(NETWORK_DMATX_IRQ, (void *)dev); + free_irq(NETWORK_STATUS_IRQ, (void *)dev); - free_dma(0); - free_dma(1); + free_dma(ETH_TX_DMA); + free_dma(ETH_RX_DMA); /* Update the statistics here. */ @@ -926,10 +973,21 @@ /* promiscuous mode */ lo_bits = 0xfffffffful; hi_bits = 0xfffffffful; + + /* Enable individual receive */ + *R_NETWORK_REC_CONFIG = + IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable) | + IO_STATE(R_NETWORK_REC_CONFIG, individual, receive); } else if (num_addr == 0) { /* Normal, clear the mc list */ lo_bits = 0x00000000ul; hi_bits = 0x00000000ul; + + /* Disable individual receive */ + *R_NETWORK_REC_CONFIG = + IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable); } else { /* MC mode, receive normal and MC packets */ char hash_ix; @@ -971,6 +1029,10 @@ } dmi = dmi->next; } + /* Disable individual receive */ + *R_NETWORK_REC_CONFIG = + IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable); } *R_NETWORK_GA_0 = lo_bits; *R_NETWORK_GA_1 = hi_bits; @@ -980,22 +1042,16 @@ e100_hardware_send_packet(char *buf, int length) { D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); - /* light the network leds depending on the current speed. - ** But only if link has been detected. - */ - if (!nolink) { - if (current_speed == 10) { - LED_NETWORK_TX_SET(1); - LED_NETWORK_RX_SET(1); - } else { - LED_NETWORK_RX_SET(1); - } - } - /* Set the earliest time we may clear the LED */ + if (!led_active && jiffies > led_next_time) { + /* light the network leds depending on the current speed. */ + e100_set_network_leds(NETWORK_ACTIVITY); + + /* Set the earliest time we may clear the LED */ + led_next_time = jiffies + NET_FLASH_TIME; + led_active = 1; + } - led_clear_time = jiffies + NET_FLASH_TIME; - /* configure the tx dma descriptor */ TxDesc.sw_len = length; @@ -1011,16 +1067,41 @@ static void e100_clear_network_leds(unsigned long dummy) { - if (jiffies > led_clear_time) { - if (nolink) - LED_NETWORK_TX_SET(1); - else - LED_NETWORK_TX_SET(0); - LED_NETWORK_RX_SET(0); + if (led_active && jiffies > led_next_time) { + e100_set_network_leds(NO_NETWORK_ACTIVITY); + + /* Set the earliest time we may set the LED */ + led_next_time = jiffies + NET_FLASH_PAUSE; + led_active = 0; } - - clear_led_timer.expires = jiffies + 10; + + clear_led_timer.expires = jiffies + HZ/10; add_timer(&clear_led_timer); +} + +static void +e100_set_network_leds(int active) +{ +#ifdef CONFIG_LED_OFF_DURING_ACTIVITY + int light_leds = (active == NO_NETWORK_ACTIVITY); +#else + int light_leds = (active == NETWORK_ACTIVITY); +#endif + + if (!current_speed) { + /* Make LED red, link is down */ + LED_NETWORK_SET(LED_RED); + } + else if (light_leds) { + if (current_speed == 10) { + LED_NETWORK_SET(LED_ORANGE); + } else { + LED_NETWORK_SET(LED_GREEN); + } + } + else { + LED_NETWORK_SET(LED_OFF); + } } static struct net_device dev_etrax_ethernet; /* only got one */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/examples/kiobuftest.c linux.ac/arch/cris/drivers/examples/kiobuftest.c --- linux.vanilla/arch/cris/drivers/examples/kiobuftest.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/examples/kiobuftest.c Tue Apr 10 18:05:08 2001 @@ -0,0 +1,108 @@ +/* + * Example showing how to pin down a range of virtual pages from user-space + * to be able to do for example DMA directly into them. + * + * It is necessary because the pages the virtual pointers reference, might + * not exist in memory (could be mapped to the zero-page, filemapped etc) + * and DMA cannot trigger the MMU to force them in (and would have time + * contraints making it impossible to wait for it anyway). + * + * Author: Bjorn Wesen + * + * $Log: kiobuftest.c,v $ + * Revision 1.2 2001/02/27 13:52:50 bjornw + * malloc.h -> slab.h + * + * Revision 1.1 2001/01/19 15:57:49 bjornw + * Example of how to do direct HW -> user-mode DMA + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KIOBUFTEST_MAJOR 124 /* in the local range, experimental */ + + +static ssize_t +kiobuf_read(struct file *filp, char *buf, size_t len, loff_t *ppos) +{ + + struct kiobuf *iobuf; + int res, i; + + /* Make a kiobuf that maps the entire length the reader has given + * us + */ + + res = alloc_kiovec(1, &iobuf); + if (res) + return res; + + if((res = map_user_kiobuf(READ, iobuf, (unsigned long)buf, len))) { + printk("map_user_kiobuf failed, return %d\n", res); + return res; + } + + /* At this point, the virtual area buf[0] -> buf[len-1] will + * have corresponding pages mapped in physical memory and locked + * until we unmap the kiobuf. They cannot be swapped out or moved + * around. + */ + + printk("nr_pages == %d\noffset == %d\nlength == %d\n", + iobuf->nr_pages, iobuf->offset, iobuf->length); + + for(i = 0; i < iobuf->nr_pages; i++) { + printk("page_add(maplist[%d]) == 0x%x\n", i, + page_address(iobuf->maplist[i])); + } + + /* This is the place to create the necessary scatter-gather vector + * for the DMA using the iobuf->maplist array and page_address + * (don't forget __pa if the DMA needs the actual physical DRAM address) + * and run it. + */ + + + + + /* Release the mapping and exit */ + + unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */ + + return len; +} + + +static struct file_operations kiobuf_fops = { + owner: THIS_MODULE, + read: kiobuf_read +}; + +static int __init +kiobuftest_init(void) +{ + int res; + + /* register char device */ + + res = register_chrdev(KIOBUFTEST_MAJOR, "kiobuftest", &kiobuf_fops); + if(res < 0) { + printk(KERN_ERR "kiobuftest: couldn't get a major number.\n"); + return res; + } + + printk("Initializing kiobuf-test device\n"); +} + +module_init(kiobuftest_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/gpio.c linux.ac/arch/cris/drivers/gpio.c --- linux.vanilla/arch/cris/drivers/gpio.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/gpio.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,318 @@ +/* $Id: gpio.c,v 1.7 2001/04/04 13:30:08 matsfg Exp $ + * + * Etrax general port I/O device + * + * Copyright (c) 1999, 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen (initial version) + * Ola Knutsson (LED handling) + * Johan Adolfsson (read/set directions) + * + * $Log: gpio.c,v $ + * Revision 1.7 2001/04/04 13:30:08 matsfg + * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping + * + * Revision 1.6 2001/03/26 16:03:06 bjornw + * Needs linux/config.h + * + * Revision 1.5 2001/03/26 14:22:03 bjornw + * Namechange of some config options + * + * Revision 1.4 2001/02/27 13:52:48 bjornw + * malloc.h -> slab.h + * + * Revision 1.3 2001/01/24 15:06:48 bjornw + * gpio_wq correct type + * + * Revision 1.2 2001/01/18 16:07:30 bjornw + * 2.4 port + * + * Revision 1.1 2001/01/18 15:55:16 bjornw + * Verbatim copy of etraxgpio.c from elinux 2.0 added + * + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define GPIO_MAJOR 120 /* experimental MAJOR number */ + +#define D(x) + +static char gpio_name[] = "etrax gpio"; + +static wait_queue_head_t *gpio_wq; + +static int gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int gpio_open(struct inode *inode, struct file *filp); +static int gpio_release(struct inode *inode, struct file *filp); +static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); + +/* private data per open() of this driver */ + +struct gpio_private { + struct gpio_private *next; + volatile unsigned char *port, *shadow; + volatile unsigned char *dir, *dir_shadow; + unsigned char changeable_dir; + unsigned char changeable_bits; + unsigned char highalarm, lowalarm; + wait_queue_head_t alarm_wq; + int minor; +}; + +/* linked list of alarms to check for */ + +static struct gpio_private *alarmlist = 0; + +#define NUM_PORTS 2 +static volatile unsigned char *ports[2] = { R_PORT_PA_DATA, R_PORT_PB_DATA }; +static volatile unsigned char *shads[2] = { + &port_pa_data_shadow, &port_pb_data_shadow }; + +/* What direction bits that are user changeable 1=changeable*/ +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR +#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00 +#endif +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR +#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00 +#endif + +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS +#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF +#endif +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS +#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF +#endif + + +static unsigned char changeable_dir[2] = { CONFIG_ETRAX_PA_CHANGEABLE_DIR, + CONFIG_ETRAX_PB_CHANGEABLE_DIR }; +static unsigned char changeable_bits[2] = { CONFIG_ETRAX_PA_CHANGEABLE_BITS, + CONFIG_ETRAX_PB_CHANGEABLE_BITS }; + +static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR }; + +static volatile unsigned char *dir_shadow[2] = { + &port_pa_dir_shadow, &port_pb_dir_shadow }; + +#define LEDS 2 + +static unsigned int +gpio_poll(struct file *filp, + struct poll_table_struct *wait) +{ + /* TODO poll on alarms! */ +#if 0 + if(!ANYTHING_WANTED) { + D(printk("gpio_select sleeping task\n")); + select_wait(&gpio_wq, table); + return 0; + } + D(printk("gpio_select ready\n")); +#endif + return 1; +} + +static int +gpio_open(struct inode *inode, struct file *filp) +{ + struct gpio_private *priv; + int p = MINOR(inode->i_rdev); + + if(p >= NUM_PORTS && p != LEDS) + return -EINVAL; + + priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), + GFP_KERNEL); + + if(!priv) + return -ENOMEM; + + priv->minor = p; + + /* initialize the io/alarm struct and link it into our alarmlist */ + + priv->next = alarmlist; + alarmlist = priv; + priv->port = ports[p]; + priv->shadow = shads[p]; + + priv->changeable_dir = changeable_dir[p]; + priv->changeable_bits = changeable_bits[p]; + priv->dir = dir[p]; + priv->dir_shadow = dir_shadow[p]; + + priv->highalarm = 0; + priv->lowalarm = 0; + init_waitqueue_head(&priv->alarm_wq); + + filp->private_data = (void *)priv; + + return 0; +} + +static int +gpio_release(struct inode *inode, struct file *filp) +{ + struct gpio_private *p = alarmlist; + struct gpio_private *todel = (struct gpio_private *)filp->private_data; + + /* unlink from alarmlist and free the private structure */ + + if(p == todel) { + alarmlist = todel->next; + } else { + while(p->next != todel) + p = p->next; + p->next = todel->next; + } + + kfree(todel); + + return 0; +} + +/* Main device API. ioctl's to read/set/clear bits, as well as to + * set alarms to wait for using a subsequent select(). + */ + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg); + +static int +gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct gpio_private *priv = (struct gpio_private *)file->private_data; + + if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { + return -EINVAL; + } + + switch (_IOC_NR(cmd)) { + case IO_READBITS: + // read the port + return *priv->port; + case IO_SETBITS: + // set changeable bits with a 1 in arg + *priv->port = *priv->shadow |= + ((unsigned char)arg & priv->changeable_bits); + break; + case IO_CLRBITS: + // clear changeable bits with a 1 in arg + *priv->port = *priv->shadow &= + ~((unsigned char)arg & priv->changeable_bits); + break; + case IO_HIGHALARM: + // set alarm when bits with 1 in arg go high + priv->highalarm |= (unsigned char)arg; + break; + case IO_LOWALARM: + // set alarm when bits with 1 in arg go low + priv->lowalarm |= (unsigned char)arg; + break; + case IO_CLRALARM: + // clear alarm for bits with 1 in arg + priv->highalarm &= ~(unsigned char)arg; + priv->lowalarm &= ~(unsigned char)arg; + break; + case IO_READDIR: + /* Read direction 0=input 1=output */ + return *priv->dir_shadow; + case IO_SETINPUT: + /* Set direction 0=unchanged 1=input */ + *priv->dir = *priv->dir_shadow &= + ~((unsigned char)arg & priv->changeable_dir); + return *priv->dir_shadow; + case IO_SETOUTPUT: + /* Set direction 0=unchanged 1=output */ + *priv->dir = *priv->dir_shadow |= + ((unsigned char)arg & priv->changeable_dir); + return *priv->dir_shadow; + default: + if(priv->minor == LEDS) + return gpio_leds_ioctl(cmd, arg); + else + return -EINVAL; + } + + return 0; +} + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg) +{ + unsigned char green; + unsigned char red; + static int initialized = 0; + if(!initialized) + { + initialized = 1; + init_ioremap(); + } + switch (_IOC_NR(cmd)) { + case IO_LEDACTIVE_SET: + green = ((unsigned char) arg) & 1; + red = (((unsigned char) arg) >> 1) & 1; + LED_ACTIVE_SET_G(green); + LED_ACTIVE_SET_R(red); + break; + case IO_LED_SETBIT: + LED_BIT_SET(arg); + break; + case IO_LED_CLRBIT: + LED_BIT_CLR(arg); + default: + return -EINVAL; + } +} + +struct file_operations gpio_fops = { + owner: THIS_MODULE, + poll: gpio_poll, + ioctl: gpio_ioctl, + open: gpio_open, + release: gpio_release, +}; + +/* main driver initialization routine, called from mem.c */ + +static __init int +gpio_init(void) +{ + int res; + + /* do the formalities */ + + res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); + if(res < 0) { + printk(KERN_ERR "gpio: couldn't get a major number.\n"); + return res; + } + + printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n"); + + return res; +} + +/* this makes sure that gpio_init is called during kernel boot */ + +module_init(gpio_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/i2c.c linux.ac/arch/cris/drivers/i2c.c --- linux.vanilla/arch/cris/drivers/i2c.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/i2c.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,699 @@ +/*!*************************************************************************** +*! +*! FILE NAME : i2c.c +*! +*! DESCRIPTION: implements an interface for IIC/I2C, both directly from other +*! kernel modules (i2c_writereg/readreg) and from userspace using +*! ioctl()'s +*! +*! Nov 30 1998 Torbjorn Eliasson Initial version. +*! Bjorn Wesen Elinux kernel version. +*! Jan 14 2000 Johan Adolfsson Fixed PB shadow register stuff - +*! don't use PB_I2C if DS1302 uses same bits, +*! use PB. +*! $Log: i2c.c,v $ +*! Revision 1.7 2001/04/04 13:11:36 markusl +*! Updated according to review remarks +*! +*! Revision 1.6 2001/03/19 12:43:00 markusl +*! Made some symbols unstatic (used by the eeprom driver) +*! +*! Revision 1.5 2001/02/27 13:52:48 bjornw +*! malloc.h -> slab.h +*! +*! Revision 1.4 2001/02/15 07:17:40 starvik +*! Corrected usage if port_pb_i2c_shadow +*! +*! Revision 1.3 2001/01/26 17:55:13 bjornw +*! * Made I2C_USES_PB_NOT_PB_I2C a CONFIG option instead of assigning it +*! magically. Config.in needs to set it for the options that need it, like +*! Dallas 1302 support. Actually, it should be default since it screws up +*! the PB bits even if you don't use I2C.. +*! * Include linux/config.h to get the above +*! +*! Revision 1.2 2001/01/18 15:49:30 bjornw +*! 2.4 port of I2C including some cleanups (untested of course) +*! +*! Revision 1.1 2001/01/18 15:35:25 bjornw +*! Verbatim copy of the Etrax i2c driver, 2.0 elinux version +*! +*! +*! --------------------------------------------------------------------------- +*! +*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! +*!***************************************************************************/ +/* $Id: i2c.c,v 1.7 2001/04/04 13:11:36 markusl Exp $ */ +/****************** INCLUDE FILES SECTION ***********************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "i2c.h" + +/****************** I2C DEFINITION SECTION *************************/ + +#define D(x) + +#define I2C_MAJOR 123 /* LOCAL/EXPERIMENTAL */ +static const char i2c_name[] = "i2c"; + +#define CLOCK_LOW_TIME 8 +#define CLOCK_HIGH_TIME 8 +#define START_CONDITION_HOLD_TIME 8 +#define STOP_CONDITION_HOLD_TIME 8 +#define ENABLE_OUTPUT 0x01 +#define ENABLE_INPUT 0x00 +#define I2C_CLOCK_HIGH 1 +#define I2C_CLOCK_LOW 0 +#define I2C_DATA_HIGH 1 +#define I2C_DATA_LOW 0 + +#if 0 +/* TODO: fix this so the CONFIG_ETRAX_I2C_USES... is set in Config.in instead */ +#if defined(CONFIG_DS1302) && (CONFIG_DS1302_SDABIT==0) && \ + (CONFIG_DS1302_SCLBIT == 1) +#define CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C +#endif +#endif + +#ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C +/* Use PB and not PB_I2C */ +#define SDABIT 0 +#define SCLBIT 1 +#define i2c_enable() +#define i2c_disable() + +/* enable or disable output-enable, to select output or input on the i2c bus */ + +#define i2c_dir_out() \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1) +#define i2c_dir_in() \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 0) + +/* control the i2c clock and data signals */ + +#define i2c_clk(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SCLBIT, x) +#define i2c_data(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x) + +/* read a bit from the i2c interface */ + +#define i2c_getbit() (*R_PORT_PB_READ & (1 << SDABIT)) + +#else +/* enable or disable the i2c interface */ + +#define i2c_enable() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_en)) +#define i2c_disable() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_en)) + +/* enable or disable output-enable, to select output or input on the i2c bus */ + +#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)) +#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)) + +/* control the i2c clock and data signals */ + +#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))) + +#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))) + +/* read a bit from the i2c interface */ + +#define i2c_getbit() (*R_PORT_PB_READ & 0x1) +#endif + +/* use the kernels delay routine */ + +#define i2c_delay(usecs) udelay(usecs) + + +/****************** FUNCTION DEFINITION SECTION *************************/ + + +/* generate i2c start condition */ + +void +i2c_start(void) +{ + /* + * SCL=1 SDA=1 + */ + i2c_dir_out(); + i2c_delay(CLOCK_HIGH_TIME/6); + i2c_data(I2C_DATA_HIGH); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); + /* + * SCL=1 SDA=0 + */ + i2c_data(I2C_DATA_LOW); + i2c_delay(START_CONDITION_HOLD_TIME); + /* + * SCL=0 SDA=0 + */ + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); +} + +/* generate i2c stop condition */ + +void +i2c_stop(void) +{ + i2c_dir_out(); + + /* + * SCL=0 SDA=0 + */ + i2c_clk(I2C_CLOCK_LOW); + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_LOW_TIME*2); + /* + * SCL=1 SDA=0 + */ + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME*2); + /* + * SCL=1 SDA=1 + */ + i2c_data(I2C_DATA_HIGH); + i2c_delay(STOP_CONDITION_HOLD_TIME); + + i2c_dir_in(); +} + +/* write a byte to the i2c interface */ + +void +i2c_outbyte(unsigned char x) +{ + int i; + + i2c_dir_out(); + + for (i = 0; i < 8; i++) { + if (x & 0x80) + i2c_data(I2C_DATA_HIGH); + else + i2c_data(I2C_DATA_LOW); + + i2c_delay(CLOCK_LOW_TIME/2); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME/2); + x <<= 1; + } + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_LOW_TIME/2); + + /* + * enable input + */ + i2c_dir_in(); +} + +/* read a byte from the i2c interface */ + +unsigned char +i2c_inbyte(void) +{ + unsigned char aBitByte = 0; + int i; + int iaa; + + /* + * enable output + */ + i2c_dir_out(); + /* + * Release data bus by setting + * data high + */ + i2c_data(I2C_DATA_HIGH); + /* + * enable input + */ + i2c_dir_in(); + /* + * Use PORT PB instead of I2C + * for input. (I2C not working) + */ + i2c_clk(1); + i2c_data(1); + /* + * get bits + */ + for (i = 0; i < 8; i++) { + i2c_delay(CLOCK_LOW_TIME/2); + /* + * low clock period + */ + i2c_clk(I2C_CLOCK_HIGH); + /* + * switch off I2C + */ + i2c_data(1); + i2c_disable(); + i2c_dir_in(); + /* + * wait before getting bit + */ + i2c_delay(CLOCK_HIGH_TIME/2); + aBitByte = (aBitByte << 1); + iaa = i2c_getbit(); + aBitByte = aBitByte | iaa ; + /* + * wait + */ + i2c_delay(CLOCK_HIGH_TIME/2); + /* + * end clock puls + */ + i2c_enable(); + i2c_dir_out(); + i2c_clk(I2C_CLOCK_LOW); + /* + * low clock period + */ + i2c_delay(CLOCK_LOW_TIME/2); + } + i2c_dir_out(); + return aBitByte; +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: i2c_getack +*# +*# DESCRIPTION : checks if ack was received from ic2 +*# +*#--------------------------------------------------------------------------*/ + +int +i2c_getack(void) +{ + int ack = 1; + /* + * enable output + */ + i2c_dir_out(); + /* + * Release data bus by setting + * data high + */ + i2c_data(I2C_DATA_HIGH); + /* + * enable input + */ + i2c_dir_in(); + i2c_delay(CLOCK_HIGH_TIME/4); + /* + * generate ACK clock pulse + */ + i2c_clk(I2C_CLOCK_HIGH); + /* + * Use PORT PB instead of I2C + * for input. (I2C not working) + */ + i2c_clk(1); + i2c_data(1); + /* + * switch off I2C + */ + i2c_data(1); + i2c_disable(); + i2c_dir_in(); + /* + * now wait for ack + */ + i2c_delay(CLOCK_HIGH_TIME/2); + /* + * check for ack + */ + if(i2c_getbit()) + ack = 0; + i2c_delay(CLOCK_HIGH_TIME/2); + if(!ack){ + if(!i2c_getbit()) /* receiver pulld SDA low */ + ack = 1; + i2c_delay(CLOCK_HIGH_TIME/2); + } + + /* + * end clock pulse + */ + i2c_enable(); + i2c_dir_out(); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_HIGH_TIME/4); + /* + * enable output + */ + i2c_dir_out(); + /* + * remove ACK clock pulse + */ + i2c_data(I2C_DATA_HIGH); + i2c_delay(CLOCK_LOW_TIME/2); + return ack; +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: I2C::sendAck +*# +*# DESCRIPTION : Send ACK on received data +*# +*#--------------------------------------------------------------------------*/ +void +i2c_sendack(void) +{ + /* + * enable output + */ + i2c_delay(CLOCK_LOW_TIME); + i2c_dir_out(); + /* + * set ack pulse high + */ + i2c_data(I2C_DATA_LOW); + /* + * generate clock pulse + */ + i2c_delay(CLOCK_HIGH_TIME/6); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME/6); + /* + * reset data out + */ + i2c_data(I2C_DATA_HIGH); + i2c_delay(CLOCK_LOW_TIME); + + i2c_dir_in(); +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: i2c_writereg +*# +*# DESCRIPTION : Writes a value to an I2C device +*# +*#--------------------------------------------------------------------------*/ +int +i2c_writereg(unsigned char theSlave, unsigned char theReg, + unsigned char theValue) +{ + int error, cntr = 3; + unsigned long flags; + + do { + error = 0; + /* + * we don't like to be interrupted + */ + save_flags(flags); + cli(); + /* + * generate start condition + */ + i2c_start(); + /* + * dummy preamble + */ + i2c_outbyte(0x01); + i2c_data(I2C_DATA_HIGH); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + + i2c_start(); + /* + * send slave address + */ + i2c_outbyte(theSlave); + /* + * wait for ack + */ + if(!i2c_getack()) + error = 1; + /* + * now select register + */ + i2c_dir_out(); + i2c_outbyte(theReg); + /* + * now it's time to wait for ack + */ + if(!i2c_getack()) + error |= 2; + /* + * send register register data + */ + i2c_outbyte(theValue); + /* + * now it's time to wait for ack + */ + if(!i2c_getack()) + error |= 4; + /* + * end byte stream + */ + i2c_stop(); + /* + * enable interrupt again + */ + restore_flags(flags); + + } while(error && cntr--); + + i2c_delay(CLOCK_LOW_TIME); + + return -error; +} + +/*#--------------------------------------------------------------------------- +*# +*# FUNCTION NAME: i2c_readreg +*# +*# DESCRIPTION : Reads a value from the decoder registers. +*# +*#--------------------------------------------------------------------------*/ +unsigned char +i2c_readreg(unsigned char theSlave, unsigned char theReg) +{ + unsigned char b = 0; + int error, cntr = 3; + unsigned long flags; + + do { + error = 0; + /* + * we don't like to be interrupted + */ + save_flags(flags); + cli(); + /* + * generate start condition + */ + i2c_start(); + /* + * dummy preamble + */ + i2c_outbyte(0x01); + i2c_data(I2C_DATA_HIGH); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ + i2c_data(I2C_DATA_LOW); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + + i2c_start(); + + /* + * send slave address + */ + i2c_outbyte(theSlave); + /* + * wait for ack + */ + if(!i2c_getack()) + error = 1; + /* + * now select register + */ + i2c_dir_out(); + i2c_outbyte(theReg); + /* + * now it's time to wait for ack + */ + if(!i2c_getack()) + error = 1; + /* + * repeat start condition + */ + i2c_delay(CLOCK_LOW_TIME); + i2c_start(); + /* + * send slave address + */ + i2c_outbyte(theSlave | 0x01); + /* + * wait for ack + */ + if(!i2c_getack()) + error = 1; + /* + * fetch register + */ + b = i2c_inbyte(); + /* + * send Ack + */ + i2c_sendack(); + /* + * end sequence + */ + i2c_stop(); + /* + * enable interrupt again + */ + restore_flags(flags); + + } while(error && cntr--); + + return b; +} + +static int +i2c_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int +i2c_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +/* Main device API. ioctl's to write or read to/from i2c registers. + */ + +static int +i2c_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) { + return -EINVAL; + } + + switch (_IOC_NR(cmd)) { + case I2C_WRITEREG: + /* write to an i2c slave */ + D(printk("i2cw %d %d %d\n", + I2C_ARGSLAVE(arg), + I2C_ARGREG(arg), + I2C_ARGVALUE(arg))); + + return i2c_writereg(I2C_ARGSLAVE(arg), + I2C_ARGREG(arg), + I2C_ARGVALUE(arg)); + case I2C_READREG: + { + unsigned char val; + /* read from an i2c slave */ + D(printk("i2cr %d %d ", + I2C_ARGSLAVE(arg), + I2C_ARGREG(arg))); + val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg)); + D(printk("= %d\n", val)); + return val; + } + default: + return -EINVAL; + + } + + return 0; +} + +static struct file_operations i2c_fops = { + owner: THIS_MODULE, + ioctl: i2c_ioctl, + open: i2c_open, + release: i2c_release, +}; + +static int __init +i2c_init(void) +{ + int res; + + /* Setup and enable the Port B I2C interface */ + +#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C + *R_PORT_PB_I2C = port_pb_i2c_shadow |= + IO_STATE(R_PORT_PB_I2C, i2c_en, on) | + IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | + IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | + IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); +#endif + + port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); + port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); + + *R_PORT_PB_DIR = (port_pb_dir_shadow |= + IO_STATE(R_PORT_PB_DIR, dir0, input) | + IO_STATE(R_PORT_PB_DIR, dir1, output)); + + /* register char device */ + + res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); + if(res < 0) { + printk(KERN_ERR "i2c: couldn't get a major number.\n"); + return res; + } + + printk("I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); + + return 0; +} + +/* this makes sure that i2c_init is called during boot */ + +module_init(i2c_init); + +/****************** END OF FILE i2c.c ********************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/i2c.h linux.ac/arch/cris/drivers/i2c.h --- linux.vanilla/arch/cris/drivers/i2c.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/i2c.h Thu Apr 19 14:13:36 2001 @@ -0,0 +1,16 @@ +/* $Id: i2c.h,v 1.3 2001/03/19 12:43:01 markusl Exp $ */ + +/* High level I2C actions */ +int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); +unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); + +/* Low level I2C */ +void i2c_start(void); +void i2c_stop(void); +void i2c_outbyte(unsigned char x); +unsigned char i2c_inbyte(void); +int i2c_getack(void); +void i2c_sendack(void); + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/ide.c linux.ac/arch/cris/drivers/ide.c --- linux.vanilla/arch/cris/drivers/ide.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/cris/drivers/ide.c Thu Apr 19 14:13:36 2001 @@ -1,4 +1,4 @@ -/* $Id: ide.c,v 1.4 2001/01/10 21:14:32 bjornw Exp $ +/* $Id: ide.c,v 1.16 2001/04/05 08:30:07 matsfg Exp $ * * Etrax specific IDE functions, like init and PIO-mode setting etc. * Almost the entire ide.c is used for the rest of the Etrax ATA driver. @@ -8,6 +8,45 @@ * Mikael Starvik (pio setup stuff) * * $Log: ide.c,v $ + * Revision 1.16 2001/04/05 08:30:07 matsfg + * Corrected cse1 and csp0 reset. + * + * Revision 1.15 2001/04/04 14:34:06 bjornw + * Re-instated code that mysteriously disappeared during review updates. + * + * Revision 1.14 2001/04/04 13:45:12 matsfg + * Calls REG_SHADOW_SET for cse1 reset so only the resetbit is affected + * + * Revision 1.13 2001/04/04 13:26:40 matsfg + * memmapping is done in init.c + * + * Revision 1.12 2001/04/04 11:37:56 markusl + * Updated according to review remarks + * + * Revision 1.11 2001/03/29 12:49:14 matsfg + * Changed check for ata_tot_size from >= to >. + * Sets sw_len to 0 if size is exactly 65536. + * + * Revision 1.10 2001/03/16 09:39:30 matsfg + * Support for reset on port CSP0 + * + * Revision 1.9 2001/03/01 13:11:18 bjornw + * 100 -> HZ + * + * Revision 1.8 2001/03/01 09:32:56 matsfg + * Moved IDE delay to a CONFIG-parameter instead + * + * Revision 1.7 2001/02/23 13:46:38 bjornw + * Spellling check + * + * Revision 1.6 2001/02/22 15:44:30 bjornw + * * Use ioremap when mapping the CSE1 memory-mapped reset-line for LX v2 + * * sw_len for a 65536 descriptor is 0, not 65536 + * * Express concern for G27 reset code + * + * Revision 1.5 2001/02/16 07:35:38 matsfg + * Now handles DMA request blocks between 64k and 128k by split into two descriptors. + * * Revision 1.4 2001/01/10 21:14:32 bjornw * Initialize hwif->ideproc, for the new way of handling ide_xxx_data * @@ -63,8 +102,13 @@ /* number of Etrax DMA descriptors */ #define MAX_DMA_DESCRS 64 +#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET +/* address where the memory-mapped IDE reset bit lives, if used */ +static volatile unsigned long *reset_addr; +#endif + #define LOWDB(x) -#define D(x) +#define D(x) void OUT_BYTE(unsigned char data, ide_ioreg_t reg) { LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg)); @@ -136,6 +180,10 @@ #define ATA_PIO0_STROBE 19 #define ATA_PIO0_HOLD 4 +static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive); +static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive, + void *buffer, unsigned int length); + /* * good_dma_drives() lists the model names (from "hdparm -i") * of drives which do not support mword2 DMA but which are @@ -152,7 +200,7 @@ unsigned long flags; pio = 4; - //pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + /* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */ save_flags(flags); cli(); @@ -204,11 +252,8 @@ restore_flags(flags); } -static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive); /* defined below */ -static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive, - void *buffer, unsigned int length); /* defined below */ - -void __init init_e100_ide (void) +void __init +init_e100_ide (void) { volatile unsigned int dummy; int h; @@ -226,6 +271,8 @@ } /* actually reset and configure the etrax100 ide/ata interface */ + /* This is mystifying; why is not G27 SET anywhere ? It's just reset here twice. */ + /* de-assert bus-reset */ #ifdef CONFIG_ETRAX_IDE_PB7_RESET port_pb_dir_shadow = port_pb_dir_shadow | @@ -252,19 +299,27 @@ *R_GEN_CONFIG = genconfig_shadow; #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 0; + init_ioremap(); + REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0); #endif - /* wait some */ +#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET + init_ioremap(); + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0); +#endif - dummy = 1; - dummy = 2; - dummy = 3; + /* wait some */ + udelay(25); #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 1 << 16; - *R_PORT_G_DATA = 0; /* de-assert bus-reset */ + REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1); +#endif +#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1); #endif +#ifdef CONFIG_ETRAX_IDE_G27_RESET + *R_PORT_G_DATA = 0; /* de-assert bus-reset */ +#endif /* make a dummy read to set the ata controller in a proper state */ dummy = *R_ATA_STATUS_DATA; @@ -286,9 +341,9 @@ IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); - printk("ide: waiting 10 seconds for drives to regain consciousness\n"); + printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_IDE_DELAY); - h = jiffies + 1000; + h = jiffies + (CONFIG_IDE_DELAY * HZ); while(jiffies < h) ; /* reset the dma channels we will use */ @@ -313,7 +368,6 @@ e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) { ide_ioreg_t data_reg = IDE_DATA_REG; - unsigned long status; D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n", data_reg, buffer, bytecount)); @@ -340,7 +394,7 @@ /* initiate a multi word dma read using PIO handshaking */ - *R_ATA_TRANSFER_CNT = bytecount >> 1; + *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1); *R_ATA_CTRL_DATA = data_reg | IO_STATE(R_ATA_CTRL_DATA, rw, read) | @@ -354,35 +408,38 @@ LED_DISK_READ(1); WAIT_DMA(3); LED_DISK_READ(0); - + #if 0 - /* old polled transfer code */ - - /* initiate a multi word read */ - - *R_ATA_TRANSFER_CNT = wcount << 1; - - *R_ATA_CTRL_DATA = data_reg | - IO_STATE(R_ATA_CTRL_DATA, rw, read) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | - IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - /* svinto has a latency until the busy bit actually is set */ - - nop(); nop(); - nop(); nop(); - nop(); nop(); - nop(); nop(); - nop(); nop(); - - /* unit should be busy during multi transfer */ - while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) { - while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav))) - status = *R_ATA_STATUS_DATA; - *ptr++ = (unsigned short)(status & 0xffff); - } + /* old polled transfer code + * this should be moved into a new function that can do polled + * transfers if DMA is not available + */ + + /* initiate a multi word read */ + + *R_ATA_TRANSFER_CNT = wcount << 1; + + *R_ATA_CTRL_DATA = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, read) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + /* svinto has a latency until the busy bit actually is set */ + + nop(); nop(); + nop(); nop(); + nop(); nop(); + nop(); nop(); + nop(); nop(); + + /* unit should be busy during multi transfer */ + while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) { + while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav))) + status = *R_ATA_STATUS_DATA; + *ptr++ = (unsigned short)(status & 0xffff); + } #endif } @@ -390,8 +447,6 @@ e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) { ide_ioreg_t data_reg = IDE_DATA_REG; - unsigned short *ptr = (unsigned short *)buffer; - unsigned long ctrl; D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n", data_reg, buffer, bytecount)); @@ -418,7 +473,7 @@ /* initiate a multi word dma write using PIO handshaking */ - *R_ATA_TRANSFER_CNT = bytecount >> 1; + *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1); *R_ATA_CTRL_DATA = data_reg | IO_STATE(R_ATA_CTRL_DATA, rw, write) | @@ -434,40 +489,42 @@ LED_DISK_WRITE(0); #if 0 - /* old polled write code */ + /* old polled write code - see comment in input_bytes */ - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ + /* wait for busy flag */ + while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); - /* initiate a multi word write */ + /* initiate a multi word write */ - *R_ATA_TRANSFER_CNT = bytecount >> 1; + *R_ATA_TRANSFER_CNT = bytecount >> 1; - ctrl = data_reg | - IO_STATE(R_ATA_CTRL_DATA, rw, write) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | - IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - LED_DISK_WRITE(1); - - /* Etrax will set busy = 1 until the multi pio transfer has finished - * and tr_rdy = 1 after each succesful word transfer. - * When the last byte has been transferred Etrax will first set tr_tdy = 1 - * and then busy = 0 (not in the same cycle). If we read busy before it - * has been set to 0 we will think that we should transfer more bytes - * and then tr_rdy would be 0 forever. This is solved by checking busy - * in the inner loop. - */ - - do { - *R_ATA_CTRL_DATA = ctrl | *ptr++; - while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) && - (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy))); - } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); + ctrl = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, write) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + LED_DISK_WRITE(1); + + /* Etrax will set busy = 1 until the multi pio transfer has finished + * and tr_rdy = 1 after each succesful word transfer. + * When the last byte has been transferred Etrax will first set tr_tdy = 1 + * and then busy = 0 (not in the same cycle). If we read busy before it + * has been set to 0 we will think that we should transfer more bytes + * and then tr_rdy would be 0 forever. This is solved by checking busy + * in the inner loop. + */ + + do { + *R_ATA_CTRL_DATA = ctrl | *ptr++; + while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) && + (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy))); + } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); + + LED_DISK_WRITE(0); +#endif - LED_DISK_WRITE(0); -#endif } /* @@ -560,14 +617,6 @@ return 1; } - /* uh.. I'm lazy.. if size >= 65536, it should loop below and split it in - more than one descriptor */ - - if(size >= 65536) { - printk("too large ATA DMA request block, size = %d!\n", size); - return 1; - } - /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more than 65536 words per transfer, so in that case we need to either 1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with @@ -576,14 +625,33 @@ those blocks that were actually set-up for transfer. */ - if(ata_tot_size + size >= 131072) { + if(ata_tot_size + size > 131072) { printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, size); return 1; } - /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + /* If size > 65536 it has to be splitted into new descriptors. Since we don't handle + size > 131072 only one split is necessary */ - ata_descrs[count].sw_len = size; + if(size > 65536) { + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ + ata_descrs[count].ctrl = 0; + ata_descrs[count].buf = addr; + ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); + count++; + ata_tot_size += 65536; + /* size and addr should refere to not handled data */ + size -= 65536; + addr += 65536; + } + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + if(size == 65536) { + ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ + } + else { + ata_descrs[count].sw_len = size; + } ata_descrs[count].ctrl = 0; ata_descrs[count].buf = addr; ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); @@ -751,9 +819,11 @@ /* initiate a multi word dma read using DMA handshaking */ - *R_ATA_TRANSFER_CNT = ata_tot_size >> 1; + *R_ATA_TRANSFER_CNT = + IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1); - *R_ATA_CTRL_DATA = IDE_DATA_REG | + *R_ATA_CTRL_DATA = + IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | IO_STATE(R_ATA_CTRL_DATA, rw, read) | IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | @@ -792,9 +862,11 @@ /* initiate a multi word dma write using DMA handshaking */ - *R_ATA_TRANSFER_CNT = ata_tot_size >> 1; + *R_ATA_TRANSFER_CNT = + IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1); - *R_ATA_CTRL_DATA = IDE_DATA_REG | + *R_ATA_CTRL_DATA = + IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | IO_STATE(R_ATA_CTRL_DATA, rw, write) | IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/parport.c linux.ac/arch/cris/drivers/parport.c --- linux.vanilla/arch/cris/drivers/parport.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/parport.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,591 @@ +/* $Id: parport.c,v 1.4 2001/04/06 13:04:02 hugo Exp $ + * + * Elinux parallel port driver + * NOTE! + * Since par0 shares DMA with ser2 and par 1 shares DMA with ser3 + * this should be handled if both are enabled at the same time. + * THIS IS NOT HANDLED YET! + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Fredrik Hugosson + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK printk +#else +static inline int DPRINTK(void *nothing, ...) {return 0;} +#endif + +/* + * Etrax100 DMAchannels: + * Par0 out : DMA2 + * Par0 in : DMA3 + * Par1 out : DMA4 + * Par1 in : DMA5 + * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding + * DMA and DMA irq + */ + +//#define CONFIG_PAR0_INT 1 +//#define CONFIG_PAR1_INT 1 + +#define SETF(var, reg, field, val) \ + var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val) + +#define SETS(var, reg, field, val) \ + var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val) + +struct etrax100par_struct { + /* parallell port control */ + volatile u32 *reg_ctrl_data; /* R_PARx_CTRL_DATA */ + const volatile u32 *reg_status_data; /* R_PARx_STATUS_DATA */ + volatile u32 *reg_config; /* R_PARx_CONFIG */ + volatile u32 *reg_delay; /* R_PARx_DELAY */ + + /* DMA control */ + int odma; + unsigned long dma_irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + + volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ + volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ + + volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ + volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ + const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ + volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ + + /* Non DMA interrupt stuff */ + unsigned long int_irq; /* R_VECT_MASK_RD */ + const volatile u32 *irq_mask_rd; /* R_IRQ_MASKX_RD */ + volatile u32 *irq_mask_clr; /* R_IRQ_MASKX_RD */ + const volatile u32 *irq_read; /* R_IRQ_READX */ + volatile u32 *irq_mask_set; /* R_IRQ_MASKX_SET */ + unsigned long irq_mask_tx; /* bitmask in R_IRQ_ for tx (ready) int */ + unsigned long irq_mask_rx; /* bitmask in R_IRQ_ for rx (data) int */ + unsigned long irq_mask_ecp_cmd; /* mask in R_IRQ_ for ecp_cmd int */ + unsigned long irq_mask_peri; /* bitmask in R_IRQ_ for peri int */ + int portnr; + + /* ----- end of fields initialised in port_table[] below ----- */ + + // struct etrax_dma_descr tr_descr; + // unsigned char tr_buf[LP_BUFFER_SIZE]; + // const unsigned char *tr_buf_curr; /* current char sent */ + // const unsigned char *tr_buf_last; /* last char in buf */ + + // int fifo_magic; /* fifo amount - bytes left in dma buffer */ + // unsigned char fifo_didmagic; /* a fifo eop has been forced */ + // volatile int tr_running; /* 1 if output is running */ + + struct parport *port; + + /* Shadow registers */ + volatile unsigned long reg_ctrl_data_shadow; /* for R_PARx_CTRL_DATA */ + volatile unsigned long reg_config_shadow; /* for R_PARx_CONFIG */ + volatile unsigned long reg_delay_shadow; /* for R_PARx_DELAY */ +}; + +/* Always have the complete structs here, even if the port is not used! + * (that way we can index this by the port number) + */ +static struct etrax100par_struct port_table[] = { + { + R_PAR0_CTRL_DATA, + R_PAR0_STATUS_DATA, + R_PAR0_CONFIG, + R_PAR0_DELAY, + /* DMA interrupt stuff */ + 2, + 1U << 4, /* uses DMA 2 and 3 */ + R_DMA_CH2_CLR_INTR, + R_DMA_CH2_FIRST, + R_DMA_CH2_CMD, + R_DMA_CH3_CLR_INTR, + R_DMA_CH3_FIRST, + R_DMA_CH3_CMD, + R_DMA_CH3_STATUS, + R_DMA_CH3_HWSW, + /* Non DMA interrupt stuff */ + IO_BITNR(R_VECT_MASK_RD, par0), + R_IRQ_MASK0_RD, + R_IRQ_MASK0_CLR, + R_IRQ_READ0, + R_IRQ_MASK0_SET, + IO_FIELD(R_IRQ_MASK0_RD, par0_ready, 1U), /* tx (ready)*/ + IO_FIELD(R_IRQ_MASK0_RD, par0_data, 1U), /* rx (data)*/ + IO_FIELD(R_IRQ_MASK0_RD, par0_ecp_cmd, 1U), /* ecp_cmd */ + IO_FIELD(R_IRQ_MASK0_RD, par0_peri, 1U), /* peri */ + 0 + }, + { + R_PAR1_CTRL_DATA, + R_PAR1_STATUS_DATA, + R_PAR1_CONFIG, + R_PAR1_DELAY, + /* DMA interrupt stuff */ + 4, + 1U << 8, /* uses DMA 4 and 5 */ + + R_DMA_CH4_CLR_INTR, + R_DMA_CH4_FIRST, + R_DMA_CH4_CMD, + R_DMA_CH5_CLR_INTR, + R_DMA_CH5_FIRST, + R_DMA_CH5_CMD, + R_DMA_CH5_STATUS, + R_DMA_CH5_HWSW, + /* Non DMA interrupt stuff */ + IO_BITNR(R_VECT_MASK_RD, par1), + R_IRQ_MASK1_RD, + R_IRQ_MASK1_CLR, + R_IRQ_READ1, + R_IRQ_MASK1_SET, + IO_FIELD(R_IRQ_MASK1_RD, par1_ready, 1U), /* tx (ready)*/ + IO_FIELD(R_IRQ_MASK1_RD, par1_data, 1U), /* rx (data)*/ + IO_FIELD(R_IRQ_MASK1_RD, par1_ecp_cmd, 1U), /* ecp_cmd */ + IO_FIELD(R_IRQ_MASK1_RD, par1_peri, 1U), /* peri */ + 1 + } +}; + + +#define NR_PORTS (sizeof(port_table)/sizeof(struct etrax100par_struct)) + +static void +parport_etrax_write_data(struct parport *p, unsigned char value) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: etrax_write_data %02X\n", p->portnum, value); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, data, value); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static unsigned char +parport_etrax_read_data(struct parport *p) +{ + unsigned char ret; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + ret = IO_EXTRACT(R_PAR0_STATUS_DATA, data, *info->reg_status_data); + + DPRINTK("* E100 PP %d: etrax_read_data %02X\n", p->portnum, ret); + return ret; +} + + +static void +parport_etrax_write_control(struct parport *p, unsigned char control) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: etrax_write_control %02x\n", p->portnum, control); + + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, strb, + (control & PARPORT_CONTROL_STROBE) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd, + (control & PARPORT_CONTROL_AUTOFD) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init, + (control & PARPORT_CONTROL_INIT) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli, + (control & PARPORT_CONTROL_SELECT) > 0); + + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static unsigned char +parport_etrax_read_control( struct parport *p) +{ + unsigned char ret = 0; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + if (IO_EXTRACT(R_PAR0_CTRL_DATA, strb, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_STROBE; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_AUTOFD; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_INIT; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_SELECT; + + DPRINTK("* E100 PP %d: etrax_read_control %02x\n", p->portnum, ret); + return ret; +} + + +static unsigned char +parport_etrax_frob_control(struct parport *p, unsigned char mask, + unsigned char val) +{ + unsigned char old; + + DPRINTK("* E100 PP %d: frob_control mask %02x, value %02x\n", + p->portnum, mask, val); + old = parport_etrax_read_control(p); + parport_etrax_write_control(p, (old & ~mask) ^ val); + return old; +} + + +static unsigned char +parport_etrax_read_status(struct parport *p) +{ + unsigned char ret = 0; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + if (IO_EXTRACT(R_PAR0_STATUS_DATA, fault, *info->reg_status_data)) + ret |= PARPORT_STATUS_ERROR; + if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data)) + ret |= PARPORT_STATUS_SELECT; + if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data)) + ret |= PARPORT_STATUS_PAPEROUT; + if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data)) + ret |= PARPORT_STATUS_ACK; + if (!IO_EXTRACT(R_PAR0_STATUS_DATA, busy, *info->reg_status_data)) + ret |= PARPORT_STATUS_BUSY; + + DPRINTK("* E100 PP %d: status register %04x\n", + p->portnum, *info->reg_status_data); + DPRINTK("* E100 PP %d: read_status %02x\n", p->portnum, ret); + return ret; +} + + +static void +parport_etrax_enable_irq(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + *info->irq_mask_set = info->irq_mask_tx; + DPRINTK("* E100 PP %d: enable irq\n", p->portnum); +} + + +static void +parport_etrax_disable_irq(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + *info->irq_mask_clr = info->irq_mask_tx; + DPRINTK("* E100 PP %d: disable irq\n", p->portnum); +} + + +static void +parport_etrax_data_forward(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: forward mode\n", p->portnum); + SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, enable); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static void +parport_etrax_data_reverse(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: reverse mode\n", p->portnum); + SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, disable); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static void +parport_etrax_init_state(struct pardevice *dev, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_init_state\n"); +} + + +static void +parport_etrax_save_state(struct parport *p, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_save_state\n"); +} + + +static void +parport_etrax_restore_state(struct parport *p, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_restore_state\n"); +} + + +static void +parport_etrax_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + + +static void +parport_etrax_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + + +static struct +parport_operations pp_etrax_ops = { + parport_etrax_write_data, + parport_etrax_read_data, + + parport_etrax_write_control, + parport_etrax_read_control, + parport_etrax_frob_control, + + parport_etrax_read_status, + + parport_etrax_enable_irq, + parport_etrax_disable_irq, + + parport_etrax_data_forward, + parport_etrax_data_reverse, + + parport_etrax_init_state, + parport_etrax_save_state, + parport_etrax_restore_state, + + parport_etrax_inc_use_count, + parport_etrax_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, +}; + + +static void +parport_etrax_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct etrax100par_struct *info = (struct etrax100par_struct *) + ((struct parport *)dev_id)->private_data; + DPRINTK("* E100 PP %d: Interrupt received\n", + ((struct parport *)dev_id)->portnum); + *info->irq_mask_clr = info->irq_mask_tx; + parport_generic_irq(irq, (struct parport *)dev_id, regs); +} + +/* ----------- Initialisation code --------------------------------- */ + +static void +parport_etrax_show_parallel_version(void) +{ + printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n"); +} + +#ifdef CONFIG_ETRAX_PAR0_DMA +#define PAR0_USE_DMA 1 +#else +#define PAR0_USE_DMA 0 +#endif + +#ifdef CONFIG_ETRAX_PAR1_DMA +#define PAR1_USE_DMA 1 +#else +#define PAR1_USE_DMA 0 +#endif + +static void +parport_etrax_init_registers(void) +{ + struct etrax100par_struct *info; + int i; + + /* The different times below will be (value*160 + 20) ns, */ + /* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6), */ + /* the setup time will be (6*160+20) = 980ns. */ + + for (i = 0, info = port_table; i < 2; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + info->reg_config_shadow = + IO_STATE(R_PAR0_CONFIG, iseli, inv) | + IO_STATE(R_PAR0_CONFIG, iautofd, inv) | + IO_STATE(R_PAR0_CONFIG, istrb, inv) | + IO_STATE(R_PAR0_CONFIG, iinit, inv) | + IO_STATE(R_PAR0_CONFIG, rle_in, disable) | + IO_STATE(R_PAR0_CONFIG, rle_out, disable) | + IO_STATE(R_PAR0_CONFIG, enable, on) | + IO_STATE(R_PAR0_CONFIG, force, off) | + IO_STATE(R_PAR0_CONFIG, ign_ack, wait) | + IO_STATE(R_PAR0_CONFIG, oe_ack, wait_oe) | + IO_STATE(R_PAR0_CONFIG, mode, manual); + + if ((i == 0 && PAR0_USE_DMA) || (i == 1 && PAR1_USE_DMA)) + info->reg_config_shadow |= + IO_STATE(R_PAR0_CONFIG, dma, enable); + else + info->reg_config_shadow |= + IO_STATE(R_PAR0_CONFIG, dma, disable); + + *info->reg_config = info->reg_config_shadow; + + info->reg_ctrl_data_shadow = + IO_STATE(R_PAR0_CTRL_DATA, peri_int, nop) | + IO_STATE(R_PAR0_CTRL_DATA, oe, enable) | + IO_STATE(R_PAR0_CTRL_DATA, seli, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, autofd, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, strb, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, init, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, ecp_cmd, data) | + IO_FIELD(R_PAR0_CTRL_DATA, data, 0); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; + + /* Clear peri int without setting shadow */ + *info->reg_ctrl_data = info->reg_ctrl_data_shadow | + IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack); + + info->reg_delay_shadow = + IO_FIELD(R_PAR0_DELAY, setup, 5) | + IO_FIELD(R_PAR0_DELAY, strobe, 5) | + IO_FIELD(R_PAR0_DELAY, hold, 5); + *info->reg_delay = info->reg_delay_shadow; + } + +#ifdef CONFIG_ETRAX_PARALLEL_PORT0 +#ifdef CONFIG_ETRAX_PAR0_DMA + RESET_DMA(2); + WAIT_DMA(2); +#ifdef CONFIG_ETRAX_SERIAL_PORT2 + printk(" Warning - DMA clash with ser2!\n"); +#endif /* SERIAL_PORT2 */ +#endif /* DMA */ +#endif /* PORT0 */ + +#ifdef CONFIG_ETRAX_PARALLEL_PORT1 +#ifdef CONFIG_ETRAX_PAR1_DMA + RESET_DMA(4); + WAIT_DMA(4); +#ifdef CONFIG_ETRAX_SERIAL_PORT3 + printk(" Warning - DMA clash with ser3!\n"); +#endif /* SERIAL_PORT3 */ +#endif /* DMA */ +#endif /* PORT1 */ +} + + +int __init +parport_etrax_init(void) +{ + struct parport *p; + int port_exists = 0; + int i; + struct etrax100par_struct *info; + const char *names[] = { "parallel 0 tx+rx", "parallel 1 tx+rx" }; + + parport_etrax_show_parallel_version(); + parport_etrax_init_registers(); + + for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + p = parport_register_port((unsigned long)0, info->int_irq, + PARPORT_DMA_NONE, &pp_etrax_ops); + if (!p) + continue; + + info->port = p; + p->private_data = info; + /* Axis FIXME: Set mode flags. */ + /* p->modes = PARPORT_MODE_TRISTATE | PARPORT_MODE_SAFEININT; */ + + if(request_irq(info->int_irq, parport_etrax_interrupt, + SA_SHIRQ, names[i], p)) { + parport_unregister_port (p); + continue; + } + + printk(KERN_INFO "%s: ETRAX 100LX port %d using irq\n", + p->name, i); + parport_proc_register(p); + parport_announce_port(p); + port_exists = 1; + } + + return port_exists; +} + +void __exit +parport_etrax_exit(void) +{ + int i; + struct etrax100par_struct *info; + + for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + if (info->int_irq != PARPORT_IRQ_NONE) + free_irq(info->int_irq, info->port); + parport_proc_unregister(info->port); + parport_unregister_port(info->port); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/serial.c linux.ac/arch/cris/drivers/serial.c --- linux.vanilla/arch/cris/drivers/serial.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/drivers/serial.c Thu Apr 19 14:13:36 2001 @@ -1,12 +1,35 @@ -/* $Id: serial.c,v 1.6 2000/11/22 16:36:09 bjornw Exp $ +/* $Id: serial.c,v 1.12 2001/04/19 12:23:07 bjornw Exp $ * * Serial port driver for the ETRAX 100LX chip * - * Copyright (C) 1998, 1999, 2000 Axis Communications AB + * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB * * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.12 2001/04/19 12:23:07 bjornw + * CONFIG_RS485 -> CONFIG_ETRAX_RS485 + * + * Revision 1.11 2001/04/05 14:29:48 markusl + * Updated according to review remarks i.e. + * -Use correct types in port structure to avoid compiler warnings + * -Try to use IO_* macros whenever possible + * -Open should never return -EBUSY + * + * Revision 1.10 2001/03/05 13:14:07 bjornw + * Another spelling fix + * + * Revision 1.9 2001/02/23 13:46:38 bjornw + * Spellling check + * + * Revision 1.8 2001/01/23 14:56:35 markusl + * Made use of ser1 optional + * Needed by USB + * + * Revision 1.7 2001/01/19 16:14:48 perf + * Added kernel options for serial ports 234. + * Changed option names from CONFIG_ETRAX100_XYZ to CONFIG_ETRAX_XYZ. + * * Revision 1.6 2000/11/22 16:36:09 bjornw * Please marketing by using the correct case when spelling Etrax. * @@ -176,7 +199,7 @@ * */ -static char *serial_version = "$Revision: 1.6 $"; +static char *serial_version = "$Revision: 1.12 $"; #include #include @@ -252,12 +275,12 @@ //#define SERIAL_HANDLE_EARLY_ERRORS -#ifndef CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS +#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS /* Default number of timer ticks before flushing rx fifo * When using "little data, low latency applications: use 0 * When using "much data applications (PPP)" use ~5 */ -#define CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS 5 +#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 #endif #define MAX_FLUSH_TIME 8 @@ -285,6 +308,18 @@ #define REG_BAUD 3 #define REG_XOFF 4 /* this is a 32 bit register */ +/* + * General note regarding the use of IO_* macros in this file: + * + * We will use the bits defined for DMA channel 6 when using various + * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are + * the same for all channels (which of course they are). + * + * We will also use the bits defined for serial port 0 when writing commands + * to the different ports, as these bits too are the same for all ports. + */ + + /* this is the data for the four serial ports in the etrax100 */ /* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ /* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ @@ -329,9 +364,9 @@ /* RS-485 */ -#if defined(CONFIG_RS485) -#if defined(CONFIG_RS485_ON_PA) -static int rs485_pa_bit = CONFIG_RS485_ON_PA_BIT; +#if defined(CONFIG_ETRAX_RS485) +#if defined(CONFIG_ETRAX_RS485_ON_PA) +static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #endif @@ -367,36 +402,36 @@ { /* Ser 0 */ { -#if defined(CONFIG_ETRAX100_SER0_DTR_RI_DSR_CD_ON_PB) +#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB) R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - CONFIG_ETRAX100_SER0_DTR_ON_PB_BIT, - CONFIG_ETRAX100_SER0_RI_ON_PB_BIT, - CONFIG_ETRAX100_SER0_DSR_ON_PB_BIT, - CONFIG_ETRAX100_SER0_CD_ON_PB_BIT + CONFIG_ETRAX_SER0_DTR_ON_PB_BIT, + CONFIG_ETRAX_SER0_RI_ON_PB_BIT, + CONFIG_ETRAX_SER0_DSR_ON_PB_BIT, + CONFIG_ETRAX_SER0_CD_ON_PB_BIT #else &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3 #endif }, /* Ser 1 */ { -#if defined(CONFIG_ETRAX100_SER1_DTR_RI_DSR_CD_ON_PB) +#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB) R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - CONFIG_ETRAX100_SER1_DTR_ON_PB_BIT, - CONFIG_ETRAX100_SER1_RI_ON_PB_BIT, - CONFIG_ETRAX100_SER1_DSR_ON_PB_BIT, - CONFIG_ETRAX100_SER1_CD_ON_PB_BIT + CONFIG_ETRAX_SER1_DTR_ON_PB_BIT, + CONFIG_ETRAX_SER1_RI_ON_PB_BIT, + CONFIG_ETRAX_SER1_DSR_ON_PB_BIT, + CONFIG_ETRAX_SER1_CD_ON_PB_BIT #else &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3 #endif }, /* Ser 2 */ { -#if defined(CONFIG_ETRAX100_SER2_DTR_RI_DSR_CD_ON_PA) +#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA) R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow, - CONFIG_ETRAX100_SER2_DTR_ON_PA_BIT, - CONFIG_ETRAX100_SER2_RI_ON_PA_BIT, - CONFIG_ETRAX100_SER2_DSR_ON_PA_BIT, - CONFIG_ETRAX100_SER2_CD_ON_PA_BIT + CONFIG_ETRAX_SER2_DTR_ON_PA_BIT, + CONFIG_ETRAX_SER2_RI_ON_PA_BIT, + CONFIG_ETRAX_SER2_DSR_ON_PA_BIT, + CONFIG_ETRAX_SER2_CD_ON_PA_BIT #else &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3 #endif @@ -407,8 +442,8 @@ } }; -#if defined(CONFIG_RS485) && defined(CONFIG_RS485_ON_PA) -unsigned char rs485_pa_port = CONFIG_RS485_ON_PA_BIT; +#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA) +unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #define E100_RTS_MASK 0x20 @@ -459,7 +494,7 @@ static struct semaphore tmp_buf_sem = MUTEX; #endif -#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST #define TIMER1_IRQ_NBR 3 /* clock select 10 for timer 1 gives 230400 Hz */ @@ -494,7 +529,7 @@ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); fast_timer_started = 1; } -#endif /* CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST */ +#endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST */ /* * This function maps from the Bxxxx defines in asm/termbits.h into real @@ -654,7 +689,8 @@ { #ifndef CONFIG_SVINTO_SIM /* disable the receiver */ - info->port[REG_REC_CTRL] = (info->rx_ctrl &= ~0x40); + info->port[REG_REC_CTRL] = info->rx_ctrl &= + ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); #endif } @@ -663,7 +699,8 @@ { #ifndef CONFIG_SVINTO_SIM /* enable the receiver */ - info->port[REG_REC_CTRL] = (info->rx_ctrl |= 0x40); + info->port[REG_REC_CTRL] = info->rx_ctrl |= + IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); #endif } @@ -733,14 +770,14 @@ } #endif -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) /* Enable RS-485 mode on selected port. This is UGLY. */ static int e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) { struct e100_serial * info = (struct e100_serial *)tty->driver_data; -#if defined(CONFIG_RS485_ON_PA) +#if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); #endif @@ -752,7 +789,6 @@ return 0; } -/* Enable RS-485 mode on selected port. This is UGLY. */ static int e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) { @@ -768,7 +804,7 @@ * the receiver before initiating a DMA transfer */ e100_rts(info, info->rs485.rts_on_send); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_disable_rx(info); e100_disable_rxdma_irq(info); #endif @@ -810,14 +846,16 @@ max_j = jiffies + (delay_ms * HZ)/1000 + 10; while (jiffies < max_j ) { - if (info->port[REG_STATUS] & 0x20) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { for( i=0 ; i<100; i++ ) {}; - if (info->port[REG_STATUS] & 0x20) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { /* ~25 for loops per usec */ - stop_delay = 25 * (1000000 / info->baud); + stop_delay = 1000000 / info->baud; if(cflags & CSTOPB) stop_delay *= 2; - for( i=0 ; irs485.rts_after_sent); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif @@ -928,7 +966,9 @@ return; #endif /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ - *info->oclrintradr = 3; + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); #ifdef SERIAL_DEBUG_INTR if(info->line == SERIAL_DEBUG_LINE) @@ -973,19 +1013,20 @@ /* our job here is done, don't schedule any new DMA transfer */ info->tr_running = 0; -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) /* Check if we should toggle RTS now */ if (info->rs485.enabled) { /* Make sure fifo is empty */ int in_fifo = 0 ; do{ - in_fifo = (*info->ostatusadr) & 0x007F ; + in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail, + *info->ostatusadr); } while (in_fifo > 0) ; /* Any way to really check transmitter empty? (TEMT) */ /* Control RTS to set to RX mode */ e100_rts(info, info->rs485.rts_after_sent); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif @@ -1046,7 +1087,9 @@ /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ - *info->iclrintradr = 3; + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); if(!tty) /* something wrong... */ return; @@ -1074,7 +1117,9 @@ /* read the status register so we can detect errors */ rstat = info->port[REG_STATUS]; - if(rstat & 0xe) { + if(rstat & (IO_MASK(R_SERIAL0_STATUS, overrun) | + IO_MASK(R_SERIAL0_STATUS, par_err) | + IO_MASK(R_SERIAL0_STATUS, framing_err))) { /* if we got an error, we must reset it by reading the * data_in field */ @@ -1134,7 +1179,7 @@ descr->status = 0; *info->ifirstadr = virt_to_phys(descr); - *info->icmdadr = 1; /* start */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); #ifdef SERIAL_HANDLE_EARLY_ERRORS e100_enable_serial_data_irq(info); @@ -1156,8 +1201,9 @@ /* reset the input dma channel to be sure it works */ - *info->icmdadr = 4; - while((*info->icmdadr & 7) == 4); + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); descr = &info->rec_descr; @@ -1172,7 +1218,8 @@ info->tty->flip.count = 0; *info->ifirstadr = virt_to_phys(descr); - *info->icmdadr = 1; /* start */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); + } @@ -1267,19 +1314,19 @@ /* dma fifo/buffer timeout handler forces an end-of-packet for the dma input channel if no chars - have been received for CONFIG_ETRAX100_RX_TIMEOUT_TICKS/100 s. - If CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST is configured then this + have been received for CONFIG_ETRAX_RX_TIMEOUT_TICKS/100 s. + If CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is configured then this handler is instead run at 15360 Hz. */ -#ifndef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +#ifndef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST static int timeout_divider = 0; #endif static struct timer_list flush_timer; static void -timed_flush_handler(void) +timed_flush_handler(unsigned long ptr) { struct e100_serial *info; int i; @@ -1367,7 +1414,7 @@ PROCSTAT(early_errors_cnt[info->line]++); /* restart the DMA */ - *info->icmdadr = 3; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); } else { /* it was a valid byte, now let the dma do the rest */ #ifdef SERIAL_DEBUG_INTR @@ -1458,7 +1505,7 @@ if (info->flags & ASYNC_INITIALIZED) { free_page(page); restore_flags(flags); - return -EBUSY; + return 0; } if (info->xmit.buf) @@ -1467,7 +1514,7 @@ info->xmit.buf = (unsigned char *) page; #ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit_buf); + printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit.buf); #endif if(info->tty) { @@ -1504,14 +1551,22 @@ * Reset the DMA channels and make sure their interrupts are cleared */ - *info->icmdadr = 4; /* reset command */ - *info->ocmdadr = 4; /* reset command */ - - while((*info->icmdadr & 7) == 4); /* wait until reset cycle is complete */ - while((*info->ocmdadr & 7) == 4); - - *info->iclrintradr = 3; /* make sure the irqs are cleared */ - *info->oclrintradr = 3; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + + /* wait until reset cycle is complete */ + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1583,8 +1638,8 @@ /* reset both dma channels */ - *info->icmdadr = 4; - *info->ocmdadr = 4; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); #endif /* CONFIG_SVINTO_SIM */ @@ -1644,42 +1699,51 @@ #ifndef CONFIG_SVINTO_SIM info->port[REG_BAUD] = cflag_to_etrax_baud(cflag); /* start with default settings and then fill in changes */ - - info->rx_ctrl &= ~(0x07); /* 8 bit, no/even parity */ - info->tx_ctrl &= ~(0x37); /* 8 bit, no/even parity, 1 stop bit, no cts */ + + /* 8 bit, no/even parity */ + info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par)); + + /* 8 bit, no/even parity, 1 stop bit, no cts */ + info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par) | + IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) | + IO_MASK(R_SERIAL0_TR_CTRL, auto_cts)); if ((cflag & CSIZE) == CS7) { /* set 7 bit mode */ - info->tx_ctrl |= 0x01; - info->rx_ctrl |= 0x01; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); } if (cflag & CSTOPB) { /* set 2 stop bit mode */ - info->tx_ctrl |= 0x10; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits); } if (cflag & PARENB) { /* enable parity */ - info->tx_ctrl |= 0x02; - info->rx_ctrl |= 0x02; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); } if (cflag & PARODD) { /* set odd parity */ - info->tx_ctrl |= 0x04; - info->rx_ctrl |= 0x04; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); } if (cflag & CRTSCTS) { /* enable automatic CTS handling */ - info->tx_ctrl |= 0x20; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); } /* make sure the tx and rx are enabled */ - info->tx_ctrl |= 0x40; - info->rx_ctrl |= 0x40; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); /* actually write the control regs to the hardware */ @@ -2316,7 +2380,7 @@ return -EFAULT; return 0; -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) case TIOCSERSETRS485: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct rs485_control)); @@ -2474,10 +2538,10 @@ /* port closed */ -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) if (info->rs485.enabled) { info->rs485.enabled = 0; -#if defined(CONFIG_RS485_ON_PA) +#if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); #endif } @@ -2688,12 +2752,15 @@ return -ENODEV; /* dont allow opening ports that are not enabled in the HW config */ - -#ifndef CONFIG_ETRAX100_SERIAL_PORT2 +#ifndef CONFIG_ETRAX_SERIAL_PORT1 + if (line == 1) + return -ENODEV; +#endif +#ifndef CONFIG_ETRAX_SERIAL_PORT2 if (line == 2) return -ENODEV; #endif -#ifndef CONFIG_ETRAX100_SERIAL_PORT3 +#ifndef CONFIG_ETRAX_SERIAL_PORT3 if (line == 3) return -ENODEV; #endif @@ -2955,7 +3022,7 @@ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { info->line = i; info->tty = 0; - info->type = PORT_ETRAX100; + info->type = PORT_ETRAX; info->tr_running = 0; info->fifo_magic = 0; info->fifo_didmagic = 0; @@ -2990,25 +3057,27 @@ if(request_irq(8, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) panic("irq8"); #endif +#ifdef CONFIG_ETRAX_SERIAL_PORT1 if(request_irq(24, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) panic("irq24"); if(request_irq(25, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) panic("irq25"); -#ifdef CONFIG_ETRAX100_SERIAL_PORT2 +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT2 /* DMA Shared with par0 (and SCSI0 and ATA) */ if(request_irq(18, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) panic("irq18"); if(request_irq(19, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) panic("irq19"); #endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT3 +#ifdef CONFIG_ETRAX_SERIAL_PORT3 /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */ if(request_irq(20, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) panic("irq20"); if(request_irq(21, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) panic("irq21"); #endif -#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST /* TODO: a timeout_interrupt needs to be written that calls timeout_handler */ if(request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ, "fast serial dma timeout", NULL)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/serial.h linux.ac/arch/cris/drivers/serial.h --- linux.vanilla/arch/cris/drivers/serial.h Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/drivers/serial.h Thu Apr 19 14:13:36 2001 @@ -4,8 +4,8 @@ * Copyright (C) 1998, 1999, 2000 Axis Communications AB */ -#ifndef _ETRAX100_SERIAL_H -#define _ETRAX100_SERIAL_H +#ifndef _ETRAX_SERIAL_H +#define _ETRAX_SERIAL_H #include #include @@ -25,26 +25,26 @@ struct e100_serial { int baud; - volatile unsigned char * port; /* R_SERIALx_CTRL */ - unsigned long irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + volatile u8 *port; /* R_SERIALx_CTRL */ + u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ - volatile unsigned long *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ - volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ - const volatile unsigned short *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ - volatile unsigned long *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ - - volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ - volatile unsigned long *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ - volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ - const volatile unsigned short *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ - volatile unsigned long *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ + volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ + volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ + const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ + volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ + + volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ + volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD, input */ + const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ + volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ int flags; /* defined in tty.h */ - unsigned char rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ - unsigned char tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ - unsigned char iseteop; /* bit number for R_SET_EOP for the input dma */ + u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ + u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ + u8 iseteop; /* bit number for R_SET_EOP for the input dma */ /* end of fields defined in rs_table[] in .c-file */ unsigned char fifo_didmagic; /* a fifo eop has been forced */ @@ -64,7 +64,7 @@ unsigned long event; unsigned long last_active; int line; - int type; /* PORT_ETRAX100 */ + int type; /* PORT_ETRAX */ int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ @@ -93,7 +93,7 @@ * system. */ -#define PORT_ETRAX100 1 +#define PORT_ETRAX 1 /* * Events are used to schedule things to happen at timer-interrupt @@ -103,4 +103,4 @@ #endif /* __KERNEL__ */ -#endif /* !(_ETRAX100_SERIAL_H) */ +#endif /* !(_ETRAX_SERIAL_H) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/sync_serial.c linux.ac/arch/cris/drivers/sync_serial.c --- linux.vanilla/arch/cris/drivers/sync_serial.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/sync_serial.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,897 @@ +/* + * Simple synchronous serial port driver for ETRAX 100LX. + * + * Synchronous serial ports are used for continous streamed data like audio. + * The default setting for this driver is compatible with the STA 013 MP3 + * decoder. The driver can easily be tuned to fit other audio encoder/decoders + * and SPI + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Mikael Starvik + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The receiver is a bit tricky beacuse of the continous stream of data. */ +/* */ +/* Two DMA descriptors are linked together. Each DMA descriptor is */ +/* responsible for one half of a common buffer. */ +/* */ +/* ------------------------------ */ +/* | ---------- ---------- | */ +/* --> | Descr1 |-->| Descr2 |--- */ +/* ---------- ---------- */ +/* | | */ +/* v v */ +/* ----------------------------- */ +/* | BUFFER | */ +/* ----------------------------- */ +/* | | */ +/* readp writep */ +/* */ +/* If the application keeps up the pace readp will be right after writep.*/ +/* If the application can't keep the pace we have to throw away data. */ +/* The idea is that readp should be ready with the data pointed out by */ +/* Descr1 when the DMA has filled in Descr2. Otherwise we will discard */ +/* the rest of the data pointed out by Descr1 and set readp to the start */ +/* of Descr2 */ + +#define SYNC_SERIAL_MAJOR 125 + +/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ +/* words can be handled */ + +#define IN_BUFFER_SIZE 12288 +#define OUT_BUFFER_SIZE 4096 + +#define DEFAULT_FRAME_RATE 0 +#define DEFAULT_WORD_RATE 7 + +#define DEBUG(x) + +/* Define some macros to access ETRAX 100 registers */ +#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ + IO_FIELD(##reg##, field, val) +#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ + IO_STATE(##reg##, field, val) + +typedef struct sync_port +{ + /* Etrax registers and bits*/ + volatile unsigned * const status; + volatile unsigned * const ctrl_data; + volatile unsigned * const output_dma_first; + volatile unsigned char * const output_dma_cmd; + volatile unsigned char * const output_dma_clr_irq; + volatile unsigned * const input_dma_first; + volatile unsigned char * const input_dma_cmd; + volatile unsigned char * const input_dma_clr_irq; + volatile unsigned * const data_out; + volatile unsigned * const data_in; + char data_avail_bit; /* In R_IRQ_MASK1_RD */ + char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */ + char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */ + char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */ + char output_dma_bit; /* In R_IRQ_MASK2_RD */ + + int enabled; /* 1 if port is enabled */ + int use_dma; /* 1 if port uses dma */ + int port_nbr; /* Port 0 or 1 */ + unsigned ctrl_data_shadow; /* Register shadow */ + char busy; /* 1 if port is busy */ + wait_queue_head_t out_wait_q; + wait_queue_head_t in_wait_q; + struct etrax_dma_descr out_descr; + struct etrax_dma_descr in_descr1; + struct etrax_dma_descr in_descr2; + char out_buffer[OUT_BUFFER_SIZE]; + int out_count; /* Remaining bytes for current transfer */ + char* outp; /* Current position in out_buffer */ + char in_buffer[IN_BUFFER_SIZE]; + volatile char* readp; /* Next byte to be read by application */ + volatile char* writep; /* Next byte to be written by etrax */ + int odd_output; /* 1 if writing odd nible in 12 bit mode */ + int odd_input; /* 1 if reading odd nible in 12 bit mode */ +} sync_port; + + +static int etrax_sync_serial_init(void); +static void initialize_port(int portnbr); +static int sync_serial_open(struct inode *, struct file*); +static int sync_serial_release(struct inode*, struct file*); +static int sync_serial_ioctl(struct inode*, struct file*, + unsigned int cmd, unsigned long arg); +static ssize_t sync_serial_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t sync_serial_manual_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t sync_serial_read(struct file *file, char *buf, + size_t count, loff_t *ppos); +static void send_word(sync_port* port); +static void start_dma(struct sync_port *port, const char* data, int count); +static void start_dma_in(sync_port* port); +static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); + +/* The ports */ +static struct sync_port ports[]= +{ + { + R_SYNC_SERIAL1_STATUS, /* status */ + R_SYNC_SERIAL1_CTRL, /* ctrl_data */ + R_DMA_CH8_FIRST, /* output_dma_first */ + R_DMA_CH8_CMD, /* output_dma_cmd */ + R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH9_FIRST, /* input_dma_first */ + R_DMA_CH9_CMD, /* input_dma_cmd */ + R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ + R_SYNC_SERIAL1_TR_DATA, /* data_out */ + R_SYNC_SERIAL1_REC_DATA,/* data in */ + IO_BITNR(R_IRQ_MASK1_RD, ser1_data), /* data_avail_bit */ + IO_BITNR(R_IRQ_MASK1_RD, ser1_ready), /* transmitter_ready_bit */ + IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma9_descr), /* input_dma_descr_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ + }, + { + R_SYNC_SERIAL3_STATUS, /* status */ + R_SYNC_SERIAL3_CTRL, /* ctrl_data */ + R_DMA_CH4_FIRST, /* output_dma_first */ + R_DMA_CH4_CMD, /* output_dma_cmd */ + R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH5_FIRST, /* input_dma_first */ + R_DMA_CH5_CMD, /* input_dma_cmd */ + R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ + R_SYNC_SERIAL3_TR_DATA, /* data_out */ + R_SYNC_SERIAL3_REC_DATA,/* data in */ + IO_BITNR(R_IRQ_MASK1_RD, ser3_data), /* data_avail_bit */ + IO_BITNR(R_IRQ_MASK1_RD, ser3_ready), /* transmitter_ready_bit */ + IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_descr_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ + } +}; + +/* Register shadows */ +static unsigned sync_serial_prescale_shadow = 0; +static unsigned gen_config_ii_shadow = 0; + +#define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) + +static struct file_operations sync_serial_fops = { + owner: THIS_MODULE, + write: sync_serial_write, + read: sync_serial_read, + ioctl: sync_serial_ioctl, + open: sync_serial_open, + release: sync_serial_release +}; + +static int __init etrax_sync_serial_init(void) +{ + ports[0].enabled = 0; + ports[1].enabled = 0; + + if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 ) + { + printk("unable to get major for synchronous serial port\n"); + return -EBUSY; + } + + /* Deselect synchronous serial ports */ + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, ser3, select); + *R_GEN_CONFIG_II = gen_config_ii_shadow; + + /* Initialize Ports */ +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) + ports[0].enabled = 1; + SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser1, ss1extra); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) + ports[0].use_dma = 1; + initialize_port(0); + if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", &ports[0])) + panic("Can't allocate sync serial port 1 IRQ"); + if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[0])) + panic("Can't allocate sync serial port 1 IRQ"); + RESET_DMA(8); WAIT_DMA(8); + RESET_DMA(9); WAIT_DMA(9); + *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); + *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); + start_dma_in(&ports[0]); +#else + ports[0].use_dma = 0; + initialize_port(0); + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0])) + panic("Can't allocate sync serial manual irq"); + *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set); +#endif +#endif + +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) + ports[1].enabled = 1; + SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser3, ss3extra); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) + ports[1].use_dma = 1; + initialize_port(1); + if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", &ports[1])) + panic("Can't allocate sync serial port 1 IRQ"); + if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", &ports[1])) + panic("Can't allocate sync serial port 1 IRQ"); + RESET_DMA(4); WAIT_DMA(4); + RESET_DMA(5); WAIT_DMA(5); + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); + *R_DMA_CH5_CLR_INTR = IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set); + start_dma_in(&ports[1]); +#else + ports[1].use_dma = 0; + initialize_port(1); + if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */ + { + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1])) + panic("Can't allocate sync serial manual irq"); + } + *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set); +#endif +#endif + + *R_PORT_PB_I2C = port_pb_i2c_shadow; /* Use PB4/PB7 */ + + /* Set up timing */ + *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow = ( + IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u1, external) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, DEFAULT_FRAME_RATE) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, DEFAULT_WORD_RATE) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal)); + + /* Select synchronous ports */ + *R_GEN_CONFIG_II = gen_config_ii_shadow; + + printk("ETRAX 100LX synchronous serial port driver\n"); + return 0; +} + +static void initialize_port(int portnbr) +{ + struct sync_port* port = &ports[portnbr]; + + DEBUG(printk("Init sync serial port %d\n", portnbr)); + + port->port_nbr = portnbr; + port->busy = 0; + port->readp = port->in_buffer; + port->writep = port->in_buffer + IN_BUFFER_SIZE/2; + port->odd_input = 0; + + init_waitqueue_head(&port->out_wait_q); + init_waitqueue_head(&port->in_wait_q); + + port->ctrl_data_shadow = + IO_STATE(R_SYNC_SERIAL1_CTRL, tr_baud, c115k2Hz) | + IO_STATE(R_SYNC_SERIAL1_CTRL, mode, master_output) | + IO_STATE(R_SYNC_SERIAL1_CTRL, error, ignore) | + IO_STATE(R_SYNC_SERIAL1_CTRL, rec_enable, disable) | + IO_STATE(R_SYNC_SERIAL1_CTRL, f_synctype, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word) | + IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, stopped) | + IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb) | + IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, disable) | + IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit) | + IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8) | + IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8) | + IO_STATE(R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_polarity, neg) | + IO_STATE(R_SYNC_SERIAL1_CTRL, frame_polarity, normal)| + IO_STATE(R_SYNC_SERIAL1_CTRL, status_polarity, inverted)| + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_driver, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, frame_driver, normal) | + IO_STATE(R_SYNC_SERIAL1_CTRL, status_driver, normal)| + IO_STATE(R_SYNC_SERIAL1_CTRL, def_out0, high); + + if (port->use_dma) + port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, on); + else + port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, off); + + *port->ctrl_data = port->ctrl_data_shadow; +} + +static int sync_serial_open(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + DEBUG(printk("Open sync serial port %d\n", dev)); + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + if (ports[dev].busy) + { + DEBUG(printk("Device is busy.. \n")); + return -EBUSY; + } + ports[dev].busy = 1; + return 0; +} + +static int sync_serial_release(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + ports[dev].busy = 0; + return 0; +} + +static int sync_serial_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int return_val = 0; + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + sync_port* port; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -1; + } + port = &ports[dev]; + + /* Disable port while changing config */ + if (dev) + { + RESET_DMA(4); WAIT_DMA(4); + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); + } + else + { + RESET_DMA(8); WAIT_DMA(8); + *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); + } + *R_GEN_CONFIG_II = gen_config_ii_shadow; + + switch(cmd) + { + case SSP_SPEED: + if (GET_SPEED(arg) == CODEC) + { + if (dev) + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec); + else + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec); + + SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, prescaler, GET_FREQ(arg)); + SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, frame_rate, GET_FRAME_RATE(arg)); + SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, word_rate, GET_WORD_RATE(arg)); + } + else + { + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_baud, GET_SPEED(arg)); + if (dev) + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, baudrate); + else + SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, baudrate); + } + break; + case SSP_MODE: + if (arg > 5) + return -EINVAL; + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg); + break; + case SSP_FRAME_SYNC: + if (arg & NORMAL_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); + else if (arg & EARLY_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, early); + + if (arg & BIT_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, bit); + else if (arg & WORD_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); + else if (arg & EXTENDED_SYNC) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, extended); + + if (arg & SYNC_ON) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); + else if (arg & SYNC_OFF) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, off); + + if (arg & WORD_SIZE_8) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); + else if (arg & WORD_SIZE_12) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size12bit); + else if (arg & WORD_SIZE_16) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size16bit); + else if (arg & WORD_SIZE_24) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size24bit); + else if (arg & WORD_SIZE_32) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size32bit); + + if (arg & BIT_ORDER_MSB) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); + else if (arg & BIT_ORDER_LSB) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, lsb); + + if (arg & FLOW_CONTROL_ENABLE) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled); + else if (arg & FLOW_CONTROL_DISABLE) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); + + if (arg & CLOCK_NOT_GATED) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal); + else if (arg & CLOCK_GATED) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated); + + break; + case SSP_IPOLARITY: + if (arg & CLOCK_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); + else if (arg & CLOCK_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, pos); + + if (arg & FRAME_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, normal); + else if (arg & FRAME_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); + + if (arg & STATUS_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, normal); + else if (arg & STATUS_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, inverted); + break; + case SSP_OPOLARITY: + if (arg & CLOCK_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, normal); + else if (arg & CLOCK_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); + + if (arg & FRAME_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, normal); + else if (arg & FRAME_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); + + if (arg & STATUS_NORMAL) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, normal); + else if (arg & STATUS_INVERT) + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, inverted); + break; + case SSP_SPI: + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); + if (arg & SPI_SLAVE) + { + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, SLAVE_INPUT); + } + else + { + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); + SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, MASTER_OUTPUT); + } + break; + default: + return_val = -1; + } + /* Set config and enable port */ + *port->ctrl_data = port->ctrl_data_shadow; + *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow; + if (dev) + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); + else + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); + + *R_GEN_CONFIG_II = gen_config_ii_shadow; + return return_val; +} + +static ssize_t sync_serial_manual_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); + sync_port* port; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + + port = &ports[dev]; + copy_from_user(port->out_buffer, buf, count); + port->outp = port->out_buffer; + port->out_count = count; + port->odd_output = 1; + add_wait_queue(&port->out_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + *R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */ + send_word(port); /* Start sender by sending first word */ + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->out_wait_q, &wait); + if (signal_pending(current)) + { + return -EINTR; + } + return count; +} + +static ssize_t sync_serial_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); + sync_port *port; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + port = &ports[dev]; + + DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count)); + + count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count; + + /* Make sure transmitter is running */ + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable); + *port->ctrl_data = port->ctrl_data_shadow; + + if (!port->use_dma) + { + return sync_serial_manual_write(file, buf, count, ppos); + } + + copy_from_user(port->out_buffer, buf, count); + add_wait_queue(&port->out_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + start_dma(port, buf, count); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->out_wait_q, &wait); + if (signal_pending(current)) + { + return -EINTR; + } + return count; +} + +static ssize_t sync_serial_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + int avail; + sync_port *port; + char* start; + char* end; + unsigned long flags; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + port = &ports[dev]; + + DEBUG(printk("Read dev %d count %d\n", dev, count)); + + /* Make sure receiver is running */ + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable); + *port->ctrl_data = port->ctrl_data_shadow; + + /* Calculate number of available bytes */ + while (port->readp == port->writep) /* No data */ + { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&port->in_wait_q); + if (signal_pending(current)) + { + return -EINTR; + } + } + + /* Save pointers to avoid that they are modified by interrupt */ + start = port->readp; + end = port->writep; + + /* Lazy read, never return wrapped data. */ + if (end > start) + avail = end - start; + else + avail = port->in_buffer + IN_BUFFER_SIZE - start; + + count = count > avail ? avail : count; + copy_to_user(buf, start, count); + + /* Disable interrupts while updating readp */ + save_flags(flags); + cli(); + port->readp += count; + if (port->readp == port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ + port->readp = port->in_buffer; + restore_flags(flags); + + DEBUG(printk("%d bytes read\n", count)); + return count; +} + +static void send_word(sync_port* port) +{ + switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) + { + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): + port->out_count--; + *port->data_out = *port->outp++; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): + port->out_count--; + if (port->odd_output) + *port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1)); + else + *port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1)); + port->odd_output = !port->odd_output; + port->outp++; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): + port->out_count-=2; + *port->data_out = *(unsigned short *)port->outp; + port->outp+=2; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): + port->out_count-=3; + *port->data_out = *(unsigned int *)port->outp; + port->outp+=3; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): + port->out_count-=4; + *port->data_out = *(unsigned int *)port->outp; + port->outp+=4; + break; + } +} + +static void start_dma(struct sync_port* port, const char* data, int count) +{ + port->out_descr.hw_len = 0; + port->out_descr.next = 0; + port->out_descr.ctrl = d_int | d_eol | d_eop; + port->out_descr.sw_len = count; + port->out_descr.buf = virt_to_phys(port->out_buffer); + port->out_descr.status = 0; + + *port->output_dma_first = virt_to_phys(&port->out_descr); + *port->output_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); +} + +static void start_dma_in(sync_port* port) +{ + if (port->writep > port->in_buffer + IN_BUFFER_SIZE) + { + panic("Offset too large in sync serial driver\n"); + return; + } + port->in_descr1.hw_len = 0; + port->in_descr1.ctrl = d_int; + port->in_descr1.status = 0; + port->in_descr1.next = virt_to_phys(&port->in_descr2); + port->in_descr2.hw_len = 0; + port->in_descr2.next = virt_to_phys(&port->in_descr1); + port->in_descr2.ctrl = d_int; + port->in_descr2.status = 0; + + /* Find out which descriptor to start */ + if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) + { + /* Start descriptor 2 */ + port->in_descr1.sw_len = IN_BUFFER_SIZE/2; /* All data available in 1 */ + port->in_descr1.buf = virt_to_phys(port->in_buffer); + port->in_descr2.sw_len = port->in_buffer + IN_BUFFER_SIZE - port->writep; + port->in_descr2.buf = virt_to_phys(port->writep); + *port->input_dma_first = virt_to_phys(&port->in_descr2); + } + else + { + /* Start descriptor 1 */ + port->in_descr1.sw_len = port->in_buffer + IN_BUFFER_SIZE/2 - port->writep; + port->in_descr1.buf = virt_to_phys(port->writep); + port->in_descr2.sw_len = IN_BUFFER_SIZE/2; + port->in_descr2.buf = virt_to_phys(port->in_buffer + IN_BUFFER_SIZE / 2); + *port->input_dma_first = virt_to_phys(&port->in_descr1); + } + *port->input_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); +} + +static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned long ireg = *R_IRQ_MASK2_RD; + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + sync_port *port = &ports[i]; + if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */ + { + /* Clear IRQ */ + *port->output_dma_clr_irq = + IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); + wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */ + } + } +} + +static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned long ireg = *R_IRQ_MASK2_RD; + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + int update = 0; + sync_port *port = &ports[i]; + + if (!port->enabled) + { + continue; + } + + if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */ + { + /* DMA has reached end of descriptor */ + *port->input_dma_clr_irq = + IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); + + /* Find out which descriptor that is ready */ + if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) + { + /* Descr 2 was ready. Restart DMA at descriptor 1 */ + port->writep = port->in_buffer; + + /* Throw away data? */ + if (port->readp < port->in_buffer + IN_BUFFER_SIZE/2) + port->readp = port->in_buffer + IN_BUFFER_SIZE/2; + } + else + { + /* Descr 1 was ready. Restart DMA at descriptor 2 */ + port->writep = port->in_buffer + IN_BUFFER_SIZE/2; + + /* Throw away data? */ + if (port->readp >= port->in_buffer + IN_BUFFER_SIZE/2) + port->readp = port->in_buffer; + } + start_dma_in(port); + wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ + } + } +} + +static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + sync_port* port = &ports[i]; + + if (!port->enabled) + { + continue; + } + + if (*R_IRQ_MASK1_RD & (1 << port->data_avail_bit)) /* Data received? */ + { + /* Read data */ + switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) + { + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): + *port->writep++ = *(volatile char *)port->data_in; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): + { + int data = *(unsigned short *)port->data_in; + if (port->odd_input) + { + *port->writep |= (data & 0x0f00) >> 8; + *(port->writep + 1) = data & 0xff; + } + else + { + *port->writep = (data & 0x0ff0) >> 4; + *(port->writep + 1) = (data & 0x0f) << 4; + } + port->odd_input = !port->odd_input; + port->writep+=1; + } + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): + *(unsigned short*)port->writep = *(volatile unsigned short *)port->data_in; + port->writep+=2; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): + *(unsigned int*)port->writep = *port->data_in; + port->writep+=3; + break; + case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): + *(unsigned int*)port->writep = *port->data_in; + port->writep+=4; + break; + } + + if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ + port->writep = port->in_buffer; + wake_up_interruptible(&port->in_wait_q); /* Wake up application */ + } + + if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */ + { + if (port->out_count) /* More data to send */ + send_word(port); + else /* transmission finished */ + { + *R_IRQ_MASK1_CLR = 1 << port->ready_irq_bit; /* Turn off IRQ */ + wake_up_interruptible(&port->out_wait_q); /* Wake up application */ + } + } + } +} + +module_init(etrax_sync_serial_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/usb-host.c linux.ac/arch/cris/drivers/usb-host.c --- linux.vanilla/arch/cris/drivers/usb-host.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/usb-host.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,2501 @@ +/* + * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD) + * + * Copyright (c) 2001 Axis Communications AB. + * + * $Id: usb-host.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "usb-host.h" + +#define ETRAX_USB_HC_IRQ 31 +#define ETRAX_USB_RX_IRQ 25 +#define ETRAX_USB_TX_IRQ 24 + +static const char *usb_hcd_version = "$Revision: 1.8 $"; + +#undef KERN_DEBUG +#define KERN_DEBUG "" + +#undef USB_DEBUG_RH +#undef USB_DEBUG_EP +#undef USB_DEBUG_DESC +#undef USB_DEBUG_TRACE +#undef USB_DEBUG_CTRL +#undef USB_DEBUG_BULK +#undef USB_DEBUG_INTR + +#ifdef USB_DEBUG_RH +#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg) +#else +#define dbg_rh(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_EP +#define dbg_ep(format, arg...) printk(KERN_DEBUG __FILE__ ": (EP) " format "\n" , ## arg) +#else +#define dbg_ep(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_CTRL +#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg) +#else +#define dbg_ctrl(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_BULK +#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg) +#else +#define dbg_bulk(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_INTR +#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg) +#else +#define dbg_intr(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_TRACE +#define DBFENTER (printk(KERN_DEBUG __FILE__ ": Entering : " __FUNCTION__ "\n")) +#define DBFEXIT (printk(KERN_DEBUG __FILE__ ": Exiting : " __FUNCTION__ "\n")) +#else +#define DBFENTER (NULL) +#define DBFEXIT (NULL) +#endif + +/*------------------------------------------------------------------- + Virtual Root Hub + -------------------------------------------------------------------*/ + +static __u8 root_hub_dev_des[] = +{ + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __u16 bcdUSB; v1.0 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; Bit 7: Bus-powered */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static __u8 root_hub_hub_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x02, /* __u8 bNbrPorts; */ + 0x00, /* __u16 wHubCharacteristics; */ + 0x00, + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + + +#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break +#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ +{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} + +static submit_urb_count = 0; + +//#define ETRAX_USB_INTR_IRQ +//#define ETRAX_USB_INTR_ERROR_FATAL + +#define RX_BUF_SIZE 32768 +#define RX_DESC_BUF_SIZE 64 +#define NBR_OF_RX_DESC (RX_BUF_SIZE / RX_DESC_BUF_SIZE) + +#define NBR_OF_EP_DESC 32 + +#define MAX_INTR_INTERVAL 128 + +static __u32 ep_usage_bitmask; +static __u32 ep_really_active; + +static unsigned char RxBuf[RX_BUF_SIZE]; +static USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4))); + +static volatile USB_IN_Desc_t *myNextRxDesc; +static volatile USB_IN_Desc_t *myLastRxDesc; +static volatile USB_IN_Desc_t *myPrevRxDesc; + +static USB_EP_Desc_t TxCtrlEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); +static USB_EP_Desc_t TxBulkEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); + +static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4))); +static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4))); + +static urb_t *URB_List[NBR_OF_EP_DESC]; +static kmem_cache_t *usb_desc_cache; +static struct usb_bus *etrax_usb_bus; + +static void dump_urb (purb_t purb); +static void init_rx_buffers(void); +static int etrax_rh_unlink_urb (urb_t *urb); +static void etrax_rh_send_irq(urb_t *urb); +static void etrax_rh_init_int_timer(urb_t *urb); +static void etrax_rh_int_timer_do(unsigned long ptr); + +static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, + char packsize, char slow); +static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp); +static int etrax_usb_allocate_epid(void); +static void etrax_usb_free_epid(char epid); +static void cleanup_sb(USB_SB_Desc_t *sb); + +static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen); +static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen); + +static int etrax_usb_submit_ctrl_urb(urb_t *urb); + +static int etrax_usb_submit_urb(urb_t *urb); +static int etrax_usb_unlink_urb(urb_t *urb); +static int etrax_usb_get_frame_number(struct usb_device *usb_dev); +static int etrax_usb_allocate_dev(struct usb_device *usb_dev); +static int etrax_usb_deallocate_dev(struct usb_device *usb_dev); + +static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs); +static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs); +static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs); + +static int etrax_rh_submit_urb (urb_t *urb); + +static int etrax_usb_hc_init(void); +static void etrax_usb_hc_cleanup(void); + +static struct usb_operations etrax_usb_device_operations = +{ + etrax_usb_allocate_dev, + etrax_usb_deallocate_dev, + etrax_usb_get_frame_number, + etrax_usb_submit_urb, + etrax_usb_unlink_urb +}; + +#ifdef USB_DEBUG_DESC +static void dump_urb(purb_t purb) +{ + printk("\nurb :0x%08X\n", purb); + printk("next :0x%08X\n", purb->next); + printk("dev :0x%08X\n", purb->dev); + printk("pipe :0x%08X\n", purb->pipe); + printk("status :%d\n", purb->status); + printk("transfer_flags :0x%08X\n", purb->transfer_flags); + printk("transfer_buffer :0x%08X\n", purb->transfer_buffer); + printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length); + printk("actual_length :%d\n", purb->actual_length); + printk("setup_packet :0x%08X\n", purb->setup_packet); + printk("start_frame :%d\n", purb->start_frame); + printk("number_of_packets :%d\n", purb->number_of_packets); + printk("interval :%d\n", purb->interval); + printk("error_count :%d\n", purb->error_count); + printk("context :0x%08X\n", purb->context); + printk("complete :0x%08X\n\n", purb->complete); +} + +static void dump_in_desc(USB_IN_Desc_t *in) +{ + printk("\nUSB_IN_Desc at 0x%08X\n", in); + printk(" sw_len : 0x%04X (%d)\n", in->sw_len, in->sw_len); + printk(" command : 0x%04X\n", in->command); + printk(" next : 0x%08X\n", in->next); + printk(" buf : 0x%08X\n", in->buf); + printk(" hw_len : 0x%04X (%d)\n", in->hw_len, in->hw_len); + printk(" status : 0x%04X\n\n", in->status); +} + +static void dump_sb_desc(USB_SB_Desc_t *sb) +{ + printk("\nUSB_SB_Desc at 0x%08X\n", sb); + printk(" sw_len : 0x%04X (%d)\n", sb->sw_len, sb->sw_len); + printk(" command : 0x%04X\n", sb->command); + printk(" next : 0x%08X\n", sb->next); + printk(" buf : 0x%08X\n\n", sb->buf); +} + + +static void dump_ep_desc(USB_EP_Desc_t *ep) +{ + printk("\nUSB_EP_Desc at 0x%08X\n", ep); + printk(" hw_len : 0x%04X (%d)\n", ep->hw_len, ep->hw_len); + printk(" command : 0x%08X\n", ep->command); + printk(" sub : 0x%08X\n", ep->sub); + printk(" nep : 0x%08X\n\n", ep->nep); +} + + +#else +#define dump_urb(...) (NULL) +#define dump_ep_desc(...) (NULL) +#define dump_sb_desc(...) (NULL) +#define dump_in_desc(...) (NULL) +#endif + +static void init_rx_buffers(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].command = 0; + RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); + RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); + RxDescList[i].hw_len = 0; + RxDescList[i].status = 0; + } + + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes); + RxDescList[i].next = virt_to_phys(&RxDescList[0]); + RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); + RxDescList[i].hw_len = 0; + RxDescList[i].status = 0; + + myNextRxDesc = &RxDescList[0]; + myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + + *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc); + *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start); + + DBFEXIT; +} + +static void init_tx_ctrl_ep(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { + TxCtrlEPList[i].hw_len = 0; + TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i); + TxCtrlEPList[i].sub = 0; + TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[i + 1]); + } + + TxCtrlEPList[i].hw_len = 0; + TxCtrlEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | + IO_FIELD(USB_EP_command, epid, i); + + TxCtrlEPList[i].sub = 0; + TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[0]); + + *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]); + *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); + + DBFEXIT; +} + +static void init_tx_bulk_ep(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { + TxBulkEPList[i].hw_len = 0; + TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i); + TxBulkEPList[i].sub = 0; + TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[i + 1]); + } + + TxBulkEPList[i].hw_len = 0; + TxBulkEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | + IO_FIELD(USB_EP_command, epid, i); + + TxBulkEPList[i].sub = 0; + TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[0]); + + *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[0]); + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); + + DBFEXIT; +} + +static void init_tx_intr_ep(void) +{ + int i; + + DBFENTER; + + TxIntrSB_zout.sw_len = 0; + TxIntrSB_zout.next = 0; + TxIntrSB_zout.buf = 0; + TxIntrSB_zout.command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { + TxIntrEPList[i].hw_len = 0; + TxIntrEPList[i].command = IO_STATE(USB_EP_command, eof, yes) | + IO_STATE(USB_EP_command, enable, yes) | + IO_FIELD(USB_EP_command, epid, 0); + TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); + TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[i + 1]); + } + + TxIntrEPList[i].hw_len = 0; + TxIntrEPList[i].command = + IO_STATE(USB_EP_command, eof, yes) | + IO_STATE(USB_EP_command, enable, yes) | + IO_FIELD(USB_EP_command, epid, 0); + TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); + TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[0]); + + *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + + DBFEXIT; +} + + +static int etrax_usb_unlink_intr_urb(urb_t *urb) +{ + struct usb_device *usb_dev = urb->dev; + etrax_hc_t *hc = usb_dev->bus->hcpriv; + + USB_EP_Desc_t *tmp_ep; + USB_EP_Desc_t *first_ep; + + USB_EP_Desc_t *ep_desc; + USB_SB_Desc_t *sb_desc; + + char epid; + char devnum; + char endpoint; + char slow; + int maxlen; + int i; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + slow = usb_pipeslow(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + err("Trying to unlink urb that is not in traffic queue!!"); + return -1; /* fix this */ + } + + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, stop); + /* Somehow wait for the DMA to finish current activities */ + i = jiffies + 100; + while (jiffies < i); + + first_ep = &TxIntrEPList[0]; + tmp_ep = first_ep; + + do { + if (IO_EXTRACT(USB_EP_command, epid, ((USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep))->command) + == epid) { + /* Unlink it !!! */ + dbg_intr("Found urb to unlink for epid %d", epid); + + ep_desc = phys_to_virt(tmp_ep->nep); + tmp_ep->nep = ep_desc->nep; + kmem_cache_free(usb_desc_cache, phys_to_virt(ep_desc->sub)); + kmem_cache_free(usb_desc_cache, ep_desc); + } + + tmp_ep = phys_to_virt(tmp_ep->nep); + + } while (tmp_ep != first_ep); + + /* We should really try to move the EP register to an EP that is not removed + instead of restarting, but this will work too */ + *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + + clear_bit(epid, (void *)&ep_really_active); + URB_List[epid] = NULL; + etrax_usb_free_epid(epid); + + DBFEXIT; + + return 0; +} + +void etrax_usb_do_intr_recover(int epid) +{ + USB_EP_Desc_t *first_ep, *tmp_ep; + + first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); + tmp_ep = first_ep; + + do { + if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid && + !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) { + tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes); + } + + tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); + + } while (tmp_ep != first_ep); +} + +static int etrax_usb_submit_intr_urb(urb_t *urb) +{ + USB_EP_Desc_t *tmp_ep; + USB_EP_Desc_t *first_ep; + + USB_SB_Desc_t *sb_desc; + + char epid; + char devnum; + char endpoint; + char maxlen; + char slow; + int interval; + int i; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + + slow = usb_pipeslow(urb->pipe); + interval = urb->interval; + + dbg_intr("Intr traffic for dev %d, endpoint %d, maxlen %d, slow %d", + devnum, endpoint, maxlen, slow); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + epid = etrax_usb_allocate_epid(); + if (epid == -1) { + /* We're out of endpoints, return some error */ + err("We're out of endpoints"); + return -ENOMEM; + } + /* Now we have to fill in this ep */ + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + } + /* Ok, now we got valid endpoint, lets insert some traffic */ + + urb_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); + urb_priv->first_sb = 0; + urb_priv->rx_offset = 0; + urb_priv->eot = 0; + INIT_LIST_HEAD(&urb_priv->ep_in_list); + urb->hcpriv = urb_priv; + + /* This is safe since there cannot be any other URB's for this epid */ + URB_List[epid] = urb; +#if 0 + first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); +#else + first_ep = &TxIntrEPList[0]; +#endif + + /* Round of the interval to 2^n, it is obvious that this code favours + smaller numbers, but that is actually a good thing */ + for (i = 0; interval; i++) { + interval = interval >> 1; + } + + urb->interval = interval = 1 << (i - 1); + + dbg_intr("Interval rounded to %d", interval); + + tmp_ep = first_ep; + i = 0; + do { + if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) { + if ((i % interval) == 0) { + /* Insert the traffic ep after tmp_ep */ + USB_EP_Desc_t *traffic_ep; + USB_SB_Desc_t *traffic_sb; + + traffic_ep = (USB_EP_Desc_t *) + kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + traffic_sb = (USB_SB_Desc_t *) + kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + traffic_ep->hw_len = 0; + traffic_ep->command = IO_FIELD(USB_EP_command, epid, epid) | + IO_STATE(USB_EP_command, enable, yes); + traffic_ep->sub = virt_to_phys(traffic_sb); + + if (usb_pipein(urb->pipe)) { + traffic_sb->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + traffic_sb->next = 0; + traffic_sb->buf = 0; + traffic_sb->command = IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + } else if (usb_pipeout(urb->pipe)) { + traffic_sb->sw_len = urb->transfer_buffer_length; + traffic_sb->next = 0; + traffic_sb->buf = virt_to_phys(urb->transfer_buffer); + traffic_sb->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, out) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes) | + IO_STATE(USB_SB_command, full, yes); + } + + traffic_ep->nep = tmp_ep->nep; + tmp_ep->nep = virt_to_phys(traffic_ep); + dbg_intr("One ep sucessfully inserted"); + } + i++; + } + tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); + } while (tmp_ep != first_ep); + + set_bit(epid, (void *)&ep_really_active); + + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + + DBFEXIT; + + return 0; +} + + +static int handle_intr_transfer_attn(char epid, int status) +{ + urb_t *old_urb; + + DBFENTER; + + old_urb = URB_List[epid]; + + /* if (status == 0 && IN) find data and copy to urb */ + if (status == 0 && usb_pipein(old_urb->pipe)) { + unsigned long flags; + etrax_urb_priv_t *urb_priv; + struct list_head *entry; + struct in_chunk *in; + + urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + + save_flags(flags); + cli(); + + list_for_each(entry, &urb_priv->ep_in_list) { + in = list_entry(entry, struct in_chunk, list); + memcpy(old_urb->transfer_buffer, in->data, in->length); + old_urb->actual_length = in->length; + old_urb->status = status; + + if (old_urb->complete) { + old_urb->complete(old_urb); + } + + list_del(entry); + kfree(in->data); + kfree(in); + } + + restore_flags(flags); + + } else if (status != 0) { + warn("Some sort of error for INTR EP !!!!"); +#ifdef ETRAX_USB_INTR_ERROR_FATAL + /* This means that an INTR error is fatal for that endpoint */ + etrax_usb_unlink_intr_urb(old_urb); + old_urb->status = status; + if (old_urb->complete) { + old_urb->complete(old_urb); + } +#else + /* In this case we reenable the disabled endpoint(s) */ + etrax_usb_do_intr_recover(epid); +#endif + } + + DBFEXIT; +} + +static int etrax_rh_unlink_urb (urb_t *urb) +{ + etrax_hc_t *hc; + + DBFENTER; + + hc = urb->dev->bus->hcpriv; + + if (hc->rh.urb == urb) { + hc->rh.send = 0; + del_timer(&hc->rh.rh_int_timer); + } + + DBFEXIT; + return 0; +} + +static void etrax_rh_send_irq(urb_t *urb) +{ + __u16 data = 0; + etrax_hc_t *hc = urb->dev->bus->hcpriv; +// static prev_wPortStatus_1 = 0; +// static prev_wPortStatus_2 = 0; + +/* DBFENTER; */ + + +/* + dbg_rh("R_USB_FM_NUMBER : 0x%08X", *R_USB_FM_NUMBER); + dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING); +*/ + + data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0; + data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0; + + *((__u16 *)urb->transfer_buffer) = cpu_to_le16(data); + urb->actual_length = 1; + urb->status = 0; + + + if (data && hc->rh.send && urb->complete) { + dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1); + dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2); + + urb->complete(urb); + } + +/* DBFEXIT; */ +} + +static void etrax_rh_init_int_timer(urb_t *urb) +{ + etrax_hc_t *hc; + +/* DBFENTER; */ + + hc = urb->dev->bus->hcpriv; + hc->rh.interval = urb->interval; + init_timer(&hc->rh.rh_int_timer); + hc->rh.rh_int_timer.function = etrax_rh_int_timer_do; + hc->rh.rh_int_timer.data = (unsigned long)urb; + hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000); + add_timer(&hc->rh.rh_int_timer); + +/* DBFEXIT; */ +} + +static void etrax_rh_int_timer_do(unsigned long ptr) +{ + urb_t *urb; + etrax_hc_t *hc; + +/* DBFENTER; */ + + urb = (urb_t*)ptr; + hc = urb->dev->bus->hcpriv; + + if (hc->rh.send) { + etrax_rh_send_irq(urb); + } + + etrax_rh_init_int_timer(urb); + +/* DBFEXIT; */ +} + +static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, char packsize, char slow) +{ + unsigned long flags; + + DBFENTER; + + save_flags(flags); + cli(); + + if (test_bit(epid, (void *)&ep_usage_bitmask)) { + warn("Trying to setup used epid %d", epid); + DBFEXIT; + return; + } + + set_bit(epid, (void *)&ep_usage_bitmask); + dbg_ep("Setting up ep_id %d with devnum %d, endpoint %d and max_len %d", + epid, devnum, endpoint, packsize); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) | + IO_FIELD(R_USB_EPT_DATA, ep, endpoint) | + IO_FIELD(R_USB_EPT_DATA, dev, devnum) | + IO_FIELD(R_USB_EPT_DATA, max_len, packsize) | + IO_FIELD(R_USB_EPT_DATA, low_speed, slow); + + restore_flags(flags); + + DBFEXIT; +} + +static void etrax_usb_free_epid(char epid) +{ + unsigned long flags; + + DBFENTER; + + if (!test_bit(epid, (void *)&ep_usage_bitmask)) { + warn("Trying to free unused epid %d", epid); + DBFEXIT; + return; + } + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold))printk("+"); + *R_USB_EPT_DATA = 0; + clear_bit(epid, (void *)&ep_usage_bitmask); + restore_flags(flags); + dbg_ep("epid: %d freed", epid); + + DBFEXIT; +} + + +static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp) +{ + int i; + unsigned long flags; + __u32 data; + + DBFENTER; + + save_flags(flags); + + /* Skip first ep_id since it is reserved when intr. or iso traffic is used */ + for (i = 0; i < NBR_OF_EP_DESC; i++) { + if (test_bit(i, (void *)&ep_usage_bitmask)) { + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i); + nop(); + data = *R_USB_EPT_DATA; + if ((IO_MASK(R_USB_EPT_DATA, valid) & data) && + (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) && + (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) && + (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) && + (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxp)) { + dbg_ep("Found ep_id %d for devnum %d, endpoint %d", + i, devnum, endpoint); + DBFEXIT; + return i; + } + } + } + + restore_flags(flags); + + dbg_ep("Found no ep_id for devnum %d, endpoint %d", + devnum, endpoint); + DBFEXIT; + return -1; +} + +static int etrax_usb_allocate_epid(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < NBR_OF_EP_DESC; i++) { + if (!test_bit(i, (void *)&ep_usage_bitmask)) { + dbg_ep("Found free ep_id at %d", i); + DBFEXIT; + return i; + } + } + + dbg_ep("Found no free ep_id's"); + DBFEXIT; + return -1; +} + +static int etrax_usb_submit_bulk_urb(urb_t *urb) +{ + char epid; + char devnum; + char endpoint; + char maxlen; + char slow; + + urb_t *tmp_urb; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + slow = usb_pipeslow(urb->pipe); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + epid = etrax_usb_allocate_epid(); + if (epid == -1) { + /* We're out of endpoints, return some error */ + err("We're out of endpoints"); + return -ENOMEM; + } + /* Now we have to fill in this ep */ + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + } + /* Ok, now we got valid endpoint, lets insert some traffic */ + + urb->status = -EINPROGRESS; + + save_flags(flags); + cli(); + + if (URB_List[epid]) { + /* Find end of list and add */ + for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) + dump_urb(tmp_urb); + + tmp_urb->next = urb; + restore_flags(flags); + } else { + /* If this is the first URB, add the URB and do HW add */ + URB_List[epid] = urb; + restore_flags(flags); + etrax_usb_do_bulk_hw_add(urb, epid, maxlen); + } + + DBFEXIT; + + return 0; +} + +static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen) +{ + USB_SB_Desc_t *sb_desc_1; + + etrax_urb_priv_t *urb_priv; + + unsigned long flags; + __u32 r_usb_ept_data; + + DBFENTER; + + urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); + sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + if (usb_pipeout(urb->pipe)) { + + dbg_bulk("Bulk transfer for epid %d is OUT", epid); + dbg_bulk("transfer_buffer_length == %d", urb->transfer_buffer_length); + dbg_bulk("actual_length == %d", urb->actual_length); + + if (urb->transfer_buffer_length > 0xffff) { + panic(__FILE__ __FUNCTION__ ":urb->transfer_buffer_length > 0xffff\n"); + } + + sb_desc_1->sw_len = urb->transfer_buffer_length; /* was actual_length */ + sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, out) | + +#if 0 + IO_STATE(USB_SB_command, full, no) | +#else + IO_STATE(USB_SB_command, full, yes) | +#endif + + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); + + sb_desc_1->buf = virt_to_phys(urb->transfer_buffer); + sb_desc_1->next = 0; + + } else if (usb_pipein(urb->pipe)) { + + dbg_bulk("Transfer for epid %d is IN", epid); + dbg_bulk("transfer_buffer_length = %d", urb->transfer_buffer_length); + dbg_bulk("rem is calculated to %d", urb->transfer_buffer_length % maxlen); + + sb_desc_1->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + dbg_bulk("sw_len got %d", sb_desc_1->sw_len); + dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); + + sb_desc_1->command = + IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + sb_desc_1->buf = 0; + sb_desc_1->next = 0; + + urb_priv->rx_offset = 0; + urb_priv->eot = 0; + } + + urb_priv->first_sb = sb_desc_1; + + urb->hcpriv = (void *)urb_priv; + + /* Reset toggle bits and reset error count, remeber to di and ei */ + /* Warning: it is possible that this locking doesn't work with bottom-halves */ + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { + panic("Hold was set in %s\n", __FUNCTION__); + } + + *R_USB_EPT_DATA &= + ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | + IO_MASK(R_USB_EPT_DATA, error_count_out)); + + if (usb_pipeout(urb->pipe)) { + char toggle = + usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out); + *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle); + } else { + char toggle = + usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in); + *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle); + } + + /* Enable the EP descr. */ + + set_bit(epid, (void *)&ep_really_active); + + TxBulkEPList[epid].sub = virt_to_phys(sb_desc_1); + TxBulkEPList[epid].hw_len = 0; + TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + + restore_flags(flags); + + if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) { + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); + + } + + DBFEXIT; +} + +static int handle_bulk_transfer_attn(char epid, int status) +{ + urb_t *old_urb; + etrax_urb_priv_t *hc_priv; + unsigned long flags; + + DBFENTER; + + clear_bit(epid, (void *)&ep_really_active); + + old_urb = URB_List[epid]; + URB_List[epid] = old_urb->next; + + /* if (status == 0 && IN) find data and copy to urb */ + if (status == 0 && usb_pipein(old_urb->pipe)) { + etrax_urb_priv_t *urb_priv; + + urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + save_flags(flags); + cli(); + if (urb_priv->eot == 1) { + old_urb->actual_length = urb_priv->rx_offset; + } else { + if (urb_priv->rx_offset == 0) { + status = 0; + } else { + status = -EPROTO; + } + + old_urb->actual_length = 0; + err("(BULK) No eot set in IN data!!! rx_offset is: %d", urb_priv->rx_offset); + } + + restore_flags(flags); + } + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + if (usb_pipeout(old_urb->pipe)) { + char toggle = + IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA); + usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), + usb_pipeout(old_urb->pipe), toggle); + } else { + char toggle = + IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA); + usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), + usb_pipeout(old_urb->pipe), toggle); + } + restore_flags(flags); + + /* If there are any more URB's in the list we'd better start sending */ + if (URB_List[epid]) { + etrax_usb_do_bulk_hw_add(URB_List[epid], epid, + usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, + usb_pipeout(URB_List[epid]->pipe))); + } +#if 1 + else { + /* This means that this EP is now free, deconfigure it */ + etrax_usb_free_epid(epid); + } +#endif + + /* Remember to free the SB's */ + hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + cleanup_sb(hc_priv->first_sb); + kfree(hc_priv); + + old_urb->status = status; + if (old_urb->complete) { + old_urb->complete(old_urb); + } + + DBFEXIT; +} + +/* ---------------------------------------------------------------------------- */ + +static int etrax_usb_submit_ctrl_urb(urb_t *urb) +{ + char epid; + char devnum; + char endpoint; + char maxlen; + char slow; + + urb_t *tmp_urb; + + etrax_urb_priv_t *urb_priv; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + slow = usb_pipeslow(urb->pipe); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + if (epid == -1) { + epid = etrax_usb_allocate_epid(); + if (epid == -1) { + /* We're out of endpoints, return some error */ + err("We're out of endpoints"); + return -ENOMEM; + } + /* Now we have to fill in this ep */ + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + } + /* Ok, now we got valid endpoint, lets insert some traffic */ + + urb->status = -EINPROGRESS; + + save_flags(flags); + cli(); + + if (URB_List[epid]) { + /* Find end of list and add */ + for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) + dump_urb(tmp_urb); + + tmp_urb->next = urb; + restore_flags(flags); + } else { + /* If this is the first URB, add the URB and do HW add */ + URB_List[epid] = urb; + restore_flags(flags); + etrax_usb_do_ctrl_hw_add(urb, epid, maxlen); + } + + DBFEXIT; + + return 0; +} + +static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen) +{ + USB_SB_Desc_t *sb_desc_1; + USB_SB_Desc_t *sb_desc_2; + USB_SB_Desc_t *sb_desc_3; + + etrax_urb_priv_t *urb_priv; + + unsigned long flags; + __u32 r_usb_ept_data; + + + DBFENTER; + + urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); + sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + if (!(sb_desc_1 && sb_desc_2)) { + panic("kmem_cache_alloc in ctrl_hw_add gave NULL pointers !!!\n"); + } + + sb_desc_1->sw_len = 8; + sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, setup) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes); + + sb_desc_1->buf = virt_to_phys(urb->setup_packet); + sb_desc_1->next = virt_to_phys(sb_desc_2); + dump_sb_desc(sb_desc_1); + + if (usb_pipeout(urb->pipe)) { + dbg_ctrl("Transfer for epid %d is OUT", epid); + + /* If this Control OUT transfer has an optional data stage we add an OUT token + before the mandatory IN (status) token, hence the reordered SB list */ + + if (urb->transfer_buffer) { + dbg_ctrl("This OUT transfer has an extra data stage"); + sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + sb_desc_1->next = virt_to_phys(sb_desc_3); + + sb_desc_3->sw_len = urb->transfer_buffer_length; + sb_desc_3->command = IO_STATE(USB_SB_command, tt, out) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes); + sb_desc_3->buf = virt_to_phys(urb->transfer_buffer); + sb_desc_3->next = virt_to_phys(sb_desc_2); + } + + sb_desc_2->sw_len = 1; + sb_desc_2->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + sb_desc_2->buf = 0; + sb_desc_2->next = 0; + dump_sb_desc(sb_desc_2); + + } else if (usb_pipein(urb->pipe)) { + + dbg_ctrl("Transfer for epid %d is IN", epid); + dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length); + dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen); + + sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); + + sb_desc_2->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + dbg_ctrl("sw_len got %d", sb_desc_2->sw_len); + + sb_desc_2->command = + IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes); + + sb_desc_2->buf = 0; + sb_desc_2->next = virt_to_phys(sb_desc_3); + dump_sb_desc(sb_desc_2); + + sb_desc_3->sw_len = 1; + sb_desc_3->command = IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes); + + sb_desc_3->buf = 0; + sb_desc_3->next = 0; + dump_sb_desc(sb_desc_3); + + urb_priv->rx_offset = 0; + urb_priv->eot = 0; + } + + urb_priv->first_sb = sb_desc_1; + + urb->hcpriv = (void *)urb_priv; + + /* Reset toggle bits and reset error count, remeber to di and ei */ + /* Warning: it is possible that this locking doesn't work with bottom-halves */ + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { + panic("Hold was set in %s\n", __FUNCTION__); + } + + + *R_USB_EPT_DATA &= + ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | + IO_MASK(R_USB_EPT_DATA, error_count_out) | + IO_MASK(R_USB_EPT_DATA, t_in) | + IO_MASK(R_USB_EPT_DATA, t_out)); + + /* Enable the EP descr. */ + + set_bit(epid, (void *)&ep_really_active); + + TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_1); + TxCtrlEPList[epid].hw_len = 0; + TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + restore_flags(flags); + + dump_ep_desc(&TxCtrlEPList[epid]); + + if (!(*R_DMA_CH8_SUB1_CMD & IO_MASK(R_DMA_CH8_SUB1_CMD, cmd))) { + *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); + + } + + DBFEXIT; +} + +static int etrax_usb_submit_urb(urb_t *urb) +{ + etrax_hc_t *hc; + int rval = -EINVAL; + + DBFENTER; + + dump_urb(urb); + submit_urb_count++; + + hc = (etrax_hc_t*) urb->dev->bus->hcpriv; + + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { + /* This request if for the Virtual Root Hub */ + rval = etrax_rh_submit_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + rval = etrax_usb_submit_ctrl_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { + rval = etrax_usb_submit_bulk_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + int bustime; + + if (urb->bandwidth == 0) { + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) { + rval = bustime; + } else { + usb_claim_bandwidth(urb->dev, urb, bustime, 0); + rval = etrax_usb_submit_intr_urb(urb); + } + + } + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + warn("Isochronous traffic is not supported !!!"); + rval = -EINVAL; + } + + DBFEXIT; + + return rval; +} + +static int etrax_usb_unlink_urb(urb_t *urb) +{ + etrax_hc_t *hc = urb->dev->bus->hcpriv; + int epid; + int pos; + int devnum, endpoint, slow, maxlen; + etrax_urb_priv_t *hc_priv; + unsigned long flags; + + DBFENTER; + dump_urb(urb); + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + slow = usb_pipeslow(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + + if (epid == -1) + return 0; + + + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { + int ret; + ret = etrax_rh_unlink_urb(urb); + DBFEXIT; + return ret; + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + int ret; + ret = etrax_usb_unlink_intr_urb(urb); + urb->status = -ENOENT; + if (urb->complete) { + urb->complete(urb); + } + DBFEXIT; + return ret; + } + + info("Unlink of BULK or CTRL"); + + save_flags(flags); + cli(); + + for (epid = 0; epid < 32; epid++) { + urb_t *u = URB_List[epid]; + pos = 0; + + for (; u; u = u->next) { + pos++; + if (u == urb) { + info("Found urb at epid %d, pos %d", epid, pos); + + if (pos == 1) { + if (usb_pipetype(u->pipe) == PIPE_CONTROL) { + if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + /* The EP was enabled, disable it and wait */ + TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid])); + } + + } else if (usb_pipetype(u->pipe) == PIPE_BULK) { + if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid])); + } + } + + URB_List[epid] = u->next; + + } else { + urb_t *up; + for (up = URB_List[epid]; up->next != u; up = up->next); + up->next = u->next; + } + u->status = -ENOENT; + if (u->complete) { + u->complete(u); + } + + hc_priv = (etrax_urb_priv_t *)u->hcpriv; + cleanup_sb(hc_priv->first_sb); + kfree(hc_priv); + } + } + } + + restore_flags(flags); + + DBFEXIT; + return 0; +} + +static int etrax_usb_get_frame_number(struct usb_device *usb_dev) +{ + DBFENTER; + DBFEXIT; + return (*R_USB_FM_NUMBER); +} + +static int etrax_usb_allocate_dev(struct usb_device *usb_dev) +{ + DBFENTER; + DBFEXIT; + return 0; +} + +static int etrax_usb_deallocate_dev(struct usb_device *usb_dev) +{ + DBFENTER; + DBFEXIT; + return 0; +} + +static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs) +{ + etrax_hc_t *hc = (etrax_hc_t *)vhc; + int epid; + char eol; + urb_t *urb; + USB_EP_Desc_t *tmp_ep; + USB_SB_Desc_t *tmp_sb; + + DBFENTER; + + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) { + info("dma8_sub0_descr (BULK) intr."); + *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) { + info("dma8_sub1_descr (CTRL) intr."); + *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) { + info("dma8_sub2_descr (INT) intr."); + *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) { + info("dma8_sub3_descr (ISO) intr."); + *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); + } + + DBFEXIT; +} + +static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs) +{ + int epid = 0; + urb_t *urb; + etrax_urb_priv_t *urb_priv; + + *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do); + + while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) { + if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { + + goto skip_out; + } + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) { + + goto skip_out; + } + + epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status); + + urb = URB_List[epid]; + + if (urb && usb_pipein(urb->pipe)) { + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + + if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + struct in_chunk *in; + dbg_intr("Packet for epid %d in rx buffers", epid); + in = kmalloc(sizeof(struct in_chunk), GFP_ATOMIC); + in->length = myNextRxDesc->hw_len; + in->data = kmalloc(in->length, GFP_ATOMIC); + memcpy(in->data, phys_to_virt(myNextRxDesc->buf), in->length); + list_add_tail(&in->list, &urb_priv->ep_in_list); +#ifndef ETRAX_USB_INTR_IRQ + etrax_usb_hc_intr_top_half(irq, vhc, regs); +#endif + + } else { + if ((urb_priv->rx_offset + myNextRxDesc->hw_len) > + urb->transfer_buffer_length) { + err("Packet (epid: %d) in RX buffer was bigger " + "than the URB has room for !!!", epid); + goto skip_out; + } + + memcpy(urb->transfer_buffer + urb_priv->rx_offset, + phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len); + + urb_priv->rx_offset += myNextRxDesc->hw_len; + } + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) { + urb_priv->eot = 1; + } + + } else { + err("This is almost fatal, inpacket for epid %d which does not exist " + " or is out !!!\nURB was at 0x%08X", epid, urb); + + goto skip_out; + } + + skip_out: + myPrevRxDesc = myNextRxDesc; + myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol); + myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol); + myLastRxDesc = myPrevRxDesc; + + myNextRxDesc->status = 0; + myNextRxDesc = phys_to_virt(myNextRxDesc->next); + } +} + + + +static void cleanup_sb(USB_SB_Desc_t *sb) +{ + USB_SB_Desc_t *next_sb; + + DBFENTER; + + if (sb == NULL) { + err("cleanup_sb was given a NULL pointer"); + return; + } + + while (!(sb->command & IO_MASK(USB_SB_command, eol))) { + next_sb = (USB_SB_Desc_t *)phys_to_virt(sb->next); + kmem_cache_free(usb_desc_cache, sb); + sb = next_sb; + } + + kmem_cache_free(usb_desc_cache, sb); + + DBFEXIT; + +} + +static int handle_control_transfer_attn(char epid, int status) +{ + urb_t *old_urb; + etrax_urb_priv_t *hc_priv; + + DBFENTER; + + clear_bit(epid, (void *)&ep_really_active); + + old_urb = URB_List[epid]; + URB_List[epid] = old_urb->next; + + /* if (status == 0 && IN) find data and copy to urb */ + if (status == 0 && usb_pipein(old_urb->pipe)) { + unsigned long flags; + etrax_urb_priv_t *urb_priv; + + urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + save_flags(flags); + cli(); + if (urb_priv->eot == 1) { + old_urb->actual_length = urb_priv->rx_offset; + dbg_ctrl("urb_priv->rx_offset: %d in handle_control_attn", urb_priv->rx_offset); + } else { + status = -EPROTO; + old_urb->actual_length = 0; + err("(CTRL) No eot set in IN data!!! rx_offset: %d", urb_priv->rx_offset); + } + + restore_flags(flags); + } + + /* If there are any more URB's in the list we'd better start sending */ + if (URB_List[epid]) { + etrax_usb_do_ctrl_hw_add(URB_List[epid], epid, + usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, + usb_pipeout(URB_List[epid]->pipe))); + } +#if 1 + else { + /* This means that this EP is now free, deconfigure it */ + etrax_usb_free_epid(epid); + } +#endif + + /* Remember to free the SB's */ + hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; + cleanup_sb(hc_priv->first_sb); + kfree(hc_priv); + + old_urb->status = status; + if (old_urb->complete) { + old_urb->complete(old_urb); + } + + DBFEXIT; +} + + + +static void etrax_usb_hc_intr_bottom_half(void *data) +{ + struct usb_reg_context *reg = (struct usb_reg_context *)data; + urb_t *old_urb; + + int error_code; + int epid; + + __u32 r_usb_ept_data; + + etrax_hc_t *hc = reg->hc; + __u16 r_usb_rh_port_status_1; + __u16 r_usb_rh_port_status_2; + + DBFENTER; + + if (reg->r_usb_irq_mask_read & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) { + + /* + The Etrax RH does not include a wPortChange register, so this has + to be handled in software. See section 11.16.2.6.2 in USB 1.1 spec + for details. + */ + + r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1; + r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2; + + dbg_rh("port_status pending"); + dbg_rh("r_usb_rh_port_status_1: 0x%04X", r_usb_rh_port_status_1); + dbg_rh("r_usb_rh_port_status_2: 0x%04X", r_usb_rh_port_status_2); + + /* C_PORT_CONNECTION is set on any transition */ + hc->rh.wPortChange_1 |= + ((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) != + (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ? + (1 << RH_PORT_CONNECTION) : 0; + + hc->rh.wPortChange_2 |= + ((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) != + (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ? + (1 << RH_PORT_CONNECTION) : 0; + + /* C_PORT_ENABLE is _only_ set on a one to zero transition */ + hc->rh.wPortChange_1 |= + ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE)) + && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_ENABLE) : 0; + + hc->rh.wPortChange_2 |= + ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE)) + && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_ENABLE) : 0; + + /* C_PORT_SUSPEND seems difficult, lets ignore it.. (for now) */ + + /* C_PORT_RESET is _only_ set on a transition from the resetting state + to the enabled state */ + hc->rh.wPortChange_1 |= + ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET)) + && (r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_RESET) : 0; + + hc->rh.wPortChange_2 |= + ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET)) + && (r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_RESET) : 0; + + hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1; + hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2; + } + + for (epid = 0; epid < 32; epid++) { + + unsigned long flags; + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); + r_usb_ept_data = *R_USB_EPT_DATA; + restore_flags(flags); + + if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) { + warn("Was hold for epid %d", epid); + continue; + } + + if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) { + continue; + } + + + if (test_bit(epid, (void *)®->r_usb_epid_attn)) { + + if (URB_List[epid] == NULL) { + err("R_USB_EPT_DATA is 0x%08X", r_usb_ept_data); + err("submit urb has been called %d times..", submit_urb_count); + err("EPID_ATTN for epid %d, with NULL entry in list", epid); + return; + } + + dbg_ep("r_usb_ept_data [%d] == 0x%08X", epid, + r_usb_ept_data); + + error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, + r_usb_ept_data); + + if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + /* no_error means that this urb was sucessfully sent or that we have + some undefinde error*/ + + if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 || + IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3) { + /* Actually there were transmission errors */ + warn("Undefined error for endpoint %d", epid); + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + handle_control_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + handle_bulk_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, -EPROTO); + } + + } else { + + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + etrax_usb_do_intr_recover(epid); + } else { + panic("Epid attention for epid %d (none INTR), with no errors and no " + "exessive retry r_usb_status is 0x%02X\n", + epid, reg->r_usb_status); + } + + } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { + panic("Epid attention for epid %d, with no errors and no " + "exessive retry r_usb_status is 0x%02X\n", + epid, reg->r_usb_status); + + } + + warn("Epid attention for epid %d, with no errors and no " + "exessive retry r_usb_status is 0x%02X", + epid, reg->r_usb_status); + warn("OUT error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_out, + r_usb_ept_data)); + warn("IN error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_in, + r_usb_ept_data)); + + + } + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) { + warn("Stall for endpoint %d", epid); + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + handle_control_transfer_attn(epid, -EPIPE); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + handle_bulk_transfer_attn(epid, -EPIPE); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, -EPIPE); + } + + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) { + panic("USB bus error for endpoint %d\n", epid); + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) { + warn("Buffer error for endpoint %d", epid); + + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + handle_control_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + handle_bulk_transfer_attn(epid, -EPROTO); + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, -EPROTO); + } + + } + } else if (test_bit(epid, (void *)&ep_really_active)) { + /* Should really be else if (testbit(really active)) */ + + if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { + + if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))) { + /* Now we have to verify that this CTRL endpoint got disabled + cause it reached end of list with no error */ + + if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == + IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + /* + This means that the endpoint has no error, is disabled + and had inserted traffic, + i.e. transfer sucessfully completed + */ + dbg_ctrl("Last SB for CTRL %d sent sucessfully", epid); + handle_control_transfer_attn(epid, 0); + } + } + + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { + if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))) { + /* Now we have to verify that this BULK endpoint go disabled + cause it reached end of list with no error */ + + if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == + IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + /* + This means that the endpoint has no error, is disabled + and had inserted traffic, + i.e. transfer sucessfully completed + */ + dbg_bulk("Last SB for BULK %d sent sucessfully", epid); + handle_bulk_transfer_attn(epid, 0); + } + } + } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { + handle_intr_transfer_attn(epid, 0); + } + } + + } + + kfree(reg); + + DBFEXIT; +} + + +static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs) +{ + struct usb_reg_context *reg; + + DBFENTER; + + reg = (struct usb_reg_context *)kmalloc(sizeof(struct usb_reg_context), GFP_ATOMIC); + + if (!(reg)) { + panic("kmalloc failed in top_half\n"); + } + + reg->hc = (etrax_hc_t *)vhc; + reg->r_usb_irq_mask_read = *R_USB_IRQ_MASK_READ; + reg->r_usb_status = *R_USB_STATUS; + +#if 0 + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { + panic("r_usb_status said perror\n"); + } + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { + panic("r_usb_status said ourun !!!\n"); + } +#endif + + reg->r_usb_epid_attn = *R_USB_EPID_ATTN; + + reg->r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1; + reg->r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2; + + reg->usb_bh.sync = 0; + reg->usb_bh.routine = etrax_usb_hc_intr_bottom_half; + reg->usb_bh.data = reg; + + queue_task(®->usb_bh, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + DBFEXIT; +} + +static int etrax_rh_submit_urb(urb_t *urb) +{ + struct usb_device *usb_dev = urb->dev; + etrax_hc_t *hc = usb_dev->bus->hcpriv; + unsigned int pipe = urb->pipe; + devrequest *cmd = (devrequest *) urb->setup_packet; + void *data = urb->transfer_buffer; + int leni = urb->transfer_buffer_length; + int len = 0; + int status = 0; + int stat = 0; + int i; + + __u16 cstatus; + + __u16 bmRType_bReq; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + + DBFENTER; + + if (usb_pipetype (pipe) == PIPE_INTERRUPT) { + dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval); + hc->rh.urb = urb; + hc->rh.send = 1; + hc->rh.interval = urb->interval; + etrax_rh_init_int_timer(urb); + DBFEXIT; + + return 0; + } + + bmRType_bReq = cmd->requesttype | cmd->request << 8; + wValue = le16_to_cpu(cmd->value); + wIndex = le16_to_cpu(cmd->index); + wLength = le16_to_cpu(cmd->length); + + dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq); + dbg_rh("wValue : 0x%04X (%d)", wValue, wValue); + dbg_rh("wIndex : 0x%04X (%d)", wIndex, wIndex); + dbg_rh("wLength : 0x%04X (%d)", wLength, wLength); + + switch (bmRType_bReq) { + + /* Request Destination: + without flags: Device, + RH_INTERFACE: interface, + RH_ENDPOINT: endpoint, + RH_CLASS means HUB here, + RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ + + case RH_GET_STATUS: + *(__u16 *) data = cpu_to_le16 (1); + OK (2); + + case RH_GET_STATUS | RH_INTERFACE: + *(__u16 *) data = cpu_to_le16 (0); + OK (2); + + case RH_GET_STATUS | RH_ENDPOINT: + *(__u16 *) data = cpu_to_le16 (0); + OK (2); + + case RH_GET_STATUS | RH_CLASS: + *(__u32 *) data = cpu_to_le32 (0); + OK (4); /* hub power ** */ + + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + if (wIndex == 1) { + *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1); + *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1); + } + else if (wIndex == 2) { + *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2); + *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2); + } + else { + dbg_rh("RH_GET_STATUS whith invalid wIndex !!"); + OK(0); + } + + OK(4); + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + switch (wValue) { + case (RH_ENDPOINT_STALL): + OK (0); + } + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + switch (wValue) { + case (RH_C_HUB_OVER_CURRENT): + OK (0); /* hub power over current ** */ + } + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_ENABLE): + if (wIndex == 1) { + + dbg_rh("trying to do disable of port 1"); + + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes); + while (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)); + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); + dbg_rh("Port 1 is disabled"); + + } else if (wIndex == 2) { + + dbg_rh("trying to do disable of port 2"); + + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes); + while (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes)); + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); + dbg_rh("Port 2 is disabled"); + + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_PORT_SUSPEND): + /* Opposite to suspend should be resume, so well do a resume */ + if (wIndex == 1) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, resume)| + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else if (wIndex == 2) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port2) | + IO_STATE(R_USB_COMMAND, port_cmd, resume)| + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_PORT_POWER): + OK (0); /* port power ** */ + case (RH_C_PORT_CONNECTION): + + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION); + } + else if (wIndex == 2) { + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION); + } + else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_C_PORT_ENABLE): + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE); + } + else if (wIndex == 2) { + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE); + } + else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE " + "with invalid wIndex == %d!!", wIndex); + } + OK (0); + case (RH_C_PORT_SUSPEND): +/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ + OK (0); + case (RH_C_PORT_OVER_CURRENT): + OK (0); /* port power over current ** */ + case (RH_C_PORT_RESET): + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET); + } + else if (wIndex == 2) { + dbg_rh("This is wPortChange before clear: 0x%04X", hc->rh.wPortChange_2); + + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET); + dbg_rh("This is wPortChange after clear: 0x%04X", hc->rh.wPortChange_2); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET " + "with invalid index == %d!!", wIndex); + } + + OK (0); + + } + break; + + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_SUSPEND): + if (wIndex == 1) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, suspend) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else if (wIndex == 2) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port2) | + IO_STATE(R_USB_COMMAND, port_cmd, suspend) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else { + dbg_rh("RH_SET_FEATURE->RH_C_PORT_SUSPEND " + "with invalid wIndex == %d!!", wIndex); + } + + OK (0); + case (RH_PORT_RESET): + if (wIndex == 1) { + int port1_retry; + + port1_redo: + dbg_rh("Doing reset of port 1"); + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, port_sel, port1); + + /* We must once again wait at least 10ms for the device to recover */ + + port1_retry = 0; + while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_1)) & + IO_STATE(R_USB_RH_PORT_STATUS_1, + enabled, yes))) { + printk(""); if (port1_retry++ >= 10000) {goto port1_redo;} + } + + /* This only seems to work if we use printk, + not even schedule() works !!! WHY ?? */ + + udelay(15000); + } + else if (wIndex == 2) { + int port2_retry; + + port2_redo: + dbg_rh("Doing reset of port 2"); + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, port_sel, port2); + + /* We must once again wait at least 10ms for the device to recover */ + + port2_retry = 0; + while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_2)) & + IO_STATE(R_USB_RH_PORT_STATUS_2, + enabled, yes))) { + printk(""); if (port2_retry++ >= 10000) {goto port2_redo;} + } + + /* This only seems to work if we use printk, + not even schedule() works !!! WHY ?? */ + + udelay(15000); + } + + /* Try to bring the HC into running state */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + dbg_rh("...Done"); + OK(0); + + case (RH_PORT_POWER): + OK (0); /* port power ** */ + case (RH_PORT_ENABLE): + /* There is no rh port enable command in the Etrax USB interface!!!! */ + OK (0); + + } + break; + + case RH_SET_ADDRESS: + hc->rh.devnum = wValue; + dbg_rh("RH address set to: %d", hc->rh.devnum); + OK (0); + + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case (0x01): /* device descriptor */ + len = min (leni, min (sizeof (root_hub_dev_des), wLength)); + memcpy (data, root_hub_dev_des, len); + OK (len); + case (0x02): /* configuration descriptor */ + len = min (leni, min (sizeof (root_hub_config_des), wLength)); + memcpy (data, root_hub_config_des, len); + OK (len); + case (0x03): /* string descriptors */ + len = usb_root_hub_string (wValue & 0xff, + 0xff, "ETRAX 100LX", + data, wLength); + if (len > 0) { + OK (min (leni, len)); + } else + stat = -EPIPE; + } + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + root_hub_hub_des[2] = hc->rh.numports; + len = min (leni, min (sizeof (root_hub_hub_des), wLength)); + memcpy (data, root_hub_hub_des, len); + OK (len); + + case RH_GET_CONFIGURATION: + *(__u8 *) data = 0x01; + OK (1); + + case RH_SET_CONFIGURATION: + OK (0); + + default: + stat = -EPIPE; + } + + urb->actual_length = len; + urb->status = stat; + urb->dev=NULL; + if (urb->complete) { + urb->complete (urb); + } + DBFEXIT; + + return 0; +} + +static int __init etrax_usb_hc_init(void) +{ + static etrax_hc_t *hc; + struct usb_bus *bus; + struct usb_device *usb_rh; + + DBFENTER; + + info("ETRAX 100LX USB-HCD %s (c) 2001 Axis Communications AB\n", usb_hcd_version); + + hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL); + + /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */ + usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0, 0, 0, 0); + if (!usb_desc_cache) { + panic("USB Desc Cache allocation failed !!!\n"); + } + + etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations); + hc->bus = bus; + bus->hcpriv = hc; + + /* Initalize RH to the default address. + And make sure that we have no status change indication */ + hc->rh.numports = 2; /* The RH has two ports */ + hc->rh.devnum = 0; + hc->rh.wPortChange_1 = 0; + hc->rh.wPortChange_2 = 0; + + /* Also initate the previous values to zero */ + hc->rh.prev_wPortStatus_1 = 0; + hc->rh.prev_wPortStatus_2 = 0; + + /* Initialize the intr-traffic flags */ + hc->intr.sleeping = 0; + hc->intr.wq = NULL; + + /* Initially all ep's are free except ep 0 */ + ep_usage_bitmask = 0; + set_bit(0, (void *)&ep_usage_bitmask); + ep_really_active = 0; + + memset(URB_List, 0, sizeof(URB_List)); + + /* This code should really be moved */ + + if (request_dma(8, "ETRAX 100LX built-in USB (Tx)")) { + err("Could not allocate DMA ch 8 for USB"); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_dma(9, "ETRAX 100LX built-in USB (Rx)")) { + err("Could not allocate DMA ch 9 for USB"); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } +#if 0 /* Moved to head.S */ + *R_GEN_CONFIG = genconfig_shadow = + (genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) | + IO_MASK(R_GEN_CONFIG, usb2) | + IO_MASK(R_GEN_CONFIG, dma8) | + IO_MASK(R_GEN_CONFIG, dma9))) | + IO_STATE(R_GEN_CONFIG, dma8, usb) | + IO_STATE(R_GEN_CONFIG, dma9, usb) +#ifdef CONFIG_ETRAX_USB_HOST_PORT1 + | IO_STATE(R_GEN_CONFIG, usb1, select) +#endif +#ifdef CONFIG_ETRAX_USB_HOST_PORT2 + | IO_STATE(R_GEN_CONFIG, usb2, select) +#endif + ; +#endif + + usb_register_bus(hc->bus); + + /* We may have to set more bits, but these are the obvious ones */ + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set); + + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); + + *R_USB_IRQ_MASK_SET = + IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set) | + IO_STATE(R_USB_IRQ_MASK_SET, ctl_eot, set) | + IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) | +#ifdef ETRAX_USB_INTR_IRQ + IO_STATE(R_USB_IRQ_MASK_SET, intr_eot, set) | +#endif + IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) | + IO_STATE(R_USB_IRQ_MASK_SET, port_status, set); + + if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_intr_top_half, 0, + "ETRAX 100LX built-in USB (HC)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0, + "ETRAX 100LX built-in USB (Rx)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0, + "ETRAX 100LX built-in USB (Tx)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + /* Reset the USB interface (configures as HC) */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, reset) | + IO_STATE(R_USB_COMMAND, port_cmd, reset); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); +#if 1 + /* Initate PSTART to all unallocatable bit times */ + *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 10000); +#endif + +#ifdef CONFIG_ETRAX_USB_HOST_PORT1 + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); +#endif + +#ifdef CONFIG_ETRAX_USB_HOST_PORT2 + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); +#endif + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config) | + IO_STATE(R_USB_COMMAND, port_cmd, reset); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, reset); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + /* Here we must wait at least 10ms so the device has time to recover */ + udelay(15000); + + init_rx_buffers(); + init_tx_bulk_ep(); + init_tx_ctrl_ep(); + init_tx_intr_ep(); + + /* This works. It seems like the host_run command only has effect when a device is connected, + i.e. it has to be done when a interrup */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); + + nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + usb_rh = usb_alloc_dev(NULL, hc->bus); + hc->bus->root_hub = usb_rh; + usb_connect(usb_rh); + usb_new_device(usb_rh); + + DBFEXIT; + + return 0; +} + +static void etrax_usb_hc_cleanup(void) +{ + DBFENTER; + + free_irq(ETRAX_USB_HC_IRQ, NULL); + free_irq(ETRAX_USB_RX_IRQ, NULL); + free_irq(ETRAX_USB_TX_IRQ, NULL); + + free_dma(8); + free_dma(9); + usb_deregister_bus(etrax_usb_bus); + + DBFEXIT; +} + +module_init(etrax_usb_hc_init); +module_exit(etrax_usb_hc_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/drivers/usb-host.h linux.ac/arch/cris/drivers/usb-host.h --- linux.vanilla/arch/cris/drivers/usb-host.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/drivers/usb-host.h Tue Apr 10 18:05:08 2001 @@ -0,0 +1,245 @@ +#ifndef __LINUX_ETRAX_USB_H +#define __LINUX_ETRAX_USB_H + +#include +#include + +typedef struct USB_IN_Desc { + __u16 sw_len; + __u16 command; + unsigned long next; + unsigned long buf; + __u16 hw_len; + __u16 status; +} USB_IN_Desc_t; + +typedef struct USB_SB_Desc { + __u16 sw_len; + __u16 command; + unsigned long next; + unsigned long buf; + __u32 dummy; +} USB_SB_Desc_t; + +typedef struct USB_EP_Desc { + __u16 hw_len; + __u16 command; + unsigned long sub; + unsigned long nep; + __u32 dummy; +} USB_EP_Desc_t; + +struct virt_root_hub { + int devnum; + void *urb; + void *int_addr; + int send; + int interval; + int numports; + struct timer_list rh_int_timer; + __u16 wPortChange_1; + __u16 wPortChange_2; + __u16 prev_wPortStatus_1; + __u16 prev_wPortStatus_2; +}; + +struct etrax_usb_intr_traffic { + int sleeping; + int error; + struct wait_queue *wq; +}; + +typedef struct etrax_usb_hc { + struct usb_bus *bus; + struct virt_root_hub rh; + struct etrax_usb_intr_traffic intr; +} etrax_hc_t; + +typedef enum {idle, eot, nodata} etrax_usb_rx_state_t; + +typedef struct etrax_usb_urb_priv { + USB_SB_Desc_t *first_sb; + __u32 rx_offset; + etrax_usb_rx_state_t rx_state; + __u8 eot; + struct list_head ep_in_list; +} etrax_urb_priv_t; + + +struct usb_reg_context +{ + etrax_hc_t *hc; + __u32 r_usb_epid_attn; + __u8 r_usb_status; + __u32 r_usb_rh_port_status_1; + __u32 r_usb_rh_port_status_2; + __u32 r_usb_irq_mask_read; + struct tq_struct usb_bh; +#if 0 + __u32 r_usb_ept_data[32]; +#endif +}; + +struct in_chunk +{ + void *data; + int length; + char epid; + struct list_head list; +}; + + +/* --------------------------------------------------------------------------- + Virtual Root HUB + ------------------------------------------------------------------------- */ +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +/* Our Vendor Specific feature */ +#define RH_REMOVE_EP 0x00 + + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + +#define min(a,b) (((a)<(b))?(a):(b)) + +/* Field definitions for */ + +#define USB_IN_command__eol__BITNR 0 /* command macros */ +#define USB_IN_command__eol__WIDTH 1 +#define USB_IN_command__eol__no 0 +#define USB_IN_command__eol__yes 1 + +#define USB_IN_command__intr__BITNR 3 +#define USB_IN_command__intr__WIDTH 1 +#define USB_IN_command__intr__no 0 +#define USB_IN_command__intr__yes 1 + +#define USB_IN_status__eop__BITNR 1 /* status macros. */ +#define USB_IN_status__eop__WIDTH 1 +#define USB_IN_status__eop__no 0 +#define USB_IN_status__eop__yes 1 + +#define USB_IN_status__eot__BITNR 5 +#define USB_IN_status__eot__WIDTH 1 +#define USB_IN_status__eot__no 0 +#define USB_IN_status__eot__yes 1 + +#define USB_IN_status__error__BITNR 6 +#define USB_IN_status__error__WIDTH 1 +#define USB_IN_status__error__no 0 +#define USB_IN_status__error__yes 1 + +#define USB_IN_status__nodata__BITNR 7 +#define USB_IN_status__nodata__WIDTH 1 +#define USB_IN_status__nodata__no 0 +#define USB_IN_status__nodata__yes 1 + +#define USB_IN_status__epid__BITNR 8 +#define USB_IN_status__epid__WIDTH 5 + +#define USB_EP_command__eol__BITNR 0 +#define USB_EP_command__eol__WIDTH 1 +#define USB_EP_command__eol__no 0 +#define USB_EP_command__eol__yes 1 + +#define USB_EP_command__eof__BITNR 1 +#define USB_EP_command__eof__WIDTH 1 +#define USB_EP_command__eof__no 0 +#define USB_EP_command__eof__yes 1 + +#define USB_EP_command__intr__BITNR 3 +#define USB_EP_command__intr__WIDTH 1 +#define USB_EP_command__intr__no 0 +#define USB_EP_command__intr__yes 1 + +#define USB_EP_command__enable__BITNR 4 +#define USB_EP_command__enable__WIDTH 1 +#define USB_EP_command__enable__no 0 +#define USB_EP_command__enable__yes 1 + +#define USB_EP_command__hw_valid__BITNR 5 +#define USB_EP_command__hw_valid__WIDTH 1 +#define USB_EP_command__hw_valid__no 0 +#define USB_EP_command__hw_valid__yes 1 + +#define USB_EP_command__epid__BITNR 8 +#define USB_EP_command__epid__WIDTH 5 + +#define USB_SB_command__eol__BITNR 0 /* command macros. */ +#define USB_SB_command__eol__WIDTH 1 +#define USB_SB_command__eol__no 0 +#define USB_SB_command__eol__yes 1 + +#define USB_SB_command__eot__BITNR 1 +#define USB_SB_command__eot__WIDTH 1 +#define USB_SB_command__eot__no 0 +#define USB_SB_command__eot__yes 1 + +#define USB_SB_command__intr__BITNR 3 +#define USB_SB_command__intr__WIDTH 1 +#define USB_SB_command__intr__no 0 +#define USB_SB_command__intr__yes 1 + +#define USB_SB_command__tt__BITNR 4 +#define USB_SB_command__tt__WIDTH 2 +#define USB_SB_command__tt__zout 0 +#define USB_SB_command__tt__in 1 +#define USB_SB_command__tt__out 2 +#define USB_SB_command__tt__setup 3 + + +#define USB_SB_command__rem__BITNR 8 +#define USB_SB_command__rem__WIDTH 6 + +#define USB_SB_command__full__BITNR 6 +#define USB_SB_command__full__WIDTH 1 +#define USB_SB_command__full__no 0 +#define USB_SB_command__full__yes 1 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/Makefile linux.ac/arch/cris/kernel/Makefile --- linux.vanilla/arch/cris/kernel/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/Makefile Thu Apr 19 14:13:36 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 2001/01/10 21:11:07 bjornw Exp $ +# $Id: Makefile,v 1.4 2001/04/17 13:58:39 orjanf Exp $ # # Makefile for the linux kernel. # @@ -18,7 +18,7 @@ ptrace.o setup.o time.o sys_cris.o shadows.o \ debugport.o semaphore.o -obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_ETRAX_KGDB) += kgdb.o clean: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/debugport.c linux.ac/arch/cris/kernel/debugport.c --- linux.vanilla/arch/cris/kernel/debugport.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/debugport.c Thu Apr 19 14:13:36 2001 @@ -12,6 +12,12 @@ * init_etrax_debug() * * $Log: debugport.c,v $ + * Revision 1.6 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.5 2001/03/26 14:22:05 bjornw + * Namechange of some config options + * * Revision 1.4 2000/10/06 12:37:26 bjornw * Use physical addresses when talking to DMA * @@ -29,7 +35,7 @@ /* Which serial-port is our debug port ? */ -#if defined(CONFIG_DEBUG_PORT0) || defined(CONFIG_DEBUG_PORT_NULL) +#if defined(CONFIG_ETRAX_DEBUG_PORT0) || defined(CONFIG_ETRAX_DEBUG_PORT_NULL) #define DEBUG_PORT_IDX 0 #define DEBUG_OCMD R_DMA_CH6_CMD #define DEBUG_FIRST R_DMA_CH6_FIRST @@ -43,7 +49,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma6_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 #define DEBUG_PORT_IDX 1 #define DEBUG_OCMD R_DMA_CH8_CMD #define DEBUG_FIRST R_DMA_CH8_FIRST @@ -57,7 +63,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma8_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 #define DEBUG_PORT_IDX 2 #define DEBUG_OCMD R_DMA_CH2_CMD #define DEBUG_FIRST R_DMA_CH2_FIRST @@ -71,7 +77,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma2_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 #define DEBUG_PORT_IDX 3 #define DEBUG_OCMD R_DMA_CH4_CMD #define DEBUG_FIRST R_DMA_CH4_FIRST @@ -97,7 +103,7 @@ unsigned long flags; int in_progress; -#ifdef CONFIG_DEBUG_PORT_NULL +#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL /* no debug printout at all */ return; #endif @@ -111,7 +117,7 @@ save_flags(flags); cli(); -#ifdef CONFIG_KGDB +#ifdef CONFIG_ETRAX_KGDB /* kgdb needs to output debug info using the gdb protocol */ putDebugString(buf, len); restore_flags(flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/entry.S linux.ac/arch/cris/kernel/entry.S --- linux.vanilla/arch/cris/kernel/entry.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/kernel/entry.S Thu Apr 19 14:13:36 2001 @@ -1,12 +1,64 @@ -/* $Id: entry.S,v 1.11 2001/01/10 21:13:29 bjornw Exp $ +/* $Id: entry.S,v 1.22 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/entry.S * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.22 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.21 2001/04/17 11:33:29 orjanf + * Updated according to review: + * * Included asm/sv_addr_ag.h to get macro for internal register. + * * Corrected comment regarding system call argument passing. + * * Removed comment about instruction being in a delay slot. + * * Added comment about SYMBOL_NAME macro. + * + * Revision 1.20 2001/04/12 08:51:07 hp + * - Add entry for sys_fcntl64. In fact copy last piece from i386 including ... + * - .rept to fill table to safe state with sys_ni_syscall. + * + * Revision 1.19 2001/04/04 09:43:32 orjanf + * * Moved do_sigtrap from traps.c to entry.S. + * * LTASK_PID need not be global anymore. + * + * Revision 1.18 2001/03/26 09:25:02 markusl + * Updated after review, should now handle USB interrupts correctly. + * + * Revision 1.17 2001/03/21 16:12:55 bjornw + * * Always make room for the cpu status record in the frame, in order to + * use the same framelength and layout for both mmu busfaults and normal + * irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore. + * * Fixed bug with using addq for popping the stack in the epilogue - it + * destroyed the flag register. Use instructions that don't affect the + * flag register instead. + * * Removed write to R_PORT_PA_DATA during spurious_interrupt + * + * Revision 1.16 2001/03/20 19:43:02 bjornw + * * Get rid of esp0 setting + * * Give a 7th argument to a systemcall - the stackframe + * + * Revision 1.15 2001/03/05 13:14:30 bjornw + * Spelling fix + * + * Revision 1.14 2001/02/23 08:36:36 perf + * New ABI; syscallnr=r9, arg5=mof, arg6=srp. + * Corrected tracesys call check. + * + * Revision 1.13 2001/02/15 08:40:55 perf + * H-P by way of perf; + * - (_system_call): Don't read system call function address into r1. + * - (RBFExit): There is no such thing as a null pop. Adjust sp by addq. + * - (_system_call): Don't use r10 and don't save and restore it. + * - (THREAD_ESP0): New constant. + * - (_system_call): Inline set_esp0. + * + * Revision 1.12 2001/01/31 17:56:25 orjanf + * Added definition of LTASK_PID and made it global. + * * Revision 1.11 2001/01/10 21:13:29 bjornw * SYMBOL_NAME is defined incorrectly for the compiler options we currently use * @@ -62,7 +114,8 @@ #include #include - +#include + ;; functions exported from this file .globl _system_call @@ -77,9 +130,11 @@ .globl _spurious_interrupt .globl _hw_bp_trigs .globl _mmu_bus_fault - + .globl _do_sigtrap + .globl _gdb_handle_breakpoint + .globl _sys_call_table - + ;; syscall error codes LENOSYS = 38 @@ -90,6 +145,11 @@ LTASK_SIGPENDING = 8 LTASK_NEEDRESCHED = 20 LTASK_PTRACE = 24 +LTASK_PID = 105 + + ;; process bits for ptrace + +PT_TRACESYS_BIT = 1 ;; some pt_regs offsets (from ptrace.h) @@ -98,8 +158,8 @@ LR12 = 12 LR11 = 16 LR10 = 20 -LR1 = 56 -LR0 = 60 +LR9 = 24 +LMOF = 64 LDCCR = 68 LSRP = 72 LIRP = 76 @@ -124,7 +184,7 @@ nop ba ret_with_reschedule ; go back but check schedule and signals first nop - + reschedule: ;; keep r9 intact push r9 @@ -153,7 +213,7 @@ ;; Since we can't have system calls inside interrupts, it should not matter ;; that we don't stack IRP. ;; - ;; In r1 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,r0 + ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp ;; ;; This function looks on the _surface_ like spaghetti programming, but it's ;; really designed so that the fast-path does not force cache-loading of non-used @@ -161,7 +221,7 @@ _system_call: ;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call - push brp ; this is normally push irp + move brp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame push srp push dccr push mof @@ -170,42 +230,40 @@ push r10 ; push orig_r10 clear.d [sp=sp-4] ; frametype == 0, normal stackframe - move.d r10,r2 ; save for later - - movs.w -LENOSYS,r10 - move.d r10,[sp+LR10] ; put the default return value in r10 in the frame - - move.d sp,r10 - jsr _set_esp0 ; save top of frame (clobbers r9...) + movs.w -LENOSYS,r0 + move.d r0,[sp+LR10] ; put the default return value in r10 in the frame ;; check if this process is syscall-traced - move.d sp, r10 - and.d -8192, r10 ; THREAD_SIZE == 8192 - move.d [r10+LTASK_PTRACE],r10 - btstq 2, r10 ; PT_TRACESYS + movs.w -8192,r0 ; THREAD_SIZE == 8192 + and.d sp,r0 + + move.d [r0+LTASK_PTRACE],r0 + btstq PT_TRACESYS_BIT, r0 bmi tracesys nop ;; check for sanity in the requested syscall number - cmpu.w NR_syscalls,r1 + cmpu.w NR_syscalls,r9 bcc _ret_from_sys_call - lslq 2,r1 ; multiply by 4, in the delay slot + lslq 2,r9 ; multiply by 4, in the delay slot - ;; read the system call vector into r1 - - move.d [r1+_sys_call_table],r1 + ;; as a bonus 7th parameter, we give the location on the stack + ;; of the register structure itself. some syscalls need this. - ;; the parameter carrying registers r11, r12 and 13 are intact - restore r10. - ;; the fifth parameter (if any) was in r0, and we need to put it on the stack + push sp + + ;; the parameter carrying registers r10, r11, r12 and 13 are intact. + ;; the fifth and sixth parameters (if any) was in mof and srp + ;; respectively, and we need to put them on the stack. - push r0 - move.d r2,r10 + push srp + push mof - jsr r1 ; actually call the corresponding system call - addq 4,sp ; pop the r0 parameter - move.d r10,[sp+LR10] ; save the return value + jsr [r9+_sys_call_table] ; actually do the system call + addq 3*4,sp ; pop the mof, srp and regs parameters + move.d r10,[sp+LR10] ; save the return value moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call @@ -248,33 +306,20 @@ pop mof ; multiply overflow register pop dccr ; condition codes pop srp ; subroutine return pointer - jmpu [sp+] ; return by popping irp and jumping there - ;; jmpu takes the U-flag into account to see if we return to - ;; user-mode or kernel mode. + ;; now we have a 4-word SBFS frame which we do not want to restore + ;; using RBF since it was not stacked with SBFS. instead we would like to + ;; just get the PC value to restart it with, and skip the rest of + ;; the frame. + move [sp=sp+16], p8 ; pop the SBFS frame from the sp + jmpu [sp-16] ; return through the irp field in the sbfs frame RBFexit: - cmpq 2, r10 ; was it CRIS_FRAME_FIXUP ? - beq 2f movem [sp+],r13 ; registers r0-r13, in delay slot pop mof ; multiply overflow register pop dccr ; condition codes pop srp ; subroutine return pointer rbf [sp+] ; return by popping the CPU status -2: pop mof ; multiply overflow register - pop dccr ; condition codes - pop srp ; subroutine return pointer - ;; now we have a 4-word SBFS frame which we do not want to restore - ;; using RBF since we have made a fixup. instead we would like to - ;; just get the PC value to restart it with, and skip the rest of - ;; the frame. - pop irp ; fixup location will be here - pop p8 ; null pop - pop p8 ; null pop - reti ; return to IRP, taking U-flag into account - pop p8 ; null pop in delayslot - - tracesys: ;; this first invocation of syscall_trace _requires_ that ;; LR10 in the frame contains -LENOSYS (as is set in the beginning @@ -289,30 +334,38 @@ ;; check for sanity in the requested syscall number - move.d [sp+LR1], r1 + move.d [sp+LR9], r9 movs.w -LENOSYS, r10 - cmpu.w NR_syscalls,r1 + cmpu.w NR_syscalls,r9 bcc 1f - lslq 2,r1 ; multiply by 4, in the delay slot + lslq 2,r9 ; multiply by 4, in the delay slot - ;; read the system call vector entry into r1 + ;; read the system call vector entry into r9 - move.d [r1+_sys_call_table],r1 + move.d [r9+_sys_call_table],r9 - ;; restore r10, r11, r12, r13 and r0 into the needed registers + ;; restore r10, r11, r12, r13, mof and srp into the needed registers move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -LENOSYS move.d [sp+LR11], r11 move.d [sp+LR12], r12 move.d [sp+LR13], r13 - move.d [sp+LR0], r0 + move [sp+LMOF], mof + move [sp+LSRP], srp - ;; the fifth parameter needs to be put on the stack for the system - ;; call to find it + ;; as a bonus 7th parameter, we give the location on the stack + ;; of the register structure itself. some syscalls need this. - push r0 - jsr r1 ; actually call the system-call - addq 4,sp ; pop the r0 parameter + push sp + + ;; the fifth and sixth parameters needs to be put on the stack for + ;; the system call to find them + + push srp + push mof + + jsr r9 ; actually call the system-call + addq 3*4,sp ; pop the srp, mof and regs parameters 1: move.d r10,[sp+LR10] ; save the return value @@ -328,8 +381,7 @@ LTHREAD_KSP = 0 LTHREAD_USP = 4 -LTHREAD_ESP0 = 8 -LTHREAD_DCCR = 12 +LTHREAD_DCCR = 8 ;; _resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct @@ -442,8 +494,6 @@ _IRQ1_interrupt: _spurious_interrupt: di - move.b 4,r0 - move.b r0,[0xb0000030] basse2: ba basse2 nop @@ -453,7 +503,7 @@ _multiple_interrupt: ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! - push irp + move irp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame push srp push dccr push mof @@ -465,15 +515,15 @@ move.d _irq_shortcuts + 8,r1 moveq 2,r2 ; first bit we care about is the timer0 irq - move.d [0xb00000d8],r0 ; read the irq bits that triggered the multiple irq + move.d [R_VECT_MASK_RD],r0 ; read the irq bits that triggered the multiple irq multloop: btst r2,r0 ; check for the irq given by bit r2 bmi do_shortcut ; actually do the shortcut nop - addq 1,r2 ; next vector bit - remember this is in the delay slot! + addq 1,r2 ; next vector bit addq 4,r1 ; next vector - cmpq 26,r2 - bne multloop ; process all irq's up to and including number 25 + cmp.b 32,r2 + bne multloop ; process all irq's up to and including number 31 nop ;; strange, we didn't get any set vector bits.. oh well, just return @@ -487,6 +537,48 @@ nop jump [r1] ; jump to the irq handlers shortcut +_do_sigtrap: + ;; + ;; SIGTRAP the process that executed the break instruction. + ;; Make a frame that Rexit in entry.S expects. + ;; + move brp,[sp=sp-16] ; Push BRP while faking a cpu status record. + push srp ; Push subroutine return pointer. + push dccr ; Push condition codes. + push mof ; Push multiply overflow reg. + di ; Need to disable irq's at this point. + subq 14*4,sp ; Make room for r0-r13. + movem r13,[sp] ; Push the r0-r13 registers. + push r10 ; Push orig_r10. + clear.d [sp=sp-4] ; Frametype - this is a normal stackframe. + + movs.w -8192,r9 ; THREAD_SIZE == 8192 + and.d sp,r9 + move.d [r9+LTASK_PID],r10 ; current->pid as arg1. + moveq 5,r11 ; SIGTRAP as arg2. + jsr _sys_kill + jump _ret_from_intr ; Use the return routine for interrupts. + +_gdb_handle_breakpoint: + push dccr + push r0 +#ifdef CONFIG_ETRAX_KGDB + move dccr,r0 ; U-flag not affected by previous insns. + btstq 8,r0 ; Test the U-flag. + bmi _ugdb_handle_breakpoint ; Go to user mode debugging. + nop ; Empty delay slot (cannot pop r0 here). + pop r0 ; Restore r0. + ba _kgdb_handle_breakpoint ; Go to kernel debugging. + pop dccr ; Restore dccr in delay slot. +#endif + +_ugdb_handle_breakpoint: + move brp,r0 ; Use r0 temporarily for calculation. + subq 2,r0 ; Set to address of previous instruction. + move r0,brp + pop r0 ; Restore r0. + ba _do_sigtrap ; SIGTRAP the offending process. + pop dccr ; Restore dccr in delay slot. .data @@ -495,8 +587,11 @@ _hw_bp_trig_ptr: .dword _hw_bp_trigs -/* linux/linkage.h got it wrong for this compiler currently */ - +/* Because we compile this file with -traditional, we need to redefine + token-concatenation to the traditional trick, using an empty comment. + Normally (in other files, with ISO C as in gcc default) this is done + with the ## preprocessor operator. */ + #undef SYMBOL_NAME #define SYMBOL_NAME(X) _/**/X @@ -722,6 +817,8 @@ .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ /* * NOTE!! This doesn't have to be exact - we just have @@ -730,9 +827,7 @@ * been shrunk every time we add a new system call. */ - ;; TODO: this needs to actually generate sys_ni_syscall entires - ;; since we now have removed the check for NULL entries in this - ;; table in system_call! - - .space (NR_syscalls-220)*4 + .rept NR_syscalls-221 + .long SYMBOL_NAME(sys_ni_syscall) + .endr diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/head.S linux.ac/arch/cris/kernel/head.S --- linux.vanilla/arch/cris/kernel/head.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/head.S Thu Apr 19 14:13:36 2001 @@ -1,53 +1,117 @@ - ;; $Id: head.S,v 1.11 2001/01/16 16:31:38 bjornw Exp $ - ;; - ;; Head of the kernel - alter with care - ;; - ;; Copyright (C) 2000, 2001 Axis Communications AB - ;; - ;; Authors: Bjorn Wesen (bjornw@axis.com) - ;; - ;; $Log: head.S,v $ - ;; Revision 1.11 2001/01/16 16:31:38 bjornw - ;; * Changed name and semantics of running_from_flash to romfs_in_flash, - ;; set by head.S to indicate to setup.c whether there is a cramfs image - ;; after the kernels BSS or not. Should work for all three boot-cases - ;; (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot), - ;; and flash with cramfs in flash) - ;; - ;; Revision 1.10 2001/01/16 14:12:21 bjornw - ;; * Check for cramfs start passed in r9 from the decompressor, if all other - ;; cramfs options fail (if we boot from DRAM but don't find a cramfs image - ;; after the kernel in DRAM, it is probably still in the flash) - ;; * Check magic in cramfs detection when booting from flash directly - ;; - ;; Revision 1.9 2001/01/15 17:17:02 bjornw - ;; * Corrected the code that detects the cramfs lengths - ;; * Added a comment saying that the above does not work due to other - ;; reasons.. - ;; - ;; Revision 1.8 2001/01/15 16:27:51 jonashg - ;; Made boot after flashing work. - ;; * end destination is __vmlinux_end in RAM. - ;; * _romfs_start moved because of virtual memory. - ;; - ;; Revision 1.7 2000/11/21 13:55:29 bjornw - ;; Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type - ;; - ;; Revision 1.6 2000/10/06 12:36:55 bjornw - ;; Forgot swapper_pg_dir when changing memory map.. - ;; - ;; Revision 1.5 2000/10/04 16:49:30 bjornw - ;; * Fixed memory mapping in LX - ;; * Check for cramfs instead of romfs - ;; - ;; +/* $Id: head.S,v 1.29 2001/04/18 12:51:59 orjanf Exp $ + * + * Head of the kernel - alter with care + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * $Log: head.S,v $ + * Revision 1.29 2001/04/18 12:51:59 orjanf + * * Reverted review change regarding the use of bcs/bcc. + * * Removed non-working LED-clearing code. + * + * Revision 1.28 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.27 2001/04/17 11:42:35 orjanf + * Changed according to review: + * * Added comment explaining memory map bug. + * * Changed bcs and bcc to blo and bhs, respectively. + * * Removed mentioning of Stallone and Olga boards. + * + * Revision 1.26 2001/04/06 12:31:07 jonashg + * Check for cramfs in flash before RAM instead of RAM before flash. + * + * Revision 1.25 2001/04/04 06:23:53 starvik + * Initialize DRAM if not already initialized + * + * Revision 1.24 2001/04/03 11:12:00 starvik + * Removed dram init (done by rescue or etrax100boot + * Corrected include + * + * Revision 1.23 2001/04/03 09:53:03 starvik + * Include hw_settings.S + * + * Revision 1.22 2001/03/26 14:23:26 bjornw + * Namechange of some config options + * + * Revision 1.21 2001/03/08 12:14:41 bjornw + * * Config name for ETRAX IDE was renamed + * * Removed G27 auto-setting when JULIETTE is chosen (need to make this + * a new config option later) + * + * Revision 1.20 2001/02/23 12:47:56 bjornw + * MMU regs during LOW_MAP updated to reflect a newer reality + * + * Revision 1.19 2001/02/19 11:12:07 bjornw + * Changed comment header format + * + * Revision 1.18 2001/02/15 07:25:38 starvik + * Added support for synchronous serial ports + * + * Revision 1.17 2001/02/08 15:53:13 starvik + * Last commit removed some important ifdefs + * + * Revision 1.16 2001/02/08 15:20:38 starvik + * Include dram_init.S as inline + * + * Revision 1.15 2001/01/29 18:12:01 bjornw + * Corrected some comments + * + * Revision 1.14 2001/01/29 13:11:29 starvik + * Include dram_init.S (with DRAM/SDRAM initialization) + * + * Revision 1.13 2001/01/23 14:54:57 markusl + * Updated for USB + * i.e. added r_gen_config settings + * + * Revision 1.12 2001/01/19 16:16:29 perf + * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion. + * Renamed serial options from ETRAX100 to ETRAX. + * + * Revision 1.11 2001/01/16 16:31:38 bjornw + * * Changed name and semantics of running_from_flash to romfs_in_flash, + * set by head.S to indicate to setup.c whether there is a cramfs image + * after the kernels BSS or not. Should work for all three boot-cases + * (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot), + * and flash with cramfs in flash) + * + * Revision 1.10 2001/01/16 14:12:21 bjornw + * * Check for cramfs start passed in r9 from the decompressor, if all other + * cramfs options fail (if we boot from DRAM but don't find a cramfs image + * after the kernel in DRAM, it is probably still in the flash) + * * Check magic in cramfs detection when booting from flash directly + * + * Revision 1.9 2001/01/15 17:17:02 bjornw + * * Corrected the code that detects the cramfs lengths + * * Added a comment saying that the above does not work due to other + * reasons.. + * + * Revision 1.8 2001/01/15 16:27:51 jonashg + * Made boot after flashing work. + * * end destination is __vmlinux_end in RAM. + * * _romfs_start moved because of virtual memory. + * + * Revision 1.7 2000/11/21 13:55:29 bjornw + * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type + * + * Revision 1.6 2000/10/06 12:36:55 bjornw + * Forgot swapper_pg_dir when changing memory map.. + * + * Revision 1.5 2000/10/04 16:49:30 bjornw + * * Fixed memory mapping in LX + * * Check for cramfs instead of romfs + * + */ #include #define ASSEMBLER_MACROS_ONLY #include #define CRAMFS_MAGIC 0x28cd3d45 - +#define RAM_INIT_MAGIC 0x56902387 + ;; exported symbols .globl _etrax_irv @@ -63,9 +127,9 @@ ;; since etrax actually starts at address 2 when booting from flash, we ;; put a nop (2 bytes) here first so we dont accidentally skip the di ;; - ;; NOTICE! The register r9 is used as a parameter carrying register from - ;; the decompressor (if the kernel was compressed). It should not be - ;; used in the code below until it is read. + ;; NOTICE! The registers r8 and r9 are used as a parameter carrying + ;; information from the decompressor (if the kernel was compressed). + ;; They should not be used in the code below until it is read. nop di @@ -80,15 +144,16 @@ ;; ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory ;; slightly different. We also let the simulator get this mapping for now. + ;; (The bug is that you can't remap bit 31.) #ifdef CONFIG_CRIS_LOW_MAP - move.d 0x0800b000, r0 ; kseg mappings + move.d 0x0004b098, r0 ; kseg mappings, temporary map of 0xc0->0x40 move.d r0, [R_MMU_KBASE_HI] move.d 0x04040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00 move.d r0, [R_MMU_KBASE_LO] - move.d 0x80074871, r0 ; mmu enable, segs e,b,6,5,4,0 segment mapped + move.d 0x80075c71, r0 ; mmu enable, segs c,b,9,8,6,5,4,0 segment mapped move.d r0, [R_MMU_CONFIG] #else move.d 0x0804b000, r0 ; kseg mappings @@ -131,24 +196,15 @@ jump inram ; enter cached ram inflash: + ;; We need to initialze DRAM registers before we start using the DRAM -#ifndef CONFIG_SVINTO_SIM - - ;; We need to setup the bus registers before we start using the DRAM - - move.d DEF_R_WAITSTATES, r0 - move.d r0, [R_WAITSTATES] - - move.d DEF_R_BUS_CONFIG, r0 - move.d r0, [R_BUS_CONFIG] - - move.d DEF_R_DRAM_CONFIG, r0 - move.d r0, [R_DRAM_CONFIG] - - move.d DEF_R_DRAM_TIMING, r0 - move.d r0, [R_DRAM_TIMING] + cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? + beq dram_init_finished + nop + +#include "../lib/dram_init.S" -#endif +dram_init_finished: ;; Copy text+data to DRAM ;; This is fragile - the calculation of r4 as the image size depends ;; on that the labels below actually are the first and last positions @@ -204,7 +260,39 @@ moveq 0, r0 move.d r0, [_romfs_length] ; default if there is no cramfs - ;; First check if there is a cramfs (magic value) + ;; The kernel could have been unpacked to DRAM by the loader, but + ;; the cramfs image could still be in the Flash directly after the + ;; compressed kernel image. The loader passes the address of the + ;; byte succeeding the last compressed byte in the flash in the + ;; register r9 when starting the kernel. Check if r9 points to a + ;; decent cramfs image! + ;; (Notice that if this is not booted from the loader, r9 will be + ;; garbage but we do sanity checks on it, the chance that it points + ;; to a cramfs magic is small.. ) + + cmp.d 0x0ffffff8, r9 + bcc no_romfs_in_flash ; r9 points outside the flash area + nop + move.d [r9], r0 ; cramfs_super.magic + cmp.d CRAMFS_MAGIC, r0 + bne no_romfs_in_flash + nop + move.d [r9+4], r0 ; cramfs_super.length + move.d r0, [_romfs_length] +#ifdef CONFIG_CRIS_LOW_MAP + add.d 0x50000000, r9 ; add flash start in virtual memory (cached) +#else + add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) +#endif + move.d r9, [_romfs_start] + + moveq 1, r0 + move.d r0, [_romfs_in_flash] + + jump start_it ; enter code, cached this time + +no_romfs_in_flash: + ;; Check if there is a cramfs (magic value). ;; Notice that we check for cramfs magic value - which is ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does ;; not need this mechanism anyway) @@ -212,7 +300,7 @@ move.d __vmlinux_end, r0 ; the image will be after the vmlinux end address move.d [r0], r1 ; cramfs assumes same endian on host/target cmp.d CRAMFS_MAGIC, r1; magic value in cramfs superblock - bne no_romfs_in_ram + bne 1f nop ;; Ok. What is its size ? @@ -249,40 +337,6 @@ move.d r0, [_romfs_in_flash] jump start_it ; better skip the additional cramfs check below - -no_romfs_in_ram: - - ;; We have still one other possibility at this point - the kernel - ;; could have been unpacked to DRAM by the loader, but the cramfs - ;; image was still in the Flash directly after the compressed kernel - ;; image. The loader passes the address of the byte succeeding the - ;; last compressed byte in the flash in the register r9 when starting - ;; the kernel. Check if r9 points to a decent cramfs image! - ;; (Notice that if this is not booted from the loader, r9 will be - ;; garbage but we do sanity checks on it, the chance that it points - ;; to a cramfs magic is small.. ) - - cmp.d 0x0ffffff8, r9 - bcc 1f ; r9 points outside the flash area - nop - move.d [r9], r0 ; cramfs_super.magic - cmp.d CRAMFS_MAGIC, r0 - bne 1f - nop - move.d [r9+4], r0 ; cramfs_super.length - move.d r0, [_romfs_length] -#ifdef CONFIG_CRIS_LOW_MAP - add.d 0x50000000, r9 ; add flash start in virtual memory (cached) -#else - add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) -#endif - move.d r9, [_romfs_start] - - moveq 1, r0 - move.d r0, [_romfs_in_flash] -1: - - jump start_it ; enter code, cached this time start_it: ;; the kernel stack is overlayed with the task structure for each @@ -354,35 +408,43 @@ ;; Etrax product HW genconfig setup moveq 0,r0 -#if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY) +#if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY) or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA #endif -#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1) +#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA -#endif +#endif #ifdef CONFIG_DMA_MEMCPY or.d 0x003c0000,r0 ; 6/7 memory-memory DMA #endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT2 +#ifdef CONFIG_ETRAX_SERIAL_PORT2 or.d 0x2808,r0 ; DMA channels 2 and 3 to serport 2, port 2 enabled #endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT3 +#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) or.d 0x28100,r0 ; DMA channels 4 and 5 to serport 3, port 3 enabled -#endif -#if defined(CONFIG_ETRAX100_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) +#endif +#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) or.w 0x4,r0 ; parport 0 enabled using DMA 2/3 #endif -#if defined(CONFIG_ETRAX100_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) +#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) or.w 0x80,r0 ; parport 1 enabled using DMA 4/5 #endif -#ifdef CONFIG_BLK_DEV_ETRAXIDE +#ifdef CONFIG_ETRAX_IDE or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled #endif + +#ifdef CONFIG_ETRAX_USB_HOST_PORT1 + or.d 0x20000000,r0 ; Set the USB port 1 enable bit +#endif +#ifdef CONFIG_ETRAX_USB_HOST_PORT2 + or.d 0x40000000,r0 ; Set the USB port 2 enable bit +#endif +#ifdef CONFIG_ETRAX_USB_HOST + and.d 0xff3fffff,r0 ; Connect DMA channels 8 and 9 to USB +#endif + #ifdef CONFIG_JULIETTE or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette -#ifndef CONFIG_BLK_DEV_ETRAXIDE - or.d 0x41,r0 ; HACK for now! To make G27 connected for the RTC -#endif #endif move.d r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG @@ -422,22 +484,25 @@ ;; setup port PA and PB default initial directions and data ;; including their shadow registers - move.b DEF_R_PORT_PA_DIR,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,r0 move.b r0,[_port_pa_dir_shadow] move.b r0,[R_PORT_PA_DIR] - move.b DEF_R_PORT_PA_DATA,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA,r0 move.b r0,[_port_pa_data_shadow] move.b r0,[R_PORT_PA_DATA] - move.b DEF_R_PORT_PB_CONFIG,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,r0 move.b r0,[_port_pb_config_shadow] move.b r0,[R_PORT_PB_CONFIG] - move.b DEF_R_PORT_PB_DIR,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR,r0 move.b r0,[_port_pb_dir_shadow] move.b r0,[R_PORT_PB_DIR] - move.b DEF_R_PORT_PB_DATA,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA,r0 move.b r0,[_port_pb_data_shadow] move.b r0,[R_PORT_PB_DATA] + move.d 0, r0 + move.d r0,[_port_pb_i2c_shadow] + move.d r0, [R_PORT_PB_I2C] moveq 0,r0 move.d r0,[_port_g_data_shadow] @@ -471,14 +536,8 @@ move.b 0x40,r0 ; tr enable move.b r0,[R_SERIAL1_TR_CTRL] -#ifdef CONFIG_ETRAX_90000000_LEDS - ;; clear LED's on Stallone and Olga boards - moveq -1,r0 - move.d r0,[_port_90000000_shadow] - move.d r0,[0x90000000] -#endif -#ifdef CONFIG_ETRAX100_SERIAL_PORT3 +#ifdef CONFIG_ETRAX_SERIAL_PORT3 ;; setup the serial port 3 at 115200 baud for debug purposes moveq 0,r0 @@ -497,8 +556,7 @@ #endif /* CONFIG_SVINTO_SIM */ jump _start_kernel ; jump into the C-function _start_kernel in init/main.c - - + .data _etrax_irv: .dword 0 @@ -508,7 +566,7 @@ .dword 0 _romfs_in_flash: .dword 0 - + ;; put some special pages at the beginning of the kernel aligned ;; to page boundaries - the kernel cannot start until after this @@ -517,3 +575,5 @@ #else _swapper_pg_dir = 0xc0002000 #endif + +#include "../lib/hw_settings.S" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/irq.c linux.ac/arch/cris/kernel/irq.c --- linux.vanilla/arch/cris/kernel/irq.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/irq.c Thu Apr 19 14:13:36 2001 @@ -1,8 +1,8 @@ -/* $Id: irq.c,v 1.5 2000/08/17 15:35:15 bjornw Exp $ +/* $Id: irq.c,v 1.14 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/kernel/irq.c * - * Copyright (c) 2000 Axis Communications AB + * Copyright (c) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -160,6 +160,8 @@ BUILD_IRQ(23, 0x800000) BUILD_IRQ(24, 0x1000000) BUILD_IRQ(25, 0x2000000) +/* IRQ 26-30 are reserved */ +BUILD_IRQ(31, 0x80000000) /* * Pointers to the low-level handlers @@ -172,7 +174,8 @@ IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, - IRQ24_interrupt, IRQ25_interrupt + IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + IRQ31_interrupt }; static void (*sinterrupt[NR_IRQS])(void) = { @@ -182,7 +185,8 @@ sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, - sIRQ24_interrupt, sIRQ25_interrupt + sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + sIRQ31_interrupt }; static void (*bad_interrupt[NR_IRQS])(void) = { @@ -198,7 +202,9 @@ bad_IRQ18_interrupt, bad_IRQ19_interrupt, bad_IRQ20_interrupt, bad_IRQ21_interrupt, bad_IRQ22_interrupt, bad_IRQ23_interrupt, - bad_IRQ24_interrupt, bad_IRQ25_interrupt + bad_IRQ24_interrupt, bad_IRQ25_interrupt, + NULL, NULL, NULL, NULL, NULL, + bad_IRQ31_interrupt }; /* @@ -212,7 +218,8 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; int get_irq_list(char *buf) @@ -254,11 +261,11 @@ irq_enter(cpu); kstat.irqs[cpu][irq]++; - action = *(irq + irq_action); + action = irq_action[irq]; if (action) { if (!(action->flags & SA_INTERRUPT)) __sti(); - action = *(irq + irq_action); + action = irq_action[irq]; do_random = 0; do { do_random |= action->flags; @@ -389,7 +396,7 @@ save_flags(flags); cli(); *p = action->next; - if (!irq[irq_action]) { + if (!irq_action[irq]) { mask_irq(irq); set_int_vector(irq, bad_interrupt[irq], 0); } @@ -412,6 +419,8 @@ */ void system_call(void); /* from entry.S */ +void do_sigtrap(void); /* from entry.S */ +void gdb_handle_breakpoint(void); /* from entry.S */ void init_IRQ(void) { @@ -431,14 +440,22 @@ for(i = 0; i < NR_IRQS; i++) irq_shortcuts[i] = NULL; - - for (i = 0; i < 256; i++) - etrax_irv->v[i] = weird_irq; - + + for (i = 0; i < 256; i++) + etrax_irv->v[i] = weird_irq; + + /* the entries in the break vector contain actual code to be + executed by the associated break handler, rather than just a jump + address. therefore we need to setup a default breakpoint handler + for all breakpoints */ + + for (i = 0; i < 16; i++) + set_break_vector(i, do_sigtrap); + /* set all etrax irq's to the bad handlers */ for (i = 2; i < NR_IRQS; i++) set_int_vector(i, bad_interrupt[i], 0); - + /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ set_int_vector(15, multiple_interrupt, 0); @@ -456,12 +473,15 @@ set_break_vector(13, system_call); -#ifdef CONFIG_KGDB - /* setup kgdb if its enabled, and break into the debugger */ + /* setup a breakpoint handler for debugging used for both user and + kernel mode debugging (which is why it is not inside an ifdef + CONFIG_ETRAX_KGDB) */ + set_break_vector(8, gdb_handle_breakpoint); +#ifdef CONFIG_ETRAX_KGDB + /* setup kgdb if its enabled, and break into the debugger */ kgdb_init(); - breakpoint(); #endif -} +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/kgdb.c linux.ac/arch/cris/kernel/kgdb.c --- linux.vanilla/arch/cris/kernel/kgdb.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/kgdb.c Thu Apr 19 14:13:36 2001 @@ -18,6 +18,15 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.5 2001/04/17 13:58:39 orjanf +*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. +*! +*! Revision 1.4 2001/02/23 13:45:19 bjornw +*! config.h check +*! +*! Revision 1.3 2001/01/31 18:08:23 orjanf +*! Removed kgdb_handle_breakpoint from being the break 8 handler. +*! *! Revision 1.2 2001/01/12 14:22:25 orjanf *! Updated kernel debugging support to work with ETRAX 100LX. *! @@ -43,7 +52,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.2 2001/01/12 14:22:25 orjanf Exp $ +*! $Id: kgdb.c,v 1.5 2001/04/17 13:58:39 orjanf Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -54,8 +63,8 @@ * kgdb usage notes: * ----------------- * - * If you select CONFIG_KGDB in the configuration, the kernel will be built - * with different gcc flags: "-g" is added to get debug infos, and + * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be + * built with different gcc flags: "-g" is added to get debug infos, and * "-fomit-frame-pointer" is omitted to make debugging easier. Since the * resulting kernel will be quite big (approx. > 7 MB), it will be stripped * before compresion. Such a kernel will behave just as usually, except if @@ -1531,7 +1540,7 @@ { /* could initialize debug port as well but it's done in head.S already... */ - set_break_vector(8, kgdb_handle_breakpoint); + /* breakpoint handler is now set in irq.c */ set_int_vector(8, kgdb_handle_serial, 0); enableDebugIRQ(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/process.c linux.ac/arch/cris/kernel/process.c --- linux.vanilla/arch/cris/kernel/process.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/process.c Thu Apr 19 14:13:36 2001 @@ -1,12 +1,16 @@ -/* $Id: process.c,v 1.8 2000/09/13 14:34:13 bjornw Exp $ +/* $Id: process.c,v 1.13 2001/03/20 19:44:06 bjornw Exp $ * * linux/arch/cris/kernel/process.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * + * $Log: process.c,v $ + * Revision 1.13 2001/03/20 19:44:06 bjornw + * Use the 7th syscall argument for regs instead of current_regs + * */ /* @@ -23,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -33,6 +37,8 @@ #include #include #include +#include + #include //#define DEBUG @@ -64,18 +70,6 @@ static int hlt_counter=0; -/* in a system call, set_esp0 is called to remember the stack frame, therefore - in the implementation of syscalls we can use that value to access the stack - frame and saved registers. -*/ - -#define currentregs ((struct pt_regs *)current->thread.esp0) - -asmlinkage void set_esp0(unsigned long ssp) -{ - current->thread.esp0 = ssp; -} - void disable_hlt(void) { hlt_counter++; @@ -134,7 +128,7 @@ register long __a __asm__ ("r10"); __asm__ __volatile__ - ("movu.w %1,r1\n\t" /* r1 contains syscall number, to sys_clone */ + ("movu.w %1,r9\n\t" /* r9 contains syscall number, to sys_clone */ "clear.d r10\n\t" /* r10 is argument 1 to clone */ "move.d %2,r11\n\t" /* r11 is argument 2 to clone, the flags */ "break 13\n\t" /* call sys_clone, this will fork */ @@ -143,14 +137,14 @@ "nop\n\t" /* delay slot */ "move.d %4,r10\n\t" /* set argument to function to call */ "jsr %5\n\t" /* call specified function */ - "movu.w %3,r1\n\t" /* r1 is sys_exit syscall number */ + "movu.w %3,r9\n\t" /* r9 is sys_exit syscall number */ "moveq -1,r10\n\t" /* Give a really bad exit-value */ "break 13\n\t" /* call sys_exit, killing the child */ "1:\n\t" : "=r" (__a) : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit), "r" (arg), "r" (fn) - : "r10", "r11", "r1"); + : "r10", "r11", "r9"); return __a; } @@ -183,7 +177,7 @@ * remember that the task_struct doubles as the kernel stack for the task */ - childregs = ((struct pt_regs *) ((unsigned long)p + THREAD_SIZE)) - 1; + childregs = user_regs(p); *childregs = *regs; /* struct copy of pt_regs */ @@ -207,14 +201,11 @@ p->thread.ksp = (unsigned long) swstack; - /* esp0 keeps the pt_regs stacked structure pointer */ - - p->thread.esp0 = (unsigned long) childregs; - #ifdef DEBUG - printk("kern_stack_page 0x%x, used stack %d, thread.usp 0x%x, usp 0x%x\n", - current->kernel_stack_page, usedstack, p->thread.usp, usp); + printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); + show_registers(childregs); #endif + return 0; } @@ -245,33 +236,53 @@ #endif } -asmlinkage int sys_fork(void) +/* + * Be aware of the "magic" 7th argument in the four system-calls below. + * They need the latest stackframe, which is put as the 7th argument by + * entry.S. The previous arguments are dummies or actually used, but need + * to be defined to reach the 7th argument. + * + * N.B.: Another method to get the stackframe is to use current_regs(). But + * it returns the latest stack-frame stacked when going from _user mode_ and + * some of these (at least sys_clone) are called from kernel-mode sometimes + * (for example during kernel_thread, above) and thus cannot use it. Thus, + * to be sure not to get any surprises, we use the method for the other calls + * as well. + */ + +asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), currentregs, 0); + return do_fork(SIGCHLD, rdusp(), regs, 0); } /* if newusp is 0, we just grab the old usp */ -asmlinkage int sys_clone(unsigned long newusp, unsigned long flags) +asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, + long r12, long r13, long mof, long srp, + struct pt_regs *regs) { if (!newusp) newusp = rdusp(); - return do_fork(flags, newusp, currentregs, 0); + return do_fork(flags, newusp, regs, 0); } /* vfork is a system call in i386 because of register-pressure - maybe * we can remove it and handle it in libc but we put it here until then. */ -asmlinkage int sys_vfork(void) +asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), currentregs, 0); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); } /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *fname, char **argv, char **envp) +asmlinkage int sys_execve(const char *fname, char **argv, char **envp, + long r13, long mof, long srp, + struct pt_regs *regs) { int error; char *filename; @@ -281,7 +292,7 @@ if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, currentregs); + error = do_execve(filename, argv, envp, regs); putname(filename); out: return error; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/ptrace.c linux.ac/arch/cris/kernel/ptrace.c --- linux.vanilla/arch/cris/kernel/ptrace.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/ptrace.c Thu Apr 19 14:13:36 2001 @@ -3,11 +3,18 @@ * * Parts taken from the m68k port. * - * Copyright (c) 2000 Axis Communications AB + * Copyright (c) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen * * $Log: ptrace.c,v $ + * Revision 1.5 2001/03/26 14:24:28 orjanf + * * Changed loop condition. + * * Added comment documenting non-standard ptrace behaviour. + * + * Revision 1.4 2001/03/20 19:44:41 bjornw + * Use the user_regs macro instead of thread.esp0 + * * Revision 1.3 2000/12/18 23:45:25 bjornw * Linux/CRIS first version * @@ -49,8 +56,8 @@ if (regno == PT_USP) return task->thread.usp; - else if (regno <= PT_MAX) - return ((unsigned long *)(task->thread.esp0))[regno]; + else if (regno < PT_MAX) + return ((unsigned long *)user_regs(task))[regno]; else return 0; } @@ -65,12 +72,20 @@ if (regno == PT_USP) task->thread.usp = data; - else if (regno <= PT_MAX) - ((unsigned long *)(task->thread.esp0))[regno] = data; + else if (regno < PT_MAX) + ((unsigned long *)user_regs(task))[regno] = data; else return -1; return 0; } + +/* Note that this implementation of ptrace behaves differently from vanilla + * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, + * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not + * ignored. Instead, the data variable is expected to point at a location + * (in user space) where the result of the ptrace call is written (instead of + * being returned). + */ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/semaphore.c linux.ac/arch/cris/kernel/semaphore.c --- linux.vanilla/arch/cris/kernel/semaphore.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/semaphore.c Wed Apr 18 13:47:23 2001 @@ -127,112 +127,3 @@ { return waking_non_zero_trylock(sem); } - -/* - * RW Semaphores - */ -void -__down_read(struct rw_semaphore *sem, int count) -{ - DOWN_VAR; - - retry_down: - if (count < 0) { - /* Wait for the lock to become unbiased. Readers - are non-exclusive. */ - - /* This takes care of granting the lock. */ - up_read(sem); - - add_wait_queue(&sem->wait, &wait); - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - mb(); - count = atomic_dec_return(&sem->count); - if (count <= 0) - goto retry_down; - } else { - add_wait_queue(&sem->wait, &wait); - - while (1) { - if (test_and_clear_bit(0, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((sem->granted & 1) == 0) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - } -} - -void -__down_write(struct rw_semaphore *sem, int count) -{ - DOWN_VAR; - - retry_down: - if (count + RW_LOCK_BIAS < 0) { - up_write(sem); - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= RW_LOCK_BIAS) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - mb(); - count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (count != 0) - goto retry_down; - } else { - /* Put ourselves at the end of the list. */ - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); - - while (1) { - if (test_and_clear_bit(1, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((sem->granted & 2) == 0) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* If the lock is currently unbiased, awaken the sleepers. - FIXME: This wakes up the readers early in a bit of a - stampede -> bad! */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); - } -} - -void -__rwsem_wake(struct rw_semaphore *sem, unsigned long readers) -{ - if (readers) { - if (test_and_set_bit(0, &sem->granted)) - BUG(); - wake_up(&sem->wait); - } else { - if (test_and_set_bit(1, &sem->granted)) - BUG(); - wake_up(&sem->write_bias_wait); - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/setup.c linux.ac/arch/cris/kernel/setup.c --- linux.vanilla/arch/cris/kernel/setup.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/setup.c Thu Apr 19 14:13:36 2001 @@ -1,9 +1,9 @@ -/* $Id: setup.c,v 1.8 2001/01/16 16:31:38 bjornw Exp $ +/* $Id: setup.c,v 1.14 2001/04/03 12:54:12 starvik Exp $ * * linux/arch/cris/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (c) 2000 Axis Communications AB + * Copyright (c) 2001 Axis Communications AB */ /* @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -66,7 +66,7 @@ * given by the macro __pa(). * * In this DRAM, the kernel code and data is loaded, in the beginning. - * It really starts at c00a0000 to make room for some special pages - + * It really starts at c0004000 to make room for some special pages - * the start address is text_start. The kernel data ends at _end. After * this the ROM filesystem is appended (if there is any). * @@ -75,18 +75,14 @@ * */ -void __init setup_arch(char **cmdline_p) +void __init +setup_arch(char **cmdline_p) { unsigned long bootmap_size; unsigned long start_pfn, max_pfn; unsigned long memory_start; extern void console_print_etrax(const char *b); -#if (defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)) - /* TODO: move this into flash_init I think */ - flash_probe(); -#endif - /* register an initial console printing routine for printk's */ init_etrax_debug(); @@ -172,14 +168,15 @@ paging_init(); - /* we dont use a command line yet, so just let it be an empty string */ - + /* we dont use a command line yet, so just let it be an empty string + to start with */ + *cmdline_p = command_line; strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */ /* give credit for the CRIS port */ - printk("Linux/CRIS port on ETRAX 100LX (c) 2000 Axis Communications AB\n"); + printk("Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n"); } @@ -192,6 +189,7 @@ #define HAS_ATA 0x0020 #define HAS_USB 0x0040 #define HAS_IRQ_BUG 0x0080 +#define HAS_MMU_BUG 0x0100 static struct cpu_info { char *model; @@ -214,7 +212,8 @@ { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, + { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, + { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, { "Unknown", 0, 0 }, }; @@ -241,6 +240,7 @@ "cache size\t: %d kB\n" "fpu\t\t: %s\n" "mmu\t\t: %s\n" + "mmu DMA bug\t: %s\n" "ethernet\t: %s Mbps\n" "token ring\t: %s\n" "scsi\t\t: %s\n" @@ -253,6 +253,7 @@ cpu_info[revision].cache, cpu_info[revision].flags & HAS_FPU ? "yes" : "no", cpu_info[revision].flags & HAS_MMU ? "yes" : "no", + cpu_info[revision].flags & HAS_MMU_BUG ? "yes" : "no", cpu_info[revision].flags & HAS_ETHERNET100 ? "10/100" : "10", cpu_info[revision].flags & HAS_TOKENRING ? "4/16 Mbps" : "no", cpu_info[revision].flags & HAS_SCSI ? "yes" : "no", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/shadows.c linux.ac/arch/cris/kernel/shadows.c --- linux.vanilla/arch/cris/kernel/shadows.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/shadows.c Thu Apr 19 14:13:36 2001 @@ -1,20 +1,36 @@ -/* $Id: shadows.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $ +/* $Id: shadows.c,v 1.2 2001/03/15 14:25:16 bjornw Exp $ * - * Various Etrax shadow registers. Defines for these are in include/asm-etrax100/io.h + * Various shadow registers. Defines for these are in include/asm-etrax100/io.h */ -#include +/* Shadows for internal Etrax-registers */ + +unsigned long genconfig_shadow; +unsigned long port_g_data_shadow; +unsigned char port_pa_dir_shadow; +unsigned char port_pa_data_shadow; +unsigned char port_pb_i2c_shadow; +unsigned char port_pb_config_shadow; +unsigned char port_pb_dir_shadow; +unsigned char port_pb_data_shadow; +unsigned long r_timer_ctrl_shadow; + +/* Shadows for external I/O port registers. + * These are only usable if there actually IS a latch connected + * to the corresponding external chip-select pin. + * + * A common usage is that CSP0 controls LED's and CSP4 video chips. + */ + +unsigned long port_cse1_shadow; +unsigned long port_csp0_shadow; +unsigned long port_csp4_shadow; + +/* Corresponding addresses for the ports. + * These are initialized in arch/cris/mm/init.c using ioremap. + */ + +volatile unsigned long *port_cse1_addr; +volatile unsigned long *port_csp0_addr; +volatile unsigned long *port_csp4_addr; -unsigned long genconfig_shadow = 42; -unsigned long port_g_data_shadow = 42; -unsigned char port_pa_dir_shadow = 42; -unsigned char port_pa_data_shadow = 42; -unsigned char port_pb_i2c_shadow = 42; -unsigned char port_pb_config_shadow = 42; -unsigned char port_pb_dir_shadow = 42; -unsigned char port_pb_data_shadow = 42; -unsigned long r_timer_ctrl_shadow = 42; - -#ifdef CONFIG_ETRAX_90000000_LEDS -unsigned long port_90000000_shadow = 42; -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/signal.c linux.ac/arch/cris/kernel/signal.c --- linux.vanilla/arch/cris/kernel/signal.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/signal.c Thu Apr 19 14:13:36 2001 @@ -36,11 +36,11 @@ /* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */ /* manipulate regs so that upon return, it will be re-executed */ +/* We rely on that pc points to the instruction after "break 13", so the + * library must never do strange things like putting it in a delay slot. + */ #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; -int sys_wait4(pid_t pid, unsigned long *stat_addr, - int options, unsigned long *ru); - int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) @@ -79,12 +79,14 @@ } /* - * Atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. Define + * dummy arguments to be able to reach the regs argument. (Note that this + * arrangement relies on old_sigset_t occupying one register.) */ int -sys_sigsuspend(old_sigset_t mask) +sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, + long srp, struct pt_regs *regs) { - struct pt_regs * regs = (struct pt_regs *)current_regs(); sigset_t saveset; mask &= _BLOCKABLE; @@ -103,10 +105,13 @@ } } +/* Define dummy arguments to be able to reach the regs argument. (Note that + * this arrangement relies on size_t occupying one register.) + */ int -sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, + long mof, long srp, struct pt_regs *regs) { - struct pt_regs * regs = (struct pt_regs *)current_regs(); sigset_t saveset, newset; /* XXX: Don't preclude handling different sized sigset_t's. */ @@ -228,9 +233,11 @@ return 1; } -asmlinkage int sys_sigreturn(void) +/* Define dummy arguments to be able to reach the regs argument. */ + +asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, + long srp, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *)current_regs(); struct sigframe *frame = (struct sigframe *)rdusp(); sigset_t set; @@ -268,9 +275,11 @@ return 0; } -asmlinkage int sys_rt_sigreturn(void) +/* Define dummy arguments to be able to reach the regs argument. */ + +asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, + long mof, long srp, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *)current_regs(); struct rt_sigframe *frame = (struct rt_sigframe *)rdusp(); sigset_t set; stack_t st; @@ -391,9 +400,8 @@ } else { /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; - /* This is movu.w __NR_sigreturn, r1; break 13; */ - /* TODO: check byteorder */ - err |= __put_user(0x1c5f, (short *)(frame->retcode+0)); + /* This is movu.w __NR_sigreturn, r9; break 13; */ + err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(0xe93d, (short *)(frame->retcode+4)); } @@ -453,9 +461,9 @@ } else { /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; - /* This is movu.w __NR_sigreturn, r1; break 13; */ + /* This is movu.w __NR_sigreturn, r9; break 13; */ /* TODO: check byteorder */ - err |= __put_user(0x1c5f, (short *)(frame->retcode+0)); + err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(0xe93d, (short *)(frame->retcode+4)); } @@ -538,7 +546,14 @@ * 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. + * + * Also note that the regs structure given here as an argument, is the latest + * pushed pt_regs. It may or may not be the same as the first pushed registers + * when the initial usermode->kernelmode transition took place. Therefore + * we can use user_mode(regs) to see if we came directly from kernel or user + * mode below. */ + int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/sys_cris.c linux.ac/arch/cris/kernel/sys_cris.c --- linux.vanilla/arch/cris/kernel/sys_cris.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/kernel/sys_cris.c Thu Apr 19 14:13:36 2001 @@ -1,6 +1,6 @@ -/* $Id: sys_cris.c,v 1.3 2000/08/02 13:59:02 bjornw Exp $ +/* $Id: sys_cris.c,v 1.7 2001/04/17 11:52:15 orjanf Exp $ * - * linux/arch/cris/kernel/sys_etrax.c + * linux/arch/cris/kernel/sys_cris.c * * This file contains various random system calls that * have a non-standard calling sequence on some platforms. @@ -97,10 +97,22 @@ return error; } -asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot, - int flags, int fd, off_t offset) -{ - return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +asmlinkage unsigned long old_mmap(unsigned long *args) +{ + unsigned long buffer[6]; + int err = -EFAULT; + + if (copy_from_user(&buffer, args, sizeof(buffer))) + goto out; + + err = -EINVAL; + if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */ + goto out; + + err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5] >> PAGE_SHIFT); +out: + return err; } asmlinkage long @@ -165,20 +177,13 @@ case MSGCTL: return sys_msgctl (first, second, (struct msqid_ds *) ptr); - 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 SHMAT: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } case SHMDT: return sys_shmdt ((char *)ptr); case SHMGET: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/kernel/traps.c linux.ac/arch/cris/kernel/traps.c --- linux.vanilla/arch/cris/kernel/traps.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/kernel/traps.c Thu Apr 19 14:13:36 2001 @@ -1,16 +1,18 @@ -/* $Id: traps.c,v 1.3 2000/10/04 16:50:06 bjornw Exp $ +/* $Id: traps.c,v 1.11 2001/04/04 09:43:31 orjanf Exp $ * * linux/arch/cris/traps.c * - * Etrax100 does not have any hardware traps, only IRQ's, which we setup - * in irq.c instead. Here we just define the die_if_kernel Oops'er. - * - * Copyright (C) 2000 Axis Communications AB + * Here we handle the break vectors not used by the system call + * mechanism, as well as some general stack/register dumping + * things. + * + * Copyright (C) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen * */ +#include #include #include #include @@ -35,14 +37,17 @@ #define MODULE_RANGE (8*1024*1024) -void show_stack(unsigned long *sp) +void +show_stack(unsigned long *sp) { unsigned long *stack, addr, module_start, module_end; int i; extern char _stext, _etext; - // debugging aid: "show_stack(NULL);" prints the - // back trace for this cpu. + /* + * debugging aid: "show_stack(NULL);" prints the + * back trace for this cpu. + */ if(sp == NULL) sp = (unsigned long*)rdsp(); @@ -86,7 +91,8 @@ #if 0 /* displays a short stack trace */ -int show_stack() +int +show_stack() { unsigned long *sp = (unsigned long *)rdusp(); int i; @@ -97,12 +103,13 @@ } #endif -void show_registers(struct pt_regs * regs) +void +show_registers(struct pt_regs * regs) { unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx\n", - regs->irp, regs->srp, regs->dccr, usp ); + printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n", + regs->irp, regs->srp, regs->dccr, usp, regs->mof ); printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", @@ -114,7 +121,7 @@ printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); - // TODO, fix in_kernel detection + /* TODO, fix in_kernel detection */ #if 0 /* @@ -145,9 +152,8 @@ #endif } - - -void die_if_kernel(const char * str, struct pt_regs * regs, long err) +void +die_if_kernel(const char * str, struct pt_regs * regs, long err) { if(user_mode(regs)) return; @@ -160,8 +166,8 @@ do_exit(SIGSEGV); } -void __init trap_init(void) +void __init +trap_init(void) { - - + /* Nothing needs to be done */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/checksum.S linux.ac/arch/cris/lib/checksum.S --- linux.vanilla/arch/cris/lib/checksum.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/lib/checksum.S Tue Apr 10 18:05:25 2001 @@ -1,16 +1,21 @@ - ;; $Id: checksum.S,v 1.1 2000/07/10 16:25:21 bjornw Exp $ - ;; A fast checksum routine using movem - ;; Copyright (c) 1998 Bjorn Wesen/Axis Communications AB +/* $Id: checksum.S,v 1.4 2001/02/19 11:11:33 bjornw Exp $ + * A fast checksum routine using movem + * Copyright (c) 1998-2001 Axis Communications AB + * + * csum_partial(const unsigned char * buff, int len, unsigned int sum) + */ - ;; csum_partial(const unsigned char * buff, int len, unsigned int sum) - .globl _csum_partial _csum_partial: + ;; r10 - src + ;; r11 - length + ;; r12 - checksum + ;; check for breakeven length between movem and normal word looping versions cmpu.w 80,r11 - bcs no_movem + blo word_loop nop ;; need to save the registers we use below in the movem loop @@ -21,10 +26,6 @@ ;; do a movem checksum - ;; r10 - src - ;; r11 - length - ;; r12 - checksum - subq 10*4,r11 ; update length for the first loop mloop: movem [r10+],r9 ; read 10 longwords @@ -65,23 +66,30 @@ addq 10*4,r11 ; compensate for last loop underflowing length - ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below - - moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1 - lsrq 16,r1 - - move.d r12,r0 - lsrq 16,r0 ; r0 = checksum >> 16 - and.d r1,r12 ; checksum = checksum & 0xffff - add.d r0,r12 ; checksum += r0 - move.d r12,r0 ; do the same again, maybe we got a carry last add - lsrq 16,r0 - and.d r1,r12 - add.d r0,r12 - movem [sp+],r8 ; restore regs -no_movem: +word_loop: + ;; only fold if there is anything to fold. + + cmpq 0,r12 + beq no_fold + + ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below. + ;; r9 and r13 can be used as temporaries. + + moveq -1,r9 ; put 0xffff in r9, faster than move.d 0xffff,r9 + lsrq 16,r9 + + move.d r12,r13 + lsrq 16,r13 ; r13 = checksum >> 16 + and.d r9,r12 ; checksum = checksum & 0xffff + add.d r13,r12 ; checksum += r13 + move.d r12,r13 ; do the same again, maybe we got a carry last add + lsrq 16,r13 + and.d r9,r12 + add.d r13,r12 + +no_fold: cmpq 2,r11 blt no_words nop @@ -110,4 +118,3 @@ ret move.d r12, r10 - \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/checksumcopy.S linux.ac/arch/cris/lib/checksumcopy.S --- linux.vanilla/arch/cris/lib/checksumcopy.S Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/lib/checksumcopy.S Tue Apr 10 18:05:25 2001 @@ -1,19 +1,25 @@ - ;; $Id: checksumcopy.S,v 1.2 2000/08/08 16:57:31 bjornw Exp $ - ;; A fast checksum+copy routine using movem - ;; Copyright (c) 1998, 2000 Axis Communications AB - ;; - ;; Authors: Bjorn Wesen - ;; - ;; csum_partial_copy_nocheck(const char *src, char *dst, - ;; int len, unsigned int sum) +/* $Id: checksumcopy.S,v 1.4 2001/02/19 11:11:34 bjornw Exp $ + * A fast checksum+copy routine using movem + * Copyright (c) 1998, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen + * + * csum_partial_copy_nocheck(const char *src, char *dst, + * int len, unsigned int sum) + */ .globl _csum_partial_copy_nocheck _csum_partial_copy_nocheck: + ;; r10 - src + ;; r11 - dst + ;; r12 - length + ;; r13 - checksum + ;; check for breakeven length between movem and normal word looping versions cmpu.w 80,r12 - bcs no_movem + blo word_loop nop ;; need to save the registers we use below in the movem loop @@ -24,11 +30,6 @@ ;; do a movem copy and checksum - ;; r10 - src - ;; r11 - dst - ;; r12 - length - ;; r13 - checksum - subq 10*4,r12 ; update length for the first loop mloop: movem [r10+],r9 ; read 10 longwords @@ -61,6 +62,8 @@ ax addq 0,r13 + ax ; do it again, since we might have generated a carry + addq 0,r13 subq 10*4,r12 bge mloop @@ -68,23 +71,27 @@ addq 10*4,r12 ; compensate for last loop underflowing length + movem [sp+],r8 ; restore regs + +word_loop: + ;; only fold if there is anything to fold. + + cmpq 0,r13 + beq no_fold + ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below + ;; r9 can be used as temporary. - moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1 - lsrq 16,r1 - - move.d r13,r0 - lsrq 16,r0 ; r0 = checksum >> 16 - and.d r1,r13 ; checksum = checksum & 0xffff - add.d r0,r13 ; checksum += r0 - move.d r13,r0 ; do the same again, maybe we got a carry last add - lsrq 16,r0 - and.d r1,r13 - add.d r0,r13 + move.d r13,r9 + lsrq 16,r9 ; r0 = checksum >> 16 + and.d 0xffff,r13 ; checksum = checksum & 0xffff + add.d r9,r13 ; checksum += r0 + move.d r13,r9 ; do the same again, maybe we got a carry last add + lsrq 16,r9 + and.d 0xffff,r13 + add.d r9,r13 - movem [sp+],r8 ; restore regs - -no_movem: +no_fold: cmpq 2,r12 blt no_words nop @@ -117,4 +124,4 @@ ret move.d r13, r10 - \ No newline at end of file + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/dram_init.S linux.ac/arch/cris/lib/dram_init.S --- linux.vanilla/arch/cris/lib/dram_init.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/lib/dram_init.S Thu Apr 19 14:13:36 2001 @@ -0,0 +1,161 @@ +/* $Id: dram_init.S,v 1.7 2001/04/18 12:05:39 bjornw Exp $ + * + * DRAM/SDRAM initialization - alter with care + * This file is intended to be included from other assembler files + * + * Note: This file may not modify r9 because r9 is used to carry + * information from the decompresser to the kernel + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Mikael Starvik (starvik@axis.com) + * + * $Log: dram_init.S,v $ + * Revision 1.7 2001/04/18 12:05:39 bjornw + * Fixed comments, and explicitely include config.h to be sure its there + * + * Revision 1.6 2001/04/10 06:20:16 starvik + * Delay should be 200us, not 200ns + * + * Revision 1.5 2001/04/09 06:01:13 starvik + * Added support for 100 MHz SDRAMs + * + * Revision 1.4 2001/03/26 14:24:01 bjornw + * Namechange of some config options + * + * Revision 1.3 2001/03/23 08:29:41 starvik + * Corrected calculation of mrs_data + * + * Revision 1.2 2001/02/08 15:20:00 starvik + * Corrected SDRAM initialization + * Should now be included as inline + * + * Revision 1.1 2001/01/29 13:08:02 starvik + * Initial version + * This file should be included from all assembler files that needs to + * initialize DRAM/SDRAM. + * + */ + +/* Just to be certain the config file is included, we include it here + * explicitely instead of depending on it being included in the file that + * uses this code. + */ + +#include + + +#ifndef CONFIG_SVINTO_SIM + move.d CONFIG_ETRAX_DEF_R_WAITSTATES, r0 + move.d r0, [R_WAITSTATES] + + move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, r0 + move.d r0, [R_BUS_CONFIG] + +#ifndef CONFIG_ETRAX_SDRAM + move.d CONFIG_ETRAX_DEF_R_DRAM_CONFIG, r0 + move.d r0, [R_DRAM_CONFIG] + + move.d CONFIG_ETRAX_DEF_R_DRAM_TIMING, r0 + move.d r0, [R_DRAM_TIMING] +#else + ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization + + ; Bank configuration + move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r0 + move.d r0, [R_SDRAM_CONFIG] + + ; Calculate value of mrs_data + ; CAS latency = 2 && bus_width = 32 => 0x40 + ; CAS latency = 3 && bus_width = 32 => 0x60 + ; CAS latency = 2 && bus_width = 16 => 0x20 + ; CAS latency = 3 && bus_width = 16 => 0x30 + + move.d 0x40, r2 ; Assume 32 bits and CAS latency = 2 + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1 + move.d r1, r3 + and.d 0x03, r1 ; Get CAS latency + and.d 0x1000, r3 ; 50 or 100 MHz? + beq speed_50 + nop +speed_100: + cmp.d 0x00, r1 ; CAS latency = 2? + beq bw_check + nop + or.d 0x20, r2 ; CAS latency = 3 + ba bw_check + nop +speed_50: + cmp.d 0x01, r1 ; CAS latency = 2? + beq bw_check + nop + or.d 0x20, r2 ; CAS latency = 3 +bw_check: + move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r1 + and.d 0x800000, r1 ; DRAM width is bit 23 + bne set_timing + nop + lsrq 1, r2 ; 16 bits. Shift down value. + + ; Set timing parameters. Starts master clock +set_timing: + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1 + and.d 0x8000f9ff, r1 ; Make sure mrs data and command is 0 + or.d 0x80000000, r1 ; Make sure sdram enable bit is set + move.d r1, r5 + or.d 0x0000c000, r1 ; ref = disable + lslq 16, r2 ; mrs data starts at bit 16 + or.d r2, r1 + move.d r1, [R_SDRAM_TIMING] + + ; Wait 200us + move.d 10000, r2 +sdram_loop: + bne sdram_loop + subq 1, r2 + + ; Issue initialization command sequence + move.d sdram_commands_start, r2 + move.d sdram_commands_end, r3 +command_loop: + clear.d r4 + move.b [r2+], r4 + lslq 9, r4 ; Command starts at bit 9 + or.d r1, r4 + move.d r4, [R_SDRAM_TIMING] + nop ; Wait five nop cycles between each command + nop + nop + nop + nop + cmp.d r2, r3 + bne command_loop + nop + move.d r5, [R_SDRAM_TIMING] + ba sdram_commands_end + nop + +sdram_commands_start: + .byte 3 ; Precharge + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 2 ; refresh + .byte 0 ; nop + .byte 1 ; mrs + .byte 0 ; nop +sdram_commands_end: +#endif +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/hw_settings.S linux.ac/arch/cris/lib/hw_settings.S --- linux.vanilla/arch/cris/lib/hw_settings.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/lib/hw_settings.S Thu Apr 19 14:13:36 2001 @@ -0,0 +1,61 @@ + ;; $Id: hw_settings.S,v 1.2 2001/04/03 11:11:09 starvik Exp $ + ;; + ;; This table is used by some tools to extract hardware parameters. + ;; The table should be included in the kernel and the decompressor. + ;; Don't forget to update the tools if you change this table. + ;; + ;; Copyright (C) 2001 Axis Communications AB + ;; + ;; Authors: Mikael Starvik (starvik@axis.com) + + +#define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \ + (CONFIG_ETRAX_DEF_R_PORT_PA_DATA)) +#define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \ + (CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \ + (CONFIG_ETRAX_DEF_R_PORT_PB_DATA)) + + .ascii "HW_PARAM_MAGIC" ; Magic number + .dword 0xc0004000 ; Kernel start address + + ; Debug port +#ifdef CONFIG_ETRAX_DEBUG_PORT0 + .dword 0 +#elif defined(CONFIG_ETRAX_DEBUG_PORT1) + .dword 1 +#elif defined(CONFIG_ETRAX_DEBUG_PORT2) + .dword 2 +#elif defined(CONFIG_ETRAX_DEBUG_PORT3) + .dword 3 +#else + .dword 4 ; No debug +#endif + + ; SDRAM or EDO DRAM? +#ifdef CONFIG_ETRAX_SDRAM + .dword 1 +#else + .dword 0 +#endif + + ; Register values + .dword R_WAITSTATES + .dword CONFIG_ETRAX_DEF_R_WAITSTATES + .dword R_BUS_CONFIG + .dword CONFIG_ETRAX_DEF_R_BUS_CONFIG +#ifdef CONFIG_ETRAX_SDRAM + .dword R_SDRAM_CONFIG + .dword CONFIG_ETRAX_DEF_R_SDRAM_CONFIG + .dword R_SDRAM_TIMING + .dword CONFIG_ETRAX_DEF_R_SDRAM_TIMING +#else + .dword R_DRAM_CONFIG + .dword CONFIG_ETRAX_DEF_R_DRAM_CONFIG + .dword R_DRAM_TIMING + .dword CONFIG_ETRAX_DEF_R_DRAM_TIMING +#endif + .dword R_PORT_PA_SET + .dword PA_SET_VALUE + .dword R_PORT_PB_SET + .dword PB_SET_VALUE + .dword 0 ; No more register values diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/memset.c linux.ac/arch/cris/lib/memset.c --- linux.vanilla/arch/cris/lib/memset.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/lib/memset.c Thu Apr 19 14:13:36 2001 @@ -27,6 +27,8 @@ /*# */ /*#-------------------------------------------------------------------------*/ +#include + /* No, there's no macro saying 12*4, since it is "hard" to get it into the asm in a good way. Thus better to expose the problem everywhere. */ @@ -39,7 +41,7 @@ void *memset(void *pdst, int c, - unsigned int plen) + size_t plen) { /* Ok. Now we want the parameters put in special registers. Make sure the compiler is able to make something useful of this. */ @@ -54,7 +56,12 @@ /* Ugh. This is fragile at best. Check with newer GCC releases, if they compile cascaded "x |= x << 8" sanely! */ - __asm__("movu.b %0,r13\n\tlslq 8,r13\n\tmove.b %0,r13\n\tmove.d r13,%0\n\tlslq 16,r13\n\tor.d r13,%0" + __asm__("movu.b %0,r13\n\t" + "lslq 8,r13\n\t" + "move.b %0,r13\n\t" + "move.d r13,%0\n\t" + "lslq 16,r13\n\t" + "or.d r13,%0" : "=r" (lc) : "0" (lc) : "r13"); { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/lib/string.c linux.ac/arch/cris/lib/string.c --- linux.vanilla/arch/cris/lib/string.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/lib/string.c Thu Apr 19 14:13:36 2001 @@ -31,9 +31,11 @@ /*# */ /*#-------------------------------------------------------------------------*/ +#include + void *memcpy(void *pdst, const void *psrc, - unsigned int pn) + size_t pn) { /* Ok. Now we want the parameters put in special registers. Make sure the compiler is able to make something useful of this. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/Makefile linux.ac/arch/cris/mm/Makefile --- linux.vanilla/arch/cris/mm/Makefile Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/mm/Makefile Tue Apr 10 18:05:25 2001 @@ -8,6 +8,6 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -obj-y := init.o fault.o tlb.o extable.o +obj-y := init.o fault.o tlb.o extable.o ioremap.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/extable.c linux.ac/arch/cris/mm/extable.c --- linux.vanilla/arch/cris/mm/extable.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/mm/extable.c Thu Apr 19 14:13:36 2001 @@ -37,8 +37,7 @@ #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; + return search_one_table(_start___ex_table, _stop___ex_table-1, addr); #else /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/fault.c linux.ac/arch/cris/mm/fault.c --- linux.vanilla/arch/cris/mm/fault.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/cris/mm/fault.c Thu Apr 19 14:13:36 2001 @@ -1,11 +1,23 @@ /* * linux/arch/cris/mm/fault.c * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.12 2001/04/04 10:51:14 bjornw + * mmap_sem is grabbed for reading + * + * Revision 1.11 2001/03/23 07:36:07 starvik + * Corrected according to review remarks + * + * Revision 1.10 2001/03/21 16:10:11 bjornw + * CRIS_FRAME_FIXUP not needed anymore, use FRAME_NORMAL + * + * Revision 1.9 2001/03/05 13:22:20 bjornw + * Spell-fix and fix in vmalloc_fault handling + * * Revision 1.8 2000/11/22 14:45:31 bjornw * * 2.4.0-test10 removed the set_pgdir instantaneous kernel global mapping * into all processes. Instead we fill in the missing PTE entries on demand. @@ -67,12 +79,12 @@ address = cause & PAGE_MASK; /* get faulting address */ - page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); + D(page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause)); + D(acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause)); + D(inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause)); + D(index = IO_EXTRACT(R_TLB_SELECT, index, select)); miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); - acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); - inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); - index = IO_EXTRACT(R_TLB_SELECT, index, select); D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, " "idx %d pid %d\n", @@ -308,16 +320,25 @@ */ if ((fixup = search_exception_table(regs->irp)) != 0) { + /* Adjust the instruction pointer in the stackframe */ + regs->irp = fixup; - regs->frametype = CRIS_FRAME_FIXUP; + + /* We do not want to return by restoring the CPU-state + * anymore, so switch frame-types (see ptrace.h) + */ + + regs->frametype = CRIS_FRAME_NORMAL; + D(printk("doing fixup to 0x%x\n", fixup)); return; } -/* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) (address) < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/init.c linux.ac/arch/cris/mm/init.c --- linux.vanilla/arch/cris/mm/init.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/mm/init.c Thu Apr 19 14:13:36 2001 @@ -2,11 +2,38 @@ * linux/arch/cris/mm/init.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.23 2001/04/04 14:35:40 bjornw + * * Removed get_pte_slow and friends (2.4.3 change) + * * Removed bad_pmd handling (2.4.3 change) + * + * Revision 1.22 2001/04/04 13:38:04 matsfg + * Moved ioremap to a separate function instead + * + * Revision 1.21 2001/03/27 09:28:33 bjornw + * ioremap used too early - lets try it in mem_init instead + * + * Revision 1.20 2001/03/23 07:39:21 starvik + * Corrected according to review remarks + * + * Revision 1.19 2001/03/15 14:25:17 bjornw + * More general shadow registers and ioremaped addresses for external I/O + * + * Revision 1.18 2001/02/23 12:46:44 bjornw + * * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached + * flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O + * is mapped straight over (for !CRIS_LOW_MAP the uncached flash is still 0xe) + * + * Revision 1.17 2001/02/22 15:05:21 bjornw + * Map 0x9 straight over during LOW_MAP to allow for memory mapped LEDs + * + * Revision 1.16 2001/02/22 15:02:35 bjornw + * Map 0xc straight over during LOW_MAP to allow for memory mapped I/O + * * Revision 1.15 2001/01/10 21:12:10 bjornw * loops_per_sec -> loops_per_jiffy * @@ -57,6 +84,7 @@ #include #include #include +#include static unsigned long totalram_pages; @@ -68,128 +96,13 @@ extern void show_net_buffers(void); extern void tlb_init(void); -/* - * empty_bad_page is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode - * unused etc.. - * - * the main point is that when a page table error occurs, we want to get - * out of the kernel safely before killing the process, so we need something - * to feed the MMU with when the fault occurs even if we don't have any - * real PTE's or page tables. - * - * empty_bad_page_table is the accompanying page-table: it is initialized - * to point to empty_bad_page writable-shared entries. - * - * empty_zero_page is a special page that is used for zero-initialized - * data and COW. - */ -unsigned long empty_bad_page_table; -unsigned long empty_bad_page; unsigned long empty_zero_page; -pte_t * __bad_pagetable(void) -{ - /* somehow it is enough to just clear it and not fill it with - * bad page PTE's... - */ - memset((void *)empty_bad_page_table, 0, PAGE_SIZE); - - return (pte_t *) empty_bad_page_table; -} - -pte_t __bad_page(void) -{ - - /* clear the empty_bad_page page. this should perhaps be - * a more simple inlined loop like it is on the other - * architectures. - */ - - memset((void *)empty_bad_page, 0, PAGE_SIZE); - - return pte_mkdirty(__mk_pte((void *)empty_bad_page, PAGE_SHARED)); -} - -static pte_t * get_bad_pte_table(void) -{ - pte_t *empty_bad_pte_table = (pte_t *)empty_bad_page_table; - pte_t v; - int i; - - v = __bad_page(); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set(pmd, get_bad_pte_table()); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set_kernel(pmd, get_bad_pte_table()); -} - -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(pte); - pmd_set_kernel(pmd, pte); - return pte + offset; - } - pmd_set_kernel(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_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(pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -#ifndef CONFIG_NO_PGT_CACHE -struct pgtable_cache_struct quicklists; - /* trim the page-table cache if necessary */ -int do_check_pgt_cache(int low, int high) +int +do_check_pgt_cache(int low, int high) { int freed = 0; @@ -200,25 +113,20 @@ freed++; } if(pmd_quicklist) { - free_pmd_slow(get_pmd_fast()); + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); freed++; } if(pte_quicklist) { - free_pte_slow(get_pte_fast()); - freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; } } while(pgtable_cache_size > low); } return freed; } -#else -int do_check_pgt_cache(int low, int high) -{ - return 0; -} -#endif -void show_mem(void) +void +show_mem(void) { int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0; int shared = 0; @@ -276,27 +184,66 @@ /* see README.mm for details on the KSEG setup */ -#ifdef CONFIG_CRIS_LOW_MAP +#ifndef CONFIG_CRIS_LOW_MAP + /* This code is for the corrected Etrax-100 LX version 2... */ + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ + IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_9, page ) | + IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_7, page ) | + IO_STATE(R_MMU_KSEG, seg_6, page ) | + IO_STATE(R_MMU_KSEG, seg_5, page ) | + IO_STATE(R_MMU_KSEG, seg_4, page ) | + IO_STATE(R_MMU_KSEG, seg_3, page ) | + IO_STATE(R_MMU_KSEG, seg_2, page ) | + IO_STATE(R_MMU_KSEG, seg_1, page ) | + IO_STATE(R_MMU_KSEG, seg_0, page ) ); + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#else /* Etrax-100 LX version 1 has a bug so that we cannot map anything * across the 0x80000000 boundary, so we need to shrink the user-virtual * area to 0x50000000 instead of 0xb0000000 and map things slightly * different. The unused areas are marked as paged so that we can catch * freak kernel accesses there. * - * The Juliette chip is mapped at 0xa so we pass that segment straight + * The ARTPEC chip is mapped at 0xa so we pass that segment straight * through. We cannot vremap it because the vmalloc area is below 0x8 * and Juliette needs an uncached area above 0x8. + * + * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards. + * We map them straight over in LOW_MAP, but use vremap in LX version 2. */ *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, page ) | - IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_e, page ) | IO_STATE(R_MMU_KSEG, seg_d, page ) | - IO_STATE(R_MMU_KSEG, seg_c, page ) | + IO_STATE(R_MMU_KSEG, seg_c, page ) | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* Juliette etc. */ - IO_STATE(R_MMU_KSEG, seg_9, page ) | - IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ + IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ + IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ @@ -307,13 +254,13 @@ IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | @@ -323,44 +270,7 @@ IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#else - /* This code is for the hopefully corrected Etrax-100 LX version 2... */ - - *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ - IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ - IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ - IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ - IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_9, page ) | - IO_STATE(R_MMU_KSEG, seg_8, page ) | - IO_STATE(R_MMU_KSEG, seg_7, page ) | - IO_STATE(R_MMU_KSEG, seg_6, page ) | - IO_STATE(R_MMU_KSEG, seg_5, page ) | - IO_STATE(R_MMU_KSEG, seg_4, page ) | - IO_STATE(R_MMU_KSEG, seg_3, page ) | - IO_STATE(R_MMU_KSEG, seg_2, page ) | - IO_STATE(R_MMU_KSEG, seg_1, page ) | - IO_STATE(R_MMU_KSEG, seg_0, page ) ); - - *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | - IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | - IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | - IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); - - *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#endif +#endif *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); @@ -379,8 +289,6 @@ * to a couple of allocated pages */ - empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); memset((void *)empty_zero_page, 0, PAGE_SIZE); @@ -398,6 +306,7 @@ */ free_area_init_node(0, 0, 0, zones_size, PAGE_OFFSET, 0); + } extern unsigned long loops_per_jiffy; /* init/main.c */ @@ -448,7 +357,7 @@ datasize >> 10, initsize >> 10 ); - + /* HACK alert - calculate a loops_per_usec for asm/delay.h here * since this is called just after calibrate_delay in init/main.c * but before places which use udelay. cannot be in time.c since @@ -460,9 +369,52 @@ return; } +/* Initialize remaps of some I/O-ports. This is designed to be callable + * multiple times from the drivers init-sections, because we don't know + * beforehand which driver will get initialized first. + */ + +void +init_ioremap(void) +{ + + /* Give the external I/O-port addresses their values */ + + static int initialized = 0; + + if( !initialized ) { + initialized++; + +#ifdef CONFIG_CRIS_LOW_MAP + /* Simply a linear map (see the KSEG map above in paging_init) */ + port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | + MEM_NON_CACHEABLE); + port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | + MEM_NON_CACHEABLE); + port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | + MEM_NON_CACHEABLE); +#else + /* Note that nothing blows up just because we do this remapping + * it's ok even if the ports are not used or connected + * to anything (or connected to a non-I/O thing) */ + port_cse1_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSE1_START | + MEM_NON_CACHEABLE), 16); + port_csp0_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP0_START | + MEM_NON_CACHEABLE), 16); + port_csp4_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP4_START | + MEM_NON_CACHEABLE), 16); +#endif + } +} + + /* free the pages occupied by initialization code */ -void free_initmem(void) +void +free_initmem(void) { #if 0 /* currently this is a bad idea since the cramfs image is catted onto @@ -483,7 +435,8 @@ #endif } -void si_meminfo(struct sysinfo *val) +void +si_meminfo(struct sysinfo *val) { int i; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/ioremap.c linux.ac/arch/cris/mm/ioremap.c --- linux.vanilla/arch/cris/mm/ioremap.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/cris/mm/ioremap.c Thu Apr 19 14:13:36 2001 @@ -0,0 +1,169 @@ +/* + * arch/cris/mm/ioremap.c + * + * Re-map IO memory to kernel address space so that we can access it. + * Needed for memory-mapped I/O devices mapped outside our normal DRAM + * window (that is, all memory-mapped I/O devices). + * + * (C) Copyright 1995 1996 Linus Torvalds + * CRIS-port by Axis Communications AB + */ + +#include +#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; + if (address >= end) + BUG(); + do { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE | + __WRITEABLE | _PAGE_GLOBAL | + _PAGE_KERNEL | flags))); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address && (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; + if (address >= end) + BUG(); + do { + pte_t * pte = pte_alloc(&init_mm, 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 && (address < end)); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + int error; + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + if (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; + if (!pmd) + break; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + break; + error = 0; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); + flush_tlb_all(); + return error; +} + +/* + * 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; + +#if 0 + /* TODO: Here we can put checks for driver-writer abuse... */ + + /* + * 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)) { + char *t_addr, *t_end; + struct page *page; + + t_addr = __va(phys_addr); + t_end = t_addr + (size - 1); + + for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) + if(!PageReserved(page)) + return NULL; + } +#endif + + /* + * 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, VM_IOREMAP); + 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 --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/cris/mm/tlb.c linux.ac/arch/cris/mm/tlb.c --- linux.vanilla/arch/cris/mm/tlb.c Fri Feb 9 00:32:44 2001 +++ linux.ac/arch/cris/mm/tlb.c Thu Apr 19 14:13:36 2001 @@ -288,7 +288,7 @@ /* clear the page_id map */ - for(i = 0; i < 64; i++) + for(i = 0; i < NUM_PAGEID; i++) page_id_map[i] = NULL; /* invalidate the entire TLB */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/Makefile linux.ac/arch/i386/Makefile --- linux.vanilla/arch/i386/Makefile Wed Jan 10 23:06:14 2001 +++ linux.ac/arch/i386/Makefile Sat Apr 14 02:08:52 2001 @@ -82,6 +82,10 @@ CFLAGS += -march=i586 endif +ifdef CONFIG_MCYRIXIII +CFLAGS += -march=i586 +endif + HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/boot/install.sh linux.ac/arch/i386/boot/install.sh --- linux.vanilla/arch/i386/boot/install.sh Tue Jan 3 11:57:26 1995 +++ linux.ac/arch/i386/boot/install.sh Tue Apr 3 17:54:29 2001 @@ -21,6 +21,7 @@ # User may have a custom install script +if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi # Default install - same as make zlilo diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/boot/setup.S linux.ac/arch/i386/boot/setup.S --- linux.vanilla/arch/i386/boot/setup.S Sat Jan 27 18:51:35 2001 +++ linux.ac/arch/i386/boot/setup.S Thu Apr 12 11:48:59 2001 @@ -18,7 +18,7 @@ * March 1993/June 1994 (Christoph.Niemann@linux.org) * * add APM BIOS checking by Stephen Rothwell, May 1994 - * (Stephen.Rothwell@canb.auug.org.au) + * (sfr@canb.auug.org.au) * * High load stuff, initrd support and position independency * by Hans Lermen & Werner Almesberger, February 1996 @@ -81,14 +81,9 @@ type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, # Bootlin, SYSLX, bootsect...) - # Else it is set by the loader: - # 0xTV: T=0 for LILO - # T=1 for Loadlin - # T=2 for bootsect-loader - # T=3 for SYSLX - # T=4 for ETHERBOOT - # V = version - + # See Documentation/i386/boot.txt for + # assigned ids + # flags, unused bits must be zero (RFU) bit within loadflags loadflags: LOADED_HIGH = 1 # If set, the kernel is loaded high @@ -228,8 +223,8 @@ # Move rest of setup code/data to here movw $2048, %di # four sectors loaded by LILO subw %si, %si - movw %cs, %ax # aka SETUPSEG - movw %ax, %es + pushw %cs + popw %es movw $SYSSEG, %ax movw %ax, %ds rep diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/config.in linux.ac/arch/i386/config.in --- linux.vanilla/arch/i386/config.in Mon Jan 8 21:27:56 2001 +++ linux.ac/arch/i386/config.in Sun Apr 22 01:15:26 2001 @@ -36,24 +36,31 @@ Pentium-III CONFIG_MPENTIUMIII \ Pentium-4 CONFIG_MPENTIUM4 \ K6/K6-II/K6-III CONFIG_MK6 \ - Athlon/K7 CONFIG_MK7 \ + Athlon/Duron/K7 CONFIG_MK7 \ Crusoe CONFIG_MCRUSOE \ Winchip-C6 CONFIG_MWINCHIPC6 \ Winchip-2 CONFIG_MWINCHIP2 \ - Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D" Pentium-Pro + Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ + CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro # # Define implied options from the CPU selection here # if [ "$CONFIG_M386" = "y" ]; then define_bool CONFIG_X86_CMPXCHG n + define_bool CONFIG_X86_XADD n define_int CONFIG_X86_L1_CACHE_SHIFT 4 + define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y + define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n else define_bool CONFIG_X86_WP_WORKS_OK y define_bool CONFIG_X86_INVLPG y define_bool CONFIG_X86_CMPXCHG y + define_bool CONFIG_X86_XADD y define_bool CONFIG_X86_BSWAP y define_bool CONFIG_X86_POPAD_OK y + define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n + define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y fi if [ "$CONFIG_M486" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 4 @@ -113,6 +120,13 @@ define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi +if [ "$CONFIG_MCYRIXIII" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_USE_3DNOW y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y +fi if [ "$CONFIG_MCRUSOE" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_TSC y @@ -121,18 +135,21 @@ define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y fi if [ "$CONFIG_MWINCHIP2" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y fi if [ "$CONFIG_MWINCHIP3D" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_OOSTORE y fi tristate 'Toshiba Laptop support' CONFIG_TOSHIBA @@ -156,10 +173,13 @@ bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP if [ "$CONFIG_SMP" != "y" ]; then - bool 'APIC and IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC + bool 'APIC support on uniprocessors' CONFIG_X86_UP_APIC + dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC + if [ "$CONFIG_X86_UP_APIC" = "y" ]; then + define_bool CONFIG_X86_LOCAL_APIC y + fi if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then define_bool CONFIG_X86_IO_APIC y - define_bool CONFIG_X86_LOCAL_APIC y fi fi @@ -285,9 +305,11 @@ fi endmenu +source drivers/message/fusion/Config.in + source drivers/ieee1394/Config.in -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -364,6 +386,16 @@ mainmenu_option next_comment comment 'Kernel hacking' -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL + +if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + + +bool ' Debug memory allocations' CONFIG_DEBUG_SLAB +bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT +bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK +bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE +fi + endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/defconfig linux.ac/arch/i386/defconfig --- linux.vanilla/arch/i386/defconfig Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/defconfig Thu Apr 19 22:37:00 2001 @@ -5,6 +5,8 @@ CONFIG_ISA=y # CONFIG_SBUS is not set CONFIG_UID16=y +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y # # Code maturity level options @@ -35,9 +37,11 @@ # CONFIG_MWINCHIPC6 is not set # CONFIG_MWINCHIP2 is not set # CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y CONFIG_X86_BSWAP=y CONFIG_X86_POPAD_OK=y CONFIG_X86_L1_CACHE_SHIFT=5 @@ -108,6 +112,7 @@ # CONFIG_PNP=y CONFIG_ISAPNP=y +CONFIG_PNPBIOS=y # # Block devices @@ -383,6 +388,9 @@ # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -561,6 +569,7 @@ # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +CONFIG_TMPFS=y # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -720,4 +729,5 @@ # # Kernel hacking # +CONFIG_DEBUG_IOVIRT=y # CONFIG_MAGIC_SYSRQ is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/Makefile linux.ac/arch/i386/kernel/Makefile --- linux.vanilla/arch/i386/kernel/Makefile Fri Dec 29 22:35:47 2000 +++ linux.ac/arch/i386/kernel/Makefile Tue Apr 3 17:54:29 2001 @@ -30,15 +30,20 @@ endif endif -obj-$(CONFIG_MCA) += mca.o -obj-$(CONFIG_MTRR) += mtrr.o -obj-$(CONFIG_X86_MSR) += msr.o -obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o -obj-$(CONFIG_X86_LOCAL_APIC) += apic.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o +obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_MTRR) += mtrr.o +obj-$(CONFIG_X86_MSR) += msr.o +obj-$(CONFIG_X86_CPUID) += cpuid.o +obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o +obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o +obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/apic.c linux.ac/arch/i386/kernel/apic.c --- linux.vanilla/arch/i386/kernel/apic.c Tue Dec 5 20:43:48 2000 +++ linux.ac/arch/i386/kernel/apic.c Tue Apr 3 17:54:30 2001 @@ -9,6 +9,7 @@ * and Rolf G. Tews * for testing these extensively. * Maciej W. Rozycki : Various updates and fixes. + * Mikael Pettersson : Power Management for UP-APIC. */ #include @@ -23,11 +24,15 @@ #include #include +#include #include #include #include #include +/* Using APIC to generate smp_local_timer_interrupt? */ +int using_apic_timer = 0; + int prof_multiplier[NR_CPUS] = { 1, }; int prof_old_multiplier[NR_CPUS] = { 1, }; int prof_counter[NR_CPUS] = { 1, }; @@ -89,10 +94,10 @@ */ clear_local_APIC(); /* - * PIC mode, enable symmetric IO mode in the IMCR, - * i.e. connect BSP's local APIC to INT and NMI lines. + * PIC mode, enable APIC mode in the IMCR, i.e. + * connect BSP's local APIC to INT and NMI lines. */ - printk("leaving PIC mode, enabling symmetric IO mode.\n"); + printk("leaving PIC mode, enabling APIC mode.\n"); outb(0x70, 0x22); outb(0x01, 0x23); } @@ -107,7 +112,7 @@ * interrupts, including IPIs, won't work beyond * this point! The only exception are INIT IPIs. */ - printk("disabling symmetric IO mode, entering PIC mode.\n"); + printk("disabling APIC mode, entering PIC mode.\n"); outb(0x70, 0x22); outb(0x00, 0x23); } @@ -124,7 +129,7 @@ * for 82489DX!). */ value = apic_read(APIC_SPIV); - value &= ~(1<<8); + value &= ~APIC_SPIV_APIC_ENABLED; apic_write_around(APIC_SPIV, value); } @@ -203,6 +208,48 @@ extern void __error_in_apic_c (void); +/* + * An initial setup of the virtual wire mode. + */ +void __init init_bsp_APIC(void) +{ + unsigned long value, ver; + + /* + * Don't do the setup now if we have a SMP BIOS as the + * through-I/O-APIC virtual wire mode might be active. + */ + if (smp_found_config || !cpu_has_apic) + return; + + value = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(value); + + /* + * Do not trust the local APIC being empty at bootup. + */ + clear_local_APIC(); + + /* + * Enable APIC. + */ + value = apic_read(APIC_SPIV); + value &= ~APIC_VECTOR_MASK; + value |= APIC_SPIV_APIC_ENABLED; + value |= APIC_SPIV_FOCUS_DISABLED; + value |= SPURIOUS_APIC_VECTOR; + apic_write_around(APIC_SPIV, value); + + /* + * Set up the virtual wire mode. + */ + apic_write_around(APIC_LVT0, APIC_DM_EXTINT); + value = APIC_DM_NMI; + if (!APIC_INTEGRATED(ver)) /* 82489DX */ + value |= APIC_LVT_LEVEL_TRIGGER; + apic_write_around(APIC_LVT1, value); +} + void __init setup_local_APIC (void) { unsigned long value, ver, maxlvt; @@ -255,7 +302,7 @@ /* * Enable APIC */ - value |= (1<<8); + value |= APIC_SPIV_APIC_ENABLED; /* * Some unknown Intel IO/APIC (or APIC) errata is biting us with @@ -270,12 +317,18 @@ * PCI Ne2000 networking cards and PII/PIII processors, dual * BX chipset. ] */ -#if 0 + /* + * Actually disabling the focus CPU check just makes the hang less + * frequent as it makes the interrupt distributon model be more + * like LRU than MRU (the short-term load is more even across CPUs). + * See also the comment in end_level_ioapic_irq(). --macro + */ +#if 1 /* Enable focus processor (bit==0) */ - value &= ~(1<<9); + value &= ~APIC_SPIV_FOCUS_DISABLED; #else /* Disable focus processor (bit==1) */ - value |= (1<<9); + value |= APIC_SPIV_FOCUS_DISABLED; #endif /* * Set spurious IRQ vector @@ -332,24 +385,250 @@ printk("ESR value after enabling vector: %08lx\n", value); } else printk("No ESR for 82489DX.\n"); + + if (nmi_watchdog == NMI_LOCAL_APIC) + setup_apic_nmi_watchdog(); } -void __init init_apic_mappings(void) +#ifdef CONFIG_PM + +#include +#include + +static struct { + /* 'active' is true if the local APIC was enabled by us and + not the BIOS; this signifies that we are also responsible + for disabling it before entering apm/acpi suspend */ + int active; + /* 'perfctr_pmdev' is here because the current (2.4.1) PM + callback system doesn't handle hierarchical dependencies */ + struct pm_dev *perfctr_pmdev; + /* r/w apic fields */ + unsigned int apic_id; + unsigned int apic_taskpri; + unsigned int apic_ldr; + unsigned int apic_dfr; + unsigned int apic_spiv; + unsigned int apic_lvtt; + unsigned int apic_lvtpc; + unsigned int apic_lvt0; + unsigned int apic_lvt1; + unsigned int apic_lvterr; + unsigned int apic_tmict; + unsigned int apic_tdcr; +} apic_pm_state; + +static void apic_pm_suspend(void *data) { - unsigned long apic_phys; + unsigned int l, h; + unsigned long flags; - if (smp_found_config) { - apic_phys = mp_lapic_addr; - } else { + if (apic_pm_state.perfctr_pmdev) + pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data); + apic_pm_state.apic_id = apic_read(APIC_ID); + apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); + apic_pm_state.apic_ldr = apic_read(APIC_LDR); + apic_pm_state.apic_dfr = apic_read(APIC_DFR); + apic_pm_state.apic_spiv = apic_read(APIC_SPIV); + apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); + apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); + apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); + apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); + apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); + apic_pm_state.apic_tmict = apic_read(APIC_TMICT); + apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); + __save_flags(flags); + __cli(); + disable_local_APIC(); + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_ENABLE; + wrmsr(MSR_IA32_APICBASE, l, h); + __restore_flags(flags); +} + +static void apic_pm_resume(void *data) +{ + unsigned int l, h; + unsigned long flags; + + __save_flags(flags); + __cli(); + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_BASE; + l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; + wrmsr(MSR_IA32_APICBASE, l, h); + apic_write(APIC_ID, apic_pm_state.apic_id); + apic_write(APIC_DFR, apic_pm_state.apic_dfr); + apic_write(APIC_LDR, apic_pm_state.apic_ldr); + apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri); + apic_write(APIC_SPIV, apic_pm_state.apic_spiv); + apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); + apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); + apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); + apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); + apic_write(APIC_TMICT, apic_pm_state.apic_tmict); + __restore_flags(flags); + if (apic_pm_state.perfctr_pmdev) + pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data); +} + +static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + switch (rqst) { + case PM_SUSPEND: + apic_pm_suspend(data); + break; + case PM_RESUME: + apic_pm_resume(data); + break; + } + return 0; +} + +/* perfctr driver should call this instead of pm_register() */ +struct pm_dev *apic_pm_register(pm_dev_t type, + unsigned long id, + pm_callback callback) +{ + struct pm_dev *dev; + + if (!apic_pm_state.active) + return pm_register(type, id, callback); + if (apic_pm_state.perfctr_pmdev) + return NULL; /* we're busy */ + dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); + if (dev) { + memset(dev, 0, sizeof(*dev)); + dev->type = type; + dev->id = id; + dev->callback = callback; + apic_pm_state.perfctr_pmdev = dev; + } + return dev; +} + +/* perfctr driver should call this instead of pm_unregister() */ +void apic_pm_unregister(struct pm_dev *dev) +{ + if (!apic_pm_state.active) { + pm_unregister(dev); + } else if (dev == apic_pm_state.perfctr_pmdev) { + apic_pm_state.perfctr_pmdev = NULL; + kfree(dev); + } +} + +static void __init apic_pm_init1(void) +{ + /* can't pm_register() at this early stage in the boot process + (causes an immediate reboot), so just set the flag */ + apic_pm_state.active = 1; +} + +static void __init apic_pm_init2(void) +{ + if (apic_pm_state.active) + pm_register(PM_SYS_DEV, 0, apic_pm_callback); +} + +#else /* CONFIG_PM */ + +static inline void apic_pm_init1(void) { } +static inline void apic_pm_init2(void) { } + +#endif /* CONFIG_PM */ + +/* + * Detect and enable local APICs on non-SMP boards. + * Original code written by Keir Fraser. + */ + +static int __init detect_init_APIC (void) +{ + u32 h, l, features; + int needs_pm = 0; + extern void get_cpu_vendor(struct cpuinfo_x86*); + + /* Workaround for us being called before identify_cpu(). */ + get_cpu_vendor(&boot_cpu_data); + + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) + break; + goto no_apic; + case X86_VENDOR_INTEL: + if (boot_cpu_data.x86 == 6 || + (boot_cpu_data.x86 == 5 && cpu_has_apic)) + break; + goto no_apic; + default: + goto no_apic; + } + + if (!cpu_has_apic) { /* - * set up a fake all zeroes page to simulate the - * local APIC and another one for the IO-APIC. We - * could use the real zero-page, but it's safer - * this way if some buggy code writes to this page ... + * Some BIOSes disable the local APIC in the + * APIC_BASE MSR. This can only be done in + * software for Intel P6 and AMD K7 (Model > 1). */ + rdmsr(MSR_IA32_APICBASE, l, h); + if (!(l & MSR_IA32_APICBASE_ENABLE)) { + printk("Local APIC disabled by BIOS -- reenabling.\n"); + l &= ~MSR_IA32_APICBASE_BASE; + l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; + wrmsr(MSR_IA32_APICBASE, l, h); + needs_pm = 1; + } + } + /* + * The APIC feature bit should now be enabled + * in `cpuid' + */ + features = cpuid_edx(1); + if (!(features & (1 << X86_FEATURE_APIC))) { + printk("Could not enable APIC!\n"); + return -1; + } + set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability); + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + boot_cpu_id = 0; + if (nmi_watchdog != NMI_NONE) + nmi_watchdog = NMI_LOCAL_APIC; + + printk("Found and enabled local APIC!\n"); + + if (needs_pm) + apic_pm_init1(); + + return 0; + +no_apic: + printk("No local APIC present or hardware disabled\n"); + return -1; +} + +void __init init_apic_mappings(void) +{ + unsigned long apic_phys; + + /* + * If no local APIC can be found then set up a fake all + * zeroes page to simulate the local APIC and another + * one for the IO-APIC. + */ + if (!smp_found_config && detect_init_APIC()) { apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); apic_phys = __pa(apic_phys); - } + } else + apic_phys = mp_lapic_addr; + set_fixmap_nocache(FIX_APIC_BASE, apic_phys); Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); @@ -596,6 +875,9 @@ void __init setup_APIC_clocks (void) { + printk("Using local APIC timer interrupts.\n"); + using_apic_timer = 1; + __cli(); calibration_result = calibrate_APIC_clock(); @@ -764,7 +1046,7 @@ apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); ack_APIC_irq(); - irq_err_count++; + atomic_inc(&irq_err_count); /* Here is what the APIC error bits mean: 0: Send CS error @@ -780,3 +1062,43 @@ smp_processor_id(), v , v1); } +/* + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ +int __init APIC_init_uniprocessor (void) +{ + if (!smp_found_config && !cpu_has_apic) + return -1; + + /* + * Complain if the BIOS pretends there is one. + */ + if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) { + printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", + boot_cpu_id); + return -1; + } + + verify_local_APIC(); + + connect_bsp_APIC(); + + phys_cpu_present_map = 1; + apic_write_around(APIC_ID, boot_cpu_id); + + apic_pm_init2(); + + setup_local_APIC(); + + if (nmi_watchdog == NMI_LOCAL_APIC) + check_nmi_watchdog(); +#ifdef CONFIG_X86_IO_APIC + if (smp_found_config) + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +#endif + setup_APIC_clocks(); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/apm.c linux.ac/arch/i386/kernel/apm.c --- linux.vanilla/arch/i386/kernel/apm.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/apm.c Tue Apr 17 15:46:40 2001 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au) * * Initial development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -23,7 +23,7 @@ * March 1996, Rik Faith (faith@cs.unc.edu): * Prohibit APM BIOS calls unless apm_enabled. * (Thanks to Ulrich Windl ) - * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au) + * April 1996, Stephen Rothwell (sfr@canb.auug.org.au) * Version 1.0 and 1.1 * May 1996, Version 1.2 * Feb 1998, Version 1.3 @@ -119,7 +119,7 @@ * Make power off under SMP work again. * Fix thinko with initial engaging of BIOS. * Make sure power off only happens on CPU 0 - * (Paul "Rusty" Russell ). + * (Paul "Rusty" Russell ). * Do error notification to user mode if BIOS calls fail. * Move entrypoint offset fix to ...boot/setup.S * where it belongs (Cosmos ). @@ -166,6 +166,11 @@ * * [This document is available from Microsoft at: * http://www.microsoft.com/hwdev/busbios/amp_12.htm] + * + * (c) 2000 Crutcher Dunnavant + * changed to use the sysrq-register hack for registering + * the power off function called by magic sysrq + * based upon discusions in irc://irc.openprojects.net/#kernelnewbies */ #include @@ -191,12 +196,11 @@ #include #include +#include + extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); -#ifdef CONFIG_MAGIC_SYSRQ -extern void (*sysrq_power_off)(void); -#endif #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) extern int (*console_blank_hook)(int); #endif @@ -227,6 +231,8 @@ * P: Toshiba 1950S: battery life information only gets updated after resume * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking * broken in BIOS [Reported by Garst R. Reese ] + * ?: AcerNote-950: oops on reading /proc/apm - workaround is a WIP + * Neale Banks December 2000 * * Legend: U = unusable with APM patches * P = partially usable with APM patches @@ -669,6 +675,23 @@ #endif } +#ifdef CONFIG_MAGIC_SYSRQ +/* + * Magic sysrq key and handler for the power off function + */ + +void handle_poweroff (int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { + apm_power_off(); +} +struct sysrq_key_op sysrq_poweroff_op = { + handler: handle_poweroff, + help_msg: "Off", + action_msg: "Power Off\n" +}; +#endif + + #ifdef CONFIG_APM_DO_ENABLE static int apm_enable_power_management(int enable) { @@ -1523,9 +1546,8 @@ /* Install our power off handler.. */ if (power_off) pm_power_off = apm_power_off; -#ifdef CONFIG_MAGIC_SYSRQ - sysrq_power_off = apm_power_off; -#endif + register_sysrq_key('o',&sysrq_poweroff_op); + if (smp_num_cpus == 1) { #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) console_blank_hook = apm_console_blank; @@ -1550,6 +1572,9 @@ apm_disabled = 1; if (strncmp(str, "on", 2) == 0) apm_disabled = 0; + if ((strncmp(str, "broken-psr", 10) == 0) || + (strncmp(str, "broken_psr", 10) == 0)) + apm_info.get_power_status_broken = 1; invert = (strncmp(str, "no-", 3) == 0); if (invert) str += 3; @@ -1720,9 +1745,7 @@ } misc_deregister(&apm_device); remove_proc_entry("apm", NULL); -#ifdef CONFIG_MAGIC_SYSRQ - sysrq_power_off = NULL; -#endif + unregister_sysrq_key('o',&sysrq_poweroff_op); if (power_off) pm_power_off = NULL; exit_kapmd = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/bluesmoke.c linux.ac/arch/i386/kernel/bluesmoke.c --- linux.vanilla/arch/i386/kernel/bluesmoke.c Fri Dec 29 22:07:20 2000 +++ linux.ac/arch/i386/kernel/bluesmoke.c Fri Apr 20 14:51:26 2001 @@ -1,16 +1,18 @@ -/* - * Machine Check Handler For PII/PIII - */ +#include #include #include #include #include #include +/* + * Machine Check Handler For PII/PIII + */ + static int banks; -void do_machine_check(struct pt_regs * regs, long error_code) +static void intel_machine_check(struct pt_regs * regs, long error_code) { int recover=1; u32 alow, ahigh, high, low; @@ -45,6 +47,7 @@ printk(" at %08x%08x", high, low); } + printk("\n"); /* Clear it */ wrmsr(0x401+i*4, 0UL, 0UL); /* Serialize */ @@ -61,28 +64,101 @@ wrmsr(0x17a,mcgstl, mcgsth); } +/* + * Machine check handler for Pentium class Intel + */ + +static void pentium_machine_check(struct pt_regs * regs, long error_code) +{ + u32 loaddr, hi, lotype; + rdmsr(0x0, loaddr, hi); + rdmsr(0x1, lotype, hi); + printk(KERN_EMERG "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype); + if(lotype&(1<<5)) + printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id()); +} /* - * This has to be run for each processor + * Machine check handler for WinChip C6 + */ + +static void winchip_machine_check(struct pt_regs * regs, long error_code) +{ + printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id()); +} + +/* + * Handle unconfigured int18 (should never happen) */ + +static void unexpected_machine_check(struct pt_regs * regs, long error_code) +{ + printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id()); +} + +/* + * Call the installed machine check handler for this CPU setup. + */ -void mcheck_init(struct cpuinfo_x86 *c) +static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; + +void do_machine_check(struct pt_regs * regs, long error_code) +{ + machine_check_vector(regs, error_code); +} + +/* + * Set up machine check reporting for Intel processors + */ + +void __init intel_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; static int done; - - if( c->x86_vendor != X86_VENDOR_INTEL ) - return; + /* + * Check for MCE support + */ + if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) ) + return; + + /* + * Pentium machine check + */ + + if(c->x86 == 5) + { + machine_check_vector = pentium_machine_check; + wmb(); + /* Read registers before enabling */ + rdmsr(0x0, l, h); + rdmsr(0x1, l, h); + if(done==0) + printk(KERN_INFO "Intel old style machine check architecture supported.\n"); + /* Enable MCE */ + __asm__ __volatile__ ( + "movl %%cr4, %%eax\n\t" + "orl $0x40, %%eax\n\t" + "movl %%eax, %%cr4\n\t" : : : "eax"); + printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id()); return; - + } + + + /* + * Check for PPro style MCA + */ + if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) ) return; /* Ok machine check is available */ + machine_check_vector = intel_machine_check; + wmb(); + if(done==0) printk(KERN_INFO "Intel machine check architecture supported.\n"); rdmsr(0x179, l, h); @@ -103,4 +179,53 @@ "movl %%eax, %%cr4\n\t" : : : "eax"); printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id()); done=1; +} + +/* + * Set up machine check reporting on the Winchip C6 series + */ + +static void winchip_mcheck_init(struct cpuinfo_x86 *c) +{ + u32 lo, hi; + /* Not supported on C3 */ + if(c->x86 != 5) + return; + /* Winchip C6 */ + machine_check_vector = winchip_machine_check; + wmb(); + rdmsr(0x107, lo, hi); + lo|= (1<<2); /* Enable EIERRINT (int 18 MCE) */ + lo&= ~(1<<4); /* Enable MCE */ + wrmsr(0x107, lo, hi); + __asm__ __volatile__ ( + "movl %%cr4, %%eax\n\t" + "orl $0x40, %%eax\n\t" + "movl %%eax, %%cr4\n\t" : : : "eax"); + printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id()); +} + + +/* + * This has to be run for each processor + */ + +void __init mcheck_init(struct cpuinfo_x86 *c) +{ + switch(c->x86_vendor) + { + case X86_VENDOR_AMD: + /* + * AMD K7 machine check is Intel like + */ + if(c->x86 == 6) + intel_mcheck_init(c); + break; + case X86_VENDOR_INTEL: + intel_mcheck_init(c); + break; + case X86_VENDOR_CENTAUR: + winchip_mcheck_init(c); + break; + } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/dmi_scan.c linux.ac/arch/i386/kernel/dmi_scan.c --- linux.vanilla/arch/i386/kernel/dmi_scan.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/i386/kernel/dmi_scan.c Sun Apr 15 22:50:01 2001 @@ -1,8 +1,10 @@ +#include #include #include #include #include #include +#include #include struct dmi_header @@ -13,6 +15,7 @@ }; #define dmi_printk(x) +//#define dmi_printk(x) printk(x) static char * __init dmi_string(struct dmi_header *dm, u8 s) { @@ -90,9 +93,163 @@ } +enum +{ + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_STRING_MAX +}; + +static char *dmi_ident[DMI_STRING_MAX]; + +/* + * Save a DMI string + */ + +static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) +{ + char *p = dmi_string(dm, string); + if(p==NULL || *p == 0) + return; + dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + if(dmi_ident[slot]) + strcpy(dmi_ident[slot], p); + else + printk(KERN_ERR "dmi_save_ident: out of memory.\n"); +} + +/* + * DMI callbacks for problem boards + */ + +struct dmi_strmatch +{ + u8 slot; + char *substr; +}; + +#define NONE 255 + +struct dmi_blacklist +{ + int (*callback)(struct dmi_blacklist *); + char *ident; + struct dmi_strmatch matches[4]; +}; + +#define NO_MATCH { NONE, NULL} +#define MATCH(a,b) { a, b } + +/* + * We have problems with IDE DMA on some platforms. In paticular the + * KT7 series. On these it seems the newer BIOS has fixed them. The + * rule needs to be improved to match specific BIOS revisions with + * corruption problems + */ + +static __init int disable_ide_dma(struct dmi_blacklist *d) +{ +#ifdef CONFIG_BLK_DEV_IDE + extern int noautodma; + if(noautodma == 0) + { + noautodma = 1; + printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident); + } +#endif + return 0; +} + +/* + * Check for clue free BIOS implementations who use + * the following QA technique + * + * [ Write BIOS Code ]<------ + * | ^ + * < Does it Compile >----N-- + * |Y ^ + * < Does it Boot Win98 >-N-- + * |Y + * [Ship It] + * + * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) + * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) + */ + +static __init int broken_apm_power(struct dmi_blacklist *d) +{ + apm_info.get_power_status_broken = 1; + printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); +} + +/* + * Process the DMI blacklists + */ + + +/* + * This will be expanded over time to force things like the APM + * interrupt mask settings according to the laptop + */ + +static __initdata struct dmi_blacklist dmi_blacklist[]={ +#if 0 + { disable_ide_dma, "KT7", { /* Overbroad right now - kill DMA on problem KT7 boards */ + MATCH(DMI_PRODUCT_NAME, "KT7-RAID"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, +#endif + { broken_apm_power, "Dell Inspiron 5000e", { /* Handle problems with APM on Inspiron 5000e */ + MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + MATCH(DMI_BIOS_VERSION, "A04"), + MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH + } }, + { NULL, } +}; + + +/* + * Walk the blacklist table running matching functions until someone + * returns 1 or we hit the end. + */ + +static __init void dmi_check_blacklist(void) +{ + struct dmi_blacklist *d; + int i; + + d=&dmi_blacklist[0]; + while(d->callback) + { + for(i=0;i<4;i++) + { + int s = d->matches[i].slot; + if(s==NONE) + continue; + if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) + continue; + /* No match */ + goto fail; + } + if(d->callback(d)) + return; +fail: + d++; + } +} + + + /* * Process a DMI table entry. Right now all we care about are the BIOS - * and machine entries. For 2.4 we should pull the smbus controller info + * and machine entries. For 2.5 we should pull the smbus controller info * out of here. */ @@ -105,66 +262,47 @@ { case 0: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("BIOS Vendor: %s\n", p)); + dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BIOS_VERSION, 5); dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8]))); - } - - /* - * Check for clue free BIOS implementations who use - * the following QA technique - * - * [ Write BIOS Code ]<------ - * | ^ - * < Does it Compile >----N-- - * |Y ^ - * < Does it Boot Win98 >-N-- - * |Y - * [Ship It] - * - * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) - * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) - */ - - if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0) - { - if(strcmp(dmi_string(dm, data[5]), "A04")==0 - && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) - { - apm_info.get_power_status_broken = 1; - printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); - } + dmi_save_ident(dm, DMI_BIOS_DATE, 8); } break; + case 1: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("System Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_SYS_VENDOR, 4); dmi_printk(("Product Name: %s.\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); dmi_printk(("Version %s.\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); dmi_printk(("Serial Number %s.\n", dmi_string(dm, data[7]))); } break; case 2: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("Board Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); dmi_printk(("Board Name: %s.\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BOARD_NAME, 5); dmi_printk(("Board Version: %s.\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_BOARD_VERSION, 6); } break; case 3: @@ -177,7 +315,10 @@ static int __init dmi_scan_machine(void) { - return dmi_iterate(dmi_decode); + int err = dmi_iterate(dmi_decode); + if(err == 0) + dmi_check_blacklist(); + return err; } module_init(dmi_scan_machine); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/head.S linux.ac/arch/i386/kernel/head.S --- linux.vanilla/arch/i386/kernel/head.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/head.S Sun Apr 22 01:15:31 2001 @@ -169,9 +169,7 @@ rep movsl 1: -#ifdef CONFIG_SMP checkCPUtype: -#endif movl $-1,X86_CPUID # -1 for no CPUID initially @@ -244,9 +242,7 @@ orl $2,%eax # set MP 2: movl %eax,%cr0 call check_x87 -#ifdef CONFIG_SMP incb ready -#endif lgdt gdt_descr lidt idt_descr ljmp $(__KERNEL_CS),$1f @@ -278,9 +274,7 @@ jmp L6 # main should never return here, but # just in case, we know what happens. -#ifdef CONFIG_SMP ready: .byte 0 -#endif /* * We depend on ET to be correct. This checks for 287/387. @@ -447,6 +441,13 @@ .quad 0x00409a0000000000 /* 0x48 APM CS code */ .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ .quad 0x0040920000000000 /* 0x58 APM DS data */ + + /* PNPBIOS segments */ + .quad 0x00c09a0000000000 /* 0x60 32-bit code */ + .quad 0x00809a0000000000 /* 16-bit code */ + .quad 0x0080920000000000 /* 16-bit data */ + .quad 0x0080920000000000 /* 16-bit data */ + .quad 0x0080920000000000 /* 0x80 16-bit data */ .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/i386_ksyms.c linux.ac/arch/i386/kernel/i386_ksyms.c --- linux.vanilla/arch/i386/kernel/i386_ksyms.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/i386_ksyms.c Sun Apr 22 01:35:15 2001 @@ -28,6 +28,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -61,7 +62,6 @@ EXPORT_SYMBOL(dump_extended_fpu); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(__io_virt_debug); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); @@ -73,13 +73,14 @@ EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +#ifdef CONFIG_DEBUG_IOVIRT +EXPORT_SYMBOL(__io_virt_debug); +#endif + EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); -EXPORT_SYMBOL_NOVERS(__down_write_failed); -EXPORT_SYMBOL_NOVERS(__down_read_failed); -EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ @@ -97,6 +98,7 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(simple_strtol); +EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user); @@ -162,3 +164,9 @@ #ifdef CONFIG_X86_PAE EXPORT_SYMBOL(empty_zero_page); #endif + +#ifdef CONFIG_DEBUG_BUGVERBOSE +EXPORT_SYMBOL(do_BUG); +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/i8259.c linux.ac/arch/i386/kernel/i8259.c --- linux.vanilla/arch/i386/kernel/i8259.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/i8259.c Tue Apr 3 17:54:30 2001 @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include @@ -321,7 +323,7 @@ printk("spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } - irq_err_count++; + atomic_inc(&irq_err_count); /* * Theoretically we do not have to handle this IRQ, * but in Linux this does not cause problems and is @@ -414,6 +416,9 @@ { int i; +#ifdef CONFIG_X86_LOCAL_APIC + init_bsp_APIC(); +#endif init_8259A(0); for (i = 0; i < NR_IRQS; i++) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/io_apic.c linux.ac/arch/i386/kernel/io_apic.c --- linux.vanilla/arch/i386/kernel/io_apic.c Fri Feb 9 19:28:31 2001 +++ linux.ac/arch/i386/kernel/io_apic.c Tue Apr 3 17:54:30 2001 @@ -33,23 +33,15 @@ #include #include +#undef APIC_LOCKUP_DEBUG + static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; /* - * # of IO-APICs and # of IRQ routing registers + * # of IRQ routing registers */ -int nr_ioapics; int nr_ioapic_registers[MAX_IO_APICS]; -/* I/O APIC entries */ -struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; - -/* # of MP IRQ source entries */ -struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; - -/* MP IRQ source entries */ -int mp_irq_entries; - #if CONFIG_SMP # define TARGET_CPUS cpu_online_map #else @@ -122,8 +114,14 @@ static void name##_IO_APIC_irq (unsigned int irq) \ __DO_ACTION(R, ACTION, FINAL) -DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ -DO_ACTION( __unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ +DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) + /* mask = 1 */ +DO_ACTION( __unmask, 0, &= 0xfffeffff, ) + /* mask = 0 */ +DO_ACTION( __mask_and_edge, 0, = (reg & 0xffff7fff) | 0x00010000, ) + /* mask = 1, trigger = 0 */ +DO_ACTION( __unmask_and_level, 0, = (reg & 0xfffeffff) | 0x00008000, ) + /* mask = 0, trigger = 1 */ static void mask_IO_APIC_irq (unsigned int irq) { @@ -146,14 +144,17 @@ void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; + unsigned long flags; /* * Disable it in the IO-APIC irq-routing table: */ memset(&entry, 0, sizeof(entry)); entry.mask = 1; + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); + spin_unlock_irqrestore(&ioapic_lock, flags); } static void clear_IO_APIC (void) @@ -581,6 +582,7 @@ { struct IO_APIC_route_entry entry; int apic, pin, idx, irq, first_notcon = 1, vector; + unsigned long flags; printk(KERN_DEBUG "init IO_APIC IRQs\n"); @@ -636,8 +638,10 @@ if (!apic && (irq < 16)) disable_8259A_irq(irq); } + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + spin_unlock_irqrestore(&ioapic_lock, flags); } } @@ -652,6 +656,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) { struct IO_APIC_route_entry entry; + unsigned long flags; memset(&entry,0,sizeof(entry)); @@ -681,8 +686,10 @@ /* * Add it to the IO-APIC irq-routing table: */ + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); + spin_unlock_irqrestore(&ioapic_lock, flags); enable_8259A_irq(0); } @@ -699,6 +706,7 @@ struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_02 reg_02; + unsigned long flags; printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) @@ -713,10 +721,12 @@ for (apic = 0; apic < nr_ioapics; apic++) { + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(apic, 0); *(int *)®_01 = io_apic_read(apic, 1); if (reg_01.version >= 0x10) *(int *)®_02 = io_apic_read(apic, 2); + spin_unlock_irqrestore(&ioapic_lock, flags); printk("\n"); printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); @@ -762,8 +772,10 @@ for (i = 0; i <= reg_01.entries; i++) { struct IO_APIC_route_entry entry; + spin_lock_irqsave(&ioapic_lock, flags); *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); + spin_unlock_irqrestore(&ioapic_lock, flags); printk(KERN_DEBUG " %02x %03X %02X ", i, @@ -790,7 +802,7 @@ continue; printk(KERN_DEBUG "IRQ%d ", i); for (;;) { - printk("-> %d", entry->pin); + printk("-> %d:%d", entry->apic, entry->pin); if (!entry->next) break; entry = irq_2_pin + entry->next; @@ -847,6 +859,8 @@ v = apic_read(APIC_EOI); printk(KERN_DEBUG "... APIC EOI: %08x\n", v); + v = apic_read(APIC_RRR); + printk(KERN_DEBUG "... APIC RRR: %08x\n", v); v = apic_read(APIC_LDR); printk(KERN_DEBUG "... APIC LDR: %08x\n", v); v = apic_read(APIC_DFR); @@ -938,6 +952,7 @@ { struct IO_APIC_reg_01 reg_01; int i; + unsigned long flags; for (i = 0; i < PIN_MAP_SIZE; i++) { irq_2_pin[i].pin = -1; @@ -951,7 +966,9 @@ * The number of IO-APIC IRQ registers (== #pins): */ for (i = 0; i < nr_ioapics; i++) { + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_01 = io_apic_read(i, 1); + spin_unlock_irqrestore(&ioapic_lock, flags); nr_ioapic_registers[i] = reg_01.entries+1; } @@ -988,6 +1005,7 @@ int apic; int i; unsigned char old_id; + unsigned long flags; /* * Set the IOAPIC ID to the value stored in the MPC table. @@ -995,7 +1013,9 @@ for (apic = 0; apic < nr_ioapics; apic++) { /* Read the register 0 value */ + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(apic, 0); + spin_unlock_irqrestore(&ioapic_lock, flags); old_id = mp_ioapics[apic].mpc_apicid; @@ -1044,12 +1064,16 @@ mp_ioapics[apic].mpc_apicid); reg_00.ID = mp_ioapics[apic].mpc_apicid; + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0, *(int *)®_00); + spin_unlock_irqrestore(&ioapic_lock, flags); /* * Sanity check */ + spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(apic, 0); + spin_unlock_irqrestore(&ioapic_lock, flags); if (reg_00.ID != mp_ioapics[apic].mpc_apicid) panic("could not set ID!\n"); else @@ -1086,25 +1110,6 @@ return 0; } -static int __init nmi_irq_works(void) -{ - irq_cpustat_t tmp[NR_CPUS]; - int j, cpu; - - memcpy(tmp, irq_stat, sizeof(tmp)); - sti(); - mdelay(50); - - for (j = 0; j < smp_num_cpus; j++) { - cpu = cpu_logical_map(j); - if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 3) { - printk(KERN_WARNING "CPU#%d NMI appears to be stuck.\n", cpu); - return 0; - } - } - return 1; -} - /* * In the SMP+IOAPIC case it might happen that there are an unspecified * number of pending IRQ events unhandled. These cases are very rare, @@ -1191,12 +1196,63 @@ #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq -static void end_level_ioapic_irq (unsigned int i) +static void end_level_ioapic_irq (unsigned int irq) { + unsigned long v; + int i; + +/* + * It appears there is an erratum which affects at least version 0x11 + * of I/O APIC (that's the 82093AA and cores integrated into various + * chipsets). Under certain conditions a level-triggered interrupt is + * erroneously delivered as edge-triggered one but the respective IRR + * bit gets set nevertheless. As a result the I/O unit expects an EOI + * message but it will never arrive and further interrupts are blocked + * from the source. The exact reason is so far unknown, but the + * phenomenon was observed when two consecutive interrupt requests + * from a given source get delivered to the same CPU and the source is + * temporarily disabled in between. + * + * A workaround is to simulate an EOI message manually. We achieve it + * by setting the trigger mode to edge and then to level when the edge + * trigger mode gets detected in the TMR of a local APIC for a + * level-triggered interrupt. We mask the source for the time of the + * operation to prevent an edge-triggered interrupt escaping meanwhile. + * The idea is from Manfred Spraul. --macro + */ + i = IO_APIC_VECTOR(irq); + v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); + ack_APIC_irq(); + + if (!(v & (1 << (i & 0x1f)))) { +#ifdef APIC_MISMATCH_DEBUG + atomic_inc(&irq_mis_count); +#endif + spin_lock(&ioapic_lock); + __mask_and_edge_IO_APIC_irq(irq); +#ifdef APIC_LOCKUP_DEBUG + for (;;) { + struct irq_pin_list *entry = irq_2_pin + irq; + unsigned int reg; + + if (entry->pin == -1) + break; + reg = io_apic_read(entry->apic, 0x10 + entry->pin * 2); + if (reg & 0x00004000) + printk(KERN_CRIT "Aieee!!! Remote IRR" + " still set after unlock!\n"); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } +#endif + __unmask_and_level_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); + } } -static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ } +static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } static void set_ioapic_affinity (unsigned int irq, unsigned long mask) { @@ -1349,13 +1405,16 @@ int pin, i; struct IO_APIC_route_entry entry0, entry1; unsigned char save_control, save_freq_select; + unsigned long flags; pin = find_isa_irq_pin(8, mp_INT); if (pin == -1) return; + spin_lock_irqsave(&ioapic_lock, flags); *(((int *)&entry0) + 1) = io_apic_read(0, 0x11 + 2 * pin); *(((int *)&entry0) + 0) = io_apic_read(0, 0x10 + 2 * pin); + spin_unlock_irqrestore(&ioapic_lock, flags); clear_IO_APIC_pin(0, pin); memset(&entry1, 0, sizeof(entry1)); @@ -1368,8 +1427,10 @@ entry1.trigger = 0; entry1.vector = 0; + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry1) + 1)); io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry1) + 0)); + spin_unlock_irqrestore(&ioapic_lock, flags); save_control = CMOS_READ(RTC_CONTROL); save_freq_select = CMOS_READ(RTC_FREQ_SELECT); @@ -1388,8 +1449,10 @@ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); clear_IO_APIC_pin(0, pin); + spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry0) + 1)); io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); + spin_unlock_irqrestore(&ioapic_lock, flags); } /* @@ -1434,11 +1497,11 @@ */ unmask_IO_APIC_irq(0); if (timer_irq_works()) { - if (nmi_watchdog) { + if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); setup_nmi(); enable_8259A_irq(0); - nmi_irq_works(); + check_nmi_watchdog(); } return; } @@ -1455,9 +1518,9 @@ setup_ExtINT_IRQ0_pin(pin2, vector); if (timer_irq_works()) { printk("works.\n"); - if (nmi_watchdog) { + if (nmi_watchdog == NMI_IO_APIC) { setup_nmi(); - nmi_irq_works(); + check_nmi_watchdog(); } return; } @@ -1538,19 +1601,3 @@ check_timer(); print_IO_APIC(); } - -#ifndef CONFIG_SMP -/* - * This initializes the IO-APIC and APIC hardware if this is - * a UP kernel. - */ -void IO_APIC_init_uniprocessor (void) -{ - if (!smp_found_config) - return; - connect_bsp_APIC(); - setup_local_APIC(); - setup_IO_APIC(); - setup_APIC_clocks(); -} -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/irq.c linux.ac/arch/i386/kernel/irq.c --- linux.vanilla/arch/i386/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/irq.c Tue Apr 3 17:54:30 2001 @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -119,7 +120,12 @@ end_none }; -volatile unsigned long irq_err_count; +atomic_t irq_err_count; +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG +atomic_t irq_mis_count; +#endif +#endif /* * Generic, controller-independent functions: @@ -160,14 +166,19 @@ p += sprintf(p, "%10u ", nmi_count(cpu_logical_map(j))); p += sprintf(p, "\n"); -#if CONFIG_SMP +#if CONFIG_X86_LOCAL_APIC p += sprintf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); p += sprintf(p, "\n"); #endif - p += sprintf(p, "ERR: %10lu\n", irq_err_count); + p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG + p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); +#endif +#endif return p - buf; } @@ -460,14 +471,15 @@ * disable_irq_nosync - disable an irq without waiting * @irq: Interrupt to disable * - * Disable the selected interrupt line. Disables of an interrupt - * stack. Unlike disable_irq(), this function does not ensure existing + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing * instances of the IRQ handler have completed before returning. * * This function may be called from IRQ context. */ -void inline disable_irq_nosync(unsigned int irq) +inline void disable_irq_nosync(unsigned int irq) { irq_desc_t *desc = irq_desc + irq; unsigned long flags; @@ -484,9 +496,9 @@ * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable * - * Disable the selected interrupt line. Disables of an interrupt - * stack. That is for two disables you need two enables. This - * function waits for any pending IRQ handlers for this interrupt + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt * to complete before returning. If you use this function while * holding a resource the IRQ handler may need you will deadlock. * @@ -505,11 +517,12 @@ } /** - * enable_irq - enable interrupt handling on an irq + * enable_irq - enable handling of an irq * @irq: Interrupt to enable * - * Re-enables the processing of interrupts on this IRQ line - * providing no disable_irq calls are now in effect. + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. * * This function may be called from IRQ context. */ @@ -1016,20 +1029,9 @@ static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; - -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; #define HEX_DIGITS 8 -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - if (count < HEX_DIGITS+1) - return -EINVAL; - return sprintf (page, "%08lx\n", irq_affinity[(long)data]); -} - static unsigned int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret) { @@ -1067,6 +1069,19 @@ return 0; } +#if CONFIG_SMP + +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); +} + static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { @@ -1078,7 +1093,6 @@ err = parse_hex_value(buffer, count, &new_value); -#if CONFIG_SMP /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least @@ -1086,7 +1100,6 @@ */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc[irq].handler->set_affinity(irq, new_value); @@ -1094,6 +1107,8 @@ return full_count; } +#endif + static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -1121,7 +1136,6 @@ static void register_irq_proc (unsigned int irq) { - struct proc_dir_entry *entry; char name [MAX_NAMELEN]; if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || @@ -1134,15 +1148,23 @@ /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); +#if CONFIG_SMP + { + struct proc_dir_entry *entry; - entry->nlink = 1; - entry->data = (void *)(long)irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - smp_affinity_entry[irq] = entry; + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } + + smp_affinity_entry[irq] = entry; + } +#endif } unsigned long prof_cpu_mask = -1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/ldt.c linux.ac/arch/i386/kernel/ldt.c --- linux.vanilla/arch/i386/kernel/ldt.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/ldt.c Thu Apr 12 11:49:12 2001 @@ -94,8 +94,6 @@ goto out_unlock; memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); - if (atomic_read(&mm->mm_users) > 1) - printk(KERN_WARNING "LDT allocated for cloned task!\n"); /* * Possibly do an SMP cross-call to other CPUs to reload * their LDTs? diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/microcode.c linux.ac/arch/i386/kernel/microcode.c --- linux.vanilla/arch/i386/kernel/microcode.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/microcode.c Tue Apr 3 17:54:30 2001 @@ -126,6 +126,7 @@ printk(KERN_ERR "microcode: failed to devfs_register()\n"); goto out; } + error = 0; printk(KERN_INFO "IA-32 Microcode Update Driver: v%s \n", MICROCODE_VERSION); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/mpparse.c linux.ac/arch/i386/kernel/mpparse.c --- linux.vanilla/arch/i386/kernel/mpparse.c Wed Nov 15 05:25:34 2000 +++ linux.ac/arch/i386/kernel/mpparse.c Tue Apr 3 17:54:30 2001 @@ -38,6 +38,18 @@ int mp_bus_id_to_type [MAX_MP_BUSSES]; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; int mp_current_pci_id; + +/* I/O APIC entries */ +struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; + +/* # of MP IRQ source entries */ +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; + +/* MP IRQ source entries */ +int mp_irq_entries; + +int nr_ioapics; + int pic_mode; unsigned long mp_lapic_addr; @@ -225,6 +237,11 @@ MAX_IO_APICS, nr_ioapics); panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); } + if (!m->mpc_apicaddr) { + printk(KERN_ERR "WARNING: bogus zero I/O APIC address" + " found in MP table, skipping!\n"); + return; + } mp_ioapics[nr_ioapics] = *m; nr_ioapics++; } @@ -361,10 +378,19 @@ return num_processors; } +static int __init ELCR_trigger(unsigned int irq) +{ + unsigned int port; + + port = 0x4d0 + (irq >> 3); + return (inb(port) >> (irq & 7)) & 1; +} + static void __init construct_default_ioirq_mptable(int mpc_default_type) { struct mpc_config_intsrc intsrc; int i; + int ELCR_fallback = 0; intsrc.mpc_type = MP_INTSRC; intsrc.mpc_irqflag = 0; /* conforming */ @@ -372,6 +398,26 @@ intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid; intsrc.mpc_irqtype = mp_INT; + + /* + * If true, we have an ISA/PCI system with no IRQ entries + * in the MP table. To prevent the PCI interrupts from being set up + * incorrectly, we try to use the ELCR. The sanity check to see if + * there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can + * never be level sensitive, so we simply see if the ELCR agrees. + * If it does, we assume it's valid. + */ + if (mpc_default_type == 5) { + printk("ISA/PCI bus type with no IRQ information... falling back to ELCR\n"); + + if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13)) + printk("ELCR contains invalid data... not using ELCR\n"); + else { + printk("Using ELCR to identify PCI interrupts\n"); + ELCR_fallback = 1; + } + } + for (i = 0; i < 16; i++) { switch (mpc_default_type) { case 2: @@ -383,6 +429,18 @@ continue; /* IRQ2 is never connected */ } + if (ELCR_fallback) { + /* + * If the ELCR indicates a level-sensitive interrupt, we + * copy that information over to the MP table in the + * irqflag field (level sensitive, active high polarity). + */ + if (ELCR_trigger(i)) + intsrc.mpc_irqflag = 13; + else + intsrc.mpc_irqflag = 0; + } + intsrc.mpc_srcbusirq = i; intsrc.mpc_dstirq = i ? i : 2; /* IRQ0 to INTIN2 */ MP_intsrc_info(&intsrc); @@ -633,7 +691,7 @@ */ void __init find_smp_config (void) { -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC find_intel_smp(); #endif #ifdef CONFIG_VISWS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/mtrr.c linux.ac/arch/i386/kernel/mtrr.c --- linux.vanilla/arch/i386/kernel/mtrr.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/mtrr.c Sat Apr 21 09:41:53 2001 @@ -231,6 +231,20 @@ v1.37 20001109 H. Peter Anvin Use the new centralized CPU feature detects. + + v1.38 + 20010309 Dave Jones + Add support for Cyrix III. + + v1.39 + 20010312 Dave Jones + Ugh, I broke AMD support. + Reworked fix by Troels Walsted Hansen + + v1.40 + 20010327 Dave Jones + Adapted Cyrix III support to include VIA C3. + */ #include #include @@ -250,6 +264,7 @@ #include #include #include +#include #define MTRR_NEED_STRINGS #include #include @@ -269,7 +284,7 @@ #include #include -#define MTRR_VERSION "1.37 (20001109)" +#define MTRR_VERSION "1.40 (20010327)" #define TRUE 1 #define FALSE 0 @@ -464,6 +479,27 @@ static int have_wrcomb (void) { unsigned long config, dummy; + struct pci_dev *dev = NULL; + + /* ServerWorks LE chipsets have problems with write-combining + Don't allow it and leave room for other chipsets to be tagged */ + + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { + switch(dev->vendor) { + case PCI_VENDOR_ID_SERVERWORKS: + switch (dev->device) { + case PCI_DEVICE_ID_SERVERWORKS_LE: + return 0; + break; + default: + break; + } + break; + default: + break; + } + } + switch ( mtrr_if ) { @@ -538,7 +574,7 @@ * Note: shift==0xf means 4G, this is unsupported. */ if (shift) - *size = (reg < 7 ? 0x1UL : 0x40UL) << shift; + *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1); else *size = 0; @@ -610,12 +646,32 @@ unsigned long low; } centaur_mcr[8]; +static u8 centaur_mcr_reserved; +static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ + +/* + * Report boot time MCR setups + */ + +void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) +{ + centaur_mcr[mcr].low = lo; + centaur_mcr[mcr].high = hi; +} + static void centaur_get_mcr (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) { *base = centaur_mcr[reg].high >> PAGE_SHIFT; *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ + if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2)) + *type = MTRR_TYPE_UNCACHABLE; + if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25) + *type = MTRR_TYPE_WRBACK; + if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31) + *type = MTRR_TYPE_WRBACK; + } /* End Function centaur_get_mcr */ static void (*get_mtrr) (unsigned int reg, unsigned long *base, @@ -758,7 +814,15 @@ else { high = base << PAGE_SHIFT; - low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + if(centaur_mcr_type == 0) + low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + else + { + if(type == MTRR_TYPE_UNCACHABLE) + low = -size << PAGE_SHIFT | 0x02; /* NC */ + else + low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */ + } } centaur_mcr[reg].high = high; centaur_mcr[reg].low = low; @@ -1068,6 +1132,28 @@ return -ENOSPC; } /* End Function generic_get_free_region */ +static int centaur_get_free_region (unsigned long base, unsigned long size) +/* [SUMMARY] Get a free MTRR. + The starting (base) address of the region. + The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + max = get_num_var_ranges (); + for (i = 0; i < max; ++i) + { + if(centaur_mcr_reserved & (1< The starting (base) address of the region. @@ -1128,9 +1214,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1193,9 +1279,13 @@ case MTRR_IF_CENTAUR_MCR: if ( mtrr_if == MTRR_IF_CENTAUR_MCR ) { - if (type != MTRR_TYPE_WRCOMB) + /* + * FIXME: Winchip2 supports uncached + */ + if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) { - printk (KERN_WARNING "mtrr: only write-combining is supported\n"); + printk (KERN_WARNING "mtrr: only write-combining%s supported\n", + centaur_mcr_type?" and uncacheable are":" is"); return -EINVAL; } } @@ -1312,9 +1402,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1777,7 +1867,8 @@ } devfs_set_file_size (devfs_handle, ascii_buf_bytes); # ifdef CONFIG_PROC_FS - proc_root_mtrr->size = ascii_buf_bytes; + if (proc_root_mtrr) + proc_root_mtrr->size = ascii_buf_bytes; # endif /* CONFIG_PROC_FS */ } /* End Function compute_ascii */ @@ -1910,23 +2001,64 @@ { unsigned i; struct set_mtrr_context ctxt; + u32 lo, hi; + int wc2 = -1; set_mtrr_prepare (&ctxt); /* Unfortunately, MCR's are read-only, so there is no way to * find out what the bios might have done. */ - /* Clear all MCR's. + + /* + * Enable MCR key if we are using a winchip2 + */ + + if(boot_cpu_data.x86_model==4) + wc2 = 0; + + if(boot_cpu_data.x86_model==8 || boot_cpu_data.x86_model == 9) + { + rdmsr(0x120, lo, hi); + if(((lo>>17)&7)==1) /* Type 1 Winchip2 MCR */ + { + lo&= ~0x1C0; /* clear key */ + lo|= 0x040; /* set key to 1 */ + wrmsr(0x120, lo, hi); /* unlock MCR */ + wc2 = 1; + centaur_mcr_type = 1; + } + } + /* Clear any unconfigured MCR's. * This way we are sure that the centaur_mcr array contains the actual * values. The disadvantage is that any BIOS tweaks are thus undone. + * */ for (i = 0; i < 8; ++i) { - centaur_mcr[i].high = 0; - centaur_mcr[i].low = 0; - wrmsr (0x110 + i , 0, 0); + if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) + { + if(wc2 == 0 || ( wc2 == 1 && !(lo & (1<<(9+i))))) + wrmsr (0x110 + i , 0, 0); + else + /* + * If the BIOS set up an MCR we cannot see it + * but we don't wish to obliterate it + */ + centaur_mcr_reserved |= (1<owner = THIS_MODULE; - proc_root_mtrr->proc_fops = &mtrr_fops; + if (proc_root_mtrr) { + proc_root_mtrr->owner = THIS_MODULE; + proc_root_mtrr->proc_fops = &mtrr_fops; + } #endif #ifdef CONFIG_DEVFS_FS devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/nmi.c linux.ac/arch/i386/kernel/nmi.c --- linux.vanilla/arch/i386/kernel/nmi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/kernel/nmi.c Tue Apr 3 17:54:30 2001 @@ -0,0 +1,299 @@ +/* + * linux/arch/i386/nmi.c + * + * NMI watchdog support on APIC systems + * + * Started by Ingo Molnar + * + * Fixes: + * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. + * Mikael Pettersson : Power Management for local APIC NMI watchdog. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +unsigned int nmi_watchdog = NMI_NONE; +static unsigned int nmi_hz = HZ; +unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ + +#define K7_EVNTSEL_ENABLE (1 << 22) +#define K7_EVNTSEL_INT (1 << 20) +#define K7_EVNTSEL_OS (1 << 17) +#define K7_EVNTSEL_USR (1 << 16) +#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76 +#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING + +#define P6_EVNTSEL0_ENABLE (1 << 22) +#define P6_EVNTSEL_INT (1 << 20) +#define P6_EVNTSEL_OS (1 << 17) +#define P6_EVNTSEL_USR (1 << 16) +#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 +#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED + +int __init check_nmi_watchdog (void) +{ + irq_cpustat_t tmp[NR_CPUS]; + int j, cpu; + + printk(KERN_INFO "testing NMI watchdog ... "); + + memcpy(tmp, irq_stat, sizeof(tmp)); + sti(); + mdelay((10*1000)/nmi_hz); // wait 10 ticks + + for (j = 0; j < smp_num_cpus; j++) { + cpu = cpu_logical_map(j); + if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) { + printk("CPU#%d: NMI appears to be stuck!\n", cpu); + return -1; + } + } + printk("OK.\n"); + + /* now that we know it works we can reduce NMI frequency to + something more reasonable; makes a difference in some configs */ + if (nmi_watchdog == NMI_LOCAL_APIC) + nmi_hz = 1; + + return 0; +} + +static int __init setup_nmi_watchdog(char *str) +{ + int nmi; + + get_option(&str, &nmi); + + if (nmi >= NMI_INVALID) + return 0; + if (nmi == NMI_NONE) + nmi_watchdog = nmi; + /* + * If any other x86 CPU has a local APIC, then + * please test the NMI stuff there and send me the + * missing bits. Right now Intel P6 and AMD K7 only. + */ + if ((nmi == NMI_LOCAL_APIC) && + (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && + (boot_cpu_data.x86 == 6)) + nmi_watchdog = nmi; + if ((nmi == NMI_LOCAL_APIC) && + (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && + (boot_cpu_data.x86 == 6)) + nmi_watchdog = nmi; + /* + * We can enable the IO-APIC watchdog + * unconditionally. + */ + if (nmi == NMI_IO_APIC) + nmi_watchdog = nmi; + return 1; +} + +__setup("nmi_watchdog=", setup_nmi_watchdog); + +#ifdef CONFIG_PM + +#include + +struct pm_dev *nmi_pmdev; + +static void disable_apic_nmi_watchdog(void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + wrmsr(MSR_K7_EVNTSEL0, 0, 0); + break; + case X86_VENDOR_INTEL: + wrmsr(MSR_IA32_EVNTSEL0, 0, 0); + break; + } +} + +static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + switch (rqst) { + case PM_SUSPEND: + disable_apic_nmi_watchdog(); + break; + case PM_RESUME: + setup_apic_nmi_watchdog(); + break; + } + return 0; +} + +static void nmi_pm_init(void) +{ + if (!nmi_pmdev) + nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); +} + +#define __pminit /*empty*/ + +#else /* CONFIG_PM */ + +static inline void nmi_pm_init(void) { } + +#define __pminit __init + +#endif /* CONFIG_PM */ + +/* + * Activate the NMI watchdog via the local APIC. + * Original code written by Keith Owens. + */ + +static void __pminit setup_k7_watchdog(void) +{ + int i; + unsigned int evntsel; + + nmi_perfctr_msr = MSR_K7_PERFCTR0; + + for(i = 0; i < 4; ++i) { + wrmsr(MSR_K7_EVNTSEL0+i, 0, 0); + wrmsr(MSR_K7_PERFCTR0+i, 0, 0); + } + + evntsel = K7_EVNTSEL_INT + | K7_EVNTSEL_OS + | K7_EVNTSEL_USR + | K7_NMI_EVENT; + + wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); + Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= K7_EVNTSEL_ENABLE; + wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); +} + +static void __pminit setup_p6_watchdog(void) +{ + int i; + unsigned int evntsel; + + nmi_perfctr_msr = MSR_IA32_PERFCTR0; + + for(i = 0; i < 2; ++i) { + wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0); + wrmsr(MSR_IA32_PERFCTR0+i, 0, 0); + } + + evntsel = P6_EVNTSEL_INT + | P6_EVNTSEL_OS + | P6_EVNTSEL_USR + | P6_NMI_EVENT; + + wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); + Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= P6_EVNTSEL0_ENABLE; + wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); +} + +void __pminit setup_apic_nmi_watchdog (void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 != 6) + return; + setup_k7_watchdog(); + break; + case X86_VENDOR_INTEL: + if (boot_cpu_data.x86 != 6) + return; + setup_p6_watchdog(); + break; + default: + return; + } + nmi_pm_init(); +} + +static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; + +/* + * the best way to detect whether a CPU has a 'hard lockup' problem + * is to check it's local APIC timer IRQ counts. If they are not + * changing then that CPU has some problem. + * + * as these watchdog NMI IRQs are generated on every CPU, we only + * have to check the current processor. + * + * since NMIs dont listen to _any_ locks, we have to be extremely + * careful not to rely on unsafe variables. The printk might lock + * up though, so we have to break up any console locks first ... + * [when there will be more tty-related locks, break them up + * here too!] + */ + +static unsigned int + last_irq_sums [NR_CPUS], + alert_counter [NR_CPUS]; + +void touch_nmi_watchdog (void) +{ + int i; + + /* + * Just reset the alert counters, (other CPUs might be + * spinning on locks we hold): + */ + for (i = 0; i < smp_num_cpus; i++) + alert_counter[i] = 0; +} + +void nmi_watchdog_tick (struct pt_regs * regs) +{ + + /* + * Since current-> is always on the stack, and we always switch + * the stack NMI-atomically, it's safe to use smp_processor_id(). + */ + int sum, cpu = smp_processor_id(); + + sum = apic_timer_irqs[cpu]; + + if (last_irq_sums[cpu] == sum) { + /* + * Ayiee, looks like this CPU is stuck ... + * wait a few IRQs (5 seconds) before doing the oops ... + */ + alert_counter[cpu]++; + if (alert_counter[cpu] == 5*nmi_hz) { + spin_lock(&nmi_print_lock); + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + bust_spinlocks(1); + printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); + show_registers(regs); + printk("console shuts up ...\n"); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); + do_exit(SIGSEGV); + } + } else { + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } + if (nmi_perfctr_msr) + wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/pci-irq.c linux.ac/arch/i386/kernel/pci-irq.c --- linux.vanilla/arch/i386/kernel/pci-irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/i386/kernel/pci-irq.c Sun Apr 22 01:55:56 2001 @@ -105,7 +105,7 @@ * known (ascending bus order) and therefore pci_scan_bus returns immediately. */ if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL)) - printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); + printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); pcibios_last_bus = -1; } @@ -222,15 +222,18 @@ /* * Cyrix: nibble offset 0x5C + * 0x5C bits 7:4 is INTB bits 3:0 is INTA + * 0x5D bits 7:4 is INTD bits 3:0 is INTC */ + static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - return read_config_nybble(router, 0x5C, pirq-1); + return read_config_nybble(router, 0x5C, pirq^1); } static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - write_config_nybble(router, 0x5C, pirq-1, irq); + write_config_nybble(router, 0x5C, pirq^1, irq); return 1; } @@ -295,10 +298,10 @@ case 0x61: case 0x6a: case 0x7e: - printk("SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n"); + printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n"); return 0; default: - printk("SiS router pirq escape (%d)\n", pirq); + printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); return 0; } return (x & 0x80) ? 0 : (x & 0x0f); @@ -329,10 +332,10 @@ case 0x61: case 0x6a: case 0x7e: - printk("advanced SiS pirq mapping not yet implemented\n"); + printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n"); return 0; default: - printk("SiS router pirq escape (%d)\n", pirq); + printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); return 0; } pci_write_config_byte(router, reg, x); @@ -351,7 +354,7 @@ static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { if (pirq > 8) { - printk("VLSI router pirq escape (%d)\n", pirq); + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); return 0; } return read_config_nybble(router, 0x74, pirq-1); @@ -360,7 +363,7 @@ static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { if (pirq > 8) { - printk("VLSI router pirq escape (%d)\n", pirq); + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); return 0; } write_config_nybble(router, 0x74, pirq-1, irq); @@ -439,7 +442,7 @@ #ifdef CONFIG_PCI_BIOS if (!rt->signature) { - printk("PCI: Using BIOS for IRQ routing\n"); + printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); pirq_router = &pirq_bios_router; return; } @@ -464,7 +467,7 @@ pirq_router = r; } } - printk("PCI: Using IRQ router %s [%04x/%04x] at %s\n", + printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", pirq_router->name, pirq_router_dev->vendor, pirq_router_dev->device, @@ -568,7 +571,7 @@ } else return 0; } - printk("PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); + printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); /* Update IRQ for all devices with the same pirq value */ pci_for_each_dev(dev2) { @@ -582,13 +585,13 @@ if (info->irq[pin].link == pirq) { /* We refuse to override the dev->irq information. Give a warning! */ if (dev2->irq && dev2->irq != irq) { - printk("IRQ routing conflict in pirq table for device %s\n", dev2->slot_name); + printk(KERN_INFO "IRQ routing conflict in pirq table for device %s\n", dev2->slot_name); continue; } dev2->irq = irq; pirq_penalty[irq]++; if (dev != dev2) - printk("PCI: The same IRQ used for device %s\n", dev2->slot_name); + printk(KERN_INFO "PCI: The same IRQ used for device %s\n", dev2->slot_name); } } return 1; @@ -667,7 +670,7 @@ } #endif if (irq >= 0) { - printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", + printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); dev->irq = irq; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/pci-pc.c linux.ac/arch/i386/kernel/pci-pc.c --- linux.vanilla/arch/i386/kernel/pci-pc.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/pci-pc.c Sun Apr 15 22:49:03 2001 @@ -843,6 +843,8 @@ pcibios_last_bus = -1; } +#if 0 +/* Until we get proper handling pray the BIOS gets it right */ /* * ServerWorks host bridges -- Find and scan all secondary buses. * Register 0x44 contains first, 0x45 last bus number routed there. @@ -860,6 +862,7 @@ printk("PCI: ServerWorks host bridge: last bus %02x\n", pcibios_last_bus); } } +#endif #if 0 /* Our bus code shouldnt need this fixup any more. Delete once verified */ @@ -957,34 +960,6 @@ d->irq = 9; } -static void __init pci_fixup_vt8363(struct pci_dev *d) -{ - /* - * The VIA bridge will corrupt disks without these settings. - */ - u8 tmp; - pci_read_config_byte(d, 0x54, &tmp); - if(tmp & (1<<2)) { - printk("PCI: Bus master Pipeline request disabled\n"); - pci_write_config_byte(d, 0x54, tmp & ~(1<<2)); - } - pci_read_config_byte(d, 0x70, &tmp); - if(tmp & (1<<3)) { - printk("PCI: Disabled enhanced CPU to PCI writes\n"); - pci_write_config_byte(d, 0x70, tmp & ~(1<<3)); - } - pci_read_config_byte(d, 0x71, &tmp); - if((tmp & (1<<3)) == 0) { - printk("PCI: Bursting cornercase bug worked around\n"); - pci_write_config_byte(d, 0x71, tmp | (1<<3)); - } - pci_read_config_byte(d, 0x76, &tmp); - if(tmp & (1<<7)) { - printk("PCI: Post Write Fail set to Retry\n"); - pci_write_config_byte(d, 0x76, tmp & ~(1<<7)); - } -} - static void __init pci_fixup_via691(struct pci_dev *d) { /* @@ -1033,7 +1008,6 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, pci_fixup_via_acpi }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, pci_fixup_via_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_vt8363 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C691, pci_fixup_via691 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, pci_fixup_via691_2 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/semaphore.c linux.ac/arch/i386/kernel/semaphore.c --- linux.vanilla/arch/i386/kernel/semaphore.c Sun Nov 19 01:31:25 2000 +++ linux.ac/arch/i386/kernel/semaphore.c Sat Apr 14 01:17:30 2001 @@ -14,7 +14,6 @@ */ #include #include - #include /* @@ -179,6 +178,7 @@ * value.. */ asm( +".text\n" ".align 4\n" ".globl __down_failed\n" "__down_failed:\n\t" @@ -193,6 +193,7 @@ ); asm( +".text\n" ".align 4\n" ".globl __down_failed_interruptible\n" "__down_failed_interruptible:\n\t" @@ -205,6 +206,7 @@ ); asm( +".text\n" ".align 4\n" ".globl __down_failed_trylock\n" "__down_failed_trylock:\n\t" @@ -217,6 +219,7 @@ ); asm( +".text\n" ".align 4\n" ".globl __up_wakeup\n" "__up_wakeup:\n\t" @@ -230,199 +233,9 @@ "ret" ); -asm( -" -.align 4 -.globl __down_read_failed -__down_read_failed: - pushl %edx - pushl %ecx - jnc 2f - -3: call down_read_failed_biased - -1: popl %ecx - popl %edx - ret - -2: call down_read_failed - " LOCK "subl $1,(%eax) - jns 1b - jnc 2b - jmp 3b -" -); - -asm( -" -.align 4 -.globl __down_write_failed -__down_write_failed: - pushl %edx - pushl %ecx - jnc 2f - -3: call down_write_failed_biased - -1: popl %ecx - popl %edx - ret - -2: call down_write_failed - " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) - jz 1b - jnc 2b - jmp 3b -" -); - -struct rw_semaphore *FASTCALL(rwsem_wake_readers(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(rwsem_wake_writer(struct rw_semaphore *sem)); - -struct rw_semaphore *FASTCALL(down_read_failed_biased(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(down_write_failed_biased(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(down_read_failed(struct rw_semaphore *sem)); -struct rw_semaphore *FASTCALL(down_write_failed(struct rw_semaphore *sem)); - -struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->read_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->write_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* if the lock is currently unbiased, awaken the sleepers - * FIXME: this wakes up the readers early in a bit of a - * stampede -> bad! - */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); - - return sem; -} - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __up_read(sem); /* this takes care of granting the lock */ - - add_wait_queue(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -/* Wait for the lock to become unbiased. Since we're - * a writer, we'll make ourselves exclusive. - */ -struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __up_write(sem); /* this takes care of granting the lock */ - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to acquire or bias the lock */ - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -asm( -" -.align 4 -.globl __rwsem_wake -__rwsem_wake: - pushl %edx - pushl %ecx - - jz 1f - call rwsem_wake_readers - jmp 2f - -1: call rwsem_wake_writer - -2: popl %ecx - popl %edx - ret -" -); - -/* Called when someone has done an up that transitioned from - * negative to non-negative, meaning that the lock has been - * granted to whomever owned the bias. +/* + * rw spinlock fallbacks */ -struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) -{ - if (xchg(&sem->read_bias_granted, 1)) - BUG(); - wake_up(&sem->wait); - return sem; -} - -struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) -{ - if (xchg(&sem->write_bias_granted, 1)) - BUG(); - wake_up(&sem->write_bias_wait); - return sem; -} - #if defined(CONFIG_SMP) asm( " @@ -451,4 +264,3 @@ " ); #endif - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/setup.c linux.ac/arch/i386/kernel/setup.c --- linux.vanilla/arch/i386/kernel/setup.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/setup.c Fri Apr 20 14:52:07 2001 @@ -58,6 +58,15 @@ * Massive cleanup of CPU detection and bug handling; * Transmeta CPU detection, * H. Peter Anvin , November 2000 + * + * Added E820 sanitization routine (removes overlapping memory regions); + * Brian Moyle , February 2001 + * + * VIA C3 Support. + * Dave Jones , March 2001 + * + * AMD Athlon/Duron/Thunderbird bluesmoke support. + * Dave Jones , April 2001. */ /* @@ -87,6 +96,7 @@ #include #include #include +#include #include #include #include @@ -142,9 +152,9 @@ extern int rd_image_start; /* starting block # of image */ #endif +extern void mcheck_init(struct cpuinfo_x86 *c); extern int root_mountflags; extern char _text, _etext, _edata, _end; -extern unsigned long cpu_khz; static int disable_x86_serial_nr __initdata = 1; static int disable_x86_fxsr __initdata = 0; @@ -440,6 +450,170 @@ } /* + * Sanitize the BIOS e820 map. + * + * Some e820 responses include overlapping entries. The following + * replaces the original e820 map with a new one, removing overlaps. + * + */ +static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) +{ + struct change_member { + struct e820entry *pbios; /* pointer to original bios entry */ + unsigned long long addr; /* address for this change point */ + }; + struct change_member change_point_list[2*E820MAX]; + struct change_member *change_point[2*E820MAX]; + struct e820entry *overlap_list[E820MAX]; + struct e820entry new_bios[E820MAX]; + struct change_member *change_tmp; + unsigned long current_type, last_type; + unsigned long long last_addr; + int chgidx, still_changing; + int overlap_entries; + int new_bios_entry; + int old_nr, new_nr; + int i; + + /* + Visually we're performing the following (1,2,3,4 = memory types)... + + Sample memory map (w/overlaps): + ____22__________________ + ______________________4_ + ____1111________________ + _44_____________________ + 11111111________________ + ____________________33__ + ___________44___________ + __________33333_________ + ______________22________ + ___________________2222_ + _________111111111______ + _____________________11_ + _________________4______ + + Sanitized equivalent (no overlap): + 1_______________________ + _44_____________________ + ___1____________________ + ____22__________________ + ______11________________ + _________1______________ + __________3_____________ + ___________44___________ + _____________33_________ + _______________2________ + ________________1_______ + _________________4______ + ___________________2____ + ____________________33__ + ______________________4_ + */ + + /* if there's only one memory region, don't bother */ + if (*pnr_map < 2) + return -1; + + old_nr = *pnr_map; + + /* bail out if we find any unreasonable addresses in bios map */ + for (i=0; iaddr = biosmap[i].addr; + change_point[chgidx++]->pbios = &biosmap[i]; + change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; + change_point[chgidx++]->pbios = &biosmap[i]; + } + + /* sort change-point list by memory addresses (low -> high) */ + still_changing = 1; + while (still_changing) { + still_changing = 0; + for (i=1; i < 2*old_nr; i++) { + /* if > , swap */ + /* or, if current= & last=, swap */ + if ((change_point[i]->addr < change_point[i-1]->addr) || + ((change_point[i]->addr == change_point[i-1]->addr) && + (change_point[i]->addr == change_point[i]->pbios->addr) && + (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) + ) + { + change_tmp = change_point[i]; + change_point[i] = change_point[i-1]; + change_point[i-1] = change_tmp; + still_changing=1; + } + } + } + + /* create a new bios memory map, removing overlaps */ + overlap_entries=0; /* number of entries in the overlap table */ + new_bios_entry=0; /* index for creating new bios map entries */ + last_type = 0; /* start with undefined memory type */ + last_addr = 0; /* start with 0 as last starting address */ + /* loop through change-points, determining affect on the new bios map */ + for (chgidx=0; chgidx < 2*old_nr; chgidx++) + { + /* keep track of all overlapping bios entries */ + if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) + { + /* add map entry to overlap list (> 1 entry implies an overlap) */ + overlap_list[overlap_entries++]=change_point[chgidx]->pbios; + } + else + { + /* remove entry from list (order independent, so swap with last) */ + for (i=0; ipbios) + overlap_list[i] = overlap_list[overlap_entries-1]; + } + overlap_entries--; + } + /* if there are overlapping entries, decide which "type" to use */ + /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ + current_type = 0; + for (i=0; itype > current_type) + current_type = overlap_list[i]->type; + /* continue building up new bios map based on this information */ + if (current_type != last_type) { + if (last_type != 0) { + new_bios[new_bios_entry].size = + change_point[chgidx]->addr - last_addr; + /* move forward only if the new size was non-zero */ + if (new_bios[new_bios_entry].size != 0) + if (++new_bios_entry >= E820MAX) + break; /* no more space left for new bios entries */ + } + if (current_type != 0) { + new_bios[new_bios_entry].addr = change_point[chgidx]->addr; + new_bios[new_bios_entry].type = current_type; + last_addr=change_point[chgidx]->addr; + } + last_type = current_type; + } + } + new_nr = new_bios_entry; /* retain count for new bios entries */ + + /* copy new bios mapping into original location */ + memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); + *pnr_map = new_nr; + + return 0; +} + +/* * Copy the BIOS e820 map into a safe place. * * Sanity-check it while we're at it.. @@ -506,6 +680,7 @@ * Otherwise fake a memory map; one section from 0k->640k, * the next section from 1mb->appropriate_mem_k */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { unsigned long mem_size; @@ -560,7 +735,7 @@ * blow away any automatically generated * size */ - unsigned long start_at, mem_size; + unsigned long long start_at, mem_size; if (usermem == 0) { /* first time in: zap the whitelist @@ -772,21 +947,19 @@ smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ #endif -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC /* * Find and reserve possible boot-time SMP configuration: */ find_smp_config(); #endif paging_init(); -#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_X86_LOCAL_APIC /* * get boot-time SMP configuration: */ if (smp_found_config) get_smp_config(); -#endif -#ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif @@ -865,6 +1038,32 @@ __setup("notsc", tsc_setup); #endif + +static void __init interpret_eblcr(struct cpuinfo_x86 *c, u32 lo, int coding) +{ + static unsigned int __initdata mult[32] = { 10, 6, 8, 0, 11, 7, 9, 0, + 10, 14, 16, 12, 0, 15, 0, 13 , + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + int mul = (lo>>22)&15; + + /* The mobile pIII added bit 27. This is zero on other intel and + on the cyrix III */ + + if(lo&(1>>27)) + mul+=16; + + c->clockmul = mult[mul]; + + if (mult[mul]==0) + { + printk(KERN_INFO "Unknown CPU/BUS multiplier (%d, %x).\n", + mul, lo); + return; + } +} + + static int __init get_model_name(struct cpuinfo_x86 *c) { unsigned int *v; @@ -1056,10 +1255,10 @@ set_bit(X86_FEATURE_K6_MTRR, &c->x86_capability); break; } - break; case 6: /* An Athlon/Duron. We can trust the BIOS probably */ + mcheck_init(c); break; } @@ -1299,6 +1498,248 @@ return; } +#ifdef CONFIG_X86_OOSTORE + +static u32 __init power2(u32 x) +{ + u32 s=1; + while(s<=x) + s<<=1; + return s>>=1; +} + +/* + * Set up an actual MCR + */ + +static void __init winchip_mcr_insert(int reg, u32 base, u32 size, int key) +{ + u32 lo, hi; + + hi = base & ~0xFFF; + lo = ~(size-1); /* Size is a power of 2 so this makes a mask */ + lo &= ~0xFFF; /* Remove the ctrl value bits */ + lo |= key; /* Attribute we wish to set */ + wrmsr(reg+0x110, lo, hi); + mtrr_centaur_report_mcr(reg, lo, hi); /* Tell the mtrr driver */ +} + +/* + * Figure what we can cover with MCR's + * + * Shortcut: We know you can't put 4Gig of RAM on a winchip + */ + +static u32 __init ramtop(void) /* 16388 */ +{ + int i; + u32 top = 0; + u32 clip = 0xFFFFFFFFUL; + + for (i = 0; i < e820.nr_map; i++) { + unsigned long start, end; + + if (e820.map[i].addr > 0xFFFFFFFFUL) + continue; + /* + * Don't MCR over reserved space. Ignore the ISA hole + * we frob around that catastrophy already + */ + + if (e820.map[i].type == E820_RESERVED) + { + if(e820.map[i].addr >= 0x100000UL && e820.map[i].addr < clip) + clip = e820.map[i].addr; + continue; + } + start = e820.map[i].addr; + end = e820.map[i].addr + e820.map[i].size; + if (start >= end) + continue; + if (end > top) + top = end; + } + /* Everything below 'top' should be RAM except for the ISA hole. + Because of the limited MCR's we want to map NV/ACPI into our + MCR range for gunk in RAM + + Clip might cause us to MCR insufficient RAM but that is an + acceptable failure mode and should only bite obscure boxes with + a VESA hole at 15Mb + + The second case Clip sometimes kicks in is when the EBDA is marked + as reserved. Again we fail safe with reasonable results + */ + + if(top>clip) + top=clip; + + return top; +} + +/* + * Compute a set of MCR's to give maximum coverage + */ + +static int __init winchip_mcr_compute(int nr, int key) +{ + u32 mem = ramtop(); + u32 root = power2(mem); + u32 base = root; + u32 top = root; + u32 floor = 0; + int ct = 0; + + while(ct high && fspace > low) + { + winchip_mcr_insert(ct, floor, fspace, key); + floor += fspace; + } + else if(high > low) + { + winchip_mcr_insert(ct, top, high, key); + top += high; + } + else if(low > 0) + { + base -= low; + winchip_mcr_insert(ct, base, low, key); + } + else break; + ct++; + } + /* + * We loaded ct values. We now need to set the mask. The caller + * must do this bit. + */ + + return ct; +} + +static void __init winchip_create_optimal_mcr(void) +{ + int i; + /* + * Allocate up to 6 mcrs to mark as much of ram as possible + * as write combining and weak write ordered. + * + * To experiment with: Linux never uses stack operations for + * mmio spaces so we could globally enable stack operation wc + * + * Load the registers with type 31 - full write combining, all + * writes weakly ordered. + */ + int used = winchip_mcr_compute(6, 31); + + /* + * Wipe unused MCRs + */ + + for(i=used;i<8;i++) + wrmsr(0x110+i, 0, 0); +} + +static void __init winchip2_create_optimal_mcr(void) +{ + u32 lo, hi; + int i; + + /* + * Allocate up to 6 mcrs to mark as much of ram as possible + * as write combining, weak store ordered. + * + * Load the registers with type 25 + * 8 - weak write ordering + * 16 - weak read ordering + * 1 - write combining + */ + + int used = winchip_mcr_compute(6, 25); + + /* + * Mark the registers we are using. + */ + + rdmsr(0x120, lo, hi); + for(i=0;i>17) & 7; + lo |= key<<6; /* replace with unlock key */ + wrmsr(0x120, lo, hi); +} + +static void __init winchip2_protect_mcr(void) +{ + u32 lo, hi; + + rdmsr(0x120, lo, hi); + lo&=~0x1C0; /* blank bits 8-6 */ + wrmsr(0x120, lo, hi); +} + +#endif + static void __init init_centaur(struct cpuinfo_x86 *c) { enum { @@ -1342,6 +1783,19 @@ fcr_clr=DPDC; printk(KERN_NOTICE "Disabling bugged TSC.\n"); clear_bit(X86_FEATURE_TSC, &c->x86_capability); +#ifdef CONFIG_X86_OOSTORE + winchip_create_optimal_mcr(); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + + The C6 original lacks weak read order + + Note 0x120 is write only on Winchip 1 */ + + wrmsr(0x120, 0x01F0001F, 0); +#endif break; case 8: switch(c->x86_mask) { @@ -1357,11 +1811,37 @@ } fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; fcr_clr=DPDC; +#ifdef CONFIG_X86_OOSTORE + winchip2_unprotect_mcr(); + winchip2_create_optimal_mcr(); + rdmsr(0x120, lo, hi); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + */ + lo|=31; + wrmsr(0x120, lo, hi); + winchip2_protect_mcr(); +#endif break; case 9: name="3"; fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; fcr_clr=DPDC; +#ifdef CONFIG_X86_OOSTORE + winchip2_unprotect_mcr(); + winchip2_create_optimal_mcr(); + rdmsr(0x120, lo, hi); + /* Enable + write combining on non-stack, non-string + write combining on string, all types + weak write ordering + */ + lo|=31; + wrmsr(0x120, lo, hi); + winchip2_protect_mcr(); +#endif break; case 10: name="4"; @@ -1397,11 +1877,12 @@ c->x86_cache_size = (cc>>24)+(dd>>24); } sprintf( c->x86_model_id, "WinChip %s", name ); + mcheck_init(c); break; case 6: switch (c->x86_model) { - case 6: /* Cyrix III */ + case 6 ... 7: /* Cyrix III or C3 */ rdmsr (0x1107, lo, hi); lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ wrmsr (0x1107, lo, hi); @@ -1411,11 +1892,13 @@ get_model_name(c); display_cacheinfo(c); + + rdmsr(0x2A, lo, hi); + interpret_eblcr(c, lo, 0); break; } break; } - } @@ -1481,6 +1964,32 @@ wrmsr(0x80860004, cap_mask, uk); } + +static void __init init_rise(struct cpuinfo_x86 *c) +{ + printk("CPU: Rise iDragon"); + if (c->x86_model > 2) + printk(" II"); + printk("\n"); + printk("If you have one of these please email davej@suse.de\n"); + + /* Unhide possibly hidden capability flags + The mp6 iDragon family don't have MSRs. + We switch on extra features with this cpuid wierdness: */ + __asm__ ( + "movl $0x6363452a, %%eax\n\t" + "movl $0x3231206c, %%ecx\n\t" + "movl $0x2a32313a, %%edx\n\t" + "cpuid\n\t" + "movl $0x63634523, %%eax\n\t" + "movl $0x32315f6c, %%ecx\n\t" + "movl $0x2333313a, %%edx\n\t" + "cpuid\n\t" : : : "eax", "ebx", "ecx", "edx" + ); + set_bit(X86_FEATURE_CX8, &c->x86_capability); +} + + extern void trap_init_f00f_bug(void); static void __init init_intel(struct cpuinfo_x86 *c) @@ -1488,7 +1997,6 @@ #ifndef CONFIG_M686 static int f00f_workaround_enabled = 0; #endif - extern void mcheck_init(struct cpuinfo_x86 *c); char *p = NULL; unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ @@ -1631,6 +2139,13 @@ if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 ) clear_bit(X86_FEATURE_SEP, &c->x86_capability); + if ( c->x86 == 6 && c->x86_model >= 3) + { + u32 lo, hi; + rdmsr(0x2A, lo, hi); + interpret_eblcr(c, lo, (c->x86_model >= 7) ? 1: 0); + } + /* Names for the Pentium II/Celeron processors detectable only by also checking the cache size. Dixon is NOT a Celeron. */ @@ -1732,8 +2247,8 @@ { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_RISE, 5, - { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + { "iDragon", NULL, "iDragon", NULL, NULL, NULL, NULL, + NULL, "iDragon II", "iDragon II", NULL, NULL, NULL, NULL, NULL, NULL }}, }; /* Look up CPU names by table lookup. */ @@ -1997,6 +2512,15 @@ case X86_VENDOR_UNKNOWN: default: /* Not much we can do here... */ + /* Check if at least it has cpuid */ + if (c->cpuid_level == -1) + { + /* No cpuid. It must be an ancient CPU */ + if (c->x86 == 4) + strcpy(c->x86_model_id, "486"); + else if (c->x86 == 3) + strcpy(c->x86_model_id, "386"); + } break; case X86_VENDOR_CYRIX: @@ -2022,6 +2546,10 @@ case X86_VENDOR_TRANSMETA: init_transmeta(c); break; + + case X86_VENDOR_RISE: + init_rise(c); + break; } printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n", @@ -2064,7 +2592,7 @@ /* Now the feature flags better reflect actual CPU features! */ - printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], @@ -2082,7 +2610,7 @@ boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; } - printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", boot_cpu_data.x86_capability[0], boot_cpu_data.x86_capability[1], boot_cpu_data.x86_capability[2], @@ -2135,6 +2663,7 @@ int get_cpuinfo(char * buffer) { + extern int x86_udelay_tsc; /* For 2.5 we need to push this int c-> */ char *p = buffer; /* @@ -2189,7 +2718,7 @@ c->x86, c->x86_model, c->x86_model_id[0] ? c->x86_model_id : "unknown"); - + if (c->x86_mask || c->cpuid_level >= 0) p += sprintf(p, "stepping\t: %d\n", c->x86_mask); else @@ -2232,6 +2761,7 @@ p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n", c->loops_per_jiffy/(500000/HZ), (c->loops_per_jiffy/(5000/HZ)) % 100); + } return p - buffer; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/smp.c linux.ac/arch/i386/kernel/smp.c --- linux.vanilla/arch/i386/kernel/smp.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/i386/kernel/smp.c Tue Apr 3 17:54:30 2001 @@ -429,9 +429,10 @@ atomic_t started; atomic_t finished; int wait; -}; +} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); static struct call_data_struct * call_data; +static struct call_data_struct call_data_array[NR_CPUS]; /* * this function sends a 'generic call function' IPI to all other CPUs @@ -453,32 +454,45 @@ * hardware interrupt handler, you may call it from a bottom half handler. */ { - struct call_data_struct data; - int cpus = smp_num_cpus-1; + struct call_data_struct *data; + int cpus = (cpu_online_map & ~(1 << smp_processor_id())); if (!cpus) return 0; - data.func = func; - data.info = info; - atomic_set(&data.started, 0); - data.wait = wait; + data = &call_data_array[smp_processor_id()]; + + data->func = func; + data->info = info; + data->wait = wait; if (wait) - atomic_set(&data.finished, 0); - - spin_lock_bh(&call_lock); - call_data = &data; + atomic_set(&data->finished, 0); + /* We have do to this one last to make sure that the IPI service + * code desn't get confused if it gets an unexpected repeat + * trigger of an old IPI while we're still setting up the new + * one. */ + atomic_set(&data->started, 0); + + local_bh_disable(); + spin_lock(&call_lock); + call_data = data; /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(CALL_FUNCTION_VECTOR); /* Wait for response */ - while (atomic_read(&data.started) != cpus) + while (atomic_read(&data->started) != cpus) barrier(); + /* It is now safe to reuse the "call_data" global, but we need + * to keep local bottom-halves disabled until after waiters have + * been acknowledged to prevent reuse of the per-cpu call data + * entry. */ + spin_unlock(&call_lock); + if (wait) - while (atomic_read(&data.finished) != cpus) + while (atomic_read(&data->finished) != cpus) barrier(); - spin_unlock_bh(&call_lock); + local_bh_enable(); return 0; } @@ -528,15 +542,17 @@ ack_APIC_irq(); /* - * Notify initiating CPU that I've grabbed the data and am - * about to execute the function + * Notify initiating CPU that I've grabbed the data and am about + * to execute the function (and avoid servicing any single IPI + * twice) */ - atomic_inc(&call_data->started); + if (test_and_set_bit(smp_processor_id(), &call_data->started)) + return; /* * At this point the info structure may be out of scope unless wait==1 */ (*func)(info); if (wait) - atomic_inc(&call_data->finished); + set_bit(smp_processor_id(), &call_data->finished); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/smpboot.c linux.ac/arch/i386/kernel/smpboot.c --- linux.vanilla/arch/i386/kernel/smpboot.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/i386/kernel/smpboot.c Tue Apr 3 17:54:30 2001 @@ -780,7 +780,6 @@ } cycles_t cacheflush_time; -extern unsigned long cpu_khz; static void smp_tune_scheduling (void) { @@ -870,12 +869,15 @@ * get out of here now! */ if (!smp_found_config) { - printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); + printk(KERN_NOTICE "SMP motherboard not detected.\n"); #ifndef CONFIG_VISWS io_apic_irqs = 0; #endif cpu_online_map = phys_cpu_present_map = 1; smp_num_cpus = 1; + if (APIC_init_uniprocessor()) + printk(KERN_NOTICE "Local APIC not detected." + " Using dummy APIC emulation.\n"); goto smp_done; } @@ -1003,7 +1005,7 @@ * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ - if (!skip_ioapic_setup) + if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); #endif @@ -1021,4 +1023,3 @@ smp_done: zap_low_mappings(); } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/time.c linux.ac/arch/i386/kernel/time.c --- linux.vanilla/arch/i386/kernel/time.c Fri Dec 29 22:07:57 2000 +++ linux.ac/arch/i386/kernel/time.c Tue Apr 3 17:54:30 2001 @@ -178,6 +178,15 @@ jiffies_t = jiffies; count |= inb_p(0x40) << 8; + + /* VIA686a test code... reset the latch if count > max */ + if (count > LATCH-1) { + outb_p(0x34, 0x43); + outb_p(LATCH & 0xff, 0x40); + outb(LATCH >> 8, 0x40); + count = LATCH - 1; + } + spin_unlock(&i8253_lock); /* @@ -413,7 +422,7 @@ if (!user_mode(regs)) x86_do_profile(regs->eip); #else - if (!smp_found_config) + if (!using_apic_timer) smp_local_timer_interrupt(regs); #endif @@ -492,6 +501,24 @@ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; + + + /* VIA686a test code... reset the latch if count > max */ + if (count > LATCH-1) { + static int last_whine; + outb_p(0x34, 0x43); + outb_p(LATCH & 0xff, 0x40); + outb(LATCH >> 8, 0x40); + count = LATCH - 1; + if(time_after(jiffies, last_whine)) + { + printk(KERN_WARNING "probable hardware bug: clock timer configuration lost - probably a VIA686a motherboard.\n"); + printk(KERN_WARNING "probable hardware bug: restoring chip configuration.\n"); + last_whine = jiffies + HZ; + } + } + + spin_unlock(&i8253_lock); count = ((LATCH-1) - count) * TICK_SIZE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/traps.c linux.ac/arch/i386/kernel/traps.c --- linux.vanilla/arch/i386/kernel/traps.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/kernel/traps.c Sat Apr 21 00:49:46 2001 @@ -63,8 +63,6 @@ */ struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; -extern void bust_spinlocks(void); - asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); @@ -118,8 +116,8 @@ if (((addr >= (unsigned long) &_stext) && (addr <= (unsigned long) &_etext)) || ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); + if (i && ((i % 6) == 0)) + printk("\n "); printk("[<%08lx>] ", addr); i++; } @@ -129,7 +127,7 @@ void show_trace_task(struct task_struct *tsk) { - show_trace(&tsk->thread.esp); + show_trace((unsigned long *)(tsk->thread.esp)); } void show_stack(unsigned long * esp) @@ -155,7 +153,7 @@ show_trace(esp); } -static void show_registers(struct pt_regs *regs) +void show_registers(struct pt_regs *regs) { int i; int in_kernel = 1; @@ -212,9 +210,10 @@ { console_verbose(); spin_lock_irq(&die_lock); + bust_spinlocks(1); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); - + bust_spinlocks(0); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } @@ -234,7 +233,7 @@ return address; } -static void inline do_trap(int trapnr, int signr, char *str, int vm86, +static inline void do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { if (vm86 && regs->eflags & VM_MASK) @@ -386,83 +385,14 @@ printk("Do you have a strange power saving mode enabled?\n"); } -#if CONFIG_X86_IO_APIC - -int nmi_watchdog = 0; - -static int __init setup_nmi_watchdog(char *str) -{ - get_option(&str, &nmi_watchdog); - return 1; -} - -__setup("nmi_watchdog=", setup_nmi_watchdog); - -static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; - -inline void nmi_watchdog_tick(struct pt_regs * regs) -{ - /* - * the best way to detect wether a CPU has a 'hard lockup' problem - * is to check it's local APIC timer IRQ counts. If they are not - * changing then that CPU has some problem. - * - * as these watchdog NMI IRQs are broadcasted to every CPU, here - * we only have to check the current processor. - * - * since NMIs dont listen to _any_ locks, we have to be extremely - * careful not to rely on unsafe variables. The printk might lock - * up though, so we have to break up console_lock first ... - * [when there will be more tty-related locks, break them up - * here too!] - */ - - static unsigned int last_irq_sums [NR_CPUS], - alert_counter [NR_CPUS]; - - /* - * Since current-> is always on the stack, and we always switch - * the stack NMI-atomically, it's safe to use smp_processor_id(). - */ - int sum, cpu = smp_processor_id(); - - sum = apic_timer_irqs[cpu]; - - if (last_irq_sums[cpu] == sum) { - /* - * Ayiee, looks like this CPU is stuck ... - * wait a few IRQs (5 seconds) before doing the oops ... - */ - alert_counter[cpu]++; - if (alert_counter[cpu] == 5*HZ) { - spin_lock(&nmi_print_lock); - /* - * We are in trouble anyway, lets at least try - * to get a message out. - */ - bust_spinlocks(); - printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); - show_registers(regs); - printk("console shuts up ...\n"); - console_silent(); - spin_unlock(&nmi_print_lock); - do_exit(SIGSEGV); - } - } else { - last_irq_sums[cpu] = sum; - alert_counter[cpu] = 0; - } -} -#endif - asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { unsigned char reason = inb(0x61); - ++nmi_count(smp_processor_id()); + if (!(reason & 0xc0)) { -#if CONFIG_X86_IO_APIC +#if CONFIG_X86_LOCAL_APIC /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. @@ -470,11 +400,9 @@ if (nmi_watchdog) { nmi_watchdog_tick(regs); return; - } else - unknown_nmi_error(reason, regs); -#else - unknown_nmi_error(reason, regs); + } #endif + unknown_nmi_error(reason, regs); return; } if (reason & 0x80) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/Makefile linux.ac/arch/i386/lib/Makefile --- linux.vanilla/arch/i386/lib/Makefile Fri Dec 29 22:07:20 2000 +++ linux.ac/arch/i386/lib/Makefile Sun Apr 22 01:35:15 2001 @@ -8,10 +8,11 @@ L_TARGET = lib.a obj-y = checksum.o old-checksum.o delay.o \ - usercopy.o getuser.o putuser.o iodebug.o \ - memcpy.o + usercopy.o getuser.o putuser.o \ + memcpy.o strstr.o obj-$(CONFIG_X86_USE_3DNOW) += mmx.o obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +obj-$(CONFIG_DEBUG_IOVIRT) += iodebug.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/mmx.c linux.ac/arch/i386/lib/mmx.c --- linux.vanilla/arch/i386/lib/mmx.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/lib/mmx.c Sun Apr 15 16:49:54 2001 @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,6 +6,7 @@ #include #include + /* * MMX 3DNow! library helper functions * @@ -95,6 +97,13 @@ return p; } +#ifdef CONFIG_MK7 + +/* + * The K7 has streaming cache bypass load/store. The Cyrix III, K6 and + * other MMX using processors do not. + */ + static void fast_clear_page(void *page) { int i; @@ -194,6 +203,110 @@ ); kernel_fpu_end(); } + +#else + +/* + * Generic MMX implementation without K7 specific streaming + */ + +static void fast_clear_page(void *page) +{ + int i; + + kernel_fpu_begin(); + + __asm__ __volatile__ ( + " pxor %%mm0, %%mm0\n" : : + ); + + for(i=0;i<4096/128;i++) + { + __asm__ __volatile__ ( + " movq %%mm0, (%0)\n" + " movq %%mm0, 8(%0)\n" + " movq %%mm0, 16(%0)\n" + " movq %%mm0, 24(%0)\n" + " movq %%mm0, 32(%0)\n" + " movq %%mm0, 40(%0)\n" + " movq %%mm0, 48(%0)\n" + " movq %%mm0, 56(%0)\n" + " movq %%mm0, 64(%0)\n" + " movq %%mm0, 72(%0)\n" + " movq %%mm0, 80(%0)\n" + " movq %%mm0, 88(%0)\n" + " movq %%mm0, 96(%0)\n" + " movq %%mm0, 104(%0)\n" + " movq %%mm0, 112(%0)\n" + " movq %%mm0, 120(%0)\n" + : : "r" (page) : "memory"); + page+=128; + } + + kernel_fpu_end(); +} + +static void fast_copy_page(void *to, void *from) +{ + int i; + + + kernel_fpu_begin(); + + __asm__ __volatile__ ( + "1: prefetch (%0)\n" + " prefetch 64(%0)\n" + " prefetch 128(%0)\n" + " prefetch 192(%0)\n" + " prefetch 256(%0)\n" + "2: \n" + ".section .fixup, \"ax\"\n" + "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from) ); + + for(i=0; i<4096/64; i++) + { + __asm__ __volatile__ ( + "1: prefetch 320(%0)\n" + "2: movq (%0), %%mm0\n" + " movq 8(%0), %%mm1\n" + " movq 16(%0), %%mm2\n" + " movq 24(%0), %%mm3\n" + " movq %%mm0, (%1)\n" + " movq %%mm1, 8(%1)\n" + " movq %%mm2, 16(%1)\n" + " movq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm0\n" + " movq 40(%0), %%mm1\n" + " movq 48(%0), %%mm2\n" + " movq 56(%0), %%mm3\n" + " movq %%mm0, 32(%1)\n" + " movq %%mm1, 40(%1)\n" + " movq %%mm2, 48(%1)\n" + " movq %%mm3, 56(%1)\n" + ".section .fixup, \"ax\"\n" + "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } + kernel_fpu_end(); +} + + +#endif /* * Favour MMX for page clear and copy. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/strstr.c linux.ac/arch/i386/lib/strstr.c --- linux.vanilla/arch/i386/lib/strstr.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/lib/strstr.c Tue Apr 10 18:07:22 2001 @@ -0,0 +1,31 @@ +#include + +char * strstr(const char * cs,const char * ct) +{ +int d0, d1; +register char * __res; +__asm__ __volatile__( + "movl %6,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ + "movl %%ecx,%%edx\n" + "1:\tmovl %6,%%edi\n\t" + "movl %%esi,%%eax\n\t" + "movl %%edx,%%ecx\n\t" + "repe\n\t" + "cmpsb\n\t" + "je 2f\n\t" /* also works for empty string, see above */ + "xchgl %%eax,%%esi\n\t" + "incl %%esi\n\t" + "cmpb $0,-1(%%eax)\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "2:" + :"=a" (__res), "=&c" (d0), "=&S" (d1) + :"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct) + :"dx", "di"); +return __res; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/lib/usercopy.c linux.ac/arch/i386/lib/usercopy.c --- linux.vanilla/arch/i386/lib/usercopy.c Fri Nov 12 12:29:47 1999 +++ linux.ac/arch/i386/lib/usercopy.c Thu Apr 12 12:11:35 2001 @@ -34,6 +34,8 @@ else mmx_copy_user_zeroing(to, from, n); } + else + memset(to, 0, n); return n; } @@ -52,6 +54,8 @@ { if (access_ok(VERIFY_READ, from, n)) __copy_user_zeroing(to,from,n); + else + memset(to, 0, n); return n; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/control_w.h linux.ac/arch/i386/math-emu/control_w.h --- linux.vanilla/arch/i386/math-emu/control_w.h Thu Jun 29 16:25:27 1995 +++ linux.ac/arch/i386/math-emu/control_w.h Tue Apr 10 18:07:47 2001 @@ -42,4 +42,4 @@ /* FULL_PRECISION simulates all exceptions masked */ #define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f) -#endif _CONTROLW_H_ +#endif /* _CONTROLW_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/div_Xsig.S linux.ac/arch/i386/math-emu/div_Xsig.S --- linux.vanilla/arch/i386/math-emu/div_Xsig.S Fri Aug 27 18:18:17 1999 +++ linux.ac/arch/i386/math-emu/div_Xsig.S Tue Apr 10 18:07:47 2001 @@ -70,7 +70,7 @@ .long 0 FPU_result_1: .long 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -91,7 +91,7 @@ #ifdef PARANOID testl $0x80000000, XsigH(%ebx) /* Divisor */ je L_bugged -#endif PARANOID +#endif /* PARANOID */ /*---------------------------------------------------------------------------+ @@ -164,7 +164,7 @@ #ifdef PARANOID jb L_bugged_1 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ incl FPU_result_3 /* Correct the answer */ @@ -177,7 +177,7 @@ #ifdef PARANOID sbbl $0,FPU_accum_3 jne L_bugged_1 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* Half of the main problem is done, there is just a reduced numerator @@ -207,7 +207,7 @@ #ifdef PARANOID je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif PARANOID +#endif /* PARANOID */ LDo_2nd_div: cmpl $0,%ecx /* augmented denom msw */ @@ -230,7 +230,7 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ movl FPU_result_2,%eax /* Get the result back */ mull XsigL(%ebx) /* now mul the ls dw of the denom */ @@ -241,14 +241,14 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ jz LDo_3rd_32_bits #ifdef PARANOID cmpl $1,FPU_accum_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ movl XsigL(%ebx),%eax @@ -260,14 +260,14 @@ #ifdef PARANOID jc L_bugged_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ addl $1,FPU_result_2 /* Correct the answer */ adcl $0,FPU_result_3 #ifdef PARANOID jc L_bugged_2 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* The division is essentially finished here, we just need to perform @@ -362,4 +362,4 @@ call EXCEPTION pop %ebx jmp L_exit -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/errors.c linux.ac/arch/i386/math-emu/errors.c --- linux.vanilla/arch/i386/math-emu/errors.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/errors.c Tue Apr 10 18:07:47 2001 @@ -141,7 +141,7 @@ if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n"); if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n"); if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n"); -#endif DEBUGGING +#endif /* DEBUGGING */ printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0, /* busy */ @@ -327,7 +327,7 @@ #ifdef PRINT_MESSAGES /* My message from the sponsor */ printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n"); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ /* Get a name string for error reporting */ for (i=0; exception_names[i].type; i++) @@ -338,7 +338,7 @@ { #ifdef PRINT_MESSAGES printk("FP Exception: %s!\n", exception_names[i].name); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ } else printk("FPU emulator: Unknown Exception: 0x%04x!\n", n); @@ -351,7 +351,7 @@ #ifdef PRINT_MESSAGES else FPU_printall(); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ /* * The 80486 generates an interrupt on the next non-control FPU @@ -363,7 +363,7 @@ #ifdef __DEBUG__ math_abort(FPU_info,SIGFPE); -#endif __DEBUG__ +#endif /* __DEBUG__ */ } @@ -469,7 +469,7 @@ else #ifdef PARANOID if (tagb == TW_NaN) -#endif PARANOID +#endif /* PARANOID */ { signalling = !(b->sigh & 0x40000000); x = b; @@ -481,7 +481,7 @@ EXCEPTION(EX_INTERNAL|0x113); x = &CONST_QNaN; } -#endif PARANOID +#endif /* PARANOID */ if ( (!signalling) || (control_word & CW_Invalid) ) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/exception.h linux.ac/arch/i386/math-emu/exception.h --- linux.vanilla/arch/i386/math-emu/exception.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/exception.h Tue Apr 10 18:07:47 2001 @@ -18,7 +18,7 @@ #ifndef SW_C1 #include "fpu_emu.h" -#endif SW_C1 +#endif /* SW_C1 */ #define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */ #define EX_ErrorSummary Const_(0x0080) /* Error summary status */ @@ -48,6 +48,6 @@ #define EXCEPTION(x) FPU_exception(x) #endif -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _EXCEPTION_H_ +#endif /* _EXCEPTION_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_asm.h linux.ac/arch/i386/math-emu/fpu_asm.h --- linux.vanilla/arch/i386/math-emu/fpu_asm.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/fpu_asm.h Tue Apr 10 18:07:47 2001 @@ -29,4 +29,4 @@ #define SIGL(x) SIGL_OFFSET##(x) #define SIGH(x) 4(x) -#endif _FPU_ASM_H_ +#endif /* _FPU_ASM_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_emu.h linux.ac/arch/i386/math-emu/fpu_emu.h --- linux.vanilla/arch/i386/math-emu/fpu_emu.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/fpu_emu.h Tue Apr 10 18:07:47 2001 @@ -88,7 +88,7 @@ #else # define RE_ENTRANT_CHECK_OFF # define RE_ENTRANT_CHECK_ON -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ #define FWAIT_OPCODE 0x9b #define OP_SIZE_PREFIX 0x66 @@ -212,6 +212,6 @@ #include "fpu_proto.h" #endif -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _FPU_EMU_H_ +#endif /* _FPU_EMU_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_entry.c linux.ac/arch/i386/math-emu/fpu_entry.c --- linux.vanilla/arch/i386/math-emu/fpu_entry.c Tue Jun 20 02:10:44 2000 +++ linux.ac/arch/i386/math-emu/fpu_entry.c Tue Apr 10 18:07:47 2001 @@ -78,7 +78,7 @@ fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, }; -#endif NO_UNDOC_CODE +#endif /* NO_UNDOC_CODE */ #define _NONE_ 0 /* Take no special action */ @@ -120,12 +120,12 @@ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ }; -#endif NO_UNDOC_CODE +#endif /* NO_UNDOC_CODE */ #ifdef RE_ENTRANT_CHECKING u_char emulating=0; -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ static int valid_prefix(u_char *Byte, u_char **fpu_eip, overrides *override); @@ -152,7 +152,7 @@ printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); } RE_ENTRANT_CHECK_ON; -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ if (!current->used_math) { @@ -251,7 +251,7 @@ #ifdef PARANOID EXCEPTION(EX_INTERNAL|0x128); math_abort(FPU_info,SIGILL); -#endif PARANOID +#endif /* PARANOID */ } RE_ENTRANT_CHECK_OFF; @@ -386,7 +386,7 @@ /* fdiv or fsub */ real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data); else -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ /* fadd, fdivr, fmul, or fsubr */ real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr); } @@ -497,7 +497,7 @@ to do this: */ operand_address.offset = 0; operand_address.selector = FPU_DS; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ st0_ptr = &st(0); st0_tag = FPU_gettag0(); @@ -557,7 +557,7 @@ RE_ENTRANT_CHECK_OFF; FPU_printall(); RE_ENTRANT_CHECK_ON; -#endif DEBUG +#endif /* DEBUG */ if (FPU_lookahead && !current->need_resched) { @@ -669,7 +669,7 @@ __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4)); #ifdef PARANOID printk("ERROR: wm-FPU-emu math_abort failed!\n"); -#endif PARANOID +#endif /* PARANOID */ } @@ -739,7 +739,7 @@ S387->twd |= 0xffff0000; S387->fcs &= ~0xf8000000; S387->fos |= 0xffff0000; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ __copy_to_user(d, &S387->cwd, 7*4); RE_ENTRANT_CHECK_ON; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_etc.c linux.ac/arch/i386/math-emu/fpu_etc.c --- linux.vanilla/arch/i386/math-emu/fpu_etc.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/fpu_etc.c Tue Apr 10 18:07:47 2001 @@ -68,7 +68,7 @@ /* This is weird! */ if (getsign(st0_ptr) == SIGN_POS) setcc(SW_C3); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return; } break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/fpu_trig.c linux.ac/arch/i386/math-emu/fpu_trig.c --- linux.vanilla/arch/i386/math-emu/fpu_trig.c Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/fpu_trig.c Tue Apr 10 18:07:47 2001 @@ -98,7 +98,7 @@ q++; } } -#endif BETTER_THAN_486 +#endif /* BETTER_THAN_486 */ } #ifdef BETTER_THAN_486 else @@ -138,7 +138,7 @@ } } } -#endif BETTER_THAN_486 +#endif /* BETTER_THAN_486 */ FPU_settag0(st0_tag); control_word = old_cw; @@ -186,7 +186,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL|0x0112); -#endif PARANOID +#endif /* PARANOID */ } @@ -232,7 +232,7 @@ #ifdef PARANOID default: EXCEPTION(EX_INTERNAL|0x0112); -#endif PARANOID +#endif /* PARANOID */ } } @@ -463,7 +463,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL | 0x119); -#endif PARANOID +#endif /* PARANOID */ } @@ -716,7 +716,7 @@ set_precision_flag_down(); /* 80486 appears to do this. */ #else set_precision_flag_up(); /* Must be up. */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return 0; } } @@ -1008,7 +1008,7 @@ setcc(SW_C2); #else setcc(0); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return; } cc = SW_C2; @@ -1114,7 +1114,7 @@ #ifdef PARANOID if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) ) EXCEPTION(EX_INTERNAL | 0x118); -#endif PARANOID +#endif /* PARANOID */ real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr); @@ -1315,7 +1315,7 @@ sign = getsign(st1_ptr); if ( FPU_divide_by_zero(1, sign) < 0 ) return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ changesign(st1_ptr); } @@ -1451,7 +1451,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL | 0x125); -#endif PARANOID +#endif /* PARANOID */ FPU_pop(); set_precision_flag_up(); /* We do not really know if up or down */ @@ -1542,7 +1542,7 @@ #ifdef PARANOID EXCEPTION(EX_INTERNAL | 0x116); return; -#endif PARANOID +#endif /* PARANOID */ } } else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) @@ -1560,7 +1560,7 @@ #else if ( arith_invalid(1) < 0 ) return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; @@ -1583,7 +1583,7 @@ changesign(st1_ptr); #else if ( arith_invalid(1) < 0 ) return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; @@ -1618,14 +1618,14 @@ /* This should have higher priority than denormals, but... */ if ( arith_invalid(1) < 0 ) /* log(-infinity) */ return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; #ifdef PECULIAR_486 /* Denormal operands actually get higher priority */ if ( arith_invalid(1) < 0 ) /* log(-infinity) */ return; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } else if ( st1_tag == TAG_Zero ) { @@ -1654,7 +1654,7 @@ EXCEPTION(EX_INTERNAL | 0x117); return; } -#endif PARANOID +#endif /* PARANOID */ FPU_pop(); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/get_address.c linux.ac/arch/i386/math-emu/get_address.c --- linux.vanilla/arch/i386/math-emu/get_address.c Mon Jun 19 20:56:08 2000 +++ linux.ac/arch/i386/math-emu/get_address.c Tue Apr 10 18:07:47 2001 @@ -143,7 +143,7 @@ EXCEPTION(EX_INTERNAL|0x130); math_abort(FPU_info,SIGSEGV); } -#endif PARANOID +#endif /* PARANOID */ addr->selector = VM86_REG_(segment); return (unsigned long)VM86_REG_(segment) << 4; } @@ -166,7 +166,7 @@ EXCEPTION(EX_INTERNAL|0x132); math_abort(FPU_info,SIGSEGV); } -#endif PARANOID +#endif /* PARANOID */ switch ( segment ) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/load_store.c linux.ac/arch/i386/math-emu/load_store.c --- linux.vanilla/arch/i386/math-emu/load_store.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/load_store.c Tue Apr 10 18:07:47 2001 @@ -85,7 +85,7 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL|0x140); -#endif PARANOID +#endif /* PARANOID */ } switch ( type_table[type] ) @@ -112,7 +112,7 @@ default: EXCEPTION(EX_INTERNAL|0x141); return 0; -#endif PARANOID +#endif /* PARANOID */ } switch ( type ) @@ -217,7 +217,7 @@ partial_status &= ~(SW_Summary | SW_Backward); #ifdef PECULIAR_486 control_word |= 0x40; /* An 80486 appears to always set this bit */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return 1; case 025: /* fld m80real */ clear_C1(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly.h linux.ac/arch/i386/math-emu/poly.h --- linux.vanilla/arch/i386/math-emu/poly.h Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/poly.h Tue Apr 10 18:07:47 2001 @@ -118,4 +118,4 @@ :"=g" (*x):"g" (x):"si","ax","cx"); } -#endif _POLY_H +#endif /* _POLY_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_2xm1.c linux.ac/arch/i386/math-emu/poly_2xm1.c --- linux.vanilla/arch/i386/math-emu/poly_2xm1.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/poly_2xm1.c Tue Apr 10 18:07:47 2001 @@ -67,7 +67,7 @@ EXCEPTION(EX_INTERNAL|0x127); return 1; } -#endif PARANOID +#endif /* PARANOID */ argSignif.lsw = 0; XSIG_LL(argSignif) = Xll = significand(arg); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_atan.c linux.ac/arch/i386/math-emu/poly_atan.c --- linux.vanilla/arch/i386/math-emu/poly_atan.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/poly_atan.c Tue Apr 10 18:07:47 2001 @@ -124,7 +124,7 @@ EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */ return; } -#endif PARANOID +#endif /* PARANOID */ argSignif.msw = 0; /* Make the transformed arg -> 0.0 */ } else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_l2.c linux.ac/arch/i386/math-emu/poly_l2.c --- linux.vanilla/arch/i386/math-emu/poly_l2.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/poly_l2.c Tue Apr 10 18:07:47 2001 @@ -157,7 +157,7 @@ #else if ( arith_invalid(1) < 0 ) return 1; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ } /* 80486 appears to do this */ @@ -243,7 +243,7 @@ /* The argument is too large */ } } -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif); adj = norm_Xsig(&argSignif); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_sin.c linux.ac/arch/i386/math-emu/poly_sin.c --- linux.vanilla/arch/i386/math-emu/poly_sin.c Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/poly_sin.c Tue Apr 10 18:07:47 2001 @@ -199,7 +199,7 @@ { EXCEPTION(EX_INTERNAL|0x150); } -#endif PARANOID +#endif /* PARANOID */ } @@ -224,7 +224,7 @@ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); return; } -#endif PARANOID +#endif /* PARANOID */ exponent = exponent(st0_ptr); @@ -392,6 +392,6 @@ { EXCEPTION(EX_INTERNAL|0x151); } -#endif PARANOID +#endif /* PARANOID */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_tan.c linux.ac/arch/i386/math-emu/poly_tan.c --- linux.vanilla/arch/i386/math-emu/poly_tan.c Wed Jul 5 18:56:13 2000 +++ linux.ac/arch/i386/math-emu/poly_tan.c Tue Apr 10 18:07:47 2001 @@ -66,7 +66,7 @@ #ifdef PARANOID if ( signnegative(st0_ptr) ) /* Can't hack a number < 0.0 */ { arith_invalid(0); return; } /* Need a positive number */ -#endif PARANOID +#endif /* PARANOID */ /* Split the problem into two domains, smaller and larger than pi/4 */ if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) ) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_compare.c linux.ac/arch/i386/math-emu/reg_compare.c --- linux.vanilla/arch/i386/math-emu/reg_compare.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_compare.c Tue Apr 10 18:07:47 2001 @@ -136,7 +136,7 @@ #ifdef PARANOID if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); -#endif PARANOID +#endif /* PARANOID */ diff = exp0 - expb; if ( diff == 0 ) @@ -203,7 +203,7 @@ EXCEPTION(EX_INTERNAL|0x121); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) @@ -255,7 +255,7 @@ EXCEPTION(EX_INTERNAL|0x122); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) @@ -312,7 +312,7 @@ EXCEPTION(EX_INTERNAL|0x123); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_constant.h linux.ac/arch/i386/math-emu/reg_constant.h --- linux.vanilla/arch/i386/math-emu/reg_constant.h Mon Dec 11 21:34:34 2000 +++ linux.ac/arch/i386/math-emu/reg_constant.h Tue Apr 10 18:07:47 2001 @@ -28,4 +28,4 @@ extern FPU_REG const CONST_MINF; extern FPU_REG const CONST_QNaN; -#endif _REG_CONSTANT_H_ +#endif /* _REG_CONSTANT_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_divide.c linux.ac/arch/i386/math-emu/reg_divide.c --- linux.vanilla/arch/i386/math-emu/reg_divide.c Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_divide.c Tue Apr 10 18:07:47 2001 @@ -201,6 +201,6 @@ EXCEPTION(EX_INTERNAL|0x102); return FPU_Exception; } -#endif PARANOID +#endif /* PARANOID */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_ld_str.c linux.ac/arch/i386/math-emu/reg_ld_str.c --- linux.vanilla/arch/i386/math-emu/reg_ld_str.c Sun Jan 25 19:01:48 1998 +++ linux.ac/arch/i386/math-emu/reg_ld_str.c Tue Apr 10 18:07:47 2001 @@ -439,7 +439,7 @@ converts to decide underflow. */ if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && (st0_ptr->sigl & 0x000007ff)) ) -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow); /* This is a special case: see sec 16.2.5.1 of @@ -559,7 +559,7 @@ /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand(); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ reg_copy(st0_ptr, &tmp); goto denormal_arg; } @@ -659,7 +659,7 @@ converts to decide underflow. */ if ( !((tmp.sigl == 0x00800000) && ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) ) -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow); /* This is a special case: see sec 16.2.5.1 of @@ -776,7 +776,7 @@ /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand(); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ goto denormal_arg; } else if (st0_tag == TW_Infinity) @@ -1221,7 +1221,7 @@ #ifdef PECULIAR_486 control_word &= ~0xe080; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ top = (partial_status >> SW_Top_Shift) & 7; @@ -1303,7 +1303,7 @@ FPU_put_user(control_word & ~0xe080, (unsigned long *) d); #else FPU_put_user(control_word, (unsigned short *) d); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ FPU_put_user(status_word(), (unsigned short *) (d+2)); FPU_put_user(fpu_tag_word, (unsigned short *) (d+4)); FPU_put_user(instruction_address.offset, (unsigned short *) (d+6)); @@ -1335,7 +1335,7 @@ fpu_tag_word |= 0xffff0000; I387.soft.fcs &= ~0xf8000000; I387.soft.fos |= 0xffff0000; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ __copy_to_user(d, &control_word, 7*4); RE_ENTRANT_CHECK_ON; d += 0x1c; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_mul.c linux.ac/arch/i386/math-emu/reg_mul.c --- linux.vanilla/arch/i386/math-emu/reg_mul.c Wed Jun 24 22:30:08 1998 +++ linux.ac/arch/i386/math-emu/reg_mul.c Tue Apr 10 18:07:47 2001 @@ -126,6 +126,6 @@ EXCEPTION(EX_INTERNAL|0x102); return FPU_Exception; } -#endif PARANOID +#endif /* PARANOID */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_round.S linux.ac/arch/i386/math-emu/reg_round.S --- linux.vanilla/arch/i386/math-emu/reg_round.S Thu Nov 4 17:10:22 1999 +++ linux.ac/arch/i386/math-emu/reg_round.S Tue Apr 10 18:07:47 2001 @@ -100,7 +100,7 @@ .byte 0 FPU_denormal: .byte 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -126,13 +126,13 @@ #ifndef NON_REENTRANT_FPU pushl %ebx /* adjust the stack pointer */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ #ifdef PARANOID /* Cannot use this here yet */ /* orl %eax,%eax */ /* jns L_entry_bugged */ -#endif PARANOID +#endif /* PARANOID */ cmpw EXP_UNDER,EXP(%edi) jle L_Make_denorm /* The number is a de-normal */ @@ -160,12 +160,12 @@ je LRound_To_64 #ifdef PARANOID jmp L_bugged_denorm_486 -#endif PARANOID +#endif /* PARANOID */ #else #ifdef PARANOID jmp L_bugged_denorm /* There is no bug, just a bad control word */ -#endif PARANOID -#endif PECULIAR_486 +#endif /* PARANOID */ +#endif /* PECULIAR_486 */ /* Round etc to 24 bit precision */ @@ -186,7 +186,7 @@ #ifdef PARANOID jmp L_bugged_round24 -#endif PARANOID +#endif /* PARANOID */ LUp_24: cmpb SIGN_POS,PARAM5 @@ -266,7 +266,7 @@ #ifdef PARANOID jmp L_bugged_round53 -#endif PARANOID +#endif /* PARANOID */ LUp_53: cmpb SIGN_POS,PARAM5 @@ -340,7 +340,7 @@ #ifdef PARANOID jmp L_bugged_round64 -#endif PARANOID +#endif /* PARANOID */ LUp_64: cmpb SIGN_POS,PARAM5 @@ -430,7 +430,7 @@ #ifndef NON_REENTRANT_FPU popl %ebx /* adjust the stack pointer */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ fpu_Arith_exit: popl %ebx @@ -570,7 +570,7 @@ /* But check it... just in case. */ cmpw EXP_UNDER+1,EXP(%edi) jne L_norm_bugged -#endif PARANOID +#endif /* PARANOID */ #ifdef PECULIAR_486 /* @@ -586,7 +586,7 @@ #else orl %eax,%eax /* ms bits */ js L_Normalised /* No longer a denormal */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ jnz LDenormal_adj_exponent @@ -673,7 +673,7 @@ call EXCEPTION popl %ebx jmp L_exception_exit -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ L_bugged_round24: pushl EX_INTERNAL|0x231 @@ -706,4 +706,4 @@ L_exception_exit: mov $-1,%eax jmp fpu_reg_round_special_exit -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_add.S linux.ac/arch/i386/math-emu/reg_u_add.S --- linux.vanilla/arch/i386/math-emu/reg_u_add.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_u_add.S Tue Apr 10 18:07:47 2001 @@ -72,7 +72,7 @@ testl $0x80000000,SIGH(%esi) je L_bugged -#endif PARANOID +#endif /* PARANOID */ /* The number to be shifted is in %eax:%ebx:%edx */ cmpw $32,%cx /* shrd only works for 0..31 bits */ @@ -164,4 +164,4 @@ popl %esi leave ret -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_div.S linux.ac/arch/i386/math-emu/reg_u_div.S --- linux.vanilla/arch/i386/math-emu/reg_u_div.S Fri Aug 27 18:18:17 1999 +++ linux.ac/arch/i386/math-emu/reg_u_div.S Tue Apr 10 18:07:47 2001 @@ -67,7 +67,7 @@ .long 0 FPU_ovfl_flag: .byte 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ #define REGA PARAM1 #define REGB PARAM2 @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -112,7 +112,7 @@ /* je L_bugged */ testl $0x80000000, SIGH(%ebx) /* Divisor */ je L_bugged -#endif PARANOID +#endif /* PARANOID */ /* Check if the divisor can be treated as having just 32 bits */ cmpl $0,SIGL(%ebx) @@ -248,7 +248,7 @@ #ifdef PARANOID jb L_bugged_1 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ incl FPU_result_2 /* Correct the answer */ @@ -261,7 +261,7 @@ #ifdef PARANOID sbbl $0,FPU_accum_3 jne L_bugged_1 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* Half of the main problem is done, there is just a reduced numerator @@ -291,7 +291,7 @@ #ifdef PARANOID je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif PARANOID +#endif /* PARANOID */ LDo_2nd_div: cmpl $0,%ecx /* augmented denom msw */ @@ -314,7 +314,7 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ movl FPU_result_1,%eax /* Get the result back */ mull SIGL(%ebx) /* now mul the ls dw of the denom */ @@ -325,14 +325,14 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ jz LDo_3rd_32_bits #ifdef PARANOID cmpl $1,FPU_accum_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ movl SIGL(%ebx),%eax @@ -344,14 +344,14 @@ #ifdef PARANOID jc L_bugged_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ addl $1,FPU_result_1 /* Correct the answer */ adcl $0,FPU_result_2 #ifdef PARANOID jc L_bugged_2 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* The division is essentially finished here, we just need to perform @@ -470,4 +470,4 @@ leave ret -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_mul.S linux.ac/arch/i386/math-emu/reg_u_mul.S --- linux.vanilla/arch/i386/math-emu/reg_u_mul.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_u_mul.S Tue Apr 10 18:07:47 2001 @@ -40,7 +40,7 @@ .long 0 FPU_accum_1: .long 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -49,7 +49,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $8,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -63,7 +63,7 @@ jz L_bugged testl $0x80000000,SIGH(%edi) jz L_bugged -#endif PARANOID +#endif /* PARANOID */ xorl %ecx,%ecx xorl %ebx,%ebx @@ -144,5 +144,5 @@ popl %esi leave ret -#endif PARANOID +#endif /* PARANOID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/reg_u_sub.S linux.ac/arch/i386/math-emu/reg_u_sub.S --- linux.vanilla/arch/i386/math-emu/reg_u_sub.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/reg_u_sub.S Tue Apr 10 18:07:47 2001 @@ -54,7 +54,7 @@ testl $0x80000000,SIGH(%esi) je L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /*--------------------------------------+ | Form a register holding the | @@ -165,7 +165,7 @@ #ifdef PARANOID /* We can never get a borrow */ jc L_bugged -#endif PARANOID +#endif /* PARANOID */ /*--------------------------------------+ | Normalize the result | @@ -199,7 +199,7 @@ #ifdef PARANOID orl %edx,%edx jnz L_bugged_3 -#endif PARANOID +#endif /* PARANOID */ /* The result is zero */ movw $0,EXP(%edi) /* exponent */ @@ -262,7 +262,7 @@ L_error_exit: movl $-1,%eax -#endif PARANOID +#endif /* PARANOID */ L_exit: popl %ebx diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/status_w.h linux.ac/arch/i386/math-emu/status_w.h --- linux.vanilla/arch/i386/math-emu/status_w.h Mon Dec 11 21:34:33 2000 +++ linux.ac/arch/i386/math-emu/status_w.h Tue Apr 10 18:07:47 2001 @@ -58,8 +58,8 @@ # define clear_C1() { partial_status &= ~SW_C1; } # else # define clear_C1() -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _STATUS_H_ +#endif /* _STATUS_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/wm_sqrt.S linux.ac/arch/i386/math-emu/wm_sqrt.S --- linux.vanilla/arch/i386/math-emu/wm_sqrt.S Wed Dec 10 01:57:09 1997 +++ linux.ac/arch/i386/math-emu/wm_sqrt.S Tue Apr 10 18:07:47 2001 @@ -70,7 +70,7 @@ .long 0 FPU_fsqrt_arg_0: .long 0 /* ls word, at most the ms bit is set */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi pushl %ebx @@ -210,7 +210,7 @@ /* It should be possible to get here only if the arg is ffff....ffff */ cmp $0xffffffff,FPU_fsqrt_arg_1 jnz sqrt_stage_2_error -#endif PARANOID +#endif /* PARANOID */ /* The best rounded result. */ xorl %eax,%eax @@ -224,7 +224,7 @@ sqrt_stage_2_error: pushl EX_INTERNAL|0x213 call EXCEPTION -#endif PARANOID +#endif /* PARANOID */ sqrt_stage_2_done: @@ -279,7 +279,7 @@ call EXCEPTION sqrt_stage_3_no_error: -#endif PARANOID +#endif /* PARANOID */ movl FPU_accum_2,%edx movl FPU_accum_1,%eax @@ -385,7 +385,7 @@ call EXCEPTION sqrt_near_exact_ok: -#endif PARANOID +#endif /* PARANOID */ or %ebx,%ebx js sqrt_near_exact_small @@ -445,7 +445,7 @@ call EXCEPTION sqrt_more_prec_ok: -#endif PARANOID +#endif /* PARANOID */ or %ebx,%ebx js sqrt_more_prec_small diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/mm/fault.c linux.ac/arch/i386/mm/fault.c --- linux.vanilla/arch/i386/mm/fault.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/mm/fault.c Wed Apr 4 13:37:37 2001 @@ -4,6 +4,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include /* For unblank_screen() */ #include #include @@ -25,6 +27,8 @@ extern void die(const char *,struct pt_regs *,long); +extern int console_loglevel; + /* * Ugly, ugly, but the goto's result in better assembly.. */ @@ -77,17 +81,69 @@ return 0; } -extern spinlock_t console_lock, timerlist_lock; +extern spinlock_t timerlist_lock; /* * Unlock any spinlocks which will prevent us from getting the * message out (timerlist_lock is acquired through the * console unblank code) */ -void bust_spinlocks(void) +void bust_spinlocks(int yes) { - spin_lock_init(&console_lock); spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + global_irq_lock = 0; /* Many serial drivers do __global_cli() */ +#endif + } else { + int loglevel_save = console_loglevel; +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + +void do_BUG(const char *file, int line) +{ + bust_spinlocks(1); + printk("kernel BUG at %s:%d!\n", file, line); +} + +static void print_pagetable_entries (pgd_t *pgdir, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgdir + __pgd_offset(address); + printk("pgd entry %p: %016Lx\n", pgd, (long long)pgd_val(*pgd)); + + if (!pgd_present(*pgd)) { + printk("... pgd not present!\n"); + return; + } + pmd = pmd_offset(pgd, address); + printk("pmd entry %p: %016Lx\n", pmd, (long long)pmd_val(*pmd)); + + if (!pmd_present(*pmd)) { + printk("... pmd not present!\n"); + return; + } + pte = pte_offset(pmd, address); + printk("pte entry %p: %016Lx\n", pte, (long long)pte_val(*pte)); + + if (!pte_present(*pte)) + printk("... pte not present!\n"); } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); @@ -264,7 +320,7 @@ * terminate things with extreme prejudice. */ - bust_spinlocks(); + bust_spinlocks(1); if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -274,15 +330,9 @@ printk(" printing eip:\n"); printk("%08lx\n", regs->eip); asm("movl %%cr3,%0":"=r" (page)); - 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); - } + print_pagetable_entries((pgd_t *)__va(page), address); die("Oops", regs, error_code); + bust_spinlocks(0); do_exit(SIGKILL); /* @@ -322,7 +372,11 @@ /* * Synchronize this task's top level page-table * with the 'reference' page table. + * + * Note. There is 1 gotcha here. We may be doing the WP + * test. If so then fixing the pgd/pmd won't help. */ + int offset = __pgd_offset(address); pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; @@ -340,7 +394,29 @@ pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + /* If the pmd is present then we either have two cpus trying + * to fill in the vmalloc entries at once, or we have an + * exception. We can treat the collision as a slow path without + * worry. Its incredibly incredibly rare + * + * If the pte is read only then we know its a fault and we must + * exception or Oops as it would loop forever otherwise + */ + + if (pmd_present(*pmd)) + { + pte_t *ptep = pte_offset(pmd, address); + if ((error_code & 2) && !pte_write(*ptep)) + { + if ((fixup = search_exception_table(regs->eip)) != 0) { + regs->eip = fixup; + return; + } + goto bad_area_nosemaphore; + } + /* SMP race.. continue */ + } + if (!pmd_present(*pmd_k)) goto bad_area_nosemaphore; set_pmd(pmd, *pmd_k); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/mm/init.c linux.ac/arch/i386/mm/init.c --- linux.vanilla/arch/i386/mm/init.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/i386/mm/init.c Sun Apr 22 01:16:07 2001 @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -35,7 +38,9 @@ #include #include #include +#include +mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long highstart_pfn, highend_pfn; static unsigned long totalram_pages; static unsigned long totalhigh_pages; @@ -131,15 +136,11 @@ pte_t *pte; pgd = swapper_pg_dir + __pgd_offset(vaddr); - if (pgd_none(*pgd)) { - printk("PAE BUG #00!\n"); - return; - } + if (pgd_none(*pgd)) + BUG(); pmd = pmd_offset(pgd, vaddr); - if (pmd_none(*pmd)) { - printk("PAE BUG #01!\n"); - return; - } + if (pmd_none(*pmd)) + BUG(); pte = pte_offset(pmd, vaddr); if (pte_val(*pte)) pte_ERROR(*pte); @@ -183,7 +184,7 @@ pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); if (pmd != pmd_offset(pgd, 0)) - printk("PAE BUG #02!\n"); + BUG(); } pmd = pmd_offset(pgd, vaddr); #else @@ -309,14 +310,11 @@ * Zap initial low-memory mappings. * * Note that "pgd_clear()" doesn't do it for - * us in this case, because pgd_clear() is a - * no-op in the 2-level case (pmd_clear() is - * the thing that clears the page-tables in - * that case). + * us, because pgd_clear() is a no-op on i386. */ for (i = 0; i < USER_PTRS_PER_PGD; i++) #if CONFIG_X86_PAE - pgd_clear(swapper_pg_dir+i); + set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); #else set_pgd(swapper_pg_dir+i, __pgd(0)); #endif @@ -581,3 +579,23 @@ val->mem_unit = PAGE_SIZE; return; } + +#if CONFIG_X86_PAE + +#include + +struct kmem_cache_s *pae_pgd_cachep; + +void __init init_pae_pgd_cache(void) +{ + /* + * PAE pgds must be 16-byte aligned: + */ + pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0, + SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL); + if (!pae_pgd_cachep) + panic("init_pae(): Cannot alloc pae_pgd SLAB cache"); +} + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/Makefile linux.ac/arch/ia64/Makefile --- linux.vanilla/arch/ia64/Makefile Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/Makefile Tue Apr 10 18:07:54 2001 @@ -5,7 +5,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1998-2000 by David Mosberger-Tang +# Copyright (C) 1998-2001 by David Mosberger-Tang # NM := $(CROSS_COMPILE)nm -B @@ -14,13 +14,13 @@ export AWK LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds -AFLAGS += -Wa,-x +AFLAGS += -Wa,-x AFLAGS_KERNEL := -mconstant-gp EXTRA = CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ -funwind-tables -falign-functions=32 -# -frename-registers +# -frename-registers (this crashes the Nov 17 compiler...) CFLAGS_KERNEL := -mconstant-gp ifeq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) @@ -53,7 +53,7 @@ endif ifdef CONFIG_IA64_SGI_SN1 -CFLAGS += -DBRINGUP + CFLAGS += -DBRINGUP SUBDIRS := arch/$(ARCH)/sn/sn1 \ arch/$(ARCH)/sn \ arch/$(ARCH)/sn/io \ @@ -103,6 +103,11 @@ FORCE: ; +compressed: vmlinux + $(OBJCOPY) --strip-all vmlinux vmlinux-tmp + gzip -9 vmlinux-tmp + mv vmlinux-tmp.gz vmlinux.gz + rawboot: @$(MAKEBOOT) rawboot @@ -120,8 +125,6 @@ @$(MAKEBOOT) srmboot archclean: - @$(MAKE) -C arch/$(ARCH)/kernel clean - @$(MAKE) -C arch/$(ARCH)/tools clean @$(MAKEBOOT) clean archmrproper: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/boot/bootloader.c linux.ac/arch/ia64/boot/bootloader.c --- linux.vanilla/arch/ia64/boot/bootloader.c Tue Oct 10 01:54:53 2000 +++ linux.ac/arch/ia64/boot/bootloader.c Tue Apr 10 18:08:40 2001 @@ -3,8 +3,8 @@ * * Loads an ELF kernel. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang * Copyright (C) 1998, 1999 Stephane Eranian * * 01/07/99 S.Eranian modified to pass command line arguments to kernel @@ -65,35 +65,22 @@ } } -void -enter_virtual_mode (unsigned long new_psr) -{ - long tmp; - - asm volatile ("movl %0=1f" : "=r"(tmp)); - asm volatile ("mov cr.ipsr=%0" :: "r"(new_psr)); - asm volatile ("mov cr.iip=%0" :: "r"(tmp)); - asm volatile ("mov cr.ifs=r0"); - asm volatile ("rfi;;"); - asm volatile ("1:"); -} - #define MAX_ARGS 32 void _start (void) { - register long sp asm ("sp"); static char stack[16384] __attribute__ ((aligned (16))); static char mem[4096]; static char buffer[1024]; - unsigned long flags, off; + unsigned long off; int fd, i; struct disk_req req; struct disk_stat stat; struct elfhdr *elf; struct elf_phdr *elf_phdr; /* program header */ unsigned long e_entry, e_phoff, e_phnum; + register struct ia64_boot_param *bp; char *kpath, *args; long arglen = 0; @@ -107,15 +94,13 @@ ssc(0, 0, 0, 0, SSC_CONSOLE_INIT); /* - * S.Eranian: extract the commandline argument from the - * simulator + * S.Eranian: extract the commandline argument from the simulator * * The expected format is as follows: * * kernelname args... * - * Both are optional but you can't have the second one without the - * first. + * Both are optional but you can't have the second one without the first. */ arglen = ssc((long) buffer, 0, 0, 0, SSC_GET_ARGS); @@ -183,6 +168,10 @@ e_phoff += sizeof(*elf_phdr); elf_phdr = (struct elf_phdr *) mem; + + if (elf_phdr->p_type != PT_LOAD) + continue; + req.len = elf_phdr->p_filesz; req.addr = __pa(elf_phdr->p_vaddr); ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ); @@ -197,38 +186,12 @@ /* fake an I/O base address: */ asm volatile ("mov ar.k0=%0" :: "r"(0xffffc000000UL)); - /* - * Install a translation register that identity maps the - * kernel's 256MB page. - */ - ia64_clear_ic(flags); - ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); - ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); - ia64_srlz_d(); - ia64_itr(0x3, 0, 1024*1024, - pte_val(mk_pte_phys(1024*1024, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), - _PAGE_SIZE_1M); - ia64_itr(0x3, 1, PAGE_OFFSET, - pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), - _PAGE_SIZE_256M); - ia64_srlz_i(); - - enter_virtual_mode(flags | IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT - | IA64_PSR_DFH | IA64_PSR_BN); - - sys_fw_init(args, arglen); + bp = sys_fw_init(args, arglen); ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS); - /* - * Install the kernel's command line argument on ZERO_PAGE - * just after the botoparam structure. - * In case we don't have any argument just put \0 - */ - memcpy(((struct ia64_boot_param *)ZERO_PAGE_ADDR) + 1, args, arglen); - sp = __pa(&stack); - - asm volatile ("br.sptk.few %0" :: "b"(e_entry)); + asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0" + :: "b"(e_entry), "r"(bp), "r"(__pa(&stack))); cons_write("kernel returned!\n"); ssc(-1, 0, 0, 0, SSC_EXIT); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/config.in linux.ac/arch/ia64/config.in --- linux.vanilla/arch/ia64/config.in Fri Feb 16 23:53:08 2001 +++ linux.ac/arch/ia64/config.in Wed Apr 18 13:47:54 2001 @@ -23,6 +23,12 @@ define_bool CONFIG_EISA n define_bool CONFIG_MCA n define_bool CONFIG_SBUS n +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n + +choice 'IA-64 processor type' \ + "Itanium CONFIG_ITANIUM \ + McKinley CONFIG_MCKINLEY" Itanium choice 'IA-64 system type' \ "generic CONFIG_IA64_GENERIC \ @@ -36,24 +42,47 @@ 16KB CONFIG_IA64_PAGE_SIZE_16KB \ 64KB CONFIG_IA64_PAGE_SIZE_64KB" 16KB -if [ "$CONFIG_IA64_DIG" = "y" ]; then - define_bool CONFIG_ITANIUM y +if [ "$CONFIG_ITANIUM" = "y" ]; then define_bool CONFIG_IA64_BRL_EMU y bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC + fi + if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B1-step specific code' CONFIG_ITANIUM_B1_SPECIFIC + fi + if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B2-step specific code' CONFIG_ITANIUM_B2_SPECIFIC fi bool ' Enable Itanium C-step specific code' CONFIG_ITANIUM_CSTEP_SPECIFIC if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC fi + if [ "$CONFIG_ITANIUM_ASTEP_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \ + -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then + define_bool CONFIG_ITANIUM_PTCG n + else + define_bool CONFIG_ITANIUM_PTCG y + fi + if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then + define_int CONFIG_IA64_L1_CACHE_SHIFT 7 # align cache-sensitive data to 128 bytes + else + define_int CONFIG_IA64_L1_CACHE_SHIFT 6 # align cache-sensitive data to 64 bytes + fi +fi + +if [ "$CONFIG_MCKINLEY" = "y" ]; then + define_bool CONFIG_ITANIUM_PTCG y + define_int CONFIG_IA64_L1_CACHE_SHIFT 7 + bool ' Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC + if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then + bool ' Enable McKinley A0/A1-step specific code' CONFIG_MCKINLEY_A0_SPECIFIC + fi +fi + +if [ "$CONFIG_IA64_DIG" = "y" ]; then bool ' Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR - bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG - bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS - bool ' Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA bool ' Enable ACPI 2.0 with errata 1.3' CONFIG_ACPI20 bool ' ACPI kernel configuration manager (EXPERIMENTAL)' CONFIG_ACPI_KERNEL_CONFIG @@ -65,11 +94,6 @@ fi if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then - bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG - bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC - fi bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM define_bool CONFIG_DEVFS_DEBUG y define_bool CONFIG_DEVFS_FS y @@ -87,7 +111,8 @@ bool 'SMP support' CONFIG_SMP bool 'Performance monitor support' CONFIG_PERFMON -bool '/proc/pal support' CONFIG_IA64_PALINFO +tristate '/proc/pal support' CONFIG_IA64_PALINFO +tristate '/proc/efi support' CONFIG_IA64_EFIVARS bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC @@ -123,7 +148,7 @@ source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in source drivers/md/Config.in mainmenu_option next_comment @@ -253,7 +278,6 @@ bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS -bool 'Enable new unwind support' CONFIG_IA64_NEW_UNWIND bool 'Disable VHPT' CONFIG_DISABLE_VHPT endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/dig/setup.c linux.ac/arch/ia64/dig/setup.c --- linux.vanilla/arch/ia64/dig/setup.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/dig/setup.c Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* - * Platform dependent support for Intel SoftSDV simulator. + * Platform dependent support for DIG64 platforms. * * Copyright (C) 1999 Intel Corp. - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1999, 2001 David Mosberger-Tang * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * Copyright (C) 1999 Vijay Chander @@ -48,18 +48,14 @@ */ ROOT_DEV = to_kdev_t(0x0802); /* default to second partition on first drive */ -#ifdef CONFIG_IA64_SOFTSDV_HACKS - ROOT_DEV = to_kdev_t(0x0302); /* 2nd partion on 1st IDE */ -#endif /* CONFIG_IA64_SOFTSDV_HACKS */ - #ifdef CONFIG_SMP init_smp_config(); #endif memset(&screen_info, 0, sizeof(screen_info)); - if (!ia64_boot_param.console_info.num_rows - || !ia64_boot_param.console_info.num_cols) + if (!ia64_boot_param->console_info.num_rows + || !ia64_boot_param->console_info.num_cols) { printk("dig_setup: warning: invalid screen-info, guessing 80x25\n"); orig_x = 0; @@ -68,10 +64,10 @@ num_rows = 25; font_height = 16; } else { - orig_x = ia64_boot_param.console_info.orig_x; - orig_y = ia64_boot_param.console_info.orig_y; - num_cols = ia64_boot_param.console_info.num_cols; - num_rows = ia64_boot_param.console_info.num_rows; + orig_x = ia64_boot_param->console_info.orig_x; + orig_y = ia64_boot_param->console_info.orig_y; + num_cols = ia64_boot_param->console_info.num_cols; + num_rows = ia64_boot_param->console_info.num_rows; font_height = 400 / num_rows; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/hp/hpsim_irq.c linux.ac/arch/ia64/hp/hpsim_irq.c --- linux.vanilla/arch/ia64/hp/hpsim_irq.c Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/hp/hpsim_irq.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Platform dependent support for HP simulator. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang */ #include @@ -35,10 +35,12 @@ void __init hpsim_irq_init (void) { + irq_desc_t *idesc; int i; - for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) { - if (irq_desc[i].handler == &no_irq_type) - irq_desc[i].handler = &irq_type_hp_sim; + for (i = 0; i < NR_IRQS; ++i) { + idesc = irq_desc(i); + if (idesc->handler == &no_irq_type) + idesc->handler = &irq_type_hp_sim; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/binfmt_elf32.c linux.ac/arch/ia64/ia32/binfmt_elf32.c --- linux.vanilla/arch/ia64/ia32/binfmt_elf32.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/ia32/binfmt_elf32.c Tue Apr 10 18:08:40 2001 @@ -57,28 +57,30 @@ if (page_count(page) != 1) printk("mem_map disagrees with %p at %08lx\n", (void *) page, address); + pgd = pgd_offset(tsk->mm, address); - pmd = pmd_alloc(pgd, address); - if (!pmd) { - __free_page(page); - force_sig(SIGKILL, tsk); - return 0; - } - pte = pte_alloc(pmd, address); - if (!pte) { - __free_page(page); - force_sig(SIGKILL, tsk); - return 0; - } - if (!pte_none(*pte)) { - pte_ERROR(*pte); - __free_page(page); - return 0; + + spin_lock(&tsk->mm->page_table_lock); + { + pmd = pmd_alloc(tsk->mm, pgd, address); + if (!pmd) + goto out; + pte = pte_alloc(tsk->mm, pmd, address); + if (!pte) + goto out; + if (!pte_none(*pte)) + goto out; + flush_page_to_ram(page); + set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED))); } - flush_page_to_ram(page); - set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED))); + spin_unlock(&tsk->mm->page_table_lock); /* no need for flush_tlb */ return page; + + out: + spin_unlock(&tsk->mm->page_table_lock); + __free_page(page); + return 0; } void ia64_elf32_init(struct pt_regs *regs) @@ -90,12 +92,13 @@ put_shared_page(current, virt_to_page(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE); nr = smp_processor_id(); - + /* Do all the IA-32 setup here */ - current->thread.map_base = 0x40000000; - current->thread.task_size = 0xc0000000; /* use what Linux/x86 uses... */ - + current->thread.map_base = 0x40000000; + current->thread.task_size = 0xc0000000; /* use what Linux/x86 uses... */ + set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ + /* setup ia32 state for ia32_load_state */ current->thread.eflag = IA32_EFLAG; @@ -124,14 +127,8 @@ : "r" ((ulong)IA32_FCR_DEFAULT)); __asm__("mov ar.fir = r0"); __asm__("mov ar.fdr = r0"); - __asm__("mov %0=ar.k0 ;;" : "=r" (current->thread.old_iob)); - __asm__("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE)); - /* TSS */ - __asm__("mov ar.k1 = %0" - : /* no outputs */ - : "r" IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, - 0x1FFFL, 0xBL, 1L, - 3L, 1L, 1L, 1L)); + current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); + ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); /* Get the segment selectors right */ regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ @@ -149,23 +146,10 @@ regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L, 1L, 1L, 1L); - /* Clear psr.ac */ + /* Clear psr.ac */ regs->cr_ipsr &= ~IA64_PSR_AC; regs->loadrs = 0; - /* - * According to the ABI %edx points to an `atexit' handler. - * Since we don't have one we'll set it to 0 and initialize - * all the other registers just to make things more deterministic, - * ala the i386 implementation. - */ - regs->r8 = 0; /* %eax */ - regs->r11 = 0; /* %ebx */ - regs->r9 = 0; /* %ecx */ - regs->r10 = 0; /* %edx */ - regs->r13 = 0; /* %ebp */ - regs->r14 = 0; /* %esi */ - regs->r15 = 0; /* %edi */ } #undef STACK_TOP @@ -185,9 +169,9 @@ bprm->exec += stack_base; mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!mpnt) - return -ENOMEM; - + if (!mpnt) + return -ENOMEM; + { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -200,7 +184,7 @@ mpnt->vm_private_data = 0; insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; - } + } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { @@ -208,7 +192,7 @@ } stack_base += PAGE_SIZE; } - + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/ia32_entry.S linux.ac/arch/ia64/ia32/ia32_entry.S --- linux.vanilla/arch/ia64/ia32/ia32_entry.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/ia32/ia32_entry.S Tue Apr 10 18:08:40 2001 @@ -4,11 +4,34 @@ #include "../kernel/entry.h" + /* + * execve() is special because in case of success, we need to + * setup a null register window frame (in case an IA-32 process + * is exec'ing an IA-64 program). + */ +ENTRY(ia32_execve) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3) + alloc loc1=ar.pfs,3,2,4,0 + mov loc0=rp + .body + mov out0=in0 // filename + ;; // stop bit between alloc and call + mov out1=in1 // argv + mov out2=in2 // envp + add out3=16,sp // regs + br.call.sptk.few rp=sys32_execve +1: cmp4.ge p6,p0=r8,r0 + mov ar.pfs=loc1 // restore ar.pfs + ;; +(p6) mov ar.pfs=r0 // clear ar.pfs in case of success + sxt4 r8=r8 // return 64-bit result + mov rp=loc0 + br.ret.sptk.few rp +END(ia32_execve) + // // Get possibly unaligned sigmask argument into an aligned // kernel buffer - .text - GLOBAL_ENTRY(ia32_rt_sigsuspend) // We'll cheat and not do an alloc here since we are ultimately // going to do a simple branch to the IA64 sys_rt_sigsuspend. @@ -16,38 +39,30 @@ // We copy this 4-byte aligned value to an 8-byte aligned buffer // in the task structure and then jump to the IA64 code. - mov r8=r0 // no memory access errors yet - add r10=4,r32 - ;; -1: - ld4 r2=[r32] // get first half of sigmask - ld4 r3=[r10] // get second half of sigmask -2: - cmp.lt p6,p0=r8,r0 // check memory access + EX(.Lfail, ld4 r2=[r32],4) // load low part of sigmask ;; -(p6) br.ret.sptk.many rp // it failed - + EX(.Lfail, ld4 r3=[r32]) // load high part of sigmask adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13 + ;; + st8 [r32]=r2 adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13 ;; - st4 [r32]=r2 + st4 [r10]=r3 br.cond.sptk.many sys_rt_sigsuspend -END(ia32_rt_sigsuspend) - .section __ex_table,"a" - data4 @gprel(1b) - data4 (2b-1b)|1 - .previous +.Lfail: br.ret.sptk.many rp // failed to read sigmask +END(ia32_rt_sigsuspend) GLOBAL_ENTRY(ia32_ret_from_syscall) PT_REGS_UNWIND_INFO(0) cmp.ge p6,p7=r8,r0 // syscall executed successfully? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 - ;; + ;; + alloc r3=ar.pfs,0,0,0,0 // drop the syscall argument frame st8 [r2]=r8 // store return value in slot for r8 - br.cond.sptk.few ia64_leave_kernel + br.cond.sptk.many ia64_leave_kernel END(ia32_ret_from_syscall) // @@ -69,7 +84,8 @@ ;; st8.spill [r2]=r8 // store return value in slot for r8 br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.ret2: br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! +.ret2: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame + br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! END(ia32_trace_syscall) GLOBAL_ENTRY(sys32_vfork) @@ -79,7 +95,7 @@ END(sys32_vfork) GLOBAL_ENTRY(sys32_fork) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) alloc r16=ar.pfs,2,2,4,0 mov out0=SIGCHLD // out0 = clone_flags ;; @@ -88,14 +104,14 @@ mov loc1=r16 // save ar.pfs across do_fork DO_SAVE_SWITCH_STACK - UNW(.body) + .body mov out1=0 mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s br.call.sptk.few rp=do_fork .ret3: mov ar.pfs=loc1 - UNW(.restore sp) + .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov rp=loc0 br.ret.sptk.many rp @@ -104,7 +120,7 @@ .rodata .align 8 .globl ia32_syscall_table -ia32_syscall_table: +ia32_syscall_table: data8 sys32_ni_syscall /* 0 - old "setup(" system call*/ data8 sys_exit data8 sys32_fork @@ -116,7 +132,7 @@ data8 sys_creat data8 sys_link data8 sys_unlink /* 10 */ - data8 sys32_execve + data8 ia32_execve data8 sys_chdir data8 sys32_time data8 sys_mknod @@ -133,8 +149,8 @@ data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ data8 sys32_ptrace data8 sys32_alarm - data8 sys_pause data8 sys32_ni_syscall + data8 sys_pause data8 ia32_utime /* 30 */ data8 sys32_ni_syscall /* old stty syscall holder */ data8 sys32_ni_syscall /* old gtty syscall holder */ @@ -153,7 +169,7 @@ data8 sys_brk /* 45 */ data8 sys_setgid data8 sys_getgid - data8 sys32_ni_syscall + data8 sys32_signal data8 sys_geteuid data8 sys_getegid /* 50 */ data8 sys_acct @@ -227,7 +243,7 @@ data8 sys32_sigreturn data8 sys_clone /* 120 */ data8 sys_setdomainname - data8 sys_newuname + data8 sys32_newuname data8 sys_modify_ldt data8 sys_adjtimex data8 sys32_mprotect /* 125 */ @@ -249,12 +265,12 @@ data8 sys32_getdents data8 sys32_select data8 sys_flock - data8 sys_msync + data8 sys32_msync data8 sys32_readv /* 145 */ data8 sys32_writev data8 sys_getsid data8 sys_fdatasync - data8 sys_sysctl + data8 sys32_sysctl data8 sys_mlock /* 150 */ data8 sys_munlock data8 sys_mlockall diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/ia32_support.c linux.ac/arch/ia64/ia32/ia32_support.c --- linux.vanilla/arch/ia64/ia32/ia32_support.c Tue Oct 10 01:54:53 2000 +++ linux.ac/arch/ia64/ia32/ia32_support.c Tue Apr 10 18:08:40 2001 @@ -2,6 +2,7 @@ * IA32 helper functions * * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context + * 02/19/01 D. Mosberger dropped tssd; it's not needed */ #include @@ -22,7 +23,7 @@ void ia32_save_state (struct thread_struct *thread) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; asm ("mov %0=ar.eflag;" "mov %1=ar.fsr;" @@ -31,9 +32,7 @@ "mov %4=ar.fdr;" "mov %5=ar.csd;" "mov %6=ar.ssd;" - "mov %7=ar.k1" - : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), - "=r"(csd), "=r"(ssd), "=r"(tssd)); + : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd)); thread->eflag = eflag; thread->fsr = fsr; thread->fcr = fcr; @@ -41,14 +40,13 @@ thread->fdr = fdr; thread->csd = csd; thread->ssd = ssd; - thread->tssd = tssd; asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob)); } void ia32_load_state (struct thread_struct *thread) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; eflag = thread->eflag; fsr = thread->fsr; @@ -57,7 +55,6 @@ fdr = thread->fdr; csd = thread->csd; ssd = thread->ssd; - tssd = thread->tssd; asm volatile ("mov ar.eflag=%0;" "mov ar.fsr=%1;" @@ -66,9 +63,7 @@ "mov ar.fdr=%4;" "mov ar.csd=%5;" "mov ar.ssd=%6;" - "mov ar.k1=%7" - :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), - "r"(csd), "r"(ssd), "r"(tssd)); + :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd)); asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob)); asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/ia32/sys_ia32.c linux.ac/arch/ia64/ia32/sys_ia32.c --- linux.vanilla/arch/ia64/ia32/sys_ia32.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/ia32/sys_ia32.c Tue Apr 10 18:08:40 2001 @@ -1,12 +1,12 @@ /* * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on - * sys_sparc32 + * sys_sparc32 * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger - * Copyright (C) 1999 Arun Sharma - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1999 Arun Sharma + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 2000 Hewlett-Packard Co. * Copyright (C) 2000 David Mosberger-Tang * @@ -16,9 +16,10 @@ #include #include +#include #include -#include -#include +#include +#include #include #include #include @@ -64,96 +65,87 @@ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *); -extern asmlinkage long sys_munmap (unsigned long, size_t len); extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long); static int -nargs(unsigned int arg, char **ap) +nargs (unsigned int arg, char **ap) { int n, err, addr; + if (!arg) + return 0; + n = 0; do { err = get_user(addr, (int *)A(arg)); if (err) return err; - if (ap) { /* no access_ok needed, we allocated */ - err = __put_user((char *)A(addr), ap++); - if (err) - return err; - } + if (ap) + *ap++ = (char *) A(addr); arg += sizeof(unsigned int); n++; } while (addr); - return(n - 1); + return n - 1; } asmlinkage long -sys32_execve( -char *filename, -unsigned int argv, -unsigned int envp, -int dummy3, -int dummy4, -int dummy5, -int dummy6, -int dummy7, -int stack) +sys32_execve (char *filename, unsigned int argv, unsigned int envp, + int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, + int stack) { struct pt_regs *regs = (struct pt_regs *)&stack; + unsigned long old_map_base, old_task_size; char **av, **ae; int na, ne, len; long r; na = nargs(argv, NULL); if (na < 0) - return(na); + return na; ne = nargs(envp, NULL); if (ne < 0) - return(ne); + return ne; len = (na + ne + 2) * sizeof(*av); - /* - * kmalloc won't work because the `sys_exec' code will attempt - * to do a `get_user' on the arg list and `get_user' will fail - * on a kernel address (simplifies `get_user'). Instead we - * do an mmap to get a user address. Note that since a successful - * `execve' frees all current memory we only have to do an - * `munmap' if the `execve' failes. - */ - down_write(¤t->mm->mmap_sem); - - av = (char **) do_mmap_pgoff(0, 0UL, len, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, 0); - - up_write(¤t->mm->mmap_sem); + av = kmalloc(len, GFP_KERNEL); + if (!av) + return -ENOMEM; - if (IS_ERR(av)) - return (long)av; ae = av + na + 1; - r = __put_user(0, (av + na)); - if (r) - goto out; - r = __put_user(0, (ae + ne)); - if (r) - goto out; + av[na] = NULL; + ae[ne] = NULL; + r = nargs(argv, av); if (r < 0) goto out; r = nargs(envp, ae); if (r < 0) goto out; + + old_map_base = current->thread.map_base; + old_task_size = current->thread.task_size; + + /* we may be exec'ing a 64-bit process: reset map base & task-size: */ + current->thread.map_base = DEFAULT_MAP_BASE; + current->thread.task_size = DEFAULT_TASK_SIZE; + + set_fs(KERNEL_DS); r = sys_execve(filename, av, ae, regs); - if (r < 0) -out: - sys_munmap((unsigned long) av, len); - return(r); + if (r < 0) { + /* oops, execve failed, switch back to old map base & task-size: */ + current->thread.map_base = old_map_base; + current->thread.task_size = old_task_size; + set_fs(USER_DS); /* establish new task-size as the address-limit */ + out: + kfree(av); + } + return r; } static inline int putstat(struct stat32 *ubuf, struct stat *kbuf) { int err; - + err = put_user (kbuf->st_dev, &ubuf->st_dev); err |= __put_user (kbuf->st_ino, &ubuf->st_ino); err |= __put_user (kbuf->st_mode, &ubuf->st_mode); @@ -178,8 +170,8 @@ int ret; struct stat s; mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); + + set_fs(KERNEL_DS); ret = sys_newstat(filename, &s); set_fs (old_fs); if (putstat (statbuf, &s)) @@ -195,7 +187,7 @@ int ret; struct stat s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_newlstat(filename, &s); set_fs (old_fs); @@ -212,7 +204,7 @@ int ret; struct stat s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); set_fs (old_fs); @@ -221,7 +213,6 @@ return ret; } -#define ALIGN4K(a) (((a) + 0xfff) & ~0xfff) #define OFFSET4K(a) ((a) & 0xfff) unsigned long @@ -287,19 +278,19 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); prot |= PROT_EXEC; - if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) - error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); + if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) + error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); else { - poff = offset & PAGE_MASK; - len += offset - poff; + poff = offset & PAGE_MASK; + len += offset - poff; + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); + up_write(¤t->mm->mmap_sem); - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); - - if (!IS_ERR((void *) error)) - error += offset - poff; - } + if (!IS_ERR((void *) error)) + error += offset - poff; + } return error; } @@ -328,18 +319,46 @@ if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; + if (PAGE_ALIGN(a.len) == 0) + return a.addr; + if (!(a.flags & MAP_ANONYMOUS)) { file = fget(a.fd); if (!file) return -EBADF; } +#ifdef CONFIG_IA64_PAGE_SIZE_4KB + if ((a.offset & ~PAGE_MASK) != 0) + return -EINVAL; + + down_write(¤t->mm->mmap_sem); + retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT); + up_write(¤t->mm->mmap_sem); +#else // CONFIG_IA64_PAGE_SIZE_4KB retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset); +#endif // CONFIG_IA64_PAGE_SIZE_4KB if (file) fput(file); return retval; } asmlinkage long +sys32_mprotect(unsigned long start, size_t len, unsigned long prot) +{ + +#ifdef CONFIG_IA64_PAGE_SIZE_4KB + return(sys_mprotect(start, len, prot)); +#else // CONFIG_IA64_PAGE_SIZE_4KB + if (prot == 0) + return(0); + len += start & ~PAGE_MASK; + if ((start & ~PAGE_MASK) && (prot & PROT_WRITE)) + prot |= PROT_EXEC; + return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); +#endif // CONFIG_IA64_PAGE_SIZE_4KB +} + +asmlinkage long sys32_pipe(int *fd) { int retval; @@ -355,15 +374,17 @@ } asmlinkage long -sys32_mprotect(unsigned long start, size_t len, unsigned long prot) +sys32_signal (int sig, unsigned int handler) { + struct k_sigaction new_sa, old_sa; + int ret; - if (prot == 0) - return(0); - len += start & ~PAGE_MASK; - if ((start & ~PAGE_MASK) && (prot & PROT_WRITE)) - prot |= PROT_EXEC; - return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); + new_sa.sa.sa_handler = (__sighandler_t) A(handler); + new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; + + ret = do_sigaction(sig, &new_sa, &old_sa); + + return ret ? ret : (unsigned long)old_sa.sa.sa_handler; } asmlinkage long @@ -393,7 +414,7 @@ | (((long)set32.sig[1]) << 32); } ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - + if (ret) return -EFAULT; } @@ -436,7 +457,7 @@ sigset32_t s32; int ret; mm_segment_t old_fs = get_fs(); - + if (set) { if (copy_from_user (&s32, set, sizeof(sigset32_t))) return -EFAULT; @@ -449,7 +470,7 @@ } set_fs (KERNEL_DS); ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, - sigsetsize); + sigsetsize); set_fs (old_fs); if (ret) return ret; if (oset) { @@ -469,7 +490,7 @@ put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { int err; - + err = put_user (kbuf->f_type, &ubuf->f_type); err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize); err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks); @@ -491,7 +512,7 @@ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_statfs((const char *)path, &s); set_fs (old_fs); @@ -508,7 +529,7 @@ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_fstatfs(fd, &s); set_fs (old_fs); @@ -534,7 +555,6 @@ return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec))); - return ENOSYS; } static inline long @@ -553,18 +573,16 @@ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); - return ENOSYS; } static inline long put_it32(struct itimerval32 *o, struct itimerval *i) { - return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) || + return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); - return ENOSYS; } extern int do_getitimer(int which, struct itimerval *value); @@ -605,7 +623,7 @@ return 0; } -asmlinkage unsigned long +asmlinkage unsigned long sys32_alarm(unsigned int seconds) { struct itimerval it_new, it_old; @@ -638,7 +656,7 @@ ia32_utime(char * filename, struct utimbuf_32 *times32) { mm_segment_t old_fs = get_fs(); - struct timeval tv[2]; + struct timeval tv[2], *tvp; long ret; if (times32) { @@ -647,15 +665,10 @@ get_user(tv[1].tv_sec, ×32->mtime); tv[1].tv_usec = 0; set_fs (KERNEL_DS); - } else { - set_fs (KERNEL_DS); - ret = sys_gettimeofday(&tv[0], 0); - if (ret < 0) - goto out; - tv[1] = tv[0]; - } - ret = sys_utimes(filename, tv); - out: + tvp = tv; + } else + tvp = NULL; + ret = sys_utimes(filename, tvp); set_fs (old_fs); return ret; } @@ -685,7 +698,7 @@ struct timeval ktv; struct timezone ktz; - if (tv) { + if (tv) { if (get_tv32(&ktv, tv)) return -EFAULT; } @@ -872,7 +885,7 @@ /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), * since we used fdset we need to allocate memory in units of - * long-words. + * long-words. */ ret = -ENOMEM; size = FDS_BYTES(n); @@ -946,11 +959,11 @@ } struct timespec32 { - int tv_sec; + int tv_sec; int tv_nsec; }; -extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); +extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); asmlinkage long sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) @@ -958,7 +971,7 @@ struct timespec t; int ret; mm_segment_t old_fs = get_fs (); - + if (get_user (t.tv_sec, &rqtp->tv_sec) || __get_user (t.tv_nsec, &rqtp->tv_nsec)) return -EFAULT; @@ -967,7 +980,7 @@ set_fs (old_fs); if (rmtp && ret == -EINTR) { if (__put_user (t.tv_sec, &rmtp->tv_sec) || - __put_user (t.tv_nsec, &rmtp->tv_nsec)) + __put_user (t.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; } return ret; @@ -1072,7 +1085,7 @@ struct rlimit r; int ret; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_getrlimit(resource, &r); set_fs (old_fs); @@ -1092,7 +1105,7 @@ int ret; mm_segment_t old_fs = get_fs (); - if (resource >= RLIM_NLIMITS) return -EINVAL; + if (resource >= RLIM_NLIMITS) return -EINVAL; if (get_user (r.rlim_cur, &rlim->rlim_cur) || __get_user (r.rlim_max, &rlim->rlim_max)) return -EFAULT; @@ -1109,7 +1122,7 @@ /* * Declare the IA32 version of the msghdr */ - + struct msghdr32 { unsigned int msg_name; /* Socket name */ int msg_namelen; /* Length of name */ @@ -1157,7 +1170,7 @@ { int size, err, ct; struct iovec32 *iov32; - + if(m->msg_namelen) { if(mode==VERIFY_READ) @@ -1166,7 +1179,7 @@ if(err<0) goto out; } - + m->msg_name = address; } else m->msg_name = NULL; @@ -1195,7 +1208,7 @@ } /* XXX This really belongs in some header file... -DaveM */ -#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - 16 for IP, 16 for IPX, 24 for IPv6, about 80 for AX.25 */ @@ -1215,13 +1228,13 @@ unsigned char *ctl_buf = ctl; struct msghdr msg_sys; int err, ctl_len, iov_size, total_len; - + err = -EFAULT; if (shape_msg(&msg_sys, msg)) - goto out; + goto out; sock = sockfd_lookup(fd, &err); - if (!sock) + if (!sock) goto out; /* do not move before msg_sys is valid */ @@ -1240,7 +1253,7 @@ /* This will also move the address data into kernel space */ err = verify_iovec32(&msg_sys, iov, address, VERIFY_READ); - if (err < 0) + if (err < 0) goto out_freeiov; total_len = err; @@ -1248,14 +1261,14 @@ if (msg_sys.msg_controllen > INT_MAX) goto out_freeiov; - ctl_len = msg_sys.msg_controllen; - if (ctl_len) + ctl_len = msg_sys.msg_controllen; + if (ctl_len) { if (ctl_len > sizeof(ctl)) { err = -ENOBUFS; ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); - if (ctl_buf == NULL) + if (ctl_buf == NULL) goto out_freeiov; } err = -EFAULT; @@ -1270,14 +1283,14 @@ err = sock_sendmsg(sock, &msg_sys, total_len); out_freectl: - if (ctl_buf != ctl) + if (ctl_buf != ctl) sock_kfree_s(sock->sk, ctl_buf, ctl_len); out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); out_put: sockfd_put(sock); -out: +out: return err; } @@ -1301,7 +1314,7 @@ /* user mode address pointers */ struct sockaddr *uaddr; int *uaddr_len; - + err=-EFAULT; if (shape_msg(&msg_sys, msg)) goto out; @@ -1313,7 +1326,7 @@ err = -EINVAL; if (msg_sys.msg_iovlen > UIO_MAXIOV) goto out_put; - + /* Check whether to allocate the iovec area*/ err = -ENOMEM; iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); @@ -1327,7 +1340,7 @@ * Save the user-mode address (verify_iovec will change the * kernel msghdr to use the kernel address space) */ - + uaddr = msg_sys.msg_name; uaddr_len = &msg->msg_namelen; err = verify_iovec32(&msg_sys, iov, addr, VERIFY_WRITE); @@ -1337,7 +1350,7 @@ cmsg_ptr = (unsigned long)msg_sys.msg_control; msg_sys.msg_flags = 0; - + if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; err = sock_recvmsg(sock, &msg_sys, total_len, flags); @@ -1353,7 +1366,7 @@ err = __put_user(msg_sys.msg_flags, &msg->msg_flags); if (err) goto out_freeiov; - err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, + err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen); if (err) goto out_freeiov; @@ -1371,15 +1384,15 @@ /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(u32)) static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), - AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), - AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, - int *upeer_addrlen); + int *upeer_addrlen); extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len); extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, @@ -1406,15 +1419,15 @@ int ret; u32 a[6]; u32 a0,a1; - + if (callSYS_RECVMSG) return -EINVAL; if (copy_from_user(a, args, nas[call])) return -EFAULT; a0=a[0]; a1=a[1]; - - switch(call) + + switch(call) { case SYS_SOCKET: ret = sys_socket(a0, a1, a[2]); @@ -1490,52 +1503,52 @@ struct ipc_perm32 { - key_t key; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_uid_t32 cuid; - __kernel_gid_t32 cgid; - __kernel_mode_t32 mode; - unsigned short seq; + key_t key; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_uid_t32 cuid; + __kernel_gid_t32 cgid; + __kernel_mode_t32 mode; + unsigned short seq; }; struct semid_ds32 { - struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ - __kernel_time_t32 sem_otime; /* last semop time */ - __kernel_time_t32 sem_ctime; /* last change time */ - u32 sem_base; /* ptr to first semaphore in array */ - u32 sem_pending; /* pending operations to be processed */ - u32 sem_pending_last; /* last pending operation */ - u32 undo; /* undo requests on this array */ - unsigned short sem_nsems; /* no. of semaphores in array */ + struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t32 sem_otime; /* last semop time */ + __kernel_time_t32 sem_ctime; /* last change time */ + u32 sem_base; /* ptr to first semaphore in array */ + u32 sem_pending; /* pending operations to be processed */ + u32 sem_pending_last; /* last pending operation */ + u32 undo; /* undo requests on this array */ + unsigned short sem_nsems; /* no. of semaphores in array */ }; struct msqid_ds32 { - struct ipc_perm32 msg_perm; - u32 msg_first; - u32 msg_last; - __kernel_time_t32 msg_stime; - __kernel_time_t32 msg_rtime; - __kernel_time_t32 msg_ctime; - u32 wwait; - u32 rwait; - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - __kernel_ipc_pid_t32 msg_lspid; - __kernel_ipc_pid_t32 msg_lrpid; + struct ipc_perm32 msg_perm; + u32 msg_first; + u32 msg_last; + __kernel_time_t32 msg_stime; + __kernel_time_t32 msg_rtime; + __kernel_time_t32 msg_ctime; + u32 wwait; + u32 rwait; + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + __kernel_ipc_pid_t32 msg_lspid; + __kernel_ipc_pid_t32 msg_lrpid; }; struct shmid_ds32 { - struct ipc_perm32 shm_perm; - int shm_segsz; - __kernel_time_t32 shm_atime; - __kernel_time_t32 shm_dtime; - __kernel_time_t32 shm_ctime; - __kernel_ipc_pid_t32 shm_cpid; - __kernel_ipc_pid_t32 shm_lpid; - unsigned short shm_nattch; + struct ipc_perm32 shm_perm; + int shm_segsz; + __kernel_time_t32 shm_atime; + __kernel_time_t32 shm_dtime; + __kernel_time_t32 shm_ctime; + __kernel_ipc_pid_t32 shm_cpid; + __kernel_ipc_pid_t32 shm_lpid; + unsigned short shm_nattch; }; #define IPCOP_MASK(__x) (1UL << (__x)) @@ -1876,7 +1889,7 @@ err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr)); break; - case SHMDT: + case SHMDT: err = sys_shmdt ((char *)AA(ptr)); break; case SHMGET: @@ -1902,7 +1915,7 @@ { int i; - /* SMP: This is fairly trivial. We grab CURRENT_TIME and + /* SMP: This is fairly trivial. We grab CURRENT_TIME and stuff it to user space. No side effects */ i = CURRENT_TIME; if (tloc) { @@ -1913,29 +1926,29 @@ } struct rusage32 { - struct timeval32 ru_utime; - struct timeval32 ru_stime; - int ru_maxrss; - int ru_ixrss; - int ru_idrss; - int ru_isrss; - int ru_minflt; - int ru_majflt; - int ru_nswap; - int ru_inblock; - int ru_oublock; - int ru_msgsnd; - int ru_msgrcv; - int ru_nsignals; - int ru_nvcsw; - int ru_nivcsw; + struct timeval32 ru_utime; + struct timeval32 ru_stime; + int ru_maxrss; + int ru_ixrss; + int ru_idrss; + int ru_isrss; + int ru_minflt; + int ru_majflt; + int ru_nswap; + int ru_inblock; + int ru_oublock; + int ru_msgsnd; + int ru_msgrcv; + int ru_nsignals; + int ru_nvcsw; + int ru_nivcsw; }; static int put_rusage (struct rusage32 *ru, struct rusage *r) { int err; - + err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); @@ -1968,7 +1981,7 @@ int ret; unsigned int status; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); set_fs (old_fs); @@ -1995,7 +2008,7 @@ struct rusage r; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_getrusage(who, &r); set_fs (old_fs); @@ -2009,7 +2022,7 @@ __kernel_clock_t32 tms_cutime; __kernel_clock_t32 tms_cstime; }; - + extern asmlinkage long sys_times(struct tms * tbuf); asmlinkage long @@ -2019,7 +2032,7 @@ long ret; mm_segment_t old_fs = get_fs (); int err; - + set_fs (KERNEL_DS); ret = sys_times(tbuf ? &t : NULL); set_fs (old_fs); @@ -2069,7 +2082,7 @@ #define PT_GS 10 #define PT_ORIG_EAX 11 #define PT_EIP 12 -#define PT_CS 13 +#define PT_CS 13 #define PT_EFL 14 #define PT_UESP 15 #define PT_SS 16 @@ -2385,7 +2398,7 @@ break; case IA32_PTRACE_GETREGS: - if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) { + if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) { ret = -EIO; break; } @@ -2399,7 +2412,7 @@ case IA32_PTRACE_SETREGS: { unsigned int tmp; - if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) { + if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) { ret = -EIO; break; } @@ -2444,7 +2457,7 @@ get_flock32(struct flock *kfl, struct flock32 *ufl) { int err; - + err = get_user(kfl->l_type, &ufl->l_type); err |= __get_user(kfl->l_whence, &ufl->l_whence); err |= __get_user(kfl->l_start, &ufl->l_start); @@ -2457,7 +2470,7 @@ put_flock32(struct flock *kfl, struct flock32 *ufl) { int err; - + err = __put_user(kfl->l_type, &ufl->l_type); err |= __put_user(kfl->l_whence, &ufl->l_whence); err |= __put_user(kfl->l_start, &ufl->l_start); @@ -2480,7 +2493,7 @@ case F_GETLK: case F_SETLK: case F_SETLKW: - if(cmd != F_GETLK && get_flock32(&f, (struct flock32 *)((long)arg))) + if(get_flock32(&f, (struct flock32 *)((long)arg))) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); @@ -2501,27 +2514,27 @@ asmlinkage long sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) { - struct k_sigaction new_ka, old_ka; - int ret; + struct k_sigaction new_ka, old_ka; + int ret; - if (act) { + if (act) { old_sigset32_t mask; - + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= __get_user(mask, &act->sa_mask); if (ret) return ret; siginitset(&new_ka.sa.sa_mask, mask); - } + } - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + } return ret; } @@ -2658,6 +2671,85 @@ return -ERESTARTNOHAND; } +asmlinkage long sys_msync(unsigned long start, size_t len, int flags); + +asmlinkage int +sys32_msync(unsigned int start, unsigned int len, int flags) +{ + unsigned int addr; + + if (OFFSET4K(start)) + return -EINVAL; + addr = start & PAGE_MASK; + return(sys_msync(addr, len + (start - addr), flags)); +} + +struct sysctl_ia32 { + unsigned int name; + int nlen; + unsigned int oldval; + unsigned int oldlenp; + unsigned int newval; + unsigned int newlen; + unsigned int __unused[4]; +}; + +extern asmlinkage long sys_sysctl(struct __sysctl_args *args); + +asmlinkage long +sys32_sysctl(struct sysctl_ia32 *args32) +{ + struct sysctl_ia32 a32; + mm_segment_t old_fs = get_fs (); + void *oldvalp, *newvalp; + size_t oldlen; + int *namep; + long ret; + + if (copy_from_user(&a32, args32, sizeof (a32))) + return -EFAULT; + + /* + * We need to pre-validate these because we have to disable address checking + * before calling do_sysctl() because of OLDLEN but we can't run the risk of the + * user specifying bad addresses here. Well, since we're dealing with 32 bit + * addresses, we KNOW that access_ok() will always succeed, so this is an + * expensive NOP, but so what... + */ + namep = (int *) A(a32.name); + oldvalp = (void *) A(a32.oldval); + newvalp = (void *) A(a32.newval); + + if ((oldvalp && get_user(oldlen, (int *) A(a32.oldlenp))) + || !access_ok(VERIFY_WRITE, namep, 0) + || !access_ok(VERIFY_WRITE, oldvalp, 0) + || !access_ok(VERIFY_WRITE, newvalp, 0)) + return -EFAULT; + + set_fs(KERNEL_DS); + lock_kernel(); + ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen); + unlock_kernel(); + set_fs(old_fs); + + if (oldvalp && put_user (oldlen, (int *) A(a32.oldlenp))) + return -EFAULT; + + return ret; +} + +asmlinkage long +sys32_newuname(struct new_utsname * name) +{ + extern asmlinkage long sys_newuname(struct new_utsname * name); + int ret = sys_newuname(name); + + if (!ret) + if (copy_to_user(name->machine, "i686\0\0\0", 8)) + ret = -EFAULT; + return ret; +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ /* In order to reduce some races, while at the same time doing additional @@ -2721,7 +2813,7 @@ __kernel_time_t32 dqb_btime; __kernel_time_t32 dqb_itime; }; - + extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr); @@ -2733,7 +2825,7 @@ struct dqblk d; mm_segment_t old_fs; char *spec; - + switch (cmds) { case Q_GETQUOTA: break; @@ -2782,7 +2874,7 @@ mm_segment_t old_fs; int ret; char *filenam; - + if (!times) return sys_utime(filename, NULL); if (get_user (t.actime, ×->actime) || @@ -2792,7 +2884,7 @@ ret = PTR_ERR(filenam); if (!IS_ERR(filenam)) { old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs (KERNEL_DS); ret = sys_utime(filenam, &t); set_fs (old_fs); putname (filenam); @@ -2869,18 +2961,18 @@ } struct ncp_mount_data32 { - int version; - unsigned int ncp_fd; - __kernel_uid_t32 mounted_uid; - __kernel_pid_t32 wdog_pid; - unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; - unsigned int time_out; - unsigned int retry_count; - unsigned int flags; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; + int version; + unsigned int ncp_fd; + __kernel_uid_t32 mounted_uid; + __kernel_pid_t32 wdog_pid; + unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; + unsigned int time_out; + unsigned int retry_count; + unsigned int flags; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; }; static void * @@ -2901,12 +2993,12 @@ } struct smb_mount_data32 { - int version; - __kernel_uid_t32 mounted_uid; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; + int version; + __kernel_uid_t32 mounted_uid; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; }; static void * @@ -3020,16 +3112,16 @@ } struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - char _f[22]; + s32 uptime; + u32 loads[3]; + u32 totalram; + u32 freeram; + u32 sharedram; + u32 bufferram; + u32 totalswap; + u32 freeswap; + unsigned short procs; + char _f[22]; }; extern asmlinkage long sys_sysinfo(struct sysinfo *info); @@ -3040,7 +3132,7 @@ struct sysinfo s; int ret, err; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_sysinfo(&s); set_fs (old_fs); @@ -3059,7 +3151,7 @@ return -EFAULT; return ret; } - + extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); @@ -3069,7 +3161,7 @@ struct timespec t; int ret; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_sched_rr_get_interval(pid, &t); set_fs (old_fs); @@ -3088,7 +3180,7 @@ old_sigset_t s; int ret; mm_segment_t old_fs = get_fs(); - + if (set && get_user (s, set)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); @@ -3106,7 +3198,7 @@ old_sigset_t s; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_sigpending(&s); set_fs (old_fs); @@ -3123,7 +3215,7 @@ sigset_t32 s32; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_rt_sigpending(&s, sigsetsize); set_fs (old_fs); @@ -3234,7 +3326,7 @@ mm_segment_t old_fs = get_fs(); siginfo_t info; siginfo_t32 info32; - + if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) return -EFAULT; switch (_NSIG_WORDS) { @@ -3270,7 +3362,7 @@ siginfo_t32 info32; int ret; mm_segment_t old_fs = get_fs(); - + if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) return -EFAULT; /* XXX: Is this correct? */ @@ -3315,7 +3407,7 @@ uid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_getresuid(&a, &b, &c); set_fs (old_fs); @@ -3354,12 +3446,12 @@ asmlinkage long sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, - __kernel_gid_t32 *sgid) + __kernel_gid_t32 *sgid) { gid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); - + set_fs (KERNEL_DS); ret = sys_getresgid(&a, &b, &c); set_fs (old_fs); @@ -3379,7 +3471,7 @@ gid_t gl[NGROUPS]; int ret, i; mm_segment_t old_fs = get_fs (); - + set_fs (KERNEL_DS); ret = sys_getgroups(gidsetsize, gl); set_fs (old_fs); @@ -3398,13 +3490,13 @@ gid_t gl[NGROUPS]; int ret, i; mm_segment_t old_fs = get_fs (); - + if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; for (i = 0; i < gidsetsize; i++, grouplist++) if (__get_user (gl[i], grouplist)) return -EFAULT; - set_fs (KERNEL_DS); + set_fs (KERNEL_DS); ret = sys_setgroups(gidsetsize, gl); set_fs (old_fs); return ret; @@ -3442,26 +3534,26 @@ } struct msghdr32 { - u32 msg_name; - int msg_namelen; - u32 msg_iov; - __kernel_size_t32 msg_iovlen; - u32 msg_control; - __kernel_size_t32 msg_controllen; - unsigned msg_flags; + u32 msg_name; + int msg_namelen; + u32 msg_iov; + __kernel_size_t32 msg_iovlen; + u32 msg_control; + __kernel_size_t32 msg_controllen; + unsigned msg_flags; }; struct cmsghdr32 { - __kernel_size_t32 cmsg_len; - int cmsg_level; - int cmsg_type; + __kernel_size_t32 cmsg_len; + int cmsg_level; + int cmsg_type; }; /* Bleech... */ #define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) \ - __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) + __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) #define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) \ - cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) + cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) #define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) @@ -3479,7 +3571,7 @@ __inline__ struct cmsghdr32 * __cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, - struct cmsghdr32 *__cmsg, int __cmsg_len) + struct cmsghdr32 *__cmsg, int __cmsg_len) { struct cmsghdr32 * __ptr; @@ -3541,7 +3633,7 @@ err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen); err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); err |= get_user(kmsg->msg_flags, &umsg->msg_flags); - + return err; } @@ -3588,7 +3680,7 @@ */ static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg, unsigned char *stackbuf, - int stackbuf_size) + int stackbuf_size) { struct cmsghdr32 *ucmsg; struct cmsghdr *kcmsg, *kcmsg_base; @@ -3812,7 +3904,7 @@ kcmsg32->cmsg_len = clen32; ucmsg = (struct cmsghdr *) (((char *)ucmsg) + - CMSG_ALIGN(clen64)); + CMSG_ALIGN(clen64)); wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); } @@ -3985,7 +4077,7 @@ } extern asmlinkage long sys_init_module(const char *name_user, - struct module *mod_user); + struct module *mod_user); /* Hey, when you're trying to init module, take time and prepare us a nice 64bit * module structure, even if from 32bit modutils... Why to pollute kernel... :)) @@ -4275,7 +4367,7 @@ asmlinkage long sys32_query_module(char *name_user, int which, char *buf, - __kernel_size_t32 bufsize, u32 ret) + __kernel_size_t32 bufsize, u32 ret) { struct module *mod; int err; @@ -4340,7 +4432,7 @@ u32 value; char name[60]; }; - + extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table); asmlinkage long @@ -4349,7 +4441,7 @@ int len, i; struct kernel_sym *tbl; mm_segment_t old_fs; - + len = sys_get_kernel_syms(NULL); if (!table) return len; tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL); @@ -4477,7 +4569,7 @@ nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port); err |= __get_user(karg->ca_svc.svc_nthreads, @@ -4489,7 +4581,7 @@ nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_client.cl_ident[0], &arg32->ca32_client.cl32_ident[0], @@ -4513,7 +4605,7 @@ nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_export.ex_client[0], &arg32->ca32_export.ex32_client[0], @@ -4589,7 +4681,7 @@ nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { int err; - + err = __get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_getfh.gf_addr, &arg32->ca32_getfh.gf32_addr, @@ -4607,7 +4699,7 @@ nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32) { int err; - + err = copy_to_user(&res32->cr32_getfh, &kres->cr_getfh, sizeof(res32->cr32_getfh)); @@ -4772,19 +4864,6 @@ } -extern asmlinkage long sys_newuname(struct new_utsname * name); - -asmlinkage long -sys32_newuname(struct new_utsname * name) -{ - int ret = sys_newuname(name); - - if (current->personality == PER_LINUX32 && !ret) { - ret = copy_to_user(name->machine, "sparc\0\0", 8); - } - return ret; -} - extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, size_t count, loff_t pos); @@ -4825,7 +4904,7 @@ } extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, - size_t count); + size_t count); asmlinkage long sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) @@ -4833,17 +4912,17 @@ mm_segment_t old_fs = get_fs(); int ret; off_t of; - + if (offset && get_user(of, offset)) return -EFAULT; - + set_fs(KERNEL_DS); ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); - + if (!ret && offset && put_user(of, offset)) return -EFAULT; - + return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/Makefile linux.ac/arch/ia64/kernel/Makefile --- linux.vanilla/arch/ia64/kernel/Makefile Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/Makefile Tue Apr 10 18:08:40 2001 @@ -11,19 +11,18 @@ O_TARGET := kernel.o -obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ +export-objs := ia64_ksyms.o + +obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_sapic.o ivt.o \ machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o obj-$(CONFIG_IA64_DIG) += iosapic.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o +obj-$(CONFIG_IA64_EFIVARS) += efivars.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o - -export-objs := ia64_ksyms.o - -clean:: include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/acpi.c linux.ac/arch/ia64/kernel/acpi.c --- linux.vanilla/arch/ia64/kernel/acpi.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/acpi.c Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* - * Advanced Configuration and Power Interface + * Advanced Configuration and Power Interface * - * Based on 'ACPI Specification 1.0b' February 2, 1999 and + * Based on 'ACPI Specification 1.0b' February 2, 1999 and * 'IA-64 Extensions to ACPI Specification' Revision 0.6 - * + * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond * Copyright (C) 2000 Hewlett-Packard Co. @@ -111,15 +111,15 @@ * Identify usable CPU's and remember them for SMP bringup later. */ static void __init -acpi20_lsapic (char *p) +acpi20_lsapic (char *p) { int add = 1; acpi20_entry_lsapic_t *lsapic = (acpi20_entry_lsapic_t *) p; - printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id); + printk(" CPU %.04x:%.04x: ", lsapic->eid, lsapic->id); if ((lsapic->flags & LSAPIC_ENABLED) == 0) { - printk("Disabled.\n"); + printk("disabled.\n"); add = 0; } @@ -127,11 +127,14 @@ smp_boot_data.cpu_phys_id[total_cpus] = -1; #endif if (add) { - printk("Available.\n"); available_cpus++; + printk("available"); #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; -#endif /* CONFIG_SMP */ + if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus]) + printk(" (BSP)"); +#endif + printk(".\n"); } total_cpus++; } @@ -199,7 +202,7 @@ printk("ACPI 2.0 MADT: LOCAL SAPIC\n"); acpi20_lsapic(p); break; - + case ACPI20_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) @@ -233,7 +236,7 @@ end = p + (madt->header.length - sizeof(acpi_madt_t)); while (p < end) { - + switch (*p) { case ACPI20_ENTRY_INT_SRC_OVERRIDE: printk("ACPI 2.0 MADT: INT SOURCE Override\n"); @@ -251,7 +254,7 @@ available_cpus, total_cpus); } -int __init +int __init acpi20_parse (acpi20_rsdp_t *rsdp20) { acpi_xsdt_t *xsdt; @@ -311,12 +314,12 @@ printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } - smp_boot_data.cpu_count = available_cpus; + smp_boot_data.cpu_count = total_cpus; #endif return 1; } /* - * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all + * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all * platforms start supporting ACPI 2.0 */ @@ -324,13 +327,13 @@ * Identify usable CPU's and remember them for SMP bringup later. */ static void __init -acpi_lsapic (char *p) +acpi_lsapic (char *p) { int add = 1; acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p; - if ((lsapic->flags & LSAPIC_PRESENT) == 0) + if ((lsapic->flags & LSAPIC_PRESENT) == 0) return; printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id); @@ -388,7 +391,7 @@ case ACPI_ENTRY_LOCAL_SAPIC: acpi_lsapic(p); break; - + case ACPI_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) @@ -415,7 +418,7 @@ printk(" %d CPUs available, %d CPUs total\n", available_cpus, total_cpus); } -int __init +int __init acpi_parse (acpi_rsdp_t *rsdp) { acpi_rsdt_t *rsdt; @@ -433,9 +436,9 @@ return 0; } - printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, + printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff); - + #ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_init(rsdp); #endif @@ -460,7 +463,7 @@ printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } - smp_boot_data.cpu_count = available_cpus; + smp_boot_data.cpu_count = total_cpus; #endif return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/brl_emu.c linux.ac/arch/ia64/kernel/brl_emu.c --- linux.vanilla/arch/ia64/kernel/brl_emu.c Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/kernel/brl_emu.c Tue Apr 10 18:08:40 2001 @@ -1,6 +1,6 @@ /* * Emulation of the "brl" instruction for IA64 processors that - * don't support it in hardware. + * don't support it in hardware. * Author: Stephan Zeisset, Intel Corp. */ @@ -23,9 +23,9 @@ * of an and operation with the mask must be all 0's * or all 1's for the address to be valid. */ -#define unimplemented_virtual_address(va) ( \ - ((va) & my_cpu_data.unimpl_va_mask) != 0 && \ - ((va) & my_cpu_data.unimpl_va_mask) != my_cpu_data.unimpl_va_mask \ +#define unimplemented_virtual_address(va) ( \ + ((va) & local_cpu_data->unimpl_va_mask) != 0 && \ + ((va) & local_cpu_data->unimpl_va_mask) != local_cpu_data->unimpl_va_mask \ ) /* @@ -35,13 +35,13 @@ * address to be valid. */ #define unimplemented_physical_address(pa) ( \ - ((pa) & my_cpu_data.unimpl_pa_mask) != 0 \ + ((pa) & local_cpu_data->unimpl_pa_mask) != 0 \ ) /* - * Handle an illegal operation fault that was caused by an + * Handle an illegal operation fault that was caused by an * unimplemented "brl" instruction. - * If we are not successful (e.g because the illegal operation + * If we are not successful (e.g because the illegal operation * wasn't caused by a "brl" after all), we return -1. * If we are successful, we return either 0 or the address * of a "fixup" function for manipulating preserved register @@ -64,8 +64,8 @@ * Decode the instruction bundle. */ - if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle))) - return rv; + if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle))) + return rv; next_ip = (unsigned long) regs->cr_iip + 16; @@ -79,14 +79,14 @@ btype = ((bundle[1] >> 29) & 0x7); qp = ((bundle[1] >> 23) & 0x3f); offset = ((bundle[1] & 0x0800000000000000L) << 4) - | ((bundle[1] & 0x00fffff000000000L) >> 32) + | ((bundle[1] & 0x00fffff000000000L) >> 32) | ((bundle[1] & 0x00000000007fffffL) << 40) | ((bundle[0] & 0xffff000000000000L) >> 24); tmp_taken = regs->pr & (1L << qp); switch(opcode) { - + case 0xC: /* * Long Branch. @@ -169,7 +169,7 @@ */ regs->cr_ifs = ((regs->cr_ifs & 0xffffffc00000007f) - ((regs->cr_ifs >> 7) & 0x7f)); - + break; default: @@ -180,7 +180,7 @@ } - regs->cr_iip += offset; + regs->cr_iip += offset; ia64_psr(regs)->ri = 0; if (ia64_psr(regs)->it == 0) @@ -188,7 +188,7 @@ else unimplemented_address = unimplemented_virtual_address(regs->cr_iip); - if (unimplemented_address) { + if (unimplemented_address) { /* * The target address contains unimplemented bits. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/efi.c linux.ac/arch/ia64/kernel/efi.c --- linux.vanilla/arch/ia64/kernel/efi.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/efi.c Sat Apr 14 01:18:00 2001 @@ -5,9 +5,9 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999-2000 Hewlett-Packard Co. + * Copyright (C) 1999-2001 Hewlett-Packard Co. * Copyright (C) 1999 David Mosberger-Tang - * Copyright (C) 1999-2000 Stephane Eranian + * Copyright (C) 1999-2001 Stephane Eranian * * All EFI Runtime Services are not implemented yet as EFI only * supports physical mode addressing on SoftSDV. This is to be fixed @@ -16,9 +16,8 @@ * Implemented EFI runtime services and virtual mode calls. --davidm * * Goutham Rao: - * Skip non-WB memory and ignore empty memory ranges. + * Skip non-WB memory and ignore empty memory ranges. */ -#include #include #include #include @@ -26,6 +25,7 @@ #include #include +#include #include #include @@ -128,9 +128,9 @@ efi_memory_desc_t *md; u64 efi_desc_size, start, end; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; @@ -203,9 +203,9 @@ u64 mask, flags; u64 vaddr; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; @@ -218,61 +218,48 @@ continue; } /* - * We must use the same page size as the one used - * for the kernel region when we map the PAL code. - * This way, we avoid overlapping TRs if code is - * executed nearby. The Alt I-TLB installs 256MB - * page sizes as defined for region 7. + * The only ITLB entry in region 7 that is used is the one installed by + * __start(). That entry covers a 64MB range. * * XXX Fixme: should be dynamic here (for page size) */ - mask = ~((1 << _PAGE_SIZE_256M)-1); + mask = ~((1 << _PAGE_SIZE_64M) - 1); vaddr = PAGE_OFFSET + md->phys_addr; /* - * We must check that the PAL mapping won't overlap - * with the kernel mapping on ITR1. + * We must check that the PAL mapping won't overlap with the kernel + * mapping. * - * PAL code is guaranteed to be aligned on a power of 2 - * between 4k and 256KB. - * Also from the documentation, it seems like there is an - * implicit guarantee that you will need only ONE ITR to - * map it. This implies that the PAL code is always aligned - * on its size, i.e., the closest matching page size supported - * by the TLB. Therefore PAL code is guaranteed never to cross - * a 256MB unless it is bigger than 256MB (very unlikely!). - * So for now the following test is enough to determine whether - * or not we need a dedicated ITR for the PAL code. + * PAL code is guaranteed to be aligned on a power of 2 between 4k and + * 256KB. Also from the documentation, it seems like there is an implicit + * guarantee that you will need only ONE ITR to map it. This implies that + * the PAL code is always aligned on its size, i.e., the closest matching + * page size supported by the TLB. Therefore PAL code is guaranteed never + * to cross a 64MB unless it is bigger than 64MB (very unlikely!). So for + * now the following test is enough to determine whether or not we need a + * dedicated ITR for the PAL code. */ - if ((vaddr & mask) == (PAGE_OFFSET & mask)) { - printk(__FUNCTION__ " : no need to install ITR for PAL Code\n"); + if ((vaddr & mask) == (KERNEL_START & mask)) { + printk(__FUNCTION__ " : no need to install ITR for PAL code\n"); continue; } - printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", + printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12), - vaddr & mask, (vaddr & mask) + 256*1024*1024); + vaddr & mask, (vaddr & mask) + 64*1024*1024); /* * Cannot write to CRx with PSR.ic=1 */ ia64_clear_ic(flags); - - /* - * ITR0/DTR0: used for kernel code/data - * ITR1/DTR1: used by HP simulator - * ITR2/DTR2: map PAL code - */ - ia64_itr(0x1, 2, vaddr & mask, - pte_val(mk_pte_phys(md->phys_addr, - __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX))), - _PAGE_SIZE_256M); + ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask, + pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), _PAGE_SIZE_64M); local_irq_restore(flags); - ia64_srlz_i (); + ia64_srlz_i(); } } -void __init +void __init efi_init (void) { void *efi_map_start, *efi_map_end; @@ -301,14 +288,14 @@ if (mem_limit != ~0UL) printk("Ignoring memory above %luMB\n", mem_limit >> 20); - efi.systab = __va(ia64_boot_param.efi_systab); + efi.systab = __va(ia64_boot_param->efi_systab); /* * Verify the EFI Table - */ - if (efi.systab == NULL) + */ + if (efi.systab == NULL) panic("Woah! Can't find EFI system table.\n"); - if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) + if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) panic("Woah! EFI system table signature incorrect\n"); if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0) printk("Warning: EFI system table major version mismatch: " @@ -360,9 +347,9 @@ efi.get_next_high_mono_count = phys_get_next_high_mono_count; efi.reset_system = phys_reset_system; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; #if EFI_DEBUG /* print EFI memory map: */ @@ -380,16 +367,7 @@ #endif efi_map_pal_code(); - -#ifndef CONFIG_IA64_SOFTSDV_HACKS - /* - * (Some) SoftSDVs seem to have a problem with this call. - * Since it's mostly a performance optimization, just don't do - * it for now... --davidm 99/12/6 - */ efi_enter_virtual_mode(); -#endif - } void @@ -400,9 +378,9 @@ efi_status_t status; u64 efi_desc_size; - efi_map_start = __va(ia64_boot_param.efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; - efi_desc_size = ia64_boot_param.efi_memdesc_size; + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; @@ -441,9 +419,9 @@ } status = efi_call_phys(__va(runtime->set_virtual_address_map), - ia64_boot_param.efi_memmap_size, - efi_desc_size, ia64_boot_param.efi_memdesc_version, - ia64_boot_param.efi_memmap); + ia64_boot_param->efi_memmap_size, + efi_desc_size, ia64_boot_param->efi_memdesc_version, + ia64_boot_param->efi_memmap); if (status != EFI_SUCCESS) { printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/efi_stub.S linux.ac/arch/ia64/kernel/efi_stub.S --- linux.vanilla/arch/ia64/kernel/efi_stub.S Sat Jul 15 00:08:11 2000 +++ linux.ac/arch/ia64/kernel/efi_stub.S Tue Apr 10 18:08:40 2001 @@ -33,13 +33,6 @@ #include #include - .text - .psr abi64 - .psr lsb - .lsb - - .text - /* * Inputs: * in0 = address of function descriptor of EFI routine to call @@ -50,15 +43,15 @@ */ GLOBAL_ENTRY(efi_call_phys) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,5,7,0 ld8 r2=[in0],8 // load EFI function's entry point mov loc0=rp - UNW(.body) + .body ;; mov loc2=gp // save global pointer mov loc4=ar.rsc // save RSE configuration - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode ;; ld8 gp=[in0] // load EFI function's global pointer @@ -80,7 +73,7 @@ mov out5=in6 mov out6=in7 br.call.sptk.few rp=b6 // call the EFI function -.ret1: mov ar.rsc=r0 // put RSE in enforced lazy, LE mode +.ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 br.call.sptk.few rp=ia64_switch_mode // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/efivars.c linux.ac/arch/ia64/kernel/efivars.c --- linux.vanilla/arch/ia64/kernel/efivars.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/kernel/efivars.c Tue Apr 10 18:08:40 2001 @@ -0,0 +1,433 @@ +/* + * EFI Variables - efivars.c + * + * Copyright (C) 2001 Dell Computer Corporation + * + * This code takes all variables accessible from EFI runtime and + * exports them via /proc + * + * Reads to /proc/efi/varname return an efi_variable_t structure. + * Writes to /proc/efi/varname must be an efi_variable_t structure. + * Writes with DataSize = 0 or Attributes = 0 deletes the variable. + * Writes with a new value in VariableName+VendorGuid creates + * a new variable. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Changelog: + * + * 12 March 2001 - Matt Domsch + * Feedback received from Stephane Eranian incorporated. + * efivar_write() checks copy_from_user() return value. + * efivar_read/write() returns proper errno. + * v0.02 release to linux-ia64@linuxia64.org + * + * 26 February 2001 - Matt Domsch + * v0.01 release to linux-ia64@linuxia64.org + */ + +#include +#include +#include +#include +#include +#include /* for capable() */ +#include +#include + +#include +#include +#ifdef CONFIG_SMP +#include +#endif + +MODULE_AUTHOR("Matt Domsch "); +MODULE_DESCRIPTION("/proc interface to EFI Variables"); + +#define EFIVARS_VERSION "0.02 2001-Mar-12" + +static int +efivar_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int +efivar_write(struct file *file, const char *buffer, + unsigned long count, void *data); + + +/* + * The maximum size of VariableName + Data = 1024 + * Therefore, it's reasonable to save that much + * space in each part of the structure, + * and we use a page for reading/writing. + */ + +typedef struct _efi_variable_t { + efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; + efi_guid_t VendorGuid; + unsigned long DataSize; + __u8 Data[1024]; + efi_status_t Status; + __u32 Attributes; +} __attribute__((packed)) efi_variable_t; + + +typedef struct _efivar_entry_t { + efi_variable_t var; + struct proc_dir_entry *entry; + struct list_head list; +} efivar_entry_t; + +spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(efivar_list); +static struct proc_dir_entry *efi_dir = NULL; + +#define efivar_entry(n) list_entry(n, efivar_entry_t, list) + +/* Return the number of unicode characters in data */ +static unsigned long +utf8_strlen(efi_char16_t *data, unsigned long maxlength) +{ + unsigned long length = 0; + while (*data++ != 0 && length < maxlength) + length++; + return length; +} + +/* Return the number of bytes is the length of this string */ +/* Note: this is NOT the same as the number of unicode characters */ +static inline unsigned long +utf8_strsize(efi_char16_t *data, unsigned long maxlength) +{ + return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * + sizeof(efi_char16_t); +} + + +static int +proc_calc_metrics(char *page, char **start, off_t off, + int count, int *eof, int len) +{ + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + + +static void +uuid_unparse(efi_guid_t *guid, char *out) +{ + sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->data1, guid->data2, guid->data3, + guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3], + guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); +} + + + + + +/* + * efivar_create_proc_entry() + * Requires: + * variable_name_size = number of bytes required to hold + * variable_name (not counting the NULL + * character at the end. + * Returns 1 on failure, 0 on success + */ +static int +efivar_create_proc_entry(unsigned long variable_name_size, + efi_char16_t *variable_name, + efi_guid_t *vendor_guid) +{ + + int i, short_name_size = variable_name_size / + sizeof(efi_char16_t) + 38; + char *short_name = kmalloc(short_name_size+1, + GFP_KERNEL); + efivar_entry_t *new_efivar = kmalloc(sizeof(efivar_entry_t), + GFP_KERNEL); + if (!short_name || !new_efivar) { + if (short_name) kfree(short_name); + if (new_efivar) kfree(new_efivar); + return 1; + } + memset(short_name, 0, short_name_size+1); + memset(new_efivar, 0, sizeof(efivar_entry_t)); + + memcpy(new_efivar->var.VariableName, variable_name, + variable_name_size); + memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t)); + + /* Convert Unicode to normal chars (assume top bits are 0), + ala UTF-8 */ + for (i=0; ientry = create_proc_entry(short_name, 0600, efi_dir); + kfree(short_name); short_name = NULL; + if (!new_efivar->entry) return 1; + + + new_efivar->entry->data = new_efivar; + new_efivar->entry->read_proc = efivar_read; + new_efivar->entry->write_proc = efivar_write; + + list_add(&new_efivar->list, &efivar_list); + + + return 0; +} + + + +/*********************************************************** + * efivar_read() + * Requires: + * Modifies: page + * Returns: number of bytes written, or -EINVAL on failure + ***********************************************************/ + +static int +efivar_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = sizeof(efi_variable_t); + efivar_entry_t *efi_var = data; + efi_variable_t *var_data = (efi_variable_t *)page; + + if (!page || !data) return -EINVAL; + + spin_lock(&efivars_lock); + MOD_INC_USE_COUNT; + + memcpy(var_data, &efi_var->var, len); + + var_data->DataSize = 1024; + var_data->Status = efi.get_variable(var_data->VariableName, + &var_data->VendorGuid, + &var_data->Attributes, + &var_data->DataSize, + var_data->Data); + + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + + return proc_calc_metrics(page, start, off, count, eof, len); +} + +/*********************************************************** + * efivar_write() + * Requires: data is an efi_setvariable_t data type, + * properly filled in, possibly by a call + * first to efivar_read(). + * Caller must have CAP_SYS_ADMIN + * Modifies: NVRAM + * Returns: var_data->DataSize on success, errno on failure + * + ***********************************************************/ +static int +efivar_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long strsize1, strsize2; + int found=0; + struct list_head *pos; + unsigned long size = sizeof(efi_variable_t); + efi_status_t status; + efivar_entry_t *efivar = data, *search_efivar = NULL; + efi_variable_t *var_data; + if (!data || count != size) { + printk(KERN_WARNING "efivars: improper struct of size 0x%lx passed.\n", count); + return -EINVAL; + } + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + spin_lock(&efivars_lock); + MOD_INC_USE_COUNT; + + var_data = kmalloc(size, GFP_KERNEL); + if (!var_data) { + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return -ENOMEM; + } + if (copy_from_user(var_data, buffer, size)) { + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return -EFAULT; + } + + + /* Since the data ptr we've currently got is probably for + a different variable find the right variable. + This allows any properly formatted data structure to + be written to any of the files in /proc/efi and it will work. + */ + list_for_each(pos, &efivar_list) { + search_efivar = efivar_entry(pos); + strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); + strsize2 = utf8_strsize(var_data->VariableName, 1024); + if ( strsize1 == strsize2 && + !memcmp(&(search_efivar->var.VariableName), + var_data->VariableName, strsize1) && + !efi_guidcmp(search_efivar->var.VendorGuid, + var_data->VendorGuid)) { + found = 1; + break; + } + } + if (found) efivar = search_efivar; + + status = efi.set_variable(var_data->VariableName, + &var_data->VendorGuid, + var_data->Attributes, + var_data->DataSize, + var_data->Data); + + if (status != EFI_SUCCESS) { + printk(KERN_WARNING "set_variable() failed: status=%lx\n", status); + kfree(var_data); + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return -EIO; + } + + + if (!var_data->DataSize || !var_data->Attributes) { + /* We just deleted the NVRAM variable */ + remove_proc_entry(efivar->entry->name, efi_dir); + list_del(&efivar->list); + kfree(efivar); + } + + /* If this is a new variable, set up the proc entry for it. */ + if (!found) { + efivar_create_proc_entry(utf8_strsize(var_data->VariableName, + 1024), + var_data->VariableName, + &var_data->VendorGuid); + } + + kfree(var_data); + MOD_DEC_USE_COUNT; + spin_unlock(&efivars_lock); + return size; +} + + + +static int __init +efivars_init(void) +{ + + efi_status_t status; + efi_guid_t vendor_guid; + efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL); + unsigned long variable_name_size = 1024; + + spin_lock(&efivars_lock); + + printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION); + + /* Per EFI spec, the maximum storage allocated for both + the variable name and variable data is 1024 bytes. + */ + + efi_dir = proc_mkdir("efi", NULL); + + memset(variable_name, 0, 1024); + + do { + variable_name_size=1024; + + status = efi.get_next_variable(&variable_name_size, + variable_name, + &vendor_guid); + + + switch (status) { + case EFI_SUCCESS: + efivar_create_proc_entry(variable_name_size, + variable_name, + &vendor_guid); + break; + case EFI_NOT_FOUND: + break; + default: + printk(KERN_WARNING "get_next_variable: status=%lx\n", status); + status = EFI_NOT_FOUND; + break; + } + + } while (status != EFI_NOT_FOUND); + + kfree(variable_name); + spin_unlock(&efivars_lock); + return 0; +} + +static void __exit +efivars_exit(void) +{ + struct list_head *pos; + efivar_entry_t *efivar; + + spin_lock(&efivars_lock); + + list_for_each(pos, &efivar_list) { + efivar = efivar_entry(pos); + remove_proc_entry(efivar->entry->name, efi_dir); + list_del(&efivar->list); + kfree(efivar); + } + remove_proc_entry(efi_dir->name, NULL); + spin_unlock(&efivars_lock); + +} + +module_init(efivars_init); +module_exit(efivars_exit); + +/* + * Overrides for Emacs so that we 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: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/entry.S linux.ac/arch/ia64/kernel/entry.S --- linux.vanilla/arch/ia64/kernel/entry.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/entry.S Tue Apr 10 18:08:40 2001 @@ -3,8 +3,8 @@ * * Kernel entry points. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * Copyright (C) 1999 Asit Mallick @@ -15,8 +15,6 @@ * kernel stack. This allows us to handle interrupts without changing * to physical mode. * - * ar.k4 is now used to hold last virtual map address - * * Jonathan Nickin * Patrick O'Rourke * 11/07/2000 @@ -25,66 +23,84 @@ * Global (preserved) predicate usage on syscall entry/exit path: * * pKern: See entry.h. + * pUser: See entry.h. * pSys: See entry.h. * pNonSys: !pSys - * p2: (Alias of pKern!) True if any signals are pending. */ #include #include #include +#include #include #include #include #include #include - -#include "entry.h" - .text - .psr abi64 - .psr lsb - .lsb +#include "minstate.h" /* * execve() is special because in case of success, we need to * setup a null register window frame. */ ENTRY(ia64_execve) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3) alloc loc1=ar.pfs,3,2,4,0 mov loc0=rp - UNW(.body) + .body mov out0=in0 // filename ;; // stop bit between alloc and call mov out1=in1 // argv mov out2=in2 // envp add out3=16,sp // regs br.call.sptk.few rp=sys_execve -.ret0: cmp4.ge p6,p0=r8,r0 +.ret0: cmp4.ge p6,p7=r8,r0 mov ar.pfs=loc1 // restore ar.pfs - ;; -(p6) mov ar.pfs=r0 // clear ar.pfs in case of success sxt4 r8=r8 // return 64-bit result + ;; + stf.spill [sp]=f0 +(p6) cmp.ne pKern,pUser=r0,r0 // a successful execve() lands us in user-mode... mov rp=loc0 +(p6) mov ar.pfs=r0 // clear ar.pfs on success +(p7) br.ret.sptk.few rp + /* + * In theory, we'd have to zap this state only to prevent leaking of + * security sensitive state (e.g., if current->dumpable is zero). However, + * this executes in less than 20 cycles even on Itanium, so it's not worth + * optimizing for...). + */ + mov r4=0; mov f2=f0; mov b1=r0 + mov r5=0; mov f3=f0; mov b2=r0 + mov r6=0; mov f4=f0; mov b3=r0 + mov r7=0; mov f5=f0; mov b4=r0 + mov ar.unat=0; mov f10=f0; mov b5=r0 + ldf.fill f11=[sp]; ldf.fill f12=[sp]; mov f13=f0 + ldf.fill f14=[sp]; ldf.fill f15=[sp]; mov f16=f0 + ldf.fill f17=[sp]; ldf.fill f18=[sp]; mov f19=f0 + ldf.fill f20=[sp]; ldf.fill f21=[sp]; mov f22=f0 + ldf.fill f23=[sp]; ldf.fill f24=[sp]; mov f25=f0 + ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 + ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 + mov ar.lc=0 br.ret.sptk.few rp END(ia64_execve) GLOBAL_ENTRY(sys_clone2) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) alloc r16=ar.pfs,3,2,4,0 DO_SAVE_SWITCH_STACK mov loc0=rp mov loc1=r16 // save ar.pfs across do_fork - UNW(.body) + .body mov out1=in1 mov out3=in2 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags br.call.sptk.few rp=do_fork -.ret1: UNW(.restore sp) +.ret1: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 mov rp=loc0 @@ -92,43 +108,42 @@ END(sys_clone2) GLOBAL_ENTRY(sys_clone) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) alloc r16=ar.pfs,2,2,4,0 DO_SAVE_SWITCH_STACK mov loc0=rp mov loc1=r16 // save ar.pfs across do_fork - UNW(.body) + .body mov out1=in1 mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags br.call.sptk.few rp=do_fork -.ret2: UNW(.restore sp) +.ret2: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp END(sys_clone) -#define KSTACK_TR 2 - /* * prev_task <- ia64_switch_to(struct task_struct *next) */ GLOBAL_ENTRY(ia64_switch_to) - UNW(.prologue) + .prologue alloc r16=ar.pfs,1,0,0,0 DO_SAVE_SWITCH_STACK - UNW(.body) + .body adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 - mov r27=ar.k4 + mov r27=IA64_KR(CURRENT_STACK) dep r20=0,in0,61,3 // physical address of "current" ;; st8 [r22]=sp // save kernel stack pointer of old task - shr.u r26=r20,_PAGE_SIZE_256M + shr.u r26=r20,_PAGE_SIZE_64M + mov r16=1 ;; - cmp.eq p7,p6=r26,r0 // check < 256M + cmp.ne p6,p7=r26,r16 // check >= 64M && < 128M adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; /* @@ -142,50 +157,36 @@ (p6) ssm psr.ic // if we we had to map, renable the psr.ic bit FIRST!!! ;; (p6) srlz.d - mov ar.k6=r20 // copy "current" into ar.k6 + mov IA64_KR(CURRENT)=r20 // update "current" application register mov r8=r13 // return pointer to previously running task mov r13=in0 // set "current" pointer ;; (p6) ssm psr.i // renable psr.i AFTER the ic bit is serialized - DO_LOAD_SWITCH_STACK( ) + DO_LOAD_SWITCH_STACK #ifdef CONFIG_SMP sync.i // ensure "fc"s done by this CPU are visible on other CPUs -#endif +#endif br.ret.sptk.few rp // boogie on out in new context .map: rsm psr.i | psr.ic - movl r25=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX + movl r25=PAGE_KERNEL ;; srlz.d or r23=r25,r20 // construct PA | page properties - mov r25=_PAGE_SIZE_256M<<2 + mov r25=_PAGE_SIZE_64M<<2 ;; mov cr.itir=r25 mov cr.ifa=in0 // VA of next task... ;; - mov r25=KSTACK_TR // use tr entry #2... - mov ar.k4=r26 // remember last page we mapped... + mov r25=IA64_TR_CURRENT_STACK + mov IA64_KR(CURRENT_STACK)=r26 // remember last page we mapped... ;; itr.d dtr[r25]=r23 // wire in new mapping... br.cond.sptk.many .done - ;; END(ia64_switch_to) -#ifndef CONFIG_IA64_NEW_UNWIND - /* - * Like save_switch_stack, but also save the stack frame that is active - * at the time this function is called. - */ -ENTRY(save_switch_stack_with_current_frame) - UNW(.prologue) - alloc r16=ar.pfs,0,0,0,0 // pass ar.pfs to save_switch_stack - DO_SAVE_SWITCH_STACK - br.ret.sptk.few rp -END(save_switch_stack_with_current_frame) -#endif /* !CONFIG_IA64_NEW_UNWIND */ - /* * Note that interrupts are enabled during save_switch_stack and * load_switch_stack. This means that we may get an interrupt with @@ -205,95 +206,108 @@ * - rp (b0) holds return address to save */ GLOBAL_ENTRY(save_switch_stack) - UNW(.prologue) - UNW(.altrp b7) + .prologue + .altrp b7 flushrs // flush dirty regs to backing store (must be first in insn group) + .save @priunat,r17 mov r17=ar.unat // preserve caller's - adds r2=16,sp // r2 = &sw->caller_unat + .body +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + adds r3=80,sp ;; - mov r18=ar.fpsr // preserve fpsr - mov ar.rsc=r0 // put RSE in mode: enforced lazy, little endian, pl 0 + lfetch.fault.excl.nt1 [r3],128 +#endif + mov ar.rsc=0 // put RSE in mode: enforced lazy, little endian, pl 0 +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + adds r2=16+128,sp ;; - mov r19=ar.rnat - adds r3=24,sp // r3 = &sw->ar_fpsr + lfetch.fault.excl.nt1 [r2],128 + lfetch.fault.excl.nt1 [r3],128 +#endif + adds r14=SW(R4)+16,sp +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + ;; + lfetch.fault.excl [r2] + lfetch.fault.excl [r3] +#endif + adds r15=SW(R5)+16,sp ;; - .savesp ar.unat,SW(CALLER_UNAT) - st8 [r2]=r17,16 - .savesp ar.fpsr,SW(AR_FPSR) - st8 [r3]=r18,24 + mov r18=ar.fpsr // preserve fpsr + mov r19=ar.rnat + add r2=SW(F2)+16,sp // r2 = &sw->f2 +.mem.offset 0,0; st8.spill [r14]=r4,16 // spill r4 +.mem.offset 8,0; st8.spill [r15]=r5,16 // spill r5 + add r3=SW(F3)+16,sp // r3 = &sw->f3 ;; - UNW(.body) stf.spill [r2]=f2,32 stf.spill [r3]=f3,32 mov r21=b0 +.mem.offset 0,0; st8.spill [r14]=r6,16 // spill r6 +.mem.offset 8,0; st8.spill [r15]=r7,16 // spill r7 + mov r22=b1 ;; + // since we're done with the spills, read and save ar.unat: + mov r29=ar.unat // M-unit + mov r20=ar.bspstore // M-unit + mov r23=b2 stf.spill [r2]=f4,32 stf.spill [r3]=f5,32 + mov r24=b3 ;; + st8 [r14]=r21,16 // save b0 + st8 [r15]=r22,16 // save b1 + mov r25=b4 stf.spill [r2]=f10,32 stf.spill [r3]=f11,32 - mov r22=b1 + mov r26=b5 ;; + st8 [r14]=r23,16 // save b2 + st8 [r15]=r24,16 // save b3 + mov r21=ar.lc // I-unit stf.spill [r2]=f12,32 stf.spill [r3]=f13,32 - mov r23=b2 ;; + st8 [r14]=r25,16 // save b4 + st8 [r15]=r26,16 // save b5 stf.spill [r2]=f14,32 stf.spill [r3]=f15,32 - mov r24=b3 ;; + st8 [r14]=r16 // save ar.pfs + st8 [r15]=r21 // save ar.lc stf.spill [r2]=f16,32 stf.spill [r3]=f17,32 - mov r25=b4 ;; stf.spill [r2]=f18,32 stf.spill [r3]=f19,32 - mov r26=b5 ;; stf.spill [r2]=f20,32 stf.spill [r3]=f21,32 - mov r17=ar.lc // I-unit ;; stf.spill [r2]=f22,32 stf.spill [r3]=f23,32 ;; stf.spill [r2]=f24,32 stf.spill [r3]=f25,32 + add r14=SW(CALLER_UNAT)+16,sp ;; stf.spill [r2]=f26,32 stf.spill [r3]=f27,32 + add r15=SW(AR_FPSR)+16,sp ;; stf.spill [r2]=f28,32 stf.spill [r3]=f29,32 - ;; - stf.spill [r2]=f30,32 - stf.spill [r3]=f31,24 - ;; -.mem.offset 0,0; st8.spill [r2]=r4,16 -.mem.offset 8,0; st8.spill [r3]=r5,16 - ;; -.mem.offset 0,0; st8.spill [r2]=r6,16 -.mem.offset 8,0; st8.spill [r3]=r7,16 - ;; - st8 [r2]=r21,16 // save b0 - st8 [r3]=r22,16 // save b1 - /* since we're done with the spills, read and save ar.unat: */ - mov r18=ar.unat // M-unit - mov r20=ar.bspstore // M-unit - ;; - st8 [r2]=r23,16 // save b2 - st8 [r3]=r24,16 // save b3 - ;; - st8 [r2]=r25,16 // save b4 - st8 [r3]=r26,16 // save b5 - ;; - st8 [r2]=r16,16 // save ar.pfs - st8 [r3]=r17,16 // save ar.lc + st8 [r14]=r17 // save caller_unat + st8 [r15]=r18 // save fpsr mov r21=pr ;; - st8 [r2]=r18,16 // save ar.unat + stf.spill [r2]=f30,(SW(AR_UNAT)-SW(F30)) + stf.spill [r3]=f31,(SW(AR_RNAT)-SW(F31)) + ;; + st8 [r2]=r29,16 // save ar.unat st8 [r3]=r19,16 // save ar.rnat - mov b7=r28 ;; st8 [r2]=r20 // save ar.bspstore st8 [r3]=r21 // save predicate registers @@ -303,16 +317,27 @@ /* * load_switch_stack: + * - "invala" MUST be done at call site (normally in DO_LOAD_SWITCH_STACK) * - b7 holds address to return to + * - must not touch r8-r11 */ ENTRY(load_switch_stack) - UNW(.prologue) - UNW(.altrp b7) - invala // invalidate ALAT - UNW(.body) - adds r2=IA64_SWITCH_STACK_B0_OFFSET+16,sp // get pointer to switch_stack.b0 - mov ar.rsc=r0 // put RSE into enforced lazy mode - adds r3=IA64_SWITCH_STACK_B0_OFFSET+24,sp // get pointer to switch_stack.b1 + .prologue + .altrp b7 + .body +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + + lfetch.fault.nt1 [sp] +#endif + adds r2=SW(AR_BSPSTORE)+16,sp + adds r3=SW(AR_UNAT)+16,sp + mov ar.rsc=0 // put RSE into enforced lazy mode + adds r14=SW(CALLER_UNAT)+16,sp + adds r15=SW(AR_FPSR)+16,sp + ;; + ld8 r27=[r2],(SW(B0)-SW(AR_BSPSTORE)) // bspstore + ld8 r29=[r3],(SW(B1)-SW(AR_UNAT)) // unat ;; ld8 r21=[r2],16 // restore b0 ld8 r22=[r3],16 // restore b1 @@ -323,84 +348,77 @@ ld8 r25=[r2],16 // restore b4 ld8 r26=[r3],16 // restore b5 ;; - ld8 r16=[r2],16 // restore ar.pfs - ld8 r17=[r3],16 // restore ar.lc + ld8 r16=[r2],(SW(PR)-SW(AR_PFS)) // ar.pfs + ld8 r17=[r3],(SW(AR_RNAT)-SW(AR_LC)) // ar.lc ;; - ld8 r18=[r2],16 // restore ar.unat - ld8 r19=[r3],16 // restore ar.rnat - mov b0=r21 + ld8 r28=[r2] // restore pr + ld8 r30=[r3] // restore rnat ;; - ld8 r20=[r2] // restore ar.bspstore - ld8 r21=[r3] // restore predicate registers - mov ar.pfs=r16 + ld8 r18=[r14],16 // restore caller's unat + ld8 r19=[r15],24 // restore fpsr ;; - mov ar.bspstore=r20 + ldf.fill f2=[r14],32 + ldf.fill f3=[r15],32 ;; - loadrs // invalidate stacked regs outside current frame - adds r2=16-IA64_SWITCH_STACK_SIZE,r2 // get pointer to switch_stack.caller_unat - ;; // stop bit for rnat dependency - mov ar.rnat=r19 - mov ar.unat=r18 // establish unat holding the NaT bits for r4-r7 - adds r3=16-IA64_SWITCH_STACK_SIZE,r3 // get pointer to switch_stack.ar_fpsr + ldf.fill f4=[r14],32 + ldf.fill f5=[r15],32 ;; - ld8 r18=[r2],16 // restore caller's unat - ld8 r19=[r3],24 // restore fpsr - mov ar.lc=r17 + ldf.fill f10=[r14],32 + ldf.fill f11=[r15],32 + ;; + ldf.fill f12=[r14],32 + ldf.fill f13=[r15],32 ;; - ldf.fill f2=[r2],32 - ldf.fill f3=[r3],32 - mov pr=r21,-1 + ldf.fill f14=[r14],32 + ldf.fill f15=[r15],32 ;; - ldf.fill f4=[r2],32 - ldf.fill f5=[r3],32 + ldf.fill f16=[r14],32 + ldf.fill f17=[r15],32 ;; - ldf.fill f10=[r2],32 - ldf.fill f11=[r3],32 + ldf.fill f18=[r14],32 + ldf.fill f19=[r15],32 + mov b0=r21 + ;; + ldf.fill f20=[r14],32 + ldf.fill f21=[r15],32 mov b1=r22 ;; - ldf.fill f12=[r2],32 - ldf.fill f13=[r3],32 + ldf.fill f22=[r14],32 + ldf.fill f23=[r15],32 mov b2=r23 ;; - ldf.fill f14=[r2],32 - ldf.fill f15=[r3],32 + mov ar.bspstore=r27 + mov ar.unat=r29 // establish unat holding the NaT bits for r4-r7 mov b3=r24 ;; - ldf.fill f16=[r2],32 - ldf.fill f17=[r3],32 + ldf.fill f24=[r14],32 + ldf.fill f25=[r15],32 mov b4=r25 ;; - ldf.fill f18=[r2],32 - ldf.fill f19=[r3],32 + ldf.fill f26=[r14],32 + ldf.fill f27=[r15],32 mov b5=r26 ;; - ldf.fill f20=[r2],32 - ldf.fill f21=[r3],32 - ;; - ldf.fill f22=[r2],32 - ldf.fill f23=[r3],32 - ;; - ldf.fill f24=[r2],32 - ldf.fill f25=[r3],32 - ;; - ldf.fill f26=[r2],32 - ldf.fill f27=[r3],32 - ;; - ldf.fill f28=[r2],32 - ldf.fill f29=[r3],32 + ldf.fill f28=[r14],32 + ldf.fill f29=[r15],32 + mov ar.pfs=r16 ;; - ldf.fill f30=[r2],32 - ldf.fill f31=[r3],24 + ldf.fill f30=[r14],32 + ldf.fill f31=[r15],24 + mov ar.lc=r17 ;; - ld8.fill r4=[r2],16 - ld8.fill r5=[r3],16 + ld8.fill r4=[r14],16 + ld8.fill r5=[r15],16 + mov pr=r28,-1 ;; - ld8.fill r6=[r2],16 - ld8.fill r7=[r3],16 + ld8.fill r6=[r14],16 + ld8.fill r7=[r15],16 + mov ar.unat=r18 // restore caller's unat + mov ar.rnat=r30 // must restore after bspstore but before rsc! mov ar.fpsr=r19 // restore fpsr mov ar.rsc=3 // put RSE back into eager mode, pl 0 - br.cond.sptk.few b7 + br.cond.sptk.many b7 END(load_switch_stack) GLOBAL_ENTRY(__ia64_syscall) @@ -415,17 +433,16 @@ br.ret.sptk.few rp END(__ia64_syscall) - // - // We invoke syscall_trace through this intermediate function to - // ensure that the syscall input arguments are not clobbered. We - // also use it to preserve b6, which contains the syscall entry point. - // + /* + * We invoke syscall_trace through this intermediate function to + * ensure that the syscall input arguments are not clobbered. We + * also use it to preserve b6, which contains the syscall entry point. + */ GLOBAL_ENTRY(invoke_syscall_trace) -#ifdef CONFIG_IA64_NEW_UNWIND - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,3,0,0 mov loc0=rp - UNW(.body) + .body mov loc2=b6 ;; br.call.sptk.few rp=syscall_trace @@ -433,33 +450,18 @@ mov ar.pfs=loc1 mov b6=loc2 br.ret.sptk.few rp -#else /* !CONFIG_IA64_NEW_SYSCALL */ - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) - alloc loc1=ar.pfs,8,3,0,0 - ;; // WAW on CFM at the br.call - mov loc0=rp - br.call.sptk.many rp=save_switch_stack_with_current_frame // must preserve b6!! -.ret4: mov loc2=b6 - br.call.sptk.few rp=syscall_trace -.ret5: adds sp=IA64_SWITCH_STACK_SIZE,sp // drop switch_stack frame - mov rp=loc0 - mov ar.pfs=loc1 - mov b6=loc2 - ;; - br.ret.sptk.few rp -#endif /* !CONFIG_IA64_NEW_SYSCALL */ END(invoke_syscall_trace) - // - // Invoke a system call, but do some tracing before and after the call. - // We MUST preserve the current register frame throughout this routine - // because some system calls (such as ia64_execve) directly - // manipulate ar.pfs. - // - // Input: - // r15 = syscall number - // b6 = syscall entry point - // + /* + * Invoke a system call, but do some tracing before and after the call. + * We MUST preserve the current register frame throughout this routine + * because some system calls (such as ia64_execve) directly + * manipulate ar.pfs. + * + * Input: + * r15 = syscall number + * b6 = syscall entry point + */ .global ia64_strace_leave_kernel GLOBAL_ENTRY(ia64_trace_syscall) @@ -468,8 +470,8 @@ .ret6: br.call.sptk.few rp=b6 // do the syscall strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? - adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 - adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 + adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 + adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 mov r10=0 (p6) br.cond.sptk.few strace_error // syscall failed -> ;; // avoid RAW on r10 @@ -492,28 +494,14 @@ br.cond.sptk.few strace_save_retval END(ia64_trace_syscall) -/* - * A couple of convenience macros to help implement/understand the state - * restoration that happens at the end of ia64_ret_from_syscall. - */ -#define rARPR r31 -#define rCRIFS r30 -#define rCRIPSR r29 -#define rCRIIP r28 -#define rARRSC r27 -#define rARPFS r26 -#define rARUNAT r25 -#define rARRNAT r24 -#define rARBSPSTORE r23 -#define rKRBS r22 -#define rB6 r21 - GLOBAL_ENTRY(ia64_ret_from_clone) PT_REGS_UNWIND_INFO(0) #ifdef CONFIG_SMP - // In SMP mode, we need to call schedule_tail to complete the scheduling process. - // Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the - // address of the previously executing task. + /* + * In SMP mode, we need to call invoke_schedule_tail to complete the scheduling process. + * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the + * address of the previously executing task. + */ br.call.sptk.few rp=invoke_schedule_tail .ret8: #endif @@ -530,8 +518,8 @@ GLOBAL_ENTRY(ia64_ret_from_syscall) PT_REGS_UNWIND_INFO(0) cmp.ge p6,p7=r8,r0 // syscall executed successfully? - adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 - adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 + adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 + adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 ;; .mem.offset 0,0 (p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit @@ -541,78 +529,57 @@ END(ia64_ret_from_syscall) // fall through GLOBAL_ENTRY(ia64_leave_kernel) - // check & deliver software interrupts: - PT_REGS_UNWIND_INFO(0) -#ifdef CONFIG_SMP - adds r2=IA64_TASK_PROCESSOR_OFFSET,r13 - movl r3=irq_stat // softirq_active - ;; - ld4 r2=[r2] + cmp.eq p16,p0=r0,r0 // set the "first_time" flag + movl r15=PERCPU_ADDR+IA64_CPU_SOFTIRQ_ACTIVE_OFFSET // r15 = &cpu_data.softirq.active ;; - shl r2=r2,SMP_CACHE_SHIFT // can't use shladd here... + ld8 r2=[r15] + movl r14=.restart ;; - add r3=r2,r3 -#else - movl r3=irq_stat // softirq_active + lfetch.fault [sp] + shr.u r3=r2,32 // r3 = cpu_data.softirq.mask + MOVBR(.ret.sptk,rp,r14,.restart) +.restart: + adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13 + adds r18=IA64_TASK_SIGPENDING_OFFSET,r13 +#ifdef CONFIG_PERFMON + adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13 #endif ;; - ld8 r2=[r3] // r3 (softirq_active+softirq_mask) is guaranteed to be 8-byte aligned! - ;; - shr r3=r2,32 + ld8 r17=[r17] // load current->need_resched + ld4 r18=[r18] // load current->sigpending +(p16) and r2=r2,r3 // r2 <- (softirq.active & softirq.mask) ;; - and r2=r2,r3 +#ifdef CONFIG_PERFMON + ld8 r19=[r19] // load current->task.pfm_notify +#endif +(p16) cmp4.ne.unc p6,p0=r2,r0 // p6 <- (softirq.active & softirq.mask) != 0 +(pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0? ;; - cmp4.ne p6,p7=r2,r0 -(p6) br.call.spnt.many rp=invoke_do_softirq -1: -(pKern) br.cond.dpnt.many restore_all // yup -> skip check for rescheduling & signal delivery - - // call schedule() until we find a task that doesn't have need_resched set: - -back_from_resched: - { .mii - adds r2=IA64_TASK_NEED_RESCHED_OFFSET,r13 - mov r3=ip - adds r14=IA64_TASK_SIGPENDING_OFFSET,r13 - } +(pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0? +#ifdef CONFIG_PERFMON + cmp.ne p9,p0=r19,r0 // current->task.pfm_notify != 0? +#endif + cmp.ne p16,p0=r0,r0 // clear the "first_time" flag ;; - ld8 r2=[r2] - ld4 r14=[r14] - mov rp=r3 // arrange for schedule() to return to back_from_resched +# if __GNUC__ < 3 +(p6) br.call.spnt.many b7=invoke_do_softirq +# else +(p6) br.call.spnt.many b7=do_softirq +# endif +#ifdef CONFIG_PERFMON +(p9) br.call.spnt.many b7=pfm_overflow_notify +#endif +# if __GNUC__ < 3 +(p7) br.call.spnt.many b7=invoke_schedule +#else +(p7) br.call.spnt.many b7=schedule +#endif + adds r2=PT(R8)+16,r12 + adds r3=PT(R9)+16,r12 +(p8) br.call.spnt.many b7=handle_signal_delivery // check & deliver pending signals ;; - cmp.ne p6,p0=r2,r0 - cmp.ne p2,p0=r14,r0 // NOTE: pKern is an alias for p2!! - srlz.d -(p6) br.call.spnt.many b6=invoke_schedule // ignore return value -2: - // check & deliver pending signals: -(p2) br.call.spnt.few rp=handle_signal_delivery -.ret9: -#ifdef CONFIG_IA64_SOFTSDV_HACKS - // Check for lost ticks - rsm psr.i - mov r2 = ar.itc - movl r14 = 1000 // latency tolerance - mov r3 = cr.itm - ;; - sub r2 = r2, r3 - ;; - sub r2 = r2, r14 - ;; - cmp.ge p6,p7 = r2, r0 -(p6) br.call.spnt.few rp=invoke_ia64_reset_itm -.ret10: - ;; - ssm psr.i -#endif -restore_all: - // start restoring the state saved on the kernel stack (struct pt_regs): - - adds r2=IA64_PT_REGS_R8_OFFSET+16,r12 - adds r3=IA64_PT_REGS_R8_OFFSET+24,r12 - ;; ld8.fill r8=[r2],16 ld8.fill r9=[r3],16 ;; @@ -643,6 +610,9 @@ ld8.fill r30=[r2],16 ld8.fill r31=[r3],16 ;; + rsm psr.i | psr.ic // initiate turning off of interrupts & interruption collection + invala // invalidate ALAT + ;; ld8 r1=[r2],16 // ar.ccv ld8 r13=[r3],16 // ar.fpsr ;; @@ -658,14 +628,11 @@ mov ar.ccv=r1 mov ar.fpsr=r13 mov b0=r14 - // turn off interrupts, interrupt collection - rsm psr.i | psr.ic ;; - srlz.i // EAS 2.5 + srlz.i // ensure interrupts & interruption collection are off mov b7=r15 ;; - invala // invalidate ALAT - bsw.0;; // switch back to bank 0 (must be last in insn group) + bsw.0 // switch back to bank 0 ;; #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC nop.i 0x0 @@ -683,17 +650,18 @@ ;; ld8 rCRIFS=[r16],16 // load cr.ifs ld8 rARUNAT=[r17],16 // load ar.unat + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ;; ld8 rARPFS=[r16],16 // load ar.pfs ld8 rARRSC=[r17],16 // load ar.rsc ;; ld8 rARRNAT=[r16],16 // load ar.rnat (may be garbage) - ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage) + ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage) ;; ld8 rARPR=[r16],16 // load predicates ld8 rB6=[r17],16 // load b6 ;; - ld8 r18=[r16],16 // load ar.rsc value for "loadrs" + ld8 r19=[r16],16 // load ar.rsc value for "loadrs" ld8.fill r1=[r17],16 // load r1 ;; ld8.fill r2=[r16],16 @@ -701,62 +669,102 @@ ;; ld8.fill r12=[r16],16 ld8.fill r13=[r17],16 - extr.u r19=rCRIPSR,32,2 // extract ps.cpl ;; - ld8.fill r14=[r16],16 - ld8.fill r15=[r17],16 - cmp.eq p6,p7=r0,r19 // are we returning to kernel mode? (psr.cpl==0) + ld8.fill r14=[r16] + ld8.fill r15=[r17] + shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; - mov b6=rB6 - mov ar.pfs=rARPFS -(p6) br.cond.dpnt.few skip_rbs_switch - + mov r16=ar.bsp // get existing backing store pointer + movl r17=PERCPU_ADDR+IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET + ;; + ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 +(pKern) br.cond.dpnt.few skip_rbs_switch /* * Restore user backing store. * * NOTE: alloc, loadrs, and cover can't be predicated. - * - * XXX This needs some scheduling/tuning once we believe it - * really does work as intended. */ - mov r16=ar.bsp // get existing backing store pointer (pNonSys) br.cond.dpnt.few dont_preserve_current_frame cover // add current frame into dirty partition ;; - mov rCRIFS=cr.ifs // fetch the cr.ifs value that "cover" produced - mov r17=ar.bsp // get new backing store pointer - ;; - sub r16=r17,r16 // calculate number of bytes that were added to rbs + mov r19=ar.bsp // get new backing store pointer + sub r16=r16,r18 // krbs = old bsp - size of dirty partition + cmp.ne p9,p0=r0,r0 // clear p9 to skip restore of cr.ifs ;; - shl r16=r16,16 // shift additional frame size into position for loadrs + sub r19=r19,r16 // calculate total byte size of dirty partition + add r18=64,r18 // don't force in0-in7 into memory... ;; - add r18=r16,r18 // adjust the loadrs value + shl r19=r19,16 // shift size of dirty partition into loadrs position ;; dont_preserve_current_frame: - alloc r16=ar.pfs,0,0,0,0 // drop the current call frame (noop for syscalls) - ;; - mov ar.rsc=r18 // load ar.rsc to be used for "loadrs" -#ifdef CONFIG_IA32_SUPPORT - tbit.nz p6,p0=rCRIPSR,IA64_PSR_IS_BIT + /* + * To prevent leaking bits between the kernel and user-space, + * we must clear the stacked registers in the "invalid" partition here. + * Not pretty, but at least it's fast (3.34 registers/cycle). + * Architecturally, this loop could go at 4.67 registers/cycle, but that would + * oversubscribe Itanium. + */ +# define pRecurse p6 +# define pReturn p7 +# define Nregs 10 + alloc loc0=ar.pfs,2,Nregs-2,2,0 + shr.u loc1=r18,9 // RNaTslots <= dirtySize / (64*8) + 1 + sub r17=r17,r18 // r17 = (physStackedSize + 8) - dirtySize + ;; + mov ar.rsc=r19 // load ar.rsc to be used for "loadrs" + shladd in0=loc1,3,r17 + mov in1=0 + ;; + .align 32 +rse_clear_invalid: + // cycle 0 + { .mii + alloc loc0=ar.pfs,2,Nregs-2,2,0 + cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse + add out0=-Nregs*8,in0 +}{ .mfb + add out1=1,in1 // increment recursion count + nop.f 0 + nop.b 0 // can't do br.call here because of alloc (WAW on CFM) + ;; +}{ .mfi // cycle 1 + mov loc1=0 + nop.f 0 + mov loc2=0 +}{ .mib + mov loc3=0 + mov loc4=0 +(pRecurse) br.call.sptk.few b6=rse_clear_invalid + +}{ .mfi // cycle 2 + mov loc5=0 + nop.f 0 + cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret +}{ .mib + mov loc6=0 + mov loc7=0 +(pReturn) br.ret.sptk.few b6 +} +# undef pRecurse +# undef pReturn + + alloc r17=ar.pfs,0,0,0,0 // drop current register frame ;; -(p6) mov ar.rsc=r0 // returning to IA32 mode -#endif - ;; loadrs ;; - mov ar.bspstore=rARBSPSTORE - ;; - mov ar.rnat=rARRNAT // must happen with RSE in lazy mode - skip_rbs_switch: + mov b6=rB6 + mov ar.pfs=rARPFS +(pUser) mov ar.bspstore=rARBSPSTORE +(p9) mov cr.ifs=rCRIFS + mov cr.ipsr=rCRIPSR + mov cr.iip=rCRIIP + ;; +(pUser) mov ar.rnat=rARRNAT // must happen with RSE in lazy mode mov ar.rsc=rARRSC mov ar.unat=rARUNAT - mov cr.ifs=rCRIFS // restore cr.ifs only if not a (synchronous) syscall mov pr=rARPR,-1 - mov cr.iip=rCRIIP - mov cr.ipsr=rCRIPSR - ;; - rfi;; // must be last instruction in an insn group + rfi END(ia64_leave_kernel) ENTRY(handle_syscall_error) @@ -784,13 +792,13 @@ br.cond.sptk.many ia64_leave_kernel END(handle_syscall_error) -#ifdef CONFIG_SMP +# ifdef CONFIG_SMP /* * Invoke schedule_tail(task) while preserving in0-in7, which may be needed * in case a system call gets restarted. */ ENTRY(invoke_schedule_tail) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,1,0 mov loc0=rp mov out0=r8 // Address of previous task @@ -801,35 +809,24 @@ br.ret.sptk.many rp END(invoke_schedule_tail) -#endif /* CONFIG_SMP */ - -#ifdef CONFIG_IA64_SOFTSDV_HACKS - -ENTRY(invoke_ia64_reset_itm) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) - alloc loc1=ar.pfs,8,2,0,0 - mov loc0=rp - ;; - UNW(.body) - br.call.sptk.many rp=ia64_reset_itm -.ret12: ;; - mov ar.pfs=loc1 - mov rp=loc0 - br.ret.sptk.many rp -END(invoke_ia64_reset_itm) - -#endif /* CONFIG_IA64_SOFTSDV_HACKS */ +# endif /* CONFIG_SMP */ +#if __GNUC__ < 3 /* * Invoke do_softirq() while preserving in0-in7, which may be needed - * in case a system call gets restarted. + * in case a system call gets restarted. Note that declaring do_softirq() + * with asmlinkage() is NOT enough because that will only preserve as many + * registers as there are formal arguments. + * + * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage + * renders all eight input registers (in0-in7) as "untouchable". */ ENTRY(invoke_do_softirq) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,0,0 mov loc0=rp ;; - UNW(.body) + .body br.call.sptk.few rp=do_softirq .ret13: mov ar.pfs=loc1 mov rp=loc0 @@ -838,27 +835,33 @@ /* * Invoke schedule() while preserving in0-in7, which may be needed - * in case a system call gets restarted. + * in case a system call gets restarted. Note that declaring schedule() + * with asmlinkage() is NOT enough because that will only preserve as many + * registers as there are formal arguments. + * + * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage + * renders all eight input registers (in0-in7) as "untouchable". */ ENTRY(invoke_schedule) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,0,0 mov loc0=rp ;; - UNW(.body) + .body br.call.sptk.few rp=schedule .ret14: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp END(invoke_schedule) - // - // Setup stack and call ia64_do_signal. Note that pSys and pNonSys need to - // be set up by the caller. We declare 8 input registers so the system call - // args get preserved, in case we need to restart a system call. - // +#endif /* __GNUC__ < 3 */ + + /* + * Setup stack and call ia64_do_signal. Note that pSys and pNonSys need to + * be set up by the caller. We declare 8 input registers so the system call + * args get preserved, in case we need to restart a system call. + */ ENTRY(handle_signal_delivery) -#ifdef CONFIG_IA64_NEW_UNWIND .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! mov r9=ar.unat @@ -882,26 +885,9 @@ mov ar.unat=r9 mov ar.pfs=loc1 br.ret.sptk.many rp -#else /* !CONFIG_IA64_NEW_UNWIND */ - .prologue - alloc r16=ar.pfs,8,0,3,0 // preserve all eight input regs in case of syscall restart! - DO_SAVE_SWITCH_STACK - UNW(.body) - - mov out0=0 // there is no "oldset" - adds out1=16,sp // out1=&sigscratch - .pred.rel.mutex pSys, pNonSys -(pSys) mov out2=1 // out2==1 => we're in a syscall -(pNonSys) mov out2=0 // out2==0 => not a syscall - br.call.sptk.few rp=ia64_do_signal -.ret16: // restore the switch stack (ptrace may have modified it) - DO_LOAD_SWITCH_STACK( ) - br.ret.sptk.many rp -#endif /* !CONFIG_IA64_NEW_UNWIND */ END(handle_signal_delivery) GLOBAL_ENTRY(sys_rt_sigsuspend) -#ifdef CONFIG_IA64_NEW_UNWIND .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! mov r9=ar.unat @@ -924,87 +910,43 @@ mov ar.unat=r9 mov ar.pfs=loc1 br.ret.sptk.many rp -#else /* !CONFIG_IA64_NEW_UNWIND */ - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) - alloc r16=ar.pfs,2,0,3,0 - DO_SAVE_SWITCH_STACK - UNW(.body) - - mov out0=in0 // mask - mov out1=in1 // sigsetsize - adds out2=16,sp // out1=&sigscratch - br.call.sptk.many rp=ia64_rt_sigsuspend -.ret18: // restore the switch stack (ptrace may have modified it) - DO_LOAD_SWITCH_STACK( ) - br.ret.sptk.many rp -#endif /* !CONFIG_IA64_NEW_UNWIND */ END(sys_rt_sigsuspend) ENTRY(sys_rt_sigreturn) -#ifdef CONFIG_IA64_NEW_UNWIND - .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler() PT_REGS_UNWIND_INFO(0) + alloc r2=ar.pfs,0,0,1,0 .prologue PT_REGS_SAVES(16) adds sp=-16,sp .body - cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall... + cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall... ;; adds out0=16,sp // out0 = &sigscratch br.call.sptk.few rp=ia64_rt_sigreturn -.ret19: adds sp=16,sp // doesn't drop pt_regs, so don't mark it as restoring sp! - PT_REGS_UNWIND_INFO(0) // instead, create a new body section with the smaller frame +.ret19: .restore sp 0 + adds sp=16,sp ;; ld8 r9=[sp] // load new ar.unat - mov b7=r8 + MOVBR(.sptk,b7,r8,ia64_leave_kernel) ;; mov ar.unat=r9 br b7 -#else /* !CONFIG_IA64_NEW_UNWIND */ - .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler() - PT_REGS_UNWIND_INFO(0) - UNW(.prologue) - UNW(.fframe IA64_PT_REGS_SIZE+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp rp, PT(CR_IIP)+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp ar.pfs, PT(CR_IFS)+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp ar.unat, PT(AR_UNAT)+IA64_SWITCH_STACK_SIZE) - UNW(.spillsp pr, PT(PR)+IA64_SWITCH_STACK_SIZE) - adds sp=-IA64_SWITCH_STACK_SIZE,sp - cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall... - ;; - UNW(.body) - - adds out0=16,sp // out0 = &sigscratch - br.call.sptk.few rp=ia64_rt_sigreturn -.ret20: adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp - ;; - ld8 r9=[r3] // load new ar.unat - mov b7=r8 - ;; - PT_REGS_UNWIND_INFO(0) - adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch-stack frame - mov ar.unat=r9 - br b7 -#endif /* !CONFIG_IA64_NEW_UNWIND */ END(sys_rt_sigreturn) GLOBAL_ENTRY(ia64_prepare_handle_unaligned) // - // r16 = fake ar.pfs, we simply need to make sure + // r16 = fake ar.pfs, we simply need to make sure // privilege is still 0 // - PT_REGS_UNWIND_INFO(0) - mov r16=r0 - UNW(.prologue) + mov r16=r0 + .prologue DO_SAVE_SWITCH_STACK br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt .ret21: .body - DO_LOAD_SWITCH_STACK(PT_REGS_UNWIND_INFO(0)) + DO_LOAD_SWITCH_STACK br.cond.sptk.many rp // goes to ia64_leave_kernel END(ia64_prepare_handle_unaligned) -#ifdef CONFIG_IA64_NEW_UNWIND - // // unw_init_running(void (*callback)(info, arg), void *arg) // @@ -1050,8 +992,6 @@ br.ret.sptk.many rp END(unw_init_running) -#endif - .rodata .align 8 .globl sys_call_table @@ -1229,7 +1169,7 @@ data8 sys_accept data8 sys_getsockname // 1195 data8 sys_getpeername - data8 sys_socketpair + data8 sys_socketpair data8 sys_send data8 sys_sendto data8 sys_recv // 1200 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/entry.h linux.ac/arch/ia64/kernel/entry.h --- linux.vanilla/arch/ia64/kernel/entry.h Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/kernel/entry.h Tue Apr 10 18:08:40 2001 @@ -1,65 +1,77 @@ +#include + +/* XXX fixme */ +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) +# define MOVBR(type,br,gr,lbl) mov br=gr +#else +# define MOVBR(type,br,gr,lbl) mov##type br=gr,lbl +#endif + /* * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! */ #define pKern p2 /* will leave_kernel return to kernel-mode? */ +#define pUser p3 /* will leave_kernel return to user-mode? */ #define pSys p4 /* are we processing a (synchronous) system call? */ #define pNonSys p5 /* complement of pSys */ -#define PT(f) (IA64_PT_REGS_##f##_OFFSET + 16) -#define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET + 16) +#define PT(f) (IA64_PT_REGS_##f##_OFFSET) +#define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET) -#define PT_REGS_SAVES(off) \ - UNW(.unwabi @svr4, 'i'); \ - UNW(.fframe IA64_PT_REGS_SIZE+16+(off)); \ - UNW(.spillsp rp, PT(CR_IIP)+(off)); \ - UNW(.spillsp ar.pfs, PT(CR_IFS)+(off)); \ - UNW(.spillsp ar.unat, PT(AR_UNAT)+(off)); \ - UNW(.spillsp ar.fpsr, PT(AR_FPSR)+(off)); \ - UNW(.spillsp pr, PT(PR)+(off)); +#define PT_REGS_SAVES(off) \ + .unwabi @svr4, 'i'; \ + .fframe IA64_PT_REGS_SIZE+16+(off); \ + .spillsp rp, PT(CR_IIP)+16+(off); \ + .spillsp ar.pfs, PT(CR_IFS)+16+(off); \ + .spillsp ar.unat, PT(AR_UNAT)+16+(off); \ + .spillsp ar.fpsr, PT(AR_FPSR)+16+(off); \ + .spillsp pr, PT(PR)+16+(off); #define PT_REGS_UNWIND_INFO(off) \ - UNW(.prologue); \ + .prologue; \ PT_REGS_SAVES(off); \ - UNW(.body) + .body -#define SWITCH_STACK_SAVES(off) \ - UNW(.savesp ar.unat,SW(CALLER_UNAT)+(off)); UNW(.savesp ar.fpsr,SW(AR_FPSR)+(off)); \ - UNW(.spillsp f2,SW(F2)+(off)); UNW(.spillsp f3,SW(F3)+(off)); \ - UNW(.spillsp f4,SW(F4)+(off)); UNW(.spillsp f5,SW(F5)+(off)); \ - UNW(.spillsp f16,SW(F16)+(off)); UNW(.spillsp f17,SW(F17)+(off)); \ - UNW(.spillsp f18,SW(F18)+(off)); UNW(.spillsp f19,SW(F19)+(off)); \ - UNW(.spillsp f20,SW(F20)+(off)); UNW(.spillsp f21,SW(F21)+(off)); \ - UNW(.spillsp f22,SW(F22)+(off)); UNW(.spillsp f23,SW(F23)+(off)); \ - UNW(.spillsp f24,SW(F24)+(off)); UNW(.spillsp f25,SW(F25)+(off)); \ - UNW(.spillsp f26,SW(F26)+(off)); UNW(.spillsp f27,SW(F27)+(off)); \ - UNW(.spillsp f28,SW(F28)+(off)); UNW(.spillsp f29,SW(F29)+(off)); \ - UNW(.spillsp f30,SW(F30)+(off)); UNW(.spillsp f31,SW(F31)+(off)); \ - UNW(.spillsp r4,SW(R4)+(off)); UNW(.spillsp r5,SW(R5)+(off)); \ - UNW(.spillsp r6,SW(R6)+(off)); UNW(.spillsp r7,SW(R7)+(off)); \ - UNW(.spillsp b0,SW(B0)+(off)); UNW(.spillsp b1,SW(B1)+(off)); \ - UNW(.spillsp b2,SW(B2)+(off)); UNW(.spillsp b3,SW(B3)+(off)); \ - UNW(.spillsp b4,SW(B4)+(off)); UNW(.spillsp b5,SW(B5)+(off)); \ - UNW(.spillsp ar.pfs,SW(AR_PFS)+(off)); UNW(.spillsp ar.lc,SW(AR_LC)+(off)); \ - UNW(.spillsp @priunat,SW(AR_UNAT)+(off)); \ - UNW(.spillsp ar.rnat,SW(AR_RNAT)+(off)); UNW(.spillsp ar.bspstore,SW(AR_BSPSTORE)+(off)); \ - UNW(.spillsp pr,SW(PR)+(off)) +#define SWITCH_STACK_SAVES(off) \ + .savesp ar.unat,SW(CALLER_UNAT)+16+(off); \ + .savesp ar.fpsr,SW(AR_FPSR)+16+(off); \ + .spillsp f2,SW(F2)+16+(off); .spillsp f3,SW(F3)+16+(off); \ + .spillsp f4,SW(F4)+16+(off); .spillsp f5,SW(F5)+16+(off); \ + .spillsp f16,SW(F16)+16+(off); .spillsp f17,SW(F17)+16+(off); \ + .spillsp f18,SW(F18)+16+(off); .spillsp f19,SW(F19)+16+(off); \ + .spillsp f20,SW(F20)+16+(off); .spillsp f21,SW(F21)+16+(off); \ + .spillsp f22,SW(F22)+16+(off); .spillsp f23,SW(F23)+16+(off); \ + .spillsp f24,SW(F24)+16+(off); .spillsp f25,SW(F25)+16+(off); \ + .spillsp f26,SW(F26)+16+(off); .spillsp f27,SW(F27)+16+(off); \ + .spillsp f28,SW(F28)+16+(off); .spillsp f29,SW(F29)+16+(off); \ + .spillsp f30,SW(F30)+16+(off); .spillsp f31,SW(F31)+16+(off); \ + .spillsp r4,SW(R4)+16+(off); .spillsp r5,SW(R5)+16+(off); \ + .spillsp r6,SW(R6)+16+(off); .spillsp r7,SW(R7)+16+(off); \ + .spillsp b0,SW(B0)+16+(off); .spillsp b1,SW(B1)+16+(off); \ + .spillsp b2,SW(B2)+16+(off); .spillsp b3,SW(B3)+16+(off); \ + .spillsp b4,SW(B4)+16+(off); .spillsp b5,SW(B5)+16+(off); \ + .spillsp ar.pfs,SW(AR_PFS)+16+(off); .spillsp ar.lc,SW(AR_LC)+16+(off); \ + .spillsp @priunat,SW(AR_UNAT)+16+(off); \ + .spillsp ar.rnat,SW(AR_RNAT)+16+(off); \ + .spillsp ar.bspstore,SW(AR_BSPSTORE)+16+(off); \ + .spillsp pr,SW(PR)+16+(off)) #define DO_SAVE_SWITCH_STACK \ movl r28=1f; \ ;; \ .fframe IA64_SWITCH_STACK_SIZE; \ adds sp=-IA64_SWITCH_STACK_SIZE,sp; \ - mov b7=r28; \ + MOVBR(.ret.sptk,b7,r28,1f); \ SWITCH_STACK_SAVES(0); \ br.cond.sptk.many save_switch_stack; \ 1: -#define DO_LOAD_SWITCH_STACK(extra) \ +#define DO_LOAD_SWITCH_STACK \ movl r28=1f; \ ;; \ - mov b7=r28; \ + invala; \ + MOVBR(.ret.sptk,b7,r28,1f); \ br.cond.sptk.many load_switch_stack; \ -1: UNW(.restore sp); \ - extra; \ +1: .restore sp; \ adds sp=IA64_SWITCH_STACK_SIZE,sp diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/fw-emu.c linux.ac/arch/ia64/kernel/fw-emu.c --- linux.vanilla/arch/ia64/kernel/fw-emu.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/fw-emu.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * PAL & SAL emulation. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang * * For the HP simulator, this file gets include in boot/bootloader.c. * For SoftSDV, this file gets included in sys_softsdv.c. @@ -22,7 +22,8 @@ #define NUM_MEM_DESCS 2 -static char fw_mem[( sizeof(efi_system_table_t) +static char fw_mem[( sizeof(struct ia64_boot_param) + + sizeof(efi_system_table_t) + sizeof(efi_runtime_services_t) + 1*sizeof(efi_config_table_t) + sizeof(struct ia64_sal_systab) @@ -151,6 +152,14 @@ movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ movl r11=0x100000064 /* itc_ratio<<32 (1/100) */ ;; +1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ +(p7) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + mov r9=96 /* num phys stacked */ + mov r10=0 /* hints */ + mov r11=0 + br.cond.sptk.few rp + 1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */ (p7) br.cond.sptk.few 1f mov r9=ar.lc @@ -168,8 +177,7 @@ ;; mov ar.lc=r9 mov r8=r0 -1: - br.cond.sptk.few rp +1: br.cond.sptk.few rp stacked: br.ret.sptk.few rp @@ -249,13 +257,7 @@ * or something platform specific? The SAL * doc ain't exactly clear on this... */ -#if defined(CONFIG_IA64_SOFTSDV_HACKS) - r9 = 4000000; -#elif defined(CONFIG_IA64_SDV) - r9 = 300000000; -#else r9 = 700000000; -#endif break; case SAL_FREQ_BASE_REALTIME_CLOCK: @@ -332,7 +334,7 @@ return (void *) addr; } -void +struct ia64_boot_param * sys_fw_init (const char *args, int arglen) { efi_system_table_t *efi_systab; @@ -358,6 +360,7 @@ sal_systab = (void *) cp; cp += sizeof(*sal_systab); sal_ed = (void *) cp; cp += sizeof(*sal_ed); efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); + bp = (void *) cp; cp += sizeof(*bp); cmd_line = (void *) cp; if (args) { @@ -423,7 +426,7 @@ strcpy(sal_systab->product_id, "SN1"); #endif - /* fill in an entry point: */ + /* fill in an entry point: */ sal_ed->type = SAL_DESC_ENTRY_POINT; sal_ed->pal_proc = __pa(pal_desc[0]); sal_ed->sal_proc = __pa(sal_desc[0]); @@ -440,15 +443,15 @@ md->pad = 0; md->phys_addr = 2*MB; md->virt_addr = 0; - md->num_pages = (64*MB) >> 12; /* 64MB (in 4KB pages) */ + md->num_pages = (128*MB) >> 12; /* 128MB (in 4KB pages) */ md->attribute = EFI_MEMORY_WB; /* descriptor for firmware emulator: */ md = &efi_memmap[1]; - md->type = EFI_RUNTIME_SERVICES_DATA; + md->type = EFI_PAL_CODE; md->pad = 0; md->phys_addr = 1*MB; - md->virt_addr = 0; + md->virt_addr = 1*MB; md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */ md->attribute = EFI_MEMORY_WB; @@ -468,7 +471,6 @@ md->attribute = EFI_MEMORY_WB; #endif - bp = id(ZERO_PAGE_ADDR); bp->efi_systab = __pa(&fw_mem); bp->efi_memmap = __pa(efi_memmap); bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t); @@ -479,6 +481,7 @@ bp->console_info.num_rows = 25; bp->console_info.orig_x = 0; bp->console_info.orig_y = 24; - bp->num_pci_vectors = 0; bp->fpswa = 0; + + return bp; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/gate.S linux.ac/arch/ia64/kernel/gate.S --- linux.vanilla/arch/ia64/kernel/gate.S Sat Jul 15 00:08:11 2000 +++ linux.ac/arch/ia64/kernel/gate.S Tue Apr 10 18:08:40 2001 @@ -1,10 +1,9 @@ /* - * This file contains the code that gets mapped at the upper end of - * each task's text region. For now, it contains the signal - * trampoline code only. + * This file contains the code that gets mapped at the upper end of each task's text + * region. For now, it contains the signal trampoline code only. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang */ #include @@ -14,11 +13,7 @@ #include #include - .psr abi64 - .psr lsb - .lsb - - .section __gate_section,"ax" + .section .text.gate,"ax" .align PAGE_SIZE @@ -51,28 +46,24 @@ * | space | * +-------------------------------+ <-- sp * - * The register stack looks _exactly_ the way it looked at the - * time the signal occurred. In other words, we're treading - * on a potential mine-field: each incoming general register - * may be a NaT value (includeing sp, in which case the process - * ends up dying with a SIGSEGV). + * The register stack looks _exactly_ the way it looked at the time the signal + * occurred. In other words, we're treading on a potential mine-field: each + * incoming general register may be a NaT value (including sp, in which case the + * process ends up dying with a SIGSEGV). * - * The first need to do is a cover to get the registers onto - * the backing store. Once that is done, we invoke the signal - * handler which may modify some of the machine state. After - * returning from the signal handler, we return control to the - * previous context by executing a sigreturn system call. A - * signal handler may call the rt_sigreturn() function to - * directly return to a given sigcontext. However, the - * user-level sigreturn() needs to do much more than calling - * the rt_sigreturn() system call as it needs to unwind the - * stack to restore preserved registers that may have been - * saved on the signal handler's call stack. + * The first need to do is a cover to get the registers onto the backing store. + * Once that is done, we invoke the signal handler which may modify some of the + * machine state. After returning from the signal handler, we return control to + * the previous context by executing a sigreturn system call. A signal handler + * may call the rt_sigreturn() function to directly return to a given sigcontext. + * However, the user-level sigreturn() needs to do much more than calling the + * rt_sigreturn() system call as it needs to unwind the stack to restore preserved + * registers that may have been saved on the signal handler's call stack. * * On entry: * r2 = signal number * r3 = plabel of signal handler - * r15 = new register backing store (ignored) + * r15 = new register backing store * [sp+16] = sigframe */ @@ -153,7 +144,7 @@ ENTRY(setup_rbs) flushrs // must be first in insn - mov ar.rsc=r0 // put RSE into enforced lazy mode + mov ar.rsc=0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; mov r14=ar.rnat // get rnat as updated by flushrs @@ -167,7 +158,7 @@ ENTRY(restore_rbs) flushrs - mov ar.rsc=r0 // put RSE into enforced lazy mode + mov ar.rsc=0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; ld8 r14=[r16] // get new rnat diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/head.S linux.ac/arch/ia64/kernel/head.S --- linux.vanilla/arch/ia64/kernel/head.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/head.S Tue Apr 10 18:08:40 2001 @@ -5,8 +5,9 @@ * to set up the kernel's global pointer and jump to the kernel * entry point. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang + * Copyright (C) 2001 Stephane Eranian * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * Copyright (C) 1999 Intel Corp. @@ -18,16 +19,15 @@ #include #include -#include +#include +#include #include +#include +#include #include #include #include - .psr abi64 - .psr lsb - .lsb - .section __special_page_section,"ax" .global empty_zero_page @@ -38,29 +38,66 @@ swapper_pg_dir: .skip PAGE_SIZE - .global empty_bad_page -empty_bad_page: - .skip PAGE_SIZE - - .global empty_bad_pte_table -empty_bad_pte_table: - .skip PAGE_SIZE - - .global empty_bad_pmd_table -empty_bad_pmd_table: - .skip PAGE_SIZE - .rodata halt_msg: stringz "Halting kernel\n" .text + .global start_ap + + /* + * Start the kernel. When the bootloader passes control to _start(), r28 + * points to the address of the boot parameter area. Execution reaches + * here in physical mode. + */ GLOBAL_ENTRY(_start) - UNW(.prologue) - UNW(.save rp, r4) // terminate unwind chain with a NULL rp - UNW(mov r4=r0) - UNW(.body) +start_ap: + .prologue + .save rp, r4 // terminate unwind chain with a NULL rp + mov r4=r0 + .body + + /* + * Initialize the region register for region 7 and install a translation register + * that maps the kernel's text and data: + */ + rsm psr.i | psr.ic + mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (_PAGE_SIZE_64M << 2)) + ;; + srlz.i + mov r18=_PAGE_SIZE_64M<<2 + movl r17=PAGE_OFFSET + 64*1024*1024 + ;; + mov rr[r17]=r16 + mov cr.itir=r18 + mov cr.ifa=r17 + mov r16=IA64_TR_KERNEL + movl r18=(64*1024*1024 | PAGE_KERNEL) + ;; + srlz.i + ;; + itr.i itr[r16]=r18 + ;; + itr.d dtr[r16]=r18 + ;; + srlz.i + + /* + * Switch into virtual mode: + */ + movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN) + ;; + mov cr.ipsr=r16 + movl r17=1f + ;; + mov cr.iip=r17 + mov cr.ifs=r0 + ;; + rfi + ;; +1: // now we are in virtual mode + // set IVT entry point---can't access I/O ports without it movl r3=ia64_ivt ;; @@ -74,7 +111,7 @@ ;; #ifdef CONFIG_IA64_EARLY_PRINTK - mov r3=(6<<8) | (28<<2) + mov r3=(6<<8) | (_PAGE_SIZE_64M<<2) movl r2=6<<61 ;; mov rr[r2]=r3 @@ -83,27 +120,32 @@ ;; #endif -#define isAP p2 // are we booting an Application Processor (not the BSP)? +#define isAP p2 // are we an Application Processor? +#define isBP p3 // are we the Bootstrap Processor? - // Find the init_task for the currently booting CPU. At poweron, and in - // UP mode, cpu_now_booting is 0 + /* + * Find the init_task for the currently booting CPU. At poweron, and in + * UP mode, cpu_now_booting is 0. + */ movl r3=cpu_now_booting ;; - ld4 r3=[r3] + ld4 r3=[r3] // r3 <- smp_processor_id() movl r2=init_tasks - ;; + ;; shladd r2=r3,3,r2 ;; ld8 r2=[r2] - cmp4.ne isAP,p0=r3,r0 // p9 == true if this is an application processor (ap) + cmp4.ne isAP,isBP=r3,r0 ;; // RAW on r2 extr r3=r2,0,61 // r3 == phys addr of task struct ;; - // load the "current" pointer (r13) and ar.k6 with the current task + // load the "current" pointer (r13) and ar.k6 with the current task mov r13=r2 - mov ar.k6=r3 // Physical address - ;; + mov IA64_KR(CURRENT)=r3 // Physical address + + // initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL) + mov IA64_KR(CURRENT_STACK)=1 /* * Reserve space at the top of the stack for "struct pt_regs". Kernel threads * don't store interesting values in that structure, but the space still needs @@ -113,14 +155,18 @@ */ addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2 addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE - mov ar.rsc=r0 // place RSE in enforced lazy mode + mov ar.rsc=0 // place RSE in enforced lazy mode ;; - mov ar.bspstore=r2 // establish the new RSE stack + loadrs // clear the dirty partition ;; - loadrs // load zero bytes from the register stack + mov ar.bspstore=r2 // establish the new RSE stack ;; mov ar.rsc=0x3 // place RSE in eager mode + +(isBP) dep r28=-1,r28,61,3 // make address virtual +(isBP) movl r2=ia64_boot_param ;; +(isBP) st8 [r2]=r28 // save the address of the boot param area passed by the bootloader #ifdef CONFIG_IA64_EARLY_PRINTK .rodata @@ -135,16 +181,12 @@ 1: // force new bundle #endif /* CONFIG_IA64_EARLY_PRINTK */ - alloc r2=ar.pfs,8,0,2,0 - ;; #ifdef CONFIG_SMP (isAP) br.call.sptk.few rp=smp_callin .ret0: (isAP) br.cond.sptk.few self #endif -#undef isAP - // This is executed by the bootstrap processor (bsp) only: #ifdef CONFIG_IA64_FW_EMU @@ -153,9 +195,11 @@ .ret1: #endif br.call.sptk.few rp=start_kernel -.ret2: addl r2=@ltoff(halt_msg),gp +.ret2: addl r3=@ltoff(halt_msg),gp + ;; + alloc r2=ar.pfs,8,0,2,0 ;; - ld8 out0=[r2] + ld8 out0=[r3] br.call.sptk.few b0=console_print self: br.sptk.few self // endless loop END(_start) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/ia64_ksyms.c linux.ac/arch/ia64/kernel/ia64_ksyms.c --- linux.vanilla/arch/ia64/kernel/ia64_ksyms.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/ia64_ksyms.c Tue Apr 10 18:08:40 2001 @@ -24,8 +24,11 @@ EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); -#include +#include EXPORT_SYMBOL(isa_irq_to_vector_map); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); #include #include @@ -40,10 +43,14 @@ EXPORT_SYMBOL(__ia64_memcpy_toio); EXPORT_SYMBOL(__ia64_memset_c_io); -#include -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(disable_irq_nosync); +#include +EXPORT_SYMBOL_NOVERS(__down); +EXPORT_SYMBOL_NOVERS(__down_interruptible); +EXPORT_SYMBOL_NOVERS(__down_trylock); +EXPORT_SYMBOL_NOVERS(__up); +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); #include EXPORT_SYMBOL(clear_page); @@ -57,14 +64,20 @@ EXPORT_SYMBOL(last_cli_ip); #endif +#include + #ifdef CONFIG_SMP +EXPORT_SYMBOL(smp_flush_tlb_all); + #include #include EXPORT_SYMBOL(synchronize_irq); #include EXPORT_SYMBOL(smp_call_function); +EXPORT_SYMBOL(smp_call_function_single); +EXPORT_SYMBOL(cpu_online_map); #include EXPORT_SYMBOL(smp_num_cpus); @@ -78,7 +91,11 @@ EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); -#endif +#else /* !CONFIG_SMP */ + +EXPORT_SYMBOL(__flush_tlb_all); + +#endif /* !CONFIG_SMP */ #include EXPORT_SYMBOL(__copy_user); @@ -111,3 +128,12 @@ extern unsigned long ia64_iobase; EXPORT_SYMBOL(ia64_iobase); + +#include +EXPORT_SYMBOL(ia64_pal_call_phys_stacked); +EXPORT_SYMBOL(ia64_pal_call_phys_static); +EXPORT_SYMBOL(ia64_pal_call_stacked); +EXPORT_SYMBOL(ia64_pal_call_static); + +extern struct efi efi; +EXPORT_SYMBOL(efi); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/iosapic.c linux.ac/arch/ia64/kernel/iosapic.c --- linux.vanilla/arch/ia64/kernel/iosapic.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/iosapic.c Tue Apr 10 18:08:40 2001 @@ -11,7 +11,7 @@ * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. * In particular, we now have separate handlers for edge * and level triggered interrupts. - * 00/10/27 Asit Mallick, Goutham Rao IRQ vector allocation + * 00/10/27 Asit Mallick, Goutham Rao IRQ vector allocation * PCI to vector mapping, shared PCI interrupts. * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. * Clean up much of the old IOSAPIC cruft. @@ -79,27 +79,27 @@ static struct iosapic_irq { char *addr; /* base address of IOSAPIC */ unsigned char base_irq; /* first irq assigned to this IOSAPIC */ - char pin; /* IOSAPIC pin (-1 => not an IOSAPIC irq) */ - unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ + char pin; /* IOSAPIC pin (-1 => not an IOSAPIC irq) */ + unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ unsigned char polarity : 1; /* interrupt polarity (see iosapic.h) */ unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ -} iosapic_irq[NR_IRQS]; +} iosapic_irq[IA64_NUM_VECTORS]; /* * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector. If no * entry exists, return -1. */ -static int +static int iosapic_irq_to_vector (int irq) { int vector; - for (vector = 0; vector < NR_IRQS; ++vector) + for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin == irq) return vector; return -1; } - + /* * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists, * return -1. @@ -137,14 +137,8 @@ (dmode << IOSAPIC_DELIVERY_SHIFT) | vector); -#ifdef CONFIG_IA64_AZUSA_HACKS - /* set Flush Disable bit */ - if (addr != (char *) 0xc0000000fec00000) - low32 |= (1 << 17); -#endif - /* dest contains both id and eid */ - high32 = (dest << IOSAPIC_DEST_SHIFT); + high32 = (dest << IOSAPIC_DEST_SHIFT); writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); writel(high32, addr + IOSAPIC_WINDOW); @@ -158,16 +152,17 @@ /* do nothing... */ } -static void -mask_irq (unsigned int vector) +static void +mask_irq (unsigned int irq) { unsigned long flags; char *addr; u32 low32; int pin; + ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vector].addr; - pin = iosapic_irq[vector].pin; + addr = iosapic_irq[vec].addr; + pin = iosapic_irq[vec].pin; if (pin < 0) return; /* not an IOSAPIC interrupt! */ @@ -183,16 +178,17 @@ spin_unlock_irqrestore(&iosapic_lock, flags); } -static void -unmask_irq (unsigned int vector) +static void +unmask_irq (unsigned int irq) { unsigned long flags; char *addr; u32 low32; int pin; + ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vector].addr; - pin = iosapic_irq[vector].pin; + addr = iosapic_irq[vec].addr; + pin = iosapic_irq[vec].pin; if (pin < 0) return; /* not an IOSAPIC interrupt! */ @@ -209,7 +205,7 @@ static void -iosapic_set_affinity (unsigned int vector, unsigned long mask) +iosapic_set_affinity (unsigned int irq, unsigned long mask) { printk("iosapic_set_affinity: not implemented yet\n"); } @@ -219,16 +215,18 @@ */ static unsigned int -iosapic_startup_level_irq (unsigned int vector) +iosapic_startup_level_irq (unsigned int irq) { - unmask_irq(vector); + unmask_irq(irq); return 0; } static void -iosapic_end_level_irq (unsigned int vector) +iosapic_end_level_irq (unsigned int irq) { - writel(vector, iosapic_irq[vector].addr + IOSAPIC_EOI); + ia64_vector vec = irq_to_vector(irq); + + writel(vec, iosapic_irq[vec].addr + IOSAPIC_EOI); } #define iosapic_shutdown_level_irq mask_irq @@ -252,9 +250,9 @@ */ static unsigned int -iosapic_startup_edge_irq (unsigned int vector) +iosapic_startup_edge_irq (unsigned int irq) { - unmask_irq(vector); + unmask_irq(irq); /* * IOSAPIC simply drops interrupts pended while the * corresponding pin was masked, so we can't know if an @@ -264,15 +262,16 @@ } static void -iosapic_ack_edge_irq (unsigned int vector) +iosapic_ack_edge_irq (unsigned int irq) { + irq_desc_t *idesc = irq_desc(irq); /* * Once we have recorded IRQ_PENDING already, we can mask the * interrupt for real. This prevents IRQ storms from unhandled * devices. */ - if ((irq_desc[vector].status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) - mask_irq(vector); + if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) + mask_irq(irq); } #define iosapic_enable_edge_irq unmask_irq @@ -291,7 +290,7 @@ }; static unsigned int -iosapic_version (char *addr) +iosapic_version (char *addr) { /* * IOSAPIC Version Register return 32 bit structure like: @@ -335,6 +334,7 @@ { struct hw_interrupt_type *irq_type; int i, irq, max_pin, vector; + irq_desc_t *idesc; unsigned int ver; char *addr; static int first_time = 1; @@ -342,18 +342,18 @@ if (first_time) { first_time = 0; - for (vector = 0; vector < NR_IRQS; ++vector) + for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) iosapic_irq[vector].pin = -1; /* mark as unused */ - /* + /* * Fetch the PCI interrupt routing table: */ #ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes); #else pci_irq.route = - (struct pci_vector_struct *) __va(ia64_boot_param.pci_vectors); - pci_irq.num_routes = ia64_boot_param.num_pci_vectors; + (struct pci_vector_struct *) __va(ia64_boot_param->pci_vectors); + pci_irq.num_routes = ia64_boot_param->num_pci_vectors; #endif } @@ -361,8 +361,8 @@ ver = iosapic_version(addr); max_pin = (ver >> 16) & 0xff; - - printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", + + printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin); if (base_irq == 0) @@ -385,20 +385,20 @@ irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); #endif - irq_type = &irq_type_iosapic_edge; - if (irq_desc[vector].handler != irq_type) { - if (irq_desc[vector].handler != &no_irq_type) + irq_type = &irq_type_iosapic_edge; + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) printk("iosapic_init: changing vector 0x%02x from %s to " - "%s\n", irq, irq_desc[vector].handler->typename, + "%s\n", irq, idesc->handler->typename, irq_type->typename); - irq_desc[vector].handler = irq_type; + idesc->handler = irq_type; } /* program the IOSAPIC routing table: */ set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); } -#ifndef CONFIG_IA64_SOFTSDV_HACKS for (i = 0; i < pci_irq.num_routes; i++) { irq = pci_irq.route[i].irq; @@ -428,18 +428,17 @@ iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); # endif irq_type = &irq_type_iosapic_level; - if (irq_desc[vector].handler != irq_type){ - if (irq_desc[vector].handler != &no_irq_type) + idesc = irq_desc(vector); + if (idesc->handler != irq_type){ + if (idesc->handler != &no_irq_type) printk("iosapic_init: changing vector 0x%02x from %s to %s\n", - vector, irq_desc[vector].handler->typename, - irq_type->typename); - irq_desc[vector].handler = irq_type; + vector, idesc->handler->typename, irq_type->typename); + idesc->handler = irq_type; } /* program the IOSAPIC routing table: */ set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); } -#endif /* !CONFIG_IA64_SOFTSDV_HACKS */ } void @@ -492,7 +491,7 @@ * Nothing to fixup * Fix out-of-range IRQ numbers */ - if (dev->irq >= NR_IRQS) + if (dev->irq >= IA64_NUM_VECTORS) dev->irq = 15; /* Spurious interrupts */ } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/irq.c linux.ac/arch/ia64/kernel/irq.c --- linux.vanilla/arch/ia64/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/ia64/kernel/irq.c Tue Apr 10 18:08:40 2001 @@ -63,7 +63,7 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = +irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; static void register_irq_proc (unsigned int irq); @@ -131,6 +131,7 @@ { int i, j; struct irqaction * action; + irq_desc_t *idesc; char *p = buf; p += sprintf(p, " "); @@ -139,8 +140,9 @@ *p++ = '\n'; for (i = 0 ; i < NR_IRQS ; i++) { - action = irq_desc[i].action; - if (!action) + idesc = irq_desc(i); + action = idesc->action; + if (!action) continue; p += sprintf(p, "%3d: ",i); #ifndef CONFIG_SMP @@ -150,7 +152,7 @@ p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); #endif - p += sprintf(p, " %14s", irq_desc[i].handler->typename); + p += sprintf(p, " %14s", idesc->handler->typename); p += sprintf(p, " %s", action->name); for (action=action->next; action; action = action->next) @@ -193,10 +195,10 @@ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [",irqs_running()); for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_irq_count(i)); + printk(" %d",irq_count(i)); printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_bh_count(i)); + printk(" %d",bh_count(i)); printk(" ]\nStack dumps:"); #if defined(__ia64__) @@ -224,7 +226,7 @@ esp &= ~(THREAD_SIZE-1); esp += sizeof(struct task_struct); show_stack((void*)esp); - } + } #else You lose... #endif @@ -232,7 +234,7 @@ show_stack(NULL); printk("\n"); } - + #define MAXCOUNT 100000000 /* @@ -266,7 +268,7 @@ # endif #endif -static inline void wait_on_irq(int cpu) +static inline void wait_on_irq(void) { int count = MAXCOUNT; @@ -278,7 +280,7 @@ * already executing in one.. */ if (!irqs_running()) - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) + if (local_bh_count() || !spin_is_locked(&global_bh_lock)) break; /* Duh, we have to loop. Release the lock to avoid deadlocks */ @@ -290,13 +292,13 @@ count = ~0; } __sti(); - SYNC_OTHER_CORES(cpu); + SYNC_OTHER_CORES(smp_processor_id()); __cli(); if (irqs_running()) continue; if (global_irq_lock) continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) + if (!local_bh_count() && spin_is_locked(&global_bh_lock)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -320,28 +322,28 @@ } } -static inline void get_irqlock(int cpu) +static inline void get_irqlock(void) { if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ - if (cpu == global_irq_holder) + if (smp_processor_id() == global_irq_holder) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { do { } while (test_bit(0,&global_irq_lock)); - } while (test_and_set_bit(0,&global_irq_lock)); + } while (test_and_set_bit(0,&global_irq_lock)); } - /* + /* * We also to make sure that nobody else is running - * in an interrupt context. + * in an interrupt context. */ - wait_on_irq(cpu); + wait_on_irq(); /* * Ok, finally.. */ - global_irq_holder = cpu; + global_irq_holder = smp_processor_id(); } #define EFLAGS_IF_SHIFT 9 @@ -365,28 +367,24 @@ #ifdef __ia64__ __save_flags(flags); if (flags & IA64_PSR_I) { - int cpu = smp_processor_id(); __cli(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); + if (!local_irq_count()) + get_irqlock(); } #else __save_flags(flags); if (flags & (1 << EFLAGS_IF_SHIFT)) { - int cpu = smp_processor_id(); __cli(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); + if (!local_irq_count()) + get_irqlock(); } #endif } void __global_sti(void) { - int cpu = smp_processor_id(); - - if (!local_irq_count(cpu)) - release_irqlock(cpu); + if (!local_irq_count()) + release_irqlock(smp_processor_id()); __sti(); } @@ -414,7 +412,7 @@ retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!local_irq_count(cpu)) { + if (!local_irq_count()) { if (local_enabled) retval = 1; if (global_irq_holder == cpu) @@ -456,9 +454,8 @@ 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); + local_irq_enter(irq); status = 1; /* Force the "do bottom halves" bit */ @@ -474,7 +471,7 @@ add_interrupt_randomness(irq); __cli(); - irq_exit(cpu, irq); + local_irq_exit(irq); return status; } @@ -483,11 +480,11 @@ * 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. + * controller lock. */ void inline disable_irq_nosync(unsigned int irq) { - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); unsigned long flags; spin_lock_irqsave(&desc->lock, flags); @@ -507,17 +504,17 @@ disable_irq_nosync(irq); #ifdef CONFIG_SMP - if (!local_irq_count(smp_processor_id())) { + if (!local_irq_count()) { do { barrier(); - } while (irq_desc[irq].status & IRQ_INPROGRESS); + } while (irq_desc(irq)->status & IRQ_INPROGRESS); } #endif } void enable_irq(unsigned int irq) { - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); unsigned long flags; spin_lock_irqsave(&desc->lock, flags); @@ -541,26 +538,14 @@ spin_unlock_irqrestore(&desc->lock, flags); } -void do_IRQ_per_cpu(unsigned long irq, struct pt_regs *regs) -{ - irq_desc_t *desc = irq_desc + irq; - int cpu = smp_processor_id(); - - kstat.irqs[cpu][irq]++; - - desc->handler->ack(irq); - handle_IRQ_event(irq, regs, desc->action); - desc->handler->end(irq); -} - /* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ unsigned int do_IRQ(unsigned long irq, 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 @@ -571,75 +556,82 @@ * handled by some other CPU. (or is disabled) */ int cpu = smp_processor_id(); - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); struct irqaction * action; unsigned int status; kstat.irqs[cpu][irq]++; - spin_lock(&desc->lock); - desc->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; + if (desc->status & IRQ_PER_CPU) { + /* no locking required for CPU-local interrupts: */ + desc->handler->ack(irq); + handle_IRQ_event(irq, regs, desc->action); + desc->handler->end(irq); + } else { + spin_lock(&desc->lock); + desc->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 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) - goto out; + /* + * 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; - /* - * 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 (;;) { + /* + * 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) + goto out; + + /* + * 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 (;;) { + spin_unlock(&desc->lock); + handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); spin_unlock(&desc->lock); - handle_IRQ_event(irq, regs, action); - spin_lock(&desc->lock); - - if (!(desc->status & IRQ_PENDING)) - break; - desc->status &= ~IRQ_PENDING; } - desc->status &= ~IRQ_INPROGRESS; -out: - /* - * The ->end() handler has to deal with interrupts which got - * disabled while the handler was running. - */ - desc->handler->end(irq); - spin_unlock(&desc->lock); - return 1; } -int request_irq(unsigned int irq, +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, + unsigned long irqflags, const char * devname, void *dev_id) { @@ -655,7 +647,7 @@ */ if (irqflags & SA_SHIRQ) { if (!dev_id) - printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + printk("Bad boy: %s called us without a dev_id!\n", devname); } #endif @@ -681,7 +673,7 @@ kfree(action); return retval; } - + void free_irq(unsigned int irq, void *dev_id) { irq_desc_t *desc; @@ -691,7 +683,7 @@ if (irq >= NR_IRQS) return; - desc = irq_desc + irq; + desc = irq_desc(irq); spin_lock_irqsave(&desc->lock,flags); p = &desc->action; for (;;) { @@ -739,16 +731,16 @@ unsigned long val; unsigned long delay; - /* + /* * something may have generated an irq long ago and we want to - * flush such a longstanding irq before considering it as spurious. + * flush such a longstanding irq before considering it as spurious. */ for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_desc + i; + desc = irq_desc(i); spin_lock_irq(&desc->lock); - if (!irq_desc[i].action) - irq_desc[i].handler->startup(i); + if (!desc->action) + desc->handler->startup(i); spin_unlock_irq(&desc->lock); } @@ -762,7 +754,7 @@ * happened in the previous stage, it may have masked itself) */ for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_desc + i; + desc = irq_desc(i); spin_lock_irq(&desc->lock); if (!desc->action) { @@ -784,7 +776,7 @@ */ val = 0; for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_desc + i; + irq_desc_t *desc = irq_desc(i); unsigned int status; spin_lock_irq(&desc->lock); @@ -816,7 +808,7 @@ mask = 0; for (i = 0; i < 16; i++) { - irq_desc_t *desc = irq_desc + i; + irq_desc_t *desc = irq_desc(i); unsigned int status; spin_lock_irq(&desc->lock); @@ -846,7 +838,7 @@ nr_irqs = 0; irq_found = 0; for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_desc + i; + irq_desc_t *desc = irq_desc(i); unsigned int status; spin_lock_irq(&desc->lock); @@ -869,13 +861,12 @@ return irq_found; } -/* this was setup_x86_irq but it seems pretty generic */ int setup_irq(unsigned int irq, struct irqaction * new) { int shared = 0; unsigned long flags; struct irqaction *old, **p; - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = irq_desc(irq); /* * Some drivers like serial.c use request_irq() heavily, @@ -986,7 +977,7 @@ int irq = (long) data, full_count = count, err; unsigned long new_value; - if (!irq_desc[irq].handler->set_affinity) + if (!irq_desc(irq)->handler->set_affinity) return -EIO; err = parse_hex_value(buffer, count, &new_value); @@ -1002,7 +993,7 @@ #endif irq_affinity[irq] = new_value; - irq_desc[irq].handler->set_affinity(irq, new_value); + irq_desc(irq)->handler->set_affinity(irq, new_value); return full_count; } @@ -1037,7 +1028,7 @@ struct proc_dir_entry *entry; char name [MAX_NAMELEN]; - if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type)) + if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type)) return; memset(name, 0, MAX_NAMELEN); @@ -1079,9 +1070,8 @@ * Create entries for all existing IRQs. */ for (i = 0; i < NR_IRQS; i++) { - if (irq_desc[i].handler == &no_irq_type) + if (irq_desc(i)->handler == &no_irq_type) continue; register_irq_proc(i); } } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/irq_ia64.c linux.ac/arch/ia64/kernel/irq_ia64.c --- linux.vanilla/arch/ia64/kernel/irq_ia64.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/ia64/kernel/irq_ia64.c Tue Apr 10 18:08:40 2001 @@ -39,7 +39,7 @@ #define IRQ_DEBUG 0 /* default base addr of IPI table */ -unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IPI_DEFAULT_BASE_ADDR); +unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR); /* * Legacy IRQ to IA-64 vector translation table. @@ -53,21 +53,23 @@ int ia64_alloc_irq (void) { - static int next_irq = FIRST_DEVICE_IRQ; + static int next_irq = IA64_FIRST_DEVICE_VECTOR; - if (next_irq > LAST_DEVICE_IRQ) + if (next_irq > IA64_LAST_DEVICE_VECTOR) /* XXX could look for sharable vectors instead of panic'ing... */ panic("ia64_alloc_irq: out of interrupt vectors!"); return next_irq++; } +extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs); + /* * That's where the IVT branches when we get an external * interrupt. This branches to the correct hardware IRQ handler via * function ptr. */ void -ia64_handle_irq (unsigned long vector, struct pt_regs *regs) +ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) { unsigned long saved_tpr; @@ -89,7 +91,7 @@ static unsigned char count; static long last_time; - if (count > 5 && jiffies - last_time > 5*HZ) + if (jiffies - last_time > 5*HZ) count = 0; if (++count < 5) { last_time = jiffies; @@ -109,19 +111,10 @@ saved_tpr = ia64_get_tpr(); ia64_srlz_d(); do { - if (vector >= NR_IRQS) { - printk("handle_irq: invalid vector %lu\n", vector); - ia64_set_tpr(saved_tpr); - ia64_srlz_d(); - return; - } ia64_set_tpr(vector); ia64_srlz_d(); - if ((irq_desc[vector].status & IRQ_PER_CPU) != 0) - do_IRQ_per_cpu(vector, regs); - else - do_IRQ(vector, regs); + do_IRQ(local_vector_to_irq(vector), regs); /* * Disable interrupts and send EOI: @@ -130,7 +123,7 @@ ia64_set_tpr(saved_tpr); ia64_eoi(); vector = ia64_get_ivr(); - } while (vector != IA64_SPURIOUS_INT); + } while (vector != IA64_SPURIOUS_INT_VECTOR); } #ifdef CONFIG_SMP @@ -144,33 +137,30 @@ }; #endif +void +register_percpu_irq (ia64_vector vec, struct irqaction *action) +{ + irq_desc_t *desc; + unsigned int irq; + + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == vec) { + desc = irq_desc(irq); + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_ia64_sapic; + if (action) + setup_irq(irq, action); + } +} + void __init init_IRQ (void) { - /* - * Disable all local interrupts - */ - ia64_set_itv(0, 1); - ia64_set_lrr0(0, 1); - ia64_set_lrr1(0, 1); - - irq_desc[IA64_SPURIOUS_INT].handler = &irq_type_ia64_sapic; + register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL); #ifdef CONFIG_SMP - /* - * Configure the IPI vector and handler - */ - irq_desc[IPI_IRQ].status |= IRQ_PER_CPU; - irq_desc[IPI_IRQ].handler = &irq_type_ia64_sapic; - setup_irq(IPI_IRQ, &ipi_irqaction); + register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction); #endif - - ia64_set_pmv(1 << 16); - ia64_set_cmcv(CMC_IRQ); /* XXX fix me */ - platform_irq_init(); - - /* clear TPR to enable all interrupt classes: */ - ia64_set_tpr(0); } void diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/ivt.S linux.ac/arch/ia64/kernel/ivt.S --- linux.vanilla/arch/ia64/kernel/ivt.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/ivt.S Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* * arch/ia64/kernel/ivt.S * - * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998, 1999 Stephane Eranian - * Copyright (C) 1998-2000 David Mosberger + * Copyright (C) 1998-2001 David Mosberger * * 00/08/23 Asit Mallick TLB handling for SMP * 00/12/20 David Mosberger-Tang DTLB/ITLB handler now uses virtual PT. @@ -14,7 +14,7 @@ * * External interrupts only use 1 entry. All others are internal interrupts * - * The first 20 entries of the table contain 64 bundles each while the + * The first 20 entries of the table contain 64 bundles each while the * remaining 48 entries contain only 16 bundles each. * * The 64 bundles are used to allow inlining the whole handler for critical @@ -22,7 +22,7 @@ * * For each entry, the comment is as follows: * - * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) + * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) * entry offset ----/ / / / / * entry number ---------/ / / / * size of the entry -------------/ / / @@ -37,7 +37,9 @@ #include +#include #include +#include #include #include #include @@ -45,6 +47,22 @@ #include #include +#if 1 +# define PSR_DEFAULT_BITS psr.ac +#else +# define PSR_DEFAULT_BITS 0 +#endif + +#if 0 + /* + * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't + * needed for something else before enabling this... + */ +# define DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16 +#else +# define DBG_FAULT(i) +#endif + #define MINSTATE_VIRT /* needed by minstate.h */ #include "minstate.h" @@ -57,8 +75,8 @@ * As we don't (hopefully) use the space available, we need to fill it with * nops. the parameter may be used for debugging and is representing the entry * number - */ -#define BREAK_BUNDLE(a) break.m (a); \ + */ +#define BREAK_BUNDLE(a) break.m (a); \ break.i (a); \ break.i (a) /* @@ -71,17 +89,15 @@ */ #define BREAK_BUNDLE8(a); BREAK_BUNDLE4(a); BREAK_BUNDLE4(a) - .psr abi64 - .psr lsb - .lsb - - .section __ivt_section,"ax" + .section .text.ivt,"ax" .align 32768 // align on 32KB boundary .global ia64_ivt ia64_ivt: ///////////////////////////////////////////////////////////////////////////////////////// // 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) +ENTRY(vhpt_miss) + DBG_FAULT(0) /* * The VHPT vector is invoked when the TLB entry for the virtual page table * is missing. This happens only as a result of a previous @@ -103,7 +119,7 @@ ;; rsm psr.dt // use physical addressing for data mov r31=pr // save the predicate registers - mov r19=ar.k7 // get page table base address + mov r19=IA64_KR(PT_BASE) // get page table base address shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 ;; @@ -146,19 +162,21 @@ (p6) br.spnt.many page_fault // handle bad address/page not present (page fault) mov cr.ifa=r22 - // Now compute and insert the TLB entry for the virtual page table. - // We never execute in a page table page so there is no need to set - // the exception deferral bit. + /* + * Now compute and insert the TLB entry for the virtual page table. We never + * execute in a page table page so there is no need to set the exception deferral + * bit. + */ adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23 ;; (p7) itc.d r24 ;; #ifdef CONFIG_SMP - // - // Re-check L2 and L3 pagetable. If they changed, we may have received - // a ptc.g between reading the pagetable and the "itc". If so, - // flush the entry we inserted and retry. - // + /* + * Re-check L2 and L3 pagetable. If they changed, we may have received a ptc.g + * between reading the pagetable and the "itc". If so, flush the entry we + * inserted and retry. + */ ld8 r25=[r21] // read L3 PTE again ld8 r26=[r17] // read L2 entry again ;; @@ -173,26 +191,29 @@ mov pr=r31,-1 // restore predicate registers rfi - ;; +END(vhpt_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x0400 Entry 1 (size 64 bundles) ITLB (21) +ENTRY(itlb_miss) + DBG_FAULT(1) /* * The ITLB handler accesses the L3 PTE via the virtually mapped linear * page table. If a nested TLB miss occurs, we switch into physical * mode, walk the page table, and then re-execute the L3 PTE read * and go on normally after that. */ -itlb_fault: mov r16=cr.ifa // get virtual address mov r29=b0 // save b0 mov r31=pr // save predicates +itlb_fault: mov r17=cr.iha // get virtual address of L3 PTE movl r30=1f // load nested fault continuation point ;; 1: ld8 r18=[r17] // read L3 PTE ;; + mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.cond.spnt.many page_fault ;; @@ -208,26 +229,29 @@ #endif mov pr=r31,-1 rfi - ;; +END(itlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) +ENTRY(dtlb_miss) + DBG_FAULT(2) /* * The DTLB handler accesses the L3 PTE via the virtually mapped linear * page table. If a nested TLB miss occurs, we switch into physical * mode, walk the page table, and then re-execute the L3 PTE read * and go on normally after that. */ -dtlb_fault: mov r16=cr.ifa // get virtual address mov r29=b0 // save b0 mov r31=pr // save predicates +dtlb_fault: mov r17=cr.iha // get virtual address of L3 PTE movl r30=1f // load nested fault continuation point ;; 1: ld8 r18=[r17] // read L3 PTE ;; + mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.cond.spnt.many page_fault ;; @@ -243,24 +267,27 @@ #endif mov pr=r31,-1 rfi - ;; +END(dtlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) +ENTRY(alt_itlb_miss) + DBG_FAULT(3) mov r16=cr.ifa // get address that caused the TLB miss - movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX + movl r17=PAGE_KERNEL mov r21=cr.ipsr mov r31=pr ;; #ifdef CONFIG_DISABLE_VHPT shr.u r22=r16,61 // get the region number into r21 ;; - cmp.gt p8,p0=6,r22 // user mode + cmp.gt p8,p0=6,r22 // user mode ;; (p8) thash r17=r16 ;; (p8) mov cr.iha=r17 +(p8) mov r29=b0 // save b0 (p8) br.cond.dptk.many itlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl @@ -277,13 +304,15 @@ itc.i r19 // insert the TLB entry mov pr=r31,-1 rfi - ;; +END(alt_itlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) +ENTRY(alt_dtlb_miss) + DBG_FAULT(4) mov r16=cr.ifa // get address that caused the TLB miss - movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX + movl r17=PAGE_KERNEL mov r20=cr.isr mov r21=cr.ipsr mov r31=pr @@ -296,6 +325,7 @@ (p8) thash r17=r16 ;; (p8) mov cr.iha=r17 +(p8) mov r29=b0 // save b0 (p8) br.cond.dptk.many dtlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl @@ -316,70 +346,63 @@ (p7) itc.d r19 // insert the TLB entry mov pr=r31,-1 rfi - ;; +END(alt_dtlb_miss) //----------------------------------------------------------------------------------- // call do_page_fault (predicates are in r31, psr.dt may be off, r16 is faulting address) -page_fault: +ENTRY(page_fault) ssm psr.dt ;; srlz.i ;; SAVE_MIN_WITH_COVER - // - // Copy control registers to temporary registers, then turn on psr bits, - // then copy the temporary regs to the output regs. We have to do this - // because the "alloc" can cause a mandatory store which could lead to - // an "Alt DTLB" fault which we can handle only if psr.ic is on. - // - mov r8=cr.ifa - mov r9=cr.isr + alloc r15=ar.pfs,0,0,3,0 + mov out0=cr.ifa + mov out1=cr.isr adds r3=8,r2 // set up second base pointer ;; - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; (p15) ssm psr.i // restore psr.i movl r14=ia64_leave_kernel ;; - alloc r15=ar.pfs,0,0,3,0 // must be first in insn group - mov out0=r8 - mov out1=r9 - ;; SAVE_REST mov rp=r14 ;; adds out2=16,r12 // out2 = pointer to pt_regs br.call.sptk.many b6=ia64_do_page_fault // ignore return address - ;; +END(page_fault) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) - // - // In the absence of kernel bugs, we get here when the virtually mapped linear page - // table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction - // Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page - // table is missing, a nested TLB miss fault is triggered and control is transferred - // to this point. When this happens, we lookup the pte for the faulting address - // by walking the page table in physical mode and return to the continuation point - // passed in register r30 (or call page_fault if the address is not mapped). - // - // Input: r16: faulting address - // r29: saved b0 - // r30: continuation address - // r31: saved pr - // - // Output: r17: physical address of L3 PTE of faulting address - // r29: saved b0 - // r30: continuation address - // r31: saved pr - // - // Clobbered: b0, r18, r19, r21, psr.dt (cleared) - // +ENTRY(nested_dtlb_miss) + /* + * In the absence of kernel bugs, we get here when the virtually mapped linear + * page table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction + * Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page + * table is missing, a nested TLB miss fault is triggered and control is + * transferred to this point. When this happens, we lookup the pte for the + * faulting address by walking the page table in physical mode and return to the + * continuation point passed in register r30 (or call page_fault if the address is + * not mapped). + * + * Input: r16: faulting address + * r29: saved b0 + * r30: continuation address + * r31: saved pr + * + * Output: r17: physical address of L3 PTE of faulting address + * r29: saved b0 + * r30: continuation address + * r31: saved pr + * + * Clobbered: b0, r18, r19, r21, psr.dt (cleared) + */ rsm psr.dt // switch to using physical data addressing - mov r19=ar.k7 // get the page table base address + mov r19=IA64_KR(PT_BASE) // get the page table base address shl r21=r16,3 // shift bit 60 into sign bit ;; shr.u r17=r16,61 // get the region number into r17 @@ -399,7 +422,6 @@ shr.u r18=r16,PMD_SHIFT // shift L2 index into position ;; ld8 r17=[r17] // fetch the L1 entry (may be 0) - mov b0=r30 ;; (p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry @@ -409,34 +431,41 @@ ;; (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry - ;; (p6) br.cond.spnt.many page_fault + mov b0=r30 br.sptk.many b0 // return to continuation point - ;; +END(nested_dtlb_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) +ENTRY(ikey_miss) + DBG_FAULT(6) FAULT(6) +END(ikey_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) +ENTRY(dkey_miss) + DBG_FAULT(7) FAULT(7) +END(dkey_miss) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) - // - // What we do here is to simply turn on the dirty bit in the PTE. We need - // to update both the page-table and the TLB entry. To efficiently access - // the PTE, we address it through the virtual page table. Most likely, the - // TLB entry for the relevant virtual page table page is still present in - // the TLB so we can normally do this without additional TLB misses. - // In case the necessary virtual page table TLB entry isn't present, we take - // a nested TLB miss hit where we look up the physical address of the L3 PTE - // and then continue at label 1 below. - // +ENTRY(dirty_bit) + DBG_FAULT(8) + /* + * What we do here is to simply turn on the dirty bit in the PTE. We need to + * update both the page-table and the TLB entry. To efficiently access the PTE, + * we address it through the virtual page table. Most likely, the TLB entry for + * the relevant virtual page table page is still present in the TLB so we can + * normally do this without additional TLB misses. In case the necessary virtual + * page table TLB entry isn't present, we take a nested TLB miss hit where we look + * up the physical address of the L3 PTE and then continue at label 1 below. + */ mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault ;; @@ -477,11 +506,13 @@ #endif mov pr=r31,-1 // restore pr rfi - ;; +END(idirty_bit) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) +ENTRY(iaccess_bit) + DBG_FAULT(9) // Like Entry 8, except for instruction access mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault @@ -504,14 +535,14 @@ mov r28=ar.ccv // save ar.ccv ;; 1: ld8 r18=[r17] + ;; # if defined(CONFIG_IA32_SUPPORT) && \ (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) - // - // Erratum 85 (Access bit fault could be reported before page not present fault) - // If the PTE is indicates the page is not present, then just turn this into a - // page fault. - // - ;; + /* + * Erratum 85 (Access bit fault could be reported before page not present fault) + * If the PTE is indicates the page is not present, then just turn this into a + * page fault. + */ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.sptk page_fault // page wasn't present # endif @@ -538,11 +569,11 @@ ;; # if defined(CONFIG_IA32_SUPPORT) && \ (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) - // - // Erratum 85 (Access bit fault could be reported before page not present fault) - // If the PTE is indicates the page is not present, then just turn this into a - // page fault. - // + /* + * Erratum 85 (Access bit fault could be reported before page not present fault) + * If the PTE is indicates the page is not present, then just turn this into a + * page fault. + */ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? (p6) br.sptk page_fault // page wasn't present # endif @@ -554,11 +585,13 @@ #endif /* !CONFIG_SMP */ mov pr=r31,-1 rfi - ;; +END(iaccess_bit) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) +ENTRY(daccess_bit) + DBG_FAULT(10) // Like Entry 8, except for data access mov r16=cr.ifa // get the address that caused the fault movl r30=1f // load continuation point in case of nested fault @@ -599,11 +632,13 @@ mov b0=r29 // restore b0 mov pr=r31,-1 rfi - ;; +END(daccess_bit) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) +ENTRY(break_fault) + DBG_FAULT(11) mov r16=cr.iim mov r17=__IA64_BREAK_SYSCALL mov r31=pr // prepare to save predicates @@ -613,8 +648,7 @@ SAVE_MIN // uses r31; defines r2: - // turn interrupt collection back on: - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 @@ -667,12 +701,12 @@ ;; st8 [r16]=r18 // store new value for cr.isr -(p8) br.call.sptk.many b6=b6 // ignore this return addr +(p8) br.call.sptk.many b6=b6 // ignore this return addr br.call.sptk.many rp=ia64_trace_syscall // rp will be overwritten (ignored) // NOT REACHED +END(break_fault) - .proc demine_args -demine_args: +ENTRY(demine_args) alloc r2=ar.pfs,8,0,0,0 tnat.nz p8,p0=in0 tnat.nz p9,p0=in1 @@ -696,16 +730,18 @@ (p14) mov in6=-1 (p15) mov in7=-1 br.ret.sptk.many rp - .endp demine_args +END(demine_args) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) +ENTRY(interrupt) + DBG_FAULT(12) mov r31=pr // prepare to save predicates ;; SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 - ssm psr.ic // turn interrupt collection + ssm psr.ic | PSR_DEFAULT_BITS ;; adds r3=8,r2 // set up second base pointer for SAVE_REST srlz.i // ensure everybody knows psr.ic is back on @@ -721,41 +757,38 @@ ;; mov rp=r14 br.call.sptk.many b6=ia64_handle_irq - ;; +END(interrupt) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3400 Entry 13 (size 64 bundles) Reserved + DBG_FAULT(13) FAULT(13) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3800 Entry 14 (size 64 bundles) Reserved + DBG_FAULT(14) FAULT(14) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3c00 Entry 15 (size 64 bundles) Reserved + DBG_FAULT(15) FAULT(15) -// -// Squatting in this space ... -// -// This special case dispatcher for illegal operation faults -// allows preserved registers to be modified through a -// callback function (asm only) that is handed back from -// the fault handler in r8. Up to three arguments can be -// passed to the callback function by returning an aggregate -// with the callback as its first element, followed by the -// arguments. -// -dispatch_illegal_op_fault: + /* + * Squatting in this space ... + * + * This special case dispatcher for illegal operation faults allows preserved + * registers to be modified through a callback function (asm only) that is handed + * back from the fault handler in r8. Up to three arguments can be passed to the + * callback function by returning an aggregate with the callback as its first + * element, followed by the arguments. + */ +ENTRY(dispatch_illegal_op_fault) SAVE_MIN_WITH_COVER - // - // The "alloc" can cause a mandatory store which could lead to - // an "Alt DTLB" fault which we can handle only if psr.ic is on. - // - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; @@ -781,27 +814,30 @@ cmp.ne p6,p0=0,r8 (p6) br.call.dpnt b6=b6 // call returns to ia64_leave_kernel br.sptk ia64_leave_kernel - ;; +END(dispatch_illegal_op_fault) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4000 Entry 16 (size 64 bundles) Reserved + DBG_FAULT(16) FAULT(16) #ifdef CONFIG_IA32_SUPPORT - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ // IA32 interrupt entry point -dispatch_to_ia32_handler: +ENTRY(dispatch_to_ia32_handler) SAVE_MIN ;; mov r14=cr.isr - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; @@ -812,7 +848,7 @@ ;; mov r15=0x80 shr r14=r14,16 // Get interrupt number - ;; + ;; cmp.ne p6,p0=r14,r15 (p6) br.call.dpnt.many b6=non_ia32_syscall @@ -823,7 +859,7 @@ st8 [r15]=r8 // save orignal EAX in r1 (IA32 procs don't use the GP) ;; alloc r15=ar.pfs,0,0,6,0 // must first in an insn group - ;; + ;; ld4 r8=[r14],8 // r8 == EAX (syscall number) mov r15=222 // sys_vfork - last implemented system call ;; @@ -842,10 +878,10 @@ ;; ld4 out4=[r14] // R15 == edi movl r16=ia32_syscall_table - ;; + ;; (p6) shladd r16=r8,3,r16 // Force ni_syscall if not valid syscall number ld8 r2=[r2] // r2 = current->ptrace - ;; + ;; ld8 r16=[r16] tbit.z p8,p0=r2,PT_TRACESYS_BIT // (current->ptrace & PT_TRACESYS) == 0? ;; @@ -857,7 +893,7 @@ ;; br.call.sptk.many rp=ia32_trace_syscall // rp will be overwritten (ignored) -non_ia32_syscall: +non_ia32_syscall: alloc r15=ar.pfs,0,0,2,0 mov out0=r14 // interrupt # add out1=16,sp // pointer to pt_regs @@ -867,16 +903,17 @@ ;; mov rp=r15 br.ret.sptk.many rp - ;; +END(dispatch_to_ia32_handler) #endif /* CONFIG_IA32_SUPPORT */ .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4400 Entry 17 (size 64 bundles) Reserved + DBG_FAULT(17) FAULT(17) -non_syscall: +ENTRY(non_syscall) SAVE_MIN_WITH_COVER // There is no particular reason for this code to be here, other than that @@ -884,49 +921,45 @@ // fault ever gets "unreserved", simply moved the following code to a more // suitable spot... - mov r8=cr.iim // get break immediate (must be done while psr.ic is off) + alloc r14=ar.pfs,0,0,2,0 + mov out0=cr.iim + add out1=16,sp adds r3=8,r2 // set up second base pointer for SAVE_REST - // turn interrupt collection back on: - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; (p15) ssm psr.i // restore psr.i movl r15=ia64_leave_kernel ;; - alloc r14=ar.pfs,0,0,2,0 - mov out0=r8 // break number - add out1=16,sp // pointer to pt_regs - ;; SAVE_REST mov rp=r15 ;; br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr - ;; +END(non_syscall) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4800 Entry 18 (size 64 bundles) Reserved + DBG_FAULT(18) FAULT(18) - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ -dispatch_unaligned_handler: +ENTRY(dispatch_unaligned_handler) SAVE_MIN_WITH_COVER ;; - // - // we can't have the alloc while psr.ic is cleared because - // we might get a mandatory RSE (when you reach the end of the - // rotating partition when doing the alloc) spill which could cause - // a page fault on the kernel virtual address and the handler - // wouldn't get the state to recover. - // - mov r15=cr.ifa - ssm psr.ic + alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) + mov out0=cr.ifa + adds out1=16,sp + + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; @@ -934,66 +967,53 @@ adds r3=8,r2 // set up second base pointer ;; SAVE_REST - ;; - alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) - ;; // avoid WAW on r14 movl r14=ia64_leave_kernel - mov out0=r15 // out0 = faulting address - adds out1=16,sp // out1 = pointer to pt_regs ;; mov rp=r14 br.sptk.many ia64_prepare_handle_unaligned - ;; +END(dispatch_unaligned_handler) .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4c00 Entry 19 (size 64 bundles) Reserved + DBG_FAULT(19) FAULT(19) - // There is no particular reason for this code to be here, other than that - // there happens to be space here that would go unused otherwise. If this - // fault ever gets "unreserved", simply moved the following code to a more - // suitable spot... + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ -dispatch_to_fault_handler: - // - // Input: - // psr.ic: off - // r19: fault vector number (e.g., 24 for General Exception) - // r31: contains saved predicates (pr) - // +ENTRY(dispatch_to_fault_handler) + /* + * Input: + * psr.ic: off + * r19: fault vector number (e.g., 24 for General Exception) + * r31: contains saved predicates (pr) + */ SAVE_MIN_WITH_COVER_R19 - // - // Copy control registers to temporary registers, then turn on psr bits, - // then copy the temporary regs to the output regs. We have to do this - // because the "alloc" can cause a mandatory store which could lead to - // an "Alt DTLB" fault which we can handle only if psr.ic is on. - // - mov r8=cr.isr - mov r9=cr.ifa - mov r10=cr.iim - mov r11=cr.itir + alloc r14=ar.pfs,0,0,5,0 + mov out0=r15 + mov out1=cr.isr + mov out2=cr.ifa + mov out3=cr.iim + mov out4=cr.itir ;; - ssm psr.ic + ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interrupt collection is enabled ;; (p15) ssm psr.i // restore psr.i adds r3=8,r2 // set up second base pointer for SAVE_REST ;; - alloc r14=ar.pfs,0,0,5,0 // must be first in insn group - mov out0=r15 - mov out1=r8 - mov out2=r9 - mov out3=r10 - mov out4=r11 - ;; SAVE_REST movl r14=ia64_leave_kernel ;; mov rp=r14 br.call.sptk.many b6=ia64_fault - ;; +END(dispatch_to_fault_handler) // // --- End of long entries, Beginning of short entries @@ -1002,55 +1022,67 @@ .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) +ENTRY(page_not_present) + DBG_FAULT(20) mov r16=cr.ifa rsm psr.dt - // The Linux page fault handler doesn't expect non-present pages to be in - // the TLB. Flush the existing entry now, so we meet that expectation. - mov r17=_PAGE_SIZE_4K<<2 + /* + * The Linux page fault handler doesn't expect non-present pages to be in + * the TLB. Flush the existing entry now, so we meet that expectation. + */ + mov r17=PAGE_SHIFT<<2 ;; ptc.l r16,r17 ;; mov r31=pr srlz.d br.sptk.many page_fault - ;; +END(page_not_present) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52) +ENTRY(key_permission) + DBG_FAULT(21) mov r16=cr.ifa rsm psr.dt mov r31=pr ;; srlz.d br.sptk.many page_fault - ;; +END(key_permission) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) +ENTRY(iaccess_rights) + DBG_FAULT(22) mov r16=cr.ifa rsm psr.dt mov r31=pr ;; srlz.d br.sptk.many page_fault - ;; +END(iaccess_rights) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) +ENTRY(daccess_rights) + DBG_FAULT(23) mov r16=cr.ifa rsm psr.dt mov r31=pr ;; srlz.d br.sptk.many page_fault - ;; +END(daccess_rights) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) +ENTRY(general_exception) + DBG_FAULT(24) mov r16=cr.isr mov r31=pr ;; @@ -1059,39 +1091,44 @@ ;; mov r19=24 // fault number br.sptk.many dispatch_to_fault_handler - ;; +END(general_exception) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) +ENTRY(disabled_fp_reg) + DBG_FAULT(25) rsm psr.dfh // ensure we can access fph ;; srlz.d mov r31=pr mov r19=25 br.sptk.many dispatch_to_fault_handler - ;; +END(disabled_fp_reg) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) +ENTRY(nat_consumption) + DBG_FAULT(26) FAULT(26) +END(nat_consumption) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5700 Entry 27 (size 16 bundles) Speculation (40) - // - // A [f]chk.[as] instruction needs to take the branch to - // the recovery code but this part of the architecture is - // not implemented in hardware on some CPUs, such as Itanium. - // Thus, in general we need to emulate the behavior. - // IIM contains the relative target (not yet sign extended). - // So after sign extending it we simply add it to IIP. - // We also need to reset the EI field of the IPSR to zero, - // i.e., the slot to restart into. - // - // cr.imm contains zero_ext(imm21) - // +ENTRY(speculation_vector) + DBG_FAULT(27) + /* + * A [f]chk.[as] instruction needs to take the branch to the recovery code but + * this part of the architecture is not implemented in hardware on some CPUs, such + * as Itanium. Thus, in general we need to emulate the behavior. IIM contains + * the relative target (not yet sign extended). So after sign extending it we + * simply add it to IIP. We also need to reset the EI field of the IPSR to zero, + * i.e., the slot to restart into. + * + * cr.imm contains zero_ext(imm21) + */ mov r18=cr.iim ;; mov r17=cr.iip @@ -1112,105 +1149,130 @@ ;; rfi // and go back - ;; +END(speculation_vector) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5800 Entry 28 (size 16 bundles) Reserved + DBG_FAULT(28) FAULT(28) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) +ENTRY(debug_vector) + DBG_FAULT(29) FAULT(29) +END(debug_vector) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) +ENTRY(unaligned_access) + DBG_FAULT(30) mov r16=cr.ipsr mov r31=pr // prepare to save predicates - ;; - br.sptk.many dispatch_unaligned_handler ;; + br.sptk.many dispatch_unaligned_handler +END(unaligned_access) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) + DBG_FAULT(31) FAULT(31) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) + DBG_FAULT(32) FAULT(32) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) + DBG_FAULT(33) FAULT(33) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Tranfer Trap (66) + DBG_FAULT(34) FAULT(34) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) + DBG_FAULT(35) FAULT(35) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) + DBG_FAULT(36) FAULT(36) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6100 Entry 37 (size 16 bundles) Reserved + DBG_FAULT(37) FAULT(37) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6200 Entry 38 (size 16 bundles) Reserved + DBG_FAULT(38) FAULT(38) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6300 Entry 39 (size 16 bundles) Reserved + DBG_FAULT(39) FAULT(39) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6400 Entry 40 (size 16 bundles) Reserved + DBG_FAULT(40) FAULT(40) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6500 Entry 41 (size 16 bundles) Reserved + DBG_FAULT(41) FAULT(41) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6600 Entry 42 (size 16 bundles) Reserved + DBG_FAULT(42) FAULT(42) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6700 Entry 43 (size 16 bundles) Reserved + DBG_FAULT(43) FAULT(43) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6800 Entry 44 (size 16 bundles) Reserved + DBG_FAULT(44) FAULT(44) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) +ENTRY(ia32_exception) + DBG_FAULT(45) FAULT(45) +END(ia32_exception) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) +ENTRY(ia32_intercept) + DBG_FAULT(46) #ifdef CONFIG_IA32_SUPPORT mov r31=pr mov r16=cr.isr @@ -1219,129 +1281,152 @@ mov r18=ar.eflag mov r19=cr.iim // old eflag value ;; - cmp.ne p2,p0=2,r17 -(p2) br.cond.spnt 1f // not a system flag fault + cmp.ne p6,p0=2,r17 +(p6) br.cond.spnt 1f // not a system flag fault xor r16=r18,r19 ;; extr.u r17=r16,18,1 // get the eflags.ac bit ;; - cmp.eq p2,p0=0,r17 -(p2) br.cond.spnt 1f // eflags.ac bit didn't change + cmp.eq p6,p0=0,r17 +(p6) br.cond.spnt 1f // eflags.ac bit didn't change ;; mov pr=r31,-1 // restore predicate registers rfi - ;; + 1: #endif // CONFIG_IA32_SUPPORT FAULT(46) +END(ia32_intercept) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) +ENTRY(ia32_interrupt) + DBG_FAULT(47) #ifdef CONFIG_IA32_SUPPORT mov r31=pr br.sptk.many dispatch_to_ia32_handler - ;; #else FAULT(47) #endif +END(ia32_interrupt) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6c00 Entry 48 (size 16 bundles) Reserved + DBG_FAULT(48) FAULT(48) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6d00 Entry 49 (size 16 bundles) Reserved + DBG_FAULT(49) FAULT(49) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6e00 Entry 50 (size 16 bundles) Reserved + DBG_FAULT(50) FAULT(50) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6f00 Entry 51 (size 16 bundles) Reserved + DBG_FAULT(51) FAULT(51) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7000 Entry 52 (size 16 bundles) Reserved + DBG_FAULT(52) FAULT(52) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7100 Entry 53 (size 16 bundles) Reserved + DBG_FAULT(53) FAULT(53) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7200 Entry 54 (size 16 bundles) Reserved + DBG_FAULT(54) FAULT(54) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7300 Entry 55 (size 16 bundles) Reserved + DBG_FAULT(55) FAULT(55) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7400 Entry 56 (size 16 bundles) Reserved + DBG_FAULT(56) FAULT(56) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7500 Entry 57 (size 16 bundles) Reserved + DBG_FAULT(57) FAULT(57) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7600 Entry 58 (size 16 bundles) Reserved + DBG_FAULT(58) FAULT(58) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7700 Entry 59 (size 16 bundles) Reserved + DBG_FAULT(59) FAULT(59) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7800 Entry 60 (size 16 bundles) Reserved + DBG_FAULT(60) FAULT(60) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7900 Entry 61 (size 16 bundles) Reserved + DBG_FAULT(61) FAULT(61) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7a00 Entry 62 (size 16 bundles) Reserved + DBG_FAULT(62) FAULT(62) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7b00 Entry 63 (size 16 bundles) Reserved + DBG_FAULT(63) FAULT(63) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7c00 Entry 64 (size 16 bundles) Reserved + DBG_FAULT(64) FAULT(64) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7d00 Entry 65 (size 16 bundles) Reserved + DBG_FAULT(65) FAULT(65) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7e00 Entry 66 (size 16 bundles) Reserved + DBG_FAULT(66) FAULT(66) .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x7f00 Entry 67 (size 16 bundles) Reserved + DBG_FAULT(67) FAULT(67) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/mca.c linux.ac/arch/ia64/kernel/mca.c --- linux.vanilla/arch/ia64/kernel/mca.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/mca.c Sat Apr 14 01:18:00 2001 @@ -1,16 +1,16 @@ /* - * File: mca.c - * Purpose: Generic MCA handling layer + * File: mca.c + * Purpose: Generic MCA handling layer * * Updated for latest kernel * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) - * + * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * - * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, - * added min save state dump, added INIT handler. + * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, + * added min save state dump, added INIT handler. */ #include #include @@ -28,7 +28,7 @@ #include - + typedef struct ia64_fptr { unsigned long fp; unsigned long gp; @@ -43,8 +43,8 @@ u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); -static void ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector); +static void ia64_mca_cmc_vector_setup(int enable, + int_vector_t cmc_vector); static void ia64_mca_wakeup_ipi_wait(void); static void ia64_mca_wakeup(int cpu); static void ia64_mca_wakeup_all(void); @@ -77,7 +77,7 @@ * console, then we would call the appropriate debug hooks here. */ void -init_handler_platform (struct pt_regs *regs) +init_handler_platform (struct pt_regs *regs) { /* if a kernel debugger is available call it here else just dump the registers */ show_regs(regs); /* dump the state info */ @@ -87,7 +87,7 @@ log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc) { } - + void ia64_mca_init_platform (void) { @@ -131,7 +131,7 @@ tpmss_ptr++; /* skip to next entry */ continue; } - } + } printk("%5s=0x%16.16lx ",min_state_labels[i],*tpmss_ptr++); @@ -142,7 +142,7 @@ /* hang city for now, until we include debugger or copy to ptregs to show: */ while (1); } - + /* * ia64_mca_cmc_vector_setup * Setup the correctable machine check vector register in the processor @@ -154,14 +154,14 @@ * None */ static void -ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector) +ia64_mca_cmc_vector_setup(int enable, + int_vector_t cmc_vector) { cmcv_reg_t cmcv; - cmcv.cmcv_regval = 0; - cmcv.cmcv_mask = enable; - cmcv.cmcv_vector = cmc_vector; + cmcv.cmcv_regval = 0; + cmcv.cmcv_mask = enable; + cmcv.cmcv_vector = cmc_vector; ia64_set_cmcv(cmcv.cmcv_regval); } @@ -223,25 +223,27 @@ for(i = 0 ; i < IA64_MAXCPUS; i++) ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - /* NOTE : The actual irqs for the rendez, wakeup and + /* NOTE : The actual irqs for the rendez, wakeup and * cmc interrupts are requested in the platform-specific * mca initialization code. */ - /* + /* * Register the rendezvous spinloop and wakeup mechanism with SAL */ /* Register the rendezvous interrupt vector with SAL */ if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_RENDEZ_INT_VECTOR, - IA64_MCA_RENDEZ_TIMEOUT)) + IA64_MCA_RENDEZ_VECTOR, + IA64_MCA_RENDEZ_TIMEOUT, + 0)) return; /* Register the wakeup interrupt vector with SAL */ if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_WAKEUP_INT_VECTOR, + IA64_MCA_WAKEUP_VECTOR, + 0, 0)) return; @@ -249,17 +251,16 @@ /* * Setup the correctable machine check vector */ - ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, - IA64_MCA_CMC_INT_VECTOR); + ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, IA64_CMC_VECTOR); IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n"); - ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); + ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); /* * XXX - disable SAL checksum by setting size to 0; should be * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); */ - ia64_mc_info.imi_mca_handler_size = 0; + ia64_mc_info.imi_mca_handler_size = 0; /* Register the os mca handler with SAL */ if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, ia64_mc_info.imi_mca_handler, @@ -271,13 +272,13 @@ IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n"); - /* + /* * XXX - disable SAL checksum by setting size to 0, should be - * IA64_INIT_HANDLER_SIZE + * IA64_INIT_HANDLER_SIZE */ - ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler); @@ -296,7 +297,7 @@ IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n"); - /* Initialize the areas set aside by the OS to buffer the + /* Initialize the areas set aside by the OS to buffer the * platform/processor error states for MCA/INIT/CMC * handling. */ @@ -308,7 +309,7 @@ ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); ia64_mca_init_platform(); - + IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n"); #if defined(MCA_TEST) @@ -321,9 +322,9 @@ /* * ia64_mca_wakeup_ipi_wait * Wait for the inter-cpu interrupt to be sent by the - * monarch processor once it is done with handling the + * monarch processor once it is done with handling the * MCA. - * Inputs + * Inputs * None * Outputs * None @@ -331,8 +332,8 @@ void ia64_mca_wakeup_ipi_wait(void) { - int irr_num = (IA64_MCA_WAKEUP_INT_VECTOR >> 6); - int irr_bit = (IA64_MCA_WAKEUP_INT_VECTOR & 0x3f); + int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); + int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); u64 irr = 0; do { @@ -356,7 +357,7 @@ /* * ia64_mca_wakeup * Send an inter-cpu interrupt to wake-up a particular cpu - * and mark that cpu to be out of rendez. + * and mark that cpu to be out of rendez. * Inputs * cpuid * Outputs @@ -365,9 +366,8 @@ void ia64_mca_wakeup(int cpu) { - platform_send_ipi(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0); + platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - } /* * ia64_mca_wakeup_all @@ -390,10 +390,10 @@ } /* * ia64_mca_rendez_interrupt_handler - * This is handler used to put slave processors into spinloop + * This is handler used to put slave processors into spinloop * while the monarch processor does the mca handling and later * wake each slave up once the monarch is done. - * Inputs + * Inputs * None * Outputs * None @@ -403,7 +403,7 @@ { int flags, cpu = 0; /* Mask all interrupts */ - save_and_cli(flags); + save_and_cli(flags); #ifdef CONFIG_SMP cpu = cpu_logical_id(hard_smp_processor_id()); @@ -414,7 +414,7 @@ */ ia64_sal_mc_rendez(); - /* Wait for the wakeup IPI from the monarch + /* Wait for the wakeup IPI from the monarch * This waiting is done by polling on the wakeup-interrupt * vector bit in the processor's IRRs */ @@ -430,30 +430,30 @@ /* * ia64_mca_wakeup_int_handler * The interrupt handler for processing the inter-cpu interrupt to the - * slave cpu which was spinning in the rendez loop. + * slave cpu which was spinning in the rendez loop. * Since this spinning is done by turning off the interrupts and - * polling on the wakeup-interrupt bit in the IRR, there is + * polling on the wakeup-interrupt bit in the IRR, there is * nothing useful to be done in the handler. * Inputs * wakeup_irq (Wakeup-interrupt bit) * arg (Interrupt handler specific argument) * ptregs (Exception frame at the time of the interrupt) * Outputs - * + * */ void ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) { - + } /* * ia64_return_to_sal_check * This is function called before going back from the OS_MCA handler - * to the OS_MCA dispatch code which finally takes the control back - * to the SAL. + * to the OS_MCA dispatch code which finally takes the control back + * to the SAL. * The main purpose of this routine is to setup the OS_MCA to SAL - * return state which can be used by the OS_MCA dispatch code + * return state which can be used by the OS_MCA dispatch code * just before going back to SAL. * Inputs * None @@ -467,16 +467,16 @@ /* Copy over some relevant stuff from the sal_to_os_mca_handoff * so that it can be used at the time of os_mca_to_sal_handoff */ - ia64_os_to_sal_handoff_state.imots_sal_gp = + ia64_os_to_sal_handoff_state.imots_sal_gp = ia64_sal_to_os_handoff_state.imsto_sal_gp; - ia64_os_to_sal_handoff_state.imots_sal_check_ra = + ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; /* For now ignore the MCA */ ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; } -/* +/* * ia64_mca_ucmc_handler * This is uncorrectable machine check handler called from OS_MCA * dispatch code which is in turn called from SAL_CHECK(). @@ -503,7 +503,7 @@ ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* + /* * Do some error handling - Platform-specific mca handler is called at this point */ @@ -520,11 +520,11 @@ ia64_return_to_sal_check(); } -/* +/* * ia64_mca_cmc_int_handler * This is correctable machine check interrupt handler. * Right now the logs are extracted and displayed in a well-defined - * format. + * format. * Inputs * None * Outputs @@ -532,7 +532,7 @@ */ void ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) -{ +{ /* Get the CMC processor log */ ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); /* Get the CMC platform log */ @@ -543,8 +543,7 @@ cmci_handler_platform(cmc_irq, arg, ptregs); /* Clear the CMC SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); + ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC); } /* @@ -563,17 +562,17 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES]; #define IA64_LOG_LOCK_INIT(it, sit) spin_lock_init(&ia64_state_log[it][sit].isl_lock) -#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s) -#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\ +#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s) +#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\ s) #define IA64_LOG_NEXT_INDEX(it, sit) ia64_state_log[it][sit].isl_index -#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index +#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index #define IA64_LOG_INDEX_INC(it, sit) \ ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index #define IA64_LOG_INDEX_DEC(it, sit) \ ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)])) -#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) +#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)])) +#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) /* * C portion of the OS INIT handler @@ -582,7 +581,7 @@ * * Inputs: pointer to pt_regs where processor info was saved. * - * Returns: + * Returns: * 0 if SAL must warm boot the System * 1 if SAL must retrun to interrupted context using PAL_MC_RESUME * @@ -601,49 +600,48 @@ /* Get the INIT platform log */ ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); -#ifdef IA64_DUMP_ALL_PROC_INFO +#ifdef IA64_DUMP_ALL_PROC_INFO ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); -#endif +#endif - /* + /* * get pointer to min state save area * */ plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); proc_ptr = &plog_ptr->devlog.proclog; - + ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs); init_handler_platform(regs); /* call platform specific routines */ /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM); + ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); } /* * ia64_log_init - * Reset the OS ia64 log buffer - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Reset the OS ia64 log buffer + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * Outputs : None */ void ia64_log_init(int sal_info_type, int sal_sub_info_type) { IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type); IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0; - memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, + memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, sizeof(ia64_psilog_t) * IA64_MAX_LOGS); } -/* +/* * ia64_log_get - * Get the current MCA log from SAL and copy it into the OS log buffer. - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Get the current MCA log from SAL and copy it into the OS log buffer. + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * Outputs : None * */ void @@ -658,7 +656,7 @@ /* Get the process state information */ log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type); - if (!(total_len=ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer))) + if (!(total_len=ia64_sal_get_state_info(sal_info_type,(u64 *)log_buffer))) prfunc("ia64_mca_log_get : Getting processor log failed\n"); IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len); @@ -669,21 +667,21 @@ } -/* +/* * ia64_log_clear - * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags + * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags * clear the OS log buffer also - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * clear_os_buffer + * clear_os_buffer * prfunc (print function) - * Outputs : None + * Outputs : None * */ void ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc) { - if (ia64_sal_clear_state_info(sal_info_type, sal_sub_info_type)) + if (ia64_sal_clear_state_info(sal_info_type)) prfunc("ia64_mca_log_get : Clearing processor log failed\n"); if (clear_os_buffer) { @@ -698,7 +696,7 @@ memset(log_buffer, 0, sizeof(ia64_psilog_t)); IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type); - + IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); } @@ -708,19 +706,19 @@ * ia64_log_processor_regs_print * Print the contents of the saved processor register(s) in the format * [] - * - * Inputs : regs (Register save buffer) - * reg_num (# of registers) + * + * Inputs : regs (Register save buffer) + * reg_num (# of registers) * reg_class (application/banked/control/bank1_general) * reg_prefix (ar/br/cr/b1_gr) - * Outputs : None + * Outputs : None * */ void -ia64_log_processor_regs_print(u64 *regs, - int reg_num, - char *reg_class, - char *reg_prefix, +ia64_log_processor_regs_print(u64 *regs, + int reg_num, + char *reg_class, + char *reg_prefix, prfunc_t prfunc) { int i; @@ -756,14 +754,14 @@ * ia64_log_cache_check_info_print * Display the machine check information related to cache error(s). * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * info (Machine check info logged by the PAL and later * captured by the SAL) * target_addr (Address which caused the cache error) - * Outputs : None + * Outputs : None */ -void -ia64_log_cache_check_info_print(int i, - pal_cache_check_info_t info, +void +ia64_log_cache_check_info_print(int i, + pal_cache_check_info_t info, u64 target_addr, prfunc_t prfunc) { @@ -794,13 +792,13 @@ * ia64_log_tlb_check_info_print * Display the machine check information related to tlb error(s). * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * info (Machine check info logged by the PAL and later * captured by the SAL) - * Outputs : None + * Outputs : None */ void -ia64_log_tlb_check_info_print(int i, +ia64_log_tlb_check_info_print(int i, pal_tlb_check_info_t info, prfunc_t prfunc) { @@ -826,16 +824,16 @@ * ia64_log_bus_check_info_print * Display the machine check information related to bus error(s). * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * info (Machine check info logged by the PAL and later * captured by the SAL) * req_addr (Address of the requestor of the transaction) * resp_addr (Address of the responder of the transaction) * target_addr (Address where the data was to be delivered to or * obtained from) - * Outputs : None + * Outputs : None */ void -ia64_log_bus_check_info_print(int i, +ia64_log_bus_check_info_print(int i, pal_bus_check_info_t info, u64 req_addr, u64 resp_addr, @@ -868,9 +866,9 @@ * ia64_log_processor_info_print * Display the processor-specific information logged by PAL as a part * of MCA or INIT or CMC. - * Inputs : lh (Pointer of the sal log header which specifies the format + * Inputs : lh (Pointer of the sal log header which specifies the format * of SAL state info as specified by the SAL spec). - * Outputs : None + * Outputs : None */ void ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc) @@ -892,29 +890,29 @@ } /* Print branch register contents if valid */ - if (slpi->slpi_valid.slpi_br) + if (slpi->slpi_valid.slpi_br) ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc); /* Print control register contents if valid */ - if (slpi->slpi_valid.slpi_cr) + if (slpi->slpi_valid.slpi_cr) ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc); /* Print application register contents if valid */ - if (slpi->slpi_valid.slpi_ar) + if (slpi->slpi_valid.slpi_ar) ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc); /* Print region register contents if valid */ - if (slpi->slpi_valid.slpi_rr) + if (slpi->slpi_valid.slpi_rr) ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc); /* Print floating-point register contents if valid */ - if (slpi->slpi_valid.slpi_fr) - ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", + if (slpi->slpi_valid.slpi_fr) + ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", prfunc); /* Print the cache check information if any*/ for (i = 0 ; i < MAX_CACHE_ERRORS; i++) - ia64_log_cache_check_info_print(i, + ia64_log_cache_check_info_print(i, slpi->slpi_cache_check_info[i].slpi_cache_check, slpi->slpi_cache_check_info[i].slpi_target_address, prfunc); @@ -924,7 +922,7 @@ /* Print the bus check information if any*/ for (i = 0 ; i < MAX_BUS_ERRORS; i++) - ia64_log_bus_check_info_print(i, + ia64_log_bus_check_info_print(i, slpi->slpi_bus_check_info[i].slpi_bus_check, slpi->slpi_bus_check_info[i].slpi_requestor_addr, slpi->slpi_bus_check_info[i].slpi_responder_addr, @@ -935,15 +933,15 @@ /* * ia64_log_print - * Display the contents of the OS error log information - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * Display the contents of the OS error log information + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * Outputs : None */ void ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) { - char *info_type, *sub_info_type; + char *info_type, *sub_info_type; switch(sal_info_type) { case SAL_INFO_TYPE_MCA: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/mca_asm.S linux.ac/arch/ia64/kernel/mca_asm.S --- linux.vanilla/arch/ia64/kernel/mca_asm.S Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/mca_asm.S Tue Apr 10 18:08:40 2001 @@ -1,4 +1,4 @@ -// +// // assembly portion of the IA64 MCA handling // // Mods by cfleck to integrate into kernel build @@ -8,6 +8,7 @@ // kstack, switch modes, jump to C INIT handler // #include + #include #include #include @@ -17,13 +18,9 @@ * When we get an machine check, the kernel stack pointer is no longer * valid, so we need to set a new stack pointer. */ -#define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */ +#define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */ #include "minstate.h" - - .psr abi64 - .psr lsb - .lsb /* * SAL_TO_OS_MCA_HANDOFF_STATE @@ -35,26 +32,26 @@ * 6. GR12 = Return address to location within SAL_CHECK */ #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - movl _tmp=ia64_sal_to_os_handoff_state;; \ - st8 [_tmp]=r1,0x08;; \ - st8 [_tmp]=r8,0x08;; \ - st8 [_tmp]=r9,0x08;; \ - st8 [_tmp]=r10,0x08;; \ - st8 [_tmp]=r11,0x08;; \ - st8 [_tmp]=r12,0x08;; + movl _tmp=ia64_sal_to_os_handoff_state;; \ + st8 [_tmp]=r1,0x08;; \ + st8 [_tmp]=r8,0x08;; \ + st8 [_tmp]=r9,0x08;; \ + st8 [_tmp]=r10,0x08;; \ + st8 [_tmp]=r11,0x08;; \ + st8 [_tmp]=r12,0x08;; /* * OS_MCA_TO_SAL_HANDOFF_STATE * 1. GR8 = OS_MCA status * 2. GR9 = SAL GP (physical) * 3. GR22 = New min state save area pointer - */ + */ #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ - movl _tmp=ia64_os_to_sal_handoff_state;; \ + movl _tmp=ia64_os_to_sal_handoff_state;; \ DATA_VA_TO_PA(_tmp);; \ - ld8 r8=[_tmp],0x08;; \ - ld8 r9=[_tmp],0x08;; \ - ld8 r22=[_tmp],0x08;; + ld8 r8=[_tmp],0x08;; \ + ld8 r9=[_tmp],0x08;; \ + ld8 r22=[_tmp],0x08;; /* * BRANCH @@ -65,9 +62,9 @@ * "ip" is the address of the instruction * located at "from_label". * "temp" is a scratch register like r2 - * "adjust" needed for HP compiler. + * "adjust" needed for HP compiler. * A screwup somewhere with constant arithmetic. - */ + */ #define BRANCH(to_label, temp, p, adjust) \ 100: (p) mov temp=ip; \ ;; \ @@ -76,7 +73,7 @@ (p) adds temp=adjust,temp; \ ;; \ (p) mov b1=temp ; \ - (p) br b1 + (p) br b1 .global ia64_os_mca_dispatch .global ia64_os_mca_dispatch_end @@ -88,11 +85,11 @@ .global ia64_mca_stack .global ia64_mca_stackframe .global ia64_mca_bspstore - .global ia64_init_stack - + .global ia64_init_stack + .text .align 16 - + ia64_os_mca_dispatch: #if defined(MCA_TEST) @@ -114,23 +111,23 @@ ;; begin_os_mca_dump: BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0) - ;; + ;; ia64_os_mca_done_dump: - // Setup new stack frame for OS_MCA handling - movl r2=ia64_mca_bspstore // local bspstore area location in r2 - movl r3=ia64_mca_stackframe // save stack frame to memory in r3 - rse_switch_context(r6,r3,r2);; // RSC management in this new context - movl r12=ia64_mca_stack;; + // Setup new stack frame for OS_MCA handling + movl r2=ia64_mca_bspstore // local bspstore area location in r2 + movl r3=ia64_mca_stackframe // save stack frame to memory in r3 + rse_switch_context(r6,r3,r2);; // RSC management in this new context + movl r12=ia64_mca_stack;; // Enter virtual mode from physical mode VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) ia64_os_mca_virtual_begin: // call our handler - movl r2=ia64_mca_ucmc_handler;; - mov b6=r2;; - br.call.sptk.few b0=b6 + movl r2=ia64_mca_ucmc_handler;; + mov b6=r2;; + br.call.sptk.few b0=b6 .ret0: // Revert back to physical mode before going back to SAL PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4) @@ -144,42 +141,36 @@ #endif /* #if defined(MCA_TEST) */ // restore the original stack frame here - movl r2=ia64_mca_stackframe // restore stack frame from memory at r2 + movl r2=ia64_mca_stackframe // restore stack frame from memory at r2 ;; DATA_VA_TO_PA(r2) - movl r4=IA64_PSR_MC + movl r4=IA64_PSR_MC ;; - rse_return_context(r4,r3,r2) // switch from interrupt context for RSE - + rse_return_context(r4,r3,r2) // switch from interrupt context for RSE + // let us restore all the registers from our PSI structure - mov r8=gp + mov r8=gp ;; begin_os_mca_restore: BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0) - ;; + ;; ia64_os_mca_done_restore: ;; -#ifdef SOFTSDV - VIRTUAL_MODE_ENTER(r2,r3, vmode_enter, r4) -vmode_enter: - br.ret.sptk.few b0 -#else // branch back to SALE_CHECK OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2) - ld8 r3=[r2];; - mov b0=r3 // SAL_CHECK return address - br b0 - ;; -#endif /* #ifdef SOFTSDV */ -ia64_os_mca_dispatch_end: + ld8 r3=[r2];; + mov b0=r3 // SAL_CHECK return address + br b0 + ;; +ia64_os_mca_dispatch_end: //EndMain////////////////////////////////////////////////////////////////////// //++ // Name: // ia64_os_mca_proc_state_dump() -// +// // Stub Description: // // This stub dumps the processor state during MCHK to a data area @@ -188,223 +179,223 @@ ia64_os_mca_proc_state_dump: // Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI - movl r2=ia64_mca_proc_state_dump;; // Os state dump area + movl r2=ia64_mca_proc_state_dump;; // Os state dump area -// save ar.NaT - mov r5=ar.unat // ar.unat +// save ar.NaT + mov r5=ar.unat // ar.unat // save banked GRs 16-31 along with NaT bits - bsw.1;; - st8.spill [r2]=r16,8;; - st8.spill [r2]=r17,8;; - st8.spill [r2]=r18,8;; - st8.spill [r2]=r19,8;; - st8.spill [r2]=r20,8;; - st8.spill [r2]=r21,8;; - st8.spill [r2]=r22,8;; - st8.spill [r2]=r23,8;; - st8.spill [r2]=r24,8;; - st8.spill [r2]=r25,8;; - st8.spill [r2]=r26,8;; - st8.spill [r2]=r27,8;; - st8.spill [r2]=r28,8;; - st8.spill [r2]=r29,8;; - st8.spill [r2]=r30,8;; - st8.spill [r2]=r31,8;; - - mov r4=ar.unat;; - st8 [r2]=r4,8 // save User NaT bits for r16-r31 - mov ar.unat=r5 // restore original unat - bsw.0;; + bsw.1;; + st8.spill [r2]=r16,8;; + st8.spill [r2]=r17,8;; + st8.spill [r2]=r18,8;; + st8.spill [r2]=r19,8;; + st8.spill [r2]=r20,8;; + st8.spill [r2]=r21,8;; + st8.spill [r2]=r22,8;; + st8.spill [r2]=r23,8;; + st8.spill [r2]=r24,8;; + st8.spill [r2]=r25,8;; + st8.spill [r2]=r26,8;; + st8.spill [r2]=r27,8;; + st8.spill [r2]=r28,8;; + st8.spill [r2]=r29,8;; + st8.spill [r2]=r30,8;; + st8.spill [r2]=r31,8;; + + mov r4=ar.unat;; + st8 [r2]=r4,8 // save User NaT bits for r16-r31 + mov ar.unat=r5 // restore original unat + bsw.0;; //save BRs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r4 - mov r3=b0 - mov r5=b1 - mov r7=b2;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=b3 - mov r5=b4 - mov r7=b5;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=b6 - mov r5=b7;; - st8 [r2]=r3,2*8 - st8 [r4]=r5,2*8;; + mov r3=b0 + mov r5=b1 + mov r7=b2;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=b3 + mov r5=b4 + mov r7=b5;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=b6 + mov r5=b7;; + st8 [r2]=r3,2*8 + st8 [r4]=r5,2*8;; cSaveCRs: // save CRs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r4 - mov r3=cr0 // cr.dcr - mov r5=cr1 // cr.itm - mov r7=cr2;; // cr.iva - - st8 [r2]=r3,8*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; // 48 byte rements + mov r3=cr0 // cr.dcr + mov r5=cr1 // cr.itm + mov r7=cr2;; // cr.iva + + st8 [r2]=r3,8*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; // 48 byte rements - mov r3=cr8;; // cr.pta - st8 [r2]=r3,8*8;; // 64 byte rements + mov r3=cr8;; // cr.pta + st8 [r2]=r3,8*8;; // 64 byte rements // if PSR.ic=0, reading interruption registers causes an illegal operation fault - mov r3=psr;; - tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p2) st8 [r2]=r0,9*8+160 // increment by 168 byte inc. -begin_skip_intr_regs: - BRANCH(SkipIntrRegs, r9, p2, 0x0) - ;; - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r6 - - mov r3=cr16 // cr.ipsr - mov r5=cr17 // cr.isr - mov r7=r0;; // cr.ida => cr18 - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr19 // cr.iip - mov r5=cr20 // cr.idtr - mov r7=cr21;; // cr.iitr - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr22 // cr.iipa - mov r5=cr23 // cr.ifs - mov r7=cr24;; // cr.iim - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr25;; // cr.iha - st8 [r2]=r3,160;; // 160 byte rement + mov r3=psr;; + tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test +(p6) st8 [r2]=r0,9*8+160 // increment by 168 byte inc. +begin_skip_intr_regs: + BRANCH(SkipIntrRegs, r9, p6, 0x0) + ;; + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r6 + + mov r3=cr16 // cr.ipsr + mov r5=cr17 // cr.isr + mov r7=r0;; // cr.ida => cr18 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr19 // cr.iip + mov r5=cr20 // cr.idtr + mov r7=cr21;; // cr.iitr + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr22 // cr.iipa + mov r5=cr23 // cr.ifs + mov r7=cr24;; // cr.iim + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr25;; // cr.iha + st8 [r2]=r3,160;; // 160 byte rement SkipIntrRegs: - st8 [r2]=r0,168 // another 168 byte . + st8 [r2]=r0,168 // another 168 byte . - mov r3=cr66;; // cr.lid - st8 [r2]=r3,40 // 40 byte rement + mov r3=cr66;; // cr.lid + st8 [r2]=r3,40 // 40 byte rement - mov r3=cr71;; // cr.ivr - st8 [r2]=r3,8 + mov r3=cr71;; // cr.ivr + st8 [r2]=r3,8 - mov r3=cr72;; // cr.tpr - st8 [r2]=r3,24 // 24 byte increment - - mov r3=r0;; // cr.eoi => cr75 - st8 [r2]=r3,168 // 168 byte inc. - - mov r3=r0;; // cr.irr0 => cr96 - st8 [r2]=r3,16 // 16 byte inc. + mov r3=cr72;; // cr.tpr + st8 [r2]=r3,24 // 24 byte increment - mov r3=r0;; // cr.irr1 => cr98 - st8 [r2]=r3,16 // 16 byte inc. + mov r3=r0;; // cr.eoi => cr75 + st8 [r2]=r3,168 // 168 byte inc. - mov r3=r0;; // cr.irr2 => cr100 - st8 [r2]=r3,16 // 16 byte inc + mov r3=r0;; // cr.irr0 => cr96 + st8 [r2]=r3,16 // 16 byte inc. - mov r3=r0;; // cr.irr3 => cr100 - st8 [r2]=r3,16 // 16b inc. + mov r3=r0;; // cr.irr1 => cr98 + st8 [r2]=r3,16 // 16 byte inc. - mov r3=r0;; // cr.itv => cr114 - st8 [r2]=r3,16 // 16 byte inc. + mov r3=r0;; // cr.irr2 => cr100 + st8 [r2]=r3,16 // 16 byte inc - mov r3=r0;; // cr.pmv => cr116 - st8 [r2]=r3,8 + mov r3=r0;; // cr.irr3 => cr100 + st8 [r2]=r3,16 // 16b inc. - mov r3=r0;; // cr.lrr0 => cr117 - st8 [r2]=r3,8 + mov r3=r0;; // cr.itv => cr114 + st8 [r2]=r3,16 // 16 byte inc. - mov r3=r0;; // cr.lrr1 => cr118 - st8 [r2]=r3,8 + mov r3=r0;; // cr.pmv => cr116 + st8 [r2]=r3,8 - mov r3=r0;; // cr.cmcv => cr119 - st8 [r2]=r3,8*10;; + mov r3=r0;; // cr.lrr0 => cr117 + st8 [r2]=r3,8 + + mov r3=r0;; // cr.lrr1 => cr118 + st8 [r2]=r3,8 + + mov r3=r0;; // cr.cmcv => cr119 + st8 [r2]=r3,8*10;; cSaveARs: // save ARs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r6 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r6 - mov r3=ar0 // ar.kro - mov r5=ar1 // ar.kr1 - mov r7=ar2;; // ar.kr2 - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=ar3 // ar.kr3 - mov r5=ar4 // ar.kr4 - mov r7=ar5;; // ar.kr5 - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=ar6 // ar.kr6 - mov r5=ar7 // ar.kr7 - mov r7=r0;; // ar.kr8 - st8 [r2]=r3,10*8 - st8 [r4]=r5,10*8 - st8 [r6]=r7,10*8;; // rement by 72 bytes + mov r3=ar0 // ar.kro + mov r5=ar1 // ar.kr1 + mov r7=ar2;; // ar.kr2 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=ar3 // ar.kr3 + mov r5=ar4 // ar.kr4 + mov r7=ar5;; // ar.kr5 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=ar6 // ar.kr6 + mov r5=ar7 // ar.kr7 + mov r7=r0;; // ar.kr8 + st8 [r2]=r3,10*8 + st8 [r4]=r5,10*8 + st8 [r6]=r7,10*8;; // rement by 72 bytes - mov r3=ar16 // ar.rsc + mov r3=ar16 // ar.rsc mov ar16=r0 // put RSE in enforced lazy mode - mov r5=ar17 // ar.bsp + mov r5=ar17 // ar.bsp ;; - mov r7=ar18;; // ar.bspstore - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; + mov r7=ar18;; // ar.bspstore + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; - mov r3=ar19;; // ar.rnat - st8 [r2]=r3,8*13 // increment by 13x8 bytes + mov r3=ar19;; // ar.rnat + st8 [r2]=r3,8*13 // increment by 13x8 bytes - mov r3=ar32;; // ar.ccv - st8 [r2]=r3,8*4 + mov r3=ar32;; // ar.ccv + st8 [r2]=r3,8*4 - mov r3=ar36;; // ar.unat - st8 [r2]=r3,8*4 + mov r3=ar36;; // ar.unat + st8 [r2]=r3,8*4 - mov r3=ar40;; // ar.fpsr - st8 [r2]=r3,8*4 + mov r3=ar40;; // ar.fpsr + st8 [r2]=r3,8*4 - mov r3=ar44;; // ar.itc - st8 [r2]=r3,160 // 160 + mov r3=ar44;; // ar.itc + st8 [r2]=r3,160 // 160 - mov r3=ar64;; // ar.pfs - st8 [r2]=r3,8 + mov r3=ar64;; // ar.pfs + st8 [r2]=r3,8 - mov r3=ar65;; // ar.lc - st8 [r2]=r3,8 + mov r3=ar65;; // ar.lc + st8 [r2]=r3,8 + + mov r3=ar66;; // ar.ec + st8 [r2]=r3 + add r2=8*62,r2 //padding - mov r3=ar66;; // ar.ec - st8 [r2]=r3 - add r2=8*62,r2 //padding - // save RRs - mov ar.lc=0x08-1 - movl r4=0x00;; + mov ar.lc=0x08-1 + movl r4=0x00;; cStRR: - mov r3=rr[r4];; - st8 [r2]=r3,8 - add r4=1,r4 - br.cloop.sptk.few cStRR - ;; + mov r3=rr[r4];; + st8 [r2]=r3,8 + add r4=1,r4 + br.cloop.sptk.few cStRR + ;; end_os_mca_dump: BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10) - ;; + ;; //EndStub////////////////////////////////////////////////////////////////////// @@ -412,7 +403,7 @@ //++ // Name: // ia64_os_mca_proc_state_restore() -// +// // Stub Description: // // This is a stub to restore the saved processor state during MCHK @@ -421,225 +412,225 @@ ia64_os_mca_proc_state_restore: -// Restore bank1 GR16-31 +// Restore bank1 GR16-31 movl r2=ia64_mca_proc_state_dump // Convert virtual address ;; // of OS state dump area DATA_VA_TO_PA(r2) // to physical address ;; restore_GRs: // restore bank-1 GRs 16-31 - bsw.1;; - add r3=16*8,r2;; // to get to NaT of GR 16-31 - ld8 r3=[r3];; - mov ar.unat=r3;; // first restore NaT - - ld8.fill r16=[r2],8;; - ld8.fill r17=[r2],8;; - ld8.fill r18=[r2],8;; - ld8.fill r19=[r2],8;; - ld8.fill r20=[r2],8;; - ld8.fill r21=[r2],8;; - ld8.fill r22=[r2],8;; - ld8.fill r23=[r2],8;; - ld8.fill r24=[r2],8;; - ld8.fill r25=[r2],8;; - ld8.fill r26=[r2],8;; - ld8.fill r27=[r2],8;; - ld8.fill r28=[r2],8;; - ld8.fill r29=[r2],8;; - ld8.fill r30=[r2],8;; - ld8.fill r31=[r2],8;; + bsw.1;; + add r3=16*8,r2;; // to get to NaT of GR 16-31 + ld8 r3=[r3];; + mov ar.unat=r3;; // first restore NaT + + ld8.fill r16=[r2],8;; + ld8.fill r17=[r2],8;; + ld8.fill r18=[r2],8;; + ld8.fill r19=[r2],8;; + ld8.fill r20=[r2],8;; + ld8.fill r21=[r2],8;; + ld8.fill r22=[r2],8;; + ld8.fill r23=[r2],8;; + ld8.fill r24=[r2],8;; + ld8.fill r25=[r2],8;; + ld8.fill r26=[r2],8;; + ld8.fill r27=[r2],8;; + ld8.fill r28=[r2],8;; + ld8.fill r29=[r2],8;; + ld8.fill r30=[r2],8;; + ld8.fill r31=[r2],8;; - ld8 r3=[r2],8;; // increment to skip NaT - bsw.0;; + ld8 r3=[r2],8;; // increment to skip NaT + bsw.0;; restore_BRs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov b0=r3 - mov b1=r5 - mov b2=r7;; - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov b3=r3 - mov b4=r5 - mov b5=r7;; - - ld8 r3=[r2],2*8 - ld8 r5=[r4],2*8;; - mov b6=r3 - mov b7=r5;; + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov b0=r3 + mov b1=r5 + mov b2=r7;; + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov b3=r3 + mov b4=r5 + mov b5=r7;; + + ld8 r3=[r2],2*8 + ld8 r5=[r4],2*8;; + mov b6=r3 + mov b7=r5;; restore_CRs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 - ld8 r3=[r2],8*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; // 48 byte increments - mov cr0=r3 // cr.dcr - mov cr1=r5 // cr.itm - mov cr2=r7;; // cr.iva + ld8 r3=[r2],8*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; // 48 byte increments + mov cr0=r3 // cr.dcr + mov cr1=r5 // cr.itm + mov cr2=r7;; // cr.iva - ld8 r3=[r2],8*8;; // 64 byte increments + ld8 r3=[r2],8*8;; // 64 byte increments // mov cr8=r3 // cr.pta // if PSR.ic=1, reading interruption registers causes an illegal operation fault - mov r3=psr;; - tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p2) st8 [r2]=r0,9*8+160 // increment by 160 byte inc. - -begin_rskip_intr_regs: - BRANCH(rSkipIntrRegs, r9, p2, 0x0) - ;; - - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr16=r3 // cr.ipsr - mov cr17=r5 // cr.isr is read only + mov r3=psr;; + tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test +(p6) st8 [r2]=r0,9*8+160 // increment by 160 byte inc. + +begin_rskip_intr_regs: + BRANCH(rSkipIntrRegs, r9, p6, 0x0) + ;; + + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr16=r3 // cr.ipsr + mov cr17=r5 // cr.isr is read only // mov cr18=r7;; // cr.ida - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr19=r3 // cr.iip - mov cr20=r5 // cr.idtr - mov cr21=r7;; // cr.iitr - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr22=r3 // cr.iipa - mov cr23=r5 // cr.ifs - mov cr24=r7 // cr.iim + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr19=r3 // cr.iip + mov cr20=r5 // cr.idtr + mov cr21=r7;; // cr.iitr + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr22=r3 // cr.iipa + mov cr23=r5 // cr.ifs + mov cr24=r7 // cr.iim - ld8 r3=[r2],160;; // 160 byte increment - mov cr25=r3 // cr.iha + ld8 r3=[r2],160;; // 160 byte increment + mov cr25=r3 // cr.iha rSkipIntrRegs: - ld8 r3=[r2],168;; // another 168 byte inc. + ld8 r3=[r2],168;; // another 168 byte inc. - ld8 r3=[r2],40;; // 40 byte increment - mov cr66=r3 // cr.lid + ld8 r3=[r2],40;; // 40 byte increment + mov cr66=r3 // cr.lid - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr71=r3 // cr.ivr is read only - ld8 r3=[r2],24;; // 24 byte increment - mov cr72=r3 // cr.tpr - - ld8 r3=[r2],168;; // 168 byte inc. + ld8 r3=[r2],24;; // 24 byte increment + mov cr72=r3 // cr.tpr + + ld8 r3=[r2],168;; // 168 byte inc. // mov cr75=r3 // cr.eoi - - ld8 r3=[r2],16;; // 16 byte inc. + + ld8 r3=[r2],16;; // 16 byte inc. // mov cr96=r3 // cr.irr0 is read only - ld8 r3=[r2],16;; // 16 byte inc. + ld8 r3=[r2],16;; // 16 byte inc. // mov cr98=r3 // cr.irr1 is read only - ld8 r3=[r2],16;; // 16 byte inc + ld8 r3=[r2],16;; // 16 byte inc // mov cr100=r3 // cr.irr2 is read only - ld8 r3=[r2],16;; // 16b inc. + ld8 r3=[r2],16;; // 16b inc. // mov cr102=r3 // cr.irr3 is read only - ld8 r3=[r2],16;; // 16 byte inc. + ld8 r3=[r2],16;; // 16 byte inc. // mov cr114=r3 // cr.itv - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr116=r3 // cr.pmv - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr117=r3 // cr.lrr0 - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov cr118=r3 // cr.lrr1 - ld8 r3=[r2],8*10;; + ld8 r3=[r2],8*10;; // mov cr119=r3 // cr.cmcv restore_ARs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov ar0=r3 // ar.kro - mov ar1=r5 // ar.kr1 - mov ar2=r7;; // ar.kr2 - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov ar3=r3 // ar.kr3 - mov ar4=r5 // ar.kr4 - mov ar5=r7;; // ar.kr5 - - ld8 r3=[r2],10*8 - ld8 r5=[r4],10*8 - ld8 r7=[r6],10*8;; - mov ar6=r3 // ar.kr6 - mov ar7=r5 // ar.kr7 + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov ar0=r3 // ar.kro + mov ar1=r5 // ar.kr1 + mov ar2=r7;; // ar.kr2 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov ar3=r3 // ar.kr3 + mov ar4=r5 // ar.kr4 + mov ar5=r7;; // ar.kr5 + + ld8 r3=[r2],10*8 + ld8 r5=[r4],10*8 + ld8 r7=[r6],10*8;; + mov ar6=r3 // ar.kr6 + mov ar7=r5 // ar.kr7 // mov ar8=r6 // ar.kr8 - ;; + ;; - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; // mov ar16=r3 // ar.rsc // mov ar17=r5 // ar.bsp is read only mov ar16=r0 // make sure that RSE is in enforced lazy mode ;; - mov ar18=r7;; // ar.bspstore + mov ar18=r7;; // ar.bspstore - ld8 r9=[r2],8*13;; - mov ar19=r9 // ar.rnat + ld8 r9=[r2],8*13;; + mov ar19=r9 // ar.rnat mov ar16=r3 // ar.rsc - ld8 r3=[r2],8*4;; - mov ar32=r3 // ar.ccv + ld8 r3=[r2],8*4;; + mov ar32=r3 // ar.ccv - ld8 r3=[r2],8*4;; - mov ar36=r3 // ar.unat + ld8 r3=[r2],8*4;; + mov ar36=r3 // ar.unat - ld8 r3=[r2],8*4;; - mov ar40=r3 // ar.fpsr + ld8 r3=[r2],8*4;; + mov ar40=r3 // ar.fpsr - ld8 r3=[r2],160;; // 160 + ld8 r3=[r2],160;; // 160 // mov ar44=r3 // ar.itc - ld8 r3=[r2],8;; - mov ar64=r3 // ar.pfs + ld8 r3=[r2],8;; + mov ar64=r3 // ar.pfs + + ld8 r3=[r2],8;; + mov ar65=r3 // ar.lc - ld8 r3=[r2],8;; - mov ar65=r3 // ar.lc + ld8 r3=[r2];; + mov ar66=r3 // ar.ec + add r2=8*62,r2;; // padding - ld8 r3=[r2];; - mov ar66=r3 // ar.ec - add r2=8*62,r2;; // padding - restore_RRs: - mov r5=ar.lc - mov ar.lc=0x08-1 - movl r4=0x00 + mov r5=ar.lc + mov ar.lc=0x08-1 + movl r4=0x00 cStRRr: - ld8 r3=[r2],8;; + ld8 r3=[r2],8;; // mov rr[r4]=r3 // what are its access previledges? - add r4=1,r4 - br.cloop.sptk.few cStRRr - ;; - mov ar.lc=r5 + add r4=1,r4 + br.cloop.sptk.few cStRRr + ;; + mov ar.lc=r5 ;; end_os_mca_restore: BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20) - ;; + ;; //EndStub////////////////////////////////////////////////////////////////////// // ok, the issue here is that we need to save state information so @@ -647,16 +638,16 @@ // In order to do this, our best bet is save the current state (plus // the state information obtain from the MIN_STATE_AREA) into a pt_regs // format. This way we can pass it on in a useable format. -// +// // // SAL to OS entry point for INIT on the monarch processor -// This has been defined for registration purposes with SAL +// This has been defined for registration purposes with SAL // as a part of ia64_mca_init. // // When we get here, the follow registers have been // set by the SAL for our use -// +// // 1. GR1 = OS INIT GP // 2. GR8 = PAL_PROC physical address // 3. GR9 = SAL_PROC physical address @@ -665,14 +656,14 @@ // 0 = Received INIT for event other than crash dump switch // 1 = Received wakeup at the end of an OS_MCA corrected machine check // 2 = Received INIT dude to CrashDump switch assertion -// +// // 6. GR12 = Return address to location within SAL_INIT procedure - + .text .align 16 -.global ia64_monarch_init_handler -.proc ia64_monarch_init_handler +.global ia64_monarch_init_handler +.proc ia64_monarch_init_handler ia64_monarch_init_handler: #if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND) @@ -680,6 +671,7 @@ // work around SAL bug that sends all processors to monarch entry // mov r17=cr.lid + // XXX fix me: this is wrong: hard_smp_processor_id() is a pair of lid/eid movl r18=__cpu_physical_id ;; dep r18=0,r18,61,3 // convert to physical address @@ -694,7 +686,7 @@ ;; #endif - + // // ok, the first thing we do is stash the information // the SAL passed to os @@ -706,8 +698,8 @@ ;; st8 [_tmp]=r1,0x08;; st8 [_tmp]=r8,0x08;; - st8 [_tmp]=r9,0x08;; - st8 [_tmp]=r10,0x08;; + st8 [_tmp]=r9,0x08;; + st8 [_tmp]=r10,0x08;; st8 [_tmp]=r11,0x08;; st8 [_tmp]=r12,0x08;; @@ -719,12 +711,12 @@ adds r3=8,r2 // set up second base pointer ;; SAVE_REST - + // ok, enough should be saved at this point to be dangerous, and supply // information for a dump // We need to switch to Virtual mode before hitting the C functions. // -// +// // movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN mov r3=psr // get the current psr, minimum enabled at this point @@ -739,7 +731,7 @@ rfi ;; IVirtual_Switch: - // + // // We should now be running virtual // // Lets call the C handler to get the rest of the state info @@ -759,7 +751,7 @@ // // SAL to OS entry point for INIT on the slave processor -// This has been defined for registration purposes with SAL +// This has been defined for registration purposes with SAL // as a part of ia64_mca_init. // @@ -767,10 +759,10 @@ .align 16 .global ia64_slave_init_handler .proc ia64_slave_init_handler -ia64_slave_init_handler: +ia64_slave_init_handler: -slave_init_spin_me: +slave_init_spin_me: br.sptk slave_init_spin_me ;; .endp diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/minstate.h linux.ac/arch/ia64/kernel/minstate.h --- linux.vanilla/arch/ia64/kernel/minstate.h Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/minstate.h Tue Apr 10 18:08:40 2001 @@ -29,20 +29,20 @@ */ #define MINSTATE_START_SAVE_MIN_VIRT \ dep r1=-1,r1,61,3; /* r1 = current (virtual) */ \ -(p7) mov ar.rsc=r0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ ;; \ -(p7) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ -(p7) mov rARRNAT=ar.rnat; \ +(pUser) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ +(pUser) mov rARRNAT=ar.rnat; \ (pKern) mov r1=sp; /* get sp */ \ ;; \ -(p7) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(p7) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ +(pUser) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(pUser) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ ;; \ (pKern) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ -(p7) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ +(pUser) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ ;; \ -(p7) mov r18=ar.bsp; \ -(p7) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) mov r18=ar.bsp; \ +(pUser) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ #define MINSTATE_END_SAVE_MIN_VIRT \ or r13=r13,r14; /* make `current' a kernel virtual address */ \ @@ -55,20 +55,20 @@ */ #define MINSTATE_START_SAVE_MIN_PHYS \ (pKern) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE; \ -(p7) mov ar.rsc=r0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ -(p7) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ +(pUser) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ ;; \ -(p7) mov rARRNAT=ar.rnat; \ +(pUser) mov rARRNAT=ar.rnat; \ (pKern) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ -(p7) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(p7) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ -(p7) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */\ +(pUser) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(pUser) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ +(pUser) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */\ ;; \ (pKern) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ -(p7) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ +(pUser) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ ;; \ -(p7) mov r18=ar.bsp; \ -(p7) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ +(pUser) mov r18=ar.bsp; \ +(pUser) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ #define MINSTATE_END_SAVE_MIN_PHYS \ or r12=r12,r14; /* make sp a kernel virtual address */ \ @@ -101,29 +101,30 @@ * r12 = kernel sp (kernel virtual address) * r13 = points to current task_struct (kernel virtual address) * p15 = TRUE if psr.i is set in cr.ipsr - * predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15: + * predicate registers (other than p2, p3, and p15), b6, r3, r8, r9, r10, r11, r14, r15: * preserved * * Note that psr.ic is NOT turned on by this macro. This is so that * we can pass interruption state as arguments to a handler. */ -#define DO_SAVE_MIN(COVER,EXTRA) \ +#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ mov rARRSC=ar.rsc; \ mov rARPFS=ar.pfs; \ mov rR1=r1; \ mov rARUNAT=ar.unat; \ mov rCRIPSR=cr.ipsr; \ - mov rB6=b6; /* rB6 = branch reg 6 */ \ + mov rB6=b6; /* rB6 = branch reg 6 */ \ mov rCRIIP=cr.iip; \ - mov r1=ar.k6; /* r1 = current (physical) */ \ + mov r1=IA64_KR(CURRENT); /* r1 = current (physical) */ \ + COVER; \ ;; \ invala; \ extr.u r16=rCRIPSR,32,2; /* extract psr.cpl */ \ ;; \ - cmp.eq pKern,p7=r0,r16; /* are we in kernel mode already? (psr.cpl==0) */ \ + cmp.eq pKern,pUser=r0,r16; /* are we in kernel mode already? (psr.cpl==0) */ \ /* switch from user to kernel RBS: */ \ - COVER; \ ;; \ + SAVE_IFS; \ MINSTATE_START_SAVE_MIN \ ;; \ mov r16=r1; /* initialize first base pointer */ \ @@ -135,7 +136,7 @@ ;; \ st8 [r16]=rCRIFS,16; /* save cr.ifs */ \ st8 [r17]=rARUNAT,16; /* save ar.unat */ \ -(p7) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ +(pUser) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ ;; \ st8 [r16]=rARPFS,16; /* save ar.pfs */ \ st8 [r17]=rARRSC,16; /* save ar.rsc */ \ @@ -143,8 +144,8 @@ ;; /* avoid RAW on r16 & r17 */ \ (pKern) adds r16=16,r16; /* skip over ar_rnat field */ \ (pKern) adds r17=16,r17; /* skip over ar_bspstore field */ \ -(p7) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ -(p7) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ +(pUser) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ +(pUser) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ ;; \ st8 [r16]=rARPR,16; /* save predicates */ \ st8 [r17]=rB6,16; /* save b6 */ \ @@ -171,7 +172,7 @@ ;; \ .mem.offset 0,0; st8.spill [r16]=r10,16; \ .mem.offset 8,0; st8.spill [r17]=r11,16; \ - mov r13=ar.k6; /* establish `current' */ \ + mov r13=IA64_KR(CURRENT); /* establish `current' */ \ ;; \ EXTRA; \ movl r1=__gp; /* establish kernel global pointer */ \ @@ -240,6 +241,6 @@ # define STOPS #endif -#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS -#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS -#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) STOPS +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) STOPS +#define SAVE_MIN DO_SAVE_MIN( , mov rCRIFS=r0, ) STOPS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/pal.S linux.ac/arch/ia64/kernel/pal.S --- linux.vanilla/arch/ia64/kernel/pal.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/pal.S Tue Apr 10 18:08:40 2001 @@ -14,11 +14,6 @@ #include #include - .text - .psr abi64 - .psr lsb - .lsb - .data pal_entry_point: data8 ia64_pal_default_handler @@ -58,7 +53,7 @@ * */ GLOBAL_ENTRY(ia64_pal_call_static) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) alloc loc1 = ar.pfs,6,90,0,0 movl loc2 = pal_entry_point 1: { @@ -73,7 +68,7 @@ ;; mov loc3 = psr mov loc0 = rp - UNW(.body) + .body mov r30 = in2 (p6) rsm psr.i | psr.ic @@ -101,14 +96,14 @@ * in2 - in3 Remaning PAL arguments */ GLOBAL_ENTRY(ia64_pal_call_stacked) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) alloc loc1 = ar.pfs,5,4,87,0 movl loc2 = pal_entry_point mov r28 = in0 // Index MUST be copied to r28 mov out0 = in0 // AND in0 of PAL function mov loc0 = rp - UNW(.body) + .body ;; ld8 loc2 = [loc2] // loc2 <- entry point mov out1 = in1 @@ -148,7 +143,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) alloc loc1 = ar.pfs,6,90,0,0 movl loc2 = pal_entry_point 1: { @@ -156,7 +151,7 @@ mov r8 = ip // save ip to compute branch mov loc0 = rp // save rp } - UNW(.body) + .body ;; ld8 loc2 = [loc2] // loc2 <- entry point mov r29 = in1 // first argument @@ -171,7 +166,7 @@ dep.z r8=r8,0,61 // convert rp to physical ;; mov b7 = loc2 // install target to branch reg - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode movl r16=PAL_PSR_BITS_TO_CLEAR movl r17=PAL_PSR_BITS_TO_SET ;; @@ -182,7 +177,7 @@ .ret1: mov rp = r8 // install return address (physical) br.cond.sptk.few b7 1: - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr br.call.sptk.few rp=ia64_switch_mode // return to virtual mode .ret2: @@ -204,7 +199,7 @@ * in2 - in3 Remaning PAL arguments */ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) - UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) alloc loc1 = ar.pfs,5,5,86,0 movl loc2 = pal_entry_point 1: { @@ -224,7 +219,7 @@ mov loc4=ar.rsc // save RSE configuration dep.z loc2=loc2,0,61 // convert pal entry point to physical ;; - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode movl r16=PAL_PSR_BITS_TO_CLEAR movl r17=PAL_PSR_BITS_TO_SET ;; @@ -236,7 +231,7 @@ .ret6: br.call.sptk.many rp=b7 // now make the call .ret7: - mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr br.call.sptk.few rp=ia64_switch_mode // return to virtual mode diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/palinfo.c linux.ac/arch/ia64/kernel/palinfo.c --- linux.vanilla/arch/ia64/kernel/palinfo.c Fri Feb 16 23:53:08 2001 +++ linux.ac/arch/ia64/kernel/palinfo.c Tue Apr 10 18:08:40 2001 @@ -5,16 +5,13 @@ * This code is based on specification of PAL as of the * Intel IA-64 Architecture Software Developer's Manual v1.0. * - * + * * Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000 Stephane Eranian - * + * * 05/26/2000 S.Eranian initial release * 08/21/2000 S.Eranian updated to July 2000 PAL specs - * - * ISSUES: - * - as of 2.2.9/2.2.12, the following values are still wrong - * PAL_VM_SUMMARY: key & rid sizes + * 02/05/2001 S.Eranian fixed module support */ #include #include @@ -36,12 +33,7 @@ MODULE_AUTHOR("Stephane Eranian "); MODULE_DESCRIPTION("/proc interface to IA-64 PAL"); -/* - * Hope to get rid of this one in a near future -*/ -#define IA64_PAL_VERSION_BUG 1 - -#define PALINFO_VERSION "0.3" +#define PALINFO_VERSION "0.4" #ifdef CONFIG_SMP #define cpu_is_online(i) (cpu_online_map & (1UL << i)) @@ -83,7 +75,7 @@ "Non-temporal, all levels", "Reserved", "Reserved", - "Reserved", + "Reserved", "Reserved" }; @@ -94,7 +86,7 @@ "Non-temporal, all levels", "Reserved", "Reserved", - "Reserved", + "Reserved", "Reserved" }; @@ -108,7 +100,7 @@ #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *)) /* - * The current revision of the Volume 2 (July 2000) of + * The current revision of the Volume 2 (July 2000) of * IA-64 Architecture Software Developer's Manual is wrong. * Table 4-10 has invalid information concerning the ma field: * Correct table is: @@ -116,7 +108,7 @@ * bit 4 - 100 - UC * bit 5 - 101 - UCE * bit 6 - 110 - WC - * bit 7 - 111 - NatPage + * bit 7 - 111 - NatPage */ static const char *mem_attrib[]={ "Write Back (WB)", /* 000 */ @@ -136,7 +128,7 @@ * * Input: * - a pointer to a buffer to hold the string - * - a 64-bit vector + * - a 64-bit vector * Ouput: * - a pointer to the end of the buffer * @@ -163,7 +155,7 @@ * * Input: * - a pointer to a buffer to hold the string - * - a 64-bit vector + * - a 64-bit vector * Ouput: * - a pointer to the end of the buffer * @@ -181,7 +173,7 @@ if (i != 0 && (i%64) == 0) value = *++reg_info; if ((value & 0x1) == 0 && skip == 0) { - if (begin <= i - 2) + if (begin <= i - 2) p += sprintf(p, "%d-%d ", begin, i-1); else p += sprintf(p, "%d ", i-1); @@ -194,7 +186,7 @@ value >>=1; } if (begin > -1) { - if (begin < 127) + if (begin < 127) p += sprintf(p, "%d-127", begin); else p += sprintf(p, "127"); @@ -219,7 +211,7 @@ if (halt_info[i].pal_power_mgmt_info_s.im == 1) { p += sprintf(p, "Power level %d:\n" \ "\tentry_latency : %d cycles\n" \ - "\texit_latency : %d cycles\n" \ + "\texit_latency : %d cycles\n" \ "\tpower consumption : %d mW\n" \ "\tCache+TLB coherency : %s\n", i, halt_info[i].pal_power_mgmt_info_s.entry_latency, @@ -233,7 +225,7 @@ return p - page; } -static int +static int cache_info(char *page) { char *p = page; @@ -288,13 +280,13 @@ for(k=0; k < 8; k++ ) { if ( cci.pcci_st_hints & 0x1) p += sprintf(p, "[%s]", cache_st_hints[k]); - cci.pcci_st_hints >>=1; + cci.pcci_st_hints >>=1; } p += sprintf(p, "\n\tLoad hints : "); for(k=0; k < 8; k++ ) { if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]); - cci.pcci_ld_hints >>=1; + cci.pcci_ld_hints >>=1; } p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" \ "\tTag LSB : %d\n" \ @@ -384,7 +376,7 @@ ptce.stride[1]); p += sprintf(p, "TC Levels : %d\n" \ - "Unique TC(s) : %d\n", + "Unique TC(s) : %d\n", vm_info_1.pal_vm_info_1_s.num_tc_levels, vm_info_1.pal_vm_info_1_s.max_unique_tcs); @@ -392,7 +384,7 @@ for (j=2; j>0 ; j--) { tc_pages = 0; /* just in case */ - + /* even without unification, some levels may not be present */ if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) { continue; @@ -422,7 +414,7 @@ } p += sprintf(p, "\n"); - return p - page; + return p - page; } @@ -446,7 +438,7 @@ if (ia64_pal_register_info(info, ®_info[0], ®_info[1]) != 0) return 0; - p += sprintf(p, "%-32s : ", info_type[info]); + p += sprintf(p, "%-32s : ", info_type[info]); p = bitregister_process(p, reg_info, 128); @@ -458,8 +450,8 @@ p += sprintf(p, "RSE stacked physical registers : %ld\n" \ "RSE load/store hints : %ld (%s)\n", phys_stacked, - hints.ph_data, - hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); + hints.ph_data, + hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); if (ia64_pal_debug_info(&iregs, &dregs)) return 0; @@ -486,15 +478,15 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Disable BINIT on processor time-out", "Disable dynamic power management (DPM)", - "Disable coherency", - "Disable cache", + "Disable coherency", + "Disable cache", "Enable CMCI promotion", "Enable MCA to BINIT promotion", "Enable MCA promotion", "Enable BEER promotion" }; - + static int processor_info(char *page) { @@ -508,7 +500,7 @@ for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) { if ( ! *v ) continue; - p += sprintf(p, "%-40s : %s%s %s\n", *v, + p += sprintf(p, "%-40s : %s%s %s\n", *v, avail & 0x1 ? "" : "NotImpl", avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); @@ -526,9 +518,9 @@ "Enable Half Transfer", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - "Enable Cache Line Repl. Exclusive", - "Enable Cache Line Repl. Shared", + NULL, NULL, NULL, NULL, + "Enable Cache Line Repl. Exclusive", + "Enable Cache Line Repl. Shared", "Disable Transaction Queuing", "Disable Reponse Error Checking", "Disable Bus Error Checking", @@ -541,7 +533,7 @@ "Disable Bus Data Error Checking" }; - + static int bus_info(char *page) { @@ -560,7 +552,7 @@ for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) { if ( ! *v ) continue; - p += sprintf(p, "%-48s : %s%s %s\n", *v, + p += sprintf(p, "%-48s : %s%s %s\n", *v, avail & 0x1 ? "" : "NotImpl", avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); @@ -568,62 +560,39 @@ return p - page; } - -/* - * physical mode call for PAL_VERSION is working fine. - * This function is meant to go away once PAL get fixed. - */ -static inline s64 -ia64_pal_version_phys(pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) -{ - struct ia64_pal_retval iprv; - PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0); - if (pal_min_version) - pal_min_version->pal_version_val = iprv.v0; - if (pal_cur_version) - pal_cur_version->pal_version_val = iprv.v1; - return iprv.status; -} - static int version_info(char *page) { - s64 status; pal_version_u_t min_ver, cur_ver; char *p = page; -#ifdef IA64_PAL_VERSION_BUG - /* The virtual mode call is buggy. But the physical mode call seems - * to be ok. Until they fix virtual mode, we do physical. - */ - status = ia64_pal_version_phys(&min_ver, &cur_ver); -#else - /* The system crashes if you enable this code with the wrong PAL - * code + /* The PAL_VERSION call is advertised as being able to support + * both physical and virtual mode calls. This seems to be a documentation + * bug rather than firmware bug. In fact, it does only support physical mode. + * So now the code reflects this fact and the pal_version() has been updated + * accordingly. */ - status = ia64_pal_version(&min_ver, &cur_ver); -#endif - if (status != 0) return 0; + if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0; p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \ "PAL_A : %x.%x.%x (min=%x.%x.%x)\n" \ "PAL_B : %x.%x.%x (min=%x.%x.%x)\n", - cur_ver.pal_version_s.pv_pal_vendor, - min_ver.pal_version_s.pv_pal_vendor, + cur_ver.pal_version_s.pv_pal_vendor, + min_ver.pal_version_s.pv_pal_vendor, - cur_ver.pal_version_s.pv_pal_a_model>>4, - cur_ver.pal_version_s.pv_pal_a_model&0xf, - cur_ver.pal_version_s.pv_pal_a_rev, - min_ver.pal_version_s.pv_pal_a_model>>4, - min_ver.pal_version_s.pv_pal_a_model&0xf, - min_ver.pal_version_s.pv_pal_a_rev, - - cur_ver.pal_version_s.pv_pal_b_model>>4, - cur_ver.pal_version_s.pv_pal_b_model&0xf, - cur_ver.pal_version_s.pv_pal_b_rev, - min_ver.pal_version_s.pv_pal_b_model>>4, - min_ver.pal_version_s.pv_pal_b_model&0xf, - min_ver.pal_version_s.pv_pal_b_rev); + cur_ver.pal_version_s.pv_pal_a_model>>4, + cur_ver.pal_version_s.pv_pal_a_model&0xf, + cur_ver.pal_version_s.pv_pal_a_rev, + min_ver.pal_version_s.pv_pal_a_model>>4, + min_ver.pal_version_s.pv_pal_a_model&0xf, + min_ver.pal_version_s.pv_pal_a_rev, + + cur_ver.pal_version_s.pv_pal_b_model>>4, + cur_ver.pal_version_s.pv_pal_b_model&0xf, + cur_ver.pal_version_s.pv_pal_b_rev, + min_ver.pal_version_s.pv_pal_b_model>>4, + min_ver.pal_version_s.pv_pal_b_model&0xf, + min_ver.pal_version_s.pv_pal_b_rev); return p - page; } @@ -650,7 +619,7 @@ "Counter width : %d bits\n" \ "Cycle event number : %d\n" \ "Retired event number : %d\n" \ - "Implemented PMC : ", + "Implemented PMC : ", pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width, pm_info.pal_perf_mon_info_s.cycles, @@ -659,15 +628,15 @@ p = bitregister_process(p, pm_buffer, 256); p += sprintf(p, "\nImplemented PMD : "); - + p = bitregister_process(p, pm_buffer+4, 256); p += sprintf(p, "\nCycles count capable : "); - + p = bitregister_process(p, pm_buffer+8, 256); p += sprintf(p, "\nRetired bundles count capable : "); - + p = bitregister_process(p, pm_buffer+12, 256); p += sprintf(p, "\n"); @@ -683,7 +652,7 @@ u64 base; if (ia64_pal_freq_base(&base) == -1) - p += sprintf(p, "Output clock : not implemented\n"); + p += sprintf(p, "Output clock : not implemented\n"); else p += sprintf(p, "Output clock : %ld ticks/s\n", base); @@ -762,7 +731,7 @@ if (ifa_reg->valid == 0) continue; - gr_reg = (struct gr_reg *)tr_buffer; + gr_reg = (struct gr_reg *)tr_buffer; itir_reg = (struct itir_reg *)&tr_buffer[1]; rid_reg = (struct rid_reg *)&tr_buffer[3]; @@ -788,7 +757,7 @@ "\trid : %x\n" \ "\tp : %d\n" \ "\tma : %d\n" \ - "\td : %d\n", + "\td : %d\n", gr_reg->pl, gr_reg->ar, rid_reg->rid, @@ -807,7 +776,7 @@ */ static palinfo_entry_t palinfo_entries[]={ { "version_info", version_info, }, - { "vm_info", vm_info, }, + { "vm_info", vm_info, }, { "cache_info", cache_info, }, { "power_info", power_info, }, { "register_info", register_info, }, @@ -821,14 +790,14 @@ #define NR_PALINFO_ENTRIES (sizeof(palinfo_entries)/sizeof(palinfo_entry_t)) /* - * this array is used to keep track of the proc entries we create. This is + * this array is used to keep track of the proc entries we create. This is * required in the module mode when we need to remove all entries. The procfs code * does not do recursion of deletion * * Notes: * - first +1 accounts for the cpuN entry * - second +1 account for toplevel palinfo - * + * */ #define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)+1) @@ -855,7 +824,7 @@ #ifdef CONFIG_SMP /* - * used to hold information about final function to call + * used to hold information about final function to call */ typedef struct { palinfo_func_t func; /* pointer to function to call */ @@ -888,7 +857,7 @@ * 0 : error or nothing to output * otherwise how many bytes in the "page" buffer were written */ -static +static int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) { palinfo_smp_data_t ptr; @@ -908,7 +877,7 @@ return ptr.ret; } #else /* ! CONFIG_SMP */ -static +static int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) { printk(__FUNCTION__" should not be called with non SMP kernel\n"); @@ -930,25 +899,25 @@ * in SMP mode, we may need to call another CPU to get correct * information. PAL, by definition, is processor specific */ - if (f->req_cpu == smp_processor_id()) + if (f->req_cpu == smp_processor_id()) len = (*palinfo_entries[f->func_id].proc_read)(page); else len = palinfo_handle_smp(f, page); - if (len <= off+count) *eof = 1; + if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; + *start = page + off; + len -= off; - if (len>count) len = count; - if (len<0) len = 0; + if (len>count) len = count; + if (len<0) len = 0; MOD_DEC_USE_COUNT; - return len; + return len; } -static int __init +static int __init palinfo_init(void) { # define CPUSTR "cpu%d" @@ -979,7 +948,7 @@ for (j=0; j < NR_PALINFO_ENTRIES; j++) { f.func_id = j; - *pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, + *pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, palinfo_read_entry, (void *)f.value); } *pdir++ = cpu_dir; @@ -994,9 +963,10 @@ { int i = 0; - /* remove all nodes: depth first pass */ + /* remove all nodes: depth first pass. Could optimize this */ for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) { - remove_proc_entry (palinfo_proc_entries[i]->name, NULL); + if (palinfo_proc_entries[i]) + remove_proc_entry (palinfo_proc_entries[i]->name, NULL); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/perfmon.c linux.ac/arch/ia64/kernel/perfmon.c --- linux.vanilla/arch/ia64/kernel/perfmon.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/perfmon.c Sat Apr 14 01:18:00 2001 @@ -7,57 +7,39 @@ * Modifications by Stephane Eranian, Hewlett-Packard Co. * Copyright (C) 1999 Ganesh Venkitachalam * Copyright (C) 1999 David Mosberger-Tang - * Copyright (C) 2000 Stephane Eranian + * Copyright (C) 2000-2001 Stephane Eranian */ #include - #include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include #include +#include #include #include -#include - -/* Long blurb on how this works: - * We set dcr.pp, psr.pp, and the appropriate pmc control values with - * this. Notice that we go about modifying _each_ task's pt_regs to - * set cr_ipsr.pp. This will start counting when "current" does an - * _rfi_. Also, since each task's cr_ipsr.pp, and cr_ipsr is inherited - * across forks, we do _not_ need additional code on context - * switches. On stopping of the counters we dont need to go about - * changing every task's cr_ipsr back to where it wuz, because we can - * just set pmc[0]=1. But we do it anyways becuase we will probably - * add thread specific accounting later. - * - * The obvious problem with this is that on SMP systems, it is a bit - * of work (when someone wants to do it:-)) - it would be easier if we - * just added code to the context-switch path, but if we wanted to support - * per-thread accounting, the context-switch path might be long unless - * we introduce a flag in the task_struct. Right now, the following code - * will NOT work correctly on MP (for more than one reason:-)). - * - * The short answer is that to make this work on SMP, we would need - * to lock the run queue to ensure no context switches, send - * an IPI to each processor, and in that IPI handler, set processor regs, - * and just modify the psr bit of only the _current_ thread, since we have - * modified the psr bit correctly in the kernel stack for every process - * which is not running. Also, we need pmd arrays per-processor, and - * the READ_PMD command will need to get values off of other processors. - * IPIs are the answer, irrespective of what the question is. Might - * crash on SMP systems without the lock_kernel(). - */ +#include /* for ia64_get_itc() */ #ifdef CONFIG_PERFMON -#define MAX_PERF_COUNTER 4 /* true for Itanium, at least */ +#define PFM_VERSION "0.2" +#define PFM_SMPL_HDR_VERSION 1 + #define PMU_FIRST_COUNTER 4 /* first generic counter */ #define PFM_WRITE_PMCS 0xa0 @@ -67,293 +49,1019 @@ #define PFM_START 0xa4 #define PFM_ENABLE 0xa5 /* unfreeze only */ #define PFM_DISABLE 0xa6 /* freeze only */ -/* +#define PFM_RESTART 0xcf +#define PFM_CREATE_CONTEXT 0xa7 +/* * Those 2 are just meant for debugging. I considered using sysctl() for * that but it is a little bit too pervasive. This solution is at least * self-contained. */ -#define PFM_DEBUG_ON 0xe0 +#define PFM_DEBUG_ON 0xe0 #define PFM_DEBUG_OFF 0xe1 + +/* + * perfmon API flags + */ +#define PFM_FL_INHERIT_NONE 0x00 /* never inherit a context across fork (default) */ +#define PFM_FL_INHERIT_ONCE 0x01 /* clone pfm_context only once across fork() */ +#define PFM_FL_INHERIT_ALL 0x02 /* always clone pfm_context across fork() */ +#define PFM_FL_SMPL_OVFL_NOBLOCK 0x04 /* do not block on sampling buffer overflow */ +#define PFM_FL_SYSTEMWIDE 0x08 /* create a systemwide context */ + +/* + * PMC API flags + */ +#define PFM_REGFL_OVFL_NOTIFY 1 /* send notification on overflow */ + +/* + * Private flags and masks + */ +#define PFM_FL_INHERIT_MASK (PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL) + #ifdef CONFIG_SMP #define cpu_is_online(i) (cpu_online_map & (1UL << i)) #else #define cpu_is_online(i) 1 #endif -#define PMC_IS_IMPL(i) (pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) -#define PMD_IS_IMPL(i) (pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) +#define PMC_IS_IMPL(i) (i < pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) +#define PMD_IS_IMPL(i) (i < pmu_conf.num_pmds && pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) #define PMD_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) #define PMC_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) +/* This is the Itanium-specific PMC layout for counter config */ +typedef struct { + unsigned long pmc_plm:4; /* privilege level mask */ + unsigned long pmc_ev:1; /* external visibility */ + unsigned long pmc_oi:1; /* overflow interrupt */ + unsigned long pmc_pm:1; /* privileged monitor */ + unsigned long pmc_ig1:1; /* reserved */ + unsigned long pmc_es:7; /* event select */ + unsigned long pmc_ig2:1; /* reserved */ + unsigned long pmc_umask:4; /* unit mask */ + unsigned long pmc_thres:3; /* threshold */ + unsigned long pmc_ig3:1; /* reserved (missing from table on p6-17) */ + unsigned long pmc_ism:2; /* instruction set mask */ + unsigned long pmc_ig4:38; /* reserved */ +} pmc_counter_reg_t; + +/* test for EAR/BTB configuration */ +#define PMU_DEAR_EVENT 0x67 +#define PMU_IEAR_EVENT 0x23 +#define PMU_BTB_EVENT 0x11 + +#define PMC_IS_DEAR(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_DEAR_EVENT) +#define PMC_IS_IEAR(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_IEAR_EVENT) +#define PMC_IS_BTB(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_BTB_EVENT) + /* - * this structure needs to be enhanced + * This header is at the beginning of the sampling buffer returned to the user. + * It is exported as Read-Only at this point. It is directly followed with the + * first record. */ typedef struct { - unsigned long pfr_reg_num; /* which register */ - unsigned long pfr_reg_value; /* configuration (PMC) or initial value (PMD) */ - unsigned long pfr_reg_reset; /* reset value on overflow (PMD) */ - void *pfr_smpl_buf; /* pointer to user buffer for EAR/BTB */ - unsigned long pfr_smpl_size; /* size of user buffer for EAR/BTB */ - pid_t pfr_notify_pid; /* process to notify */ - int pfr_notify_sig; /* signal for notification, 0=no notification */ -} perfmon_req_t; + int hdr_version; /* could be used to differentiate formats */ + int hdr_reserved; + unsigned long hdr_entry_size; /* size of one entry in bytes */ + unsigned long hdr_count; /* how many valid entries */ + unsigned long hdr_pmds; /* which pmds are recorded */ +} perfmon_smpl_hdr_t; -#if 0 +/* + * Header entry in the buffer as a header as follows. + * The header is directly followed with the PMDS to saved in increasing index order: + * PMD4, PMD5, .... How many PMDs are present is determined by the tool which must + * keep track of it when generating the final trace file. + */ typedef struct { - unsigned long pmu_reg_data; /* generic PMD register */ - unsigned long pmu_reg_num; /* which register number */ -} perfmon_reg_t; -#endif + int pid; /* identification of process */ + int cpu; /* which cpu was used */ + unsigned long rate; /* initial value of this counter */ + unsigned long stamp; /* timestamp */ + unsigned long ip; /* where did the overflow interrupt happened */ + unsigned long regs; /* which registers overflowed (up to 64)*/ +} perfmon_smpl_entry_t; /* - * This structure is initialize at boot time and contains + * There is one such data structure per perfmon context. It is used to describe the + * sampling buffer. It is to be shared among siblings whereas the pfm_context isn't. + * Therefore we maintain a refcnt which is incremented on fork(). + * This buffer is private to the kernel only the actual sampling buffer including its + * header are exposed to the user. This construct allows us to export the buffer read-write, + * if needed, without worrying about security problems. + */ +typedef struct { + atomic_t psb_refcnt; /* how many users for the buffer */ + int reserved; + void *psb_addr; /* points to location of first entry */ + unsigned long psb_entries; /* maximum number of entries */ + unsigned long psb_size; /* aligned size of buffer */ + unsigned long psb_index; /* next free entry slot */ + unsigned long psb_entry_size; /* size of each entry including entry header */ + perfmon_smpl_hdr_t *psb_hdr; /* points to sampling buffer header */ +} pfm_smpl_buffer_desc_t; + + +/* + * This structure is initialized at boot time and contains * a description of the PMU main characteristic as indicated * by PAL */ typedef struct { + unsigned long pfm_is_disabled; /* indicates if perfmon is working properly */ unsigned long perf_ovfl_val; /* overflow value for generic counters */ unsigned long max_counters; /* upper limit on counter pair (PMC/PMD) */ + unsigned long num_pmcs ; /* highest PMC implemented (may have holes) */ + unsigned long num_pmds; /* highest PMD implemented (may have holes) */ unsigned long impl_regs[16]; /* buffer used to hold implememted PMC/PMD mask */ } pmu_config_t; +#define PERFMON_IS_DISABLED() pmu_conf.pfm_is_disabled + +typedef struct { + __u64 val; /* virtual 64bit counter value */ + __u64 ival; /* initial value from user */ + __u64 smpl_rval; /* reset value on sampling overflow */ + __u64 ovfl_rval; /* reset value on overflow */ + int flags; /* notify/do not notify */ +} pfm_counter_t; +#define PMD_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) + +/* + * perfmon context. One per process, is cloned on fork() depending on inheritance flags + */ +typedef struct { + unsigned int inherit:2; /* inherit mode */ + unsigned int noblock:1; /* block/don't block on overflow with notification */ + unsigned int system:1; /* do system wide monitoring */ + unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ + unsigned int reserved:27; +} pfm_context_flags_t; + +typedef struct pfm_context { + + pfm_smpl_buffer_desc_t *ctx_smpl_buf; /* sampling buffer descriptor, if any */ + unsigned long ctx_dear_counter; /* which PMD holds D-EAR */ + unsigned long ctx_iear_counter; /* which PMD holds I-EAR */ + unsigned long ctx_btb_counter; /* which PMD holds BTB */ + + pid_t ctx_notify_pid; /* who to notify on overflow */ + int ctx_notify_sig; /* XXX: SIGPROF or other */ + pfm_context_flags_t ctx_flags; /* block/noblock */ + pid_t ctx_creator; /* pid of creator (debug) */ + unsigned long ctx_ovfl_regs; /* which registers just overflowed (notification) */ + unsigned long ctx_smpl_regs; /* which registers to record on overflow */ + + struct semaphore ctx_restart_sem; /* use for blocking notification mode */ + + pfm_counter_t ctx_pmds[IA64_NUM_PMD_COUNTERS]; /* XXX: size should be dynamic */ +} pfm_context_t; + +#define ctx_fl_inherit ctx_flags.inherit +#define ctx_fl_noblock ctx_flags.noblock +#define ctx_fl_system ctx_flags.system +#define ctx_fl_frozen ctx_flags.frozen + +#define CTX_IS_DEAR(c,n) ((c)->ctx_dear_counter == (n)) +#define CTX_IS_IEAR(c,n) ((c)->ctx_iear_counter == (n)) +#define CTX_IS_BTB(c,n) ((c)->ctx_btb_counter == (n)) +#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_noblock == 1) +#define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) +#define CTX_HAS_SMPL(c) ((c)->ctx_smpl_buf != NULL) + static pmu_config_t pmu_conf; /* for debug only */ -static unsigned long pfm_debug=1; /* 0= nodebug, >0= debug output on */ -#define DBprintk(a) {\ - if (pfm_debug >0) { printk a; } \ +static unsigned long pfm_debug=0; /* 0= nodebug, >0= debug output on */ +#define DBprintk(a) \ + do { \ + if (pfm_debug >0) { printk(__FUNCTION__" "); printk a; } \ + } while (0); + +static void perfmon_softint(unsigned long ignored); +static void ia64_reset_pmu(void); + +DECLARE_TASKLET(pfm_tasklet, perfmon_softint, 0); + +/* + * structure used to pass information between the interrupt handler + * and the tasklet. + */ +typedef struct { + pid_t to_pid; /* which process to notify */ + pid_t from_pid; /* which process is source of overflow */ + int sig; /* with which signal */ + unsigned long bitvect; /* which counters have overflowed */ +} notification_info_t; + +#define notification_is_invalid(i) (i->to_pid < 2) + +/* will need to be cache line padded */ +static notification_info_t notify_info[NR_CPUS]; + +/* + * We force cache line alignment to avoid false sharing + * given that we have one entry per CPU. + */ +static struct { + struct task_struct *owner; +} ____cacheline_aligned pmu_owners[NR_CPUS]; +/* helper macros */ +#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0); +#define PMU_OWNER() pmu_owners[smp_processor_id()].owner + +/* for debug only */ +static struct proc_dir_entry *perfmon_dir; + +/* + * finds the number of PM(C|D) registers given + * the bitvector returned by PAL + */ +static unsigned long __init +find_num_pm_regs(long *buffer) +{ + int i=3; /* 4 words/per bitvector */ + + /* start from the most significant word */ + while (i>=0 && buffer[i] == 0 ) i--; + if (i< 0) { + printk(KERN_ERR "perfmon: No bit set in pm_buffer\n"); + return 0; + } + return 1+ ia64_fls(buffer[i]) + 64 * i; } + /* - * could optimize to avoid cache line conflicts in SMP + * Generates a unique (per CPU) timestamp + */ +static inline unsigned long +perfmon_get_stamp(void) +{ + /* + * XXX: maybe find something more efficient + */ + return ia64_get_itc(); +} + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. */ -static struct task_struct *pmu_owners[NR_CPUS]; +static inline unsigned long +uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if (pte_present(pte)) { + ret = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + } + } + } + DBprintk(("uv2kva(%lx-->%lx)\n", adr, ret)); + return ret; +} + + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long +kvirt_to_pa(unsigned long adr) +{ + __u64 pa; + __asm__ __volatile__ ("tpa %0 = %1" : "=r"(pa) : "r"(adr) : "memory"); + DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); + return pa; +} + +static void * +rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr, page; + + /* XXX: may have to revisit this part because + * vmalloc() does not necessarily return a page-aligned buffer. + * This maybe a security problem when mapped at user level + */ + mem=vmalloc(size); + if (mem) { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void +rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + if (mem) { + adr=(unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +static pfm_context_t * +pfm_context_alloc(void) +{ + pfm_context_t *pfc; + + /* allocate context descriptor */ + pfc = vmalloc(sizeof(*pfc)); + if (pfc) memset(pfc, 0, sizeof(*pfc)); + + return pfc; +} + +static void +pfm_context_free(pfm_context_t *pfc) +{ + if (pfc) vfree(pfc); +} static int -do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) +pfm_remap_buffer(unsigned long buf, unsigned long addr, unsigned long size) { - perfmon_req_t tmp; - int i; + unsigned long page; - switch (cmd) { - case PFM_WRITE_PMCS: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + while (size > 0) { + page = kvirt_to_pa(buf); - if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM; + + addr += PAGE_SIZE; + buf += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +/* + * counts the number of PMDS to save per entry. + * This code is generic enough to accomodate more than 64 PMDS when they become available + */ +static unsigned long +pfm_smpl_entry_size(unsigned long *which, unsigned long size) +{ + unsigned long res = 0; + int i; + + for (i=0; i < size; i++, which++) res += hweight64(*which); + + DBprintk((" res=%ld\n", res)); + + return res; +} + +/* + * Allocates the sampling buffer and remaps it into caller's address space + */ +static int +pfm_smpl_buffer_alloc(pfm_context_t *ctx, unsigned long which_pmds, unsigned long entries, void **user_addr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long addr, size, regcount; + void *smpl_buf; + pfm_smpl_buffer_desc_t *psb; + + regcount = pfm_smpl_entry_size(&which_pmds, 1); + + /* note that regcount might be 0, in this case only the header for each + * entry will be recorded. + */ + + /* + * 1 buffer hdr and for each entry a header + regcount PMDs to save + */ + size = PAGE_ALIGN( sizeof(perfmon_smpl_hdr_t) + + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64))); + /* + * check requested size to avoid Denial-of-service attacks + * XXX: may have to refine this test + */ + if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; + + /* find some free area in address space */ + addr = get_unmapped_area(NULL, 0, size, 0, 0); + if (!addr) goto no_addr; + + DBprintk((" entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, addr)); + + /* allocate vma */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!vma) goto no_vma; + + /* XXX: see rvmalloc() for page alignment problem */ + smpl_buf = rvmalloc(size); + if (smpl_buf == NULL) goto no_buffer; + + DBprintk((" smpl_buf @%p\n", smpl_buf)); + + if (pfm_remap_buffer((unsigned long)smpl_buf, addr, size)) goto cant_remap; + + /* allocate sampling buffer descriptor now */ + psb = vmalloc(sizeof(*psb)); + if (psb == NULL) goto no_buffer_desc; + + /* start with something clean */ + memset(smpl_buf, 0x0, size); + + psb->psb_hdr = smpl_buf; + psb->psb_addr = (char *)smpl_buf+sizeof(perfmon_smpl_hdr_t); /* first entry */ + psb->psb_size = size; /* aligned size */ + psb->psb_index = 0; + psb->psb_entries = entries; + + atomic_set(&psb->psb_refcnt, 1); + + psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64); + + DBprintk((" psb @%p entry_size=%ld hdr=%p addr=%p\n", (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, (void *)psb->psb_addr)); + + /* initialize some of the fields of header */ + psb->psb_hdr->hdr_version = PFM_SMPL_HDR_VERSION; + psb->psb_hdr->hdr_entry_size = sizeof(perfmon_smpl_entry_t)+regcount*sizeof(u64); + psb->psb_hdr->hdr_pmds = which_pmds; + + /* store which PMDS to record */ + ctx->ctx_smpl_regs = which_pmds; + + /* link to perfmon context */ + ctx->ctx_smpl_buf = psb; + + /* + * initialize the vma for the sampling buffer + */ + vma->vm_mm = mm; + vma->vm_start = addr; + vma->vm_end = addr + size; + vma->vm_flags = VM_READ|VM_MAYREAD; + vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ + vma->vm_ops = NULL; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_raend = 0; + + vma->vm_private_data = ctx; /* link to pfm_context(not yet used) */ + + /* + * now insert the vma in the vm list for the process + */ + insert_vm_struct(mm, vma); + + mm->total_vm += size >> PAGE_SHIFT; + + /* + * that's the address returned to the user + */ + *user_addr = (void *)addr; + + return 0; + + /* outlined error handling */ +no_addr: + DBprintk(("Cannot find unmapped area for size %ld\n", size)); + return -ENOMEM; +no_vma: + DBprintk(("Cannot allocate vma\n")); + return -ENOMEM; +cant_remap: + DBprintk(("Can't remap buffer\n")); + rvfree(smpl_buf, size); +no_buffer: + DBprintk(("Can't allocate sampling buffer\n")); + kmem_cache_free(vm_area_cachep, vma); + return -ENOMEM; +no_buffer_desc: + DBprintk(("Can't allocate sampling buffer descriptor\n")); + kmem_cache_free(vm_area_cachep, vma); + rvfree(smpl_buf, size); + return -ENOMEM; +} + +static int +pfx_is_sane(pfreq_context_t *pfx) +{ + /* valid signal */ + if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return 0; + + /* cannot send to process 1, 0 means do not notify */ + if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return 0; + + /* asked for sampling, but nothing to record ! */ + if (pfx->smpl_entries > 0 && pfm_smpl_entry_size(&pfx->smpl_regs, 1) == 0) return 0; + + /* probably more to add here */ + + + return 1; +} + +static int +pfm_context_create(struct task_struct *task, int flags, perfmon_req_t *req) +{ + pfm_context_t *ctx; + perfmon_req_t tmp; + void *uaddr = NULL; + int ret = -EFAULT; + int ctx_flags; + + /* to go away */ + if (flags) { + printk("perfmon: use context flags instead of perfmon() flags. Obsoleted API\n"); + } + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + + ctx_flags = tmp.pfr_ctx.flags; + + /* not yet supported */ + if (ctx_flags & PFM_FL_SYSTEMWIDE) return -EINVAL; + + if (!pfx_is_sane(&tmp.pfr_ctx)) return -EINVAL; + + ctx = pfm_context_alloc(); + if (!ctx) return -ENOMEM; + + /* record who the creator is (for debug) */ + ctx->ctx_creator = task->pid; + + ctx->ctx_notify_pid = tmp.pfr_ctx.notify_pid; + ctx->ctx_notify_sig = SIGPROF; /* siginfo imposes a fixed signal */ + + if (tmp.pfr_ctx.smpl_entries) { + DBprintk((" sampling entries=%ld\n",tmp.pfr_ctx.smpl_entries)); + if ((ret=pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, tmp.pfr_ctx.smpl_entries, &uaddr)) ) goto buffer_error; + tmp.pfr_ctx.smpl_vaddr = uaddr; + } + /* initialization of context's flags */ + ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; + ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEMWIDE) ? 1: 0; + ctx->ctx_fl_frozen = 0; + + sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ + + if (copy_to_user(req, &tmp, sizeof(tmp))) goto buffer_error; + + DBprintk((" context=%p, pid=%d notify_sig %d notify_pid=%d\n",(void *)ctx, task->pid, ctx->ctx_notify_sig, ctx->ctx_notify_pid)); + DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system)); + + /* link with task */ + task->thread.pfm_context = ctx; + + return 0; + +buffer_error: + vfree(ctx); + + return ret; +} + +static void +pfm_reset_regs(pfm_context_t *ctx) +{ + unsigned long mask = ctx->ctx_ovfl_regs; + int i, cnum; + + DBprintk((" ovfl_regs=0x%lx\n", mask)); + /* + * now restore reset value on sampling overflowed counters + */ + for(i=0, cnum=PMU_FIRST_COUNTER; i < pmu_conf.max_counters; i++, cnum++, mask >>= 1) { + if (mask & 0x1) { + DBprintk((" reseting PMD[%d]=%lx\n", cnum, ctx->ctx_pmds[i].smpl_rval & pmu_conf.perf_ovfl_val)); + + /* upper part is ignored on rval */ + ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); + } + } +} + +static int +pfm_write_pmcs(struct task_struct *ta, perfmon_req_t *req, int count) +{ + struct thread_struct *th = &ta->thread; + pfm_context_t *ctx = th->pfm_context; + perfmon_req_t tmp; + unsigned long cnum; + int i; + + /* XXX: ctx locking may be required here */ + + for (i = 0; i < count; i++, req++) { + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + + cnum = tmp.pfr_reg.reg_num; + + /* XXX needs to check validity of the data maybe */ + if (!PMC_IS_IMPL(cnum)) { + DBprintk((" invalid pmc[%ld]\n", cnum)); + return -EINVAL; + } + + if (PMC_IS_COUNTER(cnum)) { + + /* + * we keep track of EARS/BTB to speed up sampling later + */ + if (PMC_IS_DEAR(&tmp.pfr_reg.reg_value)) { + ctx->ctx_dear_counter = cnum; + } else if (PMC_IS_IEAR(&tmp.pfr_reg.reg_value)) { + ctx->ctx_iear_counter = cnum; + } else if (PMC_IS_BTB(&tmp.pfr_reg.reg_value)) { + ctx->ctx_btb_counter = cnum; + } + + if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) + ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; + } + + ia64_set_pmc(cnum, tmp.pfr_reg.reg_value); + DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags)); + + } + /* + * we have to set this here event hough we haven't necessarily started monitoring + * because we may be context switched out + */ + th->flags |= IA64_THREAD_PM_VALID; + + return 0; +} + +static int +pfm_write_pmds(struct task_struct *ta, perfmon_req_t *req, int count) +{ + struct thread_struct *th = &ta->thread; + pfm_context_t *ctx = th->pfm_context; + perfmon_req_t tmp; + unsigned long cnum; + int i; + + /* XXX: ctx locking may be required here */ + + for (i = 0; i < count; i++, req++) { + int k; + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - for (i = 0; i < count; i++, req++) { - copy_from_user(&tmp, req, sizeof(tmp)); + cnum = tmp.pfr_reg.reg_num; - /* XXX needs to check validity of the data maybe */ + k = cnum - PMU_FIRST_COUNTER; - if (!PMC_IS_IMPL(tmp.pfr_reg_num)) { - DBprintk((__FUNCTION__ " invalid pmc[%ld]\n", tmp.pfr_reg_num)); - return -EINVAL; - } - - /* XXX: for counters, need to some checks */ - if (PMC_IS_COUNTER(tmp.pfr_reg_num)) { - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].sig = tmp.pfr_notify_sig; - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].pid = tmp.pfr_notify_pid; - - DBprintk((__FUNCTION__" setting PMC[%ld] send sig %d to %d\n",tmp.pfr_reg_num, tmp.pfr_notify_sig, tmp.pfr_notify_pid)); - } - ia64_set_pmc(tmp.pfr_reg_num, tmp.pfr_reg_value); + if (!PMD_IS_IMPL(cnum)) return -EINVAL; - DBprintk((__FUNCTION__" setting PMC[%ld]=0x%lx\n", tmp.pfr_reg_num, tmp.pfr_reg_value)); + /* update virtualized (64bits) counter */ + if (PMD_IS_COUNTER(cnum)) { + ctx->ctx_pmds[k].ival = tmp.pfr_reg.reg_value; + ctx->ctx_pmds[k].val = tmp.pfr_reg.reg_value & ~pmu_conf.perf_ovfl_val; + ctx->ctx_pmds[k].smpl_rval = tmp.pfr_reg.reg_smpl_reset; + ctx->ctx_pmds[k].ovfl_rval = tmp.pfr_reg.reg_ovfl_reset; + } + + /* writes to unimplemented part is ignored, so this is safe */ + ia64_set_pmd(cnum, tmp.pfr_reg.reg_value); + + /* to go away */ + ia64_srlz_d(); + DBprintk((" setting PMD[%ld]: pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx\n", + cnum, + ctx->ctx_pmds[k].val, + ctx->ctx_pmds[k].ovfl_rval, + ctx->ctx_pmds[k].smpl_rval, + ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val)); + } + /* + * we have to set this here event hough we haven't necessarily started monitoring + * because we may be context switched out + */ + th->flags |= IA64_THREAD_PM_VALID; + + return 0; +} + +static int +pfm_read_pmds(struct task_struct *ta, perfmon_req_t *req, int count) +{ + struct thread_struct *th = &ta->thread; + pfm_context_t *ctx = th->pfm_context; + unsigned long val=0; + perfmon_req_t tmp; + int i; + + /* + * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING + * This is required when the monitoring has been stoppped by user of kernel. + * If ity is still going on, then that's fine because we a re not gauranteed + * to return an accurate value in this case + */ + + /* XXX: ctx locking may be required here */ + + for (i = 0; i < count; i++, req++) { + int k; + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + + if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL; + + k = tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER; + + if (PMD_IS_COUNTER(tmp.pfr_reg.reg_num)) { + if (ta == current){ + val = ia64_get_pmd(tmp.pfr_reg.reg_num); + } else { + val = th->pmd[k]; } + val &= pmu_conf.perf_ovfl_val; /* - * we have to set this here event hough we haven't necessarily started monitoring - * because we may be context switched out + * lower part of .val may not be zero, so we must be an addition because of + * residual count (see update_counters). */ - current->thread.flags |= IA64_THREAD_PM_VALID; - break; + val += ctx->ctx_pmds[k].val; + } else { + /* for now */ + if (ta != current) return -EINVAL; - case PFM_WRITE_PMDS: + val = ia64_get_pmd(tmp.pfr_reg.reg_num); + } + tmp.pfr_reg.reg_value = val; + + DBprintk((" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg.reg_num, val)); + + if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; + } + return 0; +} + +static int +pfm_do_restart(struct task_struct *task) +{ + struct thread_struct *th = &task->thread; + pfm_context_t *ctx = th->pfm_context; + void *sem = &ctx->ctx_restart_sem; + + if (task == current) { + DBprintk((" restartig self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); + + pfm_reset_regs(ctx); + + /* + * We ignore block/don't block because we never block + * for a self-monitoring process. + */ + ctx->ctx_fl_frozen = 0; + + if (CTX_HAS_SMPL(ctx)) { + ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; + ctx->ctx_smpl_buf->psb_index = 0; + } + + /* pfm_reset_smpl_buffers(ctx,th->pfm_ovfl_regs);*/ + + /* simply unfreeze */ + ia64_set_pmc(0, 0); + ia64_srlz_d(); + + return 0; + } + + /* check if blocking */ + if (CTX_OVFL_NOBLOCK(ctx) == 0) { + DBprintk((" unblocking %d \n", task->pid)); + up(sem); + return 0; + } + + /* + * in case of non blocking mode, then it's just a matter of + * of reseting the sampling buffer (if any) index. The PMU + * is already active. + */ + + /* + * must reset the header count first + */ + if (CTX_HAS_SMPL(ctx)) { + DBprintk((" resetting sampling indexes for %d \n", task->pid)); + ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; + ctx->ctx_smpl_buf->psb_index = 0; + } + + return 0; +} + + +static int +do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) +{ + perfmon_req_t tmp; + struct thread_struct *th = &task->thread; + pfm_context_t *ctx = th->pfm_context; + + memset(&tmp, 0, sizeof(tmp)); + + switch (cmd) { + case PFM_CREATE_CONTEXT: + /* a context has already been defined */ + if (ctx) return -EBUSY; + + /* may be a temporary limitation */ + if (task != current) return -EINVAL; + + if (req == NULL || count != 1) return -EINVAL; + + if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + + return pfm_context_create(task, flags, req); + + case PFM_WRITE_PMCS: /* we don't quite support this right now */ if (task != current) return -EINVAL; if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - for (i = 0; i < count; i++, req++) { - copy_from_user(&tmp, req, sizeof(tmp)); + if (!ctx) { + DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid)); + return -EINVAL; + } + return pfm_write_pmcs(task, req, count); + + case PFM_WRITE_PMDS: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL; + if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - /* update virtualized (64bits) counter */ - if (PMD_IS_COUNTER(tmp.pfr_reg_num)) { - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val = tmp.pfr_reg_value & ~pmu_conf.perf_ovfl_val; - current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval = tmp.pfr_reg_reset; - } - /* writes to unimplemented part is ignored, so this is safe */ - ia64_set_pmd(tmp.pfr_reg_num, tmp.pfr_reg_value); - /* to go away */ - ia64_srlz_d(); - DBprintk((__FUNCTION__" setting PMD[%ld]: pmod.val=0x%lx pmd=0x%lx rval=0x%lx\n", tmp.pfr_reg_num, current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val, ia64_get_pmd(tmp.pfr_reg_num),current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval)); + if (!ctx) { + DBprintk((" PFM_WRITE_PMDS: no context for task %d\n", task->pid)); + return -EINVAL; } - /* - * we have to set this here event hough we haven't necessarily started monitoring - * because we may be context switched out - */ - current->thread.flags |= IA64_THREAD_PM_VALID; - break; + return pfm_write_pmds(task, req, count); case PFM_START: /* we don't quite support this right now */ if (task != current) return -EINVAL; - pmu_owners[smp_processor_id()] = current; + if (!ctx) { + DBprintk((" PFM_START: no context for task %d\n", task->pid)); + return -EINVAL; + } + + SET_PMU_OWNER(current); /* will start monitoring right after rfi */ ia64_psr(regs)->up = 1; - /* - * mark the state as valid. - * this will trigger save/restore at context switch - */ - current->thread.flags |= IA64_THREAD_PM_VALID; + /* + * mark the state as valid. + * this will trigger save/restore at context switch + */ + th->flags |= IA64_THREAD_PM_VALID; ia64_set_pmc(0, 0); + ia64_srlz_d(); - break; + break; case PFM_ENABLE: /* we don't quite support this right now */ if (task != current) return -EINVAL; - pmu_owners[smp_processor_id()] = current; + if (!ctx) { + DBprintk((" PFM_ENABLE: no context for task %d\n", task->pid)); + return -EINVAL; + } + + /* reset all registers to stable quiet state */ + ia64_reset_pmu(); + + /* make sure nothing starts */ + ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; + + /* do it on the live register as well */ + __asm__ __volatile__ ("rsm psr.pp|psr.pp;;"::: "memory"); + + SET_PMU_OWNER(current); - /* - * mark the state as valid. - * this will trigger save/restore at context switch - */ - current->thread.flags |= IA64_THREAD_PM_VALID; + /* + * mark the state as valid. + * this will trigger save/restore at context switch + */ + th->flags |= IA64_THREAD_PM_VALID; /* simply unfreeze */ ia64_set_pmc(0, 0); + ia64_srlz_d(); break; case PFM_DISABLE: /* we don't quite support this right now */ if (task != current) return -EINVAL; - /* simply unfreeze */ + /* simply freeze */ ia64_set_pmc(0, 1); ia64_srlz_d(); break; - case PFM_READ_PMDS: + case PFM_READ_PMDS: if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - /* This looks shady, but IMHO this will work fine. This is - * the sequence that I could come up with to avoid races - * with the interrupt handler. See explanation in the - * following comment. - */ -#if 0 -/* irrelevant with user monitors */ - local_irq_save(flags); - __asm__ __volatile__("rsm psr.pp\n"); - dcr = ia64_get_dcr(); - dcr &= ~IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); -#endif - /* - * We cannot write to pmc[0] to stop counting here, as - * that particular instruction might cause an overflow - * and the mask in pmc[0] might get lost. I'm _not_ - * sure of the hardware behavior here. So we stop - * counting by psr.pp = 0. And we reset dcr.pp to - * prevent an interrupt from mucking up psr.pp in the - * meanwhile. Perfmon interrupts are pended, hence the - * above code should be ok if one of the above instructions - * caused overflows, i.e the interrupt should get serviced - * when we re-enabled interrupts. When I muck with dcr, - * is the irq_save/restore needed? - */ - - for (i = 0; i < count; i++, req++) { - unsigned long val=0; - - copy_from_user(&tmp, req, sizeof(tmp)); - - if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL; - - if (PMD_IS_COUNTER(tmp.pfr_reg_num)) { - if (task == current){ - val = ia64_get_pmd(tmp.pfr_reg_num) & pmu_conf.perf_ovfl_val; - } else { - val = task->thread.pmd[tmp.pfr_reg_num - PMU_FIRST_COUNTER] & pmu_conf.perf_ovfl_val; - } - val += task->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val; - } else { - /* for now */ - if (task != current) return -EINVAL; - - val = ia64_get_pmd(tmp.pfr_reg_num); + if (!ctx) { + DBprintk((" PFM_READ_PMDS: no context for task %d\n", task->pid)); + return -EINVAL; } - tmp.pfr_reg_value = val; - -DBprintk((__FUNCTION__" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg_num, val)); - - if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; - } -#if 0 -/* irrelevant with user monitors */ - local_irq_save(flags); - __asm__ __volatile__("ssm psr.pp"); - dcr = ia64_get_dcr(); - dcr |= IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); -#endif - break; + return pfm_read_pmds(task, req, count); case PFM_STOP: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - ia64_set_pmc(0, 1); - ia64_srlz_d(); + ia64_set_pmc(0, 1); + ia64_srlz_d(); - ia64_psr(regs)->up = 0; + ia64_psr(regs)->up = 0; - current->thread.flags &= ~IA64_THREAD_PM_VALID; + th->flags &= ~IA64_THREAD_PM_VALID; - pmu_owners[smp_processor_id()] = NULL; + SET_PMU_OWNER(NULL); -#if 0 -/* irrelevant with user monitors */ - local_irq_save(flags); - dcr = ia64_get_dcr(); - dcr &= ~IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); - ia64_psr(regs)->up = 0; -#endif - - break; + /* we probably will need some more cleanup here */ + break; case PFM_DEBUG_ON: - printk(__FUNCTION__" debuggin on\n"); + printk(" debugging on\n"); pfm_debug = 1; break; case PFM_DEBUG_OFF: - printk(__FUNCTION__" debuggin off\n"); + printk(" debugging off\n"); pfm_debug = 0; break; + case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */ + + if ((th->flags & IA64_THREAD_PM_VALID) == 0) { + printk(" PFM_RESTART not monitoring\n"); + return -EINVAL; + } + if (!ctx) { + printk(" PFM_RESTART no ctx for %d\n", task->pid); + return -EINVAL; + } + if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_fl_frozen==0) { + printk("task %d without pmu_frozen set\n", task->pid); + return -EINVAL; + } + + return pfm_do_restart(task); /* we only look at first entry */ + default: - DBprintk((__FUNCTION__" UNknown command 0x%x\n", cmd)); - return -EINVAL; - break; - } - return 0; + DBprintk((" UNknown command 0x%x\n", cmd)); + return -EINVAL; + } + return 0; +} + +/* + * XXX: do something better here + */ +static int +perfmon_bad_permissions(struct task_struct *task) +{ + /* stolen from bad_signal() */ + return (current->session != task->session) + && (current->euid ^ task->suid) && (current->euid ^ task->uid) + && (current->uid ^ task->suid) && (current->uid ^ task->uid); } asmlinkage int @@ -361,8 +1069,16 @@ { struct pt_regs *regs = (struct pt_regs *) &stack; struct task_struct *child = current; - int ret; + int ret = -ESRCH; + + /* sanity check: + * + * ensures that we don't do bad things in case the OS + * does not have enough storage to save/restore PMC/PMD + */ + if (PERFMON_IS_DISABLED()) return -ENOSYS; + /* XXX: pid interface is going away in favor of pfm context */ if (pid != current->pid) { read_lock(&tasklist_lock); { @@ -370,37 +1086,245 @@ if (child) get_task_struct(child); } - if (!child) { - read_unlock(&tasklist_lock); - return -ESRCH; - } + + if (!child) goto abort_call; + + ret = -EPERM; + + if (perfmon_bad_permissions(child)) goto abort_call; + /* * XXX: need to do more checking here */ - if (child->state != TASK_ZOMBIE) { - DBprintk((__FUNCTION__" warning process %d not in stable state %ld\n", pid, child->state)); + if (child->state != TASK_ZOMBIE && child->state != TASK_STOPPED) { + DBprintk((" warning process %d not in stable state %ld\n", pid, child->state)); } - } + } ret = do_perfmonctl(child, cmd, flags, req, count, regs); +abort_call: if (child != current) read_unlock(&tasklist_lock); return ret; } -static inline int -update_counters (u64 pmc0) +/* + * This function is invoked on the exit path of the kernel. Therefore it must make sure + * it does does modify the caller's input registers (in0-in7) in case of entry by system call + * which can be restarted. That's why it's declared as a system call and all 8 possible args + * are declared even though not used. + */ +#if __GNUC__ >= 3 +void asmlinkage +pfm_overflow_notify(void) +#else +void asmlinkage +pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) +#endif { - unsigned long mask, i, cnum; - struct thread_struct *th; - struct task_struct *ta; + struct task_struct *task; + struct thread_struct *th = ¤t->thread; + pfm_context_t *ctx = current->thread.pfm_context; + struct siginfo si; + int ret; - if (pmu_owners[smp_processor_id()] == NULL) { - DBprintk((__FUNCTION__" Spurious overflow interrupt: PMU not owned\n")); - return 0; + /* + * do some sanity checks first + */ + if (!ctx) { + printk("perfmon: process %d has no PFM context\n", current->pid); + return; + } + if (ctx->ctx_notify_pid < 2) { + printk("perfmon: process %d invalid notify_pid=%d\n", current->pid, ctx->ctx_notify_pid); + return; + } + + DBprintk((" current=%d ctx=%p bv=0%lx\n", current->pid, (void *)ctx, ctx->ctx_ovfl_regs)); + /* + * NO matter what notify_pid is, + * we clear overflow, won't notify again + */ + th->pfm_pend_notify = 0; + + /* + * When measuring in kernel mode and non-blocking fashion, it is possible to + * get an overflow while executing this code. Therefore the state of pend_notify + * and ovfl_regs can be altered. The important point is not to loose any notification. + * It is fine to get called for nothing. To make sure we do collect as much state as + * possible, update_counters() always uses |= to add bit to the ovfl_regs field. + * + * In certain cases, it is possible to come here, with ovfl_regs == 0; + * + * XXX: pend_notify and ovfl_regs could be merged maybe ! + */ + if (ctx->ctx_ovfl_regs == 0) { + printk("perfmon: spurious overflow notification from pid %d\n", current->pid); + return; } - + read_lock(&tasklist_lock); + + task = find_task_by_pid(ctx->ctx_notify_pid); + + if (task) { + si.si_signo = ctx->ctx_notify_sig; + si.si_errno = 0; + si.si_code = PROF_OVFL; /* goes to user */ + si.si_addr = NULL; + si.si_pid = current->pid; /* who is sending */ + si.si_pfm_ovfl = ctx->ctx_ovfl_regs; + + DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); + + /* must be done with tasklist_lock locked */ + ret = send_sig_info(ctx->ctx_notify_sig, &si, task); + if (ret != 0) { + DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_pid, ret)); + task = NULL; /* will cause return */ + } + } else { + printk("perfmon: notify_pid %d not found\n", ctx->ctx_notify_pid); + } + + read_unlock(&tasklist_lock); + + /* now that we have released the lock handle error condition */ + if (!task || CTX_OVFL_NOBLOCK(ctx)) { + /* we clear all pending overflow bits in noblock mode */ + ctx->ctx_ovfl_regs = 0; + return; + } + DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid)); + + /* + * may go through without blocking on SMP systems + * if restart has been received already by the time we call down() + */ + ret = down_interruptible(&ctx->ctx_restart_sem); + + DBprintk((" CPU%d %d after sleep ret=%d\n", smp_processor_id(), current->pid, ret)); + + /* + * in case of interruption of down() we don't restart anything + */ + if (ret >= 0) { + /* we reactivate on context switch */ + ctx->ctx_fl_frozen = 0; + /* + * the ovfl_sem is cleared by the restart task and this is safe because we always + * use the local reference + */ + + pfm_reset_regs(ctx); + + /* now we can clear this mask */ + ctx->ctx_ovfl_regs = 0; + + /* + * Unlock sampling buffer and reset index atomically + * XXX: not really needed when blocking + */ + if (CTX_HAS_SMPL(ctx)) { + ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; + ctx->ctx_smpl_buf->psb_index = 0; + } + + DBprintk((" CPU%d %d unfreeze PMU\n", smp_processor_id(), current->pid)); + + ia64_set_pmc(0, 0); + ia64_srlz_d(); + + /* state restored, can go back to work (user mode) */ + } +} + +static void +perfmon_softint(unsigned long ignored) +{ + notification_info_t *info; + int my_cpu = smp_processor_id(); + struct task_struct *task; + struct siginfo si; + + info = notify_info+my_cpu; + + DBprintk((" CPU%d current=%d to_pid=%d from_pid=%d bv=0x%lx\n", \ + smp_processor_id(), current->pid, info->to_pid, info->from_pid, info->bitvect)); + + /* assumption check */ + if (info->from_pid == info->to_pid) { + DBprintk((" Tasklet assumption error: from=%d tor=%d\n", info->from_pid, info->to_pid)); + return; + } + + if (notification_is_invalid(info)) { + DBprintk((" invalid notification information\n")); + return; + } + + /* sanity check */ + if (info->to_pid == 1) { + DBprintk((" cannot notify init\n")); + return; + } + /* + * XXX: needs way more checks here to make sure we send to a task we have control over + */ + read_lock(&tasklist_lock); + + task = find_task_by_pid(info->to_pid); + + DBprintk((" after find %p\n", (void *)task)); + + if (task) { + int ret; + + si.si_signo = SIGPROF; + si.si_errno = 0; + si.si_code = PROF_OVFL; /* goes to user */ + si.si_addr = NULL; + si.si_pid = info->from_pid; /* who is sending */ + si.si_pfm_ovfl = info->bitvect; + + DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); + + /* must be done with tasklist_lock locked */ + ret = send_sig_info(SIGPROF, &si, task); + if (ret != 0) + DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", info->to_pid, ret)); + + /* invalidate notification */ + info->to_pid = info->from_pid = 0; + info->bitvect = 0; + } + + read_unlock(&tasklist_lock); + + DBprintk((" after unlock %p\n", (void *)task)); + + if (!task) { + printk("perfmon: CPU%d cannot find process %d\n", smp_processor_id(), info->to_pid); + } +} + +/* + * main overflow processing routine. + * it can be called from the interrupt path or explicitely during the context switch code + * Return: + * 0 : do not unfreeze the PMU + * 1 : PMU can be unfrozen + */ +static unsigned long +update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) +{ + unsigned long mask, i, cnum; + struct thread_struct *th; + pfm_context_t *ctx; + unsigned long bv = 0; + int my_cpu = smp_processor_id(); + int ret = 1, buffer_is_full = 0; + int ovfl_is_smpl, can_notify, need_reset_pmd16=0; /* * It is never safe to access the task for which the overflow interrupt is destinated * using the current variable as the interrupt may occur in the middle of a context switch @@ -408,76 +1332,269 @@ * * For monitoring, however, we do need to get access to the task which caused the overflow * to account for overflow on the counters. + * * We accomplish this by maintaining a current owner of the PMU per CPU. During context - * switch the ownership is changed in a way such that the reflected owner is always the + * switch the ownership is changed in a way such that the reflected owner is always the * valid one, i.e. the one that caused the interrupt. */ - ta = pmu_owners[smp_processor_id()]; - th = &pmu_owners[smp_processor_id()]->thread; + + if (ta == NULL) { + DBprintk((" owners[%d]=NULL\n", my_cpu)); + return 0x1; + } + th = &ta->thread; + ctx = th->pfm_context; /* - * Don't think this could happen given first test. Keep as sanity check + * XXX: debug test + * Don't think this could happen given upfront tests */ if ((th->flags & IA64_THREAD_PM_VALID) == 0) { - DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d not using perfmon\n", ta->pid)); + printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", ta->pid); + return 0x1; + } + if (!ctx) { + printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", ta->pid); return 0; } /* - * if PMU not frozen: spurious from previous context - * if PMC[0] = 0x1 : frozen but no overflow reported: leftover from previous context - * - * in either case we don't touch the state upon return from handler + * sanity test. Should never happen */ - if ((pmc0 & 0x1) == 0 || pmc0 == 0x1) { - DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d freeze=0\n",ta->pid)); - return 0; + if ((pmc0 & 0x1 )== 0) { + printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", ta->pid, pmc0); + return 0x0; } - mask = pmc0 >> 4; + mask = pmc0 >> PMU_FIRST_COUNTER; - for (i = 0, cnum = PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++, mask >>= 1) { + DBprintk(("pmc0=0x%lx pid=%d\n", pmc0, ta->pid)); - if (mask & 0x1) { - DBprintk((__FUNCTION__ " PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), th->pmu_counters[i].val)); - + DBprintk(("ctx is in %s mode\n", CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK")); + + if (CTX_HAS_SMPL(ctx)) { + pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; + unsigned long *e, m, idx=0; + perfmon_smpl_entry_t *h; + int j; + + idx = ia64_fetch_and_add(1, &psb->psb_index); + DBprintk((" trying to record index=%ld entries=%ld\n", idx, psb->psb_entries)); + + /* + * XXX: there is a small chance that we could run out on index before resetting + * but index is unsigned long, so it will take some time..... + */ + if (idx > psb->psb_entries) { + buffer_is_full = 1; + goto reload_pmds; + } + + /* first entry is really entry 0, not 1 caused by fetch_and_add */ + idx--; + + h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); + + h->pid = ta->pid; + h->cpu = my_cpu; + h->rate = 0; + h->ip = regs ? regs->cr_iip : 0x0; /* where did the fault happened */ + h->regs = mask; /* which registers overflowed */ + + /* guaranteed to monotonically increase on each cpu */ + h->stamp = perfmon_get_stamp(); + + e = (unsigned long *)(h+1); + /* + * selectively store PMDs in increasing index number + */ + for (j=0, m = ctx->ctx_smpl_regs; m; m >>=1, j++) { + if (m & 0x1) { + if (PMD_IS_COUNTER(j)) + *e = ctx->ctx_pmds[j-PMU_FIRST_COUNTER].val + + (ia64_get_pmd(j) & pmu_conf.perf_ovfl_val); + else + *e = ia64_get_pmd(j); /* slow */ + DBprintk((" e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); + e++; + } + } + /* make the new entry visible to user, needs to be atomic */ + ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); + + DBprintk((" index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count)); + + /* sampling buffer full ? */ + if (idx == (psb->psb_entries-1)) { + bv = mask; + buffer_is_full = 1; + + DBprintk((" sampling buffer full must notify bv=0x%lx\n", bv)); + + if (!CTX_OVFL_NOBLOCK(ctx)) goto buffer_full; /* - * Because we somtimes (EARS/BTB) reset to a specific value, we cannot simply use - * val to count the number of times we overflowed. Otherwise we would loose the value - * current in the PMD (which can be >0). So to make sure we don't loose - * the residual counts we set val to contain full 64bits value of the counter. + * here, we have a full buffer but we are in non-blocking mode + * so we need to reloads overflowed PMDs with sampling reset values + * and restart */ - th->pmu_counters[i].val += 1+pmu_conf.perf_ovfl_val+(ia64_get_pmd(cnum) &pmu_conf.perf_ovfl_val); + } + } +reload_pmds: + ovfl_is_smpl = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full; + can_notify = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_pid; - /* writes to upper part are ignored, so this is safe */ - ia64_set_pmd(cnum, th->pmu_counters[i].rval); + for (i = 0, cnum = PMU_FIRST_COUNTER; mask ; cnum++, i++, mask >>= 1) { + + if ((mask & 0x1) == 0) continue; + + DBprintk((" PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), ctx->ctx_pmds[i].val)); - DBprintk((__FUNCTION__ " pmod[%ld].val=0x%lx pmd=0x%lx\n", i, th->pmu_counters[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); + /* + * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use + * val to count the number of times we overflowed. Otherwise we would loose the current value + * in the PMD (which can be >0). So to make sure we don't loose + * the residual counts we set val to contain full 64bits value of the counter. + * + * XXX: is this needed for EARS/BTB ? + */ + ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val + + (ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val); /* slow */ + + DBprintk((" pmod[%ld].val=0x%lx pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); + + if (can_notify && PMD_OVFL_NOTIFY(ctx, i)) { + DBprintk((" CPU%d should notify process %d with signal %d\n", my_cpu, ctx->ctx_notify_pid, ctx->ctx_notify_sig)); + bv |= 1 << i; + } else { + DBprintk((" CPU%d PMD[%ld] overflow, no notification\n", my_cpu, cnum)); + /* + * In case no notification is requested, we reload the reset value right away + * otherwise we wait until the notify_pid process has been called and has + * has finished processing data. Check out pfm_overflow_notify() + */ - if (th->pmu_counters[i].pid != 0 && th->pmu_counters[i].sig>0) { - DBprintk((__FUNCTION__ " shouild notify process %d with signal %d\n",th->pmu_counters[i].pid, th->pmu_counters[i].sig)); + /* writes to upper part are ignored, so this is safe */ + if (ovfl_is_smpl) { + DBprintk((" CPU%d PMD[%ld] reloaded with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); + } else { + DBprintk((" CPU%d PMD[%ld] reloaded with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + ia64_set_pmd(cnum, ctx->ctx_pmds[i].ovfl_rval); } } + if (cnum == ctx->ctx_btb_counter) need_reset_pmd16=1; } - return 1; + /* + * In case of BTB, overflow + * we need to reset the BTB index. + */ + if (need_reset_pmd16) { + DBprintk(("reset PMD16\n")); + ia64_set_pmd(16, 0); + } +buffer_full: + /* see pfm_overflow_notify() on details for why we use |= here */ + ctx->ctx_ovfl_regs |= bv; + + /* nobody to notify, return and unfreeze */ + if (!bv) return 0x0; + + + if (ctx->ctx_notify_pid == ta->pid) { + struct siginfo si; + + si.si_errno = 0; + si.si_addr = NULL; + si.si_pid = ta->pid; /* who is sending */ + + + si.si_signo = ctx->ctx_notify_sig; /* is SIGPROF */ + si.si_code = PROF_OVFL; /* goes to user */ + si.si_pfm_ovfl = bv; + + + /* + * in this case, we don't stop the task, we let it go on. It will + * necessarily go to the signal handler (if any) when it goes back to + * user mode. + */ + DBprintk((" sending %d notification to self %d\n", si.si_signo, ta->pid)); + + + /* this call is safe in an interrupt handler */ + ret = send_sig_info(ctx->ctx_notify_sig, &si, ta); + if (ret != 0) + printk(" send_sig_info(process %d, SIGPROF)=%d\n", ta->pid, ret); + /* + * no matter if we block or not, we keep PMU frozen and do not unfreeze on ctxsw + */ + ctx->ctx_fl_frozen = 1; + + } else { +#if 0 + /* + * The tasklet is guaranteed to be scheduled for this CPU only + */ + notify_info[my_cpu].to_pid = ctx->notify_pid; + notify_info[my_cpu].from_pid = ta->pid; /* for debug only */ + notify_info[my_cpu].bitvect = bv; + /* tasklet is inserted and active */ + tasklet_schedule(&pfm_tasklet); +#endif + /* + * stored the vector of overflowed registers for use in notification + * mark that a notification/blocking is pending (arm the trap) + */ + th->pfm_pend_notify = 1; + + /* + * if we do block, then keep PMU frozen until restart + */ + if (!CTX_OVFL_NOBLOCK(ctx)) ctx->ctx_fl_frozen = 1; + + DBprintk((" process %d notify ovfl_regs=0x%lx\n", ta->pid, bv)); + } + /* + * keep PMU frozen (and overflowed bits cleared) when we have to stop, + * otherwise return a resume 'value' for PMC[0] + * + * XXX: maybe that's enough to get rid of ctx_fl_frozen ? + */ + DBprintk((" will return pmc0=0x%x\n",ctx->ctx_fl_frozen ? 0x1 : 0x0)); + return ctx->ctx_fl_frozen ? 0x1 : 0x0; } static void perfmon_interrupt (int irq, void *arg, struct pt_regs *regs) { - /* unfreeze if not spurious */ - if ( update_counters(ia64_get_pmc(0)) ) { - ia64_set_pmc(0, 0); + u64 pmc0; + struct task_struct *ta; + + pmc0 = ia64_get_pmc(0); /* slow */ + + /* + * if we have some pending bits set + * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1 + */ + if ((pmc0 & ~0x1) && (ta=PMU_OWNER())) { + + /* assumes, PMC[0].fr = 1 at this point */ + pmc0 = update_counters(ta, pmc0, regs); + + /* + * if pmu_frozen = 0 + * pmc0 = 0 and we resume monitoring right away + * else + * pmc0 = 0x1 frozen but all pending bits are cleared + */ + ia64_set_pmc(0, pmc0); ia64_srlz_d(); + } else { + printk("perfmon: Spurious PMU overflow interrupt: pmc0=0x%lx owner=%p\n", pmc0, (void *)PMU_OWNER()); } } -static struct irqaction perfmon_irqaction = { - handler: perfmon_interrupt, - flags: SA_INTERRUPT, - name: "perfmon" -}; - +/* for debug only */ static int perfmon_proc_info(char *page) { @@ -487,56 +1604,79 @@ p += sprintf(p, "PMC[0]=%lx\nPerfmon debug: %s\n", pmc0, pfm_debug ? "On" : "Off"); for(i=0; i < NR_CPUS; i++) { - if (cpu_is_online(i)) - p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i] ? pmu_owners[i]->pid: -1); + if (cpu_is_online(i)) + p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: 0); } return p - page; } +/* for debug only */ static int perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = perfmon_proc_info(page); - if (len <= off+count) *eof = 1; + if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; + *start = page + off; + len -= off; - if (len>count) len = count; - if (len<0) len = 0; + if (len>count) len = count; + if (len<0) len = 0; - return len; + return len; } -static struct proc_dir_entry *perfmon_dir; +static struct irqaction perfmon_irqaction = { + handler: perfmon_interrupt, + flags: SA_INTERRUPT, + name: "perfmon" +}; void __init perfmon_init (void) { pal_perf_mon_info_u_t pm_info; s64 status; - - irq_desc[PERFMON_IRQ].status |= IRQ_PER_CPU; - irq_desc[PERFMON_IRQ].handler = &irq_type_ia64_sapic; - setup_irq(PERFMON_IRQ, &perfmon_irqaction); - ia64_set_pmv(PERFMON_IRQ); + register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + + ia64_set_pmv(IA64_PERFMON_VECTOR); ia64_srlz_d(); - printk("perfmon: Initialized vector to %u\n",PERFMON_IRQ); + pmu_conf.pfm_is_disabled = 1; + + printk("perfmon: version %s\n", PFM_VERSION); + printk("perfmon: Interrupt vectored to %u\n", IA64_PERFMON_VECTOR); if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) { - printk(__FUNCTION__ " pal call failed (%ld)\n", status); + printk("perfmon: PAL call failed (%ld)\n", status); return; - } - pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; - - /* XXX need to use PAL instead */ + } + pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic; + pmu_conf.num_pmds = find_num_pm_regs(pmu_conf.impl_regs); + pmu_conf.num_pmcs = find_num_pm_regs(&pmu_conf.impl_regs[4]); printk("perfmon: Counters are %d bits\n", pm_info.pal_perf_mon_info_s.width); printk("perfmon: Maximum counter value 0x%lx\n", pmu_conf.perf_ovfl_val); + printk("perfmon: %ld PMC/PMD pairs\n", pmu_conf.max_counters); + printk("perfmon: %ld PMCs, %ld PMDs\n", pmu_conf.num_pmcs, pmu_conf.num_pmds); + printk("perfmon: Sampling format v%d\n", PFM_SMPL_HDR_VERSION); + + /* sanity check */ + if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) { + printk(KERN_ERR "perfmon: ERROR not enough PMC/PMD storage in kernel, perfmon is DISABLED\n"); + return; /* no need to continue anyway */ + } + /* we are all set */ + pmu_conf.pfm_is_disabled = 0; + + /* + * Insert the tasklet in the list. + * It is still disabled at this point, so it won't run + printk(__FUNCTION__" tasklet is %p state=%d, count=%d\n", &perfmon_tasklet, perfmon_tasklet.state, perfmon_tasklet.count); + */ /* * for now here for debug purposes @@ -547,7 +1687,7 @@ void perfmon_init_percpu (void) { - ia64_set_pmv(PERFMON_IRQ); + ia64_set_pmv(IA64_PERFMON_VECTOR); ia64_srlz_d(); } @@ -555,14 +1695,19 @@ * XXX: for system wide this function MUST never be called */ void -ia64_save_pm_regs (struct task_struct *ta) +pfm_save_regs (struct task_struct *ta) { - struct thread_struct *t = &ta->thread; + struct task_struct *owner; + struct thread_struct *t; u64 pmc0, psr; - int i,j; + int i; + if (ta == NULL) { + panic(__FUNCTION__" task is NULL\n"); + } + t = &ta->thread; /* - * We must maek sure that we don't loose any potential overflow + * We must make sure that we don't loose any potential overflow * interrupt while saving PMU context. In this code, external * interrupts are always enabled. */ @@ -575,94 +1720,102 @@ /* * stop monitoring: * This is the only way to stop monitoring without destroying overflow - * information in PMC[0..3]. + * information in PMC[0]. * This is the last instruction which can cause overflow when monitoring * in kernel. - * By now, we could still have an overflow interrupt in flight. + * By now, we could still have an overflow interrupt in-flight. */ - __asm__ __volatile__ ("rsm psr.up;;"::: "memory"); - + __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + + /* + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control over overflow processing from that point + * on. + * It must be an atomic operation. + */ + owner = PMU_OWNER(); + SET_PMU_OWNER(NULL); + /* * read current overflow status: * - * We may be reading stale information at this point, if we got interrupt - * just before the read(pmc0) but that's all right. However, if we did - * not get the interrupt before, this read reflects LAST state. - * + * we are guaranteed to read the final stable state */ - pmc0 = ia64_get_pmc(0); + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ /* * freeze PMU: * * This destroys the overflow information. This is required to make sure * next process does not start with monitoring on if not requested - * (PSR.up may not be enough). - * - * We could still get an overflow interrupt by now. However the handler - * will not do anything if is sees PMC[0].fr=1 but no overflow bits - * are set. So PMU will stay in frozen state. This implies that pmc0 - * will still be holding the correct unprocessed information. - * */ ia64_set_pmc(0, 1); ia64_srlz_d(); /* - * check for overflow bits set: + * Check for overflow bits and proceed manually if needed * - * If pmc0 reports PMU frozen, this means we have a pending overflow, - * therefore we invoke the handler. Handler is reentrant with regards - * to PMC[0] so it is safe to call it twice. - * - * IF pmc0 reports overflow, we need to reread current PMC[0] value - * in case the handler was invoked right after the first pmc0 read. - * it is was not invoked then pmc0==PMC[0], otherwise it's been invoked - * and overflow information has been processed, so we don't need to call. - * - * Test breakdown: - * - pmc0 & ~0x1: test if overflow happened - * - second part: check if current register reflects this as well. - * - * NOTE: testing for pmc0 & 0x1 is not enough has it would trigger call - * when PM_VALID and PMU.fr which is common when setting up registers - * just before actually starting monitors. - * - */ - if ((pmc0 & ~0x1) && ((pmc0=ia64_get_pmc(0)) &~0x1) ) { - printk(__FUNCTION__" Warning: pmc[0]=0x%lx\n", pmc0); - update_counters(pmc0); - /* - * XXX: not sure that's enough. the next task may still get the - * interrupt. - */ + * It is safe to call the interrupt handler now because it does + * not try to block the task right away. Instead it will set a + * flag and let the task proceed. The blocking will only occur + * next time the task exits from the kernel. + */ + if (pmc0 & ~0x1) { + if (owner != ta) printk(__FUNCTION__" owner=%p task=%p\n", (void *)owner, (void *)ta); + printk(__FUNCTION__" Warning: pmc[0]=0x%lx explicit call\n", pmc0); + + pmc0 = update_counters(owner, pmc0, NULL); + /* we will save the updated version of pmc0 */ } /* * restore PSR for context switch to save */ - __asm__ __volatile__ ("mov psr.l=%0;;"::"r"(psr): "memory"); + __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory"); + /* - * XXX: this will need to be extended beyong just counters + * XXX needs further optimization. + * Also must take holes into account */ - for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) { - t->pmd[i] = ia64_get_pmd(j); - t->pmc[i] = ia64_get_pmc(j); + for (i=0; i< pmu_conf.num_pmds; i++) { + t->pmd[i] = ia64_get_pmd(i); + } + + /* skip PMC[0], we handle it separately */ + for (i=1; i< pmu_conf.num_pmcs; i++) { + t->pmc[i] = ia64_get_pmc(i); } + /* - * PMU is frozen, PMU context is saved: nobody owns the PMU on this CPU - * At this point, we should not receive any pending interrupt from the - * 'switched out' task + * Throughout this code we could have gotten an overflow interrupt. It is transformed + * into a spurious interrupt as soon as we give up pmu ownership. */ - pmu_owners[smp_processor_id()] = NULL; } void -ia64_load_pm_regs (struct task_struct *ta) +pfm_load_regs (struct task_struct *ta) { struct thread_struct *t = &ta->thread; - int i,j; + pfm_context_t *ctx = ta->thread.pfm_context; + int i; + + /* + * XXX needs further optimization. + * Also must take holes into account + */ + for (i=0; i< pmu_conf.num_pmds; i++) { + ia64_set_pmd(i, t->pmd[i]); + } + + /* skip PMC[0] to avoid side effects */ + for (i=1; i< pmu_conf.num_pmcs; i++) { + ia64_set_pmc(i, t->pmc[i]); + } /* * we first restore ownership of the PMU to the 'soon to be current' @@ -670,26 +1823,277 @@ * of this function, we get an interrupt, we attribute it to the correct * task */ - pmu_owners[smp_processor_id()] = ta; + SET_PMU_OWNER(ta); + +#if 0 + /* + * check if we had pending overflow before context switching out + * If so, we invoke the handler manually, i.e. simulate interrupt. + * + * XXX: given that we do not use the tasklet anymore to stop, we can + * move this back to the pfm_save_regs() routine. + */ + if (t->pmc[0] & ~0x1) { + /* freeze set in pfm_save_regs() */ + DBprintk((" pmc[0]=0x%lx manual interrupt\n",t->pmc[0])); + update_counters(ta, t->pmc[0], NULL); + } +#endif /* - * XXX: this will need to be extended beyong just counters + * unfreeze only when possible */ - for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) { - ia64_set_pmd(j, t->pmd[i]); - ia64_set_pmc(j, t->pmc[i]); + if (ctx->ctx_fl_frozen == 0) { + ia64_set_pmc(0, 0); + ia64_srlz_d(); + } +} + + +/* + * This function is called when a thread exits (from exit_thread()). + * This is a simplified pfm_save_regs() that simply flushes hthe current + * register state into the save area taking into account any pending + * overflow. This time no notification is sent because the taks is dying + * anyway. The inline processing of overflows avoids loosing some counts. + * The PMU is frozen on exit from this call and is to never be reenabled + * again for this task. + */ +void +pfm_flush_regs (struct task_struct *ta) +{ + pfm_context_t *ctx; + u64 pmc0, psr, mask; + int i,j; + + if (ta == NULL) { + panic(__FUNCTION__" task is NULL\n"); } + ctx = ta->thread.pfm_context; + if (ctx == NULL) { + panic(__FUNCTION__" no PFM ctx is NULL\n"); + } + /* + * We must make sure that we don't loose any potential overflow + * interrupt while saving PMU context. In this code, external + * interrupts are always enabled. + */ + + /* + * save current PSR: needed because we modify it + */ + __asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory"); + + /* + * stop monitoring: + * This is the only way to stop monitoring without destroying overflow + * information in PMC[0]. + * This is the last instruction which can cause overflow when monitoring + * in kernel. + * By now, we could still have an overflow interrupt in-flight. + */ + __asm__ __volatile__ ("rsm psr.up;;"::: "memory"); + + /* + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control on overflow processing from that point + * on. + * It must be an atomic operation. + */ + SET_PMU_OWNER(NULL); + + /* + * read current overflow status: + * + * we are guaranteed to read the final stable state + */ + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ + + /* + * freeze PMU: + * + * This destroys the overflow information. This is required to make sure + * next process does not start with monitoring on if not requested + */ + ia64_set_pmc(0, 1); + ia64_srlz_d(); + + /* + * restore PSR for context switch to save + */ + __asm__ __volatile__ ("mov psr.l=%0;;srlz.i;"::"r"(psr): "memory"); + /* - * unfreeze PMU + * This loop flushes the PMD into the PFM context. + * IT also processes overflow inline. + * + * IMPORTANT: No notification is sent at this point as the process is dying. + * The implicit notification will come from a SIGCHILD or a return from a + * waitpid(). + * + * XXX: must take holes into account */ - ia64_set_pmc(0, 0); + mask = pmc0 >> PMU_FIRST_COUNTER; + for (i=0,j=PMU_FIRST_COUNTER; i< pmu_conf.max_counters; i++,j++) { + + /* collect latest results */ + ctx->ctx_pmds[i].val += ia64_get_pmd(j) & pmu_conf.perf_ovfl_val; + + /* take care of overflow inline */ + if (mask & 0x1) { + ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val; + DBprintk((" PMD[%d] overflowed pmd=0x%lx pmds.val=0x%lx\n", + j, ia64_get_pmd(j), ctx->ctx_pmds[i].val)); + } + } +} + +/* + * XXX: this routine is not very portable for PMCs + * XXX: make this routine able to work with non current context + */ +static void +ia64_reset_pmu(void) +{ + int i; + + /* PMU is frozen, no pending overflow bits */ + ia64_set_pmc(0,1); + + /* extra overflow bits + counter configs cleared */ + for(i=1; i< PMU_FIRST_COUNTER + pmu_conf.max_counters ; i++) { + ia64_set_pmc(i,0); + } + + /* opcode matcher set to all 1s */ + ia64_set_pmc(8,~0); + ia64_set_pmc(9,~0); + + /* I-EAR config cleared, plm=0 */ + ia64_set_pmc(10,0); + + /* D-EAR config cleared, PMC[11].pt must be 1 */ + ia64_set_pmc(11,1 << 28); + + /* BTB config. plm=0 */ + ia64_set_pmc(12,0); + + /* Instruction address range, PMC[13].ta must be 1 */ + ia64_set_pmc(13,1); + + /* clears all PMD registers */ + for(i=0;i< pmu_conf.num_pmds; i++) { + if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0); + } ia64_srlz_d(); } +/* + * task is the newly created task + */ +int +pfm_inherit(struct task_struct *task) +{ + pfm_context_t *ctx = current->thread.pfm_context; + pfm_context_t *nctx; + struct thread_struct *th = &task->thread; + int i, cnum; + + /* + * takes care of easiest case first + */ + if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { + DBprintk((" removing PFM context for %d\n", task->pid)); + task->thread.pfm_context = NULL; + task->thread.pfm_pend_notify = 0; + /* copy_thread() clears IA64_THREAD_PM_VALID */ + return 0; + } + nctx = pfm_context_alloc(); + if (nctx == NULL) return -ENOMEM; + + /* copy content */ + *nctx = *ctx; + + if (ctx->ctx_fl_inherit == PFM_FL_INHERIT_ONCE) { + nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; + DBprintk((" downgrading to INHERIT_NONE for %d\n", task->pid)); + } + + /* initialize counters in new context */ + for(i=0, cnum= PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++) { + nctx->ctx_pmds[i].val = nctx->ctx_pmds[i].ival & ~pmu_conf.perf_ovfl_val; + th->pmd[cnum] = nctx->ctx_pmds[i].ival & pmu_conf.perf_ovfl_val; + + } + /* clear BTB index register */ + th->pmd[16] = 0; + + /* if sampling then increment number of users of buffer */ + if (nctx->ctx_smpl_buf) { + atomic_inc(&nctx->ctx_smpl_buf->psb_refcnt); + } + + nctx->ctx_fl_frozen = 0; + nctx->ctx_ovfl_regs = 0; + sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ + + /* clear pending notification */ + th->pfm_pend_notify = 0; + + /* link with new task */ + th->pfm_context = nctx; + + DBprintk((" nctx=%p for process %d\n", (void *)nctx, task->pid)); + + /* + * the copy_thread routine automatically clears + * IA64_THREAD_PM_VALID, so we need to reenable it, if it was used by the caller + */ + if (current->thread.flags & IA64_THREAD_PM_VALID) { + DBprintk((" setting PM_VALID for %d\n", task->pid)); + th->flags |= IA64_THREAD_PM_VALID; + } + + return 0; +} + +/* called from exit_thread() */ +void +pfm_context_exit(struct task_struct *task) +{ + pfm_context_t *ctx = task->thread.pfm_context; + + if (!ctx) { + DBprintk((" invalid context for %d\n", task->pid)); + return; + } + + /* check is we have a sampling buffer attached */ + if (ctx->ctx_smpl_buf) { + pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; + + /* if only user left, then remove */ + DBprintk((" pid %d: task %d sampling psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter)); + + if (atomic_dec_and_test(&psb->psb_refcnt) ) { + rvfree(psb->psb_hdr, psb->psb_size); + vfree(psb); + DBprintk((" pid %d: cleaning task %d sampling buffer\n", current->pid, task->pid )); + } + } + DBprintk((" pid %d: task %d pfm_context is freed @%p\n", current->pid, task->pid, (void *)ctx)); + pfm_context_free(ctx); +} + #else /* !CONFIG_PERFMON */ -asmlinkage unsigned long -sys_perfmonctl (int cmd, int count, void *ptr) +asmlinkage int +sys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long arg6, long arg7, long arg8, long stack) { return -ENOSYS; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/process.c linux.ac/arch/ia64/kernel/process.c --- linux.vanilla/arch/ia64/kernel/process.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/process.c Mon Apr 16 12:37:03 2001 @@ -1,8 +1,8 @@ /* * Architecture-specific setup. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang */ #define __KERNEL_SYSCALLS__ /* see */ #include @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -27,8 +28,6 @@ #include #include -#ifdef CONFIG_IA64_NEW_UNWIND - static void do_show_stack (struct unw_frame_info *info, void *arg) { @@ -46,12 +45,9 @@ } while (unw_unwind(info) >= 0); } -#endif - void show_stack (struct task_struct *task) { -#ifdef CONFIG_IA64_NEW_UNWIND if (!task) unw_init_running(do_show_stack, 0); else { @@ -60,7 +56,6 @@ unw_init_from_blocked_task(&info, task); do_show_stack(&info, 0); } -#endif } void @@ -108,10 +103,8 @@ ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } } -#ifdef CONFIG_IA64_NEW_UNWIND if (!user_mode(regs)) show_stack(0); -#endif } void __attribute__((noreturn)) @@ -147,7 +140,7 @@ ia64_save_debug_regs(&task->thread.dbr[0]); #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) - ia64_save_pm_regs(task); + pfm_save_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_save_state(&task->thread); @@ -160,7 +153,7 @@ ia64_load_debug_regs(&task->thread.dbr[0]); #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) - ia64_load_pm_regs(task); + pfm_load_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_load_state(&task->thread); @@ -210,6 +203,7 @@ struct switch_stack *child_stack, *stack; extern char ia64_ret_from_clone; struct pt_regs *child_ptregs; + int retval = 0; #ifdef CONFIG_SMP /* @@ -290,15 +284,17 @@ if (IS_IA32_PROCESS(ia64_task_regs(current))) ia32_save_state(&p->thread); #endif - return 0; +#ifdef CONFIG_PERFMON + if (current->thread.pfm_context) + retval = pfm_inherit(p); +#endif + return retval; } -#ifdef CONFIG_IA64_NEW_UNWIND - void do_copy_regs (struct unw_frame_info *info, void *arg) { - unsigned long ar_bsp, ndirty, *krbs, addr, mask, sp, nat_bits = 0, ip; + unsigned long ar_bsp, addr, mask, sp, nat_bits = 0, ip, ar_rnat; elf_greg_t *dst = arg; struct pt_regs *pt; char nat; @@ -313,18 +309,18 @@ unw_get_sp(info, &sp); pt = (struct pt_regs *) (sp + 16); - krbs = (unsigned long *) current + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty); + ar_bsp = ia64_get_user_bsp(current, pt); /* - * Write portion of RSE backing store living on the kernel - * stack to the VM of the process. + * Write portion of RSE backing store living on the kernel stack to the VM of the + * process. */ for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) - if (ia64_peek(pt, current, addr, &val) == 0) + if (ia64_peek(current, ar_bsp, addr, &val) == 0) access_process_vm(current, addr, &val, sizeof(val), 1); + ia64_peek(current, ar_bsp, (long) ia64_rse_rnat_addr((long *) addr - 1), &ar_rnat); + /* * coredump format: * r0-r31 @@ -361,7 +357,7 @@ */ dst[46] = ar_bsp; dst[47] = pt->ar_bspstore; - unw_get_ar(info, UNW_AR_RNAT, &dst[48]); + dst[48] = ar_rnat; unw_get_ar(info, UNW_AR_CCV, &dst[49]); unw_get_ar(info, UNW_AR_UNAT, &dst[50]); unw_get_ar(info, UNW_AR_FPSR, &dst[51]); @@ -391,91 +387,16 @@ memcpy(dst + 32, current->thread.fph, 96*16); } -#endif /* CONFIG_IA64_NEW_UNWIND */ - void ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst) { -#ifdef CONFIG_IA64_NEW_UNWIND unw_init_running(do_copy_regs, dst); -#else - struct switch_stack *sw = ((struct switch_stack *) pt) - 1; - unsigned long ar_ec, cfm, ar_bsp, ndirty, *krbs, addr; - - ar_ec = (sw->ar_pfs >> 52) & 0x3f; - - cfm = pt->cr_ifs & ((1UL << 63) - 1); - if ((pt->cr_ifs & (1UL << 63)) == 0) { - /* if cr_ifs isn't valid, we got here through a syscall or a break */ - cfm = sw->ar_pfs & ((1UL << 38) - 1); - } - - krbs = (unsigned long *) current + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty); - - /* - * Write portion of RSE backing store living on the kernel - * stack to the VM of the process. - */ - for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) { - long val; - if (ia64_peek(pt, current, addr, &val) == 0) - access_process_vm(current, addr, &val, sizeof(val), 1); - } - - /* r0-r31 - * NaT bits (for r0-r31; bit N == 1 iff rN is a NaT) - * predicate registers (p0-p63) - * b0-b7 - * ip cfm user-mask - * ar.rsc ar.bsp ar.bspstore ar.rnat - * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec - */ - memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ - - /* r0 is zero */ dst[ 1] = pt->r1; dst[ 2] = pt->r2; dst[ 3] = pt->r3; - dst[ 4] = sw->r4; dst[ 5] = sw->r5; dst[ 6] = sw->r6; dst[ 7] = sw->r7; - dst[ 8] = pt->r8; dst[ 9] = pt->r9; dst[10] = pt->r10; dst[11] = pt->r11; - dst[12] = pt->r12; dst[13] = pt->r13; dst[14] = pt->r14; dst[15] = pt->r15; - memcpy(dst + 16, &pt->r16, 16*8); /* r16-r31 are contiguous */ - - dst[32] = ia64_get_nat_bits(pt, sw); - dst[33] = pt->pr; - - /* branch regs: */ - dst[34] = pt->b0; dst[35] = sw->b1; dst[36] = sw->b2; dst[37] = sw->b3; - dst[38] = sw->b4; dst[39] = sw->b5; dst[40] = pt->b6; dst[41] = pt->b7; - - dst[42] = pt->cr_iip + ia64_psr(pt)->ri; - dst[43] = pt->cr_ifs; - dst[44] = pt->cr_ipsr & IA64_PSR_UM; - - dst[45] = pt->ar_rsc; dst[46] = ar_bsp; dst[47] = pt->ar_bspstore; dst[48] = pt->ar_rnat; - dst[49] = pt->ar_ccv; dst[50] = pt->ar_unat; dst[51] = sw->ar_fpsr; dst[52] = pt->ar_pfs; - dst[53] = sw->ar_lc; dst[54] = (sw->ar_pfs >> 52) & 0x3f; -#endif /* !CONFIG_IA64_NEW_UNWIND */ } int dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) { -#ifdef CONFIG_IA64_NEW_UNWIND unw_init_running(do_dump_fpu, dst); -#else - struct switch_stack *sw = ((struct switch_stack *) pt) - 1; - - memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */ - - /* f0 is 0.0 */ /* f1 is 1.0 */ dst[2] = sw->f2; dst[3] = sw->f3; - dst[4] = sw->f4; dst[5] = sw->f5; dst[6] = pt->f6; dst[7] = pt->f7; - dst[8] = pt->f8; dst[9] = pt->f9; - memcpy(dst + 10, &sw->f10, 22*16); /* f10-f31 are contiguous */ - - ia64_flush_fph(current); - if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) - memcpy(dst + 32, current->thread.fph, 96*16); -#endif return 1; /* f0-f31 are always valid so we always return 1 */ } @@ -523,6 +444,15 @@ #endif } +#ifdef CONFIG_PERFMON +void +release_thread (struct task_struct *task) +{ + if (task->thread.pfm_context) + pfm_context_exit(task); +} +#endif + /* * Clean up state associated with current thread. This is called when * the thread calls exit(). @@ -545,7 +475,7 @@ * we garantee no race. this call we also stop * monitoring */ - ia64_save_pm_regs(current); + pfm_flush_regs(current); /* * make sure that switch_to() will not save context again */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/ptrace.c linux.ac/arch/ia64/kernel/ptrace.c --- linux.vanilla/arch/ia64/kernel/ptrace.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/kernel/ptrace.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Kernel support for the ptrace() and syscall tracing interfaces. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang * * Derived from the x86 and Alpha versions. Most of the code in here * could actually be factored into a common set of routines. @@ -22,6 +22,7 @@ #include #include #include +#include /* * Bits in the PSR that we allow ptrace() to change: @@ -36,8 +37,6 @@ (IA64_PSR_UM | IA64_PSR_DB | IA64_PSR_IS | IA64_PSR_ID | IA64_PSR_DD | IA64_PSR_RI) #define IPSR_READ_MASK IPSR_WRITE_MASK -#ifdef CONFIG_IA64_NEW_UNWIND - #define PTRACE_DEBUG 1 #if PTRACE_DEBUG @@ -97,57 +96,6 @@ # undef PUT_BITS } -#else /* !CONFIG_IA64_NEW_UNWIND */ - -/* - * Collect the NaT bits for r1-r31 from sw->caller_unat and - * sw->ar_unat and return a NaT bitset where bit i is set iff the NaT - * bit of register i is set. - */ -long -ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw) -{ -# define GET_BITS(str, first, last, unat) \ - ({ \ - unsigned long bit = ia64_unat_pos(&str->r##first); \ - unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \ - (ia64_rotl(unat, first) >> bit) & mask; \ - }) - unsigned long val; - - val = GET_BITS(pt, 1, 3, sw->caller_unat); - val |= GET_BITS(pt, 12, 15, sw->caller_unat); - val |= GET_BITS(pt, 8, 11, sw->caller_unat); - val |= GET_BITS(pt, 16, 31, sw->caller_unat); - val |= GET_BITS(sw, 4, 7, sw->ar_unat); - return val; - -# undef GET_BITS -} - -/* - * Store the NaT bitset NAT in pt->caller_unat and sw->ar_unat. - */ -void -ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat) -{ -# define PUT_BITS(str, first, last, nat) \ - ({ \ - unsigned long bit = ia64_unat_pos(&str->r##first); \ - unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit; \ - (ia64_rotr(nat, first) << bit) & mask; \ - }) - sw->caller_unat = PUT_BITS(pt, 1, 3, nat); - sw->caller_unat |= PUT_BITS(pt, 12, 15, nat); - sw->caller_unat |= PUT_BITS(pt, 8, 11, nat); - sw->caller_unat |= PUT_BITS(pt, 16, 31, nat); - sw->ar_unat = PUT_BITS(sw, 4, 7, nat); - -# undef PUT_BITS -} - -#endif /* !CONFIG_IA64_NEW_UNWIND */ - #define IA64_MLX_TEMPLATE 0x2 #define IA64_MOVL_OPCODE 6 @@ -215,7 +163,7 @@ * | slot01 | > child_regs->ar_rnat * +--------+ | * | slot02 | / kernel rbs - * +--------+ +--------+ + * +--------+ +--------+ * <- child_regs->ar_bspstore | slot61 | <-- krbs * +- - - - + +--------+ * | slot62 | @@ -275,7 +223,7 @@ /* some bits need to be merged in from pt->ar_rnat */ kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); urnat = (pt->ar_rnat & ~kmask); - } + } if (rnat0_kaddr >= kbsp) { rnat0 = sw->ar_rnat; } else if (rnat0_kaddr > krbs) { @@ -319,7 +267,7 @@ /* some bits need to be place in pt->ar_rnat: */ kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); pt->ar_rnat = (pt->ar_rnat & kmask) | (rnat & ~kmask); - } + } /* * Note: Section 11.1 of the EAS guarantees that bit 63 of an * rnat slot is ignored. so we don't have to clear it here. @@ -342,9 +290,9 @@ } long -ia64_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long *val) +ia64_peek (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long *val) { - unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr; + unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp; struct switch_stack *child_stack; struct pt_regs *child_regs; size_t copied; @@ -352,35 +300,22 @@ laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); -#ifdef CONFIG_IA64_NEW_UNWIND child_stack = (struct switch_stack *) (child->thread.ksp + 16); -#else - child_stack = (struct switch_stack *) child_regs - 1; -#endif bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); - rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs); - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) { + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) { /* - * Attempt to read the RBS in an area that's actually - * on the kernel RBS => read the corresponding bits in - * the kernel RBS. + * Attempt to read the RBS in an area that's actually on the kernel RBS => + * read the corresponding bits in the kernel RBS. */ if (ia64_rse_is_rnat_slot(laddr)) ret = get_rnat(child_regs, child_stack, krbs, laddr); else { - regnum = ia64_rse_num_regs(bspstore, laddr); - laddr = ia64_rse_skip_regs(krbs, regnum); - if (regnum >= krbs_num_regs) { + if (laddr >= ubsp) ret = 0; - } else { - if ((unsigned long) laddr >= (unsigned long) high_memory) { - printk("yikes: trying to access long at %p\n", - (void *) laddr); - return -EIO; - } - ret = *laddr; + else { + regnum = ia64_rse_num_regs(bspstore, laddr); + ret = *ia64_rse_skip_regs(krbs, regnum); } } } else { @@ -393,36 +328,28 @@ } long -ia64_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long val) +ia64_poke (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long val) { - unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr; + unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp; struct switch_stack *child_stack; struct pt_regs *child_regs; laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); -#ifdef CONFIG_IA64_NEW_UNWIND child_stack = (struct switch_stack *) (child->thread.ksp + 16); -#else - child_stack = (struct switch_stack *) child_regs - 1; -#endif bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); - rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs); - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) { + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) { /* - * Attempt to write the RBS in an area that's actually - * on the kernel RBS => write the corresponding bits - * in the kernel RBS. + * Attempt to write the RBS in an area that's actually on the kernel RBS + * => write the corresponding bits in the kernel RBS. */ if (ia64_rse_is_rnat_slot(laddr)) put_rnat(child_regs, child_stack, krbs, laddr, val); else { - regnum = ia64_rse_num_regs(bspstore, laddr); - laddr = ia64_rse_skip_regs(krbs, regnum); - if (regnum < krbs_num_regs) { - *laddr = val; + if (laddr < ubsp) { + regnum = ia64_rse_num_regs(bspstore, laddr); + *ia64_rse_skip_regs(krbs, regnum) = val; } } } else if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) { @@ -432,83 +359,76 @@ } /* - * Synchronize (i.e, write) the RSE backing store living in kernel - * space to the VM of the indicated child process. - * - * If new_bsp is non-zero, the bsp will (effectively) be updated to - * the new value upon resumption of the child process. This is - * accomplished by setting the loadrs value to zero and the bspstore - * value to the new bsp value. - * - * When new_bsp and force_loadrs_to_zero are both 0, the register - * backing store in kernel space is written to user space and the - * loadrs and bspstore values are left alone. - * - * When new_bsp is zero and force_loadrs_to_zero is 1 (non-zero), - * loadrs is set to 0, and the bspstore value is set to the old bsp - * value. This will cause the stacked registers (r32 and up) to be - * obtained entirely from the child's memory space rather than - * from the kernel. (This makes it easier to write code for - * modifying the stacked registers in multi-threaded programs.) - * - * Note: I had originally written this function without the - * force_loadrs_to_zero parameter; it was written so that loadrs would - * always be set to zero. But I had problems with certain system - * calls apparently causing a portion of the RBS to be zeroed. (I - * still don't understand why this was happening.) Anyway, it'd - * definitely less intrusive to leave loadrs and bspstore alone if - * possible. + * Calculate the user-level address that would have been in ar.bsp had the user executed a + * "cover" instruction right before entering the kernel. */ -static long -sync_kernel_register_backing_store (struct task_struct *child, - long new_bsp, - int force_loadrs_to_zero) +unsigned long +ia64_get_user_bsp (struct task_struct *child, struct pt_regs *pt) { - unsigned long *krbs, bspstore, *kbspstore, bsp, rbs_end, addr, val; - long ndirty, ret = 0; - struct pt_regs *child_regs = ia64_task_regs(child); - -#ifdef CONFIG_IA64_NEW_UNWIND + unsigned long *krbs, *bspstore, cfm; struct unw_frame_info info; - unsigned long cfm, sof; - - unw_init_from_blocked_task(&info, child); - if (unw_unwind_to_user(&info) < 0) - return -1; - - unw_get_bsp(&info, (unsigned long *) &kbspstore); + long ndirty; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19)); - bspstore = child_regs->ar_bspstore; - bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty); - - cfm = child_regs->cr_ifs; - if (!(cfm & (1UL << 63))) - unw_get_cfm(&info, &cfm); - sof = (cfm & 0x7f); - rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, sof); -#else - struct switch_stack *child_stack; - unsigned long krbs_num_regs; + bspstore = (unsigned long *) pt->ar_bspstore; + ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - child_stack = (struct switch_stack *) child_regs - 1; - kbspstore = (unsigned long *) child_stack->ar_bspstore; - krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19)); - bspstore = child_regs->ar_bspstore; - bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty); - krbs_num_regs = ia64_rse_num_regs(krbs, kbspstore); - rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, krbs_num_regs); -#endif + if ((long) pt->cr_ifs >= 0) { + /* + * If bit 63 of cr.ifs is cleared, the kernel was entered via a system + * call and we need to recover the CFM that existed on entry to the + * kernel by unwinding the kernel stack. + */ + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) == 0) { + unw_get_cfm(&info, &cfm); + ndirty += (cfm & 0x7f); + } + } + return (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); +} - /* Return early if nothing to do */ - if (bsp == new_bsp) +/* + * Synchronize (i.e, write) the RSE backing store living in kernel space to the VM of the + * indicated child process. + * + * If new_bsp is non-zero, the bsp will (effectively) be updated to the new value upon + * resumption of the child process. This is accomplished by setting the loadrs value to + * zero and the bspstore value to the new bsp value. + * + * When new_bsp and flush_user_rbs are both 0, the register backing store in kernel space + * is written to user space and the loadrs and bspstore values are left alone. + * + * When new_bsp is zero and flush_user_rbs is 1 (non-zero), loadrs is set to 0, and the + * bspstore value is set to the old bsp value. This will cause the stacked registers (r32 + * and up) to be obtained entirely from the child's memory space rather than from the + * kernel. (This makes it easier to write code for modifying the stacked registers in + * multi-threaded programs.) + * + * Note: I had originally written this function without the flush_user_rbs parameter; it + * was written so that loadrs would always be set to zero. But I had problems with + * certain system calls apparently causing a portion of the RBS to be zeroed. (I still + * don't understand why this was happening.) Anyway, it'd definitely less intrusive to + * leave loadrs and bspstore alone if possible. + */ +static long +sync_kernel_register_backing_store (struct task_struct *child, long user_bsp, long new_bsp, + int flush_user_rbs) +{ + struct pt_regs *child_regs = ia64_task_regs(child); + unsigned long addr, val; + long ret; + + /* + * Return early if nothing to do. Note that new_bsp will be zero if the caller + * wants to force synchronization without changing bsp. + */ + if (user_bsp == new_bsp) return 0; /* Write portion of backing store living on kernel stack to the child's VM. */ - for (addr = bspstore; addr < rbs_end; addr += 8) { - ret = ia64_peek(child_regs, child, addr, &val); + for (addr = child_regs->ar_bspstore; addr < user_bsp; addr += 8) { + ret = ia64_peek(child, user_bsp, addr, &val); if (ret != 0) return ret; if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) @@ -516,27 +436,26 @@ } if (new_bsp != 0) { - force_loadrs_to_zero = 1; - bsp = new_bsp; + flush_user_rbs = 1; + user_bsp = new_bsp; } - if (force_loadrs_to_zero) { + if (flush_user_rbs) { child_regs->loadrs = 0; - child_regs->ar_bspstore = bsp; + child_regs->ar_bspstore = user_bsp; } - - return ret; + return 0; } static void -sync_thread_rbs (struct task_struct *child, struct mm_struct *mm, int make_writable) +sync_thread_rbs (struct task_struct *child, long bsp, struct mm_struct *mm, int make_writable) { struct task_struct *p; read_lock(&tasklist_lock); { for_each_task(p) { if (p->mm == mm && p->state != TASK_RUNNING) - sync_kernel_register_backing_store(p, 0, make_writable); + sync_kernel_register_backing_store(p, bsp, 0, make_writable); } } read_unlock(&tasklist_lock); @@ -588,10 +507,6 @@ psr->dfh = 1; } -#ifdef CONFIG_IA64_NEW_UNWIND - -#include - static int access_fr (struct unw_frame_info *info, int regnum, int hi, unsigned long *data, int write_access) { @@ -613,7 +528,7 @@ static int access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) { - unsigned long *ptr, *rbs, *bspstore, ndirty, regnum; + unsigned long *ptr, regnum, bsp, rnat_addr; struct switch_stack *sw; struct unw_frame_info info; struct pt_regs *pt; @@ -710,36 +625,16 @@ /* scratch state */ switch (addr) { case PT_AR_BSP: + bsp = ia64_get_user_bsp(child, pt); if (write_access) - /* FIXME? Account for lack of ``cover'' in the syscall case */ - return sync_kernel_register_backing_store(child, *data, 1); + return sync_kernel_register_backing_store(child, bsp, *data, 1); else { - rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - bspstore = (unsigned long *) pt->ar_bspstore; - ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19)); - - /* - * If we're in a system call, no ``cover'' was done. So to - * make things uniform, we'll add the appropriate displacement - * onto bsp if we're in a system call. - */ - if (!(pt->cr_ifs & (1UL << 63))) { - struct unw_frame_info info; - unsigned long cfm; - - unw_init_from_blocked_task(&info, child); - if (unw_unwind_to_user(&info) < 0) - return -1; - - unw_get_cfm(&info, &cfm); - ndirty += cfm & 0x7f; - } - *data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); + *data = bsp; return 0; } case PT_CFM: - if (pt->cr_ifs & (1UL << 63)) { + if ((long) pt->cr_ifs < 0) { if (write_access) pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL) | (*data & 0x3fffffffffUL)); @@ -770,7 +665,15 @@ *data = (pt->cr_ipsr & IPSR_READ_MASK); return 0; - case PT_R1: case PT_R2: case PT_R3: + case PT_AR_RNAT: + bsp = ia64_get_user_bsp(child, pt); + rnat_addr = (long) ia64_rse_rnat_addr((long *) bsp - 1); + if (write_access) + return ia64_poke(child, bsp, rnat_addr, *data); + else + return ia64_peek(child, bsp, rnat_addr, data); + + case PT_R1: case PT_R2: case PT_R3: case PT_R8: case PT_R9: case PT_R10: case PT_R11: case PT_R12: case PT_R13: case PT_R14: case PT_R15: case PT_R16: case PT_R17: case PT_R18: case PT_R19: @@ -781,7 +684,7 @@ case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: case PT_AR_BSPSTORE: - case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT: + case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: /* scratch register */ ptr = (unsigned long *) ((long) pt + addr - PT_CR_IPSR); @@ -799,7 +702,7 @@ if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { child->thread.flags |= IA64_THREAD_DBG_VALID; memset(child->thread.dbr, 0, sizeof(child->thread.dbr)); - memset(child->thread.ibr, 0, sizeof( child->thread.ibr)); + memset(child->thread.ibr, 0, sizeof(child->thread.ibr)); } if (addr >= PT_IBR) { regnum = (addr - PT_IBR) >> 3; @@ -830,173 +733,13 @@ return 0; } -#else /* !CONFIG_IA64_NEW_UNWIND */ - -static int -access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) -{ - unsigned long *ptr = NULL, *rbs, *bspstore, ndirty, regnum; - struct switch_stack *sw; - struct pt_regs *pt; - - if ((addr & 0x7) != 0) - return -1; - - if (addr < PT_F127+16) { - /* accessing fph */ - if (write_access) - ia64_sync_fph(child); - else - ia64_flush_fph(child); - ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); - } else if (addr < PT_F9+16) { - /* accessing switch_stack or pt_regs: */ - pt = ia64_task_regs(child); - sw = (struct switch_stack *) pt - 1; - - switch (addr) { - case PT_NAT_BITS: - if (write_access) - ia64_put_nat_bits(pt, sw, *data); - else - *data = ia64_get_nat_bits(pt, sw); - return 0; - - case PT_AR_BSP: - if (write_access) - /* FIXME? Account for lack of ``cover'' in the syscall case */ - return sync_kernel_register_backing_store(child, *data, 1); - else { - rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - bspstore = (unsigned long *) pt->ar_bspstore; - ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19)); - - /* - * If we're in a system call, no ``cover'' was done. So to - * make things uniform, we'll add the appropriate displacement - * onto bsp if we're in a system call. - */ - if (!(pt->cr_ifs & (1UL << 63))) - ndirty += sw->ar_pfs & 0x7f; - *data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); - return 0; - } - - case PT_CFM: - if (write_access) { - if (pt->cr_ifs & (1UL << 63)) - pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL) - | (*data & 0x3fffffffffUL)); - else - sw->ar_pfs = ((sw->ar_pfs & ~0x3fffffffffUL) - | (*data & 0x3fffffffffUL)); - return 0; - } else { - if ((pt->cr_ifs & (1UL << 63)) == 0) - *data = sw->ar_pfs; - else - /* return only the CFM */ - *data = pt->cr_ifs & 0x3fffffffffUL; - return 0; - } - - case PT_CR_IPSR: - if (write_access) - pt->cr_ipsr = ((*data & IPSR_WRITE_MASK) - | (pt->cr_ipsr & ~IPSR_WRITE_MASK)); - else - *data = (pt->cr_ipsr & IPSR_READ_MASK); - return 0; - - case PT_AR_EC: - if (write_access) - sw->ar_pfs = (((*data & 0x3f) << 52) - | (sw->ar_pfs & ~(0x3fUL << 52))); - else - *data = (sw->ar_pfs >> 52) & 0x3f; - break; - - case PT_R1: case PT_R2: case PT_R3: - case PT_R4: case PT_R5: case PT_R6: case PT_R7: - case PT_R8: case PT_R9: case PT_R10: case PT_R11: - case PT_R12: case PT_R13: case PT_R14: case PT_R15: - case PT_R16: case PT_R17: case PT_R18: case PT_R19: - case PT_R20: case PT_R21: case PT_R22: case PT_R23: - case PT_R24: case PT_R25: case PT_R26: case PT_R27: - case PT_R28: case PT_R29: case PT_R30: case PT_R31: - case PT_B0: case PT_B1: case PT_B2: case PT_B3: - case PT_B4: case PT_B5: case PT_B6: case PT_B7: - case PT_F2: case PT_F2+8: case PT_F3: case PT_F3+8: - case PT_F4: case PT_F4+8: case PT_F5: case PT_F5+8: - case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: - case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: - case PT_F10: case PT_F10+8: case PT_F11: case PT_F11+8: - case PT_F12: case PT_F12+8: case PT_F13: case PT_F13+8: - case PT_F14: case PT_F14+8: case PT_F15: case PT_F15+8: - case PT_F16: case PT_F16+8: case PT_F17: case PT_F17+8: - case PT_F18: case PT_F18+8: case PT_F19: case PT_F19+8: - case PT_F20: case PT_F20+8: case PT_F21: case PT_F21+8: - case PT_F22: case PT_F22+8: case PT_F23: case PT_F23+8: - case PT_F24: case PT_F24+8: case PT_F25: case PT_F25+8: - case PT_F26: case PT_F26+8: case PT_F27: case PT_F27+8: - case PT_F28: case PT_F28+8: case PT_F29: case PT_F29+8: - case PT_F30: case PT_F30+8: case PT_F31: case PT_F31+8: - case PT_AR_BSPSTORE: - case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT: - case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: - case PT_AR_LC: - ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS); - break; - - default: - /* disallow accessing anything else... */ - return -1; - } - } else { - - /* access debug registers */ - - if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { - child->thread.flags |= IA64_THREAD_DBG_VALID; - memset(child->thread.dbr, 0, sizeof child->thread.dbr); - memset(child->thread.ibr, 0, sizeof child->thread.ibr); - } - if (addr >= PT_IBR) { - regnum = (addr - PT_IBR) >> 3; - ptr = &child->thread.ibr[0]; - } else { - regnum = (addr - PT_DBR) >> 3; - ptr = &child->thread.dbr[0]; - } - - if (regnum >= 8) - return -1; - - ptr += regnum; - - if (write_access) - /* don't let the user set kernel-level breakpoints... */ - *ptr = *data & ~(7UL << 56); - else - *data = *ptr; - return 0; - } - if (write_access) - *ptr = *data; - else - *data = *ptr; - return 0; -} - -#endif /* !CONFIG_IA64_NEW_UNWIND */ - asmlinkage long sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, long arg4, long arg5, long arg6, long arg7, long stack) { - struct pt_regs *regs = (struct pt_regs *) &stack; + struct pt_regs *pt, *regs = (struct pt_regs *) &stack; struct task_struct *child; - unsigned long flags; + unsigned long flags, bsp; long ret; lock_kernel(); @@ -1031,10 +774,10 @@ (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)) + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) @@ -1065,10 +808,13 @@ if (child->p_pptr != current) goto out_tsk; + pt = ia64_task_regs(child); + switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { + bsp = ia64_get_user_bsp(child, pt); + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { struct mm_struct *mm; long do_sync; @@ -1079,9 +825,9 @@ } task_unlock(child); if (do_sync) - sync_thread_rbs(child, mm, 0); + sync_thread_rbs(child, bsp, mm, 0); } - ret = ia64_peek(regs, child, addr, &data); + ret = ia64_peek(child, bsp, addr, &data); if (ret == 0) { ret = data; regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ @@ -1090,7 +836,8 @@ case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { + bsp = ia64_get_user_bsp(child, pt); + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { struct mm_struct *mm; long do_sync; @@ -1101,9 +848,9 @@ } task_unlock(child); if (do_sync) - sync_thread_rbs(child, mm, 1); + sync_thread_rbs(child, bsp, mm, 1); } - ret = ia64_poke(regs, child, addr, data); + ret = ia64_poke(child, bsp, addr, data); goto out_tsk; case PTRACE_PEEKUSR: /* read the word at addr in the USER area */ @@ -1125,21 +872,19 @@ case PTRACE_GETSIGINFO: ret = -EIO; - if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) - || child->thread.siginfo == 0) + if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) || !child->thread.siginfo) goto out_tsk; - copy_to_user((siginfo_t *) data, child->thread.siginfo, sizeof (siginfo_t)); - ret = 0; + ret = copy_siginfo_to_user((siginfo_t *) data, child->thread.siginfo); goto out_tsk; - break; + case PTRACE_SETSIGINFO: ret = -EIO; if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t)) || child->thread.siginfo == 0) goto out_tsk; - copy_from_user(child->thread.siginfo, (siginfo_t *) data, sizeof (siginfo_t)); - ret = 0; + ret = copy_siginfo_from_user(child->thread.siginfo, (siginfo_t *) data); goto out_tsk; + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; @@ -1152,8 +897,8 @@ child->exit_code = data; /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(ia64_task_regs(child))->ss = 0; - ia64_psr(ia64_task_regs(child))->tb = 0; + ia64_psr(pt)->ss = 0; + ia64_psr(pt)->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; @@ -1173,8 +918,8 @@ child->exit_code = SIGKILL; /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(ia64_task_regs(child))->ss = 0; - ia64_psr(ia64_task_regs(child))->tb = 0; + ia64_psr(pt)->ss = 0; + ia64_psr(pt)->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; @@ -1191,9 +936,9 @@ child->ptrace &= ~PT_TRACESYS; if (request == PTRACE_SINGLESTEP) { - ia64_psr(ia64_task_regs(child))->ss = 1; + ia64_psr(pt)->ss = 1; } else { - ia64_psr(ia64_task_regs(child))->tb = 1; + ia64_psr(pt)->tb = 1; } child->exit_code = data; @@ -1219,8 +964,8 @@ write_unlock_irqrestore(&tasklist_lock, flags); /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(ia64_task_regs(child))->ss = 0; - ia64_psr(ia64_task_regs(child))->tb = 0; + ia64_psr(pt)->ss = 0; + ia64_psr(pt)->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/semaphore.c linux.ac/arch/ia64/kernel/semaphore.c --- linux.vanilla/arch/ia64/kernel/semaphore.c Sun Nov 12 03:02:40 2000 +++ linux.ac/arch/ia64/kernel/semaphore.c Wed Apr 18 13:47:54 2001 @@ -155,180 +155,3 @@ spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } - -/* - * Helper routines for rw semaphores. These could be optimized some - * more, but since they're off the critical path, I prefer clarity for - * now... - */ - -/* - * This gets called if we failed to acquire the lock, but we're biased - * to acquire the lock by virtue of causing the count to change from 0 - * to -1. Being biased, we sleep and attempt to grab the lock until - * we succeed. When this function returns, we own the lock. - */ -static inline void -down_read_failed_biased (struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->read_bias_granted) - schedule(); - } - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - -/* - * This gets called if we failed to acquire the lock and we are not - * biased to acquire the lock. We undo the decrement that was - * done earlier, go to sleep, and then attempt to re-acquire the - * lock afterwards. - */ -static inline void -down_read_failed (struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* - * Undo the decrement we did in down_read() and check if we - * need to wake up someone. - */ - __up_read(sem); - - add_wait_queue(&sem->wait, &wait); - while (sem->count < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (sem->count >= 0) - break; - schedule(); - } - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - -/* - * Wait for the lock to become unbiased. Readers are non-exclusive. - */ -void -__down_read_failed (struct rw_semaphore *sem, long count) -{ - while (1) { - if (count == -1) { - down_read_failed_biased(sem); - return; - } - /* unbiased */ - down_read_failed(sem); - - count = ia64_fetch_and_add(-1, &sem->count); - if (count >= 0) - return; - } -} - -static inline void -down_write_failed_biased (struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* put ourselves at the end of the list */ - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); - - for (;;) { - if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->write_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* - * If the lock is currently unbiased, awaken the sleepers - * FIXME: this wakes up the readers early in a bit of a - * stampede -> bad! - */ - if (sem->count >= 0) - wake_up(&sem->wait); -} - - -static inline void -down_write_failed (struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __up_write(sem); /* this takes care of granting the lock */ - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (sem->count < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (sem->count >= 0) - break; /* we must attempt to acquire or bias the lock */ - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - - -/* - * Wait for the lock to become unbiased. Since we're a writer, we'll - * make ourselves exclusive. - */ -void -__down_write_failed (struct rw_semaphore *sem, long count) -{ - long old_count; - - while (1) { - if (count == -RW_LOCK_BIAS) { - down_write_failed_biased(sem); - return; - } - down_write_failed(sem); - - do { - old_count = sem->count; - count = old_count - RW_LOCK_BIAS; - } while (cmpxchg_acq(&sem->count, old_count, count) != old_count); - - if (count == 0) - return; - } -} - -void -__rwsem_wake (struct rw_semaphore *sem, long count) -{ - wait_queue_head_t *wq; - - if (count == 0) { - /* wake a writer */ - if (xchg(&sem->write_bias_granted, 1)) - BUG(); - wq = &sem->write_bias_wait; - } else { - /* wake reader(s) */ - if (xchg(&sem->read_bias_granted, 1)) - BUG(); - wq = &sem->wait; - } - wake_up(wq); /* wake up everyone on the wait queue */ -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/setup.c linux.ac/arch/ia64/kernel/setup.c --- linux.vanilla/arch/ia64/kernel/setup.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/setup.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Architecture-specific setup. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang * Copyright (C) 1998, 1999 Stephane Eranian * Copyright (C) 2000, Rohit Seth * Copyright (C) 1999 VA Linux Systems @@ -42,16 +42,20 @@ # include #endif +#if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE) +# error "struct cpuinfo_ia64 too big!" +#endif + extern char _end; /* cpu_data[0] is data for the bootstrap processor: */ -struct cpuinfo_ia64 cpu_data[NR_CPUS]; +struct cpuinfo_ia64 cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section"))); unsigned long ia64_cycles_per_usec; -struct ia64_boot_param ia64_boot_param; +struct ia64_boot_param *ia64_boot_param; struct screen_info screen_info; /* This tells _start which CPU is booting. */ -int cpu_now_booting = 0; +int cpu_now_booting; #ifdef CONFIG_SMP volatile unsigned long cpu_online_map; @@ -119,14 +123,7 @@ unw_init(); - /* - * The secondary bootstrap loader passes us the boot - * parameters at the beginning of the ZERO_PAGE, so let's - * stash away those values before ZERO_PAGE gets cleared out. - */ - memcpy(&ia64_boot_param, (void *) ZERO_PAGE_ADDR, sizeof(ia64_boot_param)); - - *cmdline_p = __va(ia64_boot_param.command_line); + *cmdline_p = __va(ia64_boot_param->command_line); strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ @@ -140,9 +137,8 @@ * change APIs, they'd do things for the better. Grumble... */ bootmap_start = PAGE_ALIGN(__pa(&_end)); - if (ia64_boot_param.initrd_size) - bootmap_start = PAGE_ALIGN(bootmap_start - + ia64_boot_param.initrd_size); + if (ia64_boot_param->initrd_size) + bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param->initrd_size); bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn); efi_memmap_walk(free_available_memory, 0); @@ -150,7 +146,7 @@ reserve_bootmem(bootmap_start, bootmap_size); #ifdef CONFIG_BLK_DEV_INITRD - initrd_start = ia64_boot_param.initrd_start; + initrd_start = ia64_boot_param->initrd_start; if (initrd_start) { u64 start, size; @@ -163,16 +159,16 @@ "for initrd, please upgrade the loader\n"); else #endif - /* + /* * The loader ONLY passes physical addresses */ initrd_start = (unsigned long)__va(initrd_start); - initrd_end = initrd_start+ia64_boot_param.initrd_size; + initrd_end = initrd_start+ia64_boot_param->initrd_size; start = initrd_start; - size = ia64_boot_param.initrd_size; + size = ia64_boot_param->initrd_size; printk("Initial ramdisk at: 0x%p (%lu bytes)\n", - (void *) initrd_start, ia64_boot_param.initrd_size); + (void *) initrd_start, ia64_boot_param->initrd_size); /* * The kernel end and the beginning of initrd can be @@ -218,19 +214,19 @@ /* process SAL system table: */ ia64_sal_init(efi.sal_systab); -#ifdef CONFIG_SMP - current->processor = 0; - cpu_physical_id(0) = hard_smp_processor_id(); -#endif /* * Set `iobase' to the appropriate address in region 6 * (uncached access range) */ - __asm__ ("mov %0=ar.k0;;" : "=r"(ia64_iobase)); + ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE); ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET); cpu_init(); /* initialize the bootstrap CPU */ +#ifdef CONFIG_SMP + cpu_physical_id(0) = hard_smp_processor_id(); +#endif + #ifdef CONFIG_IA64_GENERIC machvec_init(acpi_get_sysname()); #endif @@ -239,7 +235,7 @@ if (efi.acpi20) { /* Parse the ACPI 2.0 tables */ acpi20_parse(efi.acpi20); - } else + } else #endif if (efi.acpi) { /* Parse the ACPI tables */ @@ -259,8 +255,8 @@ ia64_mca_init(); #endif - paging_init(); platform_setup(cmdline_p); + paging_init(); } /* @@ -325,7 +321,7 @@ c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, c->itc_freq / 1000000, c->itc_freq % 1000000, lpj*HZ/500000, (lpj*HZ/5000) % 100); - } + } return p - buffer; } @@ -362,8 +358,6 @@ for (i = 0; i < 5; ++i) cpuid.bits[i] = ia64_get_cpuid(i); - memset(c, 0, sizeof(struct cpuinfo_ia64)); - memcpy(c->vendor, cpuid.field.vendor, 16); c->ppn = cpuid.field.ppn; c->number = cpuid.field.number; @@ -382,12 +376,6 @@ smp_processor_id(), impl_va_msb + 1, phys_addr_size); c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1)); c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1)); - -#ifdef CONFIG_IA64_SOFTSDV_HACKS - /* BUG: SoftSDV doesn't support the cpuid registers. */ - if (c->vendor[0] == '\0') - memcpy(c->vendor, "Intel", 6); -#endif } /* @@ -397,12 +385,18 @@ void cpu_init (void) { - extern void __init ia64_rid_init (void); - extern void __init ia64_tlb_init (void); + extern void __init ia64_mmu_init (void); + unsigned long num_phys_stacked; pal_vm_info_2_u_t vmi; unsigned int max_ctx; - identify_cpu(&my_cpu_data); + /* + * We can't pass "local_cpu_data" do identify_cpu() because we haven't called + * ia64_mmu_init() yet. And we can't call ia64_mmu_init() first because it + * depends on the data returned by identify_cpu(). We break the dependency by + * accessing cpu_data[] the old way, through identity mapped space. + */ + identify_cpu(&cpu_data[smp_processor_id()]); /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); @@ -415,22 +409,30 @@ ia64_set_dcr( IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR | IA64_DCR_DA | IA64_DCR_DD); #ifndef CONFIG_SMP - ia64_set_fpu_owner(0); /* initialize ar.k5 */ + ia64_set_fpu_owner(0); #endif atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - ia64_rid_init(); - ia64_tlb_init(); + ia64_mmu_init(); -#ifdef CONFIG_IA32_SUPPORT +#ifdef CONFIG_IA32_SUPPORT /* initialize global ia32 state - CR0 and CR4 */ __asm__("mov ar.cflg = %0" : /* no outputs */ : "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); #endif + /* disable all local interrupt sources: */ + ia64_set_itv(1 << 16); + ia64_set_lrr0(1 << 16); + ia64_set_lrr1(1 << 16); + ia64_set_pmv(1 << 16); + ia64_set_cmcv(1 << 16); + + /* clear TPR & XTP to enable all interrupt classes: */ + ia64_set_tpr(0); #ifdef CONFIG_SMP normal_xtp(); #endif @@ -439,7 +441,7 @@ if (ia64_pal_vm_summary(NULL, &vmi) == 0) max_ctx = (1U << (vmi.pal_vm_info_2_s.rid_size - 3)) - 1; else { - printk("ia64_rid_init: PAL VM summary failed, assuming 18 RID bits\n"); + printk("cpu_init: PAL VM summary failed, assuming 18 RID bits\n"); max_ctx = (1U << 15) - 1; /* use architected minimum */ } while (max_ctx < ia64_ctx.max_ctx) { @@ -447,4 +449,10 @@ if (cmpxchg(&ia64_ctx.max_ctx, old, max_ctx) == old) break; } + + if (ia64_pal_rse_info(&num_phys_stacked, 0) != 0) { + printk ("cpu_init: PAL RSE info failed, assuming 96 physical stacked regs\n"); + num_phys_stacked = 96; + } + local_cpu_data->phys_stacked_size_p8 = num_phys_stacked*8 + 8; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/signal.c linux.ac/arch/ia64/kernel/signal.c --- linux.vanilla/arch/ia64/kernel/signal.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/signal.c Tue Apr 10 18:08:40 2001 @@ -1,8 +1,8 @@ /* * Architecture-specific signal handling support. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang * * Derived from i386 and Alpha versions. */ @@ -38,12 +38,8 @@ #endif struct sigscratch { -#ifdef CONFIG_IA64_NEW_UNWIND unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */ unsigned long pad; -#else - struct switch_stack sw; -#endif struct pt_regs pt; }; @@ -52,7 +48,6 @@ struct sigcontext sc; }; -extern long sys_wait4 (int, int *, int, struct rusage *); extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */ long @@ -141,11 +136,7 @@ ia64_psr(&scr->pt)->ri = ip & 0x3; scr->pt.cr_ipsr = (scr->pt.cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM); -#ifdef CONFIG_IA64_NEW_UNWIND scr->scratch_unat = ia64_put_scratch_nat_bits(&scr->pt, nat); -#else - ia64_put_nat_bits(&scr->pt, &scr->sw, nat); /* restore the original scratch NaT bits */ -#endif if ((flags & IA64_SC_FLAG_FPH_VALID) != 0) { struct ia64_psr *psr = ia64_psr(&scr->pt); @@ -162,7 +153,7 @@ int copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) { - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; if (from->si_code < 0) return __copy_to_user(to, from, sizeof(siginfo_t)); @@ -190,6 +181,11 @@ err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); + case __SI_PROF >> 16: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_pfm_ovfl, &to->si_pfm_ovfl); + break; default: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); @@ -200,6 +196,43 @@ } } +int +copy_siginfo_from_user (siginfo_t *to, siginfo_t *from) +{ + if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t))) + return -EFAULT; + if (__copy_from_user(to, from, sizeof(siginfo_t)) != 0) + return -EFAULT; + + if (SI_FROMUSER(to)) + return 0; + + to->si_code &= ~__SI_MASK; + if (to->si_code != 0) { + switch (to->si_signo) { + case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGTRAP: + to->si_code |= __SI_FAULT; + break; + + case SIGCHLD: + to->si_code |= __SI_CHLD; + break; + + case SIGPOLL: + to->si_code |= __SI_POLL; + break; + + case SIGPROF: + to->si_code |= __SI_PROF; + break; + + default: + break; + } + } + return 0; +} + long ia64_rt_sigreturn (struct sigscratch *scr) { @@ -212,19 +245,17 @@ sc = &((struct sigframe *) (scr->pt.r12 + 16))->sc; /* - * When we return to the previously executing context, r8 and - * r10 have already been setup the way we want them. Indeed, - * if the signal wasn't delivered while in a system call, we - * must not touch r8 or r10 as otherwise user-level stat could - * be corrupted. + * When we return to the previously executing context, r8 and r10 have already + * been setup the way we want them. Indeed, if the signal wasn't delivered while + * in a system call, we must not touch r8 or r10 as otherwise user-level state + * could be corrupted. */ retval = (long) &ia64_leave_kernel; if (current->ptrace & PT_TRACESYS) /* - * strace expects to be notified after sigreturn - * returns even though the context to which we return - * may not be in the middle of a syscall. Thus, the - * return-value that strace displays for sigreturn is + * strace expects to be notified after sigreturn returns even though the + * context to which we return may not be in the middle of a syscall. + * Thus, the return-value that strace displays for sigreturn is * meaningless. */ retval = (long) &ia64_strace_leave_kernel; @@ -301,11 +332,7 @@ * preserved registers (r4-r7) are never being looked at by * the signal handler (registers r4-r7 are used instead). */ -#ifdef CONFIG_IA64_NEW_UNWIND nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat); -#else - nat = ia64_get_nat_bits(&scr->pt, &scr->sw); -#endif err = __put_user(flags, &sc->sc_flags); @@ -371,21 +398,11 @@ scr->pt.cr_iip = tramp_addr; ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */ -#ifdef CONFIG_IA64_NEW_UNWIND /* * Note: this affects only the NaT bits of the scratch regs * (the ones saved in pt_regs), which is exactly what we want. */ scr->scratch_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ -#else - /* - * Note: this affects only the NaT bits of the scratch regs - * (the ones saved in pt_regs), which is exactly what we want. - * The NaT bits for the preserved regs (r4-r7) are in - * sw->ar_unat iff this process is being PTRACED. - */ - scr->sw.caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ -#endif #if DEBUG_SIG printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n", @@ -437,13 +454,8 @@ } /* - * 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. + * 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. */ long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) @@ -454,9 +466,9 @@ long errno = scr->pt.r8; /* - * In the ia64_leave_kernel code path, we want the common case - * to go fast, which is why we may in certain cases get here - * from kernel mode. Just return without doing anything if so. + * In the ia64_leave_kernel code path, we want the common case to go fast, which + * is why we may in certain cases get here from kernel mode. Just return without + * doing anything if so. */ if (!user_mode(&scr->pt)) return 0; @@ -476,11 +488,10 @@ #endif if (scr->pt.r10 != -1) { /* - * A system calls has to be restarted only if one of - * the error codes ERESTARTNOHAND, ERESTARTSYS, or - * ERESTARTNOINTR is returned. If r10 isn't -1 then - * r8 doesn't hold an error code and we don't need to - * restart the syscall, so we set in_syscall to zero. + * A system calls has to be restarted only if one of the error codes + * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned. If r10 + * isn't -1 then r8 doesn't hold an error code and we don't need to + * restart the syscall, so we can clear the "restart" flag here. */ restart = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/smp.c linux.ac/arch/ia64/kernel/smp.c --- linux.vanilla/arch/ia64/kernel/smp.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/smp.c Tue Apr 10 18:08:40 2001 @@ -2,8 +2,8 @@ * SMP Support * * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999 David Mosberger-Tang - * + * Copyright (C) 1999, 2001 David Mosberger-Tang + * * Lots of stuff stolen from arch/alpha/kernel/smp.c * * 00/09/11 David Mosberger Do loops_per_jiffy calibration on each CPU. @@ -37,8 +37,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -50,9 +50,8 @@ extern void machine_halt(void); extern void start_ap(void); -extern int cpu_now_booting; /* Used by head.S to find idle task */ -extern volatile unsigned long cpu_online_map; /* Bitmap of available cpu's */ -extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; /* Duh... */ +extern int cpu_now_booting; /* used by head.S to find idle task */ +extern volatile unsigned long cpu_online_map; /* bitmap of available cpu's */ struct smp_boot_data smp_boot_data __initdata; @@ -60,18 +59,19 @@ char __initdata no_int_routing; +/* don't make this a CPU-local variable: it's used for IPIs, mostly... */ +int __cpu_physical_id[NR_CPUS]; /* logical ID -> physical CPU ID map */ + unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ -volatile int __cpu_physical_id[NR_CPUS] = { -1, }; /* Logical ID -> SAPIC ID */ -int smp_num_cpus = 1; -volatile int smp_threads_ready; /* Set when the idlers are all forked */ -cycles_t cacheflush_time; -unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */ +int smp_num_cpus = 1; +volatile int smp_threads_ready; /* set when the idlers are all forked */ +unsigned long ap_wakeup_vector; /* external Int to use to wakeup AP's */ static volatile unsigned long cpu_callin_map; static volatile int smp_commenced; -static int max_cpus = -1; /* Command line */ -static unsigned long ipi_op[NR_CPUS]; +static int max_cpus = -1; /* command line */ + struct smp_call_struct { void (*func) (void *info); void *info; @@ -99,7 +99,8 @@ * SMP mode to . */ -static int __init nosmp(char *str) +static int __init +nosmp (char *str) { max_cpus = 0; return 1; @@ -107,7 +108,8 @@ __setup("nosmp", nosmp); -static int __init maxcpus(char *str) +static int __init +maxcpus (char *str) { get_option(&str, &max_cpus); return 1; @@ -116,7 +118,7 @@ __setup("maxcpus=", maxcpus); static int __init -nointroute(char *str) +nointroute (char *str) { no_int_routing = 1; return 1; @@ -125,21 +127,20 @@ __setup("nointroute", nointroute); /* - * Yoink this CPU from the runnable list... + * Yoink this CPU from the runnable list... */ void -halt_processor(void) +halt_processor (void) { - clear_bit(smp_processor_id(), &cpu_online_map); + clear_bit(smp_processor_id(), &cpu_online_map); max_xtp(); __cli(); - for (;;) + for (;;) ; - } static inline int -pointer_lock(void *lock, void *data, int retry) +pointer_lock (void *lock, void *data, int retry) { volatile long *ptr = lock; again: @@ -156,14 +157,13 @@ } void -handle_IPI(int irq, void *dev_id, struct pt_regs *regs) +handle_IPI (int irq, void *dev_id, struct pt_regs *regs) { - int this_cpu = smp_processor_id(); - unsigned long *pending_ipis = &ipi_op[this_cpu]; + unsigned long *pending_ipis = &local_cpu_data->ipi_operation; unsigned long ops; /* Count this now; we may make a call that never returns. */ - cpu_data[this_cpu].ipi_count++; + local_cpu_data->ipi_count++; mb(); /* Order interrupt and bit testing. */ while ((ops = xchg(pending_ipis, 0)) != 0) { @@ -173,16 +173,16 @@ which = ffz(~ops); ops &= ~(1 << which); - + switch (which) { case IPI_RESCHEDULE: - /* - * Reschedule callback. Everything to be done is done by the - * interrupt return path. + /* + * Reschedule callback. Everything to be done is done by the + * interrupt return path. */ break; - - case IPI_CALL_FUNC: + + case IPI_CALL_FUNC: { struct smp_call_struct *data; void (*func)(void *info); @@ -203,7 +203,7 @@ /* Notify the sending CPU that the task is done. */ mb(); - if (wait) + if (wait) atomic_dec(&data->unfinished_count); } break; @@ -214,7 +214,7 @@ #ifndef CONFIG_ITANIUM_PTCG case IPI_FLUSH_TLB: - { + { extern unsigned long flush_start, flush_end, flush_nbits, flush_rid; extern atomic_t flush_cpu_count; unsigned long saved_rid = ia64_get_rr(flush_start); @@ -223,6 +223,8 @@ unsigned long nbits = flush_nbits; /* + * Current CPU may be running with different RID so we need to + * reload the RID of flushed address. * Current CPU may be running with different * RID so we need to reload the RID of flushed * address. Purging the translation also @@ -235,7 +237,7 @@ ia64_set_rr(flush_start, flush_rid); ia64_srlz_d(); } - + do { /* * Purge local TLB entries. @@ -258,7 +260,8 @@ #endif /* !CONFIG_ITANIUM_PTCG */ default: - printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", + smp_processor_id(), which); break; } /* Switch */ } while (ops); @@ -268,21 +271,21 @@ } static inline void -send_IPI_single (int dest_cpu, int op) +send_IPI_single (int dest_cpu, int op) { - - if (dest_cpu == -1) - return; - - set_bit(op, &ipi_op[dest_cpu]); - platform_send_ipi(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0); + + if (dest_cpu == -1) + return; + + set_bit(op, &cpu_data[dest_cpu].ipi_operation); + platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); } static inline void -send_IPI_allbutself(int op) +send_IPI_allbutself (int op) { int i; - + for (i = 0; i < smp_num_cpus; i++) { if (i != smp_processor_id()) send_IPI_single(i, op); @@ -290,7 +293,7 @@ } static inline void -send_IPI_all(int op) +send_IPI_all (int op) { int i; @@ -299,30 +302,42 @@ } static inline void -send_IPI_self(int op) +send_IPI_self (int op) { send_IPI_single(smp_processor_id(), op); } void -smp_send_reschedule(int cpu) +smp_send_reschedule (int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); } void -smp_send_stop(void) +smp_send_stop (void) { send_IPI_allbutself(IPI_CPU_STOP); } #ifndef CONFIG_ITANIUM_PTCG + void -smp_send_flush_tlb(void) +smp_send_flush_tlb (void) { send_IPI_allbutself(IPI_FLUSH_TLB); } -#endif /* !CONFIG_ITANIUM_PTCG */ + +void +smp_resend_flush_tlb(void) +{ + /* + * Really need a null IPI but since this rarely should happen & since this code + * will go away, lets not add one. + */ + send_IPI_allbutself(IPI_RESCHEDULE); +} + +#endif /* !CONFIG_ITANIUM_PTCG */ /* * Run a function on another CPU @@ -347,7 +362,7 @@ printk(__FUNCTION__" trying to call self\n"); return -EBUSY; } - + data.func = func; data.info = info; data.wait = wait; @@ -392,7 +407,6 @@ * Does not return until remote CPUs are nearly ready to execute * or are or have executed. */ - int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { @@ -402,7 +416,7 @@ if (cpus == 0) return 0; - + data.func = func; data.info = info; data.wait = wait; @@ -425,7 +439,7 @@ int i; for (i = 0; i < smp_num_cpus; i++) { if (i != smp_processor_id()) - platform_send_ipi(i, IPI_IRQ, IA64_IPI_DM_INT, 0); + platform_send_ipi(i, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); } goto retry; #else @@ -446,7 +460,7 @@ * want to ensure all TLB's flushed before proceeding. */ void -smp_flush_tlb_all(void) +smp_flush_tlb_all (void) { smp_call_function((void (*)(void *))__flush_tlb_all, NULL, 1, 1); __flush_tlb_all(); @@ -456,21 +470,19 @@ * Ideally sets up per-cpu profiling hooks. Doesn't do much now... */ static inline void __init -smp_setup_percpu_timer(int cpuid) +smp_setup_percpu_timer(void) { - cpu_data[cpuid].prof_counter = 1; - cpu_data[cpuid].prof_multiplier = 1; + local_cpu_data->prof_counter = 1; + local_cpu_data->prof_multiplier = 1; } -void -smp_do_timer(struct pt_regs *regs) +void +smp_do_timer (struct pt_regs *regs) { - int cpu = smp_processor_id(); - int user = user_mode(regs); - struct cpuinfo_ia64 *data = &cpu_data[cpu]; + int user = user_mode(regs); - if (--data->prof_counter <= 0) { - data->prof_counter = data->prof_multiplier; + if (--local_cpu_data->prof_counter <= 0) { + local_cpu_data->prof_counter = local_cpu_data->prof_multiplier; update_process_times(user); } } @@ -480,7 +492,7 @@ * AP's start using C here. */ void __init -smp_callin (void) +smp_callin (void) { extern void ia64_rid_init(void); extern void ia64_init_itm(void); @@ -493,12 +505,12 @@ if (test_and_set_bit(cpu, &cpu_online_map)) { printk("CPU#%d already initialized!\n", cpu); machine_halt(); - } + } efi_map_pal_code(); cpu_init(); - smp_setup_percpu_timer(cpu); + smp_setup_percpu_timer(); /* setup the CPU local timer tick */ ia64_init_itm(); @@ -506,15 +518,10 @@ #ifdef CONFIG_PERFMON perfmon_init_percpu(); #endif - - /* Disable all local interrupts */ - ia64_set_lrr0(0, 1); - ia64_set_lrr1(0, 1); - local_irq_enable(); /* Interrupts have been off until now */ calibrate_delay(); - my_cpu_data.loops_per_jiffy = loops_per_jiffy; + local_cpu_data->loops_per_jiffy = loops_per_jiffy; /* allow the master to continue */ set_bit(cpu, &cpu_callin_map); @@ -531,8 +538,8 @@ * path in which case the new idle task could get scheduled before we * had a chance to remove it from the run-queue... */ -static int __init -fork_by_hand(void) +static int __init +fork_by_hand (void) { /* * Don't care about the usp and regs settings since we'll never @@ -545,22 +552,22 @@ * Bring one cpu online. Return 0 if this fails for any reason. */ static int __init -smp_boot_one_cpu(int cpu) +smp_boot_one_cpu (int cpu) { struct task_struct *idle; int cpu_phys_id = cpu_physical_id(cpu); long timeout; - /* + /* * Create an idle task for this CPU. Note that the address we * give to kernel_thread is irrelevant -- it's going to start * where OS_BOOT_RENDEVZ vector in SAL says to start. But * this gets all the other task-y sort of data structures set - * up like we wish. We need to pull the just created idle task - * off the run queue and stuff it into the init_tasks[] array. + * up like we wish. We need to pull the just created idle task + * off the run queue and stuff it into the init_tasks[] array. * Sheesh . . . */ - if (fork_by_hand() < 0) + if (fork_by_hand() < 0) panic("failed fork for CPU 0x%x", cpu_phys_id); /* * We remove it from the pidhash and the runqueue @@ -571,7 +578,7 @@ panic("No idle process for CPU 0x%x", cpu_phys_id); init_tasks[cpu] = idle; del_from_runqueue(idle); - unhash_process(idle); + unhash_process(idle); /* Schedule the first task manually. */ idle->processor = cpu; @@ -590,50 +597,41 @@ udelay(100); } - printk(KERN_ERR "SMP: Processor 0x%x is stuck.\n", cpu_phys_id); + printk(KERN_ERR "SMP: CPU 0x%x is stuck\n", cpu_phys_id); return 0; } /* - * Called by smp_init bring all the secondaries online and hold them. - * XXX: this is ACPI specific; it uses "magic" variables exported from acpi.c - * to 'discover' the AP's. Blech. + * Called by smp_init bring all the secondaries online and hold them. */ void __init -smp_boot_cpus(void) +smp_boot_cpus (void) { int i, cpu_count = 1; unsigned long bogosum; - /* Take care of some initial bookkeeping. */ - memset(&__cpu_physical_id, -1, sizeof(__cpu_physical_id)); - memset(&ipi_op, 0, sizeof(ipi_op)); - - /* Setup BP mappings */ - __cpu_physical_id[0] = hard_smp_processor_id(); - /* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */ - my_cpu_data.loops_per_jiffy = loops_per_jiffy; + local_cpu_data->loops_per_jiffy = loops_per_jiffy; #if 0 smp_tune_scheduling(); #endif - smp_setup_percpu_timer(0); + smp_setup_percpu_timer(); if (test_and_set_bit(0, &cpu_online_map)) { printk("CPU#%d already initialized!\n", smp_processor_id()); machine_halt(); - } + } init_idle(); /* Nothing to do when told not to. */ if (max_cpus == 0) { - printk(KERN_INFO "SMP mode deactivated.\n"); + printk(KERN_INFO "SMP mode deactivated.\n"); return; } - if (max_cpus != -1) + if (max_cpus != -1) printk("Limiting CPUs to %d\n", max_cpus); if (smp_boot_data.cpu_count > 1) { @@ -650,7 +648,7 @@ continue; /* failed */ cpu_count++; /* Count good CPUs only... */ - /* + /* * Bail if we've started as many CPUS as we've been told to. */ if (cpu_count == max_cpus) @@ -663,10 +661,10 @@ } bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (cpu_online_map & (1L << i)) bogosum += cpu_data[i].loops_per_jiffy; - } + } printk(KERN_INFO "SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", cpu_count, bogosum*HZ/500000, (bogosum*HZ/5000) % 100); @@ -674,31 +672,31 @@ smp_num_cpus = cpu_count; } -/* +/* * Called when the BP is just about to fire off init. */ -void __init -smp_commence(void) +void __init +smp_commence (void) { smp_commenced = 1; } int __init -setup_profiling_timer(unsigned int multiplier) +setup_profiling_timer (unsigned int multiplier) { - return -EINVAL; + return -EINVAL; } /* * Assume that CPU's have been discovered by some platform-dependant * interface. For SoftSDV/Lion, that would be ACPI. * - * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP(). + * Setup of the IPI irq handler is done in irq.c:init_IRQ(). * * This also registers the AP OS_MC_REDVEZ address with SAL. */ void __init -init_smp_config(void) +init_smp_config (void) { struct fptr { unsigned long fp; @@ -708,14 +706,13 @@ /* Tell SAL where to drop the AP's. */ ap_startup = (struct fptr *) start_ap; - sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, - __pa(ap_startup->fp), __pa(ap_startup->gp), 0, - 0, 0, 0); + sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, __pa(ap_startup->fp), + __pa(ap_startup->gp), 0, 0, 0, 0); if (sal_ret < 0) { printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); printk(" Forcing UP mode\n"); max_cpus = 0; - smp_num_cpus = 1; + smp_num_cpus = 1; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/smpboot.c linux.ac/arch/ia64/kernel/smpboot.c --- linux.vanilla/arch/ia64/kernel/smpboot.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/kernel/smpboot.c Tue Apr 10 18:08:40 2001 @@ -1,74 +1,4 @@ /* - * SMP Support - * - * Application processor startup code, moved from smp.c to better support kernel profile */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * SAL shoves the AP's here when we start them. Physical mode, no kernel TR, - * no RRs set, better than even chance that psr is bogus. Fix all that and - * call _start. In effect, pretend to be lilo. - * - * Stolen from lilo_start.c. Thanks David! - */ -void -start_ap(void) -{ - extern void _start (void); - unsigned long flags; - - /* - * Install a translation register that identity maps the - * kernel's 256MB page(s). - */ - ia64_clear_ic(flags); - ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); - ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); - ia64_srlz_d(); - ia64_itr(0x3, 1, PAGE_OFFSET, - pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), - _PAGE_SIZE_256M); - ia64_srlz_i(); - - flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | - IA64_PSR_BN); - - asm volatile ("movl r8 = 1f\n" - ";;\n" - "mov cr.ipsr=%0\n" - "mov cr.iip=r8\n" - "mov cr.ifs=r0\n" - ";;\n" - "rfi;;" - "1:\n" - "movl r1 = __gp" :: "r"(flags) : "r8"); - _start(); -} - - +/* place holder... */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/sys_ia64.c linux.ac/arch/ia64/kernel/sys_ia64.c --- linux.vanilla/arch/ia64/kernel/sys_ia64.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/kernel/sys_ia64.c Sat Apr 14 01:18:00 2001 @@ -22,16 +22,16 @@ #define COLOR_ALIGN(addr) (((addr) + SHMLBA - 1) & ~(SHMLBA - 1)) unsigned long -get_unmapped_area (unsigned long addr, unsigned long len) +arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct vm_area_struct * vmm; if (len > RGN_MAP_LIMIT) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (current->thread.flags & IA64_THREAD_MAP_SHARED) + if (flags & MAP_SHARED) addr = COLOR_ALIGN(addr); else addr = PAGE_ALIGN(addr); @@ -39,17 +39,19 @@ for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { /* At this point: (!vmm || addr < vmm->vm_end). */ if (TASK_SIZE - len < addr) - return 0; + return -ENOMEM; if (rgn_offset(addr) + len > RGN_MAP_LIMIT) /* no risk of overflow here... */ - return 0; + return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; + if (flags & MAP_SHARED) + addr = COLOR_ALIGN(addr); } } asmlinkage long -ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6, +ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; @@ -197,15 +199,10 @@ return -EBADF; } - if (flags & MAP_SHARED) - current->thread.flags |= IA64_THREAD_MAP_SHARED; - down_write(¤t->mm->mmap_sem); addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); - current->thread.flags &= ~IA64_THREAD_MAP_SHARED; - if (file) fput(file); return addr; @@ -246,15 +243,15 @@ asmlinkage long sys_vm86 (long arg0, long arg1, long arg2, long arg3) { - printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); - return -ENOSYS; + printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); + return -ENOSYS; } asmlinkage long sys_modify_ldt (long arg0, long arg1, long arg2, long arg3) { - printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); - return -ENOSYS; + printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); + return -ENOSYS; } asmlinkage unsigned long @@ -392,7 +389,7 @@ } return err; } - + #endif #ifndef CONFIG_PCI diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/time.c linux.ac/arch/ia64/kernel/time.c --- linux.vanilla/arch/ia64/kernel/time.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/time.c Tue Apr 10 18:08:40 2001 @@ -1,9 +1,9 @@ /* * linux/arch/ia64/kernel/time.c * - * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2000 Stephane Eranian - * Copyright (C) 1999-2000 David Mosberger + * Copyright (C) 1999-2001 David Mosberger * Copyright (C) 1999 Don Dugger * Copyright (C) 1999-2000 VA Linux Systems * Copyright (C) 1999-2000 Walt Drummond @@ -32,14 +32,6 @@ #endif -static struct { - unsigned long delta; - union { - unsigned long count; - unsigned char pad[SMP_CACHE_BYTES]; - } next[NR_CPUS]; -} itm; - static void do_profile (unsigned long ip) { @@ -61,7 +53,7 @@ ip = prof_len - 1; atomic_inc((atomic_t *) &prof_buffer[ip]); - } + } } /* @@ -82,7 +74,7 @@ unsigned long now = ia64_get_itc(), last_tick; unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; - last_tick = (itm.next[smp_processor_id()].count - (lost+1)*itm.delta); + last_tick = (local_cpu_data->itm_next - (lost+1)*local_cpu_data->itm_delta); # if 1 if ((long) (now - last_tick) < 0) { printk("Yikes: now < last_tick (now=0x%lx,last_tick=%lx)! No can do.\n", @@ -91,7 +83,7 @@ } # endif elapsed_cycles = now - last_tick; - return (elapsed_cycles*my_cpu_data.usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; + return (elapsed_cycles*local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; #endif } @@ -132,7 +124,7 @@ read_lock_irqsave(&xtime_lock, flags); { usec = gettimeoffset(); - + sec = xtime.tv_sec; usec += xtime.tv_usec; } @@ -150,10 +142,9 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int cpu = smp_processor_id(); unsigned long new_itm; - new_itm = itm.next[cpu].count; + new_itm = local_cpu_data->itm_next; if (!time_after(ia64_get_itc(), new_itm)) printk("Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", @@ -165,7 +156,7 @@ * four so that we can use a prof_shift of 2 to get instruction-level * instead of just bundle-level accuracy. */ - if (!user_mode(regs)) + if (!user_mode(regs)) do_profile(regs->cr_iip + 4*ia64_psr(regs)->ri); #ifdef CONFIG_SMP @@ -183,52 +174,50 @@ write_unlock(&xtime_lock); } - new_itm += itm.delta; - itm.next[cpu].count = new_itm; + new_itm += local_cpu_data->itm_delta; + local_cpu_data->itm_next = new_itm; if (time_after(new_itm, ia64_get_itc())) break; } - /* - * If we're too close to the next clock tick for comfort, we - * increase the saftey margin by intentionally dropping the - * next tick(s). We do NOT update itm.next accordingly - * because that would force us to call do_timer() which in - * turn would let our clock run too fast (with the potentially - * devastating effect of losing monotony of time). - */ - while (!time_after(new_itm, ia64_get_itc() + itm.delta/2)) - new_itm += itm.delta; - ia64_set_itm(new_itm); -} - -#ifdef CONFIG_IA64_SOFTSDV_HACKS - -/* - * Interrupts must be disabled before calling this routine. - */ -void -ia64_reset_itm (void) -{ - timer_interrupt(0, 0, ia64_task_regs(current)); + do { + /* + * If we're too close to the next clock tick for comfort, we increase the + * saftey margin by intentionally dropping the next tick(s). We do NOT update + * itm.next because that would force us to call do_timer() which in turn would + * let our clock run too fast (with the potentially devastating effect of + * losing monotony of time). + */ + while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) + new_itm += local_cpu_data->itm_delta; + ia64_set_itm(new_itm); + /* double check, in case we got hit by a (slow) PMI: */ + } while (time_after_eq(ia64_get_itc(), new_itm)); } -#endif - /* * Encapsulate access to the itm structure for SMP. */ void __init -ia64_cpu_local_tick(void) +ia64_cpu_local_tick (void) { -#ifdef CONFIG_IA64_SOFTSDV_HACKS - ia64_set_itc(0); -#endif + int cpu = smp_processor_id(); + unsigned long shift = 0, delta; /* arrange for the cycle counter to generate a timer interrupt: */ - ia64_set_itv(TIMER_IRQ, 0); - itm.next[smp_processor_id()].count = ia64_get_itc() + itm.delta; - ia64_set_itm(itm.next[smp_processor_id()].count); + ia64_set_itv(IA64_TIMER_VECTOR); + + delta = local_cpu_data->itm_delta; + /* + * Stagger the timer tick for each CPU so they don't occur all at (almost) the + * same time: + */ + if (cpu) { + unsigned long hi = 1UL << ia64_fls(cpu); + shift = (2*(cpu - hi) + 1) * delta/hi/2; + } + local_cpu_data->itm_next = ia64_get_itc() + delta + shift; + ia64_set_itm(local_cpu_data->itm_next); } void __init @@ -258,33 +247,28 @@ itc_ratio.num = 3; itc_ratio.den = 1; } -#ifdef CONFIG_IA64_SOFTSDV_HACKS - platform_base_freq = 10000000; - proc_ratio.num = 4; proc_ratio.den = 1; - itc_ratio.num = 4; itc_ratio.den = 1; -#else if (platform_base_freq < 40000000) { printk("Platform base frequency %lu bogus---resetting to 75MHz!\n", platform_base_freq); platform_base_freq = 75000000; } -#endif if (!proc_ratio.den) - proc_ratio.num = 1; /* avoid division by zero */ + proc_ratio.den = 1; /* avoid division by zero */ if (!itc_ratio.den) - itc_ratio.num = 1; /* avoid division by zero */ + itc_ratio.den = 1; /* avoid division by zero */ - itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; - itm.delta = itc_freq / HZ; - printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", + itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; + local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; + printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, - itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); + itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); - my_cpu_data.proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; - my_cpu_data.itc_freq = itc_freq; - my_cpu_data.cyc_per_usec = itc_freq / 1000000; - my_cpu_data.usec_per_cyc = (1000000UL << IA64_USEC_PER_CYC_SHIFT) / itc_freq; + local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; + local_cpu_data->itc_freq = itc_freq; + local_cpu_data->cyc_per_usec = (itc_freq + 500000) / 1000000; + local_cpu_data->usec_per_cyc = ((1000000UL< : added isr in siginfo for SIGFPE */ -#define FPSWA_DEBUG 1 - /* * The fpu_fault() handler needs to be able to access and update all * floating point registers. Those saved in pt_regs can be accessed @@ -47,31 +45,10 @@ void __init trap_init (void) { - printk("fpswa interface at %lx\n", ia64_boot_param.fpswa); - if (ia64_boot_param.fpswa) { -#define OLD_FIRMWARE -#ifdef OLD_FIRMWARE - /* - * HACK to work around broken firmware. This code - * applies the label fixup to the FPSWA interface and - * works both with old and new (fixed) firmware. - */ - unsigned long addr = (unsigned long) __va(ia64_boot_param.fpswa); - unsigned long gp_val = *(unsigned long *)(addr + 8); - - /* go indirect and indexed to get table address */ - addr = gp_val; - gp_val = *(unsigned long *)(addr + 8); - - while (gp_val == *(unsigned long *)(addr + 8)) { - *(unsigned long *)addr |= PAGE_OFFSET; - *(unsigned long *)(addr + 8) |= PAGE_OFFSET; - addr += 16; - } -#endif + printk("fpswa interface at %lx\n", ia64_boot_param->fpswa); + if (ia64_boot_param->fpswa) /* FPSWA fixup: make the interface pointer a kernel virtual address: */ - fpswa_interface = __va(ia64_boot_param.fpswa); - } + fpswa_interface = __va(ia64_boot_param->fpswa); } void @@ -240,6 +217,7 @@ { fp_state_t fp_state; fpswa_ret_t ret; +#define FPSWA_BUG #ifdef FPSWA_BUG struct ia64_fpreg f6_15[10]; #endif @@ -250,7 +228,7 @@ memset(&fp_state, 0, sizeof(fp_state_t)); /* - * compute fp_state. only FP registers f6 - f11 are used by the + * compute fp_state. only FP registers f6 - f11 are used by the * kernel, so set those bits in the mask and set the low volatile * pointer to point to these registers. */ @@ -263,15 +241,15 @@ f6_15[1] = regs->f7; f6_15[2] = regs->f8; f6_15[3] = regs->f9; - __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4])); - __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5])); - __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6])); - __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7])); - __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8])); - __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9])); + __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4])); + __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5])); + __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6])); + __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7])); + __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8])); + __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9])); fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15; #endif - /* + /* * unsigned long (*EFI_FPSWA) ( * unsigned long trap_type, * void *Bundle, @@ -287,12 +265,12 @@ (unsigned long *) isr, (unsigned long *) pr, (unsigned long *) ifs, &fp_state); #ifdef FPSWA_BUG - __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4])); - __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5])); - __asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6])); - __asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7])); - __asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8])); - __asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9])); + __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4])); + __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5])); + __asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6])); + __asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7])); + __asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8])); + __asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9])); regs->f6 = f6_15[0]; regs->f7 = f6_15[1]; regs->f8 = f6_15[2]; @@ -319,21 +297,20 @@ if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle))) return -1; -#ifdef FPSWA_DEBUG - if (fpu_swa_count > 5 && jiffies - last_time > 5*HZ) + if (jiffies - last_time > 5*HZ) fpu_swa_count = 0; if (++fpu_swa_count < 5) { last_time = jiffies; - printk("%s(%d): floating-point assist fault at ip %016lx\n", + printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n", current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri); } -#endif + exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, - ®s->cr_ifs, regs); + ®s->cr_ifs, regs); if (fp_fault) { if (exception == 0) { /* emulation was successful */ - ia64_increment_ip(regs); + ia64_increment_ip(regs); } else if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); return -1; @@ -392,7 +369,7 @@ struct siginfo si; char buf[128]; -#ifdef CONFIG_IA64_BRL_EMU +#ifdef CONFIG_IA64_BRL_EMU { extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long); @@ -431,7 +408,7 @@ "IA-64 Reserved Register/Field fault", "Disabled Instruction Set Transition fault", "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", - "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", + "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" }; @@ -444,7 +421,7 @@ unsigned long n = vector; char buf[32], *cp; - if (count > 5 && jiffies - last_time > 5*HZ) + if (jiffies - last_time > 5*HZ) count = 0; if (count++ < 5) { @@ -502,7 +479,7 @@ case 35: /* Taken Branch Trap */ case 36: /* Single Step Trap */ switch (vector) { - case 29: + case 29: siginfo.si_code = TRAP_HWBKPT; #ifdef CONFIG_ITANIUM /* @@ -513,7 +490,7 @@ ifa = regs->cr_iip; #endif siginfo.si_addr = (void *) ifa; - break; + break; case 35: siginfo.si_code = TRAP_BRANCH; break; case 36: siginfo.si_code = TRAP_TRACE; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/unaligned.c linux.ac/arch/ia64/kernel/unaligned.c --- linux.vanilla/arch/ia64/kernel/unaligned.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/kernel/unaligned.c Tue Apr 10 18:08:40 2001 @@ -1,12 +1,16 @@ /* * Architecture-specific unaligned trap handling. * - * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999-2000 Stephane Eranian + * Copyright (C) 2001 David Mosberger-Tang + * + * 2001/01/17 Add support emulation of unaligned kernel accesses. */ #include #include #include + #include #include #include @@ -17,14 +21,28 @@ #undef DEBUG_UNALIGNED_TRAP #ifdef DEBUG_UNALIGNED_TRAP -#define DPRINT(a) { printk("%s, line %d: ", __FUNCTION__, __LINE__); printk a;} +# define DPRINT(a...) do { printk("%s.%u: ", __FUNCTION__, __LINE__); printk (a); } while (0) +# define DDUMP(str,vp,len) dump(str, vp, len) + +static void +dump (const char *str, void *vp, size_t len) +{ + unsigned char *cp = vp; + int i; + + printk("%s", str); + for (i = 0; i < len; ++i) + printk (" %02x", *cp++); + printk("\n"); +} #else -#define DPRINT(a) +# define DPRINT(a...) +# define DDUMP(str,vp,len) #endif #define IA64_FIRST_STACKED_GR 32 #define IA64_FIRST_ROTATING_FR 32 -#define SIGN_EXT9 __IA64_UL(0xffffffffffffff00) +#define SIGN_EXT9 0xffffffffffffff00ul /* * For M-unit: @@ -35,33 +53,34 @@ * --------|------|---------| * 4 | 1 | 6 | = 11 bits * -------------------------- - * However bits [31:30] are not directly useful to distinguish between - * load/store so we can use [35:32] instead, which gives the following + * However bits [31:30] are not directly useful to distinguish between + * load/store so we can use [35:32] instead, which gives the following * mask ([40:32]) using 9 bits. The 'e' comes from the fact that we defer * checking the m-bit until later in the load/store emulation. */ -#define IA64_OPCODE_MASK 0x1ef00000000 +#define IA64_OPCODE_MASK 0x1ef +#define IA64_OPCODE_SHIFT 32 /* * Table C-28 Integer Load/Store - * + * * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF * - * ld8.fill, st8.fill MUST be aligned because the RNATs are based on + * ld8.fill, st8.fill MUST be aligned because the RNATs are based on * the address (bits [8:3]), so we must failed. */ -#define LD_OP 0x08000000000 -#define LDS_OP 0x08100000000 -#define LDA_OP 0x08200000000 -#define LDSA_OP 0x08300000000 -#define LDBIAS_OP 0x08400000000 -#define LDACQ_OP 0x08500000000 +#define LD_OP 0x080 +#define LDS_OP 0x081 +#define LDA_OP 0x082 +#define LDSA_OP 0x083 +#define LDBIAS_OP 0x084 +#define LDACQ_OP 0x085 /* 0x086, 0x087 are not relevant */ -#define LDCCLR_OP 0x08800000000 -#define LDCNC_OP 0x08900000000 -#define LDCCLRACQ_OP 0x08a00000000 -#define ST_OP 0x08c00000000 -#define STREL_OP 0x08d00000000 +#define LDCCLR_OP 0x088 +#define LDCNC_OP 0x089 +#define LDCCLRACQ_OP 0x08a +#define ST_OP 0x08c +#define STREL_OP 0x08d /* 0x08e,0x8f are not relevant */ /* @@ -73,38 +92,38 @@ /* * Table C-30 Integer Load/Store +Imm - * + * * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF * - * ld8.fill, st8.fill must be aligned because the Nat register are based on + * ld8.fill, st8.fill must be aligned because the Nat register are based on * the address, so we must fail and the program must be fixed. */ -#define LD_IMM_OP 0x0a000000000 -#define LDS_IMM_OP 0x0a100000000 -#define LDA_IMM_OP 0x0a200000000 -#define LDSA_IMM_OP 0x0a300000000 -#define LDBIAS_IMM_OP 0x0a400000000 -#define LDACQ_IMM_OP 0x0a500000000 +#define LD_IMM_OP 0x0a0 +#define LDS_IMM_OP 0x0a1 +#define LDA_IMM_OP 0x0a2 +#define LDSA_IMM_OP 0x0a3 +#define LDBIAS_IMM_OP 0x0a4 +#define LDACQ_IMM_OP 0x0a5 /* 0x0a6, 0xa7 are not relevant */ -#define LDCCLR_IMM_OP 0x0a800000000 -#define LDCNC_IMM_OP 0x0a900000000 -#define LDCCLRACQ_IMM_OP 0x0aa00000000 -#define ST_IMM_OP 0x0ac00000000 -#define STREL_IMM_OP 0x0ad00000000 +#define LDCCLR_IMM_OP 0x0a8 +#define LDCNC_IMM_OP 0x0a9 +#define LDCCLRACQ_IMM_OP 0x0aa +#define ST_IMM_OP 0x0ac +#define STREL_IMM_OP 0x0ad /* 0x0ae,0xaf are not relevant */ /* * Table C-32 Floating-point Load/Store */ -#define LDF_OP 0x0c000000000 -#define LDFS_OP 0x0c100000000 -#define LDFA_OP 0x0c200000000 -#define LDFSA_OP 0x0c300000000 +#define LDF_OP 0x0c0 +#define LDFS_OP 0x0c1 +#define LDFA_OP 0x0c2 +#define LDFSA_OP 0x0c3 /* 0x0c6 is irrelevant */ -#define LDFCCLR_OP 0x0c800000000 -#define LDFCNC_OP 0x0c900000000 +#define LDFCCLR_OP 0x0c8 +#define LDFCNC_OP 0x0c9 /* 0x0cb is irrelevant */ -#define STF_OP 0x0cc00000000 +#define STF_OP 0x0cc /* * Table C-33 Floating-point Load +Reg @@ -116,17 +135,17 @@ /* * Table C-34 Floating-point Load/Store +Imm */ -#define LDF_IMM_OP 0x0e000000000 -#define LDFS_IMM_OP 0x0e100000000 -#define LDFA_IMM_OP 0x0e200000000 -#define LDFSA_IMM_OP 0x0e300000000 +#define LDF_IMM_OP 0x0e0 +#define LDFS_IMM_OP 0x0e1 +#define LDFA_IMM_OP 0x0e2 +#define LDFSA_IMM_OP 0x0e3 /* 0x0e6 is irrelevant */ -#define LDFCCLR_IMM_OP 0x0e800000000 -#define LDFCNC_IMM_OP 0x0e900000000 -#define STF_IMM_OP 0x0ec00000000 +#define LDFCCLR_IMM_OP 0x0e8 +#define LDFCNC_IMM_OP 0x0e9 +#define STF_IMM_OP 0x0ec typedef struct { - unsigned long qp:6; /* [0:5] */ + unsigned long qp:6; /* [0:5] */ unsigned long r1:7; /* [6:12] */ unsigned long imm:7; /* [13:19] */ unsigned long r3:7; /* [20:26] */ @@ -170,7 +189,7 @@ #define FR_IN_SW(x) (fr_info[x] & 0x1) static u16 gr_info[32]={ - 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */ + 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */ RPT(r1), RPT(r2), RPT(r3), @@ -186,7 +205,7 @@ }; static u16 fr_info[32]={ - 0, /* constant : WE SHOULD NEVER GET THIS */ + 0, /* constant : WE SHOULD NEVER GET THIS */ 0, /* constant : WE SHOULD NEVER GET THIS */ RSW(f2), RSW(f3), RSW(f4), RSW(f5), @@ -255,162 +274,160 @@ } static void -set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) +set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) { - struct switch_stack *sw = (struct switch_stack *)regs - 1; - unsigned long *kbs = ((unsigned long *)current) + IA64_RBS_OFFSET/8; + struct switch_stack *sw = (struct switch_stack *) regs - 1; + unsigned long *bsp, *bspstore, *addr, *rnat_addr, *ubs_end; + unsigned long *kbs = (void *) current + IA64_RBS_OFFSET; + unsigned long rnats, nat_mask; unsigned long on_kbs; - unsigned long *bsp, *bspstore, *addr, *ubs_end, *slot; - unsigned long rnats; - long nlocals; + long sof = (regs->cr_ifs) & 0x7f; - /* - * cr_ifs=[rv:ifm], ifm=[....:sof(6)] - * nlocal=number of locals (in+loc) register of the faulting function - */ - nlocals = (regs->cr_ifs) & 0x7f; + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); - DPRINT(("sw.bsptore=%lx pt.bspstore=%lx\n", sw->ar_bspstore, regs->ar_bspstore)); - DPRINT(("cr.ifs=%lx sof=%ld sol=%ld\n", - regs->cr_ifs, regs->cr_ifs &0x7f, (regs->cr_ifs>>7)&0x7f)); + if ((r1 - 32) >= sof) { + /* this should never happen, as the "rsvd register fault" has higher priority */ + DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof); + return; + } - on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore); - bspstore = (unsigned long *)regs->ar_bspstore; + on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + if (addr >= kbs) { + /* the register is on the kernel backing store: easy... */ + rnat_addr = ia64_rse_rnat_addr(addr); + if ((unsigned long) rnat_addr >= sw->ar_bspstore) + rnat_addr = &sw->ar_rnat; + nat_mask = 1UL << ia64_rse_slot_num(addr); - DPRINT(("rse_slot_num=0x%lx\n",ia64_rse_slot_num((unsigned long *)sw->ar_bspstore))); - DPRINT(("kbs=%p nlocals=%ld\n", (void *) kbs, nlocals)); - DPRINT(("bspstore next rnat slot %p\n", - (void *) ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore))); - DPRINT(("on_kbs=%ld rnats=%ld\n", - on_kbs, ((sw->ar_bspstore-(unsigned long)kbs)>>3) - on_kbs)); + *addr = val; + if (nat) + *rnat_addr |= nat_mask; + else + *rnat_addr &= ~nat_mask; + return; + } /* - * See get_rse_reg() for an explanation on the following instructions + * Avoid using user_mode() here: with "epc", we cannot use the privilege level to + * infer whether the interrupt task was running on the kernel backing store. */ + if (regs->r12 >= TASK_SIZE) { + DPRINT("ignoring kernel write to r%lu; register isn't on the RBS!", r1); + return; + } + + bspstore = (unsigned long *) regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); - bsp = ia64_rse_skip_regs(ubs_end, -nlocals); - addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); + bsp = ia64_rse_skip_regs(ubs_end, -sof); + addr = ia64_rse_skip_regs(bsp, r1 - 32); - DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", - (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr))); + DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr); - ia64_poke(regs, current, (unsigned long)addr, val); + ia64_poke(current, (unsigned long) ubs_end, (unsigned long) addr, val); - /* - * addr will now contain the address of the RNAT for the register - */ - addr = ia64_rse_rnat_addr(addr); + rnat_addr = ia64_rse_rnat_addr(addr); - ia64_peek(regs, current, (unsigned long)addr, &rnats); - DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n", - (void *) addr, rnats, nat, rnats &ia64_rse_slot_num(slot))); - - if (nat) { - rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot); - } else { - rnats &= ~(__IA64_UL(1) << ia64_rse_slot_num(slot)); - } - ia64_poke(regs, current, (unsigned long)addr, rnats); + ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); + DPRINT("rnat @%p = 0x%lx nat=%d old nat=%ld\n", + (void *) rnat_addr, rnats, nat, (rnats >> ia64_rse_slot_num(addr)) & 1); - DPRINT(("rnat changed to @%p = 0x%lx\n", (void *) addr, rnats)); + nat_mask = 1UL << ia64_rse_slot_num(addr); + if (nat) + rnats |= nat_mask; + else + rnats &= ~nat_mask; + ia64_poke(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, rnats); + + DPRINT("rnat changed to @%p = 0x%lx\n", (void *) rnat_addr, rnats); } static void -get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat) +get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat) { - struct switch_stack *sw = (struct switch_stack *)regs - 1; - unsigned long *kbs = (unsigned long *)current + IA64_RBS_OFFSET/8; + struct switch_stack *sw = (struct switch_stack *) regs - 1; + unsigned long *bsp, *addr, *rnat_addr, *ubs_end, *bspstore; + unsigned long *kbs = (void *) current + IA64_RBS_OFFSET; + unsigned long rnats, nat_mask; unsigned long on_kbs; - long nlocals; - unsigned long *bsp, *addr, *ubs_end, *slot, *bspstore; - unsigned long rnats; + long sof = (regs->cr_ifs) & 0x7f; - /* - * cr_ifs=[rv:ifm], ifm=[....:sof(6)] - * nlocals=number of local registers in the faulting function - */ - nlocals = (regs->cr_ifs) & 0x7f; + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); - /* - * save_switch_stack does a flushrs and saves bspstore. - * on_kbs = actual number of registers saved on kernel backing store - * (taking into accound potential RNATs) - * - * Note that this number can be greater than nlocals if the dirty - * parititions included more than one stack frame at the time we - * switched to KBS - */ - on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore); - bspstore = (unsigned long *)regs->ar_bspstore; + if ((r1 - 32) >= sof) { + /* this should never happen, as the "rsvd register fault" has higher priority */ + DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof); + return; + } + + on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + if (addr >= kbs) { + /* the register is on the kernel backing store: easy... */ + *val = *addr; + if (nat) { + rnat_addr = ia64_rse_rnat_addr(addr); + if ((unsigned long) rnat_addr >= sw->ar_bspstore) + rnat_addr = &sw->ar_rnat; + nat_mask = 1UL << ia64_rse_slot_num(addr); + *nat = (*rnat_addr & nat_mask) != 0; + } + return; + } /* - * To simplify the logic, we calculate everything as if there was only - * one backing store i.e., the user one (UBS). We let it to peek/poke - * to figure out whether the register we're looking for really is - * on the UBS or on KBS. - * - * regs->ar_bsptore = address of last register saved on UBS (before switch) - * - * ubs_end = virtual end of the UBS (if everything had been spilled there) - * - * We know that ubs_end is the point where the last register on the - * stack frame we're interested in as been saved. So we need to walk - * our way backward to figure out what the BSP "was" for that frame, - * this will give us the location of r32. - * - * bsp = "virtual UBS" address of r32 for our frame - * - * Finally, get compute the address of the register we're looking for - * using bsp as our base (move up again). - * - * Please note that in our case, we know that the register is necessarily - * on the KBS because we are only interested in the current frame at the moment - * we got the exception i.e., bsp is not changed until we switch to KBS. + * Avoid using user_mode() here: with "epc", we cannot use the privilege level to + * infer whether the interrupt task was running on the kernel backing store. */ + if (regs->r12 >= TASK_SIZE) { + DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1); + return; + } + + bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); - bsp = ia64_rse_skip_regs(ubs_end, -nlocals); - addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); + bsp = ia64_rse_skip_regs(ubs_end, -sof); + addr = ia64_rse_skip_regs(bsp, r1 - 32); - DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", - (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr))); - - ia64_peek(regs, current, (unsigned long)addr, val); + DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); - /* - * addr will now contain the address of the RNAT for the register - */ - addr = ia64_rse_rnat_addr(addr); + ia64_peek(current, (unsigned long) ubs_end, (unsigned long) addr, val); - ia64_peek(regs, current, (unsigned long)addr, &rnats); - DPRINT(("rnat @%p = 0x%lx\n", (void *) addr, rnats)); - - if (nat) - *nat = rnats >> ia64_rse_slot_num(slot) & 0x1; + if (nat) { + rnat_addr = ia64_rse_rnat_addr(addr); + nat_mask = 1UL << ia64_rse_slot_num(addr); + + DPRINT("rnat @%p = 0x%lx\n", (void *) rnat_addr, rnats); + + ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); + *nat = (rnats & nat_mask) != 0; + } } static void -setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) +setreg (unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) { - struct switch_stack *sw = (struct switch_stack *)regs -1; + struct switch_stack *sw = (struct switch_stack *) regs - 1; unsigned long addr; unsigned long bitmask; unsigned long *unat; - /* * First takes care of stacked registers */ - if (regnum >= IA64_FIRST_STACKED_GR) { + if (regnum >= IA64_FIRST_STACKED_GR) { set_rse_reg(regs, regnum, val, nat); return; } /* - * Using r0 as a target raises a General Exception fault which has - * higher priority than the Unaligned Reference fault. - */ + * Using r0 as a target raises a General Exception fault which has higher priority + * than the Unaligned Reference fault. + */ /* * Now look at registers in [0-31] range and init correct UNAT @@ -422,8 +439,8 @@ addr = (unsigned long)regs; unat = &sw->caller_unat; } - DPRINT(("tmp_base=%lx switch_stack=%s offset=%d\n", - addr, unat==&sw->ar_unat ? "yes":"no", GR_OFFS(regnum))); + DPRINT("tmp_base=%lx switch_stack=%s offset=%d\n", + addr, unat==&sw->ar_unat ? "yes":"no", GR_OFFS(regnum)); /* * add offset from base of struct * and do it ! @@ -436,20 +453,20 @@ * We need to clear the corresponding UNAT bit to fully emulate the load * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4 */ - bitmask = __IA64_UL(1) << (addr >> 3 & 0x3f); - DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat)); + bitmask = 1UL << (addr >> 3 & 0x3f); + DPRINT("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat); if (nat) { *unat |= bitmask; } else { *unat &= ~bitmask; } - DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat)); + DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat); } #define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR) static void -setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) +setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *)regs - 1; unsigned long addr; @@ -465,7 +482,7 @@ * * For now, we are using approach (1). */ - if (regnum >= IA64_FIRST_ROTATING_FR) { + if (regnum >= IA64_FIRST_ROTATING_FR) { ia64_sync_fph(current); current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval; } else { @@ -477,18 +494,18 @@ } else { addr = (unsigned long)regs; } - - DPRINT(("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum))); + + DPRINT("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum)); addr += FR_OFFS(regnum); *(struct ia64_fpreg *)addr = *fpval; /* - * mark the low partition as being used now + * mark the low partition as being used now * * It is highly unlikely that this bit is not already set, but * let's do it for safety. - */ + */ regs->cr_ipsr |= IA64_PSR_MFL; } } @@ -497,40 +514,40 @@ * Those 2 inline functions generate the spilled versions of the constant floating point * registers which can be used with stfX */ -static inline void -float_spill_f0(struct ia64_fpreg *final) +static inline void +float_spill_f0 (struct ia64_fpreg *final) { __asm__ __volatile__ ("stf.spill [%0]=f0" :: "r"(final) : "memory"); } -static inline void -float_spill_f1(struct ia64_fpreg *final) +static inline void +float_spill_f1 (struct ia64_fpreg *final) { __asm__ __volatile__ ("stf.spill [%0]=f1" :: "r"(final) : "memory"); } static void -getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) +getfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) { - struct switch_stack *sw = (struct switch_stack *)regs -1; + struct switch_stack *sw = (struct switch_stack *) regs - 1; unsigned long addr; /* - * From EAS-2.5: FPDisableFault has higher priority than - * Unaligned Fault. Thus, when we get here, we know the partition is + * From EAS-2.5: FPDisableFault has higher priority than + * Unaligned Fault. Thus, when we get here, we know the partition is * enabled. * * When regnum > 31, the register is still live and we need to force a save * to current->thread.fph to get access to it. See discussion in setfpreg() * for reasons and other ways of doing this. */ - if (regnum >= IA64_FIRST_ROTATING_FR) { + if (regnum >= IA64_FIRST_ROTATING_FR) { ia64_flush_fph(current); *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)]; } else { /* * f0 = 0.0, f1= 1.0. Those registers are constant and are thus - * not saved, we must generate their spilled form on the fly + * not saved, we must generate their spilled form on the fly */ switch(regnum) { case 0: @@ -546,8 +563,8 @@ addr = FR_IN_SW(regnum) ? (unsigned long)sw : (unsigned long)regs; - DPRINT(("is_sw=%d tmp_base=%lx offset=0x%x\n", - FR_IN_SW(regnum), addr, FR_OFFS(regnum))); + DPRINT("is_sw=%d tmp_base=%lx offset=0x%x\n", + FR_IN_SW(regnum), addr, FR_OFFS(regnum)); addr += FR_OFFS(regnum); *fpval = *(struct ia64_fpreg *)addr; @@ -557,12 +574,12 @@ static void -getreg(unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs) +getreg (unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs) { - struct switch_stack *sw = (struct switch_stack *)regs -1; + struct switch_stack *sw = (struct switch_stack *) regs - 1; unsigned long addr, *unat; - if (regnum >= IA64_FIRST_STACKED_GR) { + if (regnum >= IA64_FIRST_STACKED_GR) { get_rse_reg(regs, regnum, val, nat); return; } @@ -588,7 +605,7 @@ unat = &sw->caller_unat; } - DPRINT(("addr_base=%lx offset=0x%x\n", addr, GR_OFFS(regnum))); + DPRINT("addr_base=%lx offset=0x%x\n", addr, GR_OFFS(regnum)); addr += GR_OFFS(regnum); @@ -602,16 +619,16 @@ } static void -emulate_load_updates(update_t type, load_store_t *ld, struct pt_regs *regs, unsigned long ifa) -{ +emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsigned long ifa) +{ /* - * IMPORTANT: + * IMPORTANT: * Given the way we handle unaligned speculative loads, we should * not get to this point in the code but we keep this sanity check, * just in case. */ - if (ld->x6_op == 1 || ld->x6_op == 3) { - printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); + if (ld.x6_op == 1 || ld.x6_op == 3) { + printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); die_if_kernel("unaligned reference on specualtive load with register update\n", regs, 30); } @@ -624,18 +641,18 @@ if (type == UPD_IMMEDIATE) { unsigned long imm; - /* - * Load +Imm: ldXZ r1=[r3],imm(9) - * + /* + * Load +Imm: ldXZ r1=[r3],imm(9) + * * - * form imm9: [13:19] contain the first 7 bits - */ - imm = ld->x << 7 | ld->imm; + * form imm9: [13:19] contain the first 7 bits + */ + imm = ld.x << 7 | ld.imm; /* * sign extend (1+8bits) if m set */ - if (ld->m) imm |= SIGN_EXT9; + if (ld.m) imm |= SIGN_EXT9; /* * ifa == r3 and we know that the NaT bit on r3 was clear so @@ -643,109 +660,79 @@ */ ifa += imm; - setreg(ld->r3, ifa, 0, regs); + setreg(ld.r3, ifa, 0, regs); - DPRINT(("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld->x, ld->m, imm, ifa)); + DPRINT("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld.x, ld.m, imm, ifa); - } else if (ld->m) { + } else if (ld.m) { unsigned long r2; int nat_r2; /* * Load +Reg Opcode: ldXZ r1=[r3],r2 * - * Note: that we update r3 even in the case of ldfX.a + * Note: that we update r3 even in the case of ldfX.a * (where the load does not happen) * * The way the load algorithm works, we know that r3 does not * have its NaT bit set (would have gotten NaT consumption - * before getting the unaligned fault). So we can use ifa + * before getting the unaligned fault). So we can use ifa * which equals r3 at this point. * * IMPORTANT: - * The above statement holds ONLY because we know that we + * The above statement holds ONLY because we know that we * never reach this code when trying to do a ldX.s. - * If we ever make it to here on an ldfX.s then + * If we ever make it to here on an ldfX.s then */ - getreg(ld->imm, &r2, &nat_r2, regs); - + getreg(ld.imm, &r2, &nat_r2, regs); + ifa += r2; - + /* * propagate Nat r2 -> r3 */ - setreg(ld->r3, ifa, nat_r2, regs); + setreg(ld.r3, ifa, nat_r2, regs); - DPRINT(("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld->imm, r2, ifa, nat_r2)); + DPRINT("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld.imm, r2, ifa, nat_r2); } } static int -emulate_load_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { - unsigned long val; - unsigned int len = 1<< ld->x6_sz; - - /* - * the macro supposes sequential access (which is the case) - * if the first byte is an invalid address we return here. Otherwise - * there is a guard page at the top of the user's address page and - * the first access would generate a NaT consumption fault and return - * with a SIGSEGV, which is what we want. - * - * Note: the first argument is ignored - */ - if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n", ifa)); - return -1; - } + unsigned int len = 1 << ld.x6_sz; /* * r0, as target, doesn't need to be checked because Illegal Instruction * faults have higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an + * r0 cannot be found as the base as it would never generate an * unaligned reference. */ /* - * ldX.a we don't try to emulate anything but we must - * invalidate the ALAT entry. + * ldX.a we don't try to emulate anything but we must invalidate the ALAT entry. * See comment below for explanation on how we handle ldX.a */ - if (ld->x6_op != 0x2) { - /* - * we rely on the macros in unaligned.h for now i.e., - * we let the compiler figure out how to read memory gracefully. - * - * We need this switch/case because the way the inline function - * works. The code is optimized by the compiler and looks like - * a single switch/case. - */ - switch(len) { - case 2: - val = ia64_get_unaligned((void *)ifa, 2); - break; - case 4: - val = ia64_get_unaligned((void *)ifa, 4); - break; - case 8: - val = ia64_get_unaligned((void *)ifa, 8); - break; - default: - DPRINT(("unknown size: x6=%d\n", ld->x6_sz)); - return -1; - } + if (ld.x6_op != 0x2) { + unsigned long val = 0; - setreg(ld->r1, val, 0, regs); + if (len != 2 && len != 4 && len != 8) { + DPRINT("unknown size: x6=%d\n", ld.x6_sz); + return -1; + } + /* this assumes little-endian byte-order: */ + if (copy_from_user(&val, (void *) ifa, len)) + return -1; + setreg(ld.r1, val, 0, regs); } /* * check for updates on any kind of loads */ - if (ld->op == 0x5 || ld->m) - emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); + if (ld.op == 0x5 || ld.m) + emulate_load_updates(ld.op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); /* * handling of various loads (based on EAS2.4): @@ -753,7 +740,6 @@ * ldX.acq (ordered load): * - acquire semantics would have been used, so force fence instead. * - * * ldX.c.clr (check load and clear): * - if we get to this handler, it's because the entry was not in the ALAT. * Therefore the operation reverts to a normal load @@ -764,15 +750,15 @@ * ldX.c.clr.acq (ordered check load and clear): * - same as above for c.clr part. The load needs to have acquire semantics. So * we use the fence semantics which is stronger and thus ensures correctness. - * + * * ldX.a (advanced load): - * - suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the - * address doesn't match requested size alignement. This means that we would + * - suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the + * address doesn't match requested size alignement. This means that we would * possibly need more than one load to get the result. * * The load part can be handled just like a normal load, however the difficult * part is to get the right thing into the ALAT. The critical piece of information - * in the base address of the load & size. To do that, a ld.a must be executed, + * in the base address of the load & size. To do that, a ld.a must be executed, * clearly any address can be pushed into the table by using ld1.a r1=[r3]. Now * if we use the same target register, we will be okay for the check.a instruction. * If we look at the store, basically a stX [r3]=r1 checks the ALAT for any entry @@ -791,7 +777,7 @@ * store & shift to temporary; * ld1.a r1=[r3] * store & shift to temporary; - * r1=temporary + * r1=temporary * * So int this case, you would get the right value is r1 but the wrong info in * the ALAT. Notice that you could do it in reverse to finish with address 3 @@ -815,7 +801,7 @@ * So it's okay NOT to do any actual load on an unaligned ld.a. However the ALAT * must be invalidated for the register (so that's chck.a.*,ld.c.* don't pick up * a stale entry later) The register base update MUST also be performed. - * + * * Now what is the content of the register and its NaT bit in the case we don't * do the load ? EAS2.4, says (in case an actual load is needed) * @@ -828,40 +814,26 @@ */ /* - * when the load has the .acq completer then + * when the load has the .acq completer then * use ordering fence. */ - if (ld->x6_op == 0x5 || ld->x6_op == 0xa) + if (ld.x6_op == 0x5 || ld.x6_op == 0xa) mb(); /* * invalidate ALAT entry in case of advanced load */ - if (ld->x6_op == 0x2) - invala_gr(ld->r1); + if (ld.x6_op == 0x2) + invala_gr(ld.r1); return 0; } static int -emulate_store_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_store_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { unsigned long r2; - unsigned int len = 1<< ld->x6_sz; - - /* - * the macro supposes sequential access (which is the case) - * if the first byte is an invalid address we return here. Otherwise - * there is a guard page at the top of the user's address page and - * the first access would generate a NaT consumption fault and return - * with a SIGSEGV, which is what we want. - * - * Note: the first argument is ignored - */ - if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n",ifa)); - return -1; - } + unsigned int len = 1 << ld.x6_sz; /* * if we get to this handler, Nat bits on both r3 and r2 have already @@ -869,7 +841,7 @@ * * extract the value to be stored */ - getreg(ld->imm, &r2, 0, regs); + getreg(ld.imm, &r2, 0, regs); /* * we rely on the macros in unaligned.h for now i.e., @@ -879,48 +851,43 @@ * works. The code is optimized by the compiler and looks like * a single switch/case. */ - DPRINT(("st%d [%lx]=%lx\n", len, ifa, r2)); + DPRINT("st%d [%lx]=%lx\n", len, ifa, r2); - switch(len) { - case 2: - ia64_put_unaligned(r2, (void *)ifa, 2); - break; - case 4: - ia64_put_unaligned(r2, (void *)ifa, 4); - break; - case 8: - ia64_put_unaligned(r2, (void *)ifa, 8); - break; - default: - DPRINT(("unknown size: x6=%d\n", ld->x6_sz)); - return -1; + if (len != 2 && len != 4 && len != 8) { + DPRINT("unknown size: x6=%d\n", ld.x6_sz); + return -1; } + + /* this assumes little-endian byte-order: */ + if (copy_to_user((void *) ifa, &r2, len)) + return -1; + /* * stX [r3]=r2,imm(9) * * NOTE: - * ld->r3 can never be r0, because r0 would not generate an + * ld.r3 can never be r0, because r0 would not generate an * unaligned access. */ - if (ld->op == 0x5) { + if (ld.op == 0x5) { unsigned long imm; /* * form imm9: [12:6] contain first 7bits */ - imm = ld->x << 7 | ld->r1; + imm = ld.x << 7 | ld.r1; /* * sign extend (8bits) if m set */ - if (ld->m) imm |= SIGN_EXT9; + if (ld.m) imm |= SIGN_EXT9; /* * ifa == r3 (NaT is necessarily cleared) */ ifa += imm; - DPRINT(("imm=%lx r3=%lx\n", imm, ifa)); - - setreg(ld->r3, ifa, 0, regs); + DPRINT("imm=%lx r3=%lx\n", imm, ifa); + + setreg(ld.r3, ifa, 0, regs); } /* * we don't have alat_invalidate_multiple() so we need @@ -931,7 +898,7 @@ /* * stX.rel: use fence instead of release */ - if (ld->x6_op == 0xd) + if (ld.x6_op == 0xd) mb(); return 0; @@ -940,120 +907,108 @@ /* * floating point operations sizes in bytes */ -static const unsigned short float_fsz[4]={ +static const unsigned char float_fsz[4]={ 16, /* extended precision (e) */ 8, /* integer (8) */ 4, /* single precision (s) */ 8 /* double precision (d) */ }; -static inline void -mem2float_extended(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_extended (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldfe f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -mem2float_integer(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_integer (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf8 f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -mem2float_single(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_single (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldfs f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -mem2float_double(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +mem2float_double (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldfd f6=[%0];; stf.spill [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_extended(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_extended (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stfe [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_integer(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_integer (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stf8 [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_single(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_single (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stfs [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } -static inline void -float2mem_double(struct ia64_fpreg *init, struct ia64_fpreg *final) +static inline void +float2mem_double (struct ia64_fpreg *init, struct ia64_fpreg *final) { __asm__ __volatile__ ("ldf.fill f6=[%0];; stfd [%1]=f6" :: "r"(init), "r"(final) : "f6","memory"); } static int -emulate_load_floatpair(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { struct ia64_fpreg fpr_init[2]; struct ia64_fpreg fpr_final[2]; - unsigned long len = float_fsz[ld->x6_sz]; + unsigned long len = float_fsz[ld.x6_sz]; - if (access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0) { - DPRINT(("verify area failed on %lx\n", ifa)); - return -1; - } /* * fr0 & fr1 don't need to be checked because Illegal Instruction * faults have higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an + * r0 cannot be found as the base as it would never generate an * unaligned reference. */ - /* + /* * make sure we get clean buffers */ - memset(&fpr_init,0, sizeof(fpr_init)); - memset(&fpr_final,0, sizeof(fpr_final)); + memset(&fpr_init, 0, sizeof(fpr_init)); + memset(&fpr_final, 0, sizeof(fpr_final)); /* * ldfpX.a: we don't try to emulate anything but we must * invalidate the ALAT entry and execute updates, if any. */ - if (ld->x6_op != 0x2) { - /* - * does the unaligned access - */ - memcpy(&fpr_init[0], (void *)ifa, len); - memcpy(&fpr_init[1], (void *)(ifa+len), len); + if (ld.x6_op != 0x2) { + /* this assumes little-endian byte-order: */ - DPRINT(("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld->r1, ld->imm, ld->x6_sz)); -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_init; - printk("fpr_init= "); - for(i=0; i < len<<1; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + if (copy_from_user(&fpr_init[0], (void *) ifa, len) + || copy_from_user(&fpr_init[1], (void *) (ifa + len), len)) + return -1; + + DPRINT("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld.r1, ld.imm, ld.x6_sz); + DDUMP("frp_init =", &fpr_init, 2*len); /* * XXX fixme - * Could optimize inlines by using ldfpX & 2 spills + * Could optimize inlines by using ldfpX & 2 spills */ - switch( ld->x6_sz ) { + switch( ld.x6_sz ) { case 0: mem2float_extended(&fpr_init[0], &fpr_final[0]); mem2float_extended(&fpr_init[1], &fpr_final[1]); @@ -1071,15 +1026,7 @@ mem2float_double(&fpr_init[1], &fpr_final[1]); break; } -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_final; - printk("fpr_final= "); - for(i=0; i < len<<1; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DDUMP("fpr_final =", &fpr_final, 2*len); /* * XXX fixme * @@ -1087,16 +1034,15 @@ * use the storage from the saved context i.e., the actual final * destination (pt_regs, switch_stack or thread structure). */ - setfpreg(ld->r1, &fpr_final[0], regs); - setfpreg(ld->imm, &fpr_final[1], regs); + setfpreg(ld.r1, &fpr_final[0], regs); + setfpreg(ld.imm, &fpr_final[1], regs); } /* * Check for updates: only immediate updates are available for this * instruction. */ - if (ld->m) { - + if (ld.m) { /* * the immediate is implicit given the ldsz of the operation: * single: 8 (2x4) and for all others it's 16 (2x8) @@ -1104,57 +1050,45 @@ ifa += len<<1; /* - * IMPORTANT: + * IMPORTANT: * the fact that we force the NaT of r3 to zero is ONLY valid * as long as we don't come here with a ldfpX.s. * For this reason we keep this sanity check */ - if (ld->x6_op == 1 || ld->x6_op == 3) { - printk(KERN_ERR "%s: register update on speculative load pair, error\n", - __FUNCTION__); - } - + if (ld.x6_op == 1 || ld.x6_op == 3) + printk(KERN_ERR __FUNCTION__": register update on speculative load pair, " + "error\n"); - setreg(ld->r3, ifa, 0, regs); + setreg(ld.r3, ifa, 0, regs); } /* * Invalidate ALAT entries, if any, for both registers. */ - if (ld->x6_op == 0x2) { - invala_fr(ld->r1); - invala_fr(ld->imm); + if (ld.x6_op == 0x2) { + invala_fr(ld.r1); + invala_fr(ld.imm); } return 0; } static int -emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_load_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { struct ia64_fpreg fpr_init; struct ia64_fpreg fpr_final; - unsigned long len = float_fsz[ld->x6_sz]; + unsigned long len = float_fsz[ld.x6_sz]; /* - * check for load pair because our masking scheme is not fine grain enough - if (ld->x == 1) return emulate_load_floatpair(ifa,ld,regs); - */ - - if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n", ifa)); - return -1; - } - /* * fr0 & fr1 don't need to be checked because Illegal Instruction * faults have higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an + * r0 cannot be found as the base as it would never generate an * unaligned reference. */ - - /* + /* * make sure we get clean buffers */ memset(&fpr_init,0, sizeof(fpr_init)); @@ -1165,27 +1099,16 @@ * invalidate the ALAT entry. * See comments in ldX for descriptions on how the various loads are handled. */ - if (ld->x6_op != 0x2) { - - /* - * does the unaligned access - */ - memcpy(&fpr_init, (void *)ifa, len); + if (ld.x6_op != 0x2) { + if (copy_from_user(&fpr_init, (void *) ifa, len)) + return -1; - DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz)); -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_init; - printk("fpr_init= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz); + DDUMP("fpr_init =", &fpr_init, len); /* * we only do something for x6_op={0,8,9} */ - switch( ld->x6_sz ) { + switch( ld.x6_sz ) { case 0: mem2float_extended(&fpr_init, &fpr_final); break; @@ -1199,15 +1122,7 @@ mem2float_double(&fpr_init, &fpr_final); break; } -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_final; - printk("fpr_final= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DDUMP("fpr_final =", &fpr_final, len); /* * XXX fixme * @@ -1215,66 +1130,51 @@ * use the storage from the saved context i.e., the actual final * destination (pt_regs, switch_stack or thread structure). */ - setfpreg(ld->r1, &fpr_final, regs); + setfpreg(ld.r1, &fpr_final, regs); } /* * check for updates on any loads */ - if (ld->op == 0x7 || ld->m) - emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); + if (ld.op == 0x7 || ld.m) + emulate_load_updates(ld.op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); /* * invalidate ALAT entry in case of advanced floating point loads */ - if (ld->x6_op == 0x2) - invala_fr(ld->r1); + if (ld.x6_op == 0x2) + invala_fr(ld.r1); return 0; } static int -emulate_store_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +emulate_store_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs) { struct ia64_fpreg fpr_init; struct ia64_fpreg fpr_final; - unsigned long len = float_fsz[ld->x6_sz]; - - /* - * the macro supposes sequential access (which is the case) - * if the first byte is an invalid address we return here. Otherwise - * there is a guard page at the top of the user's address page and - * the first access would generate a NaT consumption fault and return - * with a SIGSEGV, which is what we want. - * - * Note: the first argument is ignored - */ - if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) { - DPRINT(("verify area failed on %lx\n",ifa)); - return -1; - } + unsigned long len = float_fsz[ld.x6_sz]; - /* + /* * make sure we get clean buffers */ memset(&fpr_init,0, sizeof(fpr_init)); memset(&fpr_final,0, sizeof(fpr_final)); - /* * if we get to this handler, Nat bits on both r3 and r2 have already * been checked. so we don't need to do it * * extract the value to be stored */ - getfpreg(ld->imm, &fpr_init, regs); + getfpreg(ld.imm, &fpr_init, regs); /* * during this step, we extract the spilled registers from the saved * context i.e., we refill. Then we store (no spill) to temporary * aligned location */ - switch( ld->x6_sz ) { + switch( ld.x6_sz ) { case 0: float2mem_extended(&fpr_init, &fpr_final); break; @@ -1288,56 +1188,40 @@ float2mem_double(&fpr_init, &fpr_final); break; } - DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz)); -#ifdef DEBUG_UNALIGNED_TRAP - { int i; char *c = (char *)&fpr_init; - printk("fpr_init= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } - { int i; char *c = (char *)&fpr_final; - printk("fpr_final= "); - for(i=0; i < len; i++ ) { - printk("%02x ", c[i]&0xff); - } - printk("\n"); - } -#endif + DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz); + DDUMP("fpr_init =", &fpr_init, len); + DDUMP("fpr_final =", &fpr_final, len); - /* - * does the unaligned store - */ - memcpy((void *)ifa, &fpr_final, len); + if (copy_to_user((void *) ifa, &fpr_final, len)) + return -1; /* * stfX [r3]=r2,imm(9) * * NOTE: - * ld->r3 can never be r0, because r0 would not generate an + * ld.r3 can never be r0, because r0 would not generate an * unaligned access. */ - if (ld->op == 0x7) { + if (ld.op == 0x7) { unsigned long imm; /* * form imm9: [12:6] contain first 7bits */ - imm = ld->x << 7 | ld->r1; + imm = ld.x << 7 | ld.r1; /* * sign extend (8bits) if m set */ - if (ld->m) - imm |= SIGN_EXT9; + if (ld.m) + imm |= SIGN_EXT9; /* * ifa == r3 (NaT is necessarily cleared) */ ifa += imm; - DPRINT(("imm=%lx r3=%lx\n", imm, ifa)); - - setreg(ld->r3, ifa, 0, regs); + DPRINT("imm=%lx r3=%lx\n", imm, ifa); + + setreg(ld.r3, ifa, 0, regs); } /* * we don't have alat_invalidate_multiple() so we need @@ -1348,132 +1232,106 @@ return 0; } -void -ia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs) +/* + * Make sure we log the unaligned access, so that user/sysadmin can notice it and + * eventually fix the program. However, we don't want to do that for every access so we + * pace it with jiffies. This isn't really MP-safe, but it doesn't really have to be + * either... + */ +static int +within_logging_rate_limit (void) { - static unsigned long unalign_count; - static long last_time; + static unsigned long count, last_time; + if (jiffies - last_time > 5*HZ) + count = 0; + if (++count < 5) { + last_time = jiffies; + return 1; + } + return 0; + +} + +void +ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) +{ + struct exception_fixup fix = { 0 }; struct ia64_psr *ipsr = ia64_psr(regs); - unsigned long *bundle_addr; + mm_segment_t old_fs = get_fs(); + unsigned long bundle[2]; unsigned long opcode; - unsigned long op; - load_store_t *insn; + struct siginfo si; + union { + unsigned long l; + load_store_t insn; + } u; int ret = -1; + if (ia64_psr(regs)->be) { + /* we don't support big-endian accesses */ + die_if_kernel("big-endian unaligned accesses are not supported", regs, 0); + goto force_sigbus; + } + /* - * Unaligned references in the kernel could come from unaligned - * arguments to system calls. We fault the user process in - * these cases and panic the kernel otherwise (the kernel should - * be fixed to not make unaligned accesses). + * Treat kernel accesses for which there is an exception handler entry the same as + * user-level unaligned accesses. Otherwise, a clever program could trick this + * handler into reading an arbitrary kernel addresses... */ if (!user_mode(regs)) { - const struct exception_table_entry *fix; - +#ifdef GAS_HAS_LOCAL_TAGS + fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); +#else fix = search_exception_table(regs->cr_iip); - if (fix) { - regs->r8 = -EFAULT; - if (fix->skip & 1) { - regs->r9 = 0; - } - regs->cr_iip += ((long) fix->skip) & ~15; - regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */ - return; - } - die_if_kernel("Unaligned reference while in kernel\n", regs, 30); - /* NOT_REACHED */ - } - /* - * For now, we don't support user processes running big-endian - * which do unaligned accesses - */ - if (ia64_psr(regs)->be) { - struct siginfo si; - - printk(KERN_ERR "%s(%d): big-endian unaligned access %016lx (ip=%016lx) not " - "yet supported\n", - current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); - - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; - force_sig_info(SIGBUS, &si, current); - return; - } - - if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) { - struct siginfo si; - - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; - force_sig_info(SIGBUS, &si, current); - return; +#endif } - - if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) { - /* - * Make sure we log the unaligned access, so that - * user/sysadmin can notice it and eventually fix the - * program. - * - * We don't want to do that for every access so we - * pace it with jiffies. - */ - if (unalign_count > 5 && jiffies - last_time > 5*HZ) - unalign_count = 0; - if (++unalign_count < 5) { + if (user_mode(regs) || fix.cont) { + if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0) + goto force_sigbus; + + if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT) + && within_logging_rate_limit()) + { char buf[200]; /* comm[] is at most 16 bytes... */ size_t len; - last_time = jiffies; - len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, ip=0x%016lx\n\r", - current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, " + "ip=0x%016lx\n\r", current->comm, current->pid, + ifa, regs->cr_iip + ipsr->ri); tty_write_message(current->tty, buf); buf[len-1] = '\0'; /* drop '\r' */ - printk("%s", buf); /* guard against command names containing %s!! */ + printk(KERN_WARNING "%s", buf); /* watch for command names containing %s */ } + } else { + if (within_logging_rate_limit()) + printk(KERN_WARNING "kernel unaligned access to 0x%016lx, ip=0x%016lx\n", + ifa, regs->cr_iip + ipsr->ri); + set_fs(KERNEL_DS); } - DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr)); - DPRINT(("ISR.ei=%d ISR.sp=%d\n", ipsr->ri, ipsr->it)); + DPRINT("iip=%lx ifa=%lx isr=%lx (ei=%d, sp=%d)\n", + regs->cr_iip, ifa, regs->cr_ipsr, ipsr->ri, ipsr->it); - bundle_addr = (unsigned long *)(regs->cr_iip); + if (__copy_from_user(bundle, (void *) regs->cr_iip, 16)) + goto failure; /* * extract the instruction from the bundle given the slot number */ - switch ( ipsr->ri ) { - case 0: op = *bundle_addr >> 5; - break; - - case 1: op = *bundle_addr >> 46 | (*(bundle_addr+1) & 0x7fffff)<<18; - break; - - case 2: op = *(bundle_addr+1) >> 23; - break; + switch (ipsr->ri) { + case 0: u.l = (bundle[0] >> 5); break; + case 1: u.l = (bundle[0] >> 46) | (bundle[1] << 18); break; + case 2: u.l = (bundle[1] >> 23); break; } + opcode = (u.l >> IA64_OPCODE_SHIFT) & IA64_OPCODE_MASK; - insn = (load_store_t *)&op; - opcode = op & IA64_OPCODE_MASK; - - DPRINT(("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d " - "ld.x6=0x%x ld.m=%d ld.op=%d\n", - opcode, - insn->qp, - insn->r1, - insn->imm, - insn->r3, - insn->x, - insn->hint, - insn->x6_sz, - insn->m, - insn->op)); + DPRINT("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d " + "ld.x6=0x%x ld.m=%d ld.op=%d\n", opcode, u.insn.qp, u.insn.r1, u.insn.imm, + u.insn.r3, u.insn.x, u.insn.hint, u.insn.x6_sz, u.insn.m, u.insn.op); /* - * IMPORTANT: + * IMPORTANT: * Notice that the swictch statement DOES not cover all possible instructions * that DO generate unaligned references. This is made on purpose because for some * instructions it DOES NOT make sense to try and emulate the access. Sometimes it @@ -1483,104 +1341,124 @@ * load/store: * - ldX.spill * - stX.spill - * Reason: RNATs are based on addresses + * Reason: RNATs are based on addresses * * synchronization: * - cmpxchg * - fetchadd * - xchg - * Reason: ATOMIC operations cannot be emulated properly using multiple - * instructions. + * Reason: ATOMIC operations cannot be emulated properly using multiple + * instructions. * * speculative loads: * - ldX.sZ - * Reason: side effects, code must be ready to deal with failure so simpler - * to let the load fail. + * Reason: side effects, code must be ready to deal with failure so simpler + * to let the load fail. * --------------------------------------------------------------------------------- * XXX fixme * * I would like to get rid of this switch case and do something * more elegant. */ - switch(opcode) { - case LDS_OP: - case LDSA_OP: - case LDS_IMM_OP: - case LDSA_IMM_OP: - case LDFS_OP: - case LDFSA_OP: - case LDFS_IMM_OP: - /* - * The instruction will be retried with defered exceptions - * turned on, and we should get Nat bit installed - * - * IMPORTANT: - * When PSR_ED is set, the register & immediate update - * forms are actually executed even though the operation - * failed. So we don't need to take care of this. - */ - DPRINT(("forcing PSR_ED\n")); - regs->cr_ipsr |= IA64_PSR_ED; - return; - - case LD_OP: - case LDA_OP: - case LDBIAS_OP: - case LDACQ_OP: - case LDCCLR_OP: - case LDCNC_OP: - case LDCCLRACQ_OP: - case LD_IMM_OP: - case LDA_IMM_OP: - case LDBIAS_IMM_OP: - case LDACQ_IMM_OP: - case LDCCLR_IMM_OP: - case LDCNC_IMM_OP: - case LDCCLRACQ_IMM_OP: - ret = emulate_load_int(ifa, insn, regs); - break; - case ST_OP: - case STREL_OP: - case ST_IMM_OP: - case STREL_IMM_OP: - ret = emulate_store_int(ifa, insn, regs); - break; - case LDF_OP: - case LDFA_OP: - case LDFCCLR_OP: - case LDFCNC_OP: - case LDF_IMM_OP: - case LDFA_IMM_OP: - case LDFCCLR_IMM_OP: - case LDFCNC_IMM_OP: - ret = insn->x ? - emulate_load_floatpair(ifa, insn, regs): - emulate_load_float(ifa, insn, regs); - break; - case STF_OP: - case STF_IMM_OP: - ret = emulate_store_float(ifa, insn, regs); - } - - DPRINT(("ret=%d\n", ret)); - if (ret) { - struct siginfo si; - - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void *) ifa; - force_sig_info(SIGBUS, &si, current); - } else { + switch (opcode) { + case LDS_OP: + case LDSA_OP: + case LDS_IMM_OP: + case LDSA_IMM_OP: + case LDFS_OP: + case LDFSA_OP: + case LDFS_IMM_OP: /* - * given today's architecture this case is not likely to happen - * because a memory access instruction (M) can never be in the - * last slot of a bundle. But let's keep it for now. - */ - if (ipsr->ri == 2) - regs->cr_iip += 16; - ipsr->ri = ++ipsr->ri & 3; - } + * The instruction will be retried with deferred exceptions turned on, and + * we should get Nat bit installed + * + * IMPORTANT: When PSR_ED is set, the register & immediate update forms + * are actually executed even though the operation failed. So we don't + * need to take care of this. + */ + DPRINT("forcing PSR_ED\n"); + regs->cr_ipsr |= IA64_PSR_ED; + goto done; + + case LD_OP: + case LDA_OP: + case LDBIAS_OP: + case LDACQ_OP: + case LDCCLR_OP: + case LDCNC_OP: + case LDCCLRACQ_OP: + case LD_IMM_OP: + case LDA_IMM_OP: + case LDBIAS_IMM_OP: + case LDACQ_IMM_OP: + case LDCCLR_IMM_OP: + case LDCNC_IMM_OP: + case LDCCLRACQ_IMM_OP: + ret = emulate_load_int(ifa, u.insn, regs); + break; + + case ST_OP: + case STREL_OP: + case ST_IMM_OP: + case STREL_IMM_OP: + ret = emulate_store_int(ifa, u.insn, regs); + break; + + case LDF_OP: + case LDFA_OP: + case LDFCCLR_OP: + case LDFCNC_OP: + case LDF_IMM_OP: + case LDFA_IMM_OP: + case LDFCCLR_IMM_OP: + case LDFCNC_IMM_OP: + if (u.insn.x) + ret = emulate_load_floatpair(ifa, u.insn, regs); + else + ret = emulate_load_float(ifa, u.insn, regs); + break; + + case STF_OP: + case STF_IMM_OP: + ret = emulate_store_float(ifa, u.insn, regs); + break; + + default: + goto failure; + } + DPRINT("ret=%d\n", ret); + if (ret) + goto failure; + + if (ipsr->ri == 2) + /* + * given today's architecture this case is not likely to happen because a + * memory access instruction (M) can never be in the last slot of a + * bundle. But let's keep it for now. + */ + regs->cr_iip += 16; + ipsr->ri = (ipsr->ri + 1) & 0x3; + + DPRINT("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip); + done: + set_fs(old_fs); /* restore original address limit */ + return; - DPRINT(("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip)); + failure: + /* something went wrong... */ + if (!user_mode(regs)) { + if (fix.cont) { + handle_exception(regs, fix); + goto done; + } + die_if_kernel("error during unaligned kernel access\n", regs, ret); + /* NOT_REACHED */ + } + force_sigbus: + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRALN; + si.si_addr = (void *) ifa; + force_sig_info(SIGBUS, &si, current); + goto done; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/kernel/unwind.c linux.ac/arch/ia64/kernel/unwind.c --- linux.vanilla/arch/ia64/kernel/unwind.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/kernel/unwind.c Sat Apr 14 01:18:00 2001 @@ -1,6 +1,6 @@ /* - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang */ /* * This file implements call frame unwind support for the Linux @@ -24,15 +24,12 @@ * o if both the unw.lock spinlock and a script's read-write lock must be * acquired, then the read-write lock must be acquired first. */ -#include #include #include #include #include -#ifdef CONFIG_IA64_NEW_UNWIND - #include #include #include @@ -306,7 +303,7 @@ } } else { /* access a stacked register */ - addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum); + addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum - 32); nat_addr = ia64_rse_rnat_addr(addr); if ((unsigned long) addr < info->regstk.limit || (unsigned long) addr >= info->regstk.top) @@ -660,7 +657,7 @@ */ if (sr->any_spills) { off = sr->spill_offset; - alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31); + alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31); alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_B1, sr->curr.reg + UNW_REG_B5); alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_R4, sr->curr.reg + UNW_REG_R7); } @@ -911,6 +908,10 @@ struct unw_reg_state *rs; rs = alloc_reg_state(); + if (!rs) { + printk("unwind: cannot stack!\n"); + return; + } memcpy(rs, &sr->curr, sizeof(*rs)); rs->label = label; rs->next = sr->reg_state_list; @@ -927,7 +928,7 @@ if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1)) return 0; if (qp > 0) { - if ((sr->pr_val & (1UL << qp)) == 0) + if ((sr->pr_val & (1UL << qp)) == 0) return 0; sr->pr_mask |= (1UL << qp); } @@ -944,7 +945,7 @@ r = sr->curr.reg + decode_abreg(abreg, 0); r->where = UNW_WHERE_NONE; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = UNW_WHEN_NEVER; r->val = 0; } @@ -1443,12 +1444,17 @@ * sp has been restored and all values on the memory stack below * psp also have been restored. */ - sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; sr.curr.reg[UNW_REG_PSP].val = 0; + sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; + sr.curr.reg[UNW_REG_PSP].when = UNW_WHEN_NEVER; for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10) || r->where == UNW_WHERE_SPREL) + { + r->val = 0; r->where = UNW_WHERE_NONE; + r->when = UNW_WHEN_NEVER; + } } script->flags = sr.flags; @@ -1477,7 +1483,7 @@ case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", r->val); break; case UNW_WHERE_NONE: printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val); - break; + break; default: printk("BADWHERE(%d)", r->where); break; } printk("\t\t%d\n", r->when); @@ -1604,7 +1610,9 @@ case UNW_INSN_LOAD: #if UNW_DEBUG - if ((s[val] & (my_cpu_data.unimpl_va_mask | 0x7)) || s[val] < TASK_SIZE) { + if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0 + || s[val] < TASK_SIZE) + { debug(1, "unwind: rejecting bad psp=0x%lx\n", s[val]); break; } @@ -1636,7 +1644,7 @@ int have_write_lock = 0; struct unw_script *scr; - if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { + if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { /* don't let obviously bad addresses pollute the cache */ debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip); info->rp_loc = 0; @@ -1672,7 +1680,7 @@ unsigned long ip, pr, num_regs; STAT(unsigned long start, flags;) int retval; - + STAT(local_irq_save(flags); ++unw.stat.api.unwinds; start = ia64_get_itc()); prev_ip = info->ip; @@ -1818,140 +1826,14 @@ STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); } -#endif /* CONFIG_IA64_NEW_UNWIND */ - void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t) { struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16); -#ifdef CONFIG_IA64_NEW_UNWIND unw_init_frame_info(info, t, sw); -#else - unsigned long sol, limit, top; - - memset(info, 0, sizeof(*info)); - - sol = (sw->ar_pfs >> 7) & 0x7f; /* size of locals */ - - limit = (unsigned long) t + IA64_RBS_OFFSET; - top = sw->ar_bspstore; - if (top - (unsigned long) t >= IA64_STK_OFFSET) - top = limit; - - info->regstk.limit = limit; - info->regstk.top = top; - info->sw = sw; - info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); - info->cfm_loc = &sw->ar_pfs; - info->ip = sw->b0; -#endif } -void -unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs) -{ -#ifdef CONFIG_IA64_NEW_UNWIND - struct switch_stack *sw = (struct switch_stack *) regs - 1; - - unw_init_frame_info(info, current, sw); - /* skip over interrupt frame: */ - unw_unwind(info); -#else - struct switch_stack *sw = (struct switch_stack *) regs - 1; - unsigned long sol, sof, *bsp, limit, top; - - limit = (unsigned long) current + IA64_RBS_OFFSET; - top = sw->ar_bspstore; - if (top - (unsigned long) current >= IA64_STK_OFFSET) - top = limit; - - memset(info, 0, sizeof(*info)); - - sol = (sw->ar_pfs >> 7) & 0x7f; /* size of frame */ - - /* this gives us the bsp top level frame (kdb interrupt frame): */ - bsp = ia64_rse_skip_regs((unsigned long *) top, -sol); - - /* now skip past the interrupt frame: */ - sof = regs->cr_ifs & 0x7f; /* size of frame */ - - info->regstk.limit = limit; - info->regstk.top = top; - info->sw = sw; - info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof); - info->cfm_loc = ®s->cr_ifs; - info->ip = regs->cr_iip; -#endif -} - -#ifndef CONFIG_IA64_NEW_UNWIND - -static unsigned long -read_reg (struct unw_frame_info *info, int regnum, int *is_nat) -{ - unsigned long *addr, *rnat_addr, rnat; - - addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum); - if ((unsigned long) addr < info->regstk.limit - || (unsigned long) addr >= info->regstk.top || ((long) addr & 0x7) != 0) - { - *is_nat = 1; - return 0xdeadbeefdeadbeef; - } - rnat_addr = ia64_rse_rnat_addr(addr); - - if ((unsigned long) rnat_addr >= info->regstk.top) - rnat = info->sw->ar_rnat; - else - rnat = *rnat_addr; - *is_nat = (rnat & (1UL << ia64_rse_slot_num(addr))) != 0; - return *addr; -} - -/* - * On entry, info->regstk.top should point to the register backing - * store for r32. - */ -int -unw_unwind (struct unw_frame_info *info) -{ - unsigned long sol, cfm = *info->cfm_loc; - int is_nat; - - sol = (cfm >> 7) & 0x7f; /* size of locals */ - - /* - * In general, we would have to make use of unwind info to - * unwind an IA-64 stack, but for now gcc uses a special - * convention that makes this possible without full-fledged - * unwindo info. Specifically, we expect "rp" in the second - * last, and "ar.pfs" in the last local register, so the - * number of locals in a frame must be at least two. If it's - * less than that, we reached the end of the C call stack. - */ - if (sol < 2) - return -1; - - info->ip = read_reg(info, sol - 2, &is_nat); - if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf))) - /* reject let obviously bad addresses */ - return -1; - - info->cfm_loc = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1); - cfm = read_reg(info, sol - 1, &is_nat); - if (is_nat) - return -1; - - sol = (cfm >> 7) & 0x7f; - - info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -sol); - return 0; -} -#endif /* !CONFIG_IA64_NEW_UNWIND */ - -#ifdef CONFIG_IA64_NEW_UNWIND - static void init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base, unsigned long gp, void *table_start, void *table_end) @@ -1979,7 +1861,7 @@ dprintk("unwind: ignoring attempt to insert empty unwind table\n"); return 0; } - + table = kmalloc(sizeof(*table), GFP_USER); if (!table) return 0; @@ -2052,12 +1934,10 @@ kfree(table); } -#endif /* CONFIG_IA64_NEW_UNWIND */ void unw_init (void) { -#ifdef CONFIG_IA64_NEW_UNWIND extern int ia64_unw_start, ia64_unw_end, __gp; extern void unw_hash_index_t_is_too_narrow (void); long i, off; @@ -2093,5 +1973,4 @@ init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp, &ia64_unw_start, &ia64_unw_end); -#endif /* CONFIG_IA64_NEW_UNWIND */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/Makefile linux.ac/arch/ia64/lib/Makefile --- linux.vanilla/arch/ia64/lib/Makefile Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/lib/Makefile Tue Apr 10 18:08:40 2001 @@ -7,18 +7,18 @@ L_TARGET = lib.a +export-objs := io.o swiotlb.o + obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \ checksum.o clear_page.o csum_partial_copy.o copy_page.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ - flush.o do_csum.o \ + flush.o io.o do_csum.o \ swiotlb.o ifneq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) obj-y += memcpy.o memset.o strlen.o endif - -export-objs += io.o IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/clear_page.S linux.ac/arch/ia64/lib/clear_page.S --- linux.vanilla/arch/ia64/lib/clear_page.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/clear_page.S Tue Apr 10 18:09:55 2001 @@ -6,29 +6,24 @@ * * Inputs: * in0: address of page - * + * * Output: * none * - * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2001 David Mosberger-Tang */ #include #include - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(clear_page) - UNW(.prologue) + .prologue alloc r11=ar.pfs,1,0,0,0 - UNW(.save ar.lc, r16) + .save ar.lc, r16 mov r16=ar.lc // slow - UNW(.body) + .body mov r17=PAGE_SIZE/32-1 // -1 = repeat/until ;; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/clear_user.S linux.ac/arch/ia64/lib/clear_user.S --- linux.vanilla/arch/ia64/lib/clear_user.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/clear_user.S Tue Apr 10 18:09:55 2001 @@ -6,8 +6,8 @@ * in1: length of buffer in bytes * Outputs: * r8: number of bytes that didn't get cleared due to a fault - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co + * + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian */ @@ -51,27 +51,12 @@ // have side effects (same thing for writing). // -// The label comes first because our store instruction contains a comma -// and confuse the preprocessor otherwise -// -#define EX(y,x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 y-99f; \ - .previous; \ -99: x - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__do_clear_user) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) - alloc saved_pfs=ar.pfs,2,0,0,0 + .prologue + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,2,0,0,0 cmp.eq p6,p0=r0,len // check for zero length - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) .body ;; // avoid WAW on CFM @@ -80,7 +65,7 @@ (p6) br.ret.spnt.few rp ;; cmp.lt p6,p0=16,len // if len > 16 then long memset - mov ar.lc=tmp // initialize lc for small count + mov ar.lc=tmp // initialize lc for small count (p6) br.cond.dptk.few long_do_clear ;; // WAR on ar.lc // @@ -91,7 +76,7 @@ // the various counters compared to how long the loop is supposed // to last on average does not make this solution viable. // -1: +1: EX( .Lexit1, st1 [buf]=r0,1 ) adds len=-1,len // countdown length using len br.cloop.dptk.few 1b @@ -99,7 +84,7 @@ // // .Lexit4: comes from byte by byte loop // len contains bytes left -.Lexit1: +.Lexit1: mov ret0=len // faster than using ar.lc mov ar.lc=saved_lc br.ret.sptk.few rp // end of short clear_user @@ -110,7 +95,7 @@ // so we focus on alignment (no branches required) // // The use of len/len2 for countdown of the number of bytes left - // instead of ret0 is due to the fact that the exception code + // instead of ret0 is due to the fact that the exception code // changes the values of r8. // long_do_clear: @@ -131,10 +116,10 @@ EX( .Lexit3, (p6) st8 [buf]=r0,8 ) // 8-byte aligned (p6) adds len=-8,len;; shr.u cnt=len,4 // number of 128-bit (2x64bit) words - ;; + ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt -(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left ;; adds buf2=8,buf // setup second base pointer mov ar.lc=tmp @@ -143,32 +128,30 @@ // // 16bytes/iteration core loop // - // The second store can never generate a fault because + // The second store can never generate a fault because // we come into the loop only when we are 16-byte aligned. // This means that if we cross a page then it will always be // in the first store and never in the second. // - // + // // We need to keep track of the remaining length. A possible (optimistic) - // way would be to ue ar.lc and derive how many byte were left by + // way would be to use ar.lc and derive how many byte were left by // doing : left= 16*ar.lc + 16. this would avoid the addition at - // every iteration. + // every iteration. // However we need to keep the synchronization point. A template // M;;MB does not exist and thus we can keep the addition at no // extra cycle cost (use a nop slot anyway). It also simplifies the // (unlikely) error recovery code // -2: - - EX(.Lexit3, st8 [buf]=r0,16 ) +2: EX(.Lexit3, st8 [buf]=r0,16 ) ;; // needed to get len correct when error st8 [buf2]=r0,16 - adds len=-16,len + adds len=-16,len br.cloop.dptk.few 2b ;; mov ar.lc=saved_lc - // + // // tail correction based on len only // // We alternate the use of len3,len2 to allow parallelism and correct @@ -176,14 +159,14 @@ // The addition of len2/len3 does not cost anything more compared to // the regular memset as we had empty slots. // -.dotail: +.dotail: mov len2=len // for parallelization of error handling mov len3=len - tbit.nz p6,p0=len,3 + tbit.nz p6,p0=len,3 ;; EX( .Lexit2, (p6) st8 [buf]=r0,8 ) // at least 8 bytes (p6) adds len3=-8,len2 - tbit.nz p7,p6=len,2 + tbit.nz p7,p6=len,2 ;; EX( .Lexit2, (p7) st4 [buf]=r0,4 ) // at least 4 bytes (p7) adds len2=-4,len3 @@ -207,8 +190,8 @@ // // // .Lexit2: - // if p6 -> coming from st8 or st2 : len2 contains what's left - // if p7 -> coming from st4 or st1 : len3 contains what's left + // if p6 -> coming from st8 or st2 : len2 contains what's left + // if p7 -> coming from st4 or st1 : len3 contains what's left // We must restore lc/pr even though might not have been used. .Lexit2: .pred.rel "mutex", p6, p7 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/copy_page.S linux.ac/arch/ia64/lib/copy_page.S --- linux.vanilla/arch/ia64/lib/copy_page.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/copy_page.S Tue Apr 10 18:09:55 2001 @@ -3,14 +3,14 @@ * Optimized version of the standard copy_page() function * * Based on comments from ddd. Try not to overflow write buffer. - * + * * Inputs: - * in0: address of target page + * in0: address of target page * in1: address of source page * Output: - * no return value + * no return value * - * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian */ #include @@ -28,28 +28,23 @@ #define tgt1 r22 #define tgt2 r23 - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(copy_page) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) .rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH] .rotp p[PIPE_DEPTH] - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // save ar.lc ahead of time - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // rotating predicates are preserved // resgisters we must save. - UNW(.body) + .body - mov src1=in1 // initialize 1st stream source - adds src2=8,in1 // initialize 2nd stream source + mov src1=in1 // initialize 1st stream source + adds src2=8,in1 // initialize 2nd stream source mov lcount=PAGE_SIZE/16-1 // as many 16bytes as there are on a page // -1 is because br.ctop is repeat/until @@ -72,7 +67,7 @@ // // The initialization of the prolog is done via the predicate registers: // the choice of EPI DEPENDS on the depth of the pipeline (n). - // When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62 + // When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62 // are then shifted right at every iteration, // Thus by initializing pr16=1 and the rest to 0 before the loop // we get EPI=1 after n iterations. @@ -87,7 +82,7 @@ // stores but no loads anymore ;; mov pr=saved_pr,0xffffffffffff0000 // restore predicates - mov ar.pfs=saved_pfs // restore ar.ec + mov ar.pfs=saved_pfs // restore ar.ec mov ar.lc=saved_lc // restore saved lc br.ret.sptk.few rp // bye... END(copy_page) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/copy_user.S linux.ac/arch/ia64/lib/copy_user.S --- linux.vanilla/arch/ia64/lib/copy_user.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/lib/copy_user.S Tue Apr 10 18:09:55 2001 @@ -12,41 +12,25 @@ * * Inputs: * in0 address of source buffer - * in1 address of destination buffer + * in1 address of destination buffer * in2 number of bytes to copy * - * Outputs: - * ret0 0 in case of success. The number of bytes NOT copied in - * case of error. + * Outputs: + * ret0 0 in case of success. The number of bytes NOT copied in + * case of error. * * Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000 Stephane Eranian * * Fixme: * - handle the case where we have more than 16 bytes and the alignment - * are different. + * are different. * - more benchmarking - * - fix extraneous stop bit introduced by the EX() macro. + * - fix extraneous stop bit introduced by the EX() macro. */ #include -// The label comes first because our store instruction contains a comma -// and confuse the preprocessor otherwise -// -#undef DEBUG -#ifdef DEBUG -#define EX(y,x...) \ -99: x -#else -#define EX(y,x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 y-99f; \ - .previous; \ -99: x -#endif - // // Tuneable parameters // @@ -85,13 +69,10 @@ #define enddst r29 #define endsrc r30 #define saved_pfs r31 - .text - .psr abi64 - .psr lsb GLOBAL_ENTRY(__copy_user) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) .rotr val1[PIPE_DEPTH],val2[PIPE_DEPTH] @@ -102,16 +83,16 @@ ;; // RAW of cfm when len=0 cmp.eq p8,p0=r0,len // check for zero length - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) (p8) br.ret.spnt.few rp // empty mempcy() ;; add enddst=dst,len // first byte after end of source add endsrc=src,len // first byte after end of destination - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates - UNW(.body) + .body mov dst1=dst // copy because of rotation mov ar.ec=PIPE_DEPTH @@ -119,7 +100,7 @@ mov src1=src // copy because of rotation mov ar.lc=len2 // initialize lc for small count - cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy + cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy xor tmp=src,dst // same alignment test prepare (p10) br.cond.dptk.few long_copy_user @@ -128,9 +109,8 @@ // Now we do the byte by byte loop with software pipeline // // p7 is necessarily false by now -1: +1: EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 1b ;; @@ -148,10 +128,10 @@ and src2=0x7,src1 // src offset and dst2=0x7,dst1 // dst offset ;; - // The basic idea is that we copy byte-by-byte at the head so - // that we can reach 8-byte alignment for both src1 and dst1. - // Then copy the body using software pipelined 8-byte copy, - // shifting the two back-to-back words right and left, then copy + // The basic idea is that we copy byte-by-byte at the head so + // that we can reach 8-byte alignment for both src1 and dst1. + // Then copy the body using software pipelined 8-byte copy, + // shifting the two back-to-back words right and left, then copy // the tail by copying byte-by-byte. // // Fault handling. If the byte-by-byte at the head fails on the @@ -162,18 +142,18 @@ // handled simply by failure_in_pipe1. // // The case p14 represents the source has more bytes in the - // the first word (by the shifted part), whereas the p15 needs to - // copy some bytes from the 2nd word of the source that has the + // the first word (by the shifted part), whereas the p15 needs to + // copy some bytes from the 2nd word of the source that has the // tail of the 1st of the destination. // // - // Optimization. If dst1 is 8-byte aligned (not rarely), we don't need - // to copy the head to dst1, to start 8-byte copy software pipleline. + // Optimization. If dst1 is 8-byte aligned (not rarely), we don't need + // to copy the head to dst1, to start 8-byte copy software pipleline. // We know src1 is not 8-byte aligned in this case. // cmp.eq p14,p15=r0,dst2 -(p15) br.cond.spnt.few 1f +(p15) br.cond.spnt.few 1f ;; sub t1=8,src2 mov t2=src2 @@ -182,10 +162,10 @@ sub len1=len,t1 // set len1 ;; sub lshift=64,rshift - ;; + ;; br.cond.spnt.few word_copy_user - ;; -1: + ;; +1: cmp.leu p14,p15=src2,dst2 sub t1=dst2,src2 ;; @@ -196,30 +176,29 @@ ;; // For the case p14, we don't need to copy the shifted part to // the 1st word of destination. - sub t2=8,t1 + sub t2=8,t1 (p14) sub word1=word1,t1 ;; sub len1=len,word1 // resulting len (p15) shl rshift=t1,3 // in bits (p14) shl rshift=t2,3 - ;; + ;; (p14) sub len1=len1,t1 adds cnt=-1,word1 - ;; + ;; sub lshift=64,rshift mov ar.ec=PIPE_DEPTH mov pr.rot=1<<16 // p16=true all others are false mov ar.lc=cnt - ;; -2: + ;; +2: EX(failure_in_pipe2,(p16) ld1 val1[0]=[src1],1) - ;; EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 2b ;; - clrrrb - ;; -word_copy_user: + clrrrb + ;; +word_copy_user: cmp.gtu p9,p0=16,len1 (p9) br.cond.spnt.few 4f // if (16 > len1) skip 8-byte copy ;; @@ -227,7 +206,7 @@ ;; adds cnt=-1,cnt ;; - .pred.rel "mutex", p14, p15 + .pred.rel "mutex", p14, p15 (p14) sub src1=src1,t2 (p15) sub src1=src1,t1 // @@ -237,23 +216,23 @@ mov ar.lc=cnt mov ar.ec=PIPE_DEPTH mov pr.rot=1<<16 // p16=true all others are false - ;; + ;; 3: // - // The pipleline consists of 3 stages: + // The pipleline consists of 3 stages: // 1 (p16): Load a word from src1 // 2 (EPI_1): Shift right pair, saving to tmp // 3 (EPI): Store tmp to dst1 // - // To make it simple, use at least 2 (p16) loops to set up val1[n] + // To make it simple, use at least 2 (p16) loops to set up val1[n] // because we need 2 back-to-back val1[] to get tmp. // Note that this implies EPI_2 must be p18 or greater. - // + // #define EPI_1 p[PIPE_DEPTH-2] #define SWITCH(pred, shift) cmp.eq pred,p0=shift,rshift #define CASE(pred, shift) \ - (pred) br.cond.spnt.few copy_user_bit##shift + (pred) br.cond.spnt.few copy_user_bit##shift #define BODY(rshift) \ copy_user_bit##rshift: \ 1: \ @@ -267,11 +246,11 @@ // // Since the instruction 'shrp' requires a fixed 128-bit value // specifying the bits to shift, we need to provide 7 cases - // below. + // below. // SWITCH(p6, 8) SWITCH(p7, 16) - SWITCH(p8, 24) + SWITCH(p8, 24) SWITCH(p9, 32) SWITCH(p10, 40) SWITCH(p11, 48) @@ -289,40 +268,40 @@ BODY(16) BODY(24) BODY(32) - BODY(40) + BODY(40) BODY(48) BODY(56) - ;; -.diff_align_do_tail: - .pred.rel "mutex", p14, p15 + ;; +.diff_align_do_tail: + .pred.rel "mutex", p14, p15 (p14) sub src1=src1,t1 -(p14) adds dst1=-8,dst1 +(p14) adds dst1=-8,dst1 (p15) sub dst1=dst1,t1 - ;; -4: + ;; +4: // Tail correction. // // The problem with this piplelined loop is that the last word is not - // loaded and thus parf of the last word written is not correct. + // loaded and thus parf of the last word written is not correct. // To fix that, we simply copy the tail byte by byte. - + sub len1=endsrc,src1,1 clrrrb - ;; + ;; mov ar.ec=PIPE_DEPTH mov pr.rot=1<<16 // p16=true all others are false mov ar.lc=len1 ;; -5: +5: EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 5b ;; + mov ar.lc=saved_lc mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs br.ret.dptk.few rp - + // // Beginning of long mempcy (i.e. > 16 bytes) // @@ -353,6 +332,7 @@ // we have never executed the ld1, therefore st1 is not executed. // EX(failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned + ;; EX(failure_out,(p6) st1 [dst1]=val1[0],1) tbit.nz p9,p0=src1,3 ;; @@ -369,12 +349,12 @@ shr.u cnt=len1,4 // number of 128-bit (2x64bit) words ;; EX(failure_out, (p9) st8 [dst1]=val2[1],8) - tbit.nz p6,p0=len1,3 + tbit.nz p6,p0=len1,3 cmp.eq p7,p0=r0,cnt adds tmp=-1,cnt // br.ctop is repeat/until (p7) br.cond.dpnt.few .dotail // we have less than 16 bytes left ;; - adds src2=8,src1 + adds src2=8,src1 adds dst2=8,dst1 mov ar.lc=tmp ;; @@ -395,12 +375,12 @@ // No matter where we come from (loop or test) the src1 pointer // is 16 byte aligned AND we have less than 16 bytes to copy. // -.dotail: +.dotail: EX(failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes tbit.nz p7,p0=len1,2 ;; EX(failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes - tbit.nz p8,p0=len1,1 + tbit.nz p8,p0=len1,1 ;; EX(failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes tbit.nz p9,p0=len1,0 @@ -430,7 +410,7 @@ // // In the same loop iteration, the dst1 pointer does not directly // reflect where the faulty load was. - // + // // - pipeline effect // When you get a fault on load, you may have valid data from // previous loads not yet store in transit. Such data must be @@ -442,7 +422,7 @@ // - we don't disrupt the pipeline, i.e. data in transit in // the software pipeline will be eventually move to memory. // We simply replace the load with a simple mov and keep the - // pipeline going. We can't really do this inline because + // pipeline going. We can't really do this inline because // p16 is always reset to 1 when lc > 0. // failure_in_pipe1: @@ -459,7 +439,7 @@ // // This is the case where the byte by byte copy fails on the load - // when we copy the head. We need to finish the pipeline and copy + // when we copy the head. We need to finish the pipeline and copy // zeros for the rest of the destination. Since this happens // at the top we still need to fill the body and tail. failure_in_pipe2: @@ -471,7 +451,7 @@ ;; sub len=enddst,dst1,1 // precompute len br.cond.dptk.few failure_in1bis - ;; + ;; // // Here we handle the head & tail part when we check for alignment. @@ -482,7 +462,7 @@ // // However some simplifications are possible given the way // things work. - // + // // 1) HEAD // Theory of operation: // @@ -506,23 +486,23 @@ // // Key point: // - if you fail on 1, 2, 4 then you have never executed any smaller - // size loads, e.g. failing ld4 means no ld1 nor ld2 executed + // size loads, e.g. failing ld4 means no ld1 nor ld2 executed // before. // // This allows us to simplify the cleanup code, because basically you // only have to worry about "pending" stores in the case of a failing - // ld8(). Given the way the code is written today, this means only + // ld8(). Given the way the code is written today, this means only // worry about st2, st4. There we can use the information encapsulated // into the predicates. - // + // // Other key point: - // - if you fail on the ld8 in the head, it means you went straight + // - if you fail on the ld8 in the head, it means you went straight // to it, i.e. 8byte alignment within an unexisting page. // Again this comes from the fact that if you crossed just for the ld8 then // you are 8byte aligned but also 16byte align, therefore you would // either go for the 16byte copy loop OR the ld8 in the tail part. // The combination ld1, ld2, ld4, ld8 where you fail on ld8 is impossible - // because it would mean you had 15bytes to copy in which case you + // because it would mean you had 15bytes to copy in which case you // would have defaulted to the byte by byte copy. // // @@ -533,18 +513,18 @@ // Key point: // This means that we either: // - are right on a page boundary - // OR - // - are at more than 16 bytes from a page boundary with + // OR + // - are at more than 16 bytes from a page boundary with // at most 15 bytes to copy: no chance of crossing. // // This allows us to assume that if we fail on a load we haven't possibly - // executed any of the previous (tail) ones, so we don't need to do - // any stores. For instance, if we fail on ld2, this means we had + // executed any of the previous (tail) ones, so we don't need to do + // any stores. For instance, if we fail on ld2, this means we had // 2 or 3 bytes left to copy and we did not execute the ld8 nor ld4. // - // This means that we are in a situation similar the a fault in the - // head part. That's nice! - // + // This means that we are in a situation similar the a fault in the + // head part. That's nice! + // failure_in1: // sub ret0=enddst,dst1 // number of bytes to zero, i.e. not copied // sub len=enddst,dst1,1 @@ -563,7 +543,7 @@ ;; 5: st1 [dst1]=r0,1 - br.cloop.dptk.few 5b + br.cloop.dptk.few 5b ;; skip_loop: mov pr=saved_pr,0xffffffffffff0000 @@ -574,7 +554,7 @@ // // Here we simply restart the loop but instead // of doing loads we fill the pipeline with zeroes - // We can't simply store r0 because we may have valid + // We can't simply store r0 because we may have valid // data in transit in the pipeline. // ar.lc and ar.ec are setup correctly at this point // @@ -593,7 +573,7 @@ ;; cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk.few failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc @@ -610,13 +590,13 @@ ;; cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk.few failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs br.ret.dptk.few rp - + // // handling of failures on stores: that's the easy part // diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/csum_partial_copy.c linux.ac/arch/ia64/lib/csum_partial_copy.c --- linux.vanilla/arch/ia64/lib/csum_partial_copy.c Mon Feb 7 02:42:40 2000 +++ linux.ac/arch/ia64/lib/csum_partial_copy.c Tue Apr 10 18:09:55 2001 @@ -1,6 +1,6 @@ /* * Network Checksum & Copy routine - * + * * Copyright (C) 1999 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian * @@ -107,22 +107,18 @@ do_csum_partial_copy_from_user (const char *src, char *dst, int len, unsigned int psum, int *errp) { - const unsigned char *psrc = src; unsigned long result; - int cplen = len; - int r = 0; /* XXX Fixme - * for now we separate the copy from checksum for obvious + * for now we separate the copy from checksum for obvious * alignment difficulties. Look at the Alpha code and you'll be * scared. */ - while ( cplen-- ) r |=__get_user(*dst++,psrc++); - - if ( r && errp ) *errp = r; + if (__copy_from_user(dst, src, len) != 0 && errp) + *errp = -EFAULT; - result = do_csum(src, len); + result = do_csum(dst, len); /* add in old sum, and carry.. */ result += psum; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/do_csum.S linux.ac/arch/ia64/lib/do_csum.S --- linux.vanilla/arch/ia64/lib/do_csum.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/do_csum.S Tue Apr 10 18:09:55 2001 @@ -7,8 +7,8 @@ * Inputs: * in0: address of buffer to checksum (char *) * in1: length of the buffer (int) - * - * Copyright (C) 1999 Hewlett-Packard Co + * + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian * */ @@ -39,7 +39,7 @@ // This version avoids synchronization in the core loop by also using a // pipeline for the accumulation of the checksum in result[]. // -// p[] +// p[] // |---| // 0| | r32 : new value loaded in pipeline // |---| @@ -50,7 +50,7 @@ // 3| | r35 : previous value added to checksum (previous iteration) // |---| // -// result[] +// result[] // |---| // 0| | r36 : new checksum // |---| @@ -68,7 +68,7 @@ // - Maybe another algorithm which would take care of the folding at the // end in a different manner // - Work with people more knowledgeable than me on the network stack -// to figure out if we could not split the function depending on the +// to figure out if we could not split the function depending on the // type of packet or alignment we get. Like the ip_fast_csum() routine // where we know we have at least 20bytes worth of data to checksum. // - Look at RFCs about checksums to see whether or not we can do better @@ -94,17 +94,11 @@ #define buf in0 #define len in1 - - .text - .psr abi64 - .psr lsb - .lsb - // unsigned long do_csum(unsigned char *buf,int len) GLOBAL_ENTRY(do_csum) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,2,8,0,8 .rotr p[4], result[3] @@ -126,7 +120,7 @@ ;; and lastoff=7,tmp1 // how many bytes off for last element andcm last=tmp2,tmp3 // address of word containing last byte - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates (rotation) ;; sub tmp3=last,first // tmp3=distance from first to last @@ -144,14 +138,14 @@ ;; shl tmp1=tmp1,3 // number of bits - shl hmask=hmask,tmp2 // build head mask, mask off [0,firstoff[ + shl hmask=hmask,tmp2 // build head mask, mask off [0,firstoff[ ;; shr.u tmask=tmask,tmp1 // build tail mask, mask off ]8,lastoff] - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // save lc ;; - UNW(.body) + .body (p8) and hmask=hmask,tmask // apply tail mask to head mask if 1 word only (p9) and p[1]=lastval,tmask // mask last it as appropriate @@ -163,7 +157,7 @@ ;; // XXX Fixme: not very nice initialization here // - // Setup loop control registers: + // Setup loop control registers: // // tmp3=0 (1 word) : lc=0, ec=2, p16=F // tmp3=1 (2 words) : lc=0, ec=3, p16=F @@ -227,7 +221,7 @@ add ret0=tmp1,tmp2 mov pr=saved_pr,0xffffffffffff0000 ;; - // if buf was odd then swap bytes + // if buf was odd then swap bytes mov ar.pfs=saved_pfs // restore ar.ec (p10) mux1 ret0=ret0,@rev // reverse word ;; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/flush.S linux.ac/arch/ia64/lib/flush.S --- linux.vanilla/arch/ia64/lib/flush.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/lib/flush.S Tue Apr 10 18:09:55 2001 @@ -1,30 +1,25 @@ /* * Cache flushing routines. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang */ #include #include - .text - .psr abi64 - .psr lsb - .lsb - /* * flush_icache_range(start,end) * Must flush range from start to end-1 but nothing else (need to * be careful not to touch addresses that may be unmapped). */ GLOBAL_ENTRY(flush_icache_range) - UNW(.prologue) + .prologue alloc r2=ar.pfs,2,0,0,0 sub r8=in1,in0,1 ;; shr.u r8=r8,5 // we flush 32 bytes per iteration - UNW(.save ar.lc, r3) - mov r3=ar.lc // save ar.lc + .save ar.lc, r3 + mov r3=ar.lc // save ar.lc ;; .body @@ -38,7 +33,7 @@ sync.i ;; srlz.i - ;; + ;; mov ar.lc=r3 // restore ar.lc br.ret.sptk.many rp END(flush_icache_range) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/idiv64.S linux.ac/arch/ia64/lib/idiv64.S --- linux.vanilla/arch/ia64/lib/idiv64.S Tue Oct 10 01:54:56 2000 +++ linux.ac/arch/ia64/lib/idiv64.S Tue Apr 10 18:09:55 2001 @@ -37,28 +37,29 @@ #define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3)) GLOBAL_ENTRY(NAME) - UNW(.prologue) + .prologue .regstk 2,0,0,0 // Transfer inputs to FP registers. setf.sig f8 = in0 setf.sig f9 = in1 - UNW(.fframe 16) - UNW(.save.f 0x20) + ;; + .fframe 16 + .save.f 0x20 stf.spill [sp] = f17,-16 // Convert the inputs to FP, to avoid FP software-assist faults. INT_TO_FP(f8, f8) ;; - UNW(.save.f 0x10) + .save.f 0x10 stf.spill [sp] = f16 - UNW(.body) + .body INT_TO_FP(f9, f9) ;; frcpa.s1 f17, p6 = f8, f9 // y0 = frcpa(b) ;; (p6) fmpy.s1 f7 = f8, f17 // q0 = a*y0 -(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 1 +(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 1 ;; (p6) fma.s1 f16 = f7, f6, f7 // q1 = q0*e0 + q0 (p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0 @@ -70,7 +71,7 @@ (p6) fma.s1 f6 = f17, f6, f17 // y1 = y0*e0 + y0 ;; (p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 -(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a +(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a ;; #ifdef MODULO setf.sig f8 = in0 // f8 = a @@ -78,7 +79,7 @@ #endif (p6) fma.s1 f17 = f7, f6, f16 // q3 = r*y2 + q2 ;; - UNW(.restore sp) + .restore sp ldf.fill f16 = [sp], 16 FP_TO_INT(f17, f17) // q = trunc(q3) ;; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/memcpy.S linux.ac/arch/ia64/lib/memcpy.S --- linux.vanilla/arch/ia64/lib/memcpy.S Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/lib/memcpy.S Tue Apr 10 18:09:55 2001 @@ -68,19 +68,19 @@ * the more general copy routine handling arbitrary * sizes/alignment etc. */ - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc or t0=in0,in1 ;; or t0=t0,in2 - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr - UNW(.body) + .body cmp.eq p6,p0=in2,r0 // zero length? mov retval=in0 // return dst diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/memset.S linux.ac/arch/ia64/lib/memset.S --- linux.vanilla/arch/ia64/lib/memset.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/memset.S Tue Apr 10 18:09:55 2001 @@ -3,14 +3,13 @@ * Optimized version of the standard memset() function * * Return: none - * * * Inputs: * in0: address of buffer * in1: byte value to use for storing * in2: length of the buffer * - * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian */ @@ -31,20 +30,16 @@ #define saved_lc r20 #define tmp r21 - .text - .psr abi64 - .psr lsb - GLOBAL_ENTRY(memset) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) - alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here + .prologue + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here cmp.eq p8,p0=r0,len // check for zero length - UNW(.save ar.lc, saved_lc) + .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) - ;; + ;; - UNW(.body) + .body adds tmp=-1,len // br.ctop is repeat/until tbit.nz p6,p0=buf,0 // odd alignment @@ -82,7 +77,7 @@ (p6) st8 [buf]=val,8 // 8-byte aligned (p6) adds len=-8,len;; shr.u cnt=len,4 // number of 128-bit (2x64bit) words - ;; + ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt (p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left @@ -96,10 +91,10 @@ br.cloop.dptk.few 2b ;; .dotail: // tail correction based on len only - tbit.nz p6,p0=len,3 + tbit.nz p6,p0=len,3 ;; (p6) st8 [buf]=val,8 // at least 8 bytes - tbit.nz p6,p0=len,2 + tbit.nz p6,p0=len,2 ;; (p6) st4 [buf]=val,4 // at least 4 bytes tbit.nz p6,p0=len,1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strlen.S linux.ac/arch/ia64/lib/strlen.S --- linux.vanilla/arch/ia64/lib/strlen.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/lib/strlen.S Tue Apr 10 18:09:55 2001 @@ -5,12 +5,12 @@ * * Inputs: * in0 address of string - * - * Outputs: - * ret0 the number of characters in the string (0 if empty string) - * does not count the \0 * - * Copyright (C) 1999 Hewlett-Packard Co + * Outputs: + * ret0 the number of characters in the string (0 if empty string) + * does not count the \0 + * + * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian * * 09/24/99 S.Eranian add speculation recovery code @@ -30,7 +30,7 @@ // string may not be 8-byte aligned. In this case we load the 8byte // quantity which includes the start of the string and mask the unused // bytes with 0xff to avoid confusing czx. -// We use speculative loads and software pipelining to hide memory +// We use speculative loads and software pipelining to hide memory // latency and do read ahead safely. This way we defer any exception. // // Because we don't want the kernel to be relying on particular @@ -42,7 +42,7 @@ // The fact that speculation may fail can be caused, for instance, by // the DCR.dm bit being set. In this case TLB misses are deferred, i.e., // a NaT bit will be set if the translation is not present. The normal -// load, on the other hand, will cause the translation to be inserted +// load, on the other hand, will cause the translation to be inserted // if the mapping exists. // // It should be noted that we execute recovery code only when we need @@ -50,22 +50,22 @@ // recovery code on pure read ahead data. // // Remarks: -// - the cmp r0,r0 is used as a fast way to initialize a predicate +// - the cmp r0,r0 is used as a fast way to initialize a predicate // register to 1. This is required to make sure that we get the parallel // compare correct. // // - we don't use the epilogue counter to exit the loop but we need to set // it to zero beforehand. // -// - after the loop we must test for Nat values because neither the +// - after the loop we must test for Nat values because neither the // czx nor cmp instruction raise a NaT consumption fault. We must be -// careful not to look too far for a Nat for which we don't care. +// careful not to look too far for a Nat for which we don't care. // For instance we don't need to look at a NaT in val2 if the zero byte // was in val1. // // - Clearly performance tuning is required. // -// +// // #define saved_pfs r11 #define tmp r10 @@ -78,15 +78,9 @@ #define val1 r22 #define val2 r23 - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(strlen) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,11,0,0,8 // rotating must be multiple of 8 .rotr v[2], w[2] // declares our 4 aliases @@ -94,11 +88,11 @@ extr.u tmp=in0,0,3 // tmp=least significant 3 bits mov orig=in0 // keep trackof initial byte address dep src=0,in0,0,3 // src=8byte-aligned in0 address - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates (rotation) ;; - UNW(.body) + .body ld8 v[1]=[src],8 // must not speculate: can fail here shl tmp=tmp,3 // multiply by 8bits/byte @@ -115,8 +109,8 @@ or v[1]=v[1],mask // now we have a safe initial byte pattern ;; 1: - ld8.s v[0]=[src],8 // speculatively load next - czx1.r val1=v[1] // search 0 byte from right + ld8.s v[0]=[src],8 // speculatively load next + czx1.r val1=v[1] // search 0 byte from right czx1.r val2=w[1] // search 0 byte from right following 8bytes ;; ld8.s w[0]=[src],8 // speculatively load next to next @@ -132,11 +126,7 @@ // - there must be a better way of doing the test // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) -#ifdef notyet tnat.nz p6,p7=val1 // test NaT on val1 -#else - tnat.z p7,p6=val1 // test NaT on val1 -#endif (p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT ;; // @@ -154,7 +144,7 @@ sub tmp=8,val1 // which byte in word mov pr=saved_pr,0xffffffffffff0000 ;; - sub ret0=ret0,tmp // adjust + sub ret0=ret0,tmp // adjust mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what br.ret.sptk.few rp // end of normal execution @@ -167,8 +157,8 @@ // // IMPORTANT: // Please note that in the case of strlen() as opposed to strlen_user() - // we don't use the exception mechanism, as this function is not - // supposed to fail. If that happens it means we have a bug and the + // we don't use the exception mechanism, as this function is not + // supposed to fail. If that happens it means we have a bug and the // code will cause of kernel fault. // // XXX Fixme @@ -187,7 +177,7 @@ 2: (p6) ld8 val=[base],8 // will fail if unrecoverable fault ;; - czx1.r val1=val // search 0 byte from right + czx1.r val1=val // search 0 byte from right ;; cmp.eq p6,p0=8,val1 // val1==8 ? (p6) br.wtop.dptk.few 2b // loop until p6 == 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strlen_user.S linux.ac/arch/ia64/lib/strlen_user.S --- linux.vanilla/arch/ia64/lib/strlen_user.S Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/lib/strlen_user.S Tue Apr 10 18:09:55 2001 @@ -6,9 +6,9 @@ * * Outputs: * ret0 0 in case of fault, strlen(buffer)+1 otherwise - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang * Copyright (C) 1998, 1999 Stephane Eranian * * 01/19/99 S.Eranian heavily enhanced version (see details below) @@ -24,8 +24,8 @@ // - length of string + 1 // - 0 in case an exception is raised // -// This is an enhanced version of the basic strlen_user. it includes a -// combination of compute zero index (czx), parallel comparisons, speculative +// This is an enhanced version of the basic strlen_user. it includes a +// combination of compute zero index (czx), parallel comparisons, speculative // loads and loop unroll using rotating registers. // // General Ideas about the algorithm: @@ -34,7 +34,7 @@ // string may not be 8-byte aligned. In this case we load the 8byte // quantity which includes the start of the string and mask the unused // bytes with 0xff to avoid confusing czx. -// We use speculative loads and software pipelining to hide memory +// We use speculative loads and software pipelining to hide memory // latency and do read ahead safely. This way we defer any exception. // // Because we don't want the kernel to be relying on particular @@ -45,7 +45,7 @@ // The fact that speculation may fail can be caused, for instance, by // the DCR.dm bit being set. In this case TLB misses are deferred, i.e., // a NaT bit will be set if the translation is not present. The normal -// load, on the other hand, will cause the translation to be inserted +// load, on the other hand, will cause the translation to be inserted // if the mapping exists. // // It should be noted that we execute recovery code only when we need @@ -53,30 +53,21 @@ // recovery code on pure read ahead data. // // Remarks: -// - the cmp r0,r0 is used as a fast way to initialize a predicate +// - the cmp r0,r0 is used as a fast way to initialize a predicate // register to 1. This is required to make sure that we get the parallel // compare correct. // // - we don't use the epilogue counter to exit the loop but we need to set // it to zero beforehand. // -// - after the loop we must test for Nat values because neither the +// - after the loop we must test for Nat values because neither the // czx nor cmp instruction raise a NaT consumption fault. We must be -// careful not to look too far for a Nat for which we don't care. +// careful not to look too far for a Nat for which we don't care. // For instance we don't need to look at a NaT in val2 if the zero byte // was in val1. // // - Clearly performance tuning is required. // -// -// - -#define EX(y,x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 y-99f; \ - .previous; \ -99: x #define saved_pfs r11 #define tmp r10 @@ -89,15 +80,9 @@ #define val1 r22 #define val2 r23 - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__strlen_user) - UNW(.prologue) - UNW(.save ar.pfs, saved_pfs) + .prologue + .save ar.pfs, saved_pfs alloc saved_pfs=ar.pfs,11,0,0,8 .rotr v[2], w[2] // declares our 4 aliases @@ -105,7 +90,7 @@ extr.u tmp=in0,0,3 // tmp=least significant 3 bits mov orig=in0 // keep trackof initial byte address dep src=0,in0,0,3 // src=8byte-aligned in0 address - UNW(.save pr, saved_pr) + .save pr, saved_pr mov saved_pr=pr // preserve predicates (rotation) ;; @@ -127,8 +112,8 @@ or v[1]=v[1],mask // now we have a safe initial byte pattern ;; 1: - ld8.s v[0]=[src],8 // speculatively load next - czx1.r val1=v[1] // search 0 byte from right + ld8.s v[0]=[src],8 // speculatively load next + czx1.r val1=v[1] // search 0 byte from right czx1.r val2=w[1] // search 0 byte from right following 8bytes ;; ld8.s w[0]=[src],8 // speculatively load next to next @@ -144,11 +129,7 @@ // - there must be a better way of doing the test // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) -#ifdef notyet tnat.nz p6,p7=val1 // test NaT on val1 -#else - tnat.z p7,p6=val1 // test NaT on val1 -#endif (p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT ;; // @@ -193,7 +174,7 @@ 2: EX(.Lexit1, (p6) ld8 val=[base],8) ;; - czx1.r val1=val // search 0 byte from right + czx1.r val1=val // search 0 byte from right ;; cmp.eq p6,p0=8,val1 // val1==8 ? (p6) br.wtop.dptk.few 2b // loop until p6 == 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strncpy_from_user.S linux.ac/arch/ia64/lib/strncpy_from_user.S --- linux.vanilla/arch/ia64/lib/strncpy_from_user.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/strncpy_from_user.S Tue Apr 10 18:09:55 2001 @@ -8,9 +8,9 @@ * in2: length of buffer in bytes * Outputs: * r8: -EFAULT in case of fault or number of bytes copied if no fault - * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang * * 00/03/06 D. Mosberger Fixed to return proper return value (bug found by * by Andreas Schwab ). @@ -18,18 +18,6 @@ #include -#define EX(x...) \ -99: x; \ - .section __ex_table,"a"; \ - data4 @gprel(99b); \ - data4 .Lexit-99b; \ - .previous - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__strncpy_from_user) alloc r2=ar.pfs,3,0,0,0 mov r8=0 @@ -41,15 +29,16 @@ // XXX braindead copy loop---this needs to be optimized .Loop1: - EX(ld1 r8=[in1],1;; st1 [in0]=r8,1; cmp.ne p6,p7=r8,r0) + EX(.Lexit, ld1 r8=[in1],1) + ;; + EX(.Lexit, st1 [in0]=r8,1) + cmp.ne p6,p7=r8,r0 ;; (p6) cmp.ne.unc p8,p0=in1,r10 (p8) br.cond.dpnt.few .Loop1 ;; (p6) mov r8=in2 // buffer filled up---return buffer length (p7) sub r8=in1,r9,1 // return string length (excluding NUL character) - br.ret.sptk.few rp - -.Lexit: +[.Lexit:] br.ret.sptk.few rp END(__strncpy_from_user) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/strnlen_user.S linux.ac/arch/ia64/lib/strnlen_user.S --- linux.vanilla/arch/ia64/lib/strnlen_user.S Thu Jun 22 15:09:44 2000 +++ linux.ac/arch/ia64/lib/strnlen_user.S Tue Apr 10 18:09:55 2001 @@ -8,41 +8,28 @@ * in1: string length limit N * Outputs: * r8: 0 in case of fault, strlen(buffer)+1 otherwise - * - * Copyright (C) 1999 David Mosberger-Tang + * + * Copyright (C) 1999, 2001 David Mosberger-Tang */ #include -/* If a fault occurs, r8 gets set to -EFAULT and r9 gets cleared. */ -#define EX(x...) \ - .section __ex_table,"a"; \ - data4 @gprel(99f); \ - data4 (.Lexit-99f)|1; \ - .previous \ -99: x; - - .text - .psr abi64 - .psr lsb - .lsb - GLOBAL_ENTRY(__strnlen_user) - UNW(.prologue) + .prologue alloc r2=ar.pfs,2,0,0,0 - UNW(.save ar.lc, r16) + .save ar.lc, r16 mov r16=ar.lc // preserve ar.lc - UNW(.body) + .body add r3=-1,in1 ;; mov ar.lc=r3 mov r9=0 - + ;; // XXX braindead strlen loop---this needs to be optimized .Loop1: - EX(ld1 r8=[in0],1) + EXCLR(.Lexit, ld1 r8=[in0],1) add r9=1,r9 ;; cmp.eq p6,p0=r8,r0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/lib/swiotlb.c linux.ac/arch/ia64/lib/swiotlb.c --- linux.vanilla/arch/ia64/lib/swiotlb.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/lib/swiotlb.c Tue Apr 10 18:09:55 2001 @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -50,14 +51,14 @@ static unsigned int io_tlb_index; /* - * We need to save away the original address corresponding to a mapped entry for the sync + * We need to save away the original address corresponding to a mapped entry for the sync * operations. */ static unsigned char **io_tlb_orig_addr; /* * Protect the above data structures in the map and unmap calls - */ + */ static spinlock_t io_tlb_lock = SPIN_LOCK_UNLOCKED; static int __init @@ -132,7 +133,7 @@ { wrap = index = ALIGN(io_tlb_index, stride); - if (index >= io_tlb_nslabs) + if (index >= io_tlb_nslabs) wrap = index = 0; do { @@ -164,12 +165,12 @@ } while (index != wrap); /* - * XXX What is a suitable recovery mechanism here? We cannot + * XXX What is a suitable recovery mechanism here? We cannot * sleep because we are called from with in interrupts! */ panic("map_single: could not allocate software IO TLB (%ld bytes)", size); -found: } + found: spin_unlock_irqrestore(&io_tlb_lock, flags); /* @@ -199,9 +200,9 @@ */ if ((direction == PCI_DMA_FROMDEVICE) || (direction == PCI_DMA_BIDIRECTIONAL)) /* - * bounce... copy the data back into the original buffer * and delete the - * bounce buffer. - */ + * bounce... copy the data back into the original buffer * and delete the + * bounce buffer. + */ memcpy(buffer, dma_addr, size); /* @@ -236,9 +237,9 @@ char *buffer = io_tlb_orig_addr[index]; /* - * bounce... copy the data back into/from the original buffer + * bounce... copy the data back into/from the original buffer * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ? - */ + */ if (direction == PCI_DMA_FROMDEVICE) memcpy(buffer, dma_addr, size); else if (direction == PCI_DMA_TODEVICE) @@ -298,8 +299,8 @@ */ return pci_addr; - /* - * get a bounce buffer: + /* + * get a bounce buffer: */ pci_addr = virt_to_phys(map_single(hwdev, ptr, size, direction)); @@ -325,12 +326,8 @@ pg_addr = PAGE_ALIGN((unsigned long) addr); end = (unsigned long) addr + size; while (pg_addr + PAGE_SIZE <= end) { -#if 0 - set_bit(PG_arch_1, virt_to_page(pg_addr)); -#else - if (!VALID_PAGE(virt_to_page(pg_addr))) - printk("Invalid addr %lx!!!\n", pg_addr); -#endif + struct page *page = virt_to_page(pg_addr); + set_bit(PG_arch_1, &page->flags); pg_addr += PAGE_SIZE; } } @@ -454,3 +451,14 @@ { return virt_to_phys(sg->address); } + +EXPORT_SYMBOL(swiotlb_init); +EXPORT_SYMBOL(swiotlb_map_single); +EXPORT_SYMBOL(swiotlb_unmap_single); +EXPORT_SYMBOL(swiotlb_map_sg); +EXPORT_SYMBOL(swiotlb_unmap_sg); +EXPORT_SYMBOL(swiotlb_sync_single); +EXPORT_SYMBOL(swiotlb_sync_sg); +EXPORT_SYMBOL(swiotlb_dma_address); +EXPORT_SYMBOL(swiotlb_alloc_consistent); +EXPORT_SYMBOL(swiotlb_free_consistent); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/extable.c linux.ac/arch/ia64/mm/extable.c --- linux.vanilla/arch/ia64/mm/extable.c Mon Feb 7 02:42:40 2000 +++ linux.ac/arch/ia64/mm/extable.c Tue Apr 10 18:09:55 2001 @@ -1,8 +1,8 @@ /* * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang */ #include @@ -43,14 +43,22 @@ return 0; } -register unsigned long gp __asm__("gp"); +#ifndef CONFIG_MODULE +register unsigned long main_gp __asm__("gp"); +#endif -const struct exception_table_entry * +struct exception_fixup search_exception_table (unsigned long addr) { + const struct exception_table_entry *entry; + struct exception_fixup fix = { 0 }; + #ifndef CONFIG_MODULE /* There is only the kernel to search. */ - return search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp); + entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - main_gp); + if (entry) + fix.cont = entry->cont + main_gp; + return fix; #else struct exception_table_entry *ret; /* The kernel is the last "module" -- no need to treat it special. */ @@ -59,10 +67,22 @@ for (mp = module_list; mp ; mp = mp->next) { if (!mp->ex_table_start) continue; - ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); - if (ret) - return ret; + entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); + if (entry) { + fix.cont = entry->cont + mp->gp; + return fix; + } } - return 0; #endif + return fix; +} + +void +handle_exception (struct pt_regs *regs, struct exception_fixup fix) +{ + regs->r8 = -EFAULT; + if (fix.cont & 4) + regs->r9 = 0; + regs->cr_iip = (long) fix.cont & ~0xf; + ia64_psr(regs)->ri = fix.cont & 0x3; /* set continuation slot number */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/fault.c linux.ac/arch/ia64/mm/fault.c --- linux.vanilla/arch/ia64/mm/fault.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/mm/fault.c Tue Apr 10 18:09:55 2001 @@ -47,7 +47,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { struct mm_struct *mm = current->mm; - const struct exception_table_entry *fix; + struct exception_fixup fix; struct vm_area_struct *vma, *prev_vma; struct siginfo si; int signal = SIGSEGV; @@ -163,14 +163,13 @@ return; } +#ifdef GAS_HAS_LOCAL_TAGS + fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); +#else fix = search_exception_table(regs->cr_iip); - if (fix) { - regs->r8 = -EFAULT; - if (fix->skip & 1) { - regs->r9 = 0; - } - regs->cr_iip += ((long) fix->skip) & ~15; - regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */ +#endif + if (fix.cont) { + handle_exception(regs, fix); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/init.c linux.ac/arch/ia64/mm/init.c --- linux.vanilla/arch/ia64/mm/init.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/mm/init.c Tue Apr 10 18:11:49 2001 @@ -1,8 +1,8 @@ /* * Initialize MMU support. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang */ #include #include @@ -23,116 +23,36 @@ #include #include #include +#include +#include + +mmu_gather_t mmu_gathers[NR_CPUS]; /* References to section boundaries: */ extern char _stext, _etext, _edata, __init_begin, __init_end; -/* - * These are allocated in head.S so that we get proper page alignment. - * If you change the size of these then change head.S as well. - */ -extern char empty_bad_page[PAGE_SIZE]; -extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; -extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; - extern void ia64_tlb_init (void); +unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; + static unsigned long totalram_pages; -/* - * Fill in empty_bad_pmd_table with entries pointing to - * empty_bad_pte_table and return the address of this PMD table. - */ -static pmd_t * -get_bad_pmd_table (void) -{ - pmd_t v; - int i; - - pmd_set(&v, empty_bad_pte_table); - - for (i = 0; i < PTRS_PER_PMD; ++i) - empty_bad_pmd_table[i] = v; - - return empty_bad_pmd_table; -} - -/* - * Fill in empty_bad_pte_table with PTEs pointing to empty_bad_page - * and return the address of this PTE table. - */ -static pte_t * -get_bad_pte_table (void) -{ - pte_t v; - int i; - - set_pte(&v, pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED))); - - for (i = 0; i < PTRS_PER_PTE; ++i) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -void -__handle_bad_pgd (pgd_t *pgd) -{ - pgd_ERROR(*pgd); - pgd_set(pgd, get_bad_pmd_table()); -} - -void -__handle_bad_pmd (pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set(pmd, get_bad_pte_table()); -} - -/* - * Allocate and initialize an L3 directory page and set - * the L2 directory entry PMD to the newly allocated page. - */ -pte_t* -get_pte_slow (pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - /* everything A-OK */ - clear_page(pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long) pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(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_page((unsigned long)get_pgd_fast()), ++freed; - if (pmd_quicklist) - free_page((unsigned long)get_pmd_fast()), ++freed; - if (pte_quicklist) - free_page((unsigned long)get_pte_fast()), ++freed; - } while (pgtable_cache_size > low); - } - return freed; + if (pgtable_cache_size > high) { + do { + if (pgd_quicklist) + free_page((unsigned long)pgd_alloc_one_fast()), ++freed; + if (pmd_quicklist) + free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed; + if (pte_quicklist) + free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed; + } while (pgtable_cache_size > low); + } + return freed; } /* @@ -188,12 +108,12 @@ { /* * EFI uses 4KB pages while the kernel can use 4KB or bigger. - * Thus EFI and the kernel may have different page sizes. It is - * therefore possible to have the initrd share the same page as - * the end of the kernel (given current setup). + * Thus EFI and the kernel may have different page sizes. It is + * therefore possible to have the initrd share the same page as + * the end of the kernel (given current setup). * * To avoid freeing/using the wrong page (kernel sized) we: - * - align up the beginning of initrd + * - align up the beginning of initrd * - keep the end untouched * * | | @@ -201,8 +121,8 @@ * | | * | | * | | 9000 - * |/////////////| - * |/////////////| + * |/////////////| + * |/////////////| * |=============| 8000 * |///INITRD////| * |/////////////| @@ -211,9 +131,9 @@ * |KKKKKKKKKKKKK| * |=============| 6000 * |KKKKKKKKKKKKK| - * |KKKKKKKKKKKKK| + * |KKKKKKKKKKKKK| * K=kernel using 8KB pages - * + * * In this example, we must free page 8000 ONLY. So we must align up * initrd_start and keep initrd_end as is. */ @@ -286,52 +206,59 @@ page_address(page)); pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ - pmd = pmd_alloc(pgd, address); - if (!pmd) { - __free_page(page); - panic("Out of memory."); - return 0; - } - pte = pte_alloc(pmd, address); - if (!pte) { - __free_page(page); - panic("Out of memory."); - return 0; - } - if (!pte_none(*pte)) { - pte_ERROR(*pte); - __free_page(page); - return 0; + + spin_lock(&init_mm.page_table_lock); + { + pmd = pmd_alloc(&init_mm, pgd, address); + if (!pmd) + goto out; + pte = pte_alloc(&init_mm, pmd, address); + if (!pte) + goto out; + if (!pte_none(*pte)) { + pte_ERROR(*pte); + goto out; + } + flush_page_to_ram(page); + set_pte(pte, mk_pte(page, PAGE_GATE)); } - flush_page_to_ram(page); - set_pte(pte, mk_pte(page, PAGE_GATE)); + out: spin_unlock(&init_mm.page_table_lock); /* no need for flush_tlb */ return page; } void __init -ia64_rid_init (void) +ia64_mmu_init (void) { unsigned long flags, rid, pta, impl_va_bits; + extern void __init tlb_init (void); #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 #else # define VHPT_ENABLE_BIT 1 #endif - /* Set up the kernel identity mappings (regions 6 & 7) and the vmalloc area (region 5): */ + /* + * Set up the kernel identity mapping for regions 6 and 5. The mapping for region + * 7 is setup up in _start(). + */ ia64_clear_ic(flags); rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); - - rid = ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET); - ia64_set_rr(PAGE_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); + ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_64M << 2)); rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); + /* ensure rr6 is up-to-date before inserting the PERCPU_ADDR translation: */ + ia64_srlz_d(); + + ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, + pte_val(mk_pte_phys(__pa(&cpu_data[smp_processor_id()]), PAGE_KERNEL)), + PAGE_SHIFT); + __restore_flags(flags); + ia64_srlz_i(); /* * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped @@ -356,7 +283,7 @@ # define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) # define POW2(n) (1ULL << (n)) - impl_va_bits = ffz(~my_cpu_data.unimpl_va_mask); + impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); if (impl_va_bits < 51 || impl_va_bits > 61) panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1); @@ -374,6 +301,8 @@ * enabled. */ ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); + + ia64_tlb_init(); } /* @@ -390,7 +319,7 @@ memset(zones_size, 0, sizeof(zones_size)); - max_dma = (PAGE_ALIGN(MAX_DMA_ADDRESS) >> PAGE_SHIFT); + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; if (max_low_pfn < max_dma) zones_size[ZONE_DMA] = max_low_pfn; else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/mm/tlb.c linux.ac/arch/ia64/mm/tlb.c --- linux.vanilla/arch/ia64/mm/tlb.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/mm/tlb.c Tue Apr 10 18:09:55 2001 @@ -1,11 +1,11 @@ /* * TLB support routines. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang * - * 08/02/00 A. Mallick - * Modified RID allocation for SMP + * 08/02/00 A. Mallick + * Modified RID allocation for SMP * Goutham Rao * IPI based ptc implementation and A-step IPI implementation. */ @@ -41,7 +41,7 @@ }; /* - * Seralize usage of ptc.g + * Seralize usage of ptc.g */ spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see */ @@ -49,7 +49,7 @@ #include -unsigned long flush_end, flush_start, flush_nbits, flush_rid; +unsigned long flush_end, flush_start, flush_nbits, flush_rid; atomic_t flush_cpu_count; /* @@ -71,7 +71,7 @@ if (!(flags & IA64_PSR_I)) { saved_tpr = ia64_get_tpr(); ia64_srlz_d(); - ia64_set_tpr(IPI_IRQ - 16); + ia64_set_tpr(IA64_IPI_VECTOR - 16); ia64_srlz_d(); local_irq_enable(); } @@ -97,13 +97,14 @@ /* * Wait for other CPUs to finish purging entries. */ -#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) { + extern void smp_resend_flush_tlb (void); unsigned long start = ia64_get_itc(); + while (atomic_read(&flush_cpu_count) > 0) { - if ((ia64_get_itc() - start) > 40000UL) { - atomic_set(&flush_cpu_count, smp_num_cpus - 1); - smp_send_flush_tlb(); + if ((ia64_get_itc() - start) > 400000UL) { + smp_resend_flush_tlb(); start = ia64_get_itc(); } } @@ -148,7 +149,7 @@ if (tsk_context == ia64_ctx.next) { if (++ia64_ctx.next >= ia64_ctx.limit) { /* empty range: reset the range limit and start over */ - if (ia64_ctx.next > max_ctx) + if (ia64_ctx.next > max_ctx) ia64_ctx.next = 300; ia64_ctx.limit = max_ctx + 1; goto repeat; @@ -166,11 +167,11 @@ { unsigned long i, j, flags, count0, count1, stride0, stride1, addr; - addr = my_cpu_data.ptce_base; - count0 = my_cpu_data.ptce_count[0]; - count1 = my_cpu_data.ptce_count[1]; - stride0 = my_cpu_data.ptce_stride[0]; - stride1 = my_cpu_data.ptce_stride[1]; + addr = local_cpu_data->ptce_base; + count0 = local_cpu_data->ptce_count[0]; + count1 = local_cpu_data->ptce_count[1]; + stride0 = local_cpu_data->ptce_stride[0]; + stride1 = local_cpu_data->ptce_stride[1]; local_irq_save(flags); for (i = 0; i < count0; ++i) { @@ -249,11 +250,11 @@ ia64_ptce_info_t ptce_info; ia64_get_ptce(&ptce_info); - my_cpu_data.ptce_base = ptce_info.base; - my_cpu_data.ptce_count[0] = ptce_info.count[0]; - my_cpu_data.ptce_count[1] = ptce_info.count[1]; - my_cpu_data.ptce_stride[0] = ptce_info.stride[0]; - my_cpu_data.ptce_stride[1] = ptce_info.stride[1]; + local_cpu_data->ptce_base = ptce_info.base; + local_cpu_data->ptce_count[0] = ptce_info.count[0]; + local_cpu_data->ptce_count[1] = ptce_info.count[1]; + local_cpu_data->ptce_stride[0] = ptce_info.stride[0]; + local_cpu_data->ptce_stride[1] = ptce_info.stride[1]; __flush_tlb_all(); /* nuke left overs from bootstrapping... */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/Makefile linux.ac/arch/ia64/sn/Makefile --- linux.vanilla/arch/ia64/sn/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/Makefile Tue Apr 10 18:09:55 2001 @@ -8,12 +8,11 @@ EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO + -DNEW_INTERRUPTS all: sn.a O_TARGET = sn.a -O_HEADERS = -O_OBJS = sn1/sn1.a +obj-y = sn1/sn1.a clean:: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/fprom/Makefile linux.ac/arch/ia64/sn/fprom/Makefile --- linux.vanilla/arch/ia64/sn/fprom/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/fprom/Makefile Tue Apr 10 18:09:55 2001 @@ -13,6 +13,7 @@ LIB = ../../lib/lib.a OBJ=fpromasm.o main.o fw-emu.o fpmem.o +obj-y=fprom fprom: $(OBJ) $(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/fprom/fw-emu.c linux.ac/arch/ia64/sn/fprom/fw-emu.c --- linux.vanilla/arch/ia64/sn/fprom/fw-emu.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/fprom/fw-emu.c Sat Apr 14 01:18:00 2001 @@ -8,6 +8,7 @@ * Copyright (C) 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) */ + #include #include #include @@ -62,6 +63,7 @@ func_ptr_t ap_entry; +static efi_runtime_services_t *efi_runtime_p; static char fw_mem[( sizeof(efi_system_table_t) + sizeof(efi_runtime_services_t) + NUM_EFI_DESCS*sizeof(efi_config_table_t) @@ -88,8 +90,8 @@ .text .proc pal_emulator_static pal_emulator_static: - mov r8=-1 - cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ + mov r8=-1;; + cmp.eq p6,p7=6,r28;; /* PAL_PTCE_INFO */ (p7) br.cond.sptk.few 1f ;; mov r8=0 /* status = 0 */ @@ -98,20 +100,20 @@ movl r11=0x1000000000002000 /* stride[0], stride[1] */ br.cond.sptk.few rp -1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ -(p7) br.cond.sptk.few 1f +1: cmp.eq p6,p7=14,r28;; /* PAL_FREQ_RATIOS */ +(p7) br.cond.sptk.few 1f;; mov r8=0 /* status = 0 */ movl r9 =0x100000064 /* proc_ratio (1/100) */ movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ movl r11=0x10000000a /* itc_ratio<<32 (1/100) */ -1: cmp.eq p6,p7=22,r28 /* PAL_MC_DRAIN */ -(p7) br.cond.sptk.few 1f +1: cmp.eq p6,p7=22,r28;; /* PAL_MC_DRAIN */ +(p7) br.cond.sptk.few 1f;; mov r8=0 br.cond.sptk.few rp -1: cmp.eq p6,p7=23,r28 /* PAL_MC_EXPECTED */ -(p7) br.cond.sptk.few 1f +1: cmp.eq p6,p7=23,r28;; /* PAL_MC_EXPECTED */ +(p7) br.cond.sptk.few 1f;; mov r8=0 br.cond.sptk.few rp @@ -256,6 +258,36 @@ _fp->gp = __fwtab_pa(base_nasid, _fp->gp); } +void +fix_virt_function_pointer(void *fptr) +{ + func_ptr_t *fp; + + fp = fptr; + fp->pc = fp->pc | PAGE_OFFSET; + fp->gp = fp->gp | PAGE_OFFSET; +} + + +int +efi_set_virtual_address_map(void) +{ + efi_runtime_services_t *runtime; + + runtime = efi_runtime_p; + fix_virt_function_pointer((void*)runtime->get_time); + fix_virt_function_pointer((void*)runtime->set_time); + fix_virt_function_pointer((void*)runtime->get_wakeup_time); + fix_virt_function_pointer((void*)runtime->set_wakeup_time); + fix_virt_function_pointer((void*)runtime->set_virtual_address_map); + fix_virt_function_pointer((void*)runtime->get_variable); + fix_virt_function_pointer((void*)runtime->get_next_variable); + fix_virt_function_pointer((void*)runtime->set_variable); + fix_virt_function_pointer((void*)runtime->get_next_high_mono_count); + fix_virt_function_pointer((void*)runtime->reset_system); + return EFI_SUCCESS;; +} + void sys_fw_init (const char *args, int arglen, int bsp) @@ -305,7 +337,7 @@ cp = fw_mem; efi_systab = (void *) cp; cp += sizeof(*efi_systab); - efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); + efi_runtime_p = efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); efi_tables = (void *) cp; cp += NUM_EFI_DESCS*sizeof(*efi_tables); sal_systab = (void *) cp; cp += sizeof(*sal_systab); sal_ed = (void *) cp; cp += sizeof(*sal_ed); @@ -354,7 +386,7 @@ efi_runtime->set_time = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->get_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->set_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_success); + efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_set_virtual_address_map); efi_runtime->get_variable = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->get_next_variable = __fwtab_pa(base_nasid, &efi_unimplemented); efi_runtime->set_variable = __fwtab_pa(base_nasid, &efi_unimplemented); @@ -370,10 +402,11 @@ fix_function_pointer(&efi_get_time); fix_function_pointer(&efi_success); fix_function_pointer(&efi_reset_system); + fix_function_pointer(&efi_set_virtual_address_map); /* fill in the ACPI system table: */ memcpy(acpi_systab->signature, "RSD PTR ", 8); - acpi_systab->rsdt = (acpi_rsdt_t*)__fwtab_pa(base_nasid, acpi_rsdt); + acpi_systab->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt); memcpy(acpi_rsdt->header.signature, "RSDT",4); acpi_rsdt->header.length = sizeof(acpi_rsdt_t); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/Makefile linux.ac/arch/ia64/sn/io/Makefile --- linux.vanilla/arch/ia64/sn/io/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/Makefile Tue Apr 10 18:09:55 2001 @@ -18,15 +18,15 @@ EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO + -DNEW_INTERRUPTS O_TARGET := sgiio.o -O_OBJS := stubs.o sgi_if.o pciio.o pcibr.o xtalk.o xbow.o xswitch.o hubspc.o \ - klgraph_hack.o io.o hubdev.o \ +obj-y := stubs.o sgi_if.o pciio.o pcibr.o xtalk.o xbow.o xswitch.o hubspc.o \ + klgraph_hack.o io.o hubdev.o huberror.o \ hcl.o labelcl.o invent.o klgraph.o klconflib.o sgi_io_sim.o \ module.o sgi_io_init.o klgraph_hack.o ml_SN_init.o \ - ml_SN_intr.o ip37.o \ + ml_SN_intr.o ip37.o pciba.o \ ml_iograph.o hcl_util.o cdl.o \ mem_refcnt.o devsupport.o alenlist.o pci_bus_cvlink.o \ - eeprom.o pci.o pci_dma.o l1.o l1_command.o + eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/alenlist.c linux.ac/arch/ia64/sn/io/alenlist.c --- linux.vanilla/arch/ia64/sn/io/alenlist.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/alenlist.c Tue Apr 10 18:09:55 2001 @@ -201,8 +201,8 @@ int alenlist_count=0; /* Currently allocated Lists */ int alenlist_chunk_count = 0; /* Currently allocated chunks */ int alenlist_cursor_count = 0; /* Currently allocate cursors */ -#define INCR_COUNT(ptr) atomicAddInt((ptr), 1); -#define DECR_COUNT(ptr) atomicAddInt((ptr), -1); +#define INCR_COUNT(ptr) atomic_inc((ptr)); +#define DECR_COUNT(ptr) atomic_dec((ptr)); #else #define INCR_COUNT(ptr) #define DECR_COUNT(ptr) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/cdl.c linux.ac/arch/ia64/sn/io/cdl.c --- linux.vanilla/arch/ia64/sn/io/cdl.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/cdl.c Tue Apr 10 18:09:55 2001 @@ -67,7 +67,7 @@ void cdl_del(cdl_p reg) { - printk("SGI IO INFRASTRUCTURE - cdl_del not supported.\n"); + return; } /* @@ -77,7 +77,7 @@ Do nothing. */ int -cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags) +cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags, cdl_drv_f *func) { return 0; } @@ -86,11 +86,9 @@ * cdl_del_driver: Not supported. */ void -cdl_del_driver(cdl_p reg, - char *prefix) +cdl_del_driver(cdl_p reg, char *prefix, cdl_drv_f *func) { - - printk("SGI IO INFRASTRUCTURE - cdl_del_driver not supported.\n"); + return; } /* @@ -106,7 +104,7 @@ */ int cdl_add_connpt(cdl_p reg, int part_num, int mfg_num, - devfs_handle_t connpt) + devfs_handle_t connpt, int drv_flags) { int i; @@ -123,27 +121,12 @@ if (sgi_infrastructure_drivers[i].attach) { return(sgi_infrastructure_drivers[i].attach(connpt)); } -#ifdef BRINGUP - /* - * XXX HACK ALERT bypassing fops for now.. - */ - else { - printk("cdl_add_connpt: NEED FOPS FOR OUR DRIVERS!!\n"); - printk("cdl_add_connpt: part_num= 0x%x mfg_num= 0x%x\n", - part_num, mfg_num); - return(-1); - } -#endif /* BRINGUP */ } else { continue; } - - printk("**** cdl_add_connpt: driver not found for part_num %d mfg_num %d ****\n", part_num, mfg_num); - - return(-1); } - if ( (i == MAX_SGI_IO_INFRA_DRVR) ) - printk("**** cdl_add_connpt: Driver not found for part_num 0x%x mfg_num 0x%x ****\n", part_num, mfg_num); + + /* printk("WARNING: cdl_add_connpt: Driver not found for part_num 0x%x mfg_num 0x%x\n", part_num, mfg_num); */ return (0); } @@ -151,11 +134,11 @@ /* * cdl_del_connpt: Not implemented. */ -void -cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt) +int +cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt, int drv_flags) { - printk("SGI IO INFRASTRUCTURE - cdl_del_cdl_del_connpt not supported.\n"); + return(0); } /* @@ -166,65 +149,54 @@ char *prefix, cdl_iter_f * func) { - - printk("SGI IO INFRASTRUCTURE - cdl_iterate not supported.\n"); + return; } async_attach_t async_attach_new(void) { - printk("SGI IO INFRASTRUCTURE - async_attach_new not supported.\n"); return(0); } void async_attach_free(async_attach_t aa) { - printk("SGI IO INFRASTRUCTURE - async_attach_free not supported.\n"); + return; } async_attach_t async_attach_get_info(devfs_handle_t vhdl) { - printk("SGI IO INFRASTRUCTURE - async_attach_get_info not supported.\n"); return(0); } void async_attach_add_info(devfs_handle_t vhdl, async_attach_t aa) { - printk("SGI IO INFRASTRUCTURE - async_attach_add_info not supported.\n"); + return; } void async_attach_del_info(devfs_handle_t vhdl) { - - printk("SGI IO INFRASTRUCTURE - async_attach_del_info not supported.\n"); - + return; } void async_attach_signal_start(async_attach_t aa) { - - printk("SGI IO INFRASTRUCTURE - async_attach_signal_start not supported.\n"); - + return; } void async_attach_signal_done(async_attach_t aa) { - - printk("SGI IO INFRASTRUCTURE - async_attach_signal_done not supported.\n"); - + return; } void async_attach_waitall(async_attach_t aa) { - - printk("SGI IO INFRASTRUCTURE - async_attach_waitall not supported.\n"); - + return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/devsupport.c linux.ac/arch/ia64/sn/io/devsupport.c --- linux.vanilla/arch/ia64/sn/io/devsupport.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/devsupport.c Tue Apr 10 18:09:55 2001 @@ -1,5 +1,3 @@ -#define ilvt_t int - /* $Id$ * * This file is subject to the terms and conditions of the GNU General Public @@ -28,7 +26,7 @@ /* =====Generic iobus support===== */ /* String table to hold names of interrupts. */ -#ifdef notyet +#ifdef LATER static struct string_table device_desc_string_table; #endif @@ -36,7 +34,7 @@ static void device_desc_init(void) { -#ifdef notyet +#ifdef LATER string_table_init(&device_desc_string_table); #endif FIXME("device_desc_init"); @@ -47,7 +45,7 @@ static device_desc_t device_desc_alloc(void) { -#ifdef notyet +#ifdef LATER device_desc_t device_desc; device_desc = (device_desc_t)kmem_zalloc(sizeof(struct device_desc_s), 0); @@ -69,7 +67,7 @@ void device_desc_free(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER if (!(device_desc->flags & D_IS_ASSOC)) /* sanity */ kfree(device_desc); #endif @@ -79,7 +77,7 @@ device_desc_t device_desc_dup(devfs_handle_t dev) { -#ifdef notyet +#ifdef LATER device_desc_t orig_device_desc, new_device_desc; @@ -111,7 +109,7 @@ device_desc_t device_desc_default_get(devfs_handle_t dev) { -#ifdef notyet +#ifdef LATER graph_error_t rc; device_desc_t device_desc; @@ -130,7 +128,7 @@ void device_desc_default_set(devfs_handle_t dev, device_desc_t new_device_desc) { -#ifdef notyet +#ifdef LATER graph_error_t rc; device_desc_t old_device_desc = NULL; @@ -164,7 +162,7 @@ devfs_handle_t device_desc_intr_target_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_target); #else FIXME("device_desc_intr_target_get"); @@ -175,7 +173,7 @@ int device_desc_intr_policy_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_policy); #else FIXME("device_desc_intr_policy_get"); @@ -186,7 +184,7 @@ ilvl_t device_desc_intr_swlevel_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_swlevel); #else FIXME("device_desc_intr_swlevel_get"); @@ -197,7 +195,7 @@ char * device_desc_intr_name_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->intr_name); #else FIXME("device_desc_intr_name_get"); @@ -208,7 +206,7 @@ int device_desc_flags_get(device_desc_t device_desc) { -#ifdef notyet +#ifdef LATER return(device_desc->flags); #else FIXME("device_desc_flags_get"); @@ -240,7 +238,7 @@ void device_desc_intr_name_set(device_desc_t device_desc, char *name) { -#ifdef notyet +#ifdef LATER if ( device_desc != (device_desc_t)0 ) device_desc->intr_name = string_table_insert(&device_desc_string_table, name); #else @@ -325,7 +323,7 @@ static void dev_admin_registry_init(dev_admin_registry_t *registry) { -#ifdef notyet +#ifdef LATER if ( registry != (dev_admin_registry_t *)0 ) DEV_ADMIN_REGISTRY_INITLOCK(®istry->reg_lock, "dev_admin_registry_lock"); @@ -349,7 +347,7 @@ char *name, char *val) { -#ifdef notyet +#ifdef LATER dev_admin_list_t *reg_entry; dev_admin_list_t *scan = 0; @@ -404,7 +402,7 @@ static char * dev_admin_registry_find(dev_admin_registry_t *registry,char *name) { -#ifdef notyet +#ifdef LATER dev_admin_list_t *scan = 0; DEV_ADMIN_REGISTRY_RDLOCK(®istry->reg_lock); @@ -433,7 +431,7 @@ device_admin_info_get(devfs_handle_t dev_vhdl, char *info_lbl) { -#ifdef notyet +#ifdef LATER char *info = 0; /* return value need not be GRAPH_SUCCESS as the labelled @@ -460,7 +458,7 @@ char *dev_info_lbl, char *dev_info_val) { -#ifdef notyet +#ifdef LATER graph_error_t rv; arbitrary_info_t old_info; @@ -570,7 +568,7 @@ device_driver_admin_info_get(char *driver_prefix, char *driver_info_lbl) { -#ifdef notyet +#ifdef LATER device_driver_t driver; driver = device_driver_get(driver_prefix); @@ -592,7 +590,7 @@ char *driver_info_lbl, char *driver_info_val) { -#ifdef notyet +#ifdef LATER device_driver_t driver; driver = device_driver_get(driver_prefix); @@ -623,7 +621,7 @@ void device_admin_table_init(void) { -#ifdef notyet +#ifdef LATER extended_dev_admin_table_size = 0; mrinit(&extended_dev_admin_table_lock, "extended_dev_admin_table_lock"); @@ -638,7 +636,7 @@ void device_admin_table_update(char *name,char *label,char *value) { -#ifdef notyet +#ifdef LATER dev_admin_info_t *p; mrupdate(&extended_dev_admin_table_lock); @@ -678,7 +676,7 @@ void device_driver_admin_table_init(void) { -#ifdef notyet +#ifdef LATER extended_drv_admin_table_size = 0; mrinit(&extended_drv_admin_table_lock, "extended_drv_admin_table_lock"); @@ -693,7 +691,7 @@ void device_driver_admin_table_update(char *name,char *label,char *value) { -#ifdef notyet +#ifdef LATER dev_admin_info_t *p; mrupdate(&extended_dev_admin_table_lock); @@ -730,7 +728,7 @@ void device_admin_info_update(devfs_handle_t dev_vhdl) { -#ifdef notyet +#ifdef LATER int i = 0; dev_admin_info_t *scan; devfs_handle_t scan_vhdl; @@ -779,7 +777,7 @@ void device_driver_admin_info_update(device_driver_t driver) { -#ifdef notyet +#ifdef LATER int i = 0; dev_admin_info_t *scan; @@ -823,7 +821,7 @@ */ #define DEVICE_DRIVER_HASH_SIZE 32 -#ifdef notyet +#ifdef LATER lock_t device_driver_lock[DEVICE_DRIVER_HASH_SIZE]; device_driver_t device_driver_hash[DEVICE_DRIVER_HASH_SIZE]; static struct string_table driver_prefix_string_table; @@ -835,7 +833,7 @@ void device_driver_init(void) { -#ifdef notyet +#ifdef LATER int i; extern void alenlist_init(void); extern void hwgraph_init(void); @@ -849,7 +847,7 @@ string_table_init(&driver_prefix_string_table); for (i=0; i #include #include -#include /* #include */ #include #include @@ -949,6 +948,7 @@ #else char msg[BRL1_QSIZE]; /* message buffer */ int len; /* number of bytes used in message buffer */ + int resp; /* l1 response code */ int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */ int offset = 0; /* current offset into spd record */ char *spd_p = spd->bytes; /* "thumb" for writing to spd */ @@ -981,11 +981,26 @@ } /* check response */ - if( sc_interpret_resp( msg, 5, + if( (resp = sc_interpret_resp( msg, 5, L1_ARG_INT, &spd_len, - L1_ARG_UNKNOWN, &len, spd_p ) < 0 ) + L1_ARG_UNKNOWN, &len, spd_p )) < 0 ) { - return( EEP_L1 ); + /* + * translate l1 response code to eeprom.c error codes: + * The L1 response will be L1_RESP_NAVAIL if the spd + * can't be read (i.e. the spd isn't physically there). It will + * return L1_RESP_INVAL if the spd exists, but fails the checksum + * test because the eeprom wasn't programmed, programmed incorrectly, + * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present, + * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is + * invalid. + */ + if(resp == L1_RESP_INVAL) { + resp = EEP_BAD_CHECKSUM; + } else { + resp = EEP_L1; + } + return( resp ); } if( spd_len > EEPROM_CHUNKSIZE ) @@ -1201,7 +1216,9 @@ #else int r; uint64_t uid = 0; +#ifdef LOG_GETENV char uid_str[32]; +#endif int l1_compt, subch; if ( IS_RUNNING_ON_SIMULATOR() ) @@ -1228,6 +1245,13 @@ if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) return EEP_L1; + if((component & C_DIMM) == C_DIMM) { + l1_compt = L1_EEP_DIMM(component & COMPT_MASK); + r = read_spd(scp,subch,l1_compt, buf->spd); + sc_close(scp,subch); + return(r); + } + switch( component ) { case C_BRICK: @@ -1252,13 +1276,6 @@ l1_compt = L1_EEP_PIMM( component & COMPT_MASK ); break; - case C_DIMM: - /* one of the DIMMs */ - l1_compt = L1_EEP_DIMM( component & COMPT_MASK ); - r = read_spd( scp, subch, l1_compt, buf->spd ); - sc_close( scp, subch ); - return r; - default: /* unsupported board type */ sc_close( scp, subch ); @@ -1297,8 +1314,7 @@ scp = get_l1sc(); } else { - elsc_t *get_elsc(void); - scp = get_elsc(); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; } return _cbrick_eeprom_read( buf, scp, component ); @@ -1333,8 +1349,7 @@ scp = get_l1sc(); } else { - elsc_t *get_elsc(void); - scp = get_elsc(); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; } if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 ) @@ -1350,9 +1365,11 @@ if( r != EEP_OK ) { sc_close( scp, subch ); -#ifdef BRINGUP /* Once EEPROMs are universally available, remove this */ + /* + * Whenever we no longer need to test on hardware + * that does not have EEPROMS, then this can be removed. + */ r = fake_an_eeprom_record( buf, component, rtc_time() ); -#endif /* BRINGUP */ return r; } break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hcl.c linux.ac/arch/ia64/sn/io/hcl.c --- linux.vanilla/arch/ia64/sn/io/hcl.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/hcl.c Tue Apr 10 18:09:55 2001 @@ -30,6 +30,7 @@ #define HCL_TEMP_NAME_LEN 44 #define HCL_VERSION "1.0" devfs_handle_t hwgraph_root = NULL; +devfs_handle_t linux_busnum = NULL; /* * Debug flag definition. @@ -41,7 +42,9 @@ static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE; #endif static unsigned int hcl_debug = HCL_DEBUG_NONE; +#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) static unsigned int boot_options = OPTION_NONE; +#endif /* * Some Global definitions. @@ -49,6 +52,12 @@ spinlock_t hcl_spinlock; devfs_handle_t hcl_handle = NULL; +invplace_t invplace_none = { + GRAPH_VERTEX_NONE, + GRAPH_VERTEX_PLACE_NONE, + NULL +}; + /* * HCL device driver. * The purpose of this device driver is to provide a facility @@ -98,6 +107,7 @@ } struct file_operations hcl_fops = { + (struct module *)0, NULL, /* lseek - default */ NULL, /* read - general block-dev read */ NULL, /* write - general block-dev write */ @@ -110,9 +120,9 @@ hcl_close, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ - NULL /* lock */ + NULL, /* lock */ + NULL, /* readv */ + NULL, /* writev */ }; @@ -134,13 +144,15 @@ extern struct string_table label_string_table; int rv = 0; +#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) printk ("\n%s: v%s Colin Ngam (cngam@sgi.com)\n", HCL_NAME, HCL_VERSION); -#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) + hcl_debug = hcl_debug_init; printk ("%s: hcl_debug: 0x%0x\n", HCL_NAME, hcl_debug); -#endif printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME, boot_options); +#endif + spin_lock_init(&hcl_spinlock); /* @@ -148,7 +160,7 @@ */ rv = hwgraph_path_add(NULL, "hw", &hwgraph_root); if (rv) - printk ("init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); + printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); /* * Create the hcl driver to support inventory entry manipulations. @@ -171,6 +183,15 @@ */ string_table_init(&label_string_table); + /* + * Create the directory that links Linux bus numbers to our Xwidget. + */ + rv = hwgraph_path_add(hwgraph_root, "linux/busnum", &linux_busnum); + if (linux_busnum == NULL) { + panic("HCL: Unable to create hw/linux/busnum\n"); + return(0); + } + return(0); } @@ -190,7 +211,6 @@ { while ( (*str != '\0') && !isspace (*str) ) { - printk("HCL: Boot time parameter %s\n", str); #ifdef CONFIG_HCL_DEBUG if (strncmp (str, "all", 3) == 0) { hcl_debug_init |= HCL_DEBUG_ALL; @@ -445,7 +465,7 @@ /* * We need to clean up! */ - printk("HCL: Unable to set the connect point to it's parent 0x%p\n", + printk(KERN_WARNING "HCL: Unable to set the connect point to it's parent 0x%p\n", new_devfs_handle); } @@ -561,19 +581,44 @@ { char *path; + char *s1; + char *index; int name_start; devfs_handle_t handle = NULL; int rv; + int i, count; path = kmalloc(1024, GFP_KERNEL); + memset(path, 0x0, 1024); + name_start = devfs_generate_path (from, path, 1024); + s1 = &path[name_start]; + count = 0; + while (1) { + index = strstr (s1, "/"); + if (index) { + count++; + s1 = ++index; + } else { + count++; + break; + } + } + + memset(path, 0x0, 1024); name_start = devfs_generate_path (to, path, 1024); + for (i = 0; i < count; i++) { + strcat(path,"../"); + } + + strcat(path, &path[name_start]); + /* * Otherwise, just create a symlink to the vertex. * In this case the vertex was previous created with a REAL pathname. */ rv = devfs_mk_symlink (from, (const char *)name, - DEVFS_FL_DEFAULT, (const char *)&path[name_start], + DEVFS_FL_DEFAULT, path, &handle, NULL); name_start = devfs_generate_path (handle, path, 1024); @@ -744,7 +789,6 @@ *placeptr = which_place + 1; if (curr && name) { tempname = devfs_get_name(*target, &namelen); - printk("hwgraph_edge_get_next: Component name = %s, length = %d\n", tempname, namelen); if (tempname && namelen) strcpy(name, tempname); } @@ -1335,7 +1379,7 @@ return(DEVNAME_UNKNOWN); } -#ifdef IRIX +#ifdef LATER /* ** Return the compact node id of the node that ultimately "owns" the specified ** vertex. In order to do this, we walk back through masters and connect points @@ -1440,7 +1484,7 @@ return (mem_vhdl); } -#endif /* IRIX */ +#endif /* LATER */ /* @@ -1454,7 +1498,7 @@ { devfs_handle_t xx = NULL; - printk("FIXME: hwgraph_char_device_add() called. Use hwgraph_register.\n"); + printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.\n"); *devhdl = xx; // Must set devhdl return(GRAPH_SUCCESS); } @@ -1462,14 +1506,13 @@ graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr) { - printk("FIXME: hwgraph_edge_remove\n"); + printk("WARNING: hwgraph_edge_remove NOT supported.\n"); return(GRAPH_ILLEGAL_REQUEST); } graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl) { - printk("FIXME: hwgraph_vertex_unref\n"); return(GRAPH_ILLEGAL_REQUEST); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hcl_util.c linux.ac/arch/ia64/sn/io/hcl_util.c --- linux.vanilla/arch/ia64/sn/io/hcl_util.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/hcl_util.c Tue Apr 10 18:09:55 2001 @@ -137,6 +137,20 @@ } } +/* +** If the specified device represents a CPU, return its cpuid; +** otherwise, return CPU_NONE. +*/ +cpuid_t +cpuvertex_to_cpuid(devfs_handle_t vhdl) +{ + arbitrary_info_t cpuid = CPU_NONE; + + (void)labelcl_info_get_LBL(vhdl, INFO_LBL_CPUID, NULL, &cpuid); + + return((cpuid_t)cpuid); +} + /* ** dev_to_name converts a devfs_handle_t into a canonical name. If the devfs_handle_t diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hubdev.c linux.ac/arch/ia64/sn/io/hubdev.c --- linux.vanilla/arch/ia64/sn/io/hubdev.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/hubdev.c Tue Apr 10 18:09:55 2001 @@ -31,7 +31,7 @@ void hubdev_init(void) { - mutex_init(&hubdev_callout_mutex, MUTEX_DEFAULT, "hubdev"); + mutex_init(&hubdev_callout_mutex); hubdev_callout_list = NULL; } @@ -45,9 +45,9 @@ callout = (hubdev_callout_t *)kmem_zalloc(sizeof(hubdev_callout_t), KM_SLEEP); ASSERT(callout); - mutex_lock(&hubdev_callout_mutex, PZERO); + mutex_lock(&hubdev_callout_mutex); /* - * Insert at the front of the list + * Insert at the end of the list */ callout->fp = hubdev_callout_list; hubdev_callout_list = callout; @@ -62,7 +62,7 @@ ASSERT(attach_method); - mutex_lock(&hubdev_callout_mutex, PZERO); + mutex_lock(&hubdev_callout_mutex); /* * Remove registry element containing attach_method */ @@ -86,7 +86,7 @@ hubdev_callout_t *p; int errcode; - mutex_lock(&hubdev_callout_mutex, PZERO); + mutex_lock(&hubdev_callout_mutex); for (p = hubdev_callout_list; p != NULL; p = p->fp) { ASSERT(p->attach_method); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/huberror.c linux.ac/arch/ia64/sn/io/huberror.c --- linux.vanilla/arch/ia64/sn/io/huberror.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/io/huberror.c Tue Apr 10 18:09:55 2001 @@ -0,0 +1,475 @@ +/* $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. + * + * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Alan Mayer + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void hubni_eint_init(cnodeid_t cnode); +extern void hubii_eint_init(cnodeid_t cnode); +extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); +extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); + +extern int maxcpus; + +#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ + + +void +hub_error_clear(nasid_t nasid) +{ + int i; + hubreg_t idsr; + int sn; + + for(sn=0; snel_spool_cur_addr[0] = + SN0_ERROR_LOG(cnode)->el_spool_last_addr[0] = + REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A); + } + + if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) { + SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] = + SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = + REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); + } + } + + + PI_SPOOL_SIZE_BYTES = + ERR_STACK_SIZE_BYTES(REMOTE_HUB_L(nasid, PI_ERR_STACK_SIZE)); + +#ifdef BRINGUP +/* BRINGUP: The following code looks like a check to make sure +the prom set up the error spool correctly for 2 processors. I +don't think it is needed. */ + for(sn=0; snel_spool_cur_addr[1] = + SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = + REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); + + } + } + } +#endif /* BRINGUP */ + + /* programming our own hub. Enable error_int_pend intr. + * If both present, CPU A takes CPU b's error interrupts and any + * generic ones. CPU B takes CPU A error ints. + */ + if (cause_intr_connect (SRB_ERR_IDX, + (intr_func_t)(hubpi_eint_handler), + SR_ALL_MASK|SR_IE)) { + cmn_err(ERR_WARN, + "hub_error_init: cause_intr_connect failed on %d", cnode); + } + } + else { + /* programming remote hub. The only valid reason that this + * is called will be on headless hubs. No interrupts + */ + for(sn=0; snhuberror_ticks = HUB_ERROR_PERIOD; + return; +} + +/* + * Function : hubii_eint_init + * Parameters : cnode + * Purpose : to initialize the hub iio error interrupt. + * Assumptions : Called once per hub, by the cpu which will ultimately + * handle this interrupt. + * Returns : None. + */ + + +void +hubii_eint_init(cnodeid_t cnode) +{ + int bit, rv; + ii_iidsr_u_t hubio_eint; + hubinfo_t hinfo; + cpuid_t intr_cpu; + devfs_handle_t hub_v; + ii_ilcsr_u_t ilcsr; + + hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); + ASSERT_ALWAYS(hub_v); + hubinfo_get(hub_v, &hinfo); + + ASSERT(hinfo); + ASSERT(hinfo->h_cnodeid == cnode); + + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + + if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { + /* + * HUB II link is not up. + * Just disable LLP, and don't connect any interrupts. + */ + ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); + return; + } + /* Select a possible interrupt target where there is a free interrupt + * bit and also reserve the interrupt bit for this IO error interrupt + */ + intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, + "HUB IO error interrupt",&bit); + if (intr_cpu == CPU_NONE) { + printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); + return; + } + + rv = intr_connect_level(intr_cpu, bit, 0,(intr_func_t)(NULL), + (void *)(long)hub_v, NULL); + synergy_intr_connect(bit, intr_cpu); + request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, NULL, (void *)hub_v); + ASSERT_ALWAYS(rv >= 0); + hubio_eint.ii_iidsr_regval = 0; + hubio_eint.ii_iidsr_fld_s.i_enable = 1; + hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ + hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); + hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); + +} + +void +hubni_eint_init(cnodeid_t cnode) +{ + int intr_bit; + cpuid_t targ; + + + if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE) + return; + + /* The prom chooses which cpu gets these interrupts, but we + * don't know which one it chose. We will register all of the + * cpus to be sure. This only costs us an irqaction per cpu. + */ + for (; targ < CPUS_PER_NODE; targ++) { + if (!cpu_enabled(targ) ) continue; + /* connect the INTEND1 bits. */ + for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) { + intr_connect_level(targ, intr_bit, II_ERRORINT, NULL, NULL, NULL); + } + request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, NULL, NULL); + /* synergy masks are initialized in the prom to enable all interrupts. */ + /* We'll just leave them that way, here, for these interrupts. */ + } +} + + +/*ARGSUSED*/ +void +hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) +{ + devfs_handle_t hub_v; + hubinfo_t hinfo; + ii_wstat_u_t wstat; + hubreg_t idsr; + + panic("Hubii interrupt\n"); +#ifdef ajm + /* + * If the NI has a problem, everyone has a problem. We shouldn't + * even attempt to handle other errors when an NI error is present. + */ + if (check_ni_errors()) { + hubni_error_handler("II interrupt", 1); + /* NOTREACHED */ + } + + /* two levels of casting avoids compiler warning.!! */ + hub_v = (devfs_handle_t)(long)(arg); + ASSERT(hub_v); + + hubinfo_get(hub_v, &hinfo); + + /* + * Identify the reason for error. + */ + wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); + + if (wstat.ii_wstat_fld_s.w_crazy) { + char *reason; + /* + * We can do a couple of things here. + * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check + * which of these caused the CRAZY bit to be set. + * You may be able to check if the Link is up really. + */ + if (wstat.ii_wstat_fld_s.w_tx_mx_rty) + reason = "Micro Packet Retry Timeout"; + else if (wstat.ii_wstat_fld_s.w_xt_tail_to) + reason = "Crosstalk Tail Timeout"; + else if (wstat.ii_wstat_fld_s.w_xt_crd_to) + reason = "Crosstalk Credit Timeout"; + else { + hubreg_t hubii_imem; + /* + * Check if widget 0 has been marked as shutdown, or + * if BTE 0/1 has been marked. + */ + hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); + if (hubii_imem & IIO_IMEM_W0ESD) + reason = "Hub Widget 0 has been Shutdown"; + else if (hubii_imem & IIO_IMEM_B0ESD) + reason = "BTE 0 has been shutdown"; + else if (hubii_imem & IIO_IMEM_B1ESD) + reason = "BTE 1 has been shutdown"; + else reason = "Unknown"; + + } + /* + * Note: we may never be able to print this, if the II talking + * to Xbow which hosts the console is dead. + */ + printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", + hinfo->h_cnodeid, reason); + } + + /* + * It's a toss as to which one among PRB/CRB to check first. + * Current decision is based on the severity of the errors. + * IO CRB errors tend to be more severe than PRB errors. + * + * It is possible for BTE errors to have been handled already, so we + * may not see any errors handled here. + */ + (void)hubiio_crb_error_handler(hub_v, hinfo); + (void)hubiio_prb_error_handler(hub_v, hinfo); + /* + * If we reach here, it indicates crb/prb handlers successfully + * handled the error. So, re-enable II to send more interrupt + * and return. + */ + REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); +#endif /* ajm */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/hubspc.c linux.ac/arch/ia64/sn/io/hubspc.c --- linux.vanilla/arch/ia64/sn/io/hubspc.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/hubspc.c Tue Apr 10 18:09:55 2001 @@ -61,7 +61,7 @@ }cpuprom_info_t; static cpuprom_info_t *cpuprom_head; -lock_t cpuprom_spinlock; +spinlock_t cpuprom_spinlock; #define PROM_LOCK() mutex_spinlock(&cpuprom_spinlock) #define PROM_UNLOCK(s) mutex_spinunlock(&cpuprom_spinlock, (s)) @@ -72,7 +72,7 @@ prominfo_add(devfs_handle_t hub, devfs_handle_t prom) { cpuprom_info_t *info; - int s; + unsigned long s; info = kmalloc(sizeof(cpuprom_info_t), GFP_KERNEL); ASSERT(info); @@ -89,7 +89,7 @@ void prominfo_del(devfs_handle_t prom) { - int s; + unsigned long s; cpuprom_info_t *info; cpuprom_info_t **prev; @@ -111,7 +111,7 @@ devfs_handle_t prominfo_nodeget(devfs_handle_t prom) { - int s; + unsigned long s; cpuprom_info_t *info; s = PROM_LOCK(); @@ -297,7 +297,7 @@ printf("hubspc_init: Completed\n"); #endif /* HUBSPC_DEBUG */ /* Initialize spinlocks */ - spinlock_init(&cpuprom_spinlock, "promlist"); + mutex_spinlock_init(&cpuprom_spinlock); } /* ARGSUSED */ @@ -312,12 +312,6 @@ break; case HUBSPC_PROM: - /* Check if the user has proper access rights to - * read/write the prom space. - */ - if (!cap_able(CAP_DEVICE_MGT)) { - errcode = EPERM; - } break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/invent.c linux.ac/arch/ia64/sn/io/invent.c --- linux.vanilla/arch/ia64/sn/io/invent.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/invent.c Tue Apr 10 18:09:55 2001 @@ -61,6 +61,9 @@ * These two routines are intended to prevent the caller from having to know * the internal structure of the inventory table. * + * The caller of get_next_inventory is supposed to call start_scan_invent + * before the irst call to get_next_inventory, and the caller is required + * to call end_scan_invent after the last call to get_next_inventory. */ inventory_t * get_next_inventory(invplace_t *place) @@ -74,11 +77,15 @@ * We've exhausted inventory items on the last device. * Advance to next device. */ + place->invplace_inv = NULL; /* Start from beginning invent on this device */ rv = hwgraph_vertex_get_next(&device, &place->invplace_vplace); - if (rv != LABELCL_SUCCESS) + if (rv == LABELCL_SUCCESS) { + place->invplace_vhdl = device; + } + else { + place->invplace_vhdl = GRAPH_VERTEX_NONE; return(NULL); - place->invplace_vhdl = device; - place->invplace_inv = NULL; /* Start from beginning invent on this device */ + } } return(pinv); @@ -91,6 +98,23 @@ return sizeof(inventory_t); } +/* Must be called prior to first call to get_next_inventory */ +void +start_scan_inventory(invplace_t *iplace) +{ + *iplace = INVPLACE_NONE; +} + +/* Must be called after last call to get_next_inventory */ +void +end_scan_inventory(invplace_t *iplace) +{ + devfs_handle_t vhdl = iplace->invplace_vhdl; + if (vhdl != GRAPH_VERTEX_NONE) + hwgraph_vertex_unref(vhdl); + *iplace = INVPLACE_NONE; /* paranoia */ +} + /* * Hardware inventory scanner. * @@ -106,11 +130,13 @@ ie = 0; rc = 0; - while ( (ie = (inventory_t *)get_next_inventory(&iplace)) ) { + start_scan_inventory(&iplace); + while ((ie = (inventory_t *)get_next_inventory(&iplace))) { rc = (*fun)(ie, arg); if (rc) break; } + end_scan_inventory(&iplace); return rc; } @@ -127,6 +153,7 @@ { invplace_t iplace = { NULL,NULL, NULL }; + start_scan_inventory(&iplace); while ((pinv = (inventory_t *)get_next_inventory(&iplace)) != NULL) { if (class != -1 && pinv->inv_class != class) continue; @@ -146,6 +173,7 @@ continue; break; } + end_scan_inventory(&iplace); return(pinv); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/io.c linux.ac/arch/ia64/sn/io/io.c --- linux.vanilla/arch/ia64/sn/io/io.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/io.c Sat Apr 14 01:18:00 2001 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -33,11 +32,6 @@ extern xtalk_provider_t hub_provider; -#ifndef CONFIG_IA64_SGI_IO -/* Global variables */ -extern pdaindr_t pdaindr[MAXCPUS]; -#endif - /* * Perform any initializations needed to support hub-based I/O. * Called once during startup. @@ -45,7 +39,7 @@ void hubio_init(void) { -#if 0 +#ifdef LATER /* This isn't needed unless we port the entire sio driver ... */ extern void early_brl1_port_init( void ); early_brl1_port_init(); @@ -101,17 +95,14 @@ hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW; IIO_ITTE_DISABLE(nasid, bigwin); } -#ifdef BRINGUP hub_set_piomode(nasid, HUB_PIO_CONVEYOR); -#else - /* Set all the xwidgets in fire-and-forget mode - * by default - */ - hub_set_piomode(nasid, HUB_PIO_FIRE_N_FORGET); -#endif /* BRINGUP */ - sv_init(&hubinfo->h_bwwait, SV_FIFO, "bigwin"); - spinlock_init(&hubinfo->h_bwlock, "bigwin"); + mutex_spinlock_init(&hubinfo->h_bwlock); +/* + * If this lock can be acquired from interrupts or bh's, add SV_INTS or SV_BHS, + * respectively, to the flags here. + */ + sv_init(&hubinfo->h_bwwait, &hubinfo->h_bwlock, SV_ORDER_FIFO | SV_MON_SPIN); } /* @@ -143,7 +134,7 @@ int bigwin, free_bw_index; nasid_t nasid; volatile hubreg_t junk; - int s; + unsigned long s; /* sanity check */ if (byte_count_max > byte_count) @@ -222,7 +213,7 @@ goto done; } - sv_wait(&hubinfo->h_bwwait, PZERO, &hubinfo->h_bwlock, s); + sv_wait(&hubinfo->h_bwwait, 0, 0); goto tryagain; } } @@ -282,7 +273,7 @@ devfs_handle_t hubv; hubinfo_t hubinfo; nasid_t nasid; - int s; + unsigned long s; /* * Small windows are permanently mapped to corresponding widgets, @@ -463,9 +454,9 @@ if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, "%v: hub_dmamap_addr re-uses dmamap.\n",vhdl); + PRINT_WARNING("%v: hub_dmamap_addr re-uses dmamap.\n",vhdl); #else - cmn_err(CE_WARN, "0x%p: hub_dmamap_addr re-uses dmamap.\n", &vhdl); + PRINT_WARNING("0x%x: hub_dmamap_addr re-uses dmamap.\n", vhdl); #endif } } else { @@ -496,9 +487,9 @@ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN,"%v: hub_dmamap_list re-uses dmamap\n",vhdl); + PRINT_WARNING("%v: hub_dmamap_list re-uses dmamap\n",vhdl); #else - cmn_err(CE_WARN,"0x%p: hub_dmamap_list re-uses dmamap\n", &vhdl); + PRINT_WARNING("0x%x: hub_dmamap_list re-uses dmamap\n", vhdl); #endif } } else { @@ -525,9 +516,9 @@ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, "%v: hub_dmamap_done already done with dmamap\n",vhdl); + PRINT_WARNING("%v: hub_dmamap_done already done with dmamap\n",vhdl); #else - cmn_err(CE_WARN, "0x%p: hub_dmamap_done already done with dmamap\n", &vhdl); + PRINT_WARNING("0x%x: hub_dmamap_done already done with dmamap\n", vhdl); #endif } } @@ -629,16 +620,17 @@ * Allocate resources required for an interrupt as specified in dev_desc. * Returns a hub interrupt handle on success, or 0 on failure. */ -hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +static hub_intr_t +do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev, /* owner of this interrupt, if known */ + int uncond_nothread) /* unconditionally non-threaded */ { - cpuid_t cpu; /* cpu to receive interrupt */ + cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */ int cpupicked = 0; int bit; /* interrupt vector */ /*REFERENCED*/ - int intr_resflags; + int intr_resflags = 0; hub_intr_t intr_hdl; cnodeid_t nodeid; /* node to receive interrupt */ /*REFERENCED*/ @@ -665,7 +657,7 @@ intr_swlevel = device_desc_intr_swlevel_get(dev_desc); if (dev_desc->flags & D_INTR_ISERR) { intr_resflags = II_ERRORINT; - } else if (!(dev_desc->flags & D_INTR_NOTHREAD)) { + } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) { intr_resflags = II_THREADED; } else { /* Neither an error nor a thread. */ @@ -673,7 +665,8 @@ } } else { intr_swlevel = default_intr_pri; - intr_resflags = II_THREADED; + if (!uncond_nothread) + intr_resflags = II_THREADED; } /* XXX - Need to determine if the interrupt should be threaded. */ @@ -692,13 +685,11 @@ /* At this point we SHOULD have a valid cpu */ if (cpu == CPU_NONE) { #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, - "%v hub_intr_alloc could not allocate interrupt\n", + PRINT_WARNING("%v hub_intr_alloc could not allocate interrupt\n", owner_dev); #else - cmn_err(CE_WARN, - "0x%p hub_intr_alloc could not allocate interrupt\n", - &owner_dev); + PRINT_WARNING("0x%x hub_intr_alloc could not allocate interrupt\n", + owner_dev); #endif return(0); @@ -714,15 +705,13 @@ owner_dev, intr_name); if (bit < 0) { #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_WARN, - "Could not reserve an interrupt bit for cpu " + PRINT_WARNING("Could not reserve an interrupt bit for cpu " " %d and dev %v\n", cpu,owner_dev); #else - cmn_err(CE_WARN, - "Could not reserve an interrupt bit for cpu " + PRINT_WARNING("Could not reserve an interrupt bit for cpu " " %d and dev 0x%x\n", - cpu, &owner_dev); + cpu, owner_dev); #endif return(0); @@ -751,8 +740,6 @@ xtalk_info->xi_dev = dev; xtalk_info->xi_vector = bit; xtalk_info->xi_addr = xtalk_addr; - xtalk_info->xi_flags = (intr_resflags == II_THREADED) ? - 0 : XTALK_INTR_NOTHREAD; /* * Regardless of which CPU we ultimately interrupt, a given crosstalk @@ -779,6 +766,31 @@ return(intr_hdl); } +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Returns a hub interrupt handle on success, or 0 on failure. + */ +hub_intr_t +hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); +} + +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Uncondtionally request non-threaded, regardless of what the device + * descriptor might say. + * Returns a hub interrupt handle on success, or 0 on failure. + */ +hub_intr_t +hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); +} /* * Free resources consumed by intr_alloc. @@ -1001,7 +1013,7 @@ { iprb_t prb; int prb_offset; -#ifdef IRIX +#ifdef LATER extern int force_fire_and_forget; extern volatile int ignore_conveyor_override; @@ -1063,7 +1075,7 @@ int direct_connect; hubii_wcr_t ii_wcr; int prbnum; - int s, cons_lock = 0; + int cons_lock = 0; ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID); if (nasid == get_console_nasid()) { @@ -1098,15 +1110,6 @@ hub_setup_prb(nasid, prbnum, 3, conveyor); } -#ifdef IRIX - /* - * In direct connect mode, disable access to all widgets but 0. - * Later, the prom will do this for us. - */ - if (direct_connect) - ii_iowa = 1; -#endif - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); if (cons_lock) @@ -1151,7 +1154,8 @@ devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; - int s,rv; + unsigned long s; + int rv; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex @@ -1178,7 +1182,7 @@ devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; - int s; + unsigned long s; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex @@ -1201,7 +1205,7 @@ devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; - int s; + unsigned long s; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex @@ -1253,25 +1257,23 @@ ii_iowa = REMOTE_HUB_L(nasid, IIO_IOWA); #if defined(SUPPORT_PRINTING_V_FORMAT) - cmn_err(CE_CONT, "Inquiry Info for %v\n", xconn); + printk("Inquiry Info for %v\n", xconn); #else - cmn_err(CE_CONT, "Inquiry Info for 0x%p\n", &xconn); + printk("Inquiry Info for 0x%x\n", xconn); #endif - cmn_err(CE_CONT,"\tDevices shutdown [ "); + printk("\tDevices shutdown [ "); for (d = 0 ; d <= 7 ; d++) if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d)))) - cmn_err(CE_CONT, " %d", d); + printk(" %d", d); - cmn_err(CE_CONT,"]\n"); + printk("]\n"); - cmn_err(CE_CONT, - "\tInbound access ? %s\n", + printk("\tInbound access ? %s\n", ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no"); - cmn_err(CE_CONT, - "\tOutbound access ? %s\n", + printk("\tOutbound access ? %s\n", ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no"); } @@ -1300,6 +1302,7 @@ (xtalk_dmalist_drain_f *) hub_dmalist_drain, (xtalk_intr_alloc_f *) hub_intr_alloc, + (xtalk_intr_alloc_f *) hub_intr_alloc_nothd, (xtalk_intr_free_f *) hub_intr_free, (xtalk_intr_connect_f *) hub_intr_connect, (xtalk_intr_disconnect_f *) hub_intr_disconnect, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/ip37.c linux.ac/arch/ia64/sn/io/ip37.c --- linux.vanilla/arch/ia64/sn/io/ip37.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/ip37.c Tue Apr 10 18:09:55 2001 @@ -30,10 +30,6 @@ ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); - printk("hub_widget_id: Found Hub Widget ID 0x%x from Register 0x%p\n", ii_wcr.wcr_fields_s.wcr_widget_id, REMOTE_HUB_ADDR(nasid, IIO_WCR)); - - printk("hub_widget_id: Found Hub Widget 0x%lx wcr_reg_value 0x%lx\n", REMOTE_HUB_L(nasid,IIO_WCR), ii_wcr.wcr_reg_value); - return ii_wcr.wcr_fields_s.wcr_widget_id; } @@ -64,8 +60,6 @@ get_hub_chiprev(nasid_t nasid) { - printk("get_hub_chiprev: Hub Chip Rev 0x%lx\n", - (REMOTE_HUB_L(nasid, LB_REV_ID) & LRI_REV_MASK) >> LRI_REV_SHFT); return ((REMOTE_HUB_L(nasid, LB_REV_ID) & LRI_REV_MASK) >> LRI_REV_SHFT); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/klconflib.c linux.ac/arch/ia64/sn/io/klconflib.c --- linux.vanilla/arch/ia64/sn/io/klconflib.c Sat Feb 17 00:02:34 2001 +++ linux.ac/arch/ia64/sn/io/klconflib.c Tue Apr 10 18:09:55 2001 @@ -82,7 +82,7 @@ } index = j; if (index == KLCF_NUM_COMPS(brd)) { - printf("find_component: Bad pointer: 0x%p\n", kli); + DBG("find_component: Bad pointer: 0x%p\n", kli); return (klinfo_t *)NULL; } index++; /* next component */ @@ -152,11 +152,6 @@ return (lboard_t *)NULL; } -#ifndef CONFIG_IA64_SGI_IO -#define tolower(c) (isupper(c) ? (c) - 'A' + 'a' : (c)) -#define toupper(c) (islower(c) ? (c) - 'a' + 'A' : (c)) -#endif - /* * Convert a NIC name to a name for use in the hardware graph. @@ -205,10 +200,6 @@ !strncmp(new_name, "mio", 3) || !strncmp(new_name, "media_io", 8)) strcpy(new_name, "baseio"); -#if !defined(CONFIG_SGI_IP35) && !defined(CONFIG_IA64_SGI_SN1) && !defined(CONFIG_IA64_GENERIC) - else if (!strncmp(new_name, "ip29", 4)) - strcpy(new_name,SN00_MOTHERBOARD); -#endif else if (!strncmp(new_name, "divo", 4)) strcpy(new_name, "divo") ; @@ -284,11 +275,11 @@ /* * PV # 540860 - * If the name is not 'baseio' or SN00 MOTHERBOARD + * If the name is not 'baseio' * get the lowest of all the names in the nic string. * This is needed for boards like divo, which can have * a bunch of daughter cards, but would like to be called - * divo. We could do this for baseio and SN00 MOTHERBOARD + * divo. We could do this for baseio * but it has some special case names that we would not * like to disturb at this point. */ @@ -355,11 +346,7 @@ /* * look for boards that might contain an xbow or xbridge */ -#if SN0 - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8); -#else - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_PBRICK_XBOW); -#endif + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); if (brd == NULL) return 0; if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) @@ -369,7 +356,7 @@ if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) return 0; - printf("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p); + DBG("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p); return 1; } @@ -395,6 +382,9 @@ if (brd->brd_type == KLTYPE_META_ROUTER) { board_name = EDGE_LBL_META_ROUTER; hasmetarouter++; + } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { + board_name = EDGE_LBL_REPEATER_ROUTER; + hasmetarouter++; } else board_name = EDGE_LBL_ROUTER; break; @@ -420,22 +410,17 @@ modnum = brd->brd_module; -#if defined(SN0) - slot = brd->brd_slot; - get_slotname(slot, slot_name); - - ASSERT(modnum >= 0); - - sprintf(path, "%H/" EDGE_LBL_SLOT "/%s/%s", - modnum, slot_name, board_name); -#else ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); -#ifdef BRINGUP /* fix IP35 hwgraph */ - sprintf(path, EDGE_LBL_MODULE "/%x/%s", modnum, board_name); +#ifdef __ia64 + { + char buffer[16]; + memset(buffer, 0, 16); + format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); + sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name); + } #else sprintf(path, "%H/%s", modnum, board_name); #endif -#endif } /* @@ -455,172 +440,8 @@ } -#ifndef CONFIG_IA64_SGI_IO -#if 1 -/* - * find_gfxpipe(#) - * - * XXXmacko - * This is only used by graphics drivers, and should be moved - * over to gfx/kern/graphics/SN0 as soon as it's convenient. - */ -static klgfx_t *graphics_pipe_list = NULL; -static devfs_handle_t hwgraph_all_gfxids = GRAPH_VERTEX_NONE; - -void -setup_gfxpipe_link(devfs_handle_t vhdl,int pipenum) -{ - char idbuf[8]; - extern graph_hdl_t hwgraph; - - graph_info_add_LBL(hwgraph, vhdl, INFO_LBL_GFXID, INFO_DESC_EXPORT, - (arbitrary_info_t)pipenum); - if (hwgraph_all_gfxids == GRAPH_VERTEX_NONE) - hwgraph_path_add(hwgraph_root, EDGE_LBL_GFX, &hwgraph_all_gfxids); - sprintf(idbuf, "%d", pipenum); - hwgraph_edge_add(hwgraph_all_gfxids, vhdl, idbuf); - -} -#endif - -/* - * find the pipenum'th logical graphics pipe (KLCLASS_GFX) - */ -lboard_t * -find_gfxpipe(int pipenum) -{ - gda_t *gdap; - cnodeid_t cnode; - nasid_t nasid; - lboard_t *lb; - klgfx_t *kg,**pkg; - int i; - - gdap = (gda_t *)GDA_ADDR(get_nasid()); - if (gdap->g_magic != GDA_MAGIC) - return NULL; - - if (!graphics_pipe_list) { - /* for all nodes */ - for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) { - nasid = gdap->g_nasidtable[cnode]; - if (nasid == INVALID_NASID) - continue; - lb = KL_CONFIG_INFO(nasid) ; - while (lb = find_lboard_class(lb, KLCLASS_GFX)) { - moduleid_t kgm, pkgm; - int kgs, pkgs; - -#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP) - printf("find_gfxpipe(): PIPE: %s mod %M slot %d\n",lb?lb->brd_name:"!LBRD", - lb->brd_module,lb->brd_slot); -#endif - /* insert lb into list */ - if (!(kg = (klgfx_t*)find_first_component(lb,KLSTRUCT_GFX))) { - lb = KLCF_NEXT(lb); - continue; - } - /* set moduleslot now that we have brd_module set */ - kg->moduleslot = (lb->brd_module << 8) | SLOTNUM_GETSLOT(lb->brd_slot); - /* make sure board has device flag set */ - kg->gfx_info.flags |= KLINFO_DEVICE; - if (kg->cookie < KLGFX_COOKIE) { - kg->gfx_next_pipe = NULL; - kg->cookie = KLGFX_COOKIE; - } - - kgm = kg->moduleslot>>8; - kgs = kg->moduleslot&0xff; - pkg = &graphics_pipe_list; - while (*pkg) { - pkgm = (*pkg)->moduleslot>>8; - pkgs = (*pkg)->moduleslot&0xff; - - if (!(MODULE_CMP(kgm, pkgm) > 0 || - (MODULE_CMP(kgm, pkgm) == 0 && - kgs > pkgs))) - break; - - pkg = &(*pkg)->gfx_next_pipe; - } - kg->gfx_next_pipe = *pkg; - *pkg = kg; - lb = KLCF_NEXT(lb); - } - } -#ifdef FIND_GFXPIPE_DEBUG - i = 0; - kg = graphics_pipe_list; - while (kg) { - lboard_t *lb; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - lb = find_lboard_class(KL_CONFIG_INFO(kg->gfx_info.nasid), KLCLASS_GFX); -#else -#error Need to figure out how to find graphics boards ... -#endif -#if defined(SUPPORT_PRINTING_M_FORMAT) - printf("find_gfxpipe(): %s pipe %d mod %M slot %d\n",lb?lb->brd_name:"!LBRD",i, - (kg->moduleslot>>8),(kg->moduleslot&0xff)); -#else - printf("find_gfxpipe(): %s pipe %d mod 0x%x slot %d\n",lb?lb->brd_name:"!LBRD",i, - (kg->moduleslot>>8),(kg->moduleslot&0xff)); -#endif - kg = kg->gfx_next_pipe; - i++; - } -#endif - } - - i = 0; - kg = graphics_pipe_list; - while (kg && (i < pipenum)) { - kg = kg->gfx_next_pipe; - i++; - } - - if (!kg) return NULL; - -#if defined(SN0) - return find_lboard_modslot(KL_CONFIG_INFO(kg->gfx_info.nasid), - (kg->moduleslot>>8), - SLOTNUM_XTALK_CLASS|(kg->moduleslot&0xff)); -#elif defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - return find_lboard_class(KL_CONFIG_INFO(kg->gfx_info.nasid), KLCLASS_GFX); -#else -#error Need to figure out how to find graphics boards ... -#endif -} -#endif - - #define MHZ 1000000 -#ifndef CONFIG_IA64_SGI_IO -uint -cpu_cycles_adjust(uint orig_cycles) -{ - klcpu_t *acpu; - uint speed; - - acpu = nasid_slice_to_cpuinfo(get_nasid(), get_slice()); - - if (acpu == NULL) return orig_cycles; - - /* - * cpu cycles seem to be half of the real value, hack and mult by 2 - * for now. - */ - speed = (orig_cycles * 2) / MHZ; - - /* - * if the cpu thinks its running at some random speed nowhere close - * the programmed speed, do nothing. - */ - if ((speed < (acpu->cpu_speed - 2)) || (speed > (acpu->cpu_speed + 2))) - return orig_cycles; - return (acpu->cpu_speed * MHZ/2); -} -#endif /* CONFIG_IA64_SGI_IO */ /* Get the canonical hardware graph name for the given pci component * on the given io board. @@ -633,9 +454,6 @@ moduleid_t modnum; slotid_t slot; char board_name[20]; -#ifdef SN0 - char slot_name[SLOTNUM_MAXLENGTH]; -#endif ASSERT(brd); @@ -646,13 +464,7 @@ * into a string */ slot = brd->brd_slot; -#ifdef SN0 - get_slotname(slot, slot_name); - - ASSERT(modnum >= 0); -#else ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); -#endif /* Get the io board name */ if (!brd || (brd->brd_sversion < 2)) { @@ -662,18 +474,10 @@ } /* Give out the canonical name of the pci device*/ -#ifdef SN0 - sprintf(name, - "/hw/"EDGE_LBL_MODULE "/%M/"EDGE_LBL_SLOT"/%s/%s/" - EDGE_LBL_PCI"/%d", - modnum, slot_name, board_name,KLCF_BRIDGE_W_ID(component)); -#elif defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) sprintf(name, "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/" EDGE_LBL_PCI"/%d", modnum, board_name,KLCF_BRIDGE_W_ID(component)); -#endif - } /* @@ -894,90 +698,6 @@ } #include "asm/sn/sn_private.h" -#ifndef CONFIG_IA64_SGI_IO -/* - * Given a physical address get the name of memory dimm bank - * in a hwgraph name format. - */ -void -membank_pathname_get(paddr_t paddr,char *name) -{ - cnodeid_t cnode; - char slotname[SLOTNUM_MAXLENGTH]; - - cnode = paddr_cnode(paddr); - /* Make sure that we have a valid name buffer */ - if (!name) - return; - - name[0] = 0; - /* Make sure that the cnode is valid */ - if ((cnode == CNODEID_NONE) || (cnode > numnodes)) - return; - /* Given a slotid(class:type) get the slotname */ -#if defined (SN0) - get_slotname(NODE_SLOTID(cnode),slotname); - sprintf(name, - "/hw/"EDGE_LBL_MODULE"/%M/"EDGE_LBL_SLOT"/%s/"EDGE_LBL_NODE - "/"EDGE_LBL_MEMORY"/dimm_bank/%d", - NODE_MODULEID(cnode),slotname,paddr_dimm(paddr)); -#elif defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - sprintf(name, - "/dev/hw/"EDGE_LBL_MODULE"/%M/"EDGE_LBL_NODE - "/"EDGE_LBL_MEMORY"/dimm_bank/%d", - NODE_MODULEID(cnode),paddr_dimm(paddr)); -#endif -} - - - -int -membank_check_mixed_hidensity(nasid_t nasid) -{ - lboard_t *brd; - klmembnk_t *mem; - int min_size = 1024, max_size = 0; - int bank, mem_size; - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); - ASSERT(brd); - - mem = (klmembnk_t *)find_first_component(brd, KLSTRUCT_MEMBNK); - ASSERT(mem); - - - for (mem_size = 0, bank = 0; bank < MD_MEM_BANKS; bank++) { - mem_size = KLCONFIG_MEMBNK_SIZE(mem, bank); - if (mem_size < min_size) - min_size = mem_size; - if (mem_size > max_size) - max_size = mem_size; - } - - if ((max_size == 512) && (max_size != min_size)) - return 1; - - return 0; -} - - -int -mem_mixed_hidensity_banks(void) -{ - cnodeid_t cnode; - nasid_t nasid; - - for (cnode = 0; cnode < maxnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - if (nasid == INVALID_NASID) - continue; - if (membank_check_mixed_hidensity(nasid)) - return 1; - } - return 0; - -} -#endif /* CONFIG_IA64_SGI_IO */ xwidgetnum_t nodevertex_widgetnum_get(devfs_handle_t node_vtx) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/klgraph.c linux.ac/arch/ia64/sn/io/klgraph.c --- linux.vanilla/arch/ia64/sn/io/klgraph.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/klgraph.c Tue Apr 10 18:09:55 2001 @@ -23,18 +23,15 @@ #include #include -#include #include -#ifdef CONFIG_IA64_SGI_IO #include -#endif #include #include #include #include #include -#define KLGRAPH_DEBUG 1 +/* #define KLGRAPH_DEBUG 1 */ #ifdef KLGRAPH_DEBUG #define GRPRINTF(x) printk x #define CE_GRPANIC CE_PANIC @@ -48,25 +45,6 @@ extern char arg_maxnodes[]; extern int maxnodes; -#ifndef BRINGUP -/* - * Gets reason for diagval using table lookup. - */ -static char* -get_diag_string(uint diagcode) -{ - int num_entries; - int i; - num_entries = sizeof(diagval_map) / sizeof(diagval_t); - for (i = 0; i < num_entries; i++){ - if ((unchar)diagval_map[i].dv_code == (unchar)diagcode) - return diagval_map[i].dv_msg; - } - return "Unknown"; -} - -#endif /* ndef BRINGUP */ - /* * Support for verbose inventory via hardware graph. @@ -105,7 +83,7 @@ klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); baseio_inventory->im_type = INV_IO6PROM; /* Read the io6prom revision from the nvram */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER nvram_prom_version_get(&version,&revision); #endif /* Store the revision info in the inventory */ @@ -169,7 +147,7 @@ (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); rc = device_master_set(myhubv, node_vertex); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Activate when we support hub stats. */ @@ -178,8 +156,7 @@ #endif if (rc != GRAPH_SUCCESS) { - cmn_err(CE_WARN, - "klhwg_add_hub: Can't add hub info label 0x%p, code %d", + PRINT_WARNING("klhwg_add_hub: Can't add hub info label 0x%p, code %d", myhubv, rc); } @@ -187,15 +164,12 @@ #ifndef BRINGUP init_hub_stats(cnode, NODEPDA(cnode)); -#endif /* ndef BRINGUP */ - -#ifndef CONFIG_IA64_SGI_IO sndrv_attach(myhubv); #else /* * Need to call our driver to do the attach? */ - printk("klhwg_add_hub: Need to add code to do the attach.\n"); + FIXME("klhwg_add_hub: Need to add code to do the attach.\n"); #endif } @@ -350,7 +324,7 @@ rps_invent->ir_gen.ig_flag = INVENT_ENABLED; } -#endif /* ndef BRINGUP */ +#endif /* BRINGUP */ void klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) @@ -366,7 +340,7 @@ #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC) if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_PBRICK_XBOW)) == NULL) + KLTYPE_IOBRICK_XBOW)) == NULL) return; #endif @@ -380,7 +354,7 @@ == NULL) return; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * We cannot support this function in devfs .. see below where * we use hwgraph_path_add() to create this vertex with a known @@ -390,21 +364,19 @@ ASSERT(err == GRAPH_SUCCESS); xswitch_vertex_init(xbow_v); -#endif /* !CONFIG_IA64_SGI_IO */ +#endif /* LATER */ for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) continue; hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); - printk("klhwg_add_xbow: Found xbow port type hub hub_nasid %d widgetnum %d\n", hub_nasid, widgetnum); if (hub_nasid == INVALID_NASID) { - cmn_err(CE_WARN, "hub widget %d, skipping xbow graph\n", widgetnum); + PRINT_WARNING("hub widget %d, skipping xbow graph\n", widgetnum); continue; } hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid); - printk("klhwg_add_xbow: cnode %d cnode %d\n", nasid_to_compact_node[0], nasid_to_compact_node[1]); if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) { continue; @@ -412,21 +384,18 @@ hubv = cnodeid_to_vertex(hub_cnode); -#ifdef CONFIG_IA64_SGI_IO - printk("klhwg_add_xbow: Hub Vertex found = %p hub_cnode %d\n", hubv, hub_cnode); err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); if (err != GRAPH_SUCCESS) { if (err == GRAPH_DUP) - cmn_err(CE_WARN, "klhwg_add_xbow: Check for " + PRINT_WARNING("klhwg_add_xbow: Check for " "working routers and router links!"); - cmn_err(CE_GRPANIC, "klhwg_add_xbow: Failed to add " + PRINT_PANIC("klhwg_add_xbow: Failed to add " "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p)," "error %d\n", hubv, hubv, xbow_v, xbow_v, err); } xswitch_vertex_init(xbow_v); -#endif NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; @@ -443,14 +412,14 @@ GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n", hub_nasid, EDGE_LBL_XTALK, hubv)); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK); if (err != GRAPH_SUCCESS) { if (err == GRAPH_DUP) - cmn_err(CE_WARN, "klhwg_add_xbow: Check for " + PRINT_WARNING("klhwg_add_xbow: Check for " "working routers and router links!"); - cmn_err(CE_GRPANIC, "klhwg_add_xbow: Failed to add " + PRINT_PANIC("klhwg_add_xbow: Failed to add " "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), " "error %d\n", hubv, hubv, xbow_v, xbow_v, err); @@ -488,9 +457,8 @@ path_buffer, hwgraph_root)); rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - printk("klhwg_add_node: rv = %d graph success %d node_vertex 0x%p\n", rv, GRAPH_SUCCESS, node_vertex); if (rv != GRAPH_SUCCESS) - cmn_err(CE_PANIC, "Node vertex creation failed. " + PRINT_PANIC("Node vertex creation failed. " "Path == %s", path_buffer); @@ -504,11 +472,8 @@ if(!board_disabled) { mark_nodevertex_as_node(node_vertex, cnode + board_disabled * numnodes); - printk("klhwg_add_node: node_vertex %p, cnode %d numnodes %d\n", node_vertex, cnode, numnodes); s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); - printk("klhwg_add_node: s %s\n", s); - NODEPDA(cnode)->hwg_node_name = kmalloc(strlen(s) + 1, GFP_KERNEL); @@ -581,7 +546,7 @@ rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); if (rv != GRAPH_SUCCESS) - cmn_err(CE_PANIC, "Router vertex creation " + PRINT_PANIC("Router vertex creation " "failed. Path == %s", path_buffer); @@ -629,12 +594,11 @@ return; if (rc != GRAPH_SUCCESS) - cmn_err(CE_WARN, "Can't find router: %s", path_buffer); + PRINT_WARNING("Can't find router: %s", path_buffer); /* We don't know what to do with multiple router components */ if (brd->brd_numcompts != 1) { - cmn_err(CE_PANIC, - "klhwg_connect_one_router: %d cmpts on router\n", + PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n", brd->brd_numcompts); return; } @@ -668,7 +632,7 @@ if (rc != GRAPH_SUCCESS) { if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) continue; - cmn_err(CE_PANIC, "Can't find router: %s", dest_path); + PRINT_PANIC("Can't find router: %s", dest_path); } GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n", path_buffer, port, dest_path)); @@ -685,7 +649,7 @@ } if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) - cmn_err(CE_GRPANIC, "Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", path_buffer, dest_path, dest_hndl, rc); } @@ -768,7 +732,7 @@ rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); if (rc != GRAPH_SUCCESS) - cmn_err(CE_WARN, "Can't find hub: %s", path_buffer); + PRINT_WARNING("Can't find hub: %s", path_buffer); dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( hub->hub_port.port_nasid, @@ -782,7 +746,7 @@ if (rc != GRAPH_SUCCESS) { if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) continue; - cmn_err(CE_PANIC, "Can't find board: %s", dest_path); + PRINT_PANIC("Can't find board: %s", dest_path); } else { @@ -792,7 +756,7 @@ rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT); if (rc != GRAPH_SUCCESS) - cmn_err(CE_GRPANIC, "Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", path_buffer, dest_path, dest_hndl, rc); } @@ -815,7 +779,7 @@ */ char device_name[MAXDEVNAME]; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER device_admin_table_init(); #endif for(cnode = 0; cnode < numnodes; cnode++) { @@ -853,7 +817,7 @@ device_component_canonical_name_get(board, component, device_name); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER device_admin_table_update(device_name, ADMIN_LBL_DISABLED, "yes"); @@ -877,13 +841,20 @@ char name[128]; devfs_handle_t vhdl; int rc; + char buffer[16]; /* Add devices under each module */ for (cm = 0; cm < nummodules; cm++) { /* Use module as module vertex fastinfo */ +#ifdef __ia64 + memset(buffer, 0, 16); + format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); + sprintf(name, EDGE_LBL_MODULE "/%s", buffer); +#else sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id); +#endif rc = hwgraph_path_add(hwgraph_root, name, &vhdl); ASSERT(rc == GRAPH_SUCCESS); @@ -893,9 +864,15 @@ /* Add system controller */ +#ifdef __ia64 + sprintf(name, + EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, + buffer); +#else sprintf(name, EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1, modules[cm]->id); +#endif rc = hwgraph_path_add(hwgraph_root, name, &vhdl); ASSERT_ALWAYS(rc == GRAPH_SUCCESS); @@ -905,7 +882,7 @@ INFO_LBL_ELSC, (arbitrary_info_t) (__psint_t) 1); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER sndrv_attach(vhdl); #else /* @@ -923,13 +900,10 @@ gda_t *gdap; cnodeid_t cnode; -#ifdef SIMULATED_KLGRAPH - //gdap = 0xa800000000011000; - gdap = (gda_t *)0xe000000000011000; - printk("klhwg_add_all_nodes: SIMULATED_KLGRAPH FIXME: gdap= 0x%p\n", gdap); -#else - gdap = GDA; -#endif /* SIMULATED_KLGRAPH */ + gdap = (gda_t *)0xe000000000002400; + + FIXME("klhwg_add_all_nodes: FIX GDA\n"); + for (cnode = 0; cnode < numnodes; cnode++) { ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); klhwg_add_node(hwgraph_root, cnode, gdap); @@ -938,12 +912,7 @@ for (cnode = 0; cnode < numnodes; cnode++) { ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); -#ifndef CONFIG_IA64_SGI_IO klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]); -#else - printk("klhwg_add_all_nodes: Fix me by getting real nasid\n"); - klhwg_add_xbow(cnode, 0); -#endif } /* @@ -959,7 +928,7 @@ * routers in the system. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER router_guardians_set(hwgraph_root); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/klgraph_hack.c linux.ac/arch/ia64/sn/io/klgraph_hack.c --- linux.vanilla/arch/ia64/sn/io/klgraph_hack.c Sat Feb 17 00:02:34 2001 +++ linux.ac/arch/ia64/sn/io/klgraph_hack.c Sat Apr 14 01:18:00 2001 @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -35,55 +34,6 @@ extern void clear_ii_error(void); #endif /* BRINGUP */ -void -simulated_BW0_init(void) -{ - - unsigned long *cnode0_hub; - unsigned long hub_widget = 0x1000000; - unsigned long hub_offset = 0x800000; - unsigned long hub_reg_base = 0; - extern void * vmalloc(unsigned long); - - memset(&nasid_to_compact_node[0], 0, sizeof(cnodeid_t) * MAX_NASIDS); - - BW0 = vmalloc(0x10000000); - if (BW0 == NULL) { - printk("Darn it .. cannot create space for Big Window 0\n"); - } - printk("BW0: Start Address %p\n", BW0); - - memset(BW0+(0x10000000 - 8), 0xf, 0x8); - - printk("BW0: Last WORD address %p has value 0x%lx\n", (char *)(BW0 +(0x10000000 - 8)), *(long *)(BW0 +(0x10000000 - 8))); - - printk("XWIDGET 8 Address = 0x%p\n", (unsigned long *)(NODE_SWIN_BASE(0, 8)) ); - - /* - * Do some HUB Register Hack .. - */ - hub_reg_base = (unsigned long)BW0 + hub_widget + hub_offset; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WID); *cnode0_hub = 0x1c110049; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WSTAT); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WCR); *cnode0_hub = 0x401b; - printk("IIO_WCR address = 0x%p\n", cnode0_hub); - - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILAPR); *cnode0_hub = 0xffffffffffffffff; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILAPO); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IOWA); *cnode0_hub = 0xff01; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIWA); *cnode0_hub = 0xff01; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIDEM); *cnode0_hub = 0xffffffffffffffff; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILCSR); *cnode0_hub = 0x3fc03ff640a; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILLR); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIDSR); *cnode0_hub = 0x1000040; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IGFX0); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IGFX1); *cnode0_hub = 0x0; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ISCR0); *cnode0_hub = 0x23d; - cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ISCR1); *cnode0_hub = 0x0; -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ -} - #define SYNERGY_WIDGET ((char *)0xc0000e0000000000) #define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) #define HUBREG ((char *)0xc0000a0001e00000) @@ -136,10 +86,10 @@ klxbow_t *klxbow_ptr; klinfo_t *klinfo_ptr; klcomp_t *klcomp_ptr; +#if 0 uint64_t *tmp; volatile u32 *tmp32; -#if 0 /* Preset some values */ /* Write IOERR clear to clear the CRAZY bit in the status */ tmp = (uint64_t *)0xc0000a0001c001f8; *tmp = (uint64_t)0xffffffff; @@ -164,7 +114,6 @@ *tmp32 = 0xba98; tmp32 = (volatile u32 *)0xc0000a000f000288L; *tmp32 = 0xba98; -#endif printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc0000a0001e00000, *( (volatile uint64_t *)0xc0000a0001e00000) ); @@ -181,6 +130,7 @@ printk("Xbow ID Address 0x%p Value 0x%x\n", (uint64_t *)0xc000020000000004, *( (volatile uint32_t *)0xc000020000000004) ); +#endif if ( test ) test_io_regs(); @@ -210,9 +160,8 @@ */ linux_klcfg = (kl_config_hdr_t *)0xe000000000030000; if (linux_klcfg->ch_magic == 0xbeedbabe) { - printk("Linux Kernel Booted from Disk\n"); + return; } else { - printk("Linux Kernel Booted from PROM\n"); linux_klcfg = kl_hdr_ptr; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/l1.c linux.ac/arch/ia64/sn/io/l1.c --- linux.vanilla/arch/ia64/sn/io/l1.c Tue Apr 3 17:31:53 2001 +++ linux.ac/arch/ia64/sn/io/l1.c Tue Apr 10 18:09:55 2001 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +51,20 @@ #include +/* + * Delete this when atomic_clear is part of atomic.h. + */ +static __inline__ int +atomic_clear (int i, atomic_t *v) +{ + __s32 old, new; + + do { + old = atomic_read(v); + new = old & ~i; + } while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old); + return new; +} #if defined(EEPROM_DEBUG) #define db_printf(x) printk x @@ -73,6 +87,7 @@ /* location of uart receive/xmit data register */ #define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), HSPEC_UART_0)) #define LOCAL_HUB LOCAL_HUB_ADDR +#define LOCK_HUB REMOTE_HUB_ADDR #define ADDR_L1_REG(n, r) \ (L1_UART_BASE(n) | ( (r) << 3 )) @@ -84,21 +99,10 @@ ( SD(ADDR_L1_REG((n), (r)), (v)) ) -/* Avoid conflicts with symmon...*/ -#define CONS_HW_LOCK(x) -#define CONS_HW_UNLOCK(x) - -#define L1_CONS_HW_LOCK(sc) CONS_HW_LOCK(sc->uart == BRL1_LOCALUART) -#define L1_CONS_HW_UNLOCK(sc) CONS_HW_UNLOCK(sc->uart == BRL1_LOCALUART) - -#if DEBUG -static int debuglock_ospl; /* For CONS_HW_LOCK macro */ -#endif - /* UART-related #defines */ #define UART_BAUD_RATE 57600 -#define UART_FIFO_DEPTH 16 +#define UART_FIFO_DEPTH 0xf0 #define UART_DELAY_SPAN 10 #define UART_PUTC_TIMEOUT 50000 #define UART_INIT_TIMEOUT 100000 @@ -146,6 +150,9 @@ _xyz[0] = _b[_i++]; \ } #else /* BIG_ENDIAN */ + +extern char *bcopy(const char * src, char * dest, int count); + #define COPY_INT_TO_BUFFER(_b, _i, _n) \ { \ bcopy((char *)&_n, _b, sizeof(_n)); \ @@ -165,13 +172,148 @@ } #endif /* LITTLE_ENDIAN */ -int atomicAddInt(int *int_ptr, int value); -int atomicClearInt(int *int_ptr, int value); void kmem_free(void *where, int size); #define BCOPY(x,y,z) memcpy(y,x,z) -extern char *bcopy(const char * src, char * dest, int count); +/* + * Console locking defines and functions. + * + */ + +#ifdef BRINGUP +#define FORCE_CONSOLE_NASID +#endif + +#define HUB_LOCK 16 + +#define PRIMARY_LOCK_TIMEOUT 10000000 +#define HUB_LOCK_REG(n) LOCK_HUB(n, MD_PERF_CNT0) + +#define SET_BITS(reg, bits) SD(reg, LD(reg) | (bits)) +#define CLR_BITS(reg, bits) SD(reg, LD(reg) & ~(bits)) +#define TST_BITS(reg, bits) ((LD(reg) & (bits)) != 0) + +#define HUB_TEST_AND_SET(n) LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ)) +#define HUB_CLEAR(n) SD(LOCK_HUB(n,LB_SCRATCH_REG3),0) + +#define RTC_TIME_MAX ((rtc_time_t) ~0ULL) + + +/* + * primary_lock + * + * Allows CPU's 0-3 to mutually exclude the hub from one another by + * obtaining a blocking lock. Does nothing if only one CPU is active. + * + * This lock should be held just long enough to set or clear a global + * lock bit. After a relatively short timeout period, this routine + * figures something is wrong, and steals the lock. It does not set + * any other CPU to "dead". + */ +inline void +primary_lock(nasid_t nasid) +{ + rtc_time_t expire; + + expire = rtc_time() + PRIMARY_LOCK_TIMEOUT; + + while (HUB_TEST_AND_SET(nasid)) { + if (rtc_time() > expire) { + HUB_CLEAR(nasid); + } + } +} + +/* + * primary_unlock (internal) + * + * Counterpart to primary_lock + */ + +inline void +primary_unlock(nasid_t nasid) +{ + HUB_CLEAR(nasid); +} + +/* + * hub_unlock + * + * Counterpart to hub_lock_timeout and hub_lock + */ + +inline void +hub_unlock(nasid_t nasid, int level) +{ + uint64_t mask = 1ULL << level; + + primary_lock(nasid); + CLR_BITS(HUB_LOCK_REG(nasid), mask); + primary_unlock(nasid); +} + +/* + * hub_lock_timeout + * + * Uses primary_lock to implement multiple lock levels. + * + * There are 20 lock levels from 0 to 19 (limited by the number of bits + * in HUB_LOCK_REG). To prevent deadlock, multiple locks should be + * obtained in order of increasingly higher level, and released in the + * reverse order. + * + * A timeout value of 0 may be used for no timeout. + * + * Returns 0 if successful, -1 if lock times out. + */ + +inline int +hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout) +{ + uint64_t mask = 1ULL << level; + rtc_time_t expire = (timeout ? rtc_time() + timeout : RTC_TIME_MAX); + int done = 0; + + while (! done) { + while (TST_BITS(HUB_LOCK_REG(nasid), mask)) { + if (rtc_time() > expire) + return -1; + } + + primary_lock(nasid); + + if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) { + SET_BITS(HUB_LOCK_REG(nasid), mask); + done = 1; + } + primary_unlock(nasid); + } + return 0; +} + + +#define LOCK_TIMEOUT (0x1500000 * 1) /* 0x1500000 is ~30 sec */ + +inline void +lock_console(nasid_t nasid) +{ + int ret; + + ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); + if ( ret != 0 ) { + /* timeout */ + hub_unlock(nasid, HUB_LOCK); + /* If the 2nd lock fails, just pile ahead.... */ + hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); + } +} + +inline void +unlock_console(nasid_t nasid) +{ + hub_unlock(nasid, HUB_LOCK); +} int @@ -189,7 +331,7 @@ UART_DELAY( delay_span ); } -#define UART_PUTC_READY(n) (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) +#define UART_PUTC_READY(n) ( (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) && (READ_L1_UART_REG((n), REG_MSR) & MSR_CTS) ) static int uart_putc( l1sc_t *sc ) @@ -198,6 +340,10 @@ /* need a delay to avoid dropping chars */ UART_DELAY(57); #endif +#ifdef FORCE_CONSOLE_NASID + /* We need this for the console write path _elscuart_flush() -> brl1_send() */ + sc->nasid = 0; +#endif WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] ); return UART_SUCCESS; @@ -210,6 +356,10 @@ u_char lsr_reg = 0; nasid_t nasid = sc->nasid; +#ifdef FORCE_CONSOLE_NASID + nasid = sc->nasid = 0; +#endif + if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) { @@ -246,7 +396,8 @@ } } - L1_CONS_HW_LOCK( sc ); + if ( sc->uart == BRL1_LOCALUART ) + lock_console(nasid); WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB ); uart_delay( UART_DELAY_SPAN ); @@ -271,17 +422,17 @@ WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO ); - L1_CONS_HW_UNLOCK( sc ); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(nasid); } +/* This requires the console lock */ static void uart_intr_enable( l1sc_t *sc, u_char mask ) { u_char lcr_reg, icr_reg; nasid_t nasid = sc->nasid; - L1_CONS_HW_LOCK(sc); - /* make sure that the DLAB bit in the LCR register is 0 */ lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); @@ -293,18 +444,15 @@ icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); icr_reg |= mask; WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - L1_CONS_HW_UNLOCK(sc); } +/* This requires the console lock */ static void uart_intr_disable( l1sc_t *sc, u_char mask ) { u_char lcr_reg, icr_reg; nasid_t nasid = sc->nasid; - L1_CONS_HW_LOCK(sc); - /* make sure that the DLAB bit in the LCR register is 0 */ lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); @@ -316,8 +464,6 @@ icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); icr_reg &= mask; WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - L1_CONS_HW_UNLOCK(sc); } #define uart_enable_xmit_intr(sc) \ @@ -353,15 +499,9 @@ } \ } -#ifdef SABLE -#define RTR_UART_PUTC_TIMEOUT 0 -#define RTR_UART_DELAY_SPAN 0 -#define RTR_UART_INIT_TIMEOUT 0 -#else #define RTR_UART_PUTC_TIMEOUT UART_PUTC_TIMEOUT*10 #define RTR_UART_DELAY_SPAN UART_DELAY_SPAN #define RTR_UART_INIT_TIMEOUT UART_INIT_TIMEOUT*10 -#endif static int rtr_uart_putc( l1sc_t *sc ) @@ -370,7 +510,11 @@ nasid_t nasid = sc->nasid; net_vec_t path = sc->uart; rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT; - + +#ifdef FORCE_CONSOLE_NASID + /* We need this for the console write path _elscuart_flush() -> brl1_send() */ + nasid = sc->nasid = 0; +#endif c = (sc->send[sc->sent] & 0xffULL); while( 1 ) @@ -399,6 +543,10 @@ nasid_t nasid = sc->nasid; net_vec_t path = sc->uart; +#ifdef FORCE_CONSOLE_NASID + nasid = sc->nasid = 0; +#endif + READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) { @@ -468,28 +616,6 @@ return 0; } - - - -/********************************************************************* - * locking macros - */ - -#define L1SC_SEND_LOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - (pl) = mutex_spinlock_spl( &((l)->send_lock), spl7 ); } - -#define L1SC_SEND_UNLOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - mutex_spinunlock( &((l)->send_lock), (pl)); } - -#define L1SC_RECV_LOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - (pl) = mutex_spinlock_spl( &((l)->recv_lock), spl7 ); } - -#define L1SC_RECV_UNLOCK(l,pl) \ - { if( (l)->uart == BRL1_LOCALUART ) \ - mutex_spinunlock( &((l)->recv_lock), (pl)); } /********************************************************************* @@ -501,60 +627,17 @@ * */ - #ifdef SPINLOCKS_WORK -#define SUBCH_LOCK(sc,pl) \ - (pl) = mutex_spinlock_spl( &((sc)->subch_lock), spl7 ) -#define SUBCH_UNLOCK(sc,pl) \ - mutex_spinunlock( &((sc)->subch_lock), (pl) ) - -#define SUBCH_DATA_LOCK(sbch,pl) \ - (pl) = mutex_spinlock_spl( &((sbch)->data_lock), spl7 ) -#define SUBCH_DATA_UNLOCK(sbch,pl) \ - mutex_spinunlock( &((sbch)->data_lock), (pl) ) +#define SUBCH_LOCK(sc) spin_lock_irq( &((sc)->subch_lock) ) +#define SUBCH_UNLOCK(sc) spin_unlock_irq( &((sc)->subch_lock) ) +#define SUBCH_DATA_LOCK(sbch) spin_lock_irq( &((sbch)->data_lock) ) +#define SUBCH_DATA_UNLOCK(sbch) spin_unlock_irq( &((sbch)->data_lock) ) #else -#define SUBCH_LOCK(sc,pl) -#define SUBCH_UNLOCK(sc,pl) -#define SUBCH_DATA_LOCK(sbch,pl) -#define SUBCH_DATA_UNLOCK(sbch,pl) -#endif /* SPINLOCKS_WORK */ - -/* - * set a function to be called for subchannel ch in the event of - * a transmission low-water interrupt from the uart - */ -void -subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - int pl; - L1SC_SEND_LOCK( sc, pl ); - sc->subch[ch].tx_notify = func; - - /* some upper layer is asking to be notified of low-water, but if the - * send buffer isn't already in use, we're going to need to get the - * interrupts going on the uart... - */ - if( func && !sc->send_in_use ) - uart_enable_xmit_intr( sc ); - L1SC_SEND_UNLOCK(sc, pl ); -} - -/* - * set a function to be called for subchannel ch when data is received - */ -void -subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ -#ifdef SPINLOCKS_WORK - int pl; +#define SUBCH_LOCK(sc) +#define SUBCH_UNLOCK(sc) +#define SUBCH_DATA_LOCK(sbch) +#define SUBCH_DATA_UNLOCK(sbch) #endif - brl1_sch_t *subch = &(sc->subch[ch]); - - SUBCH_DATA_LOCK( subch, pl ); - sc->subch[ch].rx_notify = func; - SUBCH_DATA_UNLOCK( subch, pl ); -} - /* get_myid is an internal function that reads the PI_CPU_NUM @@ -680,21 +763,18 @@ /* timeouts */ #define BRL1_INIT_TIMEOUT 500000 -extern l1sc_t * get_elsc( void ); - /* * brl1_discard_packet is a dummy "receive callback" used to get rid * of packets we don't want */ void brl1_discard_packet( l1sc_t *sc, int ch ) { - int pl; brl1_sch_t *subch = &sc->subch[ch]; sc_cq_t *q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); q->opos = q->ipos; - atomicClearInt( &(subch->packet_arrived), ~((unsigned)0) ); - SUBCH_DATA_UNLOCK( subch, pl ); + atomic_clear( &(subch->packet_arrived), ~((unsigned)0) ); + SUBCH_DATA_UNLOCK( subch ); } @@ -720,18 +800,14 @@ */ if( sc->uart == BRL1_LOCALUART ) { - CONS_HW_LOCK(1); if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) ) -// sc->fifo_space = UART_FIFO_DEPTH; - sc->fifo_space = 1000; + sc->fifo_space = UART_FIFO_DEPTH; while( (sc->sent < sc->send_len) && (sc->fifo_space) ) { uart_putc( sc ); sc->fifo_space--; sc->sent++; } - - CONS_HW_UNLOCK(1); } else @@ -770,7 +846,6 @@ } } } - return sc->sent; } @@ -786,20 +861,25 @@ * until our message has been completely transmitted. */ -int +static int brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait ) { - int pl; int index; int pkt_len = 0; unsigned short crc = INIT_CRC; char *send_ptr = sc->send; - L1SC_SEND_LOCK(sc, pl); +#ifdef BRINGUP + /* We want to be sure that we are sending the entire packet before returning */ + wait = 1; +#endif + if ( sc->uart == BRL1_LOCALUART ) + lock_console(sc->nasid); if( sc->send_in_use ) { if( !wait ) { - L1SC_SEND_UNLOCK(sc, pl); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); return 0; /* couldn't send anything; wait for buffer to drain */ } else { @@ -880,61 +960,12 @@ /* enable low-water interrupts so buffer will be drained */ uart_enable_xmit_intr(sc); } - L1SC_SEND_UNLOCK(sc, pl); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); return len; } -/* brl1_send_cont is intended to be called as an interrupt service - * routine. It sends until the UART won't accept any more characters, - * or until an error is encountered (in which case we surrender the - * send buffer and give up trying to send the packet). Once the - * last character in the packet has been sent, this routine releases - * the send buffer and calls any previously-registered "low-water" - * output routines. - */ -int -brl1_send_cont( l1sc_t *sc ) -{ - int pl; - int done = 0; - brl1_notif_t callups[BRL1_NUM_SUBCHANS]; - brl1_notif_t *callup; - brl1_sch_t *subch; - int index; - - L1SC_SEND_LOCK(sc, pl); - brl1_send_chars( sc ); - done = (sc->sent == sc->send_len); - if( done ) { - - sc->send_in_use = 0; - uart_disable_xmit_intr(sc); - - /* collect pointers to callups *before* unlocking */ - subch = sc->subch; - callup = callups; - for( index = 0; index < BRL1_NUM_SUBCHANS; index++ ) { - *callup = subch->tx_notify; - subch++; - callup++; - } - } - L1SC_SEND_UNLOCK(sc, pl); - - if( done ) { - /* call any upper layer that's asked for low-water notification */ - callup = callups; - for( index = 0; index < BRL1_NUM_SUBCHANS; index++ ) { - if( *callup ) - (*(*callup))( sc, index ); - callup++; - } - } - return 0; -} - - /* internal function -- used by brl1_receive to read a character * from the uart and check whether errors occurred in the process. */ @@ -1039,14 +1070,16 @@ { int result; /* value to be returned by brl1_receive */ int c; /* most-recently-read character */ - int pl; /* priority level for UART receive lock */ int done; /* set done to break out of recv loop */ sc_cq_t *q; /* pointer to queue we're working with */ result = BRL1_NO_MESSAGE; - L1SC_RECV_LOCK( sc, pl ); - L1_CONS_HW_LOCK( sc ); +#ifdef FORCE_CONSOLE_NASID + sc->nasid = 0; +#endif + if ( sc->uart == BRL1_LOCALUART ) + lock_console(sc->nasid); done = 0; while( !done ) @@ -1171,7 +1204,6 @@ unsigned short crc; /* holds the crc as we calculate it */ int i; /* index variable */ brl1_sch_t *subch; /* subchannel for received packet */ - int sch_pl; /* cookie for subchannel lock */ brl1_notif_t callup; /* "data ready" callup */ /* whatever else may happen, we've seen a flag and we're @@ -1226,7 +1258,7 @@ /* get the subchannel and lock it */ subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); - SUBCH_DATA_LOCK( subch, sch_pl ); + SUBCH_DATA_LOCK( subch ); /* if this isn't a console packet, we need to record * a length byte @@ -1242,16 +1274,16 @@ /* notify subchannel owner that there's something * on the queue for them */ - atomicAddInt( &(subch->packet_arrived), 1); + atomic_inc(&(subch->packet_arrived)); callup = subch->rx_notify; - SUBCH_DATA_UNLOCK( subch, sch_pl ); + SUBCH_DATA_UNLOCK( subch ); if( callup ) { - L1_CONS_HW_UNLOCK( sc ); - L1SC_RECV_UNLOCK( sc, pl ); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); (*callup)( sc, SUBCH(LAST_HDR_GET(sc)) ); - L1SC_RECV_LOCK( sc, pl ); - L1_CONS_HW_LOCK( sc ); + if ( sc->uart == BRL1_LOCALUART ) + lock_console(sc->nasid); } continue; /* go back for more! */ } @@ -1320,8 +1352,8 @@ } /* end of switch( STATE_GET(sc) ) */ } /* end of while(!done) */ - L1_CONS_HW_UNLOCK( sc ); - L1SC_RECV_UNLOCK(sc, pl); + if ( sc->uart == BRL1_LOCALUART ) + unlock_console(sc->nasid); return result; } @@ -1338,6 +1370,9 @@ brl1_sch_t *subch; bzero( sc, sizeof( *sc ) ); +#ifdef FORCE_CONSOLE_NASID + nasid = (nasid_t)0; +#endif sc->nasid = nasid; sc->uart = uart; sc->getc_f = (uart == BRL1_LOCALUART ? uart_getc : rtr_uart_getc); @@ -1351,9 +1386,9 @@ /* assign processor TTY channels */ for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = 0; - spinlock_init( &(subch->data_lock), NULL ); - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); + subch->packet_arrived = ATOMIC_INIT(0); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); subch->tx_notify = NULL; /* (for now, drop elscuart packets in the kernel) */ subch->rx_notify = brl1_discard_packet; @@ -1364,9 +1399,9 @@ * processor's individual TTY channel has been assigned) */ subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = 0; - spinlock_init( &(subch->data_lock), NULL ); - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); + subch->packet_arrived = ATOMIC_INIT(0); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); subch->tx_notify = NULL; if( sc->uart == BRL1_LOCALUART ) { subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, @@ -1387,7 +1422,7 @@ */ for( ; i < 0x10; i++, subch++ ) { subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = 0; + subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = brl1_discard_packet; subch->iqp = &sc->garbage_q; @@ -1396,7 +1431,7 @@ /* remaining subchannels are free */ for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = 0; + subch->packet_arrived = ATOMIC_INIT(0); subch->tx_notify = NULL; subch->rx_notify = brl1_discard_packet; subch->iqp = &sc->garbage_q; @@ -1404,9 +1439,7 @@ /* initialize synchronization structures */ - spinlock_init( &(sc->send_lock), NULL ); - spinlock_init( &(sc->recv_lock), NULL ); - spinlock_init( &(sc->subch_lock), NULL ); + spin_lock_init( &(sc->subch_lock) ); if( sc->uart == BRL1_LOCALUART ) { uart_init( sc, UART_BAUD_RATE ); @@ -1423,146 +1456,46 @@ extern int elsc_module_get(l1sc_t *); sc->modid = elsc_module_get( sc ); - sc->modid = - (sc->modid < 0 ? INVALID_MODULE : sc->modid); - + sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid); sc->verbose = 1; } } -/********************************************************************* - * These are interrupt-related functions used in the kernel to service - * the L1. - */ - -/* - * brl1_intrd is the function which is called in a loop by the - * xthread that services L1 interrupts. - */ -#ifdef IRIX -void -brl1_intrd( struct eframe_s *ep ) -{ - u_char isr_reg; - l1sc_t *sc = get_elsc(); - - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - - while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) { - - if( isr_reg & ISR_RxRDY ) { - brl1_receive(sc); - } - if( (isr_reg & ISR_TxRDY) || - (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) - { - brl1_send_cont(sc); - } - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - } - - /* uart interrupts were blocked at bedrock when the interrupt - * was initially answered; reenable them now - */ - intr_unblock_bit( sc->intr_cpu, UART_INTR ); - ep = ep; /* placate the compiler */ -} -#endif - - - -/* brl1_intr is called directly from the uart interrupt; after it runs, the - * interrupt "daemon" xthread is signalled to continue. - */ -#ifdef IRIX -void -brl1_intr( struct eframe_s *ep ) -{ - /* Disable the UART interrupt, giving the xthread time to respond. - * When the daemon (xthread) finishes doing its thing, it will - * unblock the interrupt. - */ - intr_block_bit( get_elsc()->intr_cpu, UART_INTR ); - ep = ep; /* placate the compiler */ -} - - -/* set up uart interrupt handling for this node's uart - */ -void -brl1_connect_intr( l1sc_t *sc ) -{ - cpuid_t last_cpu; - - sc->intr_cpu = nodepda->node_first_cpu; - - if( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, - (intr_func_t)brl1_intrd, 0, - (intr_func_t)brl1_intr) ) - cmn_err(CE_PANIC, "brl1_connect_intr: Can't connect UART interrupt."); - - uart_enable_recv_intr( sc ); -} -#endif /* IRIX */ - -#ifdef SABLE -/* this function is called periodically to generate fake interrupts - * and allow brl1_intrd to send/receive characters - */ -void -hubuart_service( void ) -{ - l1sc_t *sc = get_elsc(); - /* note that we'll lose error state by reading the lsr_reg. - * This is probably ok in the frictionless domain of sable. - */ - int lsr_reg; - nasid_t nasid = sc->nasid; - lsr_reg = READ_L1_UART_REG( nasid, REG_LSR ); - if( lsr_reg & (LSR_RCA | LSR_XSRE) ) { - REMOTE_HUB_PI_SEND_INTR(0, 0, UART_INTR); - } -} -#endif /* SABLE */ - - -/********************************************************************* - * The following function allows the kernel to "go around" the - * uninitialized l1sc structure to allow console output during - * early system startup. - */ - /* These are functions to use from serial_in/out when in protocol - * mode to send and receive uart control regs. + * mode to send and receive uart control regs. These are external + * interfaces into the protocol driver. */ void -brl1_send_control(int offset, int value) +l1_control_out(int offset, int value) { - nasid_t nasid = get_nasid(); + nasid_t nasid = 0; //(get_elsc())->nasid; WRITE_L1_UART_REG(nasid, offset, value); } int -brl1_get_control(int offset) +l1_control_in(int offset) { - nasid_t nasid = get_nasid(); + nasid_t nasid = 0; //(get_elsc())->nasid; return(READ_L1_UART_REG(nasid, offset)); } #define PUTCHAR(ch) \ { \ - while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE) ); \ + while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ + (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ } int -brl1_send_console_packet( char *str, int len ) +l1_serial_out( char *str, int len ) { int sent = len; char crc_char; unsigned short crc = INIT_CRC; - nasid_t nasid = get_nasid(); + nasid_t nasid = 0; //(get_elsc())->nasid; + + lock_console(nasid); PUTCHAR( BRL1_FLAG_CH ); PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); @@ -1598,9 +1531,18 @@ PUTCHAR( crc_char ); PUTCHAR( BRL1_FLAG_CH ); + unlock_console(nasid); return sent - len; } +int +l1_serial_in(void) +{ + static int l1_cons_getc( l1sc_t *sc ); + + return(l1_cons_getc(get_elsc())); +} + /********************************************************************* * l1_cons functions @@ -1612,7 +1554,7 @@ * */ -int +static int l1_cons_poll( l1sc_t *sc ) { /* in case this gets called before the l1sc_t structure for the module_t @@ -1623,13 +1565,13 @@ return 0; } - if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) { + if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { return 1; } brl1_receive( sc ); - if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) { + if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { return 1; } return 0; @@ -1638,13 +1580,11 @@ /* pull a character off of the system console queue (if one is available) */ -int +static int l1_cons_getc( l1sc_t *sc ) { int c; -#ifdef SPINLOCKS_WORK - int pl; -#endif + brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); sc_cq_t *q = subch->iqp; @@ -1652,16 +1592,16 @@ return 0; } - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); if( cq_empty( q ) ) { - subch->packet_arrived = 0; - SUBCH_DATA_UNLOCK( subch, pl ); + atomic_set(&subch->packet_arrived, 0); + SUBCH_DATA_UNLOCK( subch ); return 0; } cq_rem( q, c ); if( cq_empty( q ) ) - subch->packet_arrived = 0; - SUBCH_DATA_UNLOCK( subch, pl ); + atomic_set(&subch->packet_arrived, 0); + SUBCH_DATA_UNLOCK( subch ); return c; } @@ -1672,106 +1612,15 @@ void l1_cons_init( l1sc_t *sc ) { -#ifdef SPINLOCKS_WORK - int pl; -#endif brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - SUBCH_DATA_LOCK( subch, pl ); - subch->packet_arrived = 0; + SUBCH_DATA_LOCK( subch ); + atomic_set(&subch->packet_arrived, 0); cq_init( subch->iqp ); - SUBCH_DATA_UNLOCK( subch, pl ); -} - - -/* - * Write a message to the L1 on the system console subchannel. - * - * Danger: don't use a non-zero value for the wait parameter unless you're - * someone important (like a kernel error message). - */ -int -l1_cons_write( l1sc_t *sc, char *msg, int len, int wait ) -{ - return( brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ) ); -} - - -/* - * Read as many characters from the system console receive queue as are - * available there (up to avail bytes). - */ -int -l1_cons_read( l1sc_t *sc, char *buf, int avail ) -{ - int pl; - int before_wrap, after_wrap; - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - sc_cq_t *q = subch->iqp; - - if( !(subch->packet_arrived) ) - return 0; - - SUBCH_DATA_LOCK( subch, pl ); - if( q->opos > q->ipos ) { - before_wrap = BRL1_QSIZE - q->opos; - if( before_wrap >= avail ) { - before_wrap = avail; - after_wrap = 0; - } - else { - avail -= before_wrap; - after_wrap = q->ipos; - if( after_wrap > avail ) - after_wrap = avail; - } - } - else { - before_wrap = q->ipos - q->opos; - if( before_wrap > avail ) - before_wrap = avail; - after_wrap = 0; - } - - - BCOPY( q->buf + q->opos, buf, before_wrap ); - if( after_wrap ) - BCOPY( q->buf, buf + before_wrap, after_wrap ); - q->opos = ((q->opos + before_wrap + after_wrap) % BRL1_QSIZE); - - subch->packet_arrived = 0; - SUBCH_DATA_UNLOCK( subch, pl ); - - return( before_wrap + after_wrap ); -} - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when the send buffer - * has been emptied. - */ -void -l1_cons_tx_notif( l1sc_t *sc, brl1_notif_t func ) -{ - subch_set_tx_notify( sc, SC_CONS_SYSTEM, func ); -} - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when a packet has been - * received. - */ -void -l1_cons_rx_notif( l1sc_t *sc, brl1_notif_t func ) -{ - subch_set_rx_notify( sc, SC_CONS_SYSTEM, func ); + SUBCH_DATA_UNLOCK( subch ); } - - /********************************************************************* * The following functions and definitions implement the "message"- * style interface to the L1 system controller. @@ -1795,7 +1644,9 @@ sc_data_ready( l1sc_t *sc, int ch ) { brl1_sch_t *subch = &(sc->subch[ch]); + SUBCH_DATA_LOCK( subch ); sv_signal( &(subch->arrive_sv) ); + SUBCH_DATA_UNLOCK( subch ); } /* sc_open reserves a subchannel to send a request to the L1 (the @@ -1810,10 +1661,9 @@ * subchannel assignment. */ int ch; - int pl; brl1_sch_t *subch; - SUBCH_LOCK( sc, pl ); + SUBCH_LOCK( sc ); /* Look for a free subchannel. Subchannels 0-15 are reserved * for other purposes. @@ -1826,17 +1676,17 @@ if( ch == BRL1_NUM_SUBCHANS ) { /* there were no subchannels available! */ - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); return SC_NSUBCH; } subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); subch->target = target; - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); - spinlock_init( &(subch->data_lock), NULL ); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); subch->tx_notify = NULL; subch->rx_notify = sc_data_ready; subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, @@ -1854,27 +1704,28 @@ sc_close( l1sc_t *sc, int ch ) { brl1_sch_t *subch; - int pl; - SUBCH_LOCK( sc, pl ); + SUBCH_LOCK( sc ); subch = &(sc->subch[ch]); if( subch->use != BRL1_SUBCH_RSVD ) { /* we're trying to close a subchannel that's not open */ return SC_NOPEN; } - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); subch->use = BRL1_SUBCH_FREE; + SUBCH_DATA_LOCK( subch ); sv_broadcast( &(subch->arrive_sv) ); sv_destroy( &(subch->arrive_sv) ); - spinlock_destroy( &(subch->data_lock) ); + SUBCH_DATA_UNLOCK( subch ); + spin_lock_destroy( &(subch->data_lock) ); ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); kmem_free( subch->iqp, sizeof(sc_cq_t) ); subch->iqp = &sc->garbage_q; - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); return SC_SUCCESS; } @@ -2248,7 +2099,7 @@ else { q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1)); } - atomicAddInt( &(subch->packet_arrived), -1 ); + atomic_dec(&(subch->packet_arrived)); } @@ -2263,7 +2114,6 @@ int sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) { - int pl; /* lock cookie */ int is_msg = 0; brl1_sch_t *subch = &(sc->subch[ch]); @@ -2278,7 +2128,7 @@ /* kick the next lower layer and see if it pulls anything in */ brl1_receive( sc ); - is_msg = subch->packet_arrived; + is_msg = atomic_read(&subch->packet_arrived); } while( block && !is_msg && (rtc_time() < exp_time) ); @@ -2287,9 +2137,9 @@ return( SC_NMSG ); } - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return( SC_SUCCESS ); } @@ -2305,17 +2155,16 @@ int sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) { - int pl; /* lock cookie */ int is_msg = 0; brl1_sch_t *subch = &(sc->subch[ch]); do { - SUBCH_DATA_LOCK(subch, pl); - is_msg = subch->packet_arrived; + SUBCH_DATA_LOCK(subch); + is_msg = atomic_read(&subch->packet_arrived); if( !is_msg && block ) { /* wake me when you've got something */ subch->rx_notify = sc_data_ready; - sv_wait( &(subch->arrive_sv), 0, &(subch->data_lock), pl ); + sv_wait( &(subch->arrive_sv), 0, 0); if( subch->use == BRL1_SUBCH_FREE ) { /* oops-- somebody closed our subchannel while we were * sleeping! @@ -2329,12 +2178,12 @@ if( !is_msg ) { /* no message and we didn't care to wait for one */ - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return( SC_NMSG ); } subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return( SC_SUCCESS ); } @@ -2388,12 +2237,12 @@ } /* block on sc_recv_* */ -#ifdef notyet +#ifdef LATER if( sc->uart == BRL1_LOCALUART ) { return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) ); } else -#endif +#endif /* LATER */ { return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); } @@ -2438,12 +2287,12 @@ { brl1_sch_t *subch = &(sc->subch[ch]); - if( subch->packet_arrived ) + if( atomic_read(&subch->packet_arrived) ) return 1; brl1_receive( sc ); - if( subch->packet_arrived ) + if( atomic_read(&subch->packet_arrived) ) return 1; return 0; @@ -2461,6 +2310,9 @@ /* sc_dispatch_env_event handles events sent from the system control * network's environmental monitor tasks. */ + +#ifdef LINUX_KERNEL_THREADS + static void sc_dispatch_env_event( uint code, int argc, char *args, int maxlen ) { @@ -2512,18 +2364,16 @@ for( ; i < j && ((args[i] == 0xd) || (args[i] == 0xa)); i++ ); - - /* write the event to syslog */ -#ifdef IRIX - cmn_err_tag( ESPcode, CE_WARN, &(args[i]) ); -#endif } } +#endif /* LINUX_KERNEL_THREADS */ /* sc_event waits for events to arrive from the system controller, and * prints appropriate messages to the syslog. */ + +#ifdef LINUX_KERNEL_THREADS static void sc_event( l1sc_t *sc, int ch ) { @@ -2544,7 +2394,7 @@ */ result = sc_recv_intr( sc, ch, event, &event_len, 1 ); if( result != SC_SUCCESS ) { - cmn_err( CE_WARN, "Error receiving sysctl event on nasid %d\n", + PRINT_WARNING("Error receiving sysctl event on nasid %d\n", sc->nasid ); } else { @@ -2588,13 +2438,13 @@ } } +#endif /* LINUX_KERNEL_THREADS */ /* sc_listen sets up a service thread to listen for incoming events. */ void sc_listen( l1sc_t *sc ) { - int pl; int result; brl1_sch_t *subch; @@ -2602,24 +2452,26 @@ int len; /* length of message being sent */ int ch; /* system controller subchannel used */ +#ifdef LINUX_KERNEL_THREADS extern int msc_shutdown_pri; +#endif /* grab the designated "event subchannel" */ - SUBCH_LOCK( sc, pl ); + SUBCH_LOCK( sc ); subch = &(sc->subch[BRL1_EVENT_SUBCH]); if( subch->use != BRL1_SUBCH_FREE ) { - SUBCH_UNLOCK( sc, pl ); - cmn_err( CE_WARN, "sysctl event subchannel in use! " + SUBCH_UNLOCK( sc ); + PRINT_WARNING("sysctl event subchannel in use! " "Not monitoring sysctl events.\n" ); return; } subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); + SUBCH_UNLOCK( sc ); - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); subch->target = BRL1_LOCALUART; - sv_init( &(subch->arrive_sv), SV_FIFO, NULL ); - spinlock_init( &(subch->data_lock), NULL ); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); subch->tx_notify = NULL; subch->rx_notify = sc_data_ready; subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, @@ -2670,7 +2522,7 @@ err_return: /* there was a problem; complain */ - cmn_err( CE_WARN, "failed to set sysctl event-monitoring subchannel. " + PRINT_WARNING("failed to set sysctl event-monitoring subchannel. " "Sysctl events will not be monitored.\n" ); } @@ -2825,7 +2677,7 @@ int _elscuart_readc( l1sc_t *sc ) { - int c, pl; + int c; sc_cq_t *q; brl1_sch_t *subch; @@ -2833,32 +2685,32 @@ subch = &(sc->subch[ SC_CONS_SYSTEM ]); q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); if( !cq_empty( q ) ) { cq_rem( q, c ); if( cq_empty( q ) ) { - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); } - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return c; } - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); } subch = &(sc->subch[ L1_ELSCUART_SUBCH(get_myid()) ]); q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); + SUBCH_DATA_LOCK( subch ); if( cq_empty( q ) ) { - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return -1; } cq_rem( q, c ); if( cq_empty ( q ) ) { - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); } - SUBCH_DATA_UNLOCK( subch, pl ); + SUBCH_DATA_UNLOCK( subch ); return c; } @@ -2918,6 +2770,7 @@ #else char ver[BRL1_QSIZE]; extern int elsc_version( l1sc_t *, char * ); + if ( IS_RUNNING_ON_SIMULATOR() ) return 0; return( elsc_version(sc, ver) >= 0 ); @@ -2932,43 +2785,13 @@ void _elscuart_init( l1sc_t *sc ) { - int pl; brl1_sch_t *subch = &sc->subch[L1_ELSCUART_SUBCH(get_myid())]; - SUBCH_DATA_LOCK(subch, pl); + SUBCH_DATA_LOCK(subch); - subch->packet_arrived = 0; + atomic_set(&subch->packet_arrived, 0); cq_init( subch->iqp ); cq_init( &sc->oq[MAP_OQ(L1_ELSCUART_SUBCH(get_myid()))] ); - SUBCH_DATA_UNLOCK(subch, pl); -} - - -#ifdef IRIX - -/* elscuart_syscon_listen causes the processor on which it's - * invoked to "listen" to the system console subchannel (that - * is, subchannel 4) for console input. - */ -void -elscuart_syscon_listen( l1sc_t *sc ) -{ - int pl; - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - - /* if we're already listening, don't bother */ - if( sc->cons_listen ) - return; - - SUBCH_DATA_LOCK( subch, pl ); - - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = 0; - - SUBCH_DATA_UNLOCK( subch, pl ); - - - sc->cons_listen = 1; + SUBCH_DATA_UNLOCK(subch); } -#endif /* IRIX */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/l1_command.c linux.ac/arch/ia64/sn/io/l1_command.c --- linux.vanilla/arch/ia64/sn/io/l1_command.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/l1_command.c Tue Apr 10 18:09:55 2001 @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -68,7 +67,6 @@ #define SC_COMMAND sc_command - /* * elsc_init * @@ -206,6 +204,7 @@ return -1; } + /* * Command Set */ @@ -312,6 +311,7 @@ return 0; } + /* * elsc_rack_bay_get fills in the two int * arguments with the * rack number and bay number of the L1 being addressed @@ -447,8 +447,9 @@ /* construct module ID from rack and slot info */ - if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) + if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) { return ret; + } /* report unset location info. with a special, otherwise invalid modid */ if (rnum == 0 && bay == 0) @@ -935,6 +936,7 @@ return cbrick_uid_get( e->nasid, nic ); } + int _elsc_hbt(elsc_t *e, int ival, int rdly) { e = e; @@ -958,11 +960,12 @@ /* fill in msg with the opcode & params */ bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCAL ); - L1_BUILD_ADDR( &target, compt, rack, bay, L1_ADDR_TASK_CMD ); + L1_BUILD_ADDR( &target, compt, rack, bay, 0 ); + subch = sc_open( sc, target ); + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - target, L1_REQ_EXEC_CMD, 2, + L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2, L1_ARG_ASCII, cmd )) < 0 ) { sc_close( sc, subch ); @@ -970,7 +973,7 @@ } /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) < 0 ) + if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 ) { sc_close( sc, subch ); return( ELSC_ERROR_CMD_SEND ); @@ -988,6 +991,38 @@ return 0; } +/* + * sc_power_down + * + * Shuts down the c-brick associated with sc, and any attached I/O bricks + * or other c-bricks (won't go through r-bricks). + */ + +int sc_power_down(l1sc_t *sc) +{ + return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, + L1_ADDR_BAY_LOCAL, "* pwr d" ); +} + + +/* + * sc_power_down_all + * + * Works similarly to sc_power_down, except that the request is sent to the + * closest L2 and EVERYBODY gets turned off. + */ + +int sc_power_down_all(l1sc_t *sc) +{ + if( nodepda->num_routers > 0 ) { + return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, + L1_ADDR_BAY_LOCAL, "* pwr d" ); + } + else { + return sc_power_down( sc ); + } +} + /* * Routines for reading the R-brick's L1 @@ -1115,10 +1150,6 @@ if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0) return ret; - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) return ELSC_ERROR_MODULE; @@ -1203,28 +1234,101 @@ */ int -iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) +iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code ) { - char cmd[BRL1_QSIZE]; - unsigned rack, bay, brick_type; - if( iobrick_rack_bay_type_get( sc, &rack, &bay, &brick_type ) < 0 ) +#if 0 /* The "bedrock request" method of performing this function + * seems to be broken in the L1, so for now use the command- + * interpreter method + */ + + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int subch; /* system controller subchannel used */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( sc, L1_ADDR_LOCALIO ); + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + req_code, 4, + L1_ARG_INT, bus, + L1_ARG_INT, slot )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) + { + sc_close( sc, subch ); return( ELSC_ERROR_CMD_SEND ); - sprintf( cmd, "pci %d %d %s", bus, slot, - (up ? "u" : "d") ); - return( sc_command_interp - ( sc, L1_ADDR_TYPE_L1, rack, bay, cmd ) ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; + +#else + char cmd[64]; + char *fxn; + + switch( req_code ) + { + case L1_REQ_PCI_UP: + fxn = "u"; + break; + case L1_REQ_PCI_DOWN: + fxn = "d"; + break; + case L1_REQ_PCI_RESET: + fxn = "rst"; + break; + default: + return( ELSC_ERROR_CMD_ARGS ); + } + + if( slot == -1 ) + sprintf( cmd, "pci %d %s", bus, fxn ); + else + sprintf( cmd, "pci %d %d %s", bus, slot, fxn ); + + return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK, + L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd ); +#endif +} + +int +iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) +{ + return iobrick_pci_pwr( sc, bus, slot, up ); } int iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ) { - char cmd[BRL1_QSIZE]; - unsigned rack, bay, brick_type; - if( iobrick_rack_bay_type_get( sc, &rack, &bay, &brick_type ) < 0 ) - return( ELSC_ERROR_CMD_SEND ); - sprintf( cmd, "pci %d %s", bus, (up ? "u" : "d") ); - return( sc_command_interp - ( sc, L1_ADDR_TYPE_L1, rack, bay, cmd ) ); + return iobrick_pci_pwr( sc, bus, -1, up ); +} + + +int +iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot ) +{ + return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET ); +} + +int +iobrick_pci_bus_rst( l1sc_t *sc, int bus ) +{ + return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET ); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/labelcl.c linux.ac/arch/ia64/sn/io/labelcl.c --- linux.vanilla/arch/ia64/sn/io/labelcl.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/labelcl.c Tue Apr 10 18:09:55 2001 @@ -286,7 +286,7 @@ if (!strcmp(info_name, old_label_list[i].name)) { /* Not allowed to add duplicate labelled info names. */ kfree(new_label_list); - printk("labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de); + printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de); return(-1); } new_label_list[i] = old_label_list[i]; /* structure copy */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/mem_refcnt.c linux.ac/arch/ia64/sn/io/mem_refcnt.c --- linux.vanilla/arch/ia64/sn/io/mem_refcnt.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/mem_refcnt.c Sat Apr 14 01:18:00 2001 @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -58,15 +57,8 @@ mem_refcnt_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) { cnodeid_t node; -#ifndef CONFIG_IA64_SGI_SN1 - extern int numnodes; -#endif - - ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(*devp) == HUBSPC_REFCOUNTERS ); - if (!cap_able(CAP_MEMORY_MGT)) { - return (EPERM); - } + ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(*devp) == HUBSPC_REFCOUNTERS ); node = master_node_get(*devp); @@ -97,9 +89,6 @@ int errcode; char* buffer; size_t blen; -#ifndef CONFIG_IA64_SGI_SN1 - extern int numnodes; -#endif ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(dev) == HUBSPC_REFCOUNTERS ); @@ -186,7 +175,7 @@ rcb.rcb_cnodeid = node; rcb.rcb_granularity = MD_PAGE_SIZE; -#ifdef notyet +#ifdef LATER rcb.rcb_hw_counter_max = MIGR_COUNTER_MAX_GET(node); rcb.rcb_diff_threshold = MIGR_THRESHOLD_DIFF_GET(node); #endif @@ -209,7 +198,7 @@ ASSERT(nslots <= MAX_MEM_SLOTS); for (s = 0; s < nslots; s++) { slot[s].base = (uint64_t)ctob(slot_getbasepfn(node, s)); -#ifdef notyet +#ifdef LATER slot[s].size = (uint64_t)ctob(slot_getsize(node, s)); #else slot[s].size = (uint64_t)1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/ml_SN_init.c linux.ac/arch/ia64/sn/io/ml_SN_init.c --- linux.vanilla/arch/ia64/sn/io/ml_SN_init.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/ml_SN_init.c Tue Apr 10 18:09:55 2001 @@ -45,25 +45,8 @@ extern xwidgetnum_t hub_widget_id(nasid_t); -#ifndef CONFIG_IA64_SGI_IO -#if defined (IP27) -short cputype = CPU_IP27; -#elif defined (IP33) -short cputype = CPU_IP33; -#elif defined (IP35) -short cputype = CPU_IP35; -#else -#error -#endif -#endif /* CONFIG_IA64_SGI_IO */ - static int fine_mode = 0; -#ifndef CONFIG_IA64_SGI_IO -/* Global variables */ -pdaindr_t pdaindr[MAXCPUS]; -#endif - static cnodemask_t hub_init_mask; /* Mask of cpu in a node doing init */ static volatile cnodemask_t hub_init_done_mask; /* Node mask where we wait for @@ -101,7 +84,7 @@ master_nasid = get_nasid(); set_master_bridge_base(); FIXME("mlreset: Enable when we support ioc3 .."); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER if (get_console_nasid() == master_nasid) /* Set up the IOC3 */ ioc3_mlreset((ioc3_cfg_t *)KL_CONFIG_CH_CONS_INFO(master_nasid)->config_base, @@ -113,7 +96,7 @@ nvram_baseinit(); fine_mode = is_fine_dirmode(); -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* We're the master processor */ master_procid = smp_processor_id(); @@ -125,7 +108,7 @@ */ ASSERT_ALWAYS(master_nasid == get_nasid()); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Activate when calias is implemented. @@ -155,7 +138,7 @@ ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) | (0 << IIO_ITTE_WIDGET_SHIFT))); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* Set up the hub initialization mask and init the lock */ CNODEMASK_CLRALL(hub_init_mask); @@ -169,7 +152,7 @@ /* Initialize Hub Pseudodriver Management */ hubdev_init(); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Our IO system doesn't require cache writebacks. Set some * variables appropriately. @@ -192,7 +175,7 @@ * keep redundant PROM code in memory. */ he_arcs_set_vectors(); -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ } else { /* slave != 0 */ /* @@ -216,8 +199,10 @@ extern void router_map_init(nodepda_t *); extern void router_queue_init(nodepda_t *,cnodeid_t); + extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int); + #if defined(DEBUG) - extern lock_t intr_dev_targ_map_lock; + extern spinlock_t intr_dev_targ_map_lock; extern uint64_t intr_dev_targ_map_size; /* Initialize the lock to access the device - target cpu mapping @@ -229,7 +214,7 @@ * There is always a cnode 0 present. */ intr_dev_targ_map_size = 0; - init_spinlock(&intr_dev_targ_map_lock,"dtmap_lock",0); + spin_lock_init(&intr_dev_targ_map_lock); } #endif /* DEBUG */ /* Allocate per-node platform-dependent data */ @@ -241,8 +226,6 @@ hubinfo->h_cnodeid = node; hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node); - printk("init_platform_nodepda: hubinfo 0x%p, &hubinfo->h_crblock 0x%p\n", hubinfo, &hubinfo->h_crblock); - spin_lock_init(&hubinfo->h_crblock); hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); @@ -265,21 +248,18 @@ for (sn=0; snprof_count = 0; SNPDA(npda,sn)->next_prof_timeout = 0; -// ajm -#ifndef CONFIG_IA64_SGI_IO intr_init_vecblk(npda, node, sn); -#endif } npda->vector_unit_busy = 0; spin_lock_init(&npda->vector_lock); - init_MUTEX_LOCKED(&npda->xbow_sema); /* init it locked? */ + mutex_init_locked(&npda->xbow_sema); /* init it locked? */ spin_lock_init(&npda->fprom_lock); spin_lock_init(&npda->node_utlbswitchlock); npda->ni_error_print = 0; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER if (need_utlbmiss_patch) { npda->node_need_utlbmiss_patch = 1; npda->node_utlbmiss_patched = 1; @@ -299,7 +279,7 @@ npda->nasid_mask[nasid / 8] |= (1 << nasid % 8); } -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER npda->node_first_cpu = get_cnode_cpu(node); #endif @@ -324,7 +304,7 @@ * may not be guaranteed shared memory at that time * which precludes depending on a global dump stack */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER npda->dump_stack = (uint64_t *)kmem_zalloc_node(DUMP_STACK_SIZE,VM_NOSLEEP, node); ASSERT_ALWAYS(npda->dump_stack); @@ -334,7 +314,7 @@ * both the cpus on a node to proceed with nmi * handling. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER npda->dump_count = 0; /* Setup the (module,slot) --> nic mapping for all the routers @@ -356,7 +336,7 @@ npda->node_bte_info[i] = (bteinfo_t *)NULL; } #endif -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ } /* XXX - Move the interrupt stuff to intr.c ? */ @@ -369,13 +349,15 @@ void init_platform_pda(cpuid_t cpu) { hub_intmasks_t *intmasks; +#ifdef LATER cpuinfo_t cpuinfo; +#endif int i; cnodeid_t cnode; synergy_da_t *sda; int which_synergy; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* Allocate per-cpu platform-dependent data */ cpuinfo = (cpuinfo_t)kmem_alloc_node(sizeof(struct cpuinfo_s), GFP_ATOMIC, cputocnode(cpu)); ASSERT_ALWAYS(cpuinfo); @@ -390,7 +372,7 @@ // intmasks = &ppda->p_intmasks; intmasks = &sda->s_intmasks; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER ASSERT_ALWAYS(&ppda->p_nodepda); #endif @@ -400,15 +382,15 @@ /* Set up pointer to the vector block in the nodepda. */ /* (Cant use SUBNODEPDA - not working yet) */ - intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cputosubnode(cpu)].intr_dispatch0; - intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cputosubnode(cpu)].intr_dispatch1; + intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; + intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; /* Clear INT_PEND1 masks. */ for (i = 0; i < N_INTPEND1_MASKS; i++) intmasks->intpend1_masks[i] = 0; -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* Don't read the routers unless we're the master. */ ppda->p_routertick = 0; #endif @@ -419,7 +401,7 @@ #error "need protect_hub_calias, protect_nmi_handler_data" #endif -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * For now, just protect the first page (exception handlers). We * may want to protect more stuff later. @@ -433,13 +415,6 @@ for (i = 0; i < MAX_REGIONS; i++) { if (i == nasid_to_region(nasid)) continue; -#ifndef BRINGUP - /* Protect the exception handlers. */ - *(__psunsigned_t *)BDPRT_ENTRY(pa, i) = MD_PROT_NO; - - /* Protect the ARCS SPB. */ - *(__psunsigned_t *)BDPRT_ENTRY(pa + 4096, i) = MD_PROT_NO; -#endif } } @@ -455,15 +430,12 @@ for (i = 0; i < MAX_REGIONS; i++) { if (i == nasid_to_region(nasid)) continue; -#ifndef BRINGUP - *(__psunsigned_t *)BDPRT_ENTRY(pa, i) = MD_PROT_NO; -#endif } } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ -#ifdef IRIX +#ifdef LATER /* * Protect areas of memory that we access uncached by marking them as * poisoned so the T5 can't read them speculatively and erroneously @@ -492,7 +464,7 @@ CACHE_ERR_AREA_SIZE, 1); #error "SN1 not handled correctly" } -#endif /* IRIX */ +#endif /* LATER */ /* * per_hub_init @@ -509,15 +481,10 @@ ii_icmr_u_t ii_icmr; ii_ibcr_u_t ii_ibcr; #endif -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER int i; #endif -#ifdef SIMULATED_KLGRAPH - compact_to_nasid_node[0] = 0; - nasid_to_compact_node[0] = 0; - FIXME("per_hub_init: SIMULATED_KLCONFIG: compact_to_nasid_node[0] = 0\n"); -#endif /* SIMULATED_KLGRAPH */ nasid = COMPACT_TO_NASID_NODEID(cnode); ASSERT(nasid != INVALID_NASID); @@ -546,15 +513,26 @@ if (!done) { npdap = NODEPDA(cnode); +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + /* initialize per-node synergy perf instrumentation */ + npdap->synergy_perf_enabled = 0; /* off by default */ + npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; + npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; + npdap->synergy_inactive_intervals = 0; + npdap->synergy_active_intervals = 0; + npdap->synergy_perf_data = NULL; + npdap->synergy_perf_first = NULL; +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + npdap->hub_chip_rev = get_hub_chiprev(nasid); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER for (i = 0; i < CPUS_PER_NODE; i++) { cpu = cnode_slice_to_cpuid(cnode, i); if (!cpu_enabled(cpu)) SET_CPU_LEDS(nasid, i, 0xf); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* SN1 specific */ @@ -582,7 +560,6 @@ #endif /* SN0_HWDEBUG */ -#ifndef CONFIG_IA64_SGI_IO /* Reserve all of the hardwired interrupt levels. */ intr_reserve_hardwired(cnode); @@ -590,6 +567,7 @@ /* Initialize error interrupts for this hub. */ hub_error_init(cnode); +#ifdef LATER /* Set up correctable memory/directory ECC error interrupt. */ install_eccintr(cnode); @@ -599,7 +577,7 @@ /* Enable RT clock interrupts */ hub_rtc_init(cnode); hub_migrintr_init(cnode); /* Enable migration interrupt */ -#endif +#endif /* LATER */ spin_lock(&hub_mask_lock); CNODEMASK_SETB(hub_init_done_mask, cnode); @@ -609,9 +587,14 @@ /* * Wait for the other CPU to complete the initialization. */ - while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0) + while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0) { + /* + * On SNIA64 we should never get here .. + */ + printk("WARNING: per_hub_init: Should NEVER get here!\n"); /* LOOP */ ; + } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/ml_SN_intr.c linux.ac/arch/ia64/sn/io/ml_SN_intr.c --- linux.vanilla/arch/ia64/sn/io/ml_SN_intr.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/ml_SN_intr.c Sat Apr 14 01:18:00 2001 @@ -34,6 +34,8 @@ #include #include #include +#include + #if DEBUG_INTR_TSTAMP_DEBUG #include @@ -65,6 +67,8 @@ extern cnodeid_t master_node_get(devfs_handle_t vhdl); +extern snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); + #define INTR_LOCK(vecblk) \ (s = mutex_spinlock(&(vecblk)->vector_lock)) @@ -99,7 +103,7 @@ void intr_stray(void *lvl) { - printk("Stray Interrupt - level %ld to cpu %d", (long)lvl, cpuid()); + PRINT_WARNING("Stray Interrupt - level %ld to cpu %d", (long)lvl, cpuid()); } #if defined(DEBUG) @@ -119,7 +123,7 @@ intr_dev_targ_map_t intr_dev_targ_map[MAX_DEVICES]; uint64_t intr_dev_targ_map_size; -lock_t intr_dev_targ_map_lock; +spinlock_t intr_dev_targ_map_lock; /* Print out the device - target cpu mapping. * This routine is used only in the idbg command @@ -220,7 +224,7 @@ } - spinlock_init(&vecblk->vector_lock, "ivecb"); + mutex_spinlock_init(&vecblk->vector_lock); vecblk->vector_count = 0; for (i = 0; i < CPUS_PER_SUBNODE; i++) @@ -254,7 +258,7 @@ { intr_vecblk_t *vecblk; hub_intmasks_t *hub_intmasks; - int s; + unsigned long s; int rv = 0; int ip; synergy_da_t *sda; @@ -283,8 +287,7 @@ INTR_LOCK(vecblk); if (bit <= -1) { - // bit = 0; - bit = 7; /* First available on SNIA */ + bit = 0; ASSERT(reserve == II_RESERVE); /* Choose any available level */ for (; bit < N_INTPEND_BITS; bit++) { @@ -449,9 +452,9 @@ { intr_vecblk_t *vecblk; hubreg_t *intpend_masks; - int s; int rv = 0; int ip; + unsigned long s; ASSERT(bit < N_INTPEND_BITS * 2); @@ -530,7 +533,7 @@ { intr_vecblk_t *vecblk; hubreg_t *intpend_masks; - int s; + unsigned long s; int rv = 0; int ip; @@ -582,8 +585,8 @@ do_intr_block_bit(cpuid_t cpu, int bit, int block) { intr_vecblk_t *vecblk; - int s; int ip; + unsigned long s; hubreg_t *intpend_masks; volatile hubreg_t mask_value; volatile hubreg_t *mask_reg; @@ -671,7 +674,6 @@ int local_cpu_num; cpu = cnode_slice_to_cpuid(cnode, slice); - cpu = cpu_logical_id(cpu); if (cpu == CPU_NONE) continue; @@ -711,7 +713,7 @@ } -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Convert a subnode vertex into a (cnodeid, which_subnode) pair. * Return 0 on success, non-zero on failure. @@ -736,7 +738,7 @@ return(0); /* success */ } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* Make it easy to identify subnode vertices in the hwgraph */ void @@ -755,13 +757,14 @@ } -#ifndef CONFIG_IA64_SGI_IO /* * Given a device descriptor, extract interrupt target information and * choose an appropriate CPU. Return CPU_NONE if we can't make sense * out of the target information. * TBD: Should this be considered platform-independent code? */ + +#ifdef LATER static cpuid_t intr_target_from_desc(device_desc_t dev_desc, int favor_subnode) { @@ -799,10 +802,10 @@ cpuchosen: return(cpuid); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * Check if we had already visited this candidate cnode */ @@ -824,7 +827,7 @@ return(visited_cnodes); } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ @@ -915,7 +918,7 @@ { cpuid_t cpuid; /* possible intr targ*/ cnodeid_t candidate; /* possible canidate */ -#ifndef BRINGUP +#ifdef LATER cnodeid_t visited_cnodes[MAX_NASIDS], /* nodes seen so far */ center, /* node we are on */ candidate; /* possible canidate */ @@ -926,10 +929,10 @@ */ maxradius = physmem_maxradius(); void *rv; -#endif /* BRINGUP */ +#endif /* LATER */ int which_subnode = SUBNODE_ANY; -#if CONFIG_IA64_SGI_IO /* SN1 + pcibr Addressing Limitation */ +/* SN1 + pcibr Addressing Limitation */ { devfs_handle_t pconn_vhdl; pcibr_soft_t pcibr_soft; @@ -962,9 +965,8 @@ } } } -#endif /* CONFIG_IA64_SGI_IO */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* * If an interrupt target was specified for this * interrupt allocation, try to use it. @@ -998,7 +1000,7 @@ */ } -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* Check if we can find a valid interrupt target candidate on * the master node for the device. @@ -1019,7 +1021,7 @@ intr_unreserve_level(cpuid, *resp_bit); } - printk("Cannot target interrupts to closest node(%d): %ld (0x%lx)\n", + PRINT_WARNING("Cannot target interrupts to closest node(%d): %ld (0x%lx)\n", master_node_get(dev),(long) owner_dev, (unsigned long)owner_dev); /* Fall through into the default algorithm @@ -1076,10 +1078,11 @@ #else /* BRINGUP */ { // Do a stupid round-robin assignment of the node. - static cnodeid_t last_node = 0; + static cnodeid_t last_node = -1; - if (last_node > numnodes) last_node = 0; - for (candidate = last_node; candidate <= numnodes; candidate++) { + if (last_node >= numnodes) last_node = 0; + for (candidate = last_node + 1; candidate != last_node; candidate++) { + if (candidate == numnodes) candidate = 0; cpuid = intr_bit_reserve_test(CPU_NONE, which_subnode, candidate, @@ -1091,18 +1094,18 @@ if (cpuid != CPU_NONE) { if (cpu_on_subnode(cpuid, which_subnode)) { - last_node++; + last_node = candidate; return(cpuid); /* got a valid interrupt target */ } else intr_unreserve_level(cpuid, *resp_bit); } - last_node++; } + last_node = candidate; } #endif - printk("Cannot target interrupts to any close node: %ld (0x%lx)\n", + PRINT_WARNING("Cannot target interrupts to any close node: %ld (0x%lx)\n", (long)owner_dev, (unsigned long)owner_dev); /* In the worst case try to allocate interrupt bits on the @@ -1127,7 +1130,7 @@ intr_unreserve_level(cpuid, *resp_bit); } - printk("Cannot target interrupts: %ld (0x%lx)\n", + PRINT_WARNING("Cannot target interrupts: %ld (0x%lx)\n", (long)owner_dev, (unsigned long)owner_dev); return(CPU_NONE); /* Should never get here */ @@ -1515,6 +1518,7 @@ } } +#endif /* BRINGUP */ struct hardwired_intr_s { signed char level; @@ -1525,17 +1529,9 @@ { INT_PEND0_BASELVL + GFX_INTR_A, 0, "Gfx A" }, { INT_PEND0_BASELVL + GFX_INTR_B, 0, "Gfx B" }, { INT_PEND0_BASELVL + PG_MIG_INTR, II_THREADED, "Migration" }, -#if defined(SN1) && !defined(DIRECT_L1_CONSOLE) { INT_PEND0_BASELVL + UART_INTR, II_THREADED, "Bedrock/L1" }, -#else - { INT_PEND0_BASELVL + UART_INTR, 0, "Hub I2C" }, -#endif { INT_PEND0_BASELVL + CC_PEND_A, 0, "Crosscall A" }, { INT_PEND0_BASELVL + CC_PEND_B, 0, "Crosscall B" }, - { INT_PEND0_BASELVL + MSC_MESG_INTR, II_THREADED, "MSC Message" }, - { INT_PEND0_BASELVL + CPU_ACTION_A, 0, "CPU Action A" }, - { INT_PEND0_BASELVL + CPU_ACTION_B, 0, "CPU Action B" }, - { INT_PEND1_BASELVL + IO_ERROR_INTR, II_ERRORINT, "IO Error" }, { INT_PEND1_BASELVL + CLK_ERR_INTR, II_ERRORINT, "Clock Error" }, { INT_PEND1_BASELVL + COR_ERR_INTR_A, II_ERRORINT, "Correctable Error A" }, { INT_PEND1_BASELVL + COR_ERR_INTR_B, II_ERRORINT, "Correctable Error B" }, @@ -1546,13 +1542,11 @@ { INT_PEND1_BASELVL + MSC_PANIC_INTR, II_ERRORINT, "MSC Panic" }, { INT_PEND1_BASELVL + LLP_PFAIL_INTR_A, II_ERRORINT, "LLP Pfail WAR" }, { INT_PEND1_BASELVL + LLP_PFAIL_INTR_B, II_ERRORINT, "LLP Pfail WAR" }, -#ifdef SN1 { INT_PEND1_BASELVL + NACK_INT_A, 0, "CPU A Nack count == NACK_CMP" }, { INT_PEND1_BASELVL + NACK_INT_B, 0, "CPU B Nack count == NACK_CMP" }, { INT_PEND1_BASELVL + LB_ERROR, 0, "Local Block Error" }, { INT_PEND1_BASELVL + XB_ERROR, 0, "Local XBar Error" }, -#endif /* SN1 */ - { -1, 0, (char *)NULL} + { -1, 0, (char *)NULL}, }; /* @@ -1567,7 +1561,13 @@ int i; char subnode_done[NUM_SUBNODES]; - cpu = cnodetocpu(cnode); + // cpu = cnodetocpu(cnode); + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (cpuid_to_cnodeid(cpu) == cnode) { + break; + } + } + if (cpu == smp_num_cpus) cpu = CPU_NONE; if (cpu == CPU_NONE) { printk("Node %d has no CPUs", cnode); return; @@ -1576,7 +1576,7 @@ for (i=0; ixswitch_volunteer_mutex); + mutex_init(&xvolinfo->xswitch_volunteer_mutex); xvolinfo->xswitch_volunteer_count = 0; rc = hwgraph_info_add_LBL(xswitch, INFO_LBL_XSWITCH_VOL, @@ -78,7 +85,7 @@ rc = hwgraph_info_remove_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER ASSERT(rc == GRAPH_SUCCESS); rc = rc; #endif @@ -97,64 +104,26 @@ INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { -#ifndef CONFIG_IA64_SGI_IO - if (!is_headless_node_vertex(master)) - cmn_err(CE_WARN, - "volunteer for widgets: vertex %v has no info label", +#ifdef LATER + if (!is_headless_node_vertex(master)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("volunteer for widgets: vertex %v has no info label", + xswitch); +#else + PRINT_WARNING("volunteer for widgets: vertex 0x%x has no info label", xswitch); #endif + } +#endif /* LATER */ return; } -#ifndef CONFIG_IA64_SGI_IO - mutex_lock(&xvolinfo->xswitch_volunteer_mutex, PZERO); -#endif + mutex_lock(&xvolinfo->xswitch_volunteer_mutex); ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; xvolinfo->xswitch_volunteer_count++; -#ifndef CONFIG_IA64_SGI_IO mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); -#endif -} - -#ifndef BRINGUP -/* - * The "ideal fixed assignment" of 12 IO slots to 4 node slots. - * At index N is the node slot number of the node board that should - * ideally control the widget in IO slot N. Note that if there is - * only one node board on a given xbow, it will control all of the - * devices on that xbow regardless of these defaults. - * - * N1 controls IO slots IO1, IO3, IO5 (upper left) - * N3 controls IO slots IO2, IO4, IO6 (upper right) - * N2 controls IO slots IO7, IO9, IO11 (lower left) - * N4 controls IO slots IO8, IO10, IO12 (lower right) - * - * This makes assignments predictable and easily controllable. - * TBD: Allow administrator to override these defaults. - */ -static slotid_t ideal_assignment[] = { - -1, /* IO0 -->non-existent */ - 1, /* IO1 -->N1 */ - 3, /* IO2 -->N3 */ - 1, /* IO3 -->N1 */ - 3, /* IO4 -->N3 */ - 1, /* IO5 -->N1 */ - 3, /* IO6 -->N3 */ - 2, /* IO7 -->N2 */ - 4, /* IO8 -->N4 */ - 2, /* IO9 -->N2 */ - 4, /* IO10-->N4 */ - 2, /* IO11-->N2 */ - 4 /* IO12-->N4 */ -}; - -static int -is_ideal_assignment(slotid_t hubslot, slotid_t ioslot) -{ - return(ideal_assignment[ioslot] == hubslot); } -#endif /* ifndef BRINGUP */ extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); @@ -166,15 +135,12 @@ static void assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) { + int curr_volunteer, num_volunteer; + xwidgetnum_t widgetnum; xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; - xwidgetnum_t widgetnum; - int curr_volunteer, num_volunteer; nasid_t nasid; hubinfo_t hubinfo; -#ifndef BRINGUP - int xbownum; -#endif hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; @@ -186,13 +152,19 @@ INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { -#ifndef CONFIG_IA64_SGI_IO - if (!is_headless_node_vertex(hubv)) - cmn_err(CE_WARN, - "assign_widgets_to_volunteers:vertex %v has " +#ifdef LATER + if (!is_headless_node_vertex(hubv)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("assign_widgets_to_volunteers:vertex %v has " + " no info label", + xswitch); +#else + PRINT_WARNING("assign_widgets_to_volunteers:vertex 0x%x has " " no info label", xswitch); #endif + } +#endif /* LATER */ return; } @@ -206,10 +178,6 @@ xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); } -#ifndef BRINGUP - xbownum = get_node_crossbow(nasid); -#endif /* ifndef BRINGUP */ - /* * TBD: Use administrative information to alter assignment of * widgets to hubs. @@ -239,29 +207,12 @@ if (nasid == get_console_nasid()) goto do_assignment; } -#ifndef CONFIG_IA64_SGI_IO - cmn_err(CE_PANIC, - "Nasid == %d, console nasid == %d", +#ifdef LATER + PRINT_PANIC("Nasid == %d, console nasid == %d", nasid, get_console_nasid()); #endif } -#ifndef BRINGUP - /* - * Try to do the "ideal" assignment if IO slots to nodes. - */ - for (i=0; ixswitch_volunteer[i]; - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - if (is_ideal_assignment(SLOTNUM_GETSLOT(get_node_slotid(nasid)), - SLOTNUM_GETSLOT(get_widget_slotnum(xbownum, widgetnum)))) { - - goto do_assignment; - - } - } -#endif /* ifndef BRINGUP */ /* * Do a round-robin assignment among the volunteer nodes. @@ -301,13 +252,13 @@ for(cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); board = (lboard_t *)KL_CONFIG_INFO(nasid); - printk("iograph_early_init: Found board 0x%p\n", board); + DBG("iograph_early_init: Found board 0x%p\n", board); /* Check out all the board info stored on a node */ while(board) { board->brd_graph_link = GRAPH_VERTEX_NONE; board = KLCF_NEXT(board); - printk("iograph_early_init: Found board 0x%p\n", board); + DBG("iograph_early_init: Found board 0x%p\n", board); } @@ -316,7 +267,7 @@ hubio_init(); } -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* There is an identical definition of this in os/scheduler/runq.c */ #define INIT_COOKIE(cookie) cookie.must_run = 0; cookie.cpu = PDA_RUNANYWHERE /* @@ -363,12 +314,11 @@ { restoremustrun(cookie); } -static sema_t io_init_sema; - -#endif /* !CONFIG_IA64_SGI_IO */ - -struct semaphore io_init_sema; +#endif /* LATER */ +#ifdef LINUX_KERNEL_THREADS +static struct semaphore io_init_sema; +#endif /* * Let boot processor know that we're done initializing our node's IO @@ -378,9 +328,11 @@ static void io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) { -#ifndef CONFIG_IA64_SGI_IO /* Let boot processor know that we're done. */ +#ifdef LINUX_KERNEL_THREADS up(&io_init_sema); +#endif +#ifdef LATER /* This is for the setnoderun done when the io_init thread * started */ @@ -420,17 +372,12 @@ * We're able to read from a widget because our hub's * WIDGET_ID was set up earlier. */ -#ifdef BRINGUP widgetreg_t widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); - printk("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, + DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); -#else /* !BRINGUP */ - widgetreg_t widget_id = XWIDGET_ID_READ(nasid, 0); -#endif /* BRINGUP */ - hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); @@ -438,8 +385,6 @@ /* TBD: link reset */ } else { - panic("\n\n**** early_probe_for_widget: Hub Vertex 0x%p is DOWN llp_csr_reg 0x%x ****\n\n", hubv, llp_csr_reg); - hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; @@ -499,8 +444,9 @@ moduleid_t module; slotid_t slot; lboard_t *board = NULL; + char buffer[16]; - printk("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); + DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); /* * Verify that xswitchv is indeed an attached xswitch. */ @@ -546,8 +492,8 @@ * but I don't feel like figuring out vhdl right now.. * and I know for a fact the answer is 0x2d000049 */ - printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - printk("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); + DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { #else if (nasid_has_xbridge(nasid)) { @@ -557,8 +503,18 @@ module, KLTYPE_IOBRICK); - if (board) - printk("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); +DBG("io_xswitch_widget_init: Board 0x%p\n", board); +{ + lboard_t dummy; + + if (board) { + DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); + } else { + DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); + board = &dummy; + } + +} /* * BRINGUP @@ -568,11 +524,16 @@ #ifdef SUPPORT_PRINTING_M_FORMAT sprintf(pathname, EDGE_LBL_MODULE "/%M/" -#else - sprintf(pathname, EDGE_LBL_MODULE "/%x/" -#endif "%cbrick" "/%s/%d", NODEPDA(cnode)->module_id, + +#else + memset(buffer, 0, 16); + format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); + sprintf(pathname, EDGE_LBL_MODULE "/%s/" + "%cbrick" "/%s/%d", + buffer, +#endif #ifdef BRINGUP (board->brd_type == KLTYPE_IBRICK) ? 'I' : @@ -584,7 +545,7 @@ EDGE_LBL_XTALK, widgetnum); } - printk("io_xswitch_widget_init: path= %s\n", pathname); + DBG("io_xswitch_widget_init: path= %s\n", pathname); rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); ASSERT(rc == GRAPH_SUCCESS); @@ -612,7 +573,7 @@ module = NODEPDA(cnode)->module_id; #ifdef XBRIDGE_REGS_SIM - printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { #else if (nasid_has_xbridge(nasid)) { @@ -647,16 +608,21 @@ */ #ifdef SUPPORT_PRINTING_M_FORMAT sprintf(pathname, EDGE_LBL_MODULE "/%M/" + EDGE_LBL_SLOT "/%s/%s", + NODEPDA(cnode)->module_id, + slotname, new_name); #else - sprintf(pathname, EDGE_LBL_MODULE "/%x/" -#endif + memset(buffer, 0, 16); + format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); + sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLOT "/%s/%s", - NODEPDA(cnode)->module_id, + buffer, slotname, new_name); +#endif } rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - printk("io_xswitch_widget_init: (2) path= %s\n", pathname); + DBG("io_xswitch_widget_init: (2) path= %s\n", pathname); /* * This is a weird ass code needed for error injection * purposes. @@ -666,7 +632,7 @@ klhwg_baseio_inventory_add(widgetv,cnode); } sprintf(name, "%d", widgetnum); - printk("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); + DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); rc = hwgraph_edge_add(xswitchv, widgetv, name); /* @@ -683,7 +649,7 @@ */ #ifdef XBRIDGE_REGS_SIM widget_id = 0x2d000049; - printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); #else widget_id = XWIDGET_ID_READ(nasid, widgetnum); #endif /* XBRIDGE_REGS_SIM */ @@ -715,21 +681,13 @@ aa = async_attach_new(); - printk("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); + DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { -#ifdef BRINGUP - if (widgetnum != 0xe) - io_xswitch_widget_init(xswitchv, - cnodeid_to_vertex(cnode), - widgetnum, aa); - -#else io_xswitch_widget_init(xswitchv, cnodeid_to_vertex(cnode), widgetnum, aa); -#endif /* BRINGUP */ } /* * Wait for parallel attach threads, if any, to complete. @@ -798,9 +756,12 @@ #endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ } if (board == NULL) { -#ifndef CONFIG_IA64_SGI_IO - cmn_err(CE_WARN, - "Could not find PROM info for vertex %v, " +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("Could not find PROM info for vertex %v, " + "FRU analyzer may fail", + vhdl); +#else + PRINT_WARNING("Could not find PROM info for vertex 0x%x, " "FRU analyzer may fail", vhdl); #endif @@ -828,16 +789,13 @@ hubinfo_t hubinfo; int is_xswitch; nodepda_t *npdap; -#ifndef CONFIG_IA64_SGI_IO - sema_t *peer_sema = 0; -#else struct semaphore *peer_sema = 0; -#endif uint32_t widget_partnum; nodepda_router_info_t *npda_rip; cpu_cookie_t c = 0; + extern int hubdev_docallouts(devfs_handle_t); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* Try to execute on the node that we're initializing. */ c = setnoderun(cnodeid); #endif @@ -851,13 +809,11 @@ * form /hw/module/%M/slot/%d/node */ hubv = cnodeid_to_vertex(cnodeid); - printk("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); + DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); ASSERT(hubv != GRAPH_VERTEX_NONE); -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC hubdev_docallouts(hubv); -#endif /* * Set up the dependent routers if we have any. @@ -877,10 +833,10 @@ /* * Read mfg info on this hub */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n"); HUB_VERTEX_MFG_INFO(hubv); -#endif /* CONFIG_IA64_SGI_IO */ +#endif /* LATER */ /* * If nothing connected to this hub's xtalk port, we're done. @@ -892,7 +848,7 @@ int index; for (index = 0; index < 600; index++) - printk("Interfering with device probing!!!\n"); + DBG("Interfering with device probing!!!\n"); } #endif /* io_init_done takes cpu cookie as 2nd argument @@ -900,8 +856,8 @@ * at the start of this thread */ - printk("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); - io_init_done(cnodeid,c); + DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); + return; /* NOTREACHED */ } @@ -931,13 +887,13 @@ (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); - printk("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); + DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); ASSERT(switchv != GRAPH_VERTEX_NONE); (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); - printk("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); + DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); /* * We need to find the widget id and update the basew_id field @@ -951,7 +907,7 @@ widget_partnum == XBRIDGE_WIDGET_PART_NUM){ npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - printk("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); + DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); } else if (widget_partnum == XBOW_WIDGET_PART_NUM || widget_partnum == XXBOW_WIDGET_PART_NUM) { @@ -959,7 +915,7 @@ * Xbow control register does not have the widget ID field. * So, hard code the widget ID to be zero. */ - printk("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); + DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); npdap->basew_id = 0; #if defined(BRINGUP) @@ -982,7 +938,7 @@ char widname[10]; sprintf(widname, "%x", npdap->basew_id); (void)hwgraph_path_add(switchv, widname, &widgetv); - printk("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); + DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); ASSERT(widgetv != GRAPH_VERTEX_NONE); } @@ -1043,13 +999,13 @@ /* Signal that we're done */ if (peer_sema) { - up(peer_sema); + mutex_unlock(peer_sema); } } else { /* Wait 'til master is done assigning widgets. */ - down(&npdap->xbow_sema); + mutex_lock(&npdap->xbow_sema); } #ifdef PROBE_TEST @@ -1057,7 +1013,7 @@ int index; for (index = 0; index < 500; index++) - printk("Interfering with device probing!!!\n"); + DBG("Interfering with device probing!!!\n"); } #endif /* Now both nodes can safely inititialize widgets */ @@ -1070,15 +1026,12 @@ */ io_init_done(cnodeid,c); - printk("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); + DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); } #define IOINIT_STKSZ (16 * 1024) -#ifndef CONFIG_IA64_SGI_IO -#include -#endif #define __DEVSTR1 "/../.master/" #define __DEVSTR2 "/target/" #define __DEVSTR3 "/lun/0/disk/partition/" @@ -1145,6 +1098,7 @@ {"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2}, {"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3}, {"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4}, + {"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5}, {NULL, -1} /* must be last */ }; @@ -1181,11 +1135,7 @@ } -#ifndef CONFIG_IA64_SGI_IO -#include -#else #include -#endif extern devfs_handle_t ioc3_console_vhdl_get(void); devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; @@ -1203,7 +1153,7 @@ int slot; devfs_handle_t baseio_console_conn; - printk("sys_critical_graph_init: FIXME.\n"); + DBG("sys_critical_graph_init: FIXME.\n"); baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); if (baseio_console_conn == NULL) { @@ -1303,7 +1253,7 @@ devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; - printk("baseio_ctlr_num_set; FIXME\n"); + DBG("baseio_ctlr_num_set; FIXME\n"); console_vhdl = ioc3_console_vhdl_get(); if (console_vhdl == GRAPH_VERTEX_NONE) return; @@ -1384,10 +1334,8 @@ else { rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0); } -#ifndef CONFIG_IA64_SGI_IO if (rtn_val) - cmn_err(CE_WARN, "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); -#endif + PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) { @@ -1406,10 +1354,8 @@ /* nothing in slot 5 or 7 */ rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0); } -#ifndef CONFIG_IA64_SGI_IO if (rtn_val) - cmn_err(CE_WARN, "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); -#endif + PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); } @@ -1423,17 +1369,18 @@ /* Governor on init threads..bump up when safe * (beware many devfs races) */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER int io_init_node_threads = 2; #endif cnodeid_t cnodeid, active; - init_MUTEX(&io_init_sema); - +#ifdef LINUX_KERNEL_THREADS + sema_init(&io_init_sema, 0); +#endif active = 0; for (cnodeid = 0; cnodeid < maxnodes; cnodeid++) { -#ifndef CONFIG_IA64_SGI_IO +#ifdef LINUX_KERNEL_THREADS char thread_name[16]; extern int io_init_pri; @@ -1448,20 +1395,17 @@ io_init_pri, KT_PS, (st_func_t *)io_init_node, (void *)(long)cnodeid, 0, 0, 0); #else - printk("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); + DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); io_init_node(cnodeid); - printk("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); - -#endif /* !CONFIG_IA64_SGI_IO */ + DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); +#endif /* LINUX_KERNEL_THREADS */ +#ifdef LINUX_KERNEL_THREADS /* Limit how many nodes go at once, to not overload hwgraph */ /* TBD: Should timeout */ -#ifdef AA_DEBUG - printk("started thread for cnode %d\n", cnodeid); -#endif -#ifdef LINUX_KERNEL_THREADS + DBG("started thread for cnode %d\n", cnodeid); active++; if (io_init_node_threads && active >= io_init_node_threads) { @@ -1476,9 +1420,9 @@ while (active > 0) { #ifdef AA_DEBUG - printk("waiting, %d still active\n", active); + DBG("waiting, %d still active\n", active); #endif - sema(&io_init_sema); + down(&io_init_sema); active--; } @@ -1534,22 +1478,22 @@ int i; int viable_found = 0; - printk("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); - printk("prom \"root\" variables of the form dksXdXsX.\n"); - printk("To use another disk you must use the full hardware graph path\n\n"); - printk("Possible controller numbers for use in 'dksXdXsX' on this system: "); + DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); + DBG("prom \"root\" variables of the form dksXdXsX.\n"); + DBG("To use another disk you must use the full hardware graph path\n\n"); + DBG("Possible controller numbers for use in 'dksXdXsX' on this system: "); for (i=0; i XBOW_PORT_F) + return 0; + + /* Find "brick" in the path name */ + bp = strstr(hw_path_name, "brick"); + if (bp == NULL) + return 0; + + /* Find preceding slash */ + sp = bp; + while (sp > hw_path_name) { + sp--; + if (*sp == '/') + break; + } + + /* Invalid if no preceding slash */ + if (!sp) + return 0; + + /* Bump slash pointer to "brick" prefix */ + sp++; + /* + * Verify "brick" prefix length; valid exaples: + * 'I' from "/Ibrick" + * 'P' from "/Pbrick" + * 'X' from "/Xbrick" + */ + if ((bp - sp) != 1) + return 0; + + return (io_brick_map_widget(*sp, widget_num)); + } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/module.c linux.ac/arch/ia64/sn/io/module.c --- linux.vanilla/arch/ia64/sn/io/module.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/module.c Sat Apr 14 01:18:00 2001 @@ -9,13 +9,11 @@ */ #include -#include #include #include #include #include #include -#include #include #include #include @@ -24,12 +22,17 @@ #include #include #include +#include -#define LDEBUG 1 +/* #define LDEBUG 1 */ -#define DPRINTF if (LDEBUG) printk +#ifdef LDEBUG +#define DPRINTF printk #define printf printk +#else +#define DPRINTF(x...) +#endif module_t *modules[MODULE_MAX]; int nummodules; @@ -100,8 +103,6 @@ { int i; - DPRINTF("module_lookup: id=%d\n", id); - for (i = 0; i < nummodules; i++) if (modules[i]->id == id) { DPRINTF("module_lookup: found m=0x%p\n", modules[i]); @@ -125,29 +126,29 @@ { module_t *m; int i; + char buffer[16]; - DPRINTF("module_add_node: id=%x node=%d\n", id, n); +#ifdef __ia64 + memset(buffer, 0, 16); + format_module_id(buffer, id, MODULE_FORMAT_BRIEF); + DPRINTF("module_add_node: id=%s node=%d\n", buffer, n); +#endif if ((m = module_lookup(id)) == 0) { -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n); #else m = kmalloc(sizeof (module_t), GFP_KERNEL); memset(m, 0 , sizeof(module_t)); - printk("Module nodecnt = %d\n", m->nodecnt); #endif ASSERT_ALWAYS(m); - DPRINTF("module_add_node: m=0x%p\n", m); - m->id = id; spin_lock_init(&m->lock); - init_MUTEX_LOCKED(&m->thdcnt); + mutex_init_locked(&m->thdcnt); -printk("Set elsc to 0x%p on node %d\n", &m->elsc, get_nasid()); - -set_elsc(&m->elsc); +// set_elsc(&m->elsc); elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n)); spin_lock_init(&m->elsclock); @@ -162,8 +163,7 @@ m->nodes[m->nodecnt++] = n; -printk("module_add_node: module %x now has %d nodes\n", id, m->nodecnt); - DPRINTF("module_add_node: module %x now has %d nodes\n", id, m->nodecnt); + DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); return m; } @@ -172,6 +172,7 @@ { lboard_t *board; klmod_serial_num_t *comp; + char * bcopy(const char * src, char * dest, int count); board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8); @@ -204,14 +205,8 @@ if (m->snum_valid) return 1; else { -#ifndef CONFIG_IA64_SGI_IO - cmn_err(CE_WARN | CE_MAINTENANCE, - "Invalid serial number for module %d, " - "possible missing or invalid NIC.", m->id); -#else - printk("Invalid serial number for module %d, " + DPRINTF("Invalid serial number for module %d, " "possible missing or invalid NIC.", m->id); -#endif return 0; } } @@ -246,32 +241,12 @@ nserial); if (nserial == 0) - cmn_err(CE_WARN, "No serial number found."); + PRINT_WARNING("io_module_init: No serial number found.\n"); } -#ifdef BRINGUP -elsc_t *Elsc[100]; - -void -set_elsc(elsc_t *p) -{ - Elsc[get_nasid()] = p; -} -#endif - elsc_t *get_elsc(void) { -#ifdef BRINGUP -return(Elsc[get_nasid()]); -#else - if ( NODEPDA(get_nasid())->module == (module_t *)0 ) { - printf("get_elsc() for nasd %d fails\n", get_nasid()); -// return((elsc_t *)0); - } - return &NODEPDA(get_nasid())->module->elsc; - -// return &NODEPDA(NASID_TO_COMPACT_NODEID(0))->module->elsc; -#endif + return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc; } int diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pci.c linux.ac/arch/ia64/sn/io/pci.c --- linux.vanilla/arch/ia64/sn/io/pci.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/pci.c Tue Apr 10 18:09:55 2001 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -250,18 +249,9 @@ pci_fixup_ioc3(struct pci_dev *d) { int i; - int slot; - unsigned long res = 0; - unsigned int val, size; - int ret; - u_short command; + unsigned int size; - devfs_handle_t device_vertex; devfs_handle_t bridge_vhdl = pci_bus_to_vertex(d->bus->number); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t devreg; /* IOC3 only decodes 0x20 bytes of the config space, reading * beyond that is relatively benign but writing beyond that @@ -271,7 +261,7 @@ * currently we hack this with special code in * sgi_pci_intr_support() */ - printk("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); + DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); /* I happen to know from the spec that the ioc3 needs only 0xfffff * The standard pci trick of writing ~0 to the baddr and seeing @@ -296,7 +286,9 @@ * DEV_DIRECT bit. This will not work if IOC3 is not on Slot * 4. */ - *(volatile u32 *)0xc0000a000f000220 |= 0x90000; + DBG("pci_fixup_ioc3: FIXME .. need to take NASID into account when setting IOC3 devreg 0x%x\n", *(volatile u32 *)0xc0000a000f000220); + + *(volatile u32 *)0xc0000a000f000220 |= 0x90000; d->subsystem_vendor = 0; d->subsystem_device = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pci_bus_cvlink.c linux.ac/arch/ia64/sn/io/pci_bus_cvlink.c --- linux.vanilla/arch/ia64/sn/io/pci_bus_cvlink.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/pci_bus_cvlink.c Sat Apr 14 01:18:00 2001 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -32,23 +31,32 @@ #include #include #include -#include #include // #include #include #include extern int bridge_rev_b_data_check_disable; +#include #define MAX_PCI_XWIDGET 256 -devfs_handle_t busnum_to_xwidget[MAX_PCI_XWIDGET]; +devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; +void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; unsigned char num_bridges; static int done_probing = 0; static int pci_bus_map_create(devfs_handle_t xtalk); devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); +#define SN1_IOPORTS_UNIT 256 +#define MAX_IOPORTS 0xffff +#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN1_IOPORTS_UNIT) +struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS]; +unsigned long sn1_allocate_ioports(unsigned long pci_address); + + + /* * pci_bus_cvlink_init() - To be called once during initialization before * SGI IO Infrastructure init is called. @@ -56,9 +64,13 @@ void pci_bus_cvlink_init(void) { - - memset(busnum_to_xwidget, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); + memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); + + memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); + + memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs)); + num_bridges = 0; } @@ -70,27 +82,13 @@ pci_bus_to_vertex(unsigned char busnum) { - devfs_handle_t xwidget; devfs_handle_t pci_bus = NULL; /* * First get the xwidget vertex. */ - xwidget = busnum_to_xwidget[busnum]; - if (!xwidget) - return (NULL); - - /* - * Use devfs to get the pci vertex from xwidget. - */ - if (hwgraph_traverse(xwidget, EDGE_LBL_PCI, &pci_bus) != GRAPH_SUCCESS) { - if (!pci_bus) { - printk("pci_bus_to_vertex: Cannot find pci bus for given bus number %d\n", busnum); - return (NULL); - } - } - + pci_bus = busnum_to_pcibr_vhdl[busnum]; return(pci_bus); } @@ -138,7 +136,6 @@ if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { if (!device_vertex) { - printk("devfn_to_vertex: Unable to get slot&func %s from pci vertex 0x%p\n", name, pci_bus); return(NULL); } } @@ -175,6 +172,61 @@ } /* + * sn1_allocate_ioports() - This routine provides the allocation and + * mappings between Linux style IOPORTs management. + * + * For simplicity sake, SN1 will allocate IOPORTs in chunks of + * 256bytes .. irrespective of what the card desires. This may + * have to change when we understand how to deal with legacy ioports + * which are hardcoded in some drivers e.g. SVGA. + * + * Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers. + * It will remain so. The IO Infrastructure will continue to map + * IO Resource just like IRIX. When this is done, we map IOPORT + * chunks to these resources. The Linux drivers will see and use real + * IOPORT numbers. The various IOPORT access macros e.g. inb/outb etc. + * does the munging of these IOPORT numbers to make a Uncache Virtual + * Address. This address via the tlb entries generates the PCI Address + * allocated by the SN1 IO Infrastructure Layer. + */ +static unsigned long sn1_ioport_num = 0x100; /* Reserve room for Legacy stuff */ +unsigned long +sn1_allocate_ioports(unsigned long pci_address) +{ + + unsigned long ioport_index; + + /* + * Just some idiot checking .. + */ + if ( sn1_ioport_num > 0xffff ) { + printk("sn1_allocate_ioports: No more IO PORTS available\n"); + return(-1); + } + + /* + * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's + * Manual for details. + */ + ioport_index = sn1_ioport_num / SN1_IOPORTS_UNIT; + ioports_to_tlbs[ioport_index].ppn = pci_address; + ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */ + ioports_to_tlbs[ioport_index].ma = 5; /* Memory Attributes */ + ioports_to_tlbs[ioport_index].a = 0; /* Set Data Access Bit Fault */ + ioports_to_tlbs[ioport_index].d = 0; /* Dirty Bit */ + ioports_to_tlbs[ioport_index].pl = 3;/* Privilege Level - All levels can R/W*/ + ioports_to_tlbs[ioport_index].ar = 2; /* Access Rights - R/W only*/ + ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */ + ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */ + + printk("sn1_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index].ppn); + + sn1_ioport_num += SN1_IOPORTS_UNIT; + + return(sn1_ioport_num - SN1_IOPORTS_UNIT); +} + +/* * sn1_pci_fixup() - This routine is called when platform_pci_fixup() is * invoked at the end of pcibios_init() to link the Linux pci * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c @@ -189,6 +241,11 @@ struct pci_dev *device_dev = NULL; struct sn1_widget_sysdata *widget_sysdata; struct sn1_device_sysdata *device_sysdata; + unsigned long ioport; + pciio_intr_t intr_handle; + int cpuid, bit; + devfs_handle_t *device_vertex; + pciio_intr_line_t lines; extern void sn1_pci_find_bios(void); @@ -204,7 +261,6 @@ devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); bridge_t *bridge = pcibr_soft->bs_base; -printk("Before Changing PIO Map Address:\n"); printk("pci_fixup_ioc3: Before devreg fixup\n"); printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); @@ -280,16 +336,11 @@ size = device_dev->resource[idx].end - device_dev->resource[idx].start; if (size) { -res = 0; -res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); -printk("Before pciio_pio_addr Base address %d = 0x%lx\n", idx, res); - - printk(" Changing device %d:%d resource start address from 0x%lx", - PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn), - device_dev->resource[idx].start); - device_dev->resource[idx].start = - (unsigned long)pciio_pio_addr(vhdl, 0, - PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); + res = 0; + res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); + device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); + +/* printk("sn1_pci_fixup: Mapped Address = 0x%p size = 0x%x\n", device_dev->resource[idx].start, size); */ } else continue; @@ -304,13 +355,14 @@ device_dev->resource[idx].start & 0xfffff7ffffffffff; device_dev->resource[idx].end = device_dev->resource[idx].end & 0xfffff7ffffffffff; - printk(" to 0x%lx\n", device_dev->resource[idx].start); -res = 0; -res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); -printk("After pciio_pio_addr Base address %d = 0x%lx\n", idx, res); - - if (device_dev->resource[idx].flags & IORESOURCE_IO) + res = 0; + res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); + if (device_dev->resource[idx].flags & IORESOURCE_IO) { cmd |= PCI_COMMAND_IO; + ioport = sn1_allocate_ioports(device_dev->resource[idx].start); + /* device_dev->resource[idx].start = ioport; */ + /* device_dev->resource[idx].end = ioport + SN1_IOPORTS_UNIT */ + } else if (device_dev->resource[idx].flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } @@ -319,9 +371,6 @@ */ size = device_dev->resource[PCI_ROM_RESOURCE].end - device_dev->resource[PCI_ROM_RESOURCE].start; - printk(" Changing device %d:%d ROM resource start address from 0x%lx", - PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn), - device_dev->resource[PCI_ROM_RESOURCE].start); device_dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, size, 0, PCIIO_BYTE_STREAM); @@ -341,24 +390,26 @@ /* bit gets dropped .. no harm */ pci_write_config_word(device_dev, PCI_COMMAND, cmd); - printk(" to 0x%lx\n", device_dev->resource[PCI_ROM_RESOURCE].start); + pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, &lines); +#ifdef BRINGUP + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { + lines = 1; + } - /* - * Set the irq correctly. - * Bits 7:3 = slot - * Bits 2:0 = function - * - * In the IRQ we will have: - * Bits 24:16 = bus number - * Bits 15:8 = slot|func number - */ - irq = 0; - irq = (irq | (device_dev->devfn << 8)); - irq = (irq | ( (device_dev->bus->number & 0xff) << 16) ); +#endif + + device_sysdata = (struct sn1_device_sysdata *)device_dev->sysdata; + device_vertex = device_sysdata->vhdl; + + intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); + + bit = intr_handle->pi_irq; + cpuid = intr_handle->pi_cpu; + irq = bit_pos_to_irq(bit); + irq = irq + (cpuid << 8); + pciio_intr_connect(intr_handle, NULL, NULL, NULL); device_dev->irq = irq; -printk("sn1_pci_fixup: slot= %d fn= %d vendor= 0x%x device= 0x%x irq= 0x%x\n", -PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn),device_dev->vendor, -device_dev->device, device_dev->irq); } #endif /* REAL_HARDWARE */ @@ -369,7 +420,6 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); bridge_t *bridge = pcibr_soft->bs_base; -printk("After Changing PIO Map Address:\n"); printk("pci_fixup_ioc3: Before devreg fixup\n"); printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); @@ -386,6 +436,25 @@ /* * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. + * + * Linux PCI Bus numbers are assigned from lowest module_id numbers + * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to + * HUB_WIDGET_ID_MIN: + * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. + * + * Given 2 modules 001c01 and 001c02 we get the following mappings: + * 001c01, widgetnum 15 = Bus number 0 + * 001c01, widgetnum 14 = Bus number 1 + * 001c02, widgetnum 15 = Bus number 3 + * 001c02, widgetnum 14 = Bus number 4 + * etc. + * + * The rational for starting Bus Number 0 with Widget number 15 is because + * the system boot disks are always connected via Widget 15 Slot 0 of the + * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 + * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest + * module id(Master Cnode) of the system. + * */ static int pci_bus_map_create(devfs_handle_t xtalk) @@ -402,10 +471,21 @@ /* * Loop throught this vertex and get the Xwidgets .. */ - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { + { + int pos; + char dname[256]; + pos = devfs_generate_path(xtalk, dname, 256); + printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); + } + sprintf(pathname, "%d", widgetnum); xwidget = NULL; + /* + * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget + * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device + */ rv = hwgraph_traverse(xtalk, pathname, &xwidget); if ( (rv != GRAPH_SUCCESS) ) { if (!xwidget) @@ -425,25 +505,35 @@ * Should not be any race here ... */ num_bridges++; - busnum_to_xwidget[num_bridges - 1] = xwidget; + busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; /* * Get the master node and from there get the NASID. */ master_node_vertex = device_master_get(xwidget); if (!master_node_vertex) { - printk(" **** pci_bus_map_create: Unable to get .master for vertex 0x%p **** \n", xwidget); + printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", xwidget); } hubinfo_get(master_node_vertex, &hubinfo); if (!hubinfo) { - printk(" **** pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p ****\n", master_node_vertex); + printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", master_node_vertex); return(1); } else { busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; } - printk("pci_bus_map_create: Found Hub nasid %d PCI Xwidget 0x%p widgetnum= %d\n", hubinfo->h_nasid, xwidget, widgetnum); + /* + * Pre assign DMA maps needed for 32 Bits Page Map DMA. + */ + busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( + sizeof(struct sn1_dma_maps_s) * 512, GFP_KERNEL); + if (!busnum_to_atedmamaps[num_bridges - 1]) + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, xwidget); + + memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, + sizeof(struct sn1_dma_maps_s) * 512); + } return(0); @@ -468,6 +558,9 @@ graph_vertex_place_t placeptr = EDGE_PLACE_WANT_REAL_EDGES; int rv = 0; char name[256]; + int master_iobrick; + moduleid_t iobrick_id; + int i; /* * Iterate throught each xtalk links in the system .. @@ -480,42 +573,48 @@ devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); /* - * Loop throught this directory "/devfs/hw/module/" and get each - * of it's entry. - */ - while (1) { - - /* Get vertex of component /dev/hw/ */ - memset((char *)name, '0', 256); - module_comp = NULL; - rv = hwgraph_edge_get_next(devfs_hdl, (char *)name, &module_comp, (uint *)&placeptr); - if ((rv == 0) && (module_comp)) { - /* Found a valid entry */ - node = NULL; - rv = hwgraph_edge_get(module_comp, "node", &node); - - } else { - printk("pci_bus_to_hcl_cvlink: No more Module Component.\n"); - return(0); + * To provide consistent(not persistent) device naming, we need to start + * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 + * with an attached I-Brick. Find the master_iobrick. + */ + master_iobrick = -1; + for (i = 0; i < nummodules; i++) { + moduleid_t iobrick_id; + iobrick_id = iobrick_module_get(&modules[i]->elsc); + if (iobrick_id > 0) { /* Valid module id */ + if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) { + master_iobrick = i; + break; + } } + } - if ( (rv != 0) || (!node) ){ - printk("pci_bus_to_hcl_cvlink: Module Component does not have node vertex.\n"); - continue; - } else { - xtalk = NULL; - rv = hwgraph_edge_get(node, "xtalk", &xtalk); - if ( (rv != 0) || (xtalk == NULL) ){ - printk("pci_bus_to_hcl_cvlink: Node has no xtalk vertex.\n"); - continue; - } + /* + * The master_iobrick gets bus 0 and 1. + */ + if (master_iobrick >= 0) { + memset(name, 0, 256); + format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF); + strcat(name, "/node/xtalk"); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); + pci_bus_map_create(xtalk); + } + + /* + * Now go do the rest of the modules, starting from the C-Brick with the lowest + * module id, remembering to skip the master_iobrick, which was done above. + */ + for (i = 0; i < nummodules; i++) { + if (i == master_iobrick) { + continue; /* Did the master_iobrick already. */ } - printk("pci_bus_to_hcl_cvlink: Found Module %s node vertex = 0x%p xtalk vertex = 0x%p\n", name, node, xtalk); - /* - * Call routine to get the existing PCI Xwidget and create - * the convenience link from "/devfs/hw/pci_bus/.." - */ + memset(name, 0, 256); + format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); + strcat(name, "/node/xtalk"); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); pci_bus_map_create(xtalk); } @@ -539,10 +638,8 @@ struct sn1_widget_sysdata *widget_sysdata; struct sn1_device_sysdata *device_sysdata; - printk("sgi_pci_intr_support: Called with requested_irq 0x%x\n", requested_irq); - if (!dev_desc || !bus_vertex || !device_vertex) { - printk("sgi_pci_intr_support: Invalid parameter dev_desc 0x%p, bus_vertex 0x%p, device_vertex 0x%p\n", dev_desc, bus_vertex, device_vertex); + printk("WARNING: sgi_pci_intr_support: Invalid parameter dev_desc 0x%p, bus_vertex 0x%p, device_vertex 0x%p\n", dev_desc, bus_vertex, device_vertex); return(-1); } @@ -577,15 +674,11 @@ if (pci_dev->vendor == PCI_VENDOR_ID_SGI && pci_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { *lines = 1; - printk("%s : IOC3 HACK: lines= %d\n", __FUNCTION__, *lines); } #endif /* BRINGUP */ /* Not supported currently */ *dev_desc = NULL; - - printk("sgi_pci_intr_support: Device Descriptor 0x%p, Bus Vertex 0x%p, Interrupt Pins 0x%x, Device Vertex 0x%p\n", *dev_desc, *bus_vertex, *lines, *device_vertex); - return(0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pci_dma.c linux.ac/arch/ia64/sn/io/pci_dma.c --- linux.vanilla/arch/ia64/sn/io/pci_dma.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/pci_dma.c Sat Apr 14 01:18:00 2001 @@ -21,9 +21,6 @@ #ifndef _LANGUAGE_C #define _LANGUAGE_C 99 #endif -#ifndef CONFIG_IA64_SGI_IO -#define CONFIG_IA64_SGI_IO 99 -#endif #include #include @@ -32,9 +29,9 @@ #include #include #include -#include #include #include +#include /* * this is REALLY ugly, blame it on gcc's lame inlining that we @@ -43,13 +40,69 @@ #if LANGUAGE_C == 99 #undef LANGUAGE_C #endif -#if _LANGUAGE_C == 99 -#undef _LANGUAGE_C -#endif #if CONFIG_IA64_SGI_IO == 99 #undef CONFIG_IA64_SGI_IO #endif +pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); +struct sn1_dma_maps_s *find_sn1_dma_map(dma_addr_t, unsigned char); +extern devfs_handle_t busnum_to_pcibr_vhdl[]; +extern nasid_t busnum_to_nid[]; +extern void * busnum_to_atedmamaps[]; + +/* + * Get a free pciio_dmamap_t entry. + */ +pciio_dmamap_t +get_free_pciio_dmamap(devfs_handle_t pci_bus) +{ + int i; + struct sn1_dma_maps_s *sn1_dma_map = NULL; + + /* + * Darn, we need to get the maps allocated for this bus. + */ + for (i=0; i<512; i++) { + if (busnum_to_pcibr_vhdl[i] == pci_bus) { + sn1_dma_map = busnum_to_atedmamaps[i]; + } + } + + /* + * Now get a free dmamap entry from this list. + */ + for (i=0; i<512; i++, sn1_dma_map++) { + if (!sn1_dma_map->dma_addr) { + sn1_dma_map->dma_addr = -1; + return( (pciio_dmamap_t) sn1_dma_map ); + } + } + +printk("get_pciio_dmamap: Unable to find a free dmamap\n"); + return(NULL); + +} + +struct sn1_dma_maps_s * +find_sn1_dma_map(dma_addr_t dma_addr, unsigned char busnum) +{ + + struct sn1_dma_maps_s *sn1_dma_map = NULL; + int i; + + sn1_dma_map = busnum_to_atedmamaps[busnum]; + + for (i=0; i<512; i++, sn1_dma_map++) { + if (sn1_dma_map->dma_addr == dma_addr) { + return( sn1_dma_map ); + } + } + +printk("find_pciio_dmamap: Unable find the corresponding dma map\n"); + return(NULL); + +} + /* * sn1 platform specific pci_alloc_consistent() * @@ -74,7 +127,7 @@ device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; - if ( ret = (void *)__get_free_pages(gfp, get_order(size)) ) { + if ( (ret = (void *)__get_free_pages(gfp, get_order(size))) ) { memset(ret, 0, size); } else { return(NULL); @@ -142,6 +195,8 @@ dma_addr_t dma_addr; paddr_t temp_ptr; struct sn1_device_sysdata *device_sysdata; + pciio_dmamap_t dma_map; + if (direction == PCI_DMA_NONE) @@ -153,7 +208,7 @@ device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; for (i = 0; i < nents; i++, sg++) { - sg->orig_address = sg->address; + sg->orig_address = (char *)NULL; dma_addr = 0; temp_ptr = (paddr_t) __pa(sg->address); @@ -166,7 +221,6 @@ PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD | PCIIO_DMA_A64 ); sg->address = (char *)dma_addr; -/* printk("pci_map_sg: 64Bits hwdev %p DMA Address 0x%p alt_address 0x%p orig_address 0x%p length 0x%x\n", hwdev, sg->address, sg->alt_address, sg->orig_address, sg->length); */ continue; } @@ -180,17 +234,28 @@ PCIIO_DMA_CMD); if (dma_addr) { sg->address = (char *)dma_addr; -/* printk("pci_map_single: 32Bit direct pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */ continue; - } else { - /* - * We need to map this request by using ATEs. - */ - printk("pci_map_single: 32Bits DMA Page Map support not available yet!"); - BUG(); - } + } + + /* + * It is a 32bit card and we cannot do Direct mapping. + * Let's 32Bit Page map the request. + */ + dma_map = NULL; + dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, + PCIBR_BARRIER | PCIIO_BYTE_STREAM | + PCIIO_DMA_CMD); + if (!dma_map) { + printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n"); + BUG(); + } + dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length); + /* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */ + sg->address = (char *)dma_addr; + sg->orig_address = (char *)dma_map; + } return nents; @@ -206,13 +271,25 @@ sn1_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { int i; + struct sn1_dma_maps_s *sn1_dma_map; + if (direction == PCI_DMA_NONE) BUG(); + for (i = 0; i < nelems; i++, sg++) - if (sg->orig_address != sg->address) { + if (sg->orig_address) { + /* + * We maintain the DMA Map pointer in sg->orig_address if + * it is ever allocated. + */ /* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */ - sg->address = sg->orig_address; + /* sg->address = sg->orig_address; */ + sg->address = (char *)-1; + sn1_dma_map = (struct sn1_dma_maps_s *)sg->orig_address; + pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map); + sn1_dma_map->dma_addr = 0; sg->orig_address = 0; } } @@ -234,24 +311,20 @@ dma_addr_t dma_addr; paddr_t temp_ptr; struct sn1_device_sysdata *device_sysdata; + pciio_dmamap_t dma_map = NULL; + struct sn1_dma_maps_s *sn1_dma_map; if (direction == PCI_DMA_NONE) BUG(); - if (IS_PCI32L(hwdev)) { - /* - * SNIA64 cannot support DMA Addresses smaller than 32 bits. - */ - return ((dma_addr_t) NULL); - } /* * find vertex for the device */ device_sysdata = (struct sn1_device_sysdata *)hwdev->sysdata; vhdl = device_sysdata->vhdl; -/* printk("pci_map_single: Called vhdl = 0x%p ptr = 0x%p size = %d\n", vhdl, ptr, size); */ + /* * Call our dmamap interface */ @@ -266,7 +339,6 @@ temp_ptr, size, PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD | PCIIO_DMA_A64 ); -/* printk("pci_map_single: 64Bit pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */ return (dma_addr); } @@ -281,14 +353,7 @@ temp_ptr, size, PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); if (dma_addr) { -/* printk("pci_map_single: 32Bit direct pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */ return (dma_addr); - } else { - /* - * We need to map this request by using ATEs. - */ - printk("pci_map_single: 32Bits DMA Page Map support not available yet!"); - BUG(); } } @@ -297,23 +362,56 @@ * SNIA64 cannot support DMA Addresses smaller than 32 bits. */ return ((dma_addr_t) NULL); + } + + /* + * It is a 32bit card and we cannot do Direct mapping. + * Let's 32Bit Page map the request. + */ + dma_map = NULL; + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIBR_BARRIER | + PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); + if (!dma_map) { + printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.\n"); + BUG(); } - return ((dma_addr_t) NULL); + dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, temp_ptr, size); + /* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, + temp_ptr, dma_addr); */ + sn1_dma_map = (struct sn1_dma_maps_s *)dma_map; + sn1_dma_map->dma_addr = dma_addr; + return ((dma_addr_t)dma_addr); } void sn1_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { + + struct sn1_dma_maps_s *sn1_dma_map = NULL; + if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ + BUG(); + + /* + * Get the sn1_dma_map entry. + */ + if (IS_PCI32_MAPPED(dma_addr)) + sn1_dma_map = find_sn1_dma_map(dma_addr, hwdev->bus->number); + + if (sn1_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map); + sn1_dma_map->dma_addr = (dma_addr_t)NULL; + } + } void sn1_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { + if (direction == PCI_DMA_NONE) BUG(); /* Nothing to do */ @@ -330,5 +428,5 @@ unsigned long sn1_dma_address (struct scatterlist *sg) { - return (sg->address); + return ((unsigned long)sg->address); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pciba.c linux.ac/arch/ia64/sn/io/pciba.c --- linux.vanilla/arch/ia64/sn/io/pciba.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/io/pciba.c Sat Apr 14 01:18:00 2001 @@ -0,0 +1,1716 @@ +/* $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. + * + * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Colin Ngam + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) +#include +#include +#endif + +#define copyin(_a, _b, _c) copy_from_user(_b, _a, _c) + +#ifndef DEBUG_PCIBA +#define DEBUG_PCIBA 0 +#endif + +/* v_mapphys does not percolate page offset back. */ +#define PCIBA_ALIGN_CHECK 1 + +#include + +/* grab an unused space code for "User DMA" space */ +#ifndef PCIBA_SPACE_UDMA +#define PCIBA_SPACE_UDMA (14) +#endif + +#if DEBUG_REFCT +extern int hwgraph_vertex_refct(vertex_hdl_t); +#endif +extern int pci_user_dma_max_pages; + +#define NEW(ptr) (ptr = kmem_zalloc(sizeof (*(ptr)), KM_SLEEP)) +#define DEL(ptr) (kfree(ptr)) + +/* Oops -- no standard "pci address" type! */ +typedef uint64_t pciaddr_t; + +/* ================================================================ + * driver types + */ +typedef struct pciba_slot_s *pciba_slot_t; +typedef struct pciba_comm_s *pciba_comm_t; +typedef struct pciba_soft_s *pciba_soft_t; +typedef struct pciba_map_s *pciba_map_t, **pciba_map_h; +typedef struct pciba_dma_s *pciba_dma_t, **pciba_dma_h; +typedef struct pciba_bus_s *pciba_bus_t; + +#define TRACKED_SPACES 16 +struct pciba_comm_s { + devfs_handle_t conn; + pciba_bus_t bus; + int refct; + pciba_soft_t soft[TRACKED_SPACES][2]; + struct semaphore lock; + pciba_dma_t dmap; +}; + +/* pciba_soft: device_info() for all openables */ +struct pciba_soft_s { + pciba_comm_t comm; + devfs_handle_t vhdl; + int refct; + pciio_space_t space; + size_t size; + pciio_space_t iomem; + pciaddr_t base; + unsigned flags; +}; + +#define pciba_soft_get(v) (pciba_soft_t)hwgraph_fastinfo_get(v) +#define pciba_soft_set(v,i) hwgraph_fastinfo_set(v,(arbitrary_info_t)(i)) + +#define pciba_soft_lock(soft) down(&soft->comm->lock) +#define pciba_soft_unlock(soft) up(&soft->comm->lock) + +/* pciba_map: data describing a mapping. + * (ie. a user mmap request) + */ +struct pciba_map_s { + pciba_map_t next; +#ifdef LATER + uthread_t *uthread; +#endif + __psunsigned_t handle; + uvaddr_t uvaddr; + size_t size; + pciio_piomap_t map; + pciio_space_t space; + pciaddr_t base; + unsigned flags; +}; + +/* pciba_dma: data describing a DMA mapping. + */ +struct pciba_dma_s { + pciba_dma_t next; + iopaddr_t paddr; /* starting phys addr */ + caddr_t kaddr; /* starting kern addr */ + pciio_dmamap_t map; /* mapping resources (ugh!) */ + pciaddr_t daddr; /* starting pci addr */ + size_t pages; /* size of block in pages */ + size_t bytes; /* size of block in bytes */ + __psunsigned_t handle; /* mapping handle */ +}; + +/* pciba_bus: common bus info for all openables + * descended from the same master vertex. + */ +struct pciba_bus_s { + struct semaphore lock; + pciba_map_t maps; /* stack of mappings */ + int refct; +}; + +#define pciba_bus_lock(bus) down(&bus->lock) +#define pciba_bus_unlock(bus) up(&bus->lock) + +typedef union ioctl_arg_buffer_u { + char data[IOCPARM_MASK + 1]; + uint8_t uc; + uint16_t us; + uint32_t ui; + uint64_t ud; + caddr_t ca; +#if ULI + struct uliargs uli; + struct uliargs32 uli32; +#endif +} ioctl_arg_buffer_t; + +/* ================================================================ + * driver variables + */ +char *pciba_mversion = "mload version 7.0"; +int pciba_devflag = 0x1 | + 0x200 | + 0x400; + +/* this counts the reasons why we can not + * currently unload this driver. + */ +atomic_t pciba_prevent_unload = ATOMIC_INIT(0); + +#if DEBUG_PCIBA +static struct reg_values space_v[] = +{ + {PCIIO_SPACE_NONE, "none"}, + {PCIIO_SPACE_ROM, "ROM"}, + {PCIIO_SPACE_IO, "I/O"}, + {PCIIO_SPACE_MEM, "MEM"}, + {PCIIO_SPACE_MEM32, "MEM(32)"}, + {PCIIO_SPACE_MEM64, "MEM(64)"}, + {PCIIO_SPACE_CFG, "CFG"}, + {PCIIO_SPACE_WIN(0), "WIN(0)"}, + {PCIIO_SPACE_WIN(1), "WIN(1)"}, + {PCIIO_SPACE_WIN(2), "WIN(2)"}, + {PCIIO_SPACE_WIN(3), "WIN(3)"}, + {PCIIO_SPACE_WIN(4), "WIN(4)"}, + {PCIIO_SPACE_WIN(5), "WIN(5)"}, + {PCIBA_SPACE_UDMA, "UDMA"}, + {PCIIO_SPACE_BAD, "BAD"}, + {0} +}; + +static struct reg_desc space_desc[] = +{ + {0xFF, 0, "space", 0, space_v}, + {0} +}; +#endif + +char pciba_edge_lbl_base[] = "base"; +char pciba_edge_lbl_cfg[] = "config"; +char pciba_edge_lbl_dma[] = "dma"; +char pciba_edge_lbl_intr[] = "intr"; +char pciba_edge_lbl_io[] = "io"; +char pciba_edge_lbl_mem[] = "mem"; +char pciba_edge_lbl_rom[] = "rom"; +char *pciba_edge_lbl_win[6] = +{"0", "1", "2", "3", "4", "5"}; + +#define PCIBA_EDGE_LBL_BASE pciba_edge_lbl_base +#define PCIBA_EDGE_LBL_CFG pciba_edge_lbl_cfg +#define PCIBA_EDGE_LBL_DMA pciba_edge_lbl_dma +#define PCIBA_EDGE_LBL_INTR pciba_edge_lbl_intr +#define PCIBA_EDGE_LBL_IO pciba_edge_lbl_io +#define PCIBA_EDGE_LBL_MEM pciba_edge_lbl_mem +#define PCIBA_EDGE_LBL_ROM pciba_edge_lbl_rom +#define PCIBA_EDGE_LBL_WIN(n) pciba_edge_lbl_win[n] + +#define PCIBA_EDGE_LBL_FLIP pciba_edge_lbl_flip + +static char pciba_info_lbl_bus[] = "pciba_bus"; + +#define PCIBA_INFO_LBL_BUS pciba_info_lbl_bus + +struct file_operations pciba_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: NULL, + open: NULL, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL +}; + +/* ================================================================ + * function table of contents + */ + +void pciba_init(void); +int pciba_attach(devfs_handle_t); + +static void pciba_sub_attach(pciba_comm_t, + pciio_space_t, pciio_space_t, pciaddr_t, + devfs_handle_t, devfs_handle_t, char *); + +static pciba_bus_t pciba_find_bus(devfs_handle_t, int); +#ifdef LATER +static void pciba_map_push(pciba_bus_t, pciba_map_t); +static pciba_map_t pciba_map_pop_hdl(pciba_bus_t, __psunsigned_t); +static void pciba_sub_detach(devfs_handle_t, char *); +static pciio_iter_f pciba_unload_me; +#endif + +int pciba_unload(void); +int pciba_unreg(void); +int pciba_detach(devfs_handle_t); + +int pciba_open(dev_t *, int, int, struct cred *); +int pciba_close(dev_t); +int pciba_read(dev_t, cred_t *); +int pciba_write(dev_t, cred_t *); +int pciba_ioctl(dev_t, int, void *, int, cred_t *, int *); + +int pciba_map(dev_t, vhandl_t *, off_t, size_t, uint32_t); +int pciba_unmap(dev_t, vhandl_t *); + +#if ULI +void pciba_clearuli(struct uli *); +static intr_func_f pciba_intr; +#endif /* Undef as it gets implemented */ + +/* ================================================================ + * driver load, register, and setup + */ +void +pciba_init(void) +{ + + /* + * What do we need to do here? + */ +#if DEBUG_PCIBA + printk("pciba_init()\n"); +#endif +} + +#ifdef LATER +#if HWG_PERF_CHECK && IP30 && !DEBUG +void +pciba_timeout(void *arg1, void *arg2) +{ + struct semaphore *semap = (sema_t *) arg1; + unsigned long *cvalp = (unsigned long *) arg2; + + if (cvalp) + cvalp[0] = RAW_COUNT(); + if (semap) + up(semap); +} + +volatile unsigned long cNval[1]; +struct semaphore tsema; + +void +pciba_timeout_test(void) +{ + unsigned long c0val, cval; + toid_t tid; + + extern void hwg_hprint(unsigned long, char *); + + sema_init(&tsema, 0); + + cNval[0] = 0; + c0val = RAW_COUNT(); + tid = timeout((void (*)()) pciba_timeout, (void *) 0, 1, (void *) cNval); + DELAY(1000000); + cval = cNval[0]; + if (cval == 0) { + untimeout(tid); + PRINT_ALERT("pciba: one-tick timeout did not happen in a second\n"); + return; + } + cval = cval - c0val; + hwg_hprint(cval, "timeout(1)"); + + cNval[0] = 0; + c0val = RAW_COUNT(); + tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, 2, (void *) cNval); + + /* FIXME : this probably needs to be down_interruptible() */ + + if (down(&tsema) < 0) { /* wait for the pciba_timeout */ + untimeout(tid); + PRINT_WARNING("pciba: timeout(2) time check aborted\n"); + return; + } + cval = cNval[0]; + if (cval == 0) { + untimeout(tid); + PRINT_WARNING("pciba: timeout(2) time not logged\n"); + return; + } + cval = cval - c0val; + hwg_hprint(cval, "timeout(2)"); + + cNval[0] = 0; + c0val = RAW_COUNT(); + tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, HZ, (void *) cNval); + + /* FIXME : this probably needs to be down_interruptible() */ + + if (down(&tsema) < 0) { /* wait for the pciba_timeout */ + untimeout(tid); + PRINT_WARNING("pciba: timeout(HZ) time check aborted\n"); + return; + } + cval = cNval[0]; + if (cval == 0) { + untimeout(tid); + PRINT_WARNING("pciba: timeout(HZ) time not logged\n"); + return; + } + cval = cval - c0val; + hwg_hprint(cval, "timeout(HZ)"); + + printk("verifying untimeout() cancells ...\n"); + cNval[0] = 0; + tid = timeout((void (*)()) pciba_timeout, (void *) 0, 2, (void *) cNval); + untimeout(tid); + DELAY(1000000); + cval = cNval[0]; + if (cval != 0) { + PRINT_ALERT("pciba: unable to cancel two-tick timeout\n"); + cval -= c0val; + hwg_hprint(cval, "CANCELLED timeout(2)"); + } +} +#endif + +int +pciba_reg(void) +{ +#if DEBUG_PCIBA + printk("pciba_reg()\n"); +#endif + pciio_driver_register(-1, -1, "pciba_", 0); + +#if HWG_PERF_CHECK && IP30 && !DEBUG + printk("%s %d\n", __FUNCTION__, __LINE__); +pciba_timeout_test(); +#endif + +#if DEBUG_REFCT + { + char *cname = "pciba"; + char *dname = "ptv"; + char *cpath0 = "node/xtalk/15"; + char *uname0 = "0"; + char *cpath1 = "node/xtalk/13"; + char *uname1 = "1"; + devfs_handle_t conn; + devfs_handle_t conv; + devfs_handle_t vhdl; + int ret; + + printk("pciba refct tests:\n"); + +#define SHOWREF(vhdl,func) printk("ref=%d\t%s\t(%d) %v\n", hwgraph_vertex_refct(vhdl), #func, vhdl, vhdl); + + if (GRAPH_SUCCESS != (ret = hwgraph_path_add(hwgraph_root, cname, &conv))) + printk("\tunable to create conv (ret=%d)\n", ret); + else { SHOWREF(conv, hwgraph_path_add); + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath0, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl))) + printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_char_device_add); + hwgraph_chmod(vhdl, 0666); SHOWREF(vhdl, hwgraph_chmod); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname0))) + printk("unable to create %v/%s (ret=%d)\n", conn, uname0, vhdl, ret); + else SHOWREF(vhdl, hwgraph_edge_add); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath1, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl))) + printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_char_device_add); + hwgraph_chmod(vhdl, 0666); SHOWREF(vhdl, hwgraph_chmod); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname1))) + printk("unable to create %v/%s (ret=%d)\n", conn, uname1, vhdl, ret); + else SHOWREF(vhdl, hwgraph_edge_add); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath0, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl))) + printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname0, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname0, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl))) + printk("\tvertex %d destroyed OK\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_destroy); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn))) + printk("\tunable to find %s (ret=%d)\n", cpath1, ret); + else { SHOWREF(conn, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl))) + printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret); + else { SHOWREF(vhdl, hwgraph_traverse); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname1, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname1, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret); + else SHOWREF(vhdl, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) + printk("unable to unref %v\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_unref); + if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl))) + printk("\tvertex %d destroyed OK\n", vhdl); + else SHOWREF(vhdl, hwgraph_vertex_destroy); + } + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) + printk("unable to unref %v\n", conn); + else SHOWREF(conn, hwgraph_vertex_unref); + } + + if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(hwgraph_root, cname, NULL))) + printk("\tunable to remove edge %v/%s (ret=%d)\n", hwgraph_root, cname, ret); + else SHOWREF(conv, hwgraph_edge_remove); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conv))) + printk("unable to unref %v\n", conv); + else SHOWREF(conv, hwgraph_vertex_unref); + if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(conv))) + printk("\tvertex %d destroyed OK\n", conv); + else SHOWREF(conv, hwgraph_vertex_destroy); + } + } +#endif + + return 0; +} + +#endif +int +pciba_attach(devfs_handle_t hconn) +{ +#if defined(PCIIO_SLOT_NONE) + pciio_info_t info = pciio_info_get(hconn); + pciio_slot_t slot = pciio_info_slot_get(info); +#endif + pciba_comm_t comm; + pciba_bus_t bus; + int ht; + devfs_handle_t hbase; + devfs_handle_t gconn; + devfs_handle_t gbase; + int win; + int wins; + pciio_space_t space; + pciaddr_t base; + + int iwins; + int mwins; + +#if DEBUG_PCIBA + printk("pciba_attach(%p)\n", hconn); +#endif + + /* Pick up "dualslot guest" vertex, + * which gets all functionality except + * config space access. + */ + if ((GRAPH_SUCCESS != + hwgraph_traverse(hconn, ".guest", &gconn)) || + (hconn == gconn)) + gconn = GRAPH_VERTEX_NONE; + + bus = pciba_find_bus(hconn, 1); + bus->refct ++; + + /* set up data common to all pciba openables + * on this connection point. + */ + NEW(comm); + comm->conn = hconn; + comm->bus = bus; + comm->refct = 0; + sema_init(&comm->lock, 1); + +#if !defined(PCIIO_SLOT_NONE) + if (bus->refct == 1) +#else + if (slot == PCIIO_SLOT_NONE) +#endif + { + pciio_info_t pciio_info; + devfs_handle_t master; + + pciio_info = pciio_info_get(hconn); + master = pciio_info_master_get(pciio_info); + + pciba_sub_attach(comm, PCIIO_SPACE_IO, PCIIO_SPACE_IO, 0, master, master, PCIBA_EDGE_LBL_IO); + pciba_sub_attach(comm, PCIIO_SPACE_MEM, PCIIO_SPACE_MEM, 0, master, master, PCIBA_EDGE_LBL_MEM); +#if defined(PCIIO_SLOT_NONE) + return 0; +#endif + } + + ht = 0x7F & pciio_config_get(hconn, PCI_CFG_HEADER_TYPE, 1); + + wins = ((ht == 0x00) ? 6 : + (ht == 0x01) ? 2 : + 0); + + mwins = iwins = 0; + + hbase = GRAPH_VERTEX_NONE; + gbase = GRAPH_VERTEX_NONE; + + for (win = 0; win < wins; win++) { + + base = pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win), 4); + if (base & 1) { + space = PCIIO_SPACE_IO; + base &= 0xFFFFFFFC; + } else if ((base & 7) == 4) { + space = PCIIO_SPACE_MEM; + base &= 0xFFFFFFF0; + base |= ((pciaddr_t) pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win + 1), 4)) << 32; + } else { + space = PCIIO_SPACE_MEM; + base &= 0xFFFFFFF0; + } + + if (!base) + break; + +#if PCIBA_ALIGN_CHECK + if (base & (_PAGESZ - 1)) { +#if DEBUG_PCIBA + PRINT_WARNING("%p pciba: BASE%d not page aligned!\n" + "\tmmap this window at offset 0x%x via \".../pci/%s\"\n", + hconn, win, base, + (space == PCIIO_SPACE_IO) ? "io" : "mem"); +#endif + continue; /* next window */ + } +#endif + + if ((hbase == GRAPH_VERTEX_NONE) && + ((GRAPH_SUCCESS != + hwgraph_path_add(hconn, PCIBA_EDGE_LBL_BASE, &hbase)) || + (hbase == GRAPH_VERTEX_NONE))) + break; /* no base vertex, no more windows. */ + + if ((gconn != GRAPH_VERTEX_NONE) && + (gbase == GRAPH_VERTEX_NONE) && + ((GRAPH_SUCCESS != + hwgraph_path_add(gconn, PCIBA_EDGE_LBL_BASE, &gbase)) || + (gbase == GRAPH_VERTEX_NONE))) + break; /* no base vertex, no more windows. */ + + pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hbase, gbase, PCIBA_EDGE_LBL_WIN(win)); + + if (space == PCIIO_SPACE_IO) { + if (!iwins++) { + pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_IO); + } + } else { + if (!mwins++) { + pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_MEM); + } + } + + if ((base & 7) == 4) + win++; + } + + pciba_sub_attach(comm, PCIIO_SPACE_CFG, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_CFG); + pciba_sub_attach(comm, PCIBA_SPACE_UDMA, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_DMA); +#if ULI + pciba_sub_attach(comm, PCIIO_SPACE_NONE, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_INTR); +#endif + + /* XXX should ignore if device is an IOC3 */ + if (ht == 0x01) + base = pciio_config_get(hconn, PCI_EXPANSION_ROM+8, 4); + else + base = pciio_config_get(hconn, PCI_EXPANSION_ROM, 4); + + base &= 0xFFFFF000; + + if (base) { + if (base & (_PAGESZ - 1)) +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("%v pciba: ROM is 0x%x\n" + "\tnot page aligned, mmap will be difficult\n", + hconn, base); +#else + PRINT_WARNING("0x%x pciba: ROM is 0x%x\n" + "\tnot page aligned, mmap will be difficult\n", + hconn, base); +#endif + pciba_sub_attach(comm, PCIIO_SPACE_ROM, PCIIO_SPACE_MEM, base, hconn, gconn, PCIBA_EDGE_LBL_ROM); + } + +#if !FICUS /* FICUS shorts the refct by one on path_add */ + if (hbase != GRAPH_VERTEX_NONE) + hwgraph_vertex_unref(hbase); + + if (gbase != GRAPH_VERTEX_NONE) + hwgraph_vertex_unref(gbase); +#endif + + return 0; +} + +static void +pciba_sub_attach2(pciba_comm_t comm, + pciio_space_t space, + pciio_space_t iomem, + pciaddr_t base, + devfs_handle_t from, + char *name, + char *suf, + unsigned bigend) +{ + char nbuf[128]; + pciba_soft_t soft; + devfs_handle_t handle = NULL; + + if (suf && *suf) { + strcpy(nbuf, name); + name = nbuf; + strcat(name, suf); + } + +#if DEBUG_PCIBA + printk("pciba_sub_attach2 %p/%s %p at %p[%x]\n", + from, name, space, space_desc, iomem, space_desc, base, from, name); +#endif + + if (space < TRACKED_SPACES) + if ((soft = comm->soft[space][bigend]) != NULL) { + soft->refct ++; + hwgraph_edge_add(from, soft->vhdl, name); + return; + } + + NEW(soft); + if (!soft) + return; + + soft->comm = comm; + soft->space = space; + soft->size = 0; + soft->iomem = iomem; + soft->base = base; + soft->refct = 1; + + if (space == PCIIO_SPACE_NONE) + soft->flags = 0; + else if (bigend) + soft->flags = PCIIO_BYTE_STREAM; + else + soft->flags = PCIIO_WORD_VALUES; + + handle = hwgraph_register(from, name, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &pciba_fops, NULL); + soft->vhdl = handle; + pciba_soft_set(soft->vhdl, soft); + if (space < TRACKED_SPACES) + comm->soft[space][bigend] = soft; + comm->refct ++; +} + +static void +pciba_sub_attach1(pciba_comm_t comm, + pciio_space_t space, + pciio_space_t iomem, + pciaddr_t base, + devfs_handle_t hfrom, + devfs_handle_t gfrom, + char *name, + char *suf, + unsigned bigend) +{ + pciba_sub_attach2(comm, space, iomem, base, hfrom, name, suf, bigend); + if ((gfrom != GRAPH_VERTEX_NONE) && (gfrom != hfrom)) + pciba_sub_attach2(comm, space, iomem, base, gfrom, name, suf, bigend); +} + +static void +pciba_sub_attach(pciba_comm_t comm, + pciio_space_t space, + pciio_space_t iomem, + pciaddr_t base, + devfs_handle_t hfrom, + devfs_handle_t gfrom, + char *name) +{ + pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, NULL, 0); + if (iomem != PCIIO_SPACE_NONE) { + pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_le", 0); + pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_be", 1); + } +} + +#ifdef LATER +static void +pciba_reload_me(devfs_handle_t pconn_vhdl) +{ + devfs_handle_t vhdl; + +#if DEBUG_PCIBA + printf("pciba_reload_me(%v)\n", pconn_vhdl); +#endif + + if (GRAPH_SUCCESS != + hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &vhdl)) + return; + + hwgraph_vertex_unref(vhdl); +} +#endif /* LATER */ + +static pciba_bus_t +pciba_find_bus(devfs_handle_t pconn, int cflag) +{ + pciio_info_t pciio_info; + devfs_handle_t master; + arbitrary_info_t ainfo; + pciba_bus_t bus; + + pciio_info = pciio_info_get(pconn); + master = pciio_info_master_get(pciio_info); + + if (GRAPH_SUCCESS == + hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo)) + return (pciba_bus_t) ainfo; + + if (!cflag) + return 0; + + NEW(bus); + if (!bus) + return 0; + + sema_init(&bus->lock, 1); + + ainfo = (arbitrary_info_t) bus; + hwgraph_info_add_LBL(master, PCIBA_INFO_LBL_BUS, ainfo); + hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo); + if ((pciba_bus_t) ainfo != bus) + DEL(bus); +#if DEBUG_PCIBA + else + printk("pcbia_find_bus: new bus at %p\n", master); +#endif + + return (pciba_bus_t) ainfo; +} + +#ifdef LATER +static void +pciba_map_push(pciba_bus_t bus, pciba_map_t map) +{ +#if DEBUG_PCIBA + printk("pciba_map_push(bus=0x%x, map=0x%x, hdl=0x%x\n", + bus, map, map->handle); +#endif + pciba_bus_lock(bus); + map->next = bus->maps; + bus->maps = map; + pciba_bus_unlock(bus); +} + +static pciba_map_t +pciba_map_pop_hdl(pciba_bus_t bus, __psunsigned_t handle) +{ + pciba_map_h hdl; + pciba_map_t map; + + pciba_bus_lock(bus); + for (hdl = &bus->maps; map = *hdl; hdl = &map->next) + if (map->handle == handle) { + *hdl = map->next; + break; + } + pciba_bus_unlock(bus); +#if DEBUG_PCIBA + printk("pciba_map_pop_va(bus=0x%x, handle=0x%x) returns map=0x%x\n", + bus, handle, map); +#endif + return map; +} + +/* ================================================================ + * driver teardown, unregister and unload + */ +int +pciba_unload(void) +{ +#if DEBUG_PCIBA + printk("pciba_unload()\n"); +#endif + + if (atomic_read(&pciba_prevent_unload)) + return -1; + + pciio_iterate("pciba_", pciba_unload_me); + + return 0; +} + +int +pciba_unreg(void) +{ + +#if DEBUG_PCIBA + printf("pciba_unreg()\n"); +#endif + + if (atomic_read(&pciba_prevent_unload)) + return -1; + + pciio_driver_unregister("pciba_"); + return 0; +} + +int +pciba_detach(devfs_handle_t conn) +{ + devfs_handle_t base; + pciba_bus_t bus; + devfs_handle_t gconn; + devfs_handle_t gbase; + + pciio_info_t pciio_info; + devfs_handle_t master; + arbitrary_info_t ainfo; + int ret; + +#if DEBUG_PCIBA + printf("pciba_detach(%v)\n", conn); +#endif + + if ((GRAPH_SUCCESS != + hwgraph_traverse(conn, ".guest", &gconn)) || + (conn == gconn)) + gconn = GRAPH_VERTEX_NONE; + + if (gconn != GRAPH_VERTEX_NONE) { + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_CFG); + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_DMA); + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_ROM); +#if ULI + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_INTR); +#endif + if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &gbase)) { + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_MEM); + pciba_sub_detach(gconn, PCIBA_EDGE_LBL_IO); + pciba_sub_detach(gbase, "0"); + pciba_sub_detach(gbase, "1"); + pciba_sub_detach(gbase, "2"); + pciba_sub_detach(gbase, "3"); + pciba_sub_detach(gbase, "4"); + pciba_sub_detach(gbase, "5"); + hwgraph_vertex_unref(gbase); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(gbase))) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", + conn, ret); +#else + PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", + conn, ret); +#endif +#if DEBUG_REFCT + printk("\tretained refct %d\n", hwgraph_vertex_refct(gbase)); +#endif + } + } + } + + pciba_sub_detach(conn, PCIBA_EDGE_LBL_CFG); + pciba_sub_detach(conn, PCIBA_EDGE_LBL_DMA); + pciba_sub_detach(conn, PCIBA_EDGE_LBL_ROM); +#if ULI + pciba_sub_detach(conn, PCIBA_EDGE_LBL_INTR); +#endif + + if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &base)) { + pciba_sub_detach(conn, PCIBA_EDGE_LBL_MEM); + pciba_sub_detach(conn, PCIBA_EDGE_LBL_IO); + pciba_sub_detach(base, "0"); + pciba_sub_detach(base, "1"); + pciba_sub_detach(base, "2"); + pciba_sub_detach(base, "3"); + pciba_sub_detach(base, "4"); + pciba_sub_detach(base, "5"); + hwgraph_vertex_unref(base); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(base))) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", + conn, ret); +#else + PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", + conn, ret); +#endif +#if DEBUG_REFCT + printk("\tretained refct %d\n", hwgraph_vertex_refct(base)); +#endif + } + } + + bus = pciba_find_bus(conn, 0); + if (bus && !--(bus->refct)) { + + pciio_info = pciio_info_get(conn); + + master = pciio_info_master_get(pciio_info); + + pciba_sub_detach(master, PCIBA_EDGE_LBL_IO); + pciba_sub_detach(master, PCIBA_EDGE_LBL_MEM); + pciba_sub_detach(master, PCIBA_EDGE_LBL_CFG); + hwgraph_info_remove_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo); + +#if DEBUG_PCIBA + printf("pcbia_detach: DEL(bus) at %v\n", master); +#endif + DEL(bus); + } + + return 0; +} + +static void +pciba_sub_detach1(devfs_handle_t conn, + char *name, + char *suf) +{ + devfs_handle_t vhdl; + pciba_soft_t soft; + pciba_comm_t comm; + int ret; + char nbuf[128]; + + if (suf && *suf) { + strcpy(nbuf, name); + name = nbuf; + strcat(name, suf); + } + + if ((GRAPH_SUCCESS == hwgraph_edge_remove(conn, name, &vhdl)) && + ((soft = pciba_soft_get(vhdl)) != NULL)) { +#if DEBUG_PCIBA +#if defined(SUPPORT_PRINTING_V_FORMAT) + prink("pciba_sub_detach(%v,%s)\n", conn, name); +#else + prink("pciba_sub_detach(0x%x,%s)\n", conn, name); +#endif +#endif + + hwgraph_vertex_unref(soft->vhdl); +#if DEBUG_REFCT + printk("\tadjusted refct %d (soft ref: %d)\n", + hwgraph_vertex_refct(vhdl), + soft->refct); +#endif + if (!--(soft->refct)) { + comm = soft->comm; + if (!--(comm->refct)) { + DEL(comm); + } + pciba_soft_set(vhdl, 0); + DEL(soft); + + hwgraph_vertex_unref(vhdl); + if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(vhdl))) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/%s) failed (%d)", + conn, name, ret); +#else + PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/%s) failed (%d)", + conn, name, ret); +#endif +#if DEBUG_REFCT + printk("\tretained refct %d\n", hwgraph_vertex_refct(vhdl)); +#endif + } + } + } +} + +static void +pciba_sub_detach(devfs_handle_t conn, + char *name) +{ + pciba_sub_detach1(conn, name, ""); + pciba_sub_detach1(conn, name, "_le"); + pciba_sub_detach1(conn, name, "_be"); +} + +static void +pciba_unload_me(devfs_handle_t pconn_vhdl) +{ + devfs_handle_t c_vhdl; + +#if DEBUG_PCIBA + printf("pciba_unload_me(%v)\n", pconn_vhdl); +#endif + + if (GRAPH_SUCCESS != + hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &c_vhdl)) + return; + + hwgraph_vertex_unref(c_vhdl); +} + +/* ================================================================ + * standard unix entry points + */ + +/*ARGSUSED */ +int +pciba_open(dev_t *devp, int flag, int otyp, struct cred *crp) +{ + +#if DEBUG_PCIBA + printf("pciba_open(%V)\n", *devp); +#endif + return 0; +} + +/*ARGSUSED */ +int +pciba_close(dev_t dev) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + pciba_soft_t soft = pciba_soft_get(vhdl); + +#if DEBUG_PCIBA + printf("pciba_close(%V)\n", dev); +#endif + + /* if there is pending DMA for this device, hit the + * device over the head with a baseball bat and + * release the system memory resources. + */ + if (soft && soft->comm->dmap) { + pciba_dma_t next; + pciba_dma_t dmap; + + pciba_soft_lock(soft); + if (dmap = soft->comm->dmap) { + soft->comm->dmap = 0; + + pciio_reset(soft->comm->conn); + + do { + if (!dmap->kaddr) + break; + if (!dmap->paddr) + break; + if (dmap->bytes < NBPP) + break; + next = dmap->next; + kvpfree(dmap->kaddr, dmap->bytes / NBPP); + dmap->paddr = 0; + dmap->bytes = 0; + DEL(dmap); + } while (dmap = next); + } + pciba_soft_unlock(soft); + } + return 0; +} + +/* ARGSUSED */ +int +pciba_read(dev_t dev, cred_t *crp) +{ +#if DEBUG_PCIBA + printf("pciba_read(%V)\n", dev); +#endif + + return EINVAL; +} + +/* ARGSUSED */ +int +pciba_write(dev_t dev, cred_t *crp) +{ +#if DEBUG_PCIBA + printf("pciba_write(%V)\n", dev); +#endif + + return EINVAL; +} + +/*ARGSUSED */ +int +pciba_ioctl(dev_t dev, int cmd, void *uarg, int mode, cred_t *crp, int *rvalp) +{ + devfs_handle_t vhdl; + pciba_soft_t soft; + pciio_space_t space; + ioctl_arg_buffer_t arg; + int psize; + int err = 0; + +#if ULI + char abi = get_current_abi(); + pciio_intr_t intr=0; + device_desc_t desc; + cpuid_t intrcpu; + unsigned lines; + struct uli *uli = 0; +#endif + unsigned flags; + void *kaddr = 0; + iopaddr_t paddr; + pciba_dma_h dmah; + pciba_dma_t dmap = 0; + pciio_dmamap_t dmamap = 0; + size_t bytes; + int pages; + pciaddr_t daddr; + +#if DEBUG_PCIBA + printf("pciba_ioctl(%V,0x%x)\n", dev, cmd); +#endif + + psize = (cmd >> 16) & IOCPARM_MASK; + +#if ULI + ASSERT(sizeof(struct uliargs) > 8); /* prevent CFG access conflict */ + ASSERT(sizeof(struct uliargs) <= IOCPARM_MASK); +#endif + + arg.ca = uarg; + + if ((psize > 0) && (cmd & (IOC_OUT | IOC_IN))) { + if (psize > sizeof(arg)) + err = EINVAL; /* "bad parameter size */ + else { + if (cmd & IOC_OUT) + bzero(arg.data, psize); + if ((cmd & IOC_IN) && + (copyin(uarg, arg.data, psize) < 0)) + err = EFAULT; /* "parameter copyin failed" */ + } + } + vhdl = dev_to_vhdl(dev); + soft = pciba_soft_get(vhdl); + space = soft->space; + + if (err == 0) { + err = EINVAL; /* "invalid ioctl for this vertex" */ + switch (space) { +#if ULI + case PCIIO_SPACE_NONE: /* the "intr" vertex */ + /* PCIIOCSETULI: set up user interrupts. + */ + lines = cmd & 15; + if (ABI_IS_64BIT(abi)) { + if (cmd != PCIIOCSETULI(lines)) { + err = EINVAL; /* "invalid ioctl for this vertex" */ + break; + } + } + else { + struct uliargs uliargs; + + if (cmd != PCIIOCSETULI32(lines)) { + err = EINVAL; /* "invalid ioctl for this vertex" */ + break; + } + + uliargs32_to_uliargs(&arg.uli32, &uliargs); + arg.uli = uliargs; + } + desc = device_desc_dup(soft->comm->conn); + device_desc_flags_set(desc, (device_desc_flags_get(desc) | + D_INTR_NOTHREAD)); + device_desc_intr_swlevel_set(desc, INTR_SWLEVEL_NOTHREAD_DEFAULT); + device_desc_intr_name_set(desc, "PCIBA"); + device_desc_default_set(soft->comm->conn, desc); + + /* When designating interrupts, the slot number + * is taken from the connection point. + * Bits 0..3 are used to select INTA..INTD; more + * than one bit can be specified. These should + * be constructed using PCIIO_INTR_LINE_[ABCD]. + */ + intr = pciio_intr_alloc + (soft->comm->conn, desc, lines, soft->vhdl); + if (intr == 0) { + err = ENOMEM; /* "insufficient resources" */ + break; + } + intrcpu = cpuvertex_to_cpuid(pciio_intr_cpu_get(intr)); + + if (err = new_uli(&arg.uli, &uli, intrcpu)) { + break; /* "unable to set up ULI" */ + } + atomic_inc(&pciba_prevent_unload); + + pciio_intr_connect(intr, pciba_intr, uli, (void *) 0); + + /* NOTE: don't set the teardown function + * until the interrupt is connected. + */ + uli->teardownarg1 = (__psint_t) intr; + uli->teardown = pciba_clearuli; + + arg.uli.id = uli->index; + + if (!ABI_IS_64BIT(abi)) { + struct uliargs32 uliargs32; + uliargs_to_uliargs32(&arg.uli, &uliargs32); + arg.uli32 = uliargs32; + } + + err = 0; + break; +#endif + + case PCIBA_SPACE_UDMA: /* the "dma" vertex */ + + switch (cmd) { + + case PCIIOCDMAALLOC: + /* PCIIOCDMAALLOC: allocate a chunk of physical + * memory and set it up for DMA. Return the + * PCI address that gets to it. + * NOTE: this allocates memory local to the + * CPU doing the ioctl, not local to the + * device that will be doing the DMA. + */ + + if (!_CAP_ABLE(CAP_DEVICE_MGT)) { + err = EPERM; + break; + } + /* separate the halves of the incoming parameter */ + flags = arg.ud >> 32; + bytes = arg.ud & 0xFFFFFFFF; + +#if DEBUG_PCIBA + printf("pciba: user wants 0x%x bytes of DMA, flags 0x%x\n", + bytes, flags); +#endif + + /* round up the requested size to the next highest page */ + pages = (bytes + NBPP - 1) / NBPP; + + /* make sure the requested size is something reasonable */ + if (pages > pci_user_dma_max_pages) { +#if DEBUG_PCIBA + printf("pciba: request for too much buffer space\n"); +#endif + err = EINVAL; + break; /* "request for too much buffer space" */ + } + /* "correct" number of bytes */ + bytes = pages * NBPP; + + /* allocate the space */ + /* XXX- force to same node as the device? */ + /* XXX- someday, we want to handle user buffers, + * and noncontiguous pages, but this will + * require either fancy mapping or handing + * a list of blocks back to the user. For + * now, just tell users to allocate a lot of + * individual single-pages and manage their + * scatter-gather manually. + */ + kaddr = kvpalloc(pages, VM_DIRECT | KM_NOSLEEP, 0); + if (kaddr == 0) { +#if DEBUG_PCIBA + printf("pciba: unable to get %d contiguous pages\n", pages); +#endif + err = EAGAIN; /* "insufficient resources, try again later" */ + break; + } +#if DEBUG_PCIBA + printf("pciba: kaddr is 0x%x\n", kaddr); +#endif + paddr = kvtophys(kaddr); + + daddr = pciio_dmatrans_addr + (soft->comm->conn, 0, paddr, bytes, flags); + if (daddr == 0) { /* "no direct path available" */ +#if DEBUG_PCIBA + printf("pciba: dmatrans failed, trying dmamap\n"); +#endif + dmamap = pciio_dmamap_alloc + (soft->comm->conn, 0, bytes, flags); + if (dmamap == 0) { +#if DEBUG_PCIBA + printf("pciba: unable to allocate dmamap\n"); +#endif + err = ENOMEM; + break; /* "out of mapping resources" */ + } + daddr = pciio_dmamap_addr + (dmamap, paddr, bytes); + if (daddr == 0) { +#if DEBUG_PCIBA + printf("pciba: dmamap_addr failed\n"); +#endif + err = EINVAL; + break; /* "can't get there from here" */ + } + } +#if DEBUG_PCIBA + printf("pciba: daddr is 0x%x\n", daddr); +#endif + NEW(dmap); + if (!dmap) { + err = ENOMEM; + break; /* "no memory available" */ + } + dmap->bytes = bytes; + dmap->pages = pages; + dmap->paddr = paddr; + dmap->kaddr = kaddr; + dmap->map = dmamap; + dmap->daddr = daddr; + dmap->handle = 0; + +#if DEBUG_PCIBA + printf("pciba: dmap 0x%x contains va 0x%x bytes 0x%x pa 0x%x pages 0x%x daddr 0x%x\n", + dmap, kaddr, bytes, paddr, pages, daddr); +#endif + + arg.ud = dmap->daddr; + + err = 0; + break; + + case PCIIOCDMAFREE: + /* PCIIOCDMAFREE: Find the chunk of + * User DMA memory, and release its + * resources back to the system. + */ + + if (!_CAP_ABLE(CAP_DEVICE_MGT)) { + err = EPERM; /* "you can't do that" */ + break; + } + if (soft->comm->dmap == NULL) { + err = EINVAL; /* "no User DMA to free" */ + break; + } + /* find the request. */ + daddr = arg.ud; + err = EINVAL; /* "block not found" */ + pciba_soft_lock(soft); + for (dmah = &soft->comm->dmap; dmap = *dmah; dmah = &dmap->next) { + if (dmap->daddr == daddr) { + if (dmap->handle != 0) { + dmap = 0; /* don't DEL this dmap! */ + err = EINVAL; /* "please unmap first" */ + break; /* break outa for loop. */ + } + *dmah = dmap->next; + + if (dmamap = dmap->map) { + pciio_dmamap_free(dmamap); + dmamap = 0; /* don't free it twice! */ + } + kvpfree(dmap->kaddr, dmap->bytes / NBPP); + DEL(dmap); + dmap = 0; /* don't link this back into the list! */ + err = 0; /* "all done" */ + break; /* break outa for loop. */ + } + } + pciba_soft_unlock(soft); + break; /* break outa case PCIIOCDMAFREE: */ + } + break; /* break outa case PCIBA_SPACE_UDMA: */ + + case PCIIO_SPACE_CFG: + + /* PCIIOCCFG{RD,WR}: read and/or write + * PCI configuration space. If both, + * the read happens first (this becomes + * a swap operation, atomic with respect + * to other updates through this path). + * + * Should be *last* IOCTl command checked, + * so other patterns can nip useless codes + * out of the space this decodes. + */ + err = EINVAL; + if ((psize > 0) || (psize <= 8) && + (((cmd & 0xFF) + psize) <= 256) && + (cmd & (IOC_IN | IOC_OUT))) { + + uint64_t rdata; + uint64_t wdata; + int shft; + + shft = 64 - (8 * psize); + + wdata = arg.ud >> shft; + + pciba_soft_lock(soft); + + if (cmd & IOC_OUT) + rdata = pciio_config_get(soft->comm->conn, cmd & 0xFFFF, psize); + if (cmd & IOC_IN) + pciio_config_set(soft->comm->conn, cmd & 0xFFFF, psize, wdata); + + pciba_soft_unlock(soft); + + arg.ud = rdata << shft; + err = 0; + break; + } + break; + } + } + /* done: come here if all went OK. + */ + if ((err == 0) && + ((cmd & IOC_OUT) && (psize > 0)) && + copyout(arg.data, uarg, psize)) + err = EFAULT; + + /* This gets delayed until after the copyout so we + * do not free the dmap on a copyout error, or + * alternately end up with a dangling allocated + * buffer that the user never got back. + */ + if ((err == 0) && dmap) { + pciba_soft_lock(soft); + dmap->next = soft->comm->dmap; + soft->comm->dmap = dmap; + pciba_soft_unlock(soft); + } + if (err) { + /* Things went badly. Clean up. + */ +#if ULI + if (intr) { + pciio_intr_disconnect(intr); + pciio_intr_free(intr); + } + if (uli) + free_uli(uli); +#endif + if (dmap) { + if (dmap->map && (dmap->map != dmamap)) + pciio_dmamap_free(dmap->map); + DEL(dmap); + } + if (dmamap) + pciio_dmamap_free(dmamap); + if (kaddr) + kvpfree(kaddr, pages); + } + return *rvalp = err; +} + +/* ================================================================ + * mapping support + */ + +/*ARGSUSED */ +int +pciba_map(dev_t dev, vhandl_t *vt, + off_t off, size_t len, uint32_t prot) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + pciba_soft_t soft = pciba_soft_get(vhdl); + devfs_handle_t conn = soft->comm->conn; + pciio_space_t space = soft->space; + size_t pages = (len + NBPP - 1) / NBPP; + pciio_piomap_t pciio_piomap = 0; + caddr_t kaddr; + pciba_map_t map; + pciba_dma_t dmap; + +#if DEBUG_PCIBA + printf("pciba_map(%V,vt=0x%x)\n", dev, vt); +#endif + + if (space == PCIBA_SPACE_UDMA) { + pciba_soft_lock(soft); + + for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) { + if (off == dmap->daddr) { + if (pages != dmap->pages) { + pciba_soft_unlock(soft); + return EINVAL; /* "size mismatch" */ + } + v_mapphys(vt, dmap->kaddr, dmap->bytes); + dmap->handle = v_gethandle(vt); + pciba_soft_unlock(soft); +#if DEBUG_PCIBA + printf("pciba: mapped dma at kaddr 0x%x via handle 0x%x\n", + dmap->kaddr, dmap->handle); +#endif + return 0; + } + } + pciba_soft_unlock(soft); + return EINVAL; /* "block not found" */ + } + if (soft->iomem == PCIIO_SPACE_NONE) + return EINVAL; /* "mmap not supported" */ + + kaddr = (caddr_t) pciio_pio_addr + (conn, 0, space, off, len, &pciio_piomap, soft->flags | PCIIO_FIXED ); + +#if DEBUG_PCIBA + printf("pciba: mapped %R[0x%x..0x%x] via map 0x%x to kaddr 0x%x\n", + space, space_desc, off, off + len - 1, pciio_piomap, kaddr); +#endif + + if (kaddr == NULL) + return EINVAL; /* "you can't get there from here" */ + + NEW(map); + if (map == NULL) { + if (pciio_piomap) + pciio_piomap_free(pciio_piomap); + return ENOMEM; /* "unable to get memory resources */ + } +#ifdef LATER + map->uthread = curuthread; +#endif + map->handle = v_gethandle(vt); + map->uvaddr = v_getaddr(vt); + map->map = pciio_piomap; + map->space = soft->iomem; + map->base = soft->base + off; + map->size = len; + pciba_map_push(soft->comm->bus, map); + + /* Inform the system of the correct + * kvaddr corresponding to the thing + * that is being mapped. + */ + v_mapphys(vt, kaddr, len); + + return 0; +} + +/*ARGSUSED */ +int +pciba_unmap(dev_t dev, vhandl_t *vt) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + pciba_soft_t soft = pciba_soft_get(vhdl); + pciba_bus_t bus = soft->comm->bus; + pciba_map_t map; + __psunsigned_t handle = v_gethandle(vt); + +#if DEBUG_PCIBA + printf("pciba_unmap(%V,vt=%x)\n", dev, vt); +#endif + + /* If this is a userDMA buffer, + * make a note that it has been unmapped + * so it can be released. + */ + if (soft->comm->dmap) { + pciba_dma_t dmap; + + pciba_soft_lock(soft); + for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) + if (handle == dmap->handle) { + dmap->handle = 0; + pciba_soft_unlock(soft); +#if DEBUG_PCIBA + printf("pciba: unmapped dma at kaddr 0x%x via handle 0x%x\n", + dmap->kaddr, handle); +#endif + return 0; /* found userPCI */ + } + pciba_soft_unlock(soft); + } + map = pciba_map_pop_hdl(bus, handle); + if (map == NULL) + return EINVAL; /* no match */ + + if (map->map) + pciio_piomap_free(map->map); + DEL(map); + + return (0); /* all done OK */ +} + +#if ULI +void +pciba_clearuli(struct uli *uli) +{ + pciio_intr_t intr = (pciio_intr_t) uli->teardownarg1; + +#if DEBUG_PCIBA + printf("pciba_clearuli(0x%x)\n", uli); +#endif + + pciio_intr_disconnect(intr); + pciio_intr_free(intr); + atomic_dec(&pciba_prevent_unload); +} + +void +pciba_intr(intr_arg_t arg) +{ + struct uli *uli = (struct uli *) arg; + int ulinum = uli->index; + + extern void frs_handle_uli(void); + + if (ulinum >= 0 && ulinum < MAX_ULIS) { + uli_callup(ulinum); + + if (private.p_frs_flags) + frs_handle_uli(); + } +} +#endif +#endif /* LATER - undef as we implement each routine */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pcibr.c linux.ac/arch/ia64/sn/io/pcibr.c --- linux.vanilla/arch/ia64/sn/io/pcibr.c Tue Apr 3 17:31:54 2001 +++ linux.ac/arch/ia64/sn/io/pcibr.c Sat Apr 14 01:18:00 2001 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -41,6 +41,14 @@ #include #endif +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +#undef PCIBR_ATE_DEBUG #if defined(BRINGUP) #if 0 #define DEBUG 1 /* To avoid lots of bad printk() formats leave off */ @@ -54,6 +62,24 @@ #define LOCAL static #endif +/* + * Macros related to the Lucent USS 302/312 usb timeout workaround. It + * appears that if the lucent part can get into a retry loop if it sees a + * DAC on the bus during a pio read retry. The loop is broken after about + * 1ms, so we need to set up bridges holding this part to allow at least + * 1ms for pio. + */ + +#define USS302_TIMEOUT_WAR + +#ifdef USS302_TIMEOUT_WAR +#include +#define LUCENT_USBHC_VENDOR_ID_NUM 0x11c1 +#define LUCENT_USBHC302_DEVICE_ID_NUM 0x5801 +#define LUCENT_USBHC312_DEVICE_ID_NUM 0x5802 +#define USS302_BRIDGE_TIMEOUT_HLD 4 +#endif + #define PCIBR_LLP_CONTROL_WAR #if defined (PCIBR_LLP_CONTROL_WAR) int pcibr_llp_control_war_cnt; @@ -69,6 +95,7 @@ int pcibr_devflag = D_MP; +#ifdef LATER #define F(s,n) { 1l<<(s),-(s), n } struct reg_desc bridge_int_status_desc[] = @@ -246,6 +273,7 @@ {0} }; #endif +#endif /* LATER */ /* kbrick widgetnum-to-bus layout */ int p_busnum[MAX_PORT_NUM] = { /* widget# */ @@ -275,8 +303,8 @@ * CPU to a particular IO device are synched before the start of the next * set of PIO operations to the same device. */ -#define pcibr_lock(pcibr_soft) io_splock(pcibr_soft->bs_lock) -#define pcibr_unlock(pcibr_soft, s) io_spunlock(pcibr_soft->bs_lock,s) +#define pcibr_lock(pcibr_soft) io_splock(&pcibr_soft->bs_lock) +#define pcibr_unlock(pcibr_soft,s) io_spunlock(&pcibr_soft->bs_lock,s) #if PCIBR_SOFT_LIST typedef struct pcibr_list_s *pcibr_list_p; @@ -302,6 +330,31 @@ extern int hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags); #endif +extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); + +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +struct file_operations pcibr_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: NULL, + open: NULL, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL +}; extern devfs_handle_t hwgraph_root; extern graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl); @@ -317,7 +370,7 @@ extern struct map *rmallocmap(uint64_t mapsiz); extern void rmfreemap(struct map *mp); extern int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr); -extern void cmn_err_tag(int seqnumber, register int level, char *fmt, ...); +extern int io_path_map_widget(devfs_handle_t vertex); @@ -363,17 +416,13 @@ void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); -#ifndef BRINGUP LOCAL int pcibr_init_ext_ate_ram(bridge_t *); -#endif LOCAL int pcibr_ate_alloc(pcibr_soft_t, int); LOCAL void pcibr_ate_free(pcibr_soft_t, int, int); LOCAL pcibr_info_t pcibr_info_get(devfs_handle_t); LOCAL pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); LOCAL void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); -LOCAL int pcibr_device_attach(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_device_detach(devfs_handle_t,pciio_slot_t); LOCAL iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); @@ -411,7 +460,7 @@ devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void pcibr_intr_list_func(intr_arg_t); +void pcibr_intr_func(intr_arg_t); LOCAL void print_bridge_errcmd(uint32_t, char *); @@ -450,21 +499,32 @@ void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); void pcibr_hints_handsoff(devfs_handle_t); -void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); +void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); -LOCAL int pcibr_slot_reset(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); + +#ifdef LATER +LOCAL int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, + pcibr_slot_info_resp_t); +LOCAL void pcibr_slot_func_info_return(pcibr_info_h, int, + pcibr_slot_func_info_resp_t); +#endif /* LATER */ + LOCAL int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); LOCAL int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); LOCAL int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_call_device_attach(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_call_device_detach(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_call_device_attach(devfs_handle_t, + pciio_slot_t, int); +LOCAL int pcibr_slot_call_device_detach(devfs_handle_t, + pciio_slot_t, int); -int pcibr_slot_powerup(devfs_handle_t,pciio_slot_t); -int pcibr_slot_shutdown(devfs_handle_t,pciio_slot_t); -int pcibr_slot_inquiry(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); +LOCAL int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); +#ifdef LATER +LOCAL int pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t); +#endif /* ===================================================================== * RRB management @@ -754,7 +814,7 @@ int final_vchan0; int final_vchan1; int avail_rrbs; - unsigned s; + unsigned long s; int error; /* @@ -930,7 +990,7 @@ pciio_info_t pciio_info; pciio_slot_t pciio_slot; pcibr_soft_t pcibr_soft; - unsigned s; + unsigned long s; int error = -1; if ((pciio_info = pciio_info_get(pconn_vhdl)) && @@ -978,11 +1038,7 @@ int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) { devfs_handle_t pcibr_vhdl; -#ifdef colin - pcibr_soft_t pcibr_soft; -#else - pcibr_soft_t pcibr_soft = NULL; -#endif + pcibr_soft_t pcibr_soft = NULL; bridge_t *bridge = NULL; uint32_t rrb_setting = 0; @@ -991,7 +1047,7 @@ int dev_rrbs[4]; int virt[4]; int i, j; - unsigned s; + unsigned long s; if (GRAPH_SUCCESS == hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { @@ -1089,7 +1145,7 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; - unsigned s; + unsigned long s; reg_p rrbp; unsigned rrbm; int i; @@ -1141,7 +1197,7 @@ bridgereg_t badd32; bridgereg_t badd64; bridgereg_t fix; - unsigned s; + unsigned long s; bridgereg_t xmask; xmask = mask; @@ -1203,29 +1259,16 @@ /* Generic macro flags */ if (flags & PCIIO_DMA_DATA) { -#ifdef colin - new = new - & ~BRIDGE_DEV_BARRIER /* barrier off */ - | BRIDGE_DEV_PREF; /* prefetch on */ -#else new = (new & ~BRIDGE_DEV_BARRIER) /* barrier off */ | BRIDGE_DEV_PREF; /* prefetch on */ -#endif } if (flags & PCIIO_DMA_CMD) { -#ifdef colin - new = new - & ~BRIDGE_DEV_PREF /* prefetch off */ - & ~BRIDGE_DEV_WRGA_BITS /* write gather off */ - | BRIDGE_DEV_BARRIER; /* barrier on */ -#else new = ((new & ~BRIDGE_DEV_PREF) /* prefetch off */ & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ | BRIDGE_DEV_BARRIER; /* barrier on */ -#endif } /* Generic detail flags */ @@ -1297,13 +1340,8 @@ * but the alternative is not allowing * the new stream at all. */ -#ifdef colin - if (fix = bad & (BRIDGE_DEV_PRECISE | - BRIDGE_DEV_BARRIER)) { -#else if ( (fix = bad & (BRIDGE_DEV_PRECISE | BRIDGE_DEV_BARRIER)) ){ -#endif bad &= ~fix; /* don't change these bits if * they are already set in "old" @@ -1317,13 +1355,8 @@ * but the alternative is not allowing * the new stream at all. */ -#ifdef colin - if (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) { -#else if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) ){ -#endif + BRIDGE_DEV_PREF)) ) { bad &= ~fix; /* don't change these bits if * we wanted to turn them on. @@ -1379,7 +1412,7 @@ bridgereg_t mask) { pcibr_soft_slot_t slotp; - unsigned s; + unsigned long s; slotp = &pcibr_soft->bs_slot[slot]; @@ -1403,7 +1436,7 @@ pciio_slot_t slot) { bridge_t *bridge; - unsigned s; + unsigned long s; volatile uint32_t wrf; s = pcibr_lock(pcibr_soft); bridge = pcibr_soft->bs_base; @@ -1429,14 +1462,14 @@ { int rv; bridgereg_t old_enable, new_enable; + int badaddr_val(volatile void *, int, volatile void *); + old_enable = bridge->b_int_enable; new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; bridge->b_int_enable = new_enable; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#if defined(BRINGUP) /* * The xbridge doesn't clear b_err_int_view unless * multi-err is cleared... @@ -1445,8 +1478,6 @@ if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; } -#endif /* BRINGUP */ -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; @@ -1454,8 +1485,6 @@ } rv = badaddr_val((void *) cfg, 4, valp); -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#if defined(BRINGUP) /* * The xbridge doesn't set master timeout in b_int_status * here. Fortunately it's in error_interrupt_view. @@ -1465,8 +1494,6 @@ bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; rv = 1; /* unoccupied slot */ } -#endif /* BRINGUP */ -#endif /* CONFIG_SGI_IP35 */ bridge->b_int_enable = old_enable; bridge->b_wid_tflush; /* wait until Bridge PIO complete */ @@ -1514,10 +1541,6 @@ int pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) { -#ifndef CONFIG_IA64_SGI_IO - if (!_CAP_CRABLE((uint64_t)credp, (uint64_t)CAP_DEVICE_MGT)) - return EPERM; -#endif return 0; } @@ -1630,42 +1653,10 @@ return slot; } + /*========================================================================== * BRIDGE PCI SLOT RELATED IOCTLs */ -/* - * pcibr_slot_powerup - * Software initialize the pci slot. - */ -int -pcibr_slot_powerup(devfs_handle_t pcibr_vhdl,pciio_slot_t slot) -{ - /* Check for the valid slot */ - if (!PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - if (pcibr_device_attach(pcibr_vhdl,slot)) - return(EINVAL); - - return(0); -} -/* - * pcibr_slot_shutdown - * Software shutdown the pci slot - */ -int -pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl,pciio_slot_t slot) -{ - /* Check for valid slot */ - if (!PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - if (pcibr_device_detach(pcibr_vhdl,slot)) - return(EINVAL); - - return(0); -} - char *pci_space_name[] = {"NONE", "ROM", "IO", @@ -1683,177 +1674,163 @@ "", "BAD"}; + +#ifdef LATER + void -pcibr_slot_func_info_print(pcibr_info_h pcibr_infoh, int func, int verbose) +pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, + int func, + pcibr_slot_func_info_resp_t funcp) { - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; + pcibr_info_t pcibr_info = pcibr_infoh[func]; + int win; + funcp->resp_f_status = 0; + + if (!pcibr_info) { + return; + } + + funcp->resp_f_status |= FUNC_IS_VALID; #ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_vertex); -#endif - if (!verbose) { - printk("\tSlot Name : %s\n",name); - } else { - printk("\tPER-SLOT FUNCTION INFO\n"); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_vertex); + sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); +#else + sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex); #endif - printk("\tSlot Name : %s\n",name); - printk("\tPCI Bus : %d ",pcibr_info->f_bus); - printk("Slot : %d ", pcibr_info->f_slot); - printk("Function : %d\n", pcibr_info->f_func); + + if(is_sys_critical_vertex(pcibr_info->f_vertex)) { + funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; + } + + funcp->resp_f_bus = pcibr_info->f_bus; + funcp->resp_f_slot = pcibr_info->f_slot; + funcp->resp_f_func = pcibr_info->f_func; #ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_master); + sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master); +#else + sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master); #endif - printk("\tBus provider : %s\n",name); - printk("\tProvider Fns : 0x%p ", pcibr_info->f_pops); - printk("Error Handler : 0x%p Arg 0x%p\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); + funcp->resp_f_pops = pcibr_info->f_pops; + funcp->resp_f_efunc = pcibr_info->f_efunc; + funcp->resp_f_einfo = pcibr_info->f_einfo; + + funcp->resp_f_vendor = pcibr_info->f_vendor; + funcp->resp_f_device = pcibr_info->f_device; + + for(win = 0 ; win < 6 ; win++) { + funcp->resp_f_window[win].resp_w_base = + pcibr_info->f_window[win].w_base; + funcp->resp_f_window[win].resp_w_size = + pcibr_info->f_window[win].w_size; + sprintf(funcp->resp_f_window[win].resp_w_space, + "%s", + pci_space_name[pcibr_info->f_window[win].w_space]); } - printk("\tVendorId : 0x%x " , pcibr_info->f_vendor); - printk("DeviceId : 0x%x\n", pcibr_info->f_device); - printk("\n\tBase Register Info\n"); - printk("\t\tReg#\tBase\t\tSize\t\tSpace\n"); - for(win = 0 ; win < 6 ; win++) - printk("\t\t%d\t0x%lx\t%s0x%lx\t%s%s\n", - win, - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_base >= 0x100000 ? "": "\t", - pcibr_info->f_window[win].w_size, - pcibr_info->f_window[win].w_size >= 0x100000 ? "": "\t", - pci_space_name[pcibr_info->f_window[win].w_space]); - - printk("\t\t7\t0x%x\t%s0x%x\t%sROM\n", - pcibr_info->f_rbase, - pcibr_info->f_rbase > 0x100000 ? "" : "\t", - pcibr_info->f_rsize, - pcibr_info->f_rsize > 0x100000 ? "" : "\t"); + funcp->resp_f_rbase = pcibr_info->f_rbase; + funcp->resp_f_rsize = pcibr_info->f_rsize; - printk("\n\tInterrupt Bit Map\n"); - printk("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - printk("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - printk("\n"); -} + for (win = 0 ; win < 4; win++) { + funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win]; + } + funcp->resp_f_att_det_error = pcibr_info->f_att_det_error; -void -pcibr_slot_info_print(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - int verbose) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t b_resp; - reg_p b_respp; - int dev; - bridgereg_t b_int_device; - bridgereg_t b_int_host; - bridgereg_t b_int_enable; - int pin = 0; - int int_bits = 0; +} + +int +pcibr_slot_info_return(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + pcibr_slot_info_resp_t respp) +{ + pcibr_soft_slot_t pss; + int func; + bridge_t *bridge = pcibr_soft->bs_base; + reg_p b_respp; + pcibr_slot_info_resp_t slotp; + pcibr_slot_func_info_resp_t funcp; + + slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP); + if (slotp == NULL) { + return(ENOMEM); + } pss = &pcibr_soft->bs_slot[slot]; printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot); - if (verbose) { - printk("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - printk("\tHost Slot : %d\n",pss->host_slot); + slotp->resp_has_host = pss->has_host; + slotp->resp_host_slot = pss->host_slot; #ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(slot_conn_name, "%v", pss->slot_conn); + sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn); +#else + sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn); #endif - printk("\tSlot Conn : %s\n",slot_conn_name); - printk("\t#Functions : %d\n",pss->bss_ninfo); + slotp->resp_slot_status = pss->slot_status; + slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl); + + if (is_sys_critical_vertex(pss->slot_conn)) { + slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; } - for (func = 0; func < pss->bss_ninfo; func++) - pcibr_slot_func_info_print(pss->bss_infos,func, verbose); - printk("\tDevio[Space:%s,Base:0x%lx,Shadow:0x%x]\n", - pci_space_name[pss->bss_devio.bssd_space], - pss->bss_devio.bssd_base, - pss->bss_device); - - if (verbose) { - printk("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - printk("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - (unsigned int)pss->bss_d64_base, pss->bss_d64_flags, - (unsigned int)pss->bss_d32_base, pss->bss_d32_flags); - - printk("\tExt ATEs active ? %s", - pss->bss_ext_ates_active ? "yes" : "no"); - printk(" Command register : 0x%p ", pss->bss_cmd_pointer); - printk(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); + + slotp->resp_bss_ninfo = pss->bss_ninfo; + + for (func = 0; func < pss->bss_ninfo; func++) { + funcp = &(slotp->resp_func[func]); + pcibr_slot_func_info_return(pss->bss_infos, func, funcp); } - printk("\tSoft RRB Info[Valid %d+%d, Reserved %d]\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); + sprintf(slotp->resp_bss_devio_bssd_space, "%s", + pci_space_name[pss->bss_devio.bssd_space]); + slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base; + slotp->resp_bss_device = pss->bss_device; + slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr; + slotp->resp_bss_d32_uctr = pss->bss_d32_uctr; + slotp->resp_bss_d64_uctr = pss->bss_d64_uctr; - if (slot & 1) - b_respp = &bridge->b_odd_resp; - else - b_respp = &bridge->b_even_resp; + slotp->resp_bss_d64_base = pss->bss_d64_base; + slotp->resp_bss_d64_flags = pss->bss_d64_flags; + slotp->resp_bss_d32_base = pss->bss_d32_base; + slotp->resp_bss_d32_flags = pss->bss_d32_flags; - b_resp = *b_respp; + slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active); - printk("\n\tBridge RRB Info\n"); - printk("\t\tRRB#\tVirtual\n"); - for (dev = 0; dev < 8; dev++) { - if ((b_resp & BRIDGE_RRB_EN) && - (b_resp & BRIDGE_RRB_PDEV) == (slot >> 1)) - printk( "\t\t%d\t%s\n", - dev, - (b_resp & BRIDGE_RRB_VDEV) ? "yes" : "no"); - b_resp >>= 4; - - } - b_int_device = bridge->b_int_device; - b_int_enable = bridge->b_int_enable; + slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer; + slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow; - printk("\n\tBridge Interrupt Info\n" - "\t\tInt_device 0x%x\n\t\tInt_enable 0x%x " - "\n\t\tEnabled pin#s for this slot: ", - b_int_device, - b_int_enable); + slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot]; + slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]; + slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot]; - while (b_int_device) { - if (((b_int_device & 7) == slot) && - (b_int_enable & (1 << pin))) { - int_bits |= (1 << pin); - printk("%d ", pin); - } - pin++; - b_int_device >>= 3; + if (slot & 1) { + b_respp = &bridge->b_odd_resp; + } else { + b_respp = &bridge->b_even_resp; } - if (!int_bits) - printk("NONE "); + slotp->resp_b_resp = *b_respp; - b_int_host = bridge->b_int_addr[slot].addr; + slotp->resp_b_int_device = bridge->b_int_device; + slotp->resp_b_int_enable = bridge->b_int_enable; + slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; - printk("\n\t\tInt_host_addr 0x%x\n", - b_int_host); - + if (COPYOUT(slotp, respp, sizeof(*respp))) { + return(EFAULT); + } + + kmem_free(slotp, sizeof(*slotp)); + + return(0); } -int verbose = 0; /* - * pcibr_slot_inquiry - * Print information about the pci slot maintained by the infrastructure. - * Current information displayed + * pcibr_slot_query + * Return information about the PCI slot maintained by the infrastructure. + * Information is requested in the request structure. + * + * Information returned in the response structure: * Slot hwgraph name * Vendor/Device info * Base register info @@ -1861,7 +1838,6 @@ * Devio register * Software RRB info * RRB register info - * In verbose mode following additional info is displayed * Host/Gues info * PCI Bus #,slot #, function # * Slot provider hwgraph name @@ -1872,28 +1848,76 @@ * External SSRAM workaround info */ int -pcibr_slot_inquiry(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) +pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp) { - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pciio_slot_t slot = reqp->req_slot; + pciio_slot_t tmp_slot; + pcibr_slot_info_resp_t respp = (pcibr_slot_info_resp_t) reqp->req_respp; + int size = reqp->req_size; + int error; /* Make sure that we are dealing with a bridge device vertex */ - if (!pcibr_soft) - return(EINVAL); + if (!pcibr_soft) { + return(EINVAL); + } - /* Make sure that we have a valid pci slot number or PCIIO_SLOT_NONE */ - if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) - return(EINVAL); + /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ + if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) { + return(EINVAL); + } - /* Print information for the requested pci slot */ +#ifdef LATER + /* Do not allow a query of a slot in a shoehorn */ + if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { + return(EPERM); + } +#endif + + /* Return information for the requested PCI slot */ if (slot != PCIIO_SLOT_NONE) { - pcibr_slot_info_print(pcibr_soft,slot,verbose); - return(0); + if (size < sizeof(*respp)) { + return(EINVAL); + } + + /* Acquire read access to the slot */ + mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, slot, respp); + + /* Release the slot lock */ + mrunlock(pcibr_soft->bs_slot[slot].slot_lock); + + return(error); } - /* Print information for all the slots */ - for (slot = 0; slot < 8; slot++) - pcibr_slot_info_print(pcibr_soft, slot,verbose); - return(0); + + /* Return information for all the slots */ + for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) { + + if (size < sizeof(*respp)) { + return(EINVAL); + } + + /* Acquire read access to the slot */ + mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp); + + /* Release the slot lock */ + mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock); + + if (error) { + return(error); + } + + ++respp; + size -= sizeof(*respp); + } + + return(error); } +#endif /* LATER */ + /*ARGSUSED */ int @@ -1905,7 +1929,7 @@ int *rvalp) { devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); -#ifdef colin +#ifdef LATER pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); #endif int error = 0; @@ -1913,7 +1937,7 @@ hwgraph_vertex_unref(pcibr_vhdl); switch (cmd) { -#ifdef colin +#ifdef LATER case GIOCSETBW: { grio_ioctl_info_t info; @@ -1969,7 +1993,6 @@ pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); break; } -#endif /* colin */ case PCIBR_SLOT_POWERUP: { @@ -1985,31 +2008,33 @@ break; } case PCIBR_SLOT_SHUTDOWN: - { - pciio_slot_t slot; - if (!cap_able(CAP_DEVICE_MGT)) { error = EPERM; break; } slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_shutdown(pcibr_vhdl,slot); + error = pcibr_slot_powerup(pcibr_vhdl,slot); break; } - case PCIBR_SLOT_INQUIRY: + case PCIBR_SLOT_QUERY: { - pciio_slot_t slot; + struct pcibr_slot_info_req_s req; if (!cap_able(CAP_DEVICE_MGT)) { error = EPERM; break; } - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_inquiry(pcibr_vhdl,slot); + if (COPYIN(arg, &req, sizeof(req))) { + error = EFAULT; + break; + } + + error = pcibr_slot_query(pcibr_vhdl, &req); break; } +#endif /* LATER */ default: break; @@ -2055,7 +2080,6 @@ *free_basep = last + 1; /* keep upper chunk */ } -#ifdef IRIX /* Convert from ssram_bits in control register to number of SSRAM entries */ #define ATE_NUM_ENTRIES(n) _ate_info[n] @@ -2070,14 +2094,12 @@ #define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) #define ATE_PROBE_VALUE 0x0123456789abcdefULL -#endif /* IRIX */ /* * Determine the size of this bridge's external mapping SSRAM, and set * the control register appropriately to reflect this size, and initialize * the external SSRAM. */ -#ifndef BRINGUP LOCAL int pcibr_init_ext_ate_ram(bridge_t *bridge) { @@ -2087,9 +2109,6 @@ bridgereg_t old_enable, new_enable; int s; - if (is_xbridge(bridge)) - return 0; - /* Probe SSRAM to determine its size. */ old_enable = bridge->b_int_enable; new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; @@ -2116,11 +2135,9 @@ */ s = splhi(); -#ifdef colin bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); -#endif bridge->b_wid_control; /* inval addr bug war */ splx(s); @@ -2139,7 +2156,6 @@ return (num_entries); } -#endif /* !BRINGUP */ /* * Allocate "count" contiguous Bridge Address Translation Entries @@ -2155,6 +2171,7 @@ int index = 0; index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); +/* printk("Colin: pcibr_ate_alloc - index %d count %d \n", index, count); */ if (!index && pcibr_soft->bs_ext_ate_map) index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); @@ -2174,6 +2191,8 @@ /* note the "+1" since rmalloc handles 1..n but * we start counting ATEs at zero. */ +/* printk("Colin: pcibr_ate_free - index %d count %d\n", index, count); */ + rmfree((index < pcibr_soft->bs_int_ate_size) ? pcibr_soft->bs_int_ate_map : pcibr_soft->bs_ext_ate_map, @@ -2233,8 +2252,6 @@ /* * Record the info in the sparse func info space. */ -printk("pcibr_device_info_new: slot= %d func= %d bss_ninfo= %d pcibr_info= 0x%p\n", slot, func, pcibr_soft->bs_slot[slot].bss_ninfo, pcibr_info); - if (func < pcibr_soft->bs_slot[slot].bss_ninfo) pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; } @@ -2281,7 +2298,7 @@ slotp->bss_d32_flags = 0; /* Clear out shadow info necessary for the external SSRAM workaround */ - slotp->bss_ext_ates_active = 0; + slotp->bss_ext_ates_active = ATOMIC_INIT(0); slotp->bss_cmd_pointer = 0; slotp->bss_cmd_shadow = 0; @@ -2336,55 +2353,10 @@ pcibr_soft->bs_spinfo.pci_mem_last); /* - * pcibr_slot_reset - * Reset the pci device in the particular slot . - */ -int -pcibr_slot_reset(devfs_handle_t pcibr_vhdl,pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge; - bridgereg_t ctrlreg,tmp; - volatile bridgereg_t *wrb_flush; - - if (!PCIBR_VALID_SLOT(slot)) - return(1); - - if (!pcibr_soft) - return(1); - - /* Enable the DMA operations from this device of the xtalk widget - * (PCI host bridge in this case). - */ - xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot); - /* Set the reset slot bit in the bridge's wid control register - * to reset the pci slot - */ - bridge = pcibr_soft->bs_base; - /* Read the bridge widget control and clear out the reset pin - * bit for the corresponding slot. - */ - tmp = ctrlreg = bridge->b_wid_control; - tmp &= ~BRIDGE_CTRL_RST_PIN(slot); - bridge->b_wid_control = tmp; - tmp = bridge->b_wid_control; - /* Restore the old control register back. - * NOTE : pci card gets reset when the reset pin bit - * changes from 0 (set above) to 1 (going to be set now). - */ - bridge->b_wid_control = ctrlreg; - - /* Flush the write buffers if any !! */ - wrb_flush = &(bridge->b_wr_req_buf[slot].reg); - while (*wrb_flush); - - return(0); -} -/* * pcibr_slot_info_init * Probe for this slot and see if it is populated. - * If it is populated initialize the generic pci infrastructural - * information associated with this particular pci device. + * If it is populated initialize the generic PCI infrastructural + * information associated with this particular PCI device. */ int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, @@ -2401,6 +2373,9 @@ pciio_vendor_id_t vendor; pciio_device_id_t device; unsigned htype; +#if !defined(CONFIG_IA64_SGI_SN1) + int nbars; +#endif cfg_p wptr; int win; pciio_space_t space; @@ -2416,40 +2391,41 @@ /* Get the basic software information required to proceed */ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; if (!PCIBR_VALID_SLOT(slot)) - return(1); - - slotp = &pcibr_soft->bs_slot[slot]; - - /* Load the current values of allocated pci address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); + return(EINVAL); - /* If we have a host slot (eg:- IOC3 has 2 pci slots and the initialization + /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization * is done by the host slot then we are done. */ - if (pcibr_soft->bs_slot[slot].has_host) - return(0); + if (pcibr_soft->bs_slot[slot].has_host) { + return(0); + } + + /* Check for a slot with any system critical functions */ + if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); + + /* Load the current values of allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_LOAD(); /* Try to read the device-id/vendor-id from the config space */ cfgw = bridge->b_type0_cfg_dev[slot].l; -#ifdef BRINGUP - if (slot < 3 || slot == 7) - return (0); - else -#endif /* BRINGUP */ - if (pcibr_probe_slot(bridge, cfgw, &idword)) - return(0); + if (pcibr_probe_slot(bridge, cfgw, &idword)) + return(ENODEV); + + slotp = &pcibr_soft->bs_slot[slot]; + slotp->slot_status |= SLOT_POWER_UP; vendor = 0xFFFF & idword; /* If the vendor id is not valid then the slot is not populated * and we are done. */ - if (vendor == 0xFFFF) - return(0); /* next slot */ + if (vendor == 0xFFFF) + return(ENODEV); device = 0xFFFF & (idword >> 16); htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); @@ -2503,7 +2479,13 @@ if (htype != 0x00) { PRINT_WARNING("%s pcibr: pci slot %d func %d has strange header type 0x%x\n", pcibr_soft->bs_name, slot, func, htype); +#if defined(CONFIG_IA64_SGI_SN1) continue; +#else + nbars = 2; + } else { + nbars = PCI_CFG_BASE_ADDRS; +#endif } #if DEBUG && ATTACH_DEBUG PRINT_NOTICE( @@ -2516,13 +2498,17 @@ conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); if (func == 0) slotp->slot_conn = conn_vhdl; - + cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { +#if defined(CONFIG_IA64_SGI_SN1) + for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) +#else + for (win = 0; win < nbars; ++win) +#endif + { iopaddr_t base, mask, code; size_t size; @@ -2573,9 +2559,9 @@ base = wptr[((win*4)^4)/4]; #else base = wptr[win]; -#endif /* LITTLE_ENDIAN */ +#endif - if (base & 1) { + if (base & PCI_BA_IO_SPACE) { /* BASE is in I/O space. */ space = PCIIO_SPACE_IO; mask = -4; @@ -2590,7 +2576,7 @@ /* BASE is in MEM space. */ space = PCIIO_SPACE_MEM; mask = -16; - code = base & 15; + code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ base = base & mask; if (base == 0) { ; /* not assigned */ @@ -2697,37 +2683,30 @@ } /* next win */ } /* next func */ - /* Store back the values for allocated pci address spaces */ + /* Store back the values for allocated PCI address spaces */ PCI_ADDR_SPACE_LIMITS_STORE(); return(0); } /* * pcibr_slot_info_free - * Remove all the pci infrastructural information associated - * with a particular pci device. + * Remove all the PCI infrastructural information associated + * with a particular PCI device. */ int -pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; int nfunc; -#if defined(PCI_HOTSWAP_DEBUG) - cfg_p cfgw; - bridge_t *bridge; - int win; - cfg_p wptr; -#endif /* PCI_HOTSWAP_DEBUG */ - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); -#if defined(PCI_HOTSWAP_DEBUG) +#if !defined(CONFIG_IA64_SGI_SN1) /* Clean out all the base registers */ bridge = pcibr_soft->bs_base; cfgw = bridge->b_type0_cfg_dev[slot].l; @@ -2739,7 +2718,7 @@ #else wptr[win] = 0; #endif /* LITTLE_ENDIAN */ -#endif /* PCI_HOTSWAP_DEBUG */ +#endif /* !CONFIG_IA64_SGI_SN1 */ nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; @@ -2750,13 +2729,12 @@ pcibr_soft->bs_slot[slot].bss_ninfo = 0; return(0); - - } + int as_debug = 0; /* * pcibr_slot_addr_space_init - * Reserve chunks of pci address space as required by + * Reserve chunks of PCI address space as required by * the base registers in the card. */ int @@ -2772,38 +2750,40 @@ iopaddr_t pci_hi_fb, pci_hi_fl; size_t align; iopaddr_t mask; + int nbars; int nfunc; int func; int win; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; - /* Get the current values for the allocated pci address spaces */ + /* Get the current values for the allocated PCI address spaces */ PCI_ADDR_SPACE_LIMITS_LOAD(); if (as_debug) -#ifdef colin +#ifdef LATER PCI_ADDR_SPACE_LIMITS_PRINT(); #endif /* allocate address space, * for windows that have not been * previously assigned. */ - - if (pcibr_soft->bs_slot[slot].has_host) + if (pcibr_soft->bs_slot[slot].has_host) { return(0); + } nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; if (nfunc < 1) - return(0); + return(EINVAL); pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; if (!pcibr_infoh) - return(0); + return(EINVAL); /* * Try to make the DevIO windows not @@ -2842,7 +2822,16 @@ cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { +#if defined(CONFIG_IA64_SGI_SN1) + nbars = PCI_CFG_BASE_ADDRS; +#else + if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) + nbars = 2; + else + nbars = PCI_CFG_BASE_ADDRS; +#endif + + for (win = 0; win < nbars; ++win) { space = pcibr_info->f_window[win].w_space; base = pcibr_info->f_window[win].w_base; @@ -2908,7 +2897,9 @@ pcibr_info->f_window[win].w_base = base; #ifdef LITTLE_ENDIAN wptr[((win*4)^4)/4] = base; +#if DEBUG && PCI_DEBUG printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); +#endif #else wptr[win] = base; #endif /* LITTLE_ENDIAN */ @@ -2976,7 +2967,22 @@ * be sure are set. */ pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; - pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; + + /* + * The Adaptec 1160 FC Controller WAR #767995: + * The part incorrectly ignores the upper 32 bits of a 64 bit + * address when decoding references to it's registers so to + * keep it from responding to a bus cycle that it shouldn't + * we only use I/O space to get at it's registers. Don't + * enable memory space accesses on that PCI device. + */ + #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ + #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ + + if ((pcibr_info->f_vendor != FCADP_VENDID) || + (pcibr_info->f_device != FCADP_DEVID)) + pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; + pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; @@ -2991,28 +2997,30 @@ } /* next func */ - /* Now that we have allocated new chunks of pci address spaces to this + /* Now that we have allocated new chunks of PCI address spaces to this * card we need to update the bookkeeping values which indicate - * the current pci address space allocations. + * the current PCI address space allocations. */ PCI_ADDR_SPACE_LIMITS_STORE(); return(0); } + /* * pcibr_slot_device_init - * Setup the device register in the bridge for this pci slot. + * Setup the device register in the bridge for this PCI slot. */ int -pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { - pcibr_soft_t pcibr_soft; + pcibr_soft_t pcibr_soft; bridge_t *bridge; - bridgereg_t devreg; + bridgereg_t devreg; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; @@ -3036,13 +3044,13 @@ #if DEBUG && PCI_DEBUG printk("pcibr: PCI space allocation done.\n"); #endif - + return(0); } /* * pcibr_slot_guest_info_init - * Setup the host/guest relations for a pci slot. + * Setup the host/guest relations for a PCI slot. */ int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, @@ -3056,7 +3064,7 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); slotp = &pcibr_soft->bs_slot[slot]; @@ -3103,17 +3111,17 @@ return(0); } + /* * pcibr_slot_initial_rrb_alloc * Allocate a default number of rrbs for this slot on - * the two channels. This is dictated by the rrb allocation + * the two channels. This is dictated by the rrb allocation * strategy routine defined per platform. */ int -pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) - +pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; @@ -3123,16 +3131,17 @@ int r; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); bridge = pcibr_soft->bs_base; - /* How may RRBs are on this slot? */ c0 = do_pcibr_rrb_count_valid(bridge, slot); c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); + #if PCIBR_RRB_DEBUG printk("pcibr_attach: slot %d started with %d+%d\n", slot, c0, c1); #endif @@ -3149,7 +3158,7 @@ do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); pcibr_soft->bs_rrb_valid[slot] = 0x1000; pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; - return(0); + return(ENODEV); } pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; @@ -3173,17 +3182,19 @@ pcibr_soft->bs_rrb_res[slot]); printk("\n"); #endif + return(0); } /* * pcibr_slot_call_device_attach - * This calls the associated driver attach routine for the pci + * This calls the associated driver attach routine for the PCI * card in this slot. */ int -pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; @@ -3192,14 +3203,19 @@ int func; devfs_handle_t xconn_vhdl,conn_vhdl; int nfunc; + int error_func; + int error_slot = 0; + int error = ENODEV; pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + return(EINVAL); - if (pcibr_soft->bs_slot[slot].has_host) - return(0); + if (pcibr_soft->bs_slot[slot].has_host) { + return(EPERM); + } xconn_vhdl = pcibr_soft->bs_conn; aa = async_attach_get_info(xconn_vhdl); @@ -3207,8 +3223,6 @@ nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - printk("\npcibr_slot_call_device_attach: link 0x%p pci bus 0x%p slot %d\n", xconn_vhdl, pcibr_vhdl, slot); - for (func = 0; func < nfunc; ++func) { pcibr_info = pcibr_infoh[func]; @@ -3221,51 +3235,77 @@ conn_vhdl = pcibr_info->f_vertex; - /* If the pci device has been disabled in the prom, + /* If the PCI device has been disabled in the prom, * do not set it up for driver attach. NOTE: usrpci * and pciba will not "see" this connection point! */ if (device_admin_info_get(conn_vhdl, ADMIN_LBL_DISABLED)) { #ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING( "pcibr_slot_call_device_attach: %v disabled\n", + PRINT_WARNING("pcibr_slot_call_device_attach: %v disabled\n", conn_vhdl); #endif continue; } +#ifdef LATER + /* + * Activate if and when we support cdl. + */ if (aa) async_attach_add_info(conn_vhdl, aa); - pciio_device_attach(conn_vhdl); - } /* next func */ +#endif /* LATER */ - printk("\npcibr_slot_call_device_attach: DONE\n"); + error_func = pciio_device_attach(conn_vhdl, drv_flags); - return(0); + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + + } /* next func */ + + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; + } else { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; + } + + return(error); } + /* * pcibr_slot_call_device_detach - * This calls the associated driver detach routine for the pci + * This calls the associated driver detach routine for the PCI * card in this slot. */ int -pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; int func; - devfs_handle_t conn_vhdl; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; int nfunc; - int ndetach = 1; + int error_func; + int error_slot = 0; + int error = ENODEV; pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(1); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); if (pcibr_soft->bs_slot[slot].has_host) - return(0); - + return(EPERM); + + /* Make sure that we do not detach a system critical function vertex */ + if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; @@ -3281,94 +3321,120 @@ continue; conn_vhdl = pcibr_info->f_vertex; - - /* Make sure that we do not detach a system critical device - * vertex. - */ - if (is_sys_critical_vertex(conn_vhdl)) { -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING( "%v is a system critical device vertex\n", - conn_vhdl); -#endif - continue; - } - - ndetach = 0; - pciio_device_detach(conn_vhdl); + + error_func = pciio_device_detach(conn_vhdl, drv_flags); + + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + } /* next func */ + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - return(ndetach); + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; + } else { + if (conn_vhdl != GRAPH_VERTEX_NONE) + pcibr_device_unregister(conn_vhdl); + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; + } + + return(error); } /* - * pcibr_device_attach + * pcibr_slot_detach * This is a place holder routine to keep track of all the - * slot-specific initialization that needs to be done. - * This is usually called when we want to initialize a new - * pci card on the bus. + * slot-specific freeing that needs to be done. */ int -pcibr_device_attach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_slot_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) { - return ( - /* Reset the slot */ - pcibr_slot_reset(pcibr_vhdl,slot) || - /* FInd out what is out there */ - pcibr_slot_info_init(pcibr_vhdl,slot) || - - /* Set up the address space for this slot in the pci land */ - pcibr_slot_addr_space_init(pcibr_vhdl,slot) || - - /* Setup the device register */ - pcibr_slot_device_init(pcibr_vhdl, slot) || - - /* Setup host/guest relations */ - pcibr_slot_guest_info_init(pcibr_vhdl,slot) || - - /* Initial RRB management */ - pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot) || - - /* Call the device attach */ - pcibr_slot_call_device_attach(pcibr_vhdl,slot) - ); + int error; + + /* Call the device detach function */ + error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); + return (error); } + /* - * pcibr_device_detach - * This is a place holder routine to keep track of all the - * slot-specific freeing that needs to be done. + * pcibr_is_slot_sys_critical + * Check slot for any functions that are system critical. + * Return 1 if any are system critical or 0 otherwise. + * + * This function will always return 0 when called by + * pcibr_attach() because the system critical vertices + * have not yet been set in the hwgraph. */ int -pcibr_device_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) +pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) { - - /* Call the device detach */ - return (pcibr_slot_call_device_detach(pcibr_vhdl,slot)); + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + int nfunc; + int func; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(0); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + if (is_sys_critical_vertex(conn_vhdl)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("%v is a system critical device vertex\n", conn_vhdl); +#else + PRINT_WARNING("%p is a system critical device vertex\n", conn_vhdl); +#endif + return(1); + } + + } + return(0); } + /* * pcibr_device_unregister - * This frees up any hardware resources reserved for this pci device - * and removes any pci infrastructural information setup for it. - * This is usually used at the time of shutting down of the pci card. + * This frees up any hardware resources reserved for this PCI device + * and removes any PCI infrastructural information setup for it. + * This is usually used at the time of shutting down of the PCI card. */ -void +int pcibr_device_unregister(devfs_handle_t pconn_vhdl) { - pciio_info_t pciio_info; - devfs_handle_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; + pciio_info_t pciio_info; + devfs_handle_t pcibr_vhdl; + pciio_slot_t slot; + pcibr_soft_t pcibr_soft; bridge_t *bridge; + int error_call; + int error = 0; pciio_info = pciio_info_get(pconn_vhdl); - /* Detach the pciba name space */ - pciio_device_detach(pconn_vhdl); - pcibr_vhdl = pciio_info_master_get(pciio_info); slot = pciio_info_slot_get(pciio_info); @@ -3382,19 +3448,31 @@ pcibr_rrb_flush(pconn_vhdl); /* Free the rrbs allocated to this slot */ - do_pcibr_rrb_free(bridge, slot, - pcibr_soft->bs_rrb_valid[slot] + - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]); + error_call = do_pcibr_rrb_free(bridge, slot, + pcibr_soft->bs_rrb_valid[slot] + + pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]); + if (error_call) + error = ERANGE; pcibr_soft->bs_rrb_valid[slot] = 0; pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0; pcibr_soft->bs_rrb_res[slot] = 0; /* Flush the write buffers !! */ - (void)pcibr_wrb_flush(pconn_vhdl); + error_call = pcibr_wrb_flush(pconn_vhdl); + + if (error_call) + error = error_call; + /* Clear the information specific to the slot */ - (void)pcibr_slot_info_free(pcibr_vhdl, slot); + error_call = pcibr_slot_info_free(pcibr_vhdl, slot); + + if (error_call) + error = error_call; + + return(error); } @@ -3467,6 +3545,7 @@ return (rv == GRAPH_SUCCESS); } + /* * pcibr_attach: called every time the crosstalk * infrastructure is asked to initialize a widget @@ -3502,11 +3581,15 @@ iopaddr_t pci_hi_fb, pci_hi_fl; int spl_level; +#ifdef LATER char *nicinfo = (char *)0; +#endif #if PCI_FBBE int fast_back_to_back_enable; #endif + l1sc_t *scp; + nasid_t nasid; async_attach_t aa = NULL; @@ -3542,8 +3625,6 @@ NeedXbridgeSwap = 1; #endif - printk("pcibr_attach: Called with vertex 0x%p, b_wid_stat 0x%x, gio 0x%x\n",xconn_vhdl, bridge->b_wid_stat, BRIDGE_STAT_PCI_GIO_N); - /* * Create the vertex for the PCI bus, which we * will also use to hold the pcibr_soft and @@ -3558,8 +3639,14 @@ rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); ASSERT(rc == GRAPH_SUCCESS); - rc = hwgraph_char_device_add(pcibr_vhdl, EDGE_LBL_CONTROLLER, "pcibr_", &ctlr_vhdl); - ASSERT(rc == GRAPH_SUCCESS); + ctlr_vhdl = NULL; + ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &pcibr_fops, NULL); + + ASSERT(ctlr_vhdl != NULL); /* * decode the nic, and hang its stuff off our @@ -3606,6 +3693,10 @@ pcibr_soft->bs_xbridge = 0; } + nasid = NASID_GET(bridge); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; + pcibr_soft->bs_l1sc = scp; + pcibr_soft->bs_moduleid = iobrick_module_get(scp); pcibr_soft->bsi_err_intr = 0; /* Bridges up through REV C @@ -3660,7 +3751,7 @@ /* * Init bridge lock. */ - spinlock_init(&pcibr_soft->bs_lock, "pcibr_loc"); + spin_lock_init(&pcibr_soft->bs_lock); /* * If we have one, process the hints structure. @@ -3691,12 +3782,18 @@ pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_ext_ates_active = 0; + pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); } for (ibit = 0; ibit < 8; ++ibit) { pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_list = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = + &(bridge->b_int_status); + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; } /* @@ -3733,7 +3830,7 @@ iopaddr_t xbase; xwidgetnum_t xport; iopaddr_t offset; - int num_entries; + int num_entries = 0; int entry; cnodeid_t cnodeid; nasid_t nasid; @@ -3801,10 +3898,6 @@ dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; -#ifdef IRIX - dirmap |= BRIDGE_DIRMAP_RMF_64; -#endif - if (xbase) dirmap |= BRIDGE_DIRMAP_OFF & xbase; else if (offset >= (512 << 20)) @@ -3855,15 +3948,10 @@ * recomparing against BRIDGE_INTERNAL_ATES every * time. */ -#ifdef BRINGUP - /* - * 082799: for some reason pcibr_init_ext_ate_ram is causing - * a Data Bus Error. It should be zero anyway so just force it. - */ - num_entries = 0; -#else - num_entries = pcibr_init_ext_ate_ram(bridge); -#endif + if (is_xbridge(bridge)) + num_entries = 0; + else + num_entries = pcibr_init_ext_ate_ram(bridge); /* we always have 128 ATEs (512 for Xbridge) inside the chip * even if disabled for debugging. @@ -3947,7 +4035,6 @@ pcibr_soft->bsi_err_intr = xtalk_intr; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* * On IP35 with XBridge, we do some extra checks in pcibr_setwidint * in order to work around some addressing limitations. In order @@ -3955,9 +4042,6 @@ * start from a known clean state. */ pcibr_clearwidint(bridge); -#endif - - printk("pribr_attach: FIXME Error Interrupt not registered\n"); xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler, @@ -4054,13 +4138,13 @@ } #endif -#ifdef IRIX +#ifdef LATER /* If the bridge has been reset then there is no need to reset * the individual PCI slots. */ for (slot = 0; slot < 8; ++slot) /* Reset all the slots */ - (void)pcibr_slot_reset(pcibr_vhdl,slot); + (void)pcibr_slot_reset(pcibr_vhdl, slot); #endif for (slot = 0; slot < 8; ++slot) @@ -4075,6 +4159,7 @@ /* Setup the device register */ (void)pcibr_slot_device_init(pcibr_vhdl, slot); +#ifndef __ia64 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) for (slot = 0; slot < 8; ++slot) /* Set up convenience links */ @@ -4082,6 +4167,7 @@ if (pcibr_soft->bs_slot[slot].bss_ninfo > 0) /* if occupied */ pcibr_bus_cnvlink(pcibr_info->f_vertex, slot); #endif +#endif for (slot = 0; slot < 8; ++slot) /* Setup host/guest relations */ @@ -4091,12 +4177,34 @@ /* Initial RRB management */ (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); -#ifdef dagum /* driver attach routines should be called out from generic linux code */ for (slot = 0; slot < 8; ++slot) /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl,slot); -#endif /* dagum */ + (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); + + /* + * Each Pbrick PCI bus only has slots 1 and 2. Similarly for + * widget 0xe on Ibricks. Allocate RRB's accordingly. + */ + if (pcibr_soft->bs_moduleid > 0) { + switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { + case 'p': /* Pbrick */ + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + break; + case 'i': /* Ibrick */ + /* port 0xe on the Ibrick only has slots 1 and 2 */ + if (pcibr_soft->bs_xid == 0xe) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + } + else { + /* allocate one RRB for the serial port */ + do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); + } + break; + } /* switch */ + } #ifdef LATER if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { @@ -4119,13 +4227,13 @@ #endif } #else - printk("pcibr_attach: FIXME to call do_pcibr_rrb_autoalloc nicinfo 0x%p\n", nicinfo); + FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); #endif if (aa) async_attach_add_info(noslot_conn, aa); - pciio_device_attach(noslot_conn); + pciio_device_attach(noslot_conn, 0); /* @@ -4166,14 +4274,14 @@ printk("pcibr_device_detach called for %p/%d\n", pcibr_vhdl,slot); #endif - pcibr_device_detach(pcibr_vhdl, slot); + pcibr_slot_detach(pcibr_vhdl, slot, 0); } /* Unregister the no-slot connection point */ pciio_device_info_unregister(pcibr_vhdl, &(pcibr_soft->bs_noslot_info->f_c)); - spinlock_destroy(&pcibr_soft->bs_lock); + spin_lock_destroy(&pcibr_soft->bs_lock); kfree(pcibr_soft->bs_name); /* Error handler gets unregistered when the widget info is @@ -4264,7 +4372,7 @@ size_t msize; /* size of devio(x) mapped area on PCI */ size_t mmask; /* addr bits stored in Device(x) */ - unsigned s; + unsigned long s; s = pcibr_lock(pcibr_soft); @@ -4327,7 +4435,7 @@ if (wspace == PCIIO_SPACE_NONE) goto done; - /* get pci base and size */ + /* get PCI base and size */ wbase = pcibr_info->f_window[bar].w_base; wsize = pcibr_info->f_window[bar].w_size; @@ -4587,7 +4695,7 @@ pcibr_piomap_t pcibr_piomap; iopaddr_t xio_addr; xtalk_piomap_t xtalk_piomap; - unsigned s; + unsigned long s; /* Make sure that the req sizes are non-zero */ if ((req_size < 1) || (req_size_max < 1)) @@ -4631,7 +4739,7 @@ pcibr_piomap->bp_pciaddr = pci_addr; pcibr_piomap->bp_mapsz = req_size; pcibr_piomap->bp_soft = pcibr_soft; - pcibr_piomap->bp_toc[0] = 0; + pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); if (mapptr) { s = pcibr_lock(pcibr_soft); @@ -4733,7 +4841,7 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); pciio_piospace_t piosp; - int s; + unsigned long s; iopaddr_t *pciaddr, *pcilast; iopaddr_t start_addr; @@ -4751,7 +4859,7 @@ /* * First look if a previously allocated chunk exists. */ - if ((piosp = pcibr_info->f_piospace) != (pciio_piospace_t)0) { + if ((piosp = pcibr_info->f_piospace)) { /* * Look through the list for a right sized free chunk. */ @@ -4825,7 +4933,7 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; pciio_piospace_t piosp; - int s; + unsigned long s; char name[1024]; /* @@ -4901,7 +5009,7 @@ iopaddr_t attributes = 0; /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ -#ifdef IRIX +#ifdef LATER ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); #endif @@ -5031,7 +5139,16 @@ /* merge in forced flags */ flags |= pcibr_soft->bs_dma_flags; +#ifdef IRIX NEWf(pcibr_dmamap, flags); +#else + /* + * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() + * can be called within an interrupt thread. + */ + pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); +#endif + if (!pcibr_dmamap) return 0; @@ -5162,7 +5279,7 @@ pcibr_dmamap->bd_pci_addr = PCI32_MAPPED_BASE + IOPGSIZE * ate_index; /* - * for xbridge the byte-swap bit == bit 29 of pci address + * for xbridge the byte-swap bit == bit 29 of PCI address */ if (pcibr_soft->bs_xbridge) { if (flags & PCIIO_BYTE_STREAM) @@ -5201,7 +5318,7 @@ bridge_t *bridge = pcibr_soft->bs_base; volatile unsigned *cmd_regp; unsigned cmd_reg; - unsigned s; + unsigned long s; pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; @@ -5239,20 +5356,15 @@ pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; pciio_slot_t slot = pcibr_dmamap->bd_slot; -#ifdef IRIX unsigned flags = pcibr_dmamap->bd_flags; -#endif /* Make sure that bss_ext_ates_active * is properly kept up to date. */ -#ifdef IRIX + if (PCIBR_DMAMAP_BUSY & flags) if (PCIBR_DMAMAP_SSRAM & flags) - atomicAddInt(&(pcibr_soft-> - bs_slot[slot]. - bss_ext_ates_active), -1); -#endif + atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); @@ -5265,7 +5377,9 @@ pcibr_dmamap->bd_ate_count); pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); } +#ifdef IRIX DEL(pcibr_dmamap); +#endif } /* @@ -5325,7 +5439,6 @@ /* We are starting to get more complexity * surrounding writing ATEs, so pull * the writing code into this new function. - * XXX mail ranga@engr for IP27 prom! */ #if PCIBR_FREEZE_TIME @@ -5342,13 +5455,13 @@ unsigned *cmd_regs) { pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef IRIX +#ifdef LATER int dma_slot = pcibr_dmamap->bd_slot; #endif int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; int slot; - unsigned s; + unsigned long s; unsigned cmd_reg; volatile unsigned *cmd_lwa; unsigned cmd_lwd; @@ -5371,27 +5484,22 @@ */ s = pcibr_lock(pcibr_soft); -#ifdef IRIX +#ifdef LATER /* just in case pcibr_dmamap_done was not called */ if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomicAddInt(&(pcibr_soft-> - bs_slot[dma_slot]. - bss_ext_ates_active), -1); + atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); } -#endif +#endif /* LATER */ #if PCIBR_FREEZE_TIME *freeze_time_ptr = get_timestamp(); #endif cmd_lwa = 0; for (slot = 0; slot < 8; ++slot) - if (pcibr_soft-> - bs_slot[slot]. - bss_ext_ates_active) { - + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { cmd_reg = pcibr_soft-> bs_slot[slot]. bss_cmd_shadow; @@ -5418,9 +5526,7 @@ /* Flush all the write buffers in the bridge */ for (slot = 0; slot < 8; ++slot) - if (pcibr_soft-> - bs_slot[slot]. - bss_ext_ates_active) { + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { /* Flush the write buffer associated with this * PCI device which might be using dma map RAM. */ @@ -5462,9 +5568,7 @@ unsigned s) { pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef IRIX int dma_slot = pcibr_dmamap->bd_slot; -#endif int slot; bridge_t *bridge = pcibr_soft->bs_base; int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; @@ -5486,11 +5590,7 @@ bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; -#ifdef IRIX - atomicAddInt(&(pcibr_soft-> - bs_slot[dma_slot]. - bss_ext_ates_active), 1); -#endif + atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); #if PCIBR_FREEZE_TIME freeze_time = get_timestamp() - freeze_time_start; @@ -5685,11 +5785,7 @@ unsigned flags) { pcibr_soft_t pcibr_soft; -#ifdef IRIX - bridge_t *bridge; -#else bridge_t *bridge=NULL; -#endif unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; int inplace = flags & PCIIO_INPLACE; @@ -5699,19 +5795,11 @@ size_t length; iopaddr_t offset; unsigned direct64; -#ifdef IRIX - int ate_index; - int ate_count; - int ate_total = 0; - bridge_ate_p ate_ptr; - bridge_ate_t ate_proto; -#else int ate_index = 0; int ate_count = 0; int ate_total = 0; bridge_ate_p ate_ptr = (bridge_ate_p)0; bridge_ate_t ate_proto = (bridge_ate_t)0; -#endif bridge_ate_t ate_prev; bridge_ate_t ate; alenaddr_t xio_addr; @@ -5899,16 +5987,12 @@ * between _addr/_list and _done, but Hub does. */ -#ifdef IRIX if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomicAddInt(&(pcibr_dmamap->bd_soft-> - bs_slot[pcibr_dmamap->bd_slot]. - bss_ext_ates_active), -1); + atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); } -#endif xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); } @@ -6332,11 +6416,7 @@ */ if (xio_port == pcibr_soft->bs_xid) { pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); -#ifdef IRIX - if (pci_addr == NULL) -#else if ( (pci_addr == (alenaddr_t)NULL) ) -#endif goto fail; } else if (direct64) { ASSERT(xio_port != 0); @@ -6371,11 +6451,7 @@ } } -#ifdef IRIX - if (relbits) -#else if (relbits) { -#endif if (direct64) { slotp->bss_d64_flags = flags; slotp->bss_d64_base = pci_base; @@ -6383,9 +6459,7 @@ slotp->bss_d32_flags = flags; slotp->bss_d32_base = pci_base; } -#ifndef IRIX } -#endif if (!inplace) alenlist_done(xtalk_alenlist); @@ -6480,26 +6554,155 @@ return bbits; } -#ifdef IRIX + +/* + * Get the next wrapper pointer queued in the interrupt circular buffer. + */ +#ifdef KERNEL_THREADS +pcibr_intr_wrap_t +pcibr_wrap_get(pcibr_intr_cbuf_t cbuf) +{ + pcibr_intr_wrap_t wrap; + + if (cbuf->ib_in == cbuf->ib_out) + PRINT_PANIC("pcibr intr circular buffer empty, cbuf=0x%x, ib_in=ib_out=%d\n", + cbuf, cbuf->ib_out); + + wrap = cbuf->ib_cbuf[cbuf->ib_out++]; + cbuf->ib_out = cbuf->ib_out % IBUFSIZE; + return(wrap); +} + +/* + * Queue a wrapper pointer in the interrupt circular buffer. + */ +void +pcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf) +{ + int in; + unsigned long s; + + /* + * Multiple CPUs could be executing this code simultaneously + * if a handler has registered multiple interrupt lines and + * the interrupts are directed to different CPUs. + */ + s = mutex_spinlock(&cbuf->ib_lock); + in = (cbuf->ib_in + 1) % IBUFSIZE; + if (in == cbuf->ib_out) + PRINT_PANIC("pcibr intr circular buffer full, cbuf=0x%x, ib_in=%d\n", + cbuf, cbuf->ib_in); + + cbuf->ib_cbuf[cbuf->ib_in] = wrap; + cbuf->ib_in = in; + mutex_spinunlock(&cbuf->ib_lock, s); + return; +} +#endif /* KERNEL_THREADS */ + +/* + * There are end cases where a deadlock can occur if interrupt + * processing completes and the Bridge b_int_status bit is still set. + * + * One scenerio is if a second PCI interrupt occurs within 60ns of + * the previous interrupt being cleared. In this case the Bridge + * does not detect the transition, the Bridge b_int_status bit + * remains set, and because no transition was detected no interrupt + * packet is sent to the Hub/Heart. + * + * A second scenerio is possible when a b_int_status bit is being + * shared by multiple devices: + * Device #1 generates interrupt + * Bridge b_int_status bit set + * Device #2 generates interrupt + * interrupt processing begins + * ISR for device #1 runs and + * clears interrupt + * Device #1 generates interrupt + * ISR for device #2 runs and + * clears interrupt + * (b_int_status bit still set) + * interrupt processing completes + * + * Interrupt processing is now complete, but an interrupt is still + * outstanding for Device #1. But because there was no transition of + * the b_int_status bit, no interrupt packet will be generated and + * a deadlock will occur. + * + * To avoid these deadlock situations, this function is used + * to check if a specific Bridge b_int_status bit is set, and if so, + * cause the setting of the corresponding interrupt bit. + * + * On a XBridge (IP35), we do this by writing the appropriate Bridge Force + * Interrupt register. + */ +void +pcibr_force_interrupt(pcibr_intr_wrap_t wrap) +{ + unsigned bit; + pcibr_soft_t pcibr_soft = wrap->iw_soft; + bridge_t *bridge = pcibr_soft->bs_base; + cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); + + bit = wrap->iw_intr; + + if (pcibr_soft->bs_xbridge) { + bridge->b_force_pin[bit].intr = 1; + } else if ((1 << bit) & *wrap->iw_stat) { + cpuid_t cpu; + unsigned intr_bit; + xtalk_intr_t xtalk_intr = + pcibr_soft->bs_intr[bit].bsi_xtalk_intr; + + intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); + cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); + REMOTE_CPU_SEND_INTR(cpu, intr_bit); + } +} + /* Wrapper for pcibr interrupt threads. */ +#ifdef KERNEL_THREADS static void pcibr_intrd(pcibr_intr_t intr) { + pcibr_intr_wrap_t wrap; + /* Called on each restart */ ASSERT(cpuid() == intr->bi_mustruncpu); #ifdef ITHREAD_LATENCY - xthread_update_latstats(intr->bi_tinfo->thd_latstats); + xthread_update_latstats(intr->bi_tinfo.thd_latstats); #endif /* ITHREAD_LATENCY */ ASSERT(intr->bi_func != NULL); intr->bi_func(intr->bi_arg); /* Invoke the interrupt handler */ + /* + * The pcibr_intrd thread needs access to the wrapper struct + * specific to the current interrupt it is processing. Because + * multiple calls/wakeups to the thread could be queued, each + * potentially from a different interrupt line (PCIIO_INTR_LINE_A, + * etc), multiple wrapper struct pointers need to be queued. This + * is done via a circular buffer of wrapper struct pointers. + */ + wrap = pcibr_wrap_get(&intr->bi_ibuf); + + /* + * The interrupt handler has completed. Now decrement the running + * count tracking the number of handlers still running for this line. + * If this was the last handler to complete (i.e., iw_hdlrcnt == 0), + * avoid a potential deadlock condition and ensure that another + * interrupt will occur if the Bridge b_int_status bit is still + * set. + */ + atomicAddInt(&(wrap->iw_hdlrcnt), -1); + if (wrap->iw_hdlrcnt == 0) + pcibr_force_interrupt(wrap); + ipsema(&intr->bi_tinfo.thd_isync); /* Sleep 'till next interrupt */ /* NOTREACHED */ } - static void pcibr_intrd_start(pcibr_intr_t intr) { @@ -6519,14 +6722,16 @@ char thread_name[32]; sprintf(thread_name, "pcibr_intrd[0x%x]", bridge_levels); + thread_name[IT_NAMELEN-1] = '\0'; /* XXX need to adjust priority whenever an interrupt is connected */ + intr->bi_tinfo.thd_pri = intr_swlevel; atomicSetInt(&intr->bi_tinfo.thd_flags, THD_ISTHREAD | THD_REG); xthread_setup(thread_name, intr_swlevel, &intr->bi_tinfo, (xt_func_t *)pcibr_intrd_start, (void *)intr); } -#endif /* IRIX */ +#endif /* KERNEL_THREADS */ @@ -6542,13 +6747,16 @@ pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; bridge_t *bridge = pcibr_soft->bs_base; - int is_threaded; + int is_threaded = 0; +#ifdef KERNEL_THREADS + cpuid_t mustruncpu = CPU_NONE; + cpuid_t old_intrcpu = CPU_NONE; +#endif int thread_swlevel; xtalk_intr_t *xtalk_intr_p; pcibr_intr_t *pcibr_intr_p; pcibr_intr_list_t *intr_list_p; - pcibr_intr_wrap_t *intr_wrap_p; unsigned pcibr_int_bits; unsigned pcibr_int_bit; @@ -6557,7 +6765,6 @@ pcibr_intr_t pcibr_intr; pcibr_intr_list_t intr_entry; pcibr_intr_list_t intr_list; - pcibr_intr_wrap_t intr_wrap; bridgereg_t int_dev; #if DEBUG && INTR_DEBUG @@ -6576,9 +6783,29 @@ return NULL; if (dev_desc) { + cpuid_t intr_target_from_desc(device_desc_t, int); + +#ifdef KERNEL_THREADS is_threaded = !(device_desc_flags_get(dev_desc) & D_INTR_NOTHREAD); - if (is_threaded) + if (is_threaded) { + /* + * If the device descriptor contains interrupt target info, + * save the CPU requested. This is the CPU the pcibr_intrd + * thread will be set to run on. + * + * We need to get the interrupt target info at this time, because + * the original intr_target value can be overwritten, as part of + * the xtalk_intr_alloc_nothd() call, with the actual interrupt CPU. + * This can be different than the requested CPU if the lower layers + * could not direct the hardware interrupt to the requested CPU. + * Regardless of which CPU processes the hardware interrupt, the + * ISR thread will still be setup to run on the CPU originally + * requested. + */ + mustruncpu = intr_target_from_desc(dev_desc, SUBNODE_ANY); thread_swlevel = device_desc_intr_swlevel_get(dev_desc); + } +#endif /* KERNEL_THREADS */ } else { extern int default_intr_pri; @@ -6594,6 +6821,11 @@ pcibr_intr->bi_arg = 0; /* unset until connect */ pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; pcibr_intr->bi_mustruncpu = CPU_NONE; +#ifdef KERNEL_THREADS + pcibr_intr->bi_ibuf.ib_in = 0; + pcibr_intr->bi_ibuf.ib_out = 0; +#endif + mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); @@ -6626,7 +6858,17 @@ * single Bridge. (IP35-specific code forces this, and we * verify in pcibr_setwidint.) */ - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, owner_dev); + + /* + * All code dealing with threaded PCI interrupt handlers + * is located at the pcibr level. Because of this, + * we always want the lower layers (hub/heart_intr_alloc, + * intr_level_connect) to treat us as non-threaded so we + * don't set up a duplicate threaded environment. We make + * this happen by calling a special xtalk interface. + */ + xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, + owner_dev); #if DEBUG && INTR_DEBUG printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); #endif @@ -6690,32 +6932,64 @@ } } - /* - * For threaded drivers, set the interrupt thread to run wherever - * the interrupt is targeted. - */ -#ifdef notyet +#ifdef KERNEL_THREADS if (is_threaded) { - cpuid_t old_mustrun = pcibr_intr->bi_mustruncpu; - pcibr_intr->bi_mustruncpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); - ASSERT(pcibr_intr->bi_mustruncpu >= 0); + cpuid_t intrcpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); /* - * This is possible, but very unlikely: It means that 2 (or more) interrupts - * originating on a single Bridge and used by a single device were unable to - * find sufficient xtalk interrupt resources that would allow them all to be - * handled by the same CPU. If someone tries to target lots of interrupts to - * a single CPU, we might hit this case. Things should still operate correctly, - * but it's a sub-optimal configuration. + * It is possible that 2 (or more) interrupts originating on a + * single Bridge and used by a single device were assigned to + * different CPUs. If this occurs issue a warning message for + * this sub-optimal configuration. There are two ways this + * could happen: + * + * - There were insufficient xtalk interrupt resources to + * allow all interrupts to be assigned to the same CPU. + * This is an unlikely case, but could happen if someone + * tries to target a lot of interrupts to a single CPU. + * + * - If there is no device descriptor associated with this + * device, the xtalk/hub/heart layers will not know to + * assign the same CPU to any additional interrupts this + * driver has specified, and will perform the normal load + * leveling of interrupts across CPUs. + * (The lower layers store the CPU assigned to the first + * interrupt in the device desc, if present, and then when + * called again for additional interrupts for the same device, + * use this information to assign the same CPU to these + * interrupts.) */ - if ((old_mustrun != CPU_NONE) && (old_mustrun != pcibr_intr->bi_mustruncpu)) { -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING( "Conflict on where to schedule interrupts for %v\n", pconn_vhdl); + if ((old_intrcpu != CPU_NONE) && (old_intrcpu != intrcpu)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_WARNING("Conflict on where to schedule interrupts for %v\n", pconn_vhdl); +#else + PRINT_WARNING("Conflict on where to schedule interrupts for 0x%x\n", pconn_vhdl); #endif - PRINT_WARNING( "(on cpu %d or on cpu %d)\n", old_mustrun, pcibr_intr->bi_mustruncpu); + PRINT_WARNING("(on cpu %d or on cpu %d), cpu %d used\n", old_intrcpu, intrcpu, intrcpu); + } + if (old_intrcpu == CPU_NONE) + old_intrcpu = intrcpu; + /* + * For threaded drivers, set the interrupt thread to run wherever + * the interrupt is targeted, or where requested in the dev_desc. + */ + if (mustruncpu != CPU_NONE) { + pcibr_intr->bi_mustruncpu = mustruncpu; + if (mustruncpu != intrcpu) { + PRINT_WARNING("Request to target PCI interrupts to CPU %d could not\n" + " be satisfied, CPU %d used. However, interrupt thread\n" + " pcibr_intrd will run on CPU %d as requested.\n" + " %v (0x%x)\n", + mustruncpu, intrcpu, mustruncpu, owner_dev, + owner_dev); + } + } else { + pcibr_intr->bi_mustruncpu = intrcpu; } + ASSERT(pcibr_intr->bi_mustruncpu >= 0); + } -#endif +#endif /* KERNEL_THREADS */ pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; @@ -6723,8 +6997,20 @@ intr_entry->il_next = NULL; intr_entry->il_intr = pcibr_intr; intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); + intr_list_p = + &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; +#if DEBUG && INTR_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("0x%x: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#else + printk("%v: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#endif +#endif - intr_list_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_list; if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* we are the first interrupt on this bridge bit. */ @@ -6751,29 +7037,12 @@ intr_list_p = &intr_list->il_next; if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* we are the new second interrupt on this bit. - * switch to local wrapper. */ + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; #if DEBUG && INTR_DEBUG printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", pconn_vhdl, pcibr_int_bits, pcibr_int_bit); #endif - NEW(intr_wrap); - intr_wrap->iw_soft = pcibr_soft; - intr_wrap->iw_stat = &(bridge->b_int_status); - intr_wrap->iw_intr = 1 << pcibr_int_bit; - intr_wrap->iw_list = intr_list; - intr_wrap_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (!compare_and_swap_ptr((void **) intr_wrap_p, NULL, intr_wrap)) { - /* someone else set up the wrapper. - */ - DEL(intr_wrap); - continue; -#if DEBUG && INTR_DEBUG - } else { - printk("%v bridge bit %d wrapper state created\n", - pconn_vhdl, pcibr_int_bit); -#endif - } continue; } while (1) { @@ -6807,13 +7076,13 @@ } } -#ifdef IRIX +#ifdef KERNEL_THREADS if (is_threaded) { /* Set pcibr_intr->bi_tinfo */ pcibr_thread_setup(pcibr_intr, pcibr_int_bits, thread_swlevel); ASSERT(!(pcibr_intr->bi_flags & PCIIO_INTR_CONNECTED)); } -#endif +#endif /* KERNEL_THREADS */ #if DEBUG && INTR_DEBUG printk("%v pcibr_intr_alloc complete\n", pconn_vhdl); @@ -6832,13 +7101,13 @@ pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; unsigned pcibr_int_bit; pcibr_intr_list_t intr_list; - pcibr_intr_wrap_t intr_wrap; + int intr_shared; xtalk_intr_t *xtalk_intrp; for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { if (pcibr_int_bits & (1 << pcibr_int_bit)) { for (intr_list = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_list; + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; intr_list != NULL; intr_list = intr_list->il_next) if (compare_and_swap_ptr((void **) &intr_list->il_intr, @@ -6852,10 +7121,11 @@ /* If this interrupt line is not being shared between multiple * devices release the xtalk interrupt resources. */ - intr_wrap = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; + intr_shared = + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - if ((intr_wrap == NULL) && (*xtalk_intrp)) { + + if ((!intr_shared) && (*xtalk_intrp)) { bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t int_dev; @@ -6900,7 +7170,7 @@ unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; bridgereg_t b_int_enable; - unsigned s; + unsigned long s; if (pcibr_intr == NULL) return -1; @@ -6924,59 +7194,29 @@ if (pcibr_int_bits & (1 << pcibr_int_bit)) { pcibr_intr_wrap_t intr_wrap; xtalk_intr_t xtalk_intr; - int *setptr; xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - /* if we have no wrap structure, - * tell xtalk to deliver the interrupt - * directly to the client. + intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; + /* + * If this interrupt line is being shared and the connect has + * already been done, no need to do it again. */ - intr_wrap = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (intr_wrap == NULL) { - xtalk_intr_connect(xtalk_intr, - (intr_func_t) intr_func, - (intr_arg_t) intr_arg, - (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), - thread); -#if DEBUG && INTR_DEBUG - printk("%v bridge bit %d routed by xtalk\n", - pcibr_intr->bi_dev, pcibr_int_bit); -#endif + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) continue; - } - - setptr = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set; - if (*setptr) - continue; - - /* We have a wrap structure, so we're sharing a Bridge interrupt level */ - - xtalk_intr_disconnect(xtalk_intr); /* Disconnect old interrupt */ /* - If the existing xtalk_intr was allocated without the NOTHREAD flag, - we need to allocate a new one that's NOTHREAD, and connect to the - new one. pcibr_intr_list_func expects to run at interrupt level - rather than in a thread. With today's devices, this can't happen, - so let's punt on writing the code till we need it (probably never). - Instead, just ASSERT that we're a NOTHREAD xtalk_intr. - */ -#ifdef IRIX - ASSERT_ALWAYS(!(pcibr_intr->bi_flags & PCIIO_INTR_NOTHREAD) || - xtalk_intr_flags_get(xtalk_intr) & XTALK_INTR_NOTHREAD); -#endif - - /* Use the wrapper dispatch function to handle shared Bridge interrupts */ + * Use the pcibr wrapper function to handle all Bridge interrupts + * regardless of whether the interrupt line is shared or not. + */ xtalk_intr_connect(xtalk_intr, - pcibr_intr_list_func, + pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t) pcibr_setpciint, (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), 0); - *setptr = 1; + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; #if DEBUG && INTR_DEBUG printk("%v bridge bit %d wrapper connected\n", @@ -7001,9 +7241,9 @@ bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; - pcibr_intr_wrap_t intr_wrap; + pcibr_intr_wrap_t intr_wrap; bridgereg_t b_int_enable; - unsigned s; + unsigned long s; /* Stop calling the function. Now. */ @@ -7021,7 +7261,7 @@ */ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if ((pcibr_int_bits & (1 << pcibr_int_bit)) && - (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set)) + (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) pcibr_int_bits &= ~(1 << pcibr_int_bit); if (!pcibr_int_bits) return; @@ -7035,26 +7275,32 @@ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) { - /* if we have set up the share wrapper, + /* if the interrupt line is now shared, * do not disconnect it. */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set) + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; + +#if DEBUG && INTR_DEBUG + printk("%s: xtalk disconnect done for Bridge bit %d\n", + pcibr_soft->bs_name, pcibr_int_bit); +#endif - /* if we have a share wrapper state, + /* if we are sharing the interrupt line, * connect us up; this closes the hole - * where the connection of the wrapper + * where the another pcibr_intr_alloc() * was in progress as we disconnected. */ - intr_wrap = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (intr_wrap == NULL) + intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; + if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, - pcibr_intr_list_func, + pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t) pcibr_setpciint, (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), @@ -7168,7 +7414,7 @@ bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; } else { - /* routing a pci device interrupt. + /* routing a PCI device interrupt. * targ and low 38 bits of addr must * be the same as the already set * value for the widget error interrupt. @@ -7187,46 +7433,71 @@ bridge->b_wid_tflush; /* wait until Bridge PIO complete */ } + +/* + * pcibr_intr_func() + * + * This is the pcibr interrupt "wrapper" function that is called, + * in interrupt context, to initiate the interrupt handler(s) registered + * (via pcibr_intr_alloc/connect) for the occuring interrupt. Non-threaded + * handlers will be called directly, and threaded handlers will have their + * thread woken up. + */ void -pcibr_intr_list_func(intr_arg_t arg) +pcibr_intr_func(intr_arg_t arg) { pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; - reg_p statp = wrap->iw_stat; - bridgereg_t mask = wrap->iw_intr; reg_p wrbf; - pcibr_intr_list_t list; - pcibr_intr_t intr; intr_func_t func; + pcibr_intr_t intr; + pcibr_intr_list_t list; int clearit; - int thread_count = 0; +#ifdef KERNEL_THREADS + int do_nonthreaded = 0; + int do_threaded = 1; + int is_threaded = 0; +#else + int do_nonthreaded = 1; + int do_threaded = 0; + int is_threaded = 0; +#endif + int nonthreaded_count = 0; + int x = 0; + + /* + * If any handler is still running from a previous interrupt + * just return. If there's a need to call the handler(s) again, + * another interrupt will be generated either by the device or by + * pcibr_force_interrupt(). + */ + + if (wrap->iw_hdlrcnt) { + return; + } /* - * Loop until either - * 1) All interrupts have been removed by direct-called interrupt handlers OR - * 2) We've woken up at least one interrupt thread that will presumably clear - * Bridge interrupt bits + * Call all interrupt handlers registered. + * First, the pcibr_intrd threads for any threaded handlers will be + * awoken, then any non-threaded handlers will be called sequentially. */ - while ((!thread_count) && (mask & *statp)) { clearit = 1; - for (list = wrap->iw_list; - list != NULL; - list = list->il_next) { - if ((intr = list->il_intr) && - (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - int is_threaded; + while (do_threaded || do_nonthreaded) { + for (list = wrap->iw_list; list != NULL; list = list->il_next) { + if ((intr = list->il_intr) && + (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - ASSERT(intr->bi_func); + ASSERT(intr->bi_func); /* * This device may have initiated write * requests since the bridge last saw * an edge on this interrupt input; flushing - * the buffer here should help but may not - * be sufficient if we get more requests after - * the flush, followed by the card deciding - * it wants service, before the interrupt - * handler checks to see if things need + * the buffer prior to invoking the handler + * should help but may not be sufficient if we + * get more requests after the flush, followed + * by the card deciding it wants service, before + * the interrupt handler checks to see if things need * to be done. * * There is a similar race condition if @@ -7238,28 +7509,96 @@ * has completed, but before observing the * contents of memory? */ -#ifdef IRIX - if (wrbf = list->il_wrbf) + +#ifdef KERNEL_THREADS + is_threaded = !(intr->bi_flags & PCIIO_INTR_NOTHREAD); + if (!is_threaded) { + nonthreaded_count++; + } + + if ((do_threaded) && (is_threaded)) { + /* Only need to flush write buffers if sharing */ + + if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { + if (x = *wrbf) /* write request buffer flush */ +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_ALERT("pcibr_intr_func %v: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); #else - if ((wrbf = list->il_wrbf)) + PRINT_ALERT("pcibr_intr_func 0x%x: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); #endif - (void) *wrbf; /* write request buffer flush */ + } + + /* + * Keep a running count of the number of interrupt + * handlers that have yet to complete. + */ + atomicAddInt(&(wrap->iw_hdlrcnt), 1); + + /* + * Prior to waking up pcibr_intrd, a pointer to the + * wrapper struct corresponding to the interrupt taken + * needs to be queued in the interrupt circular buffer. + * The pcibr_intrd thread needs the wrapper pointer in + * order to decrement the handler count (iw_hdlrcnt). + */ + pcibr_wrap_put(wrap, &intr->bi_ibuf); +#ifdef ITHREAD_LATENCY + xthread_set_istamp(intr->bi_tinfo.thd_latstats); +#endif /* ITHREAD_LATENCY */ + up(&intr->bi_tinfo.thd_isync); + } else +#endif /* KERNEL_THREADS */ + if ((do_nonthreaded) && (!is_threaded)) { + /* Non-threaded. + * Call the interrupt handler at interrupt level + */ - is_threaded = !(intr->bi_flags & PCIIO_INTR_NOTHREAD); + /* Only need to flush write buffers if sharing */ - if (is_threaded) { - thread_count++; -#ifdef IRIX - icvsema(&intr->bi_tinfo.thd_isync, intr->bi_tinfo.thd_pri, - NULL, NULL, NULL); + if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { + if ((x = *wrbf)) /* write request buffer flush */ +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_ALERT("pcibr_intr_func %v: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); +#else + PRINT_ALERT("pcibr_intr_func %p: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); #endif - } else { - /* Non-threaded. Call the interrupt handler at interrupt level */ + } + func = intr->bi_func; func(intr->bi_arg); + } + + clearit = 0; } + } + + if (do_threaded) { + /* + * All threaded handlers have been called; + * next do non-threaded, if any. + */ + do_threaded = 0; - clearit = 0; + if (nonthreaded_count) + do_nonthreaded = 1; + } else { + do_nonthreaded = 0; + /* + * If the non-threaded handler was the last to complete, + * (i.e., no threaded handlers still running) force an + * interrupt to avoid a potential deadlock situation. + */ + if (wrap->iw_hdlrcnt == 0) { + pcibr_force_interrupt(wrap); + } } } @@ -7275,7 +7614,8 @@ pcibr_soft_t pcibr_soft = wrap->iw_soft; bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t b_int_enable; - unsigned s; + bridgereg_t mask = 1 << wrap->iw_intr; + unsigned long s; s = pcibr_lock(pcibr_soft); b_int_enable = bridge->b_int_enable; @@ -7285,7 +7625,6 @@ pcibr_unlock(pcibr_soft, s); return; } - } } /* ===================================================================== @@ -7403,7 +7742,7 @@ bridge->b_pci_err_lower); } if (int_status & BRIDGE_ISR_ERROR_FATAL) { - cmn_err_tag(14, (int)CE_PANIC, "PCI Bridge Error interrupt killed the system"); + PRINT_PANIC("PCI Bridge Error interrupt killed the system"); /*NOTREACHED */ } else { PRINT_ALERT( "Non-fatal Error in Bridge.."); @@ -7491,10 +7830,8 @@ soft->bs_slot[slot].bss_window[win].bssw_base; else if (map->bp_space == PCIIO_SPACE_ROM) base += pcibr_info->f_rbase; -#ifdef IRIX if ((pci_addr >= base) && (pci_addr < (base + size))) - atomicAddInt(map->bp_toc, 1); -#endif + atomic_inc(map->bp_toc); } } } @@ -7532,34 +7869,8 @@ bridgereg_t err_status; int i; -#if defined(SN0_HWDEBUG) - extern int la_trigger_nasid1; - extern int la_trigger_nasid2; - extern long la_trigger_val; -#endif - /* REFERENCED */ bridgereg_t disable_errintr_mask = 0; -#ifdef IRIX - int rv; -#else - int rv = 0; -#endif - int error_code = IOECODE_DMA | IOECODE_READ; - ioerror_mode_t mode = MODE_DEVERROR; - ioerror_t ioe; - -#if defined(SN0_HWDEBUG) - /* - * trigger points for logic analyzer. Used to debug the DMA timeout - * note that 0xcafe is added to the trigger values to avoid false - * triggers when la_trigger_val shows up in a cacheline as data - */ - if (la_trigger_nasid1 != -1) - REMOTE_HUB_PI_S(la_trigger_nasid1, 0, PI_CPU_NUM, la_trigger_val + 0xcafe); - if (la_trigger_nasid2 != -1) - REMOTE_HUB_PI_S(la_trigger_nasid2, 0, PI_CPU_NUM, la_trigger_val + 0xcafe); -#endif #if PCIBR_SOFT_LIST /* IP27 seems to be handing us junk. @@ -7635,7 +7946,7 @@ bs_estat->bs_errcount_total++; -#ifdef IRIX +#ifdef LATER current_tick = lbolt; #else current_tick = 0; @@ -7777,7 +8088,7 @@ if ((err_status & BRIDGE_ISR_INVLD_ADDR) && ((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower)) == (BRIDGE_INT_RST_STAT & 0xff0))) { -#ifdef IRIX +#ifdef LATER if (kdebug) PRINT_NOTICE( "%s bridge: ignoring llp/control address interrupt", pcibr_soft->bs_name); @@ -7787,32 +8098,6 @@ } #endif /* PCIBR_LLP_CONTROL_WAR */ - /* Check if this is the RESP_XTALK_ERROR interrupt. - * This can happen due to a failed DMA READ operation. - */ - if (err_status & BRIDGE_ISR_RESP_XTLK_ERR) { - /* Phase 1 : Look at the error state in the bridge and further - * down in the device layers. - */ -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_LOOKUP); -#endif - IOERROR_SETVALUE(&ioe, widgetnum, pcibr_soft->bs_xid); - (void)pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - /* Phase 2 : Perform the action agreed upon in phase 1. - */ -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_ACTION); -#endif - rv = pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - } - if (rv != IOERROR_HANDLED) { #ifdef DEBUG if (err_status & BRIDGE_ISR_ERROR_DUMP) pcibr_error_dump(pcibr_soft); @@ -7822,7 +8107,7 @@ pcibr_error_dump(pcibr_soft); } #endif - } + /* * We can't return without re-enabling the interrupt, since * it would cause problems for devices like IOC3 (Lost @@ -7853,11 +8138,7 @@ iopaddr_t *offsetp, pciio_function_t *funcp) { -#ifdef IRIX - int s, f, w; -#else int s, f=0, w; -#endif iopaddr_t base; size_t size; pciio_piospace_t piosp; @@ -8082,7 +8363,7 @@ * decodes the PCI specific portions -- we count on our * callers to dump the raw IOE data. */ -#ifdef colin +#ifdef LATER #define BEM_ADD_IOE(ioe) \ do { \ if (IOERROR_FIELDVALID(ioe, busspace)) { \ @@ -8165,7 +8446,7 @@ * and need to construct the slot/space/offset. */ -#ifdef colin +#ifdef LATER bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr); #else bad_xaddr = -1; @@ -8207,7 +8488,7 @@ if (x > 1) x--; /* x is which devio reg; no guarantee - * pci slot x will be responding. + * PCI slot x will be responding. * still need to figure out who decodes * space/offset on the bus. */ @@ -8253,7 +8534,7 @@ if ((slot == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) { /* we've got a space/offset but not which - * pci slot decodes it. Check through our + * PCI slot decodes it. Check through our * notions of which devices decode where. * * Yes, this "duplicates" some logic in @@ -8353,9 +8634,7 @@ wx = PCIIO_SPACE_MEM; wl = wb + ws; if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) { -#ifdef IRIX - atomicAddInt(map->bp_toc, 1); -#endif + atomic_inc(map->bp_toc); if (slot == PCIIO_SLOT_NONE) { slot = cs; space = map->bp_space; @@ -8369,7 +8648,7 @@ if (space != PCIIO_SPACE_NONE) { if (slot != PCIIO_SLOT_NONE) { -#ifdef IRIX +#ifdef LATER if (func != PCIIO_FUNC_NONE) IOERROR_SETVALUE(ioe, widgetdev, pciio_widgetdev_create(slot,func)); @@ -8451,10 +8730,10 @@ * error interrupt is due to read/write error.. */ - /* We know the xtalk addr, the raw pci bus space, - * the raw pci bus address, the decoded pci bus + /* We know the xtalk addr, the raw PCI bus space, + * the raw PCI bus address, the decoded PCI bus * space, the offset within that space, and the - * decoded pci slot (which may be "PCIIO_SLOT_NONE" if no slot + * decoded PCI slot (which may be "PCIIO_SLOT_NONE" if no slot * is known to be involved). */ @@ -8506,7 +8785,7 @@ BEM_ADD_VAR(raw_paddr); if (IOERROR_FIELDVALID(ioe, widgetdev)) { -#ifdef colin +#ifdef LATER slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)); func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, @@ -8545,7 +8824,7 @@ * Need a way to ensure we don't inadvertently clear some * other errors. */ -#ifdef IRIX +#ifdef LATER if (IOERROR_FIELDVALID(ioe, widgetdev)) pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get( @@ -8586,7 +8865,7 @@ * Look up the address, in the bridge error registers, and * take appropriate action */ -#ifdef colin +#ifdef LATER ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid); ASSERT(bridge); #endif @@ -8618,7 +8897,7 @@ retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); if (retval != IOERROR_HANDLED) -#ifdef colin +#ifdef LATER pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get( IOERROR_GETVALUE(ioe,widgetdev))); @@ -8690,7 +8969,7 @@ retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); -#ifdef IRIX +#ifdef LATER if (retval != IOERROR_HANDLED) { pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get( @@ -8722,22 +9001,8 @@ { pcibr_soft_t pcibr_soft; int retval = IOERROR_BADERRORCODE; - devfs_handle_t xconn_vhdl,pcibr_vhdl; -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - error_state_t e_state; -#endif - pcibr_soft = (pcibr_soft_t) einfo; - - xconn_vhdl = pcibr_soft->bs_conn; - pcibr_vhdl = pcibr_soft->bs_vhdl; -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - e_state = error_state_get(xconn_vhdl); - - if (error_state_set(pcibr_vhdl, e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif + pcibr_soft = (pcibr_soft_t) einfo; /* If we are in the action handling phase clean out the error state * on the xswitch. @@ -8844,7 +9109,7 @@ bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t ctlreg; unsigned cfgctl[8]; - unsigned s; + unsigned long s; int f, nf; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; @@ -8869,11 +9134,7 @@ /* XXX delay? */ for (f = 0; f < nf; ++f) -#ifdef IRIX - if (pcibr_info = pcibr_infoh[f]) -#else if ((pcibr_info = pcibr_infoh[f])) -#endif for (win = 0; win < 6; ++win) if (pcibr_info->f_window[win].w_base != 0) bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = @@ -8901,7 +9162,7 @@ pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridgereg_t devreg; - unsigned s; + unsigned long s; /* * Bridge supports hardware swapping; so we can always @@ -8944,7 +9205,7 @@ pciio_slot_t pciio_slot, pciio_priority_t device_prio) { - int s; + unsigned long s; int *counter; bridgereg_t rtbits = 0; bridgereg_t devreg; @@ -8966,9 +9227,9 @@ * XXX- Bug in Rev B Bridge Si: * Symptom: Prefetcher starts operating incorrectly. This happens * due to corruption of the address storage ram in the prefetcher - * when a non-real time pci request is pulled and a real-time one is + * when a non-real time PCI request is pulled and a real-time one is * put in it's place. Workaround: Use only a single arbitration ring - * on pci bus. GBR and RR can still be uniquely used per + * on PCI bus. GBR and RR can still be uniquely used per * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. */ @@ -8983,18 +9244,12 @@ s = pcibr_lock(pcibr_soft); devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; if (device_prio == PCI_PRIO_HIGH) { -#ifdef IRIX - if (++*counter == 1) -#else if ((++*counter == 1)) { -#endif if (rtbits) devreg |= rtbits; else rc = PRIO_FAIL; -#ifndef IRIX } -#endif } else if (device_prio == PCI_PRIO_LOW) { if (*counter <= 0) rc = PRIO_FAIL; @@ -9082,15 +9337,11 @@ if (set || clr) { bridgereg_t devreg; - unsigned s; + unsigned long s; s = pcibr_lock(pcibr_soft); devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; -#ifdef IRIX - devreg = devreg & ~clr | set; -#else devreg = (devreg & ~clr) | set; -#endif if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { bridge_t *bridge = pcibr_soft->bs_base; @@ -9146,13 +9397,9 @@ pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - if ( (pcibr_soft_t)0 != pcibr_soft ) { - bridge = pcibr_soft->bs_base; - if ( (bridge_t *)0 != bridge ) { - cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; - } - } + bridge = pcibr_soft->bs_base; + cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; return cfgbase; } @@ -9215,7 +9462,7 @@ case 3: if (reg & 1) { CB(cfgbase, reg) = value; - CS(cfgbase, reg + 1) = value >> 8; + CS(cfgbase, (reg + 1)) = value >> 8; } else { CS(cfgbase, reg) = value; CB(cfgbase, reg + 2) = value >> 16; @@ -9266,6 +9513,16 @@ (pciio_error_devenable_f *) pcibr_error_devenable, (pciio_error_extract_f *) pcibr_error_extract, + +#ifdef LATER + (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, + (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, +#else + (pciio_driver_reg_callback_f *) 0, + (pciio_driver_unreg_callback_f *) 0, +#endif + (pciio_device_unregister_f *) pcibr_device_unregister, + (pciio_dma_enabled_f *) pcibr_dma_enabled, }; LOCAL pcibr_hints_t @@ -9299,7 +9556,7 @@ return (pcibr_hints_t) ainfo; abnormal_exit: -#ifdef IRIX +#ifdef LATER printf("SHOULD NOT BE HERE\n"); #endif DEL(hint); @@ -9417,12 +9674,7 @@ if (ainfo == (arbitrary_info_t) subdevp) return; DEL(subdevp); -#ifdef IRIX - if (ainfo == NULL) -#else - if (ainfo == (arbitrary_info_t) NULL) -#endif - { + if (ainfo == (arbitrary_info_t) NULL) { #if DEBUG printk("pcibr_hints_subdevs: null subdevs ptr at\n" "\t%p\n", pconn_vhdl); @@ -9438,7 +9690,7 @@ } -#ifdef colin +#ifdef LATER #include #include @@ -9531,7 +9783,7 @@ pss->bss_d32_base, pss->bss_d32_flags); qprintf("\tExt ATEs active ? %s", - pss->bss_ext_ates_active ? "yes" : "no"); + atomic_read(&pss->bss_ext_ates_active) ? "yes" : "no"); qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); @@ -9559,7 +9811,7 @@ qprintf("Invalid ips %d\n",ips); } -#endif /* colin */ +#endif /* LATER */ int pcibr_dma_enabled(devfs_handle_t pconn_vhdl) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/pciio.c linux.ac/arch/ia64/sn/io/pciio.c --- linux.vanilla/arch/ia64/sn/io/pciio.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/pciio.c Tue Apr 10 18:09:56 2001 @@ -14,6 +14,7 @@ #include #include #include +#include /* Must be before iograph.h to get MAX_PORT_NUM */ #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #define DEBUG_PCIIO #undef DEBUG_PCIIO /* turn this on for yet more console output */ @@ -38,28 +40,30 @@ int badaddr_val(volatile void *addr, int len, volatile void *ptr) { + int ret = 0; + volatile void *new_addr; + switch (len) { - case 4: *(volatile u32*)ptr = *(((volatile u32*)(((u64) addr)^4))); - default: printk("FIXME: argh fix badaddr_val\n"); + case 4: + new_addr = (void *)(((u64) addr)^4); + ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); + break; + default: + printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); } - /* no such thing as a bad addr .... */ - return(0); -} + if (ret < 0) + panic("badaddr_val: unexpected status (%d) in probing", ret); + return(ret); -void -cmn_err_tag(int seqnumber, register int level, char *fmt, ...) -{ } + nasid_t get_console_nasid(void) { -#ifdef IRIX + extern nasid_t console_nasid; return console_nasid; -#else - return 0; -#endif } int @@ -208,8 +212,8 @@ void pciio_device_info_free(pciio_info_t); devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); -int pciio_device_attach(devfs_handle_t); -int pciio_device_detach(devfs_handle_t); +int pciio_device_attach(devfs_handle_t, int); +int pciio_device_detach(devfs_handle_t, int); void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); int pciio_reset(devfs_handle_t); @@ -234,13 +238,30 @@ pciio_info_t card_info; pciio_provider_t *provider_fns; - card_info = pciio_info_get(dev); - ASSERT(card_info != NULL); + /* + * We're called with two types of vertices, one is + * the bridge vertex (ends with "pci") and the other is the + * pci slot vertex (ends with "pci/[0-8]"). For the first type + * we need to get the provider from the PFUNCS label. For + * the second we get it from fastinfo/c_pops. + */ + provider_fns = pciio_provider_fns_get(dev); + if (provider_fns == NULL) { + card_info = pciio_info_get(dev); + if (card_info != NULL) { + provider_fns = pciio_info_pops_get(card_info); + } + } + + if (provider_fns == NULL) +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_PANIC("%v: provider_fns == NULL", dev); +#else + PRINT_PANIC("0x%x: provider_fns == NULL", dev); +#endif - provider_fns = pciio_info_pops_get(card_info); - ASSERT(provider_fns != NULL); + return provider_fns; - return (provider_fns); } #define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func @@ -672,15 +693,21 @@ error_state_t e_state; #endif -#ifdef IRIX #if DEBUG && ERROR_DEBUG - cmn_err(CE_CONT, "%v: pciio_error_handler\n", pciio_vhdl); +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: pciio_error_handler\n", pciio_vhdl); +#else + printk("0x%x: pciio_error_handler\n", pciio_vhdl); #endif #endif - IOERR_PRINTF(cmn_err(CE_NOTE, - "%v: PCI Bus Error: Error code: %d Error mode: %d\n", +#if defined(SUPPORT_PRINTING_V_FORMAT) + IOERR_PRINTF(printk("%v: PCI Bus Error: Error code: %d Error mode: %d\n", pciio_vhdl, error_code, mode)); +#else + IOERR_PRINTF(printk("0x%x: PCI Bus Error: Error code: %d Error mode: %d\n", + pciio_vhdl, error_code, mode)); +#endif /* If there is an error handler sitting on * the "no-slot" connection point, give it @@ -715,7 +742,7 @@ * widgetdev is a 4byte value encoded as slot in the higher order * 2 bytes and function in the lower order 2 bytes. */ -#ifdef IRIX +#ifdef LATER slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioerror, widgetdev)); #else slot = 0; @@ -732,9 +759,12 @@ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) e_state = error_state_get(pciio_vhdl); + if (e_state == ERROR_STATE_ACTION) (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); + + if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE) return(IOERROR_UNHANDLED); @@ -825,12 +855,18 @@ ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE)); #if DEBUG - cmn_err(CE_ALERT, - "%v: pciio_endian_set is going away.\n" +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_ALERT("%v: pciio_endian_set is going away.\n" + "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" + "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", + dev); +#else + PRINT_ALERT("0x%x: pciio_endian_set is going away.\n" "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", dev); #endif +#endif return DEV_FUNC(dev, endian_set) (dev, device_end, desired_end); @@ -1027,8 +1063,6 @@ (pciio_info->c_fingerprint != pciio_info_fingerprint)) { #endif /* BRINGUP */ - printk("pciio_info_get: Found fastinfo 0x%p but wrong fingerprint %s\n", pciio_info, - pciio_info->c_fingerprint); return((pciio_info_t)-1); /* Should panic .. */ } @@ -1198,7 +1232,11 @@ pciio_attach(devfs_handle_t pciio) { #if DEBUG && ATTACH_DEBUG - cmn_err(CE_CONT, "%v: pciio_attach\n", pciio); +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: pciio_attach\n", pciio); +#else + printk("0x%x: pciio_attach\n", pciio); +#endif #endif return 0; } @@ -1220,11 +1258,7 @@ { arbitrary_info_t ainfo; -#ifdef IRIX - hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, &ainfo); -#else hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); -#endif } /* @@ -1258,7 +1292,7 @@ return cdl_add_driver(pciio_registry, vendor_id, device_id, - driver_prefix, flags); + driver_prefix, flags, NULL); } /* @@ -1274,7 +1308,33 @@ */ ASSERT(pciio_registry != NULL); - cdl_del_driver(pciio_registry, driver_prefix); + cdl_del_driver(pciio_registry, driver_prefix, NULL); +} + +/* + * Set the slot status for a device supported by the + * driver being registered. + */ +void +pciio_driver_reg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ +} + +/* + * Set the slot status for a device supported by the + * driver being unregistered. + */ +void +pciio_driver_unreg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ } /* @@ -1307,7 +1367,6 @@ pciio_vendor_id_t vendor_id, pciio_device_id_t device_id) { - return pciio_device_info_register (connectpt, pciio_device_info_new (NULL, master, slot, func, vendor_id, device_id)); @@ -1366,8 +1425,6 @@ pciio_info->c_slot, pciio_info->c_func); - printk("pciio_device_info_register: connectpt 0x%p, pciio_info 0x%p\n", connectpt, pciio_info); - if (GRAPH_SUCCESS != hwgraph_path_add(connectpt, name, &pconn)) return pconn; @@ -1379,7 +1436,9 @@ int pos; char dname[256]; pos = devfs_generate_path(pconn, dname, 256); +#ifdef DEBUG_PCIIO printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); +#endif } #endif /* BRINGUP */ @@ -1421,6 +1480,7 @@ /* Remove the link to our pci provider */ hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); + hwgraph_vertex_unref(pconn); hwgraph_vertex_destroy(pconn); @@ -1447,18 +1507,21 @@ static void pciio_device_inventory_remove(devfs_handle_t pconn_vhdl) { -#ifdef IRIX +#ifdef LATER hwgraph_inventory_remove(pconn_vhdl,-1,-1,-1,-1,-1); #endif } /*ARGSUSED */ int -pciio_device_attach(devfs_handle_t pconn) +pciio_device_attach(devfs_handle_t pconn, + int drv_flags) { pciio_info_t pciio_info; pciio_vendor_id_t vendor_id; pciio_device_id_t device_id; + int pciba_attach(devfs_handle_t); + pciio_device_inventory_add(pconn); pciio_info = pciio_info_get(pconn); @@ -1466,8 +1529,6 @@ vendor_id = pciio_info->c_vendor; device_id = pciio_info->c_device; - printk("pciio_device_attach: Function 0x%p, vendor 0x%x, device_id %x\n", pconn, vendor_id, device_id); - /* we don't start attaching things until * all the driver init routines (including * pciio_init) have been called; so we @@ -1475,12 +1536,17 @@ */ ASSERT(pciio_registry != NULL); - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn)); + /* + * Since pciba is not called from cdl routines .. call it here. + */ + pciba_attach(pconn); + return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); } int -pciio_device_detach(devfs_handle_t pconn) +pciio_device_detach(devfs_handle_t pconn, + int drv_flags) { pciio_info_t pciio_info; pciio_vendor_id_t vendor_id; @@ -1499,10 +1565,9 @@ */ ASSERT(pciio_registry != NULL); - cdl_del_connpt(pciio_registry, vendor_id, device_id, pconn); + return(cdl_del_connpt(pciio_registry, vendor_id, device_id, + pconn, drv_flags)); - return(0); - } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/sgi_if.c linux.ac/arch/ia64/sn/io/sgi_if.c --- linux.vanilla/arch/ia64/sn/io/sgi_if.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/sgi_if.c Tue Apr 10 18:09:56 2001 @@ -21,8 +21,6 @@ #include #include -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); - void * kmem_zalloc(size_t size, int flag) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/sgi_io_init.c linux.ac/arch/ia64/sn/io/sgi_io_init.c --- linux.vanilla/arch/ia64/sn/io/sgi_io_init.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/io/sgi_io_init.c Tue Apr 10 18:12:08 2001 @@ -79,13 +79,8 @@ void sgi_master_io_infr_init(void) { -#ifdef Colin - /* - * Simulate Big Window 0. - * Only when we build for lutsen etc. .. - */ - simulated_BW0_init(); -#endif + int cnode; + extern int maxnodes; /* * Do any early init stuff .. einit_tbl[] etc. @@ -122,7 +117,9 @@ sn_mp_setup(); DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n"); - per_hub_init(0); /* Need to get and send in actual cnode number */ + for (cnode = 0; cnode < maxnodes; cnode++) { + per_hub_init(cnode); + } /* We can do headless hub cnodes here .. */ @@ -188,7 +185,7 @@ /* Emulate cboot() .. */ mlreset(1); /* This is a slave cpu */ - per_hub_init(0); /* Need to get and send in actual cnode number */ + // per_hub_init(0); /* Need to get and send in actual cnode number */ /* Done */ } @@ -212,12 +209,8 @@ * do not currently support yet .. just a hack for now. */ #ifdef NUMA_BASE - DBG("sn_mp_setup(): maxnodes= %d numnodes= %d\n", maxnodes,numnodes); maxnodes = numnodes; -#ifdef SIMULATED_KLGRAPH - maxnodes = 1; - numnodes = 1; -#endif /* SIMULATED_KLGRAPH */ + DBG("sn_mp_setup(): maxnodes= %d numnodes= %d\n", maxnodes,numnodes); printk("sn_mp_setup(): Allocating backing store for *Nodepdaindr[%2d] \n", maxnodes); @@ -259,6 +252,14 @@ * ml/SN/promif.c */ +#ifdef CONFIG_IA64_SGI_SN1 + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + /* Skip holes in CPU space */ + if (cpu_enabled(cpu)) { + init_platform_pda(cpu); + } + } +#endif for (cnode = 0; cnode < maxnodes; cnode++) { /* * Set up platform-dependent nodepda fields. @@ -267,29 +268,7 @@ */ DBG("sn_mp_io_setup: calling init_platform_nodepda(%2d)\n",cnode); init_platform_nodepda(Nodepdaindr[cnode], cnode); - - /* - * This routine clears the Hub's Interrupt registers. - */ -#ifndef CONFIG_IA64_SGI_IO - /* - * We need to move this intr_clear_all() routine - * from SN/intr.c to a more appropriate file. - * Talk to Al Mayer. - */ - intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); -#endif } - -#ifdef CONFIG_IA64_SGI_IO - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - /* Skip holes in CPU space */ - if (cpu_enabled(cpu)) { - init_platform_pda(cpu); - } - } -#endif - /* * Initialize platform-dependent vertices in the hwgraph: * module @@ -309,4 +288,26 @@ klhwg_add_all_modules(hwgraph_root); DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n"); klhwg_add_all_nodes(hwgraph_root); + + + for (cnode = 0; cnode < maxnodes; cnode++) { + + /* + * This routine clears the Hub's Interrupt registers. + */ +#ifdef CONFIG_IA64_SGI_SN1 + /* + * We need to move this intr_clear_all() routine + * from SN/intr.c to a more appropriate file. + * Talk to Al Mayer. + */ + intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); + /* now init the hub */ + // per_hub_init(cnode); +#endif + } + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + synergy_perf_init(); +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/sgi_io_sim.c linux.ac/arch/ia64/sn/io/sgi_io_sim.c --- linux.vanilla/arch/ia64/sn/io/sgi_io_sim.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/sgi_io_sim.c Tue Apr 10 18:12:08 2001 @@ -17,9 +17,6 @@ #include #include -cnodeid_t nasid_to_compact_node[MAX_NASIDS]; -nasid_t compact_to_nasid_node[MAX_COMPACT_NODES]; -cnodeid_t cpuid_to_compact_node[MAXCPUS]; cpuid_t master_procid = 0; int maxnodes; char arg_maxnodes[4]; @@ -42,12 +39,6 @@ return (strlen(s) != 0); } - -void pciba_init(void) -{ - FIXME("pciba_init : no-op\n"); -} - void xbmon_init(void) { FIXME("xbmon_init : no-op\n"); @@ -82,7 +73,7 @@ * Routines provided by ml/SN/promif.c. */ static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL; -static nasid_t console_nasid; +nasid_t console_nasid; static char console_wid; static char console_pcislot; @@ -90,19 +81,12 @@ set_master_bridge_base(void) { -#ifdef SIMULATED_KLGRAPH - printk("set_master_bridge_base: SIMULATED_KLGRAPH FIXME hardwired master.\n"); - console_nasid = 0; - console_wid = 0x8; - console_pcislot = 0x2; -#else console_nasid = KL_CONFIG_CH_CONS_INFO(master_nasid)->nasid; console_wid = WIDGETID_GET(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base); console_pcislot = KL_CONFIG_CH_CONS_INFO(master_nasid)->npci; -#endif /* SIMULATED_KLGRAPH */ - master_bridge_base = (__psunsigned_t)NODE_SWIN_BASE(console_nasid, console_wid); + FIXME("WARNING: set_master_bridge_base: NON NASID 0 DOES NOT WORK\n"); } int @@ -133,21 +117,6 @@ } else { return 0; } -} - -cnodeid_t -nasid_to_compact_nodeid(nasid_t nasid) -{ - ASSERT(nasid >= 0 && nasid < MAX_NASIDS); - return nasid_to_compact_node[nasid]; -} - -nasid_t -compact_to_nasid_nodeid(cnodeid_t cnode) -{ - ASSERT(cnode >= 0 && cnode <= MAX_COMPACT_NODES); - ASSERT(compact_to_nasid_node[cnode] >= 0); - return compact_to_nasid_node[cnode]; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/stubs.c linux.ac/arch/ia64/sn/io/stubs.c --- linux.vanilla/arch/ia64/sn/io/stubs.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/stubs.c Tue Apr 10 18:12:08 2001 @@ -31,8 +31,6 @@ int force_fire_and_forget; int ignore_conveyor_override; -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); - devfs_handle_t dummy_vrtx; /* Needed for cpuid_to_vertex() in hack.h */ @@ -105,32 +103,6 @@ return((zone_t *)0); } -uint64_t -rmalloc(struct map *mp, size_t size) -{ - FIXME("rmalloc : returns NULL"); - return((uint64_t)0); -} - -void -rmfree(struct map *mp, size_t size, uint64_t a) -{ - FIXME("rmfree : no-op"); -} - -struct map * -rmallocmap(uint64_t mapsiz) -{ - FIXME("rmallocmap : returns NULL"); - return((struct map *)0); -} - -void -rmfreemap(struct map *mp) -{ - FIXME("rmfreemap : no-op"); -} - int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) { @@ -170,40 +142,6 @@ ioc3_console_vhdl_get(void) {FIXME("ioc3_console_vhdl_get"); return( (devfs_handle_t)-1);} - -#if 0 -#define io_splock(l) 1 -#define io_spunlock(l,s) - -#define spinlock_destroy(a) /* needed by pcibr_detach() */ -#define mutex_spinlock(a) 0 -#define mutex_spinunlock(a,b) -#define mutex_init(a,b,c) ; -#define mutex_lock(a,b) ; -#define mutex_unlock(a) ; -#define dev_to_vhdl(dev) 0 -#define get_timestamp() 0 -#define us_delay(a) -#define v_mapphys(a,b,c) 0 -#define splhi() 0 -#define splx(s) -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); -#endif /* 0 */ - -int -cap_able(uint64_t x) -{ - FIXME("cap_able : returns 1"); - return(1); -} - -int -cap_able_cred(uint64_t a, uint64_t b) -{ - FIXME("cap_able_cred : returns 1"); - return(1); -} - void nic_vmc_check(devfs_handle_t vhdl, char *nicinfo) { @@ -236,21 +174,5 @@ uint64_t value) { FIXME("vector_write_node\n"); - return(0); -} - -int -atomicAddInt(int *int_ptr, int value) -{ -// FIXME("atomicAddInt : simple add\n"); - *int_ptr += value; - return(0); -} - -int -atomicClearInt(int *int_ptr, int value) -{ - FIXME("atomicClearInt : simple clear\n"); - *int_ptr &= ~value; return(0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/xbow.c linux.ac/arch/ia64/sn/io/xbow.c --- linux.vanilla/arch/ia64/sn/io/xbow.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/sn/io/xbow.c Sat Apr 14 01:18:00 2001 @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -17,19 +16,18 @@ #include #include #include +#include #include #include -#define DEBUG 1 -#define XBOW_DEBUG 1 +/* #define DEBUG 1 */ +/* #define XBOW_DEBUG 1 */ /* * Files needed to get the device driver entry points */ -/* #include */ - #include #include #include @@ -66,7 +64,7 @@ xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; - lock_t xbow_perf_lock; + spinlock_t xbow_perf_lock; int link_monitor; widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ @@ -74,7 +72,7 @@ * destination port since contention happens there. * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. */ - lock_t xbow_bw_alloc_lock; /* bw allocation lock */ + spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ }; @@ -118,15 +116,8 @@ int xbow_disable_llp_monitor(devfs_handle_t); int xbow_enable_llp_monitor(devfs_handle_t); - -#ifdef IRIX -int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, - unsigned long long, unsigned long long); -#else int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, unsigned long long, unsigned long long); -#endif - xswitch_reset_link_f xbow_reset_link; @@ -237,7 +228,11 @@ int xbow_num; #if DEBUG && ATTACH_DEBUG - cmn_err(CE_CONT, "%v: xbow_attach\n", conn); +#if defined(SUPPORT_PRINTING_V_FORMAT + printk("%v: xbow_attach\n", conn); +#else + printk("0x%x: xbow_attach\n", conn); +#endif #endif /* @@ -261,7 +256,9 @@ * of our connection point. */ busv = hwgraph_connectpt_get(conn); +#if DEBUG && ATTACH_DEBUG printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); +#endif ASSERT(busv != GRAPH_VERTEX_NONE); @@ -283,8 +280,7 @@ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, /* &hcl_fops */ (void *)&vhdl, NULL); if (!vhdl) { - printk("xbow_attach: Unable to create char device for xbow conn -0x%p\n", + printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", conn); } @@ -306,11 +302,7 @@ /* Add xbow number as a suffix to the hwgraph name of the xbow. * This is helpful while looking at the error/warning messages. */ -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC xbow_num = 0; -#else - xbow_num = xswitch_id_get(busv); -#endif /* * get the name of this xbow vertex and keep the info. @@ -341,7 +333,7 @@ * Crossbow is DOWNREV: these chips are not good * to have around, and the operator should be told. */ -#ifdef IRIX +#ifdef LATER #if !DEBUG if ( #if SHOW_REVS @@ -349,8 +341,7 @@ #endif /* SHOW_REVS */ (rev < XBOW_REV_1_1)) #endif /* !DEBUG */ - cmn_err((rev < XBOW_REV_1_1) ? CE_WARN : CE_CONT, - "%sCrossbow ASIC: rev %s (code=%d) at %s%s", + printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s", (rev < XBOW_REV_1_1) ? "DOWNREV " : "", (rev == XBOW_REV_1_0) ? "1.0" : (rev == XBOW_REV_1_1) ? "1.1" : @@ -362,14 +353,13 @@ "unknown", rev, soft->name, (rev < XBOW_REV_1_1) ? "" : "\n"); -#endif /* IRIX */ - - spinlock_init(&soft->xbow_perf_lock, "xbow_perf_lock"); +#endif /* LATER */ + mutex_spinlock_init(&soft->xbow_perf_lock); soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; /* Initialization for GBR bw allocation */ - spinlock_init(&soft->xbow_bw_alloc_lock, "xbow_bw_alloc_lock"); + mutex_spinlock_init(&soft->xbow_bw_alloc_lock); #define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */ #define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ @@ -403,7 +393,7 @@ xwidget_error_register(conn, xbow_error_handler, soft); #else - printk("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n"); + FIXME("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n"); #endif /* LATER */ /* @@ -479,8 +469,6 @@ int xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) { - if (!_CAP_CRABLE((uint64_t)credp, CAP_DEVICE_MGT)) - return EPERM; return 0; } @@ -525,28 +513,9 @@ char devname[MAXDEVNAME]; xwidget_info_t xwidget_info; int i; -#if IP27 - cnodeid_t cnodeid = CNODEID_NONE; -#endif vertex_to_name(dev, devname, MAXDEVNAME); -#if IP30 - /* If there is a ".connection" edge from this vertex, - * then it must be "/hw/node" vertex. Return the widget - * number for heart: 8. - */ - if (hwgraph_edge_get(dev, EDGE_LBL_CONN, &tdev) == - GRAPH_SUCCESS) { - return ((xwidgetnum_t) 8); - } -#elif IP27 - if ((cnodeid = nodevertex_to_cnodeid(dev)) != CNODEID_NONE) { - ASSERT(cnodeid < maxnodes); - return(hub_widget_id(COMPACT_TO_NASID_NODEID(cnodeid))); - } -#endif - /* If this is a pci controller vertex, traverse up using * the ".." links to get to the widget. */ @@ -601,7 +570,7 @@ ASSERT_ALWAYS(rc != 0); #endif switch (cmd) { -#ifdef IRIX +#ifdef LATER case XBOWIOC_PERF_ENABLE: case XBOWIOC_PERF_DISABLE: { @@ -630,7 +599,7 @@ } #endif -#ifdef IRIX +#ifdef LATER case XBOWIOC_PERF_GET: { xbow_perf_link_t *xbow_perf_cnt; @@ -652,10 +621,6 @@ #endif case XBOWIOC_LLP_ERROR_ENABLE: - if (!_CAP_CRABLE((uint64_t)cr, CAP_DEVICE_MGT)) { - error = EPERM; - break; - } if ((error = xbow_enable_llp_monitor(vhdl)) != 0) error = EINVAL; @@ -663,16 +628,12 @@ case XBOWIOC_LLP_ERROR_DISABLE: - if (!_CAP_CRABLE((uint64_t)cr, CAP_DEVICE_MGT)) { - error = EPERM; - break; - } if ((error = xbow_disable_llp_monitor(vhdl)) != 0) error = EINVAL; break; -#ifdef IRIX +#ifdef LATER case XBOWIOC_LLP_ERROR_GET: { xbow_link_status_t *xbow_llp_status; @@ -693,17 +654,12 @@ } #endif -#ifdef IRIX +#ifdef LATER case GIOCSETBW: { grio_ioctl_info_t info; xwidgetnum_t src_widgetnum, dest_widgetnum; - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { error = EFAULT; break; @@ -863,14 +819,14 @@ xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); } -#define XEM_ADD_STR(s) cmn_err(CE_CONT, "%s", (s)) -#define XEM_ADD_NVAR(n,v) cmn_err(CE_CONT, "\t%20s: 0x%x\n", (n), (v)) +#define XEM_ADD_STR(s) printk("%s", (s)) +#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%x\n", (n), (v)) #define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v)) #define XEM_ADD_IOEF(n) if (IOERROR_FIELDVALID(ioe,n)) \ XEM_ADD_NVAR("ioe." #n, \ IOERROR_GETVALUE(ioe,n)) -#ifdef IRIX +#ifdef LATER static void xem_add_ioe(ioerror_t *ioe) { @@ -891,7 +847,7 @@ } #define XEM_ADD_IOE() (xem_add_ioe(ioe)) -#endif /* IRIX */ +#endif /* LATER */ int xbow_xmit_retry_errors = 0; @@ -971,7 +927,6 @@ static void xbow_errintr_handler(intr_arg_t arg) { -#ifdef IRIX ioerror_t ioe[1]; xbow_soft_t soft = (xbow_soft_t) arg; xbow_t *xbow = soft->base; @@ -1065,9 +1020,8 @@ xwidget_vhdl = xbow_widget_lookup(soft->busv,port); xwidget_name = xwidget_name_get(xwidget_vhdl); -#ifdef IRIX - cmn_err(CE_CONT, - "%s port %X[%s] XIO Bus Error", +#ifdef LATER + printk("%s port %X[%s] XIO Bus Error", soft->name, port, xwidget_name); if (link_status & XB_STAT_MULTI_ERR) XEM_ADD_STR("\tMultiple Errors\n"); @@ -1089,8 +1043,7 @@ XEM_ADD_STR("\tMaximum Request Timeout\n"); if (link_status & XB_STAT_SRC_TOUT_ERR) XEM_ADD_STR("\tSource Timeout Error\n"); -#endif - +#endif /* LATER */ { int other_port; @@ -1130,8 +1083,7 @@ | XB_WID_STAT_XTALK_ERR | XB_WID_STAT_REG_ACC_ERR)) { - cmn_err(CE_CONT, - "%s Port 0 XIO Bus Error", + printk("%s Port 0 XIO Bus Error", soft->name); if (wid_stat & XB_WID_STAT_MULTI_ERR) XEM_ADD_STR("\tMultiple Error\n"); @@ -1150,9 +1102,8 @@ XEM_ADD_VAR(wid_err_upper); XEM_ADD_VAR(wid_err_lower); XEM_ADD_VAR(wid_err_addr); - cmn_err_tag(8, CE_PANIC, "XIO Bus Error"); + PRINT_PANIC("XIO Bus Error"); } -#endif } #endif /* LATER */ @@ -1180,7 +1131,6 @@ ioerror_mode_t mode, ioerror_t *ioerror) { -#ifdef IRIX int retval = IOERROR_WIDGETLEVEL; xbow_soft_t soft = (xbow_soft_t) einfo; @@ -1204,7 +1154,7 @@ busv = soft->busv; #if DEBUG && ERROR_DEBUG - cmn_err(CE_CONT, "%s: xbow_error_handler\n", soft->name, busv); + printk("%s: xbow_error_handler\n", soft->name, busv); #endif port = IOERROR_GETVALUE(ioerror, widgetnum); @@ -1217,14 +1167,12 @@ return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { - cmn_err(CE_ALERT, - "DMA error blamed on Crossbow at %s\n" + PRINT_ALERT("DMA error blamed on Crossbow at %s\n" "\tbut Crosbow never initiates DMA!", soft->name); } if (error_code & IOECODE_PIO) { - cmn_err(CE_ALERT, - "PIO Error on XIO Bus %s\n" + PRINT_ALERt("PIO Error on XIO Bus %s\n" "\tattempting to access XIO controller\n" "\twith offset 0x%X", soft->name, @@ -1258,14 +1206,12 @@ return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { - cmn_err(CE_ALERT, - "DMA error blamed on XIO port at %s/%d\n" + PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n" "\tbut Crossbow does not support that port", soft->name, port); } if (error_code & IOECODE_PIO) { - cmn_err(CE_ALERT, - "PIO Error on XIO Bus %s\n" + PRINT_ALERT("PIO Error on XIO Bus %s\n" "\tattempting to access XIO port %d\n" "\t(which Crossbow does not support)" "\twith offset 0x%X", @@ -1309,14 +1255,12 @@ return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { - cmn_err(CE_ALERT, - "DMA error blamed on XIO port at %s/%d\n" + PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n" "\tbut there is no device connected there.", soft->name, port); } if (error_code & IOECODE_PIO) { - cmn_err(CE_ALERT, - "PIO Error on XIO Bus %s\n" + PRINT_ALERT("PIO Error on XIO Bus %s\n" "\tattempting to access XIO port %d\n" "\t(which has no device connected)" "\twith offset 0x%X", @@ -1349,16 +1293,14 @@ if (mode == MODE_DEVPROBE) return IOERROR_HANDLED; - cmn_err(CE_ALERT, - "%s%sError on XIO Bus %s port %d", + PRINT_ALERT("%s%sError on XIO Bus %s port %d", (error_code & IOECODE_DMA) ? "DMA " : "", (error_code & IOECODE_PIO) ? "PIO " : "", soft->name, port); if ((error_code & IOECODE_PIO) && (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - cmn_err(CE_CONT, - "\tAccess attempted to offset 0x%X\n", + printk("\tAccess attempted to offset 0x%X\n", IOERROR_GETVALUE(ioerror, xtalkaddr)); } if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD) @@ -1393,16 +1335,14 @@ if (retval == IOERROR_UNHANDLED) { retval = IOERROR_PANIC; - cmn_err(CE_ALERT, - "%s%sError on XIO Bus %s port %d", + PRINT_ALERT("%s%sError on XIO Bus %s port %d", (error_code & IOECODE_DMA) ? "DMA " : "", (error_code & IOECODE_PIO) ? "PIO " : "", soft->name, port); if ((error_code & IOECODE_PIO) && (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - cmn_err(CE_CONT, - "\tAccess attempted to offset 0x%X\n", + printk("\tAccess attempted to offset 0x%X\n", IOERROR_GETVALUE(ioerror, xtalkaddr)); } } @@ -1428,7 +1368,6 @@ */ return retval; -#endif /* IRIX */ } #endif /* LATER */ @@ -1440,7 +1379,8 @@ xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; xbow_perfcount_t perf_reg; - int link, s, i; + unsigned long s; + int link, i; for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) @@ -1460,7 +1400,7 @@ } /* Do port /mode multiplexing here */ -#ifdef IRIX +#ifdef LATER (void) timeout(xbow_update_perf_counters, (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); #endif @@ -1484,7 +1424,8 @@ xbow_linkctrl_t xbow_link_ctrl; xbow_t *xbow = xbow_soft->base; xbow_perfcount_t perf_reg; - int s, i; + unsigned long s; + int i; link -= BASE_XBOW_PORT; if ((link < 0) || (link >= MAX_XBOW_PORTS)) @@ -1525,7 +1466,7 @@ *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; xbow_perf->xp_current = perf_reg.xb_perf.count; -#ifdef IRIX +#ifdef LATER (void) timeout(xbow_update_perf_counters, (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); #endif @@ -1578,13 +1519,13 @@ aux_sts.xb_aux_linkstatus.tx_retry_cnt; if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { -#ifdef IRIX - cmn_err(CE_WARN, "link %d[%s]: bad status 0x%x\n", +#ifdef LATER + PRINT_WARNING("link %d[%s]: bad status 0x%x\n", link, xwidget_name, lnk_sts.linkstatus); #endif } } -#ifdef IRIX +#ifdef LATER if (xbow_soft->link_monitor) (void) timeout(xbow_update_llp_status, (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); @@ -1611,7 +1552,7 @@ { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); -#ifdef IRIX +#ifdef LATER (void) timeout(xbow_update_llp_status, (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); #endif @@ -1690,7 +1631,7 @@ int i; xb_linkregs_t *link; -#ifdef IRIX +#ifdef LATER if (dev_is_vertex((devfs_handle_t) regs)) { devfs_handle_t vhdl = (devfs_handle_t) regs; xbow_soft_t soft = xbow_soft_get(vhdl); @@ -1702,7 +1643,7 @@ xbow = (xbow_t *) regs; } -#ifdef IRIX +#ifdef LATER qprintf("Printing xbow registers starting at 0x%x\n", xbow); qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, @@ -1716,7 +1657,7 @@ for (i = 8; i <= 0xf; i++) { link = &xbow->xb_link(i); -#ifdef IRIX +#ifdef LATER qprintf("Link %d registers\n", i); qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", link->link_control, link->link_status, @@ -1795,7 +1736,7 @@ xbow_soft_t soft = xbow_soft_get(vhdl); volatile xbowreg_t *xreg; xbowreg_t mask; - int s; + unsigned long s; int error = 0; bandwidth_t old_bw_BYTES, req_bw_BYTES; xbowreg_t old_xreg; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/xswitch.c linux.ac/arch/ia64/sn/io/xswitch.c --- linux.vanilla/arch/ia64/sn/io/xswitch.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/io/xswitch.c Tue Apr 10 18:12:08 2001 @@ -88,13 +88,15 @@ xswitch_info = (xswitch_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef IRIX +#ifdef LATER if ((xswitch_info != NULL) && (xswitch_info->fingerprint != xswitch_info_fingerprint)) - cmn_err(CE_PANIC, "%v xswitch_info_get bad fingerprint", xwidget); +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_PANIC("%v xswitch_info_get bad fingerprint", xwidget); +#else + PRINT_PANIC("%x xswitch_info_get bad fingerprint", xwidget); #endif - - printk("xswitch_info_get: xwidget 0x%p xswitch_info 0x%p\n", xwidget, xswitch_info); +#endif /* LATER */ return (xswitch_info); } @@ -118,9 +120,9 @@ xswitch_info_vhdl_get(xswitch_info_t xswitch_info, xwidgetnum_t port) { -#ifdef IRIX +#ifdef LATER if (xswitch_info == NULL) - cmn_err(CE_PANIC, "xswitch_info_vhdl_get: null xswitch_info"); + PRINT_PANIC("xswitch_info_vhdl_get: null xswitch_info"); #endif #if XSWITCH_CENSUS_PORT_MIN @@ -196,8 +198,6 @@ GRAPH_VERTEX_NONE); } xswitch_info_set(xwidget, xswitch_info); - printk("xswitch_info_new: xswitch_info_set xwidget 0x%p, xswitch_info 0x%p\n", - xwidget, xswitch_info); } return xswitch_info; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/io/xtalk.c linux.ac/arch/ia64/sn/io/xtalk.c --- linux.vanilla/arch/ia64/sn/io/xtalk.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/ia64/sn/io/xtalk.c Sat Apr 14 01:18:00 2001 @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -71,6 +70,7 @@ void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); +xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); void xtalk_intr_free(xtalk_intr_t); int xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *, void *); void xtalk_intr_disconnect(xtalk_intr_t); @@ -318,7 +318,7 @@ unsigned flags) { #if DEBUG - cmn_err(CE_PANIC, "null_xtalk_early_piotrans_addr"); + PRINT_PANIC("null_xtalk_early_piotrans_addr"); #endif return NULL; } @@ -439,6 +439,19 @@ (dev, dev_desc, owner_dev); } +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Unconditionally setup resources to be non-threaded. + * Return resource handle in intr_hdl. + */ +xtalk_intr_t +xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt */ +{ + return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) + (dev, dev_desc, owner_dev); +} /* * Free resources consumed by intr_alloc. @@ -527,7 +540,11 @@ xwidget_info_t xwidget_info; #if DEBUG && ERROR_DEBUG - cmn_err(CE_CONT, "%v: xtalk_error_handler\n", xconn); +#ifdef SUPPORT_PRINTING_V_FORMAT + printk("%v: xtalk_error_handler\n", xconn); +#else + printk("%x: xtalk_error_handler\n", xconn); +#endif #endif xwidget_info = xwidget_info_get(xconn); @@ -549,9 +566,13 @@ (mode == MODE_DEVREENABLE)) return IOERROR_HANDLED; -#ifdef IRIX - cmn_err(CE_WARN, "Xbow at %v encountered Fatal error", xconn); +#ifdef LATER +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_WARNING("Xbow at %v encountered Fatal error", xconn); +#else + PRINT_WARNING("Xbow at %x encountered Fatal error", xconn); #endif +#endif /* LATER */ ioerror_dump("xtalk", error_code, mode, ioerror); return IOERROR_UNHANDLED; @@ -648,13 +669,6 @@ return (xtalk_intr->xi_sfarg); } - -int -xtalk_intr_flags_get(xtalk_intr_t xtalk_intr) -{ - return(xtalk_intr->xi_flags); -} - /****** Generic crosstalk pio interfaces ******/ devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) @@ -726,11 +740,15 @@ widget_info = (xwidget_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef IRIX +#ifdef LATER if ((widget_info != NULL) && (widget_info->w_fingerprint != widget_info_fingerprint)) - cmn_err(CE_PANIC, "%v bad xwidget_info", xwidget); +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_PANIC("%v bad xwidget_info", xwidget); +#else + PRINT_PANIC("%x bad xwidget_info", xwidget); #endif +#endif /* LATER */ return (widget_info); } @@ -894,7 +912,7 @@ return cdl_add_driver(xtalk_registry, part_num, mfg_num, - driver_prefix, flags); + driver_prefix, flags, NULL); } /* @@ -910,7 +928,7 @@ */ ASSERT(xtalk_registry != NULL); - cdl_del_driver(xtalk_registry, driver_prefix); + cdl_del_driver(xtalk_registry, driver_prefix, NULL); } /* @@ -963,7 +981,6 @@ * long as we have it, we can use it elsewhere. */ s = dev_to_name(widget,devnm,MAXDEVNAME); - printk("xwidget_register: dev_to_name widget id 0x%p, s = %s\n", widget, s); widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); strcpy(widget_info->w_name,s); @@ -985,7 +1002,8 @@ if (aa) async_attach_add_info(widget, aa); - return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, widget); + return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); } /* @@ -1009,8 +1027,8 @@ hwid = &(widget_info->w_hwid); - cdl_del_connpt(xtalk_registry, hwid->part_num, - hwid->mfg_num, widget); + cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); /* Clean out the xwidget information */ (void)kfree(widget_info->w_name); @@ -1051,7 +1069,7 @@ xswitch_reset_link(xwidget); info = xwidget_info_get(xwidget); -#ifdef IRIX +#ifdef LATER ASSERT_ALWAYS(info != NULL); #endif @@ -1083,26 +1101,7 @@ ASSERT(info != NULL); return(xwidget_info_name_get(info)); } -/* - * xtalk_device_powerup - * Reset and initialize the specified xtalk widget - */ -int -xtalk_device_powerup(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ -#ifndef CONFIG_IA64_SGI_IO - extern void io_xswitch_widget_init(devfs_handle_t, - devfs_handle_t, - xwidgetnum_t, - async_attach_t); - io_xswitch_widget_init(xbus_vhdl, - hwgraph_connectpt_get(xbus_vhdl), - widget, - NULL); -#endif /* CONFIG_IA64_SGI_IO */ - - return(0); -} + /* * xtalk_device_shutdown * Disable the specified xtalk widget and clean out all the software diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/Makefile linux.ac/arch/ia64/sn/sn1/Makefile --- linux.vanilla/arch/ia64/sn/sn1/Makefile Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/sn1/Makefile Tue Apr 10 18:12:08 2001 @@ -8,7 +8,7 @@ EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO + -DNEW_INTERRUPTS .S.s: $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< @@ -18,18 +18,13 @@ all: sn1.a O_TARGET = sn1.a -O_HEADERS = -O_OBJS = irq.o setup.o iomv.o mm.o smp.o synergy.o sn1_asm.o \ - discontig.o -ifeq ($(CONFIG_IA64_SGI_AUTOTEST),y) -O_OBJS += llsc4.o -endif +obj-y = irq.o setup.o iomv.o mm.o smp.o synergy.o sn1_asm.o \ + discontig.o probe.o error.o sv.o - -ifeq ($(CONFIG_IA64_GENERIC),y) -O_OBJS += machvec.o -endif +obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o +obj-$(CONFIG_IA64_GENERIC) += machvec.o +obj-$(CONFIG_MODULES) += sn1_ksyms.o clean:: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/discontig.c linux.ac/arch/ia64/sn/sn1/discontig.c --- linux.vanilla/arch/ia64/sn/sn1/discontig.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/discontig.c Tue Apr 10 18:12:08 2001 @@ -139,35 +139,6 @@ dump_bootmem_info() ; } -void __init -discontig_paging_init(void) -{ - int i; - unsigned long max_dma, zones_size[MAX_NR_ZONES]; - void dump_node_data(void); - - max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - for (i = 0; i < numnodes; i++) { - extern void free_unused_memmap_node(int); - unsigned long startpfn = __pa((void *)NODE_START(i)) >> PAGE_SHIFT; - unsigned long numpfn = NODE_SIZE(i) >> PAGE_SHIFT; - memset(zones_size, 0, sizeof(zones_size)); - - if ((startpfn + numpfn) < max_dma) { - zones_size[ZONE_DMA] = numpfn; - } else if (startpfn > max_dma) { - zones_size[ZONE_NORMAL] = numpfn; - } else { - zones_size[ZONE_DMA] = (max_dma - startpfn); - zones_size[ZONE_NORMAL] = numpfn - zones_size[ZONE_DMA]; - } - free_area_init_node(i, NODE_DATA(i), NULL, zones_size, startpfn< +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void +snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) { + unsigned long long intpend_val; + unsigned long long bit; + + switch (irq) { + case SGI_UART_IRQ: + // This isn't really an error interrupt. We're just + // here because we have to do something with them. + // This is probably wrong, and this code will be + // removed. + intpend_val = LOCAL_HUB_L(PI_INT_PEND0); + if ( (bit = ~(1L<= 0x1f0 && port <= 0x1f7 || + port == 0x3f6 || port == 0x3f7) { io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000; addr = io_base | ((port >> 2) << 12) | (port & 0xfff); } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/irq.c linux.ac/arch/ia64/sn/sn1/irq.c --- linux.vanilla/arch/ia64/sn/sn1/irq.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/irq.c Tue Apr 10 18:12:08 2001 @@ -4,11 +4,13 @@ * Copyright (C) 2000 Silicon Graphics * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) * Copyright (C) 2000 Alan Mayer (ajm@sgi.com) + * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com) */ #include #include #include +#include #include #include #include @@ -30,28 +32,23 @@ #include #include +#define IRQ_BIT_OFFSET 64 -int bit_pos_to_irq(int bit); -int irq_to_bit_pos(int irq); -void add_interrupt_randomness(int irq); -void * kmalloc(size_t size, int flags); -void kfree(const void *); -int sgi_pci_intr_support (unsigned int, device_desc_t *, devfs_handle_t *, pciio_intr_line_t *, devfs_handle_t *); -pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -int request_irq(unsigned int, void (*)(int, void *, struct pt_regs *), unsigned long, const char *, void *); - -/* This should be dynamically allocated, at least part of it. */ -/* For the time being, though, we'll statically allocate it */ -/* because kmalloc hasn't been initiallized at the time this */ -/* array is initiallized. One way to do it would be to statically */ -/* allocate the data for node 0, then let other nodes, as they */ -/* need it, dynamically allocate their own data space. */ - -struct sn1_cnode_action_list *sn1_node_actions[MAX_COMPACT_NODES]; -struct sn1_cnode_action_list sn1_actions[MAX_COMPACT_NODES][256]; +int bit_pos_to_irq(int bit) +{ + if (bit > 118) + bit = 118; + return (bit + IRQ_BIT_OFFSET); +} +static inline int irq_to_bit_pos(int irq) +{ + int bit = irq - IRQ_BIT_OFFSET; -extern int numnodes; + if (bit > 63) + bit -= 64; + return bit; +} static unsigned int sn1_startup_irq(unsigned int irq) @@ -82,6 +79,10 @@ static void sn1_end_irq(unsigned int irq) { + int bit; + + bit = irq_to_bit_pos(irq); + LOCAL_HUB_CLR_INTR(bit); } static void @@ -89,38 +90,6 @@ { } - -static void -sn1_handle_irq(int irq, void *dummy, struct pt_regs *regs) -{ - int bit, cnode; - struct sn1_cnode_action_list *alp; - struct sn1_intr_action *ap; - void (*handler)(int, void *, struct pt_regs *); - unsigned long flags = 0; - int cpuid = smp_processor_id(); - - - bit = irq_to_bit_pos(irq); - LOCAL_HUB_CLR_INTR(bit); - cnode = cpuid_to_cnodeid(cpuid); - alp = sn1_node_actions[cnode]; - ap = alp[irq].action_list; - if (ap == NULL) { - return; - } - while (ap) { - flags |= ap->flags; - handler = ap->handler; - (*handler)(irq,ap->intr_arg,regs); - ap = ap->next; - } - if ((flags & SA_SAMPLE_RANDOM) != 0) - add_interrupt_randomness(irq); - - return; -} - struct hw_interrupt_type irq_type_sn1 = { "sn1_irq", sn1_startup_irq, @@ -132,134 +101,83 @@ sn1_set_affinity_irq }; -struct irqaction sn1_irqaction = { - sn1_handle_irq, - 0, - 0, - NULL, - NULL, - NULL, -}; void sn1_irq_init (void) { - int i,j; + int i; for (i = 0; i <= NR_IRQS; ++i) { - if (irq_desc[i].handler == &no_irq_type) { - irq_desc[i].handler = &irq_type_sn1; - if (i >=71 && i <= 181) { - irq_desc[i].action = &sn1_irqaction; - } - } - } - - for (i = 0; i < numnodes; i++) { - sn1_node_actions[i] = sn1_actions[i]; - memset(sn1_node_actions[i], 0, - sizeof(struct sn1_cnode_action_list) * - (IA64_MAX_VECTORED_IRQ + 1)); - for (j=0; jhandler == &no_irq_type) { + idesc_from_vector(i)->handler = &irq_type_sn1; } } } -int -sn1_request_irq (unsigned int requested_irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - devfs_handle_t curr_dev; - devfs_handle_t dev; - pciio_intr_t intr_handle; - pciio_intr_line_t line; - device_desc_t dev_desc; - int cpuid, bit, cnode; - struct sn1_intr_action *ap, *new_ap; - struct sn1_cnode_action_list *alp; - int irq; - - if ( (requested_irq & 0xff) == 0 ) { - int ret; - - sgi_pci_intr_support(requested_irq, - &dev_desc, &dev, &line, &curr_dev); - intr_handle = pciio_intr_alloc(curr_dev, NULL, line, curr_dev); - bit = intr_handle->pi_irq; - cpuid = intr_handle->pi_cpu; - irq = bit_pos_to_irq(bit); - cnode = cpuid_to_cnodeid(cpuid); - new_ap = (struct sn1_intr_action *)kmalloc( - sizeof(struct sn1_intr_action), GFP_KERNEL); - irq_desc[irq].status = 0; - new_ap->handler = handler; - new_ap->intr_arg = dev_id; - new_ap->flags = irqflags; - new_ap->next = NULL; - alp = sn1_node_actions[cnode]; - - spin_lock(&alp[irq].action_list_lock); - ap = alp[irq].action_list; - /* check action list for "share" consistency */ - while (ap){ - if (!(ap->flags & irqflags & SA_SHIRQ) ) { - return(-EBUSY); - spin_unlock(&alp[irq].action_list_lock); - } - ap = ap->next; - } - ap = alp[irq].action_list; - if (ap) { - while (ap->next) { - ap = ap->next; - } - ap->next = new_ap; - } else { - alp[irq].action_list = new_ap; - } - ret = pciio_intr_connect(intr_handle, (intr_func_t)handler, dev_id, NULL); - if (ret) { /* connect failed, undo what we did. */ - new_ap = alp[irq].action_list; - if (new_ap == ap) { - alp[irq].action_list = NULL; - kfree(ap); - } else { - while (new_ap->next && new_ap->next != ap) { - new_ap = new_ap->next; - } - if (new_ap->next == ap) { - new_ap->next = ap->next; - kfree(ap); - } - } - } - - spin_unlock(&alp[irq].action_list_lock); - return(ret); - } else { - return(request_irq(requested_irq, handler, irqflags, devname, dev_id)); - } -} -#if !defined(CONFIG_IA64_SGI_IO) +#if !defined(CONFIG_IA64_SGI_SN1) void sn1_pci_fixup(int arg) { } #endif -int -bit_pos_to_irq(int bit) { -#define BIT_TO_IRQ 64 +#ifdef CONFIG_PERCPU_IRQ + +extern irq_desc_t irq_descX[NR_IRQS]; +irq_desc_t *irq_desc_ptr[NR_CPUS] = { irq_descX }; + +/* + * Each slave AP allocates its own irq table. + */ +int __init cpu_irq_init(void) +{ + irq_desc_ptr[smp_processor_id()] = (irq_desc_t *)kmalloc(sizeof(irq_descX), GFP_KERNEL); + if (irq_desc_ptr[smp_processor_id()] == 0) + return(-1); + memcpy(irq_desc_ptr[smp_processor_id()], irq_desc_ptr[0], + sizeof(irq_descX)); + return(0); +} + +/* + * This can also allocate the irq tables for the other cpus, specifically + * on their nodes. + */ +int __init master_irq_init(void) +{ + return(0); +} + +/* + * The input is an ivt level. + */ +irq_desc_t *idesc_from_vector(unsigned int ivnum) +{ + return(irq_desc_ptr[smp_processor_id()] + ivnum); +} - return bit + BIT_TO_IRQ; +/* + * The input is a "soft" level, that we encoded in. + */ +irq_desc_t *idesc_from_irq(unsigned int irq) +{ + return(irq_desc_ptr[irq >> 8] + (irq & 0xff)); } -int -irq_to_bit_pos(int irq) { -#define IRQ_TO_BIT 64 +unsigned int ivector_from_irq(unsigned int irq) +{ + return(irq & 0xff); +} - return irq - IRQ_TO_BIT; +/* + * This should return the Linux irq # for the i/p vector on the + * i/p cpu. We currently do not track this. + */ +unsigned int irq_from_cpuvector(int cpunum, unsigned int vector) +{ + return (vector); } + +#endif /* CONFIG_PERCPU_IRQ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/llsc4.c linux.ac/arch/ia64/sn/sn1/llsc4.c --- linux.vanilla/arch/ia64/sn/sn1/llsc4.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/llsc4.c Tue Apr 10 18:12:08 2001 @@ -35,6 +35,15 @@ static int inttest=0; #endif +#ifdef IA64_SEMFIX_INSN +#undef IA64_SEMFIX_INSN +#endif +#ifdef IA64_SEMFIX +#undef IA64_SEMFIX +#endif +# define IA64_SEMFIX_INSN +# define IA64_SEMFIX "" + /* * Test parameter table for AUTOTEST @@ -46,22 +55,22 @@ } autotest_table_t; autotest_table_t autotest_table[] = { - {1000000, 2, 0x2b4 }, - {1000000, 16, 0, }, - {1000000, 16, 4, }, - {1000000, 128, 0x44 }, - {1000000, 128, 0x84 }, - {1000000, 128, 0x200 }, - {1000000, 128, 0x204 }, - {1000000, 128, 0x2b4 }, - {1000000, 2, 8*MB+0x2b4 }, - {1000000, 16, 8*MB+0 }, - {1000000, 16, 8*MB+4 }, - {1000000, 128, 8*MB+0x44 }, - {1000000, 128, 8*MB+0x84 }, - {1000000, 128, 8*MB+0x200 }, - {1000000, 128, 8*MB+0x204 }, - {1000000, 128, 8*MB+0x2b4 }, + {5000000, 2, 0x2b4 }, + {5000000, 16, 0, }, + {5000000, 16, 4, }, + {5000000, 128, 0x44 }, + {5000000, 128, 0x84 }, + {5000000, 128, 0x200 }, + {5000000, 128, 0x204 }, + {5000000, 128, 0x2b4 }, + {5000000, 2, 8*MB+0x2b4 }, + {5000000, 16, 8*MB+0 }, + {5000000, 16, 8*MB+4 }, + {5000000, 128, 8*MB+0x44 }, + {5000000, 128, 8*MB+0x84 }, + {5000000, 128, 8*MB+0x200 }, + {5000000, 128, 8*MB+0x204 }, + {5000000, 128, 8*MB+0x2b4 }, {0}}; /* @@ -134,20 +143,21 @@ static void Speedo(void); int autotest_enabled=0; -static int autotest_explicit_flush=0; static int llsctest_number=-1; static int errstop_enabled=0; static int fail_enabled=0; static int selective_trigger=0; +static int dump_block_addrs_opt=0; +static uint errlock=0; static int __init autotest_enable(char *str) { autotest_enabled = 1; return 1; } -static int __init set_llscxflush(char *str) +static int __init set_llscblkadr(char *str) { - autotest_explicit_flush = 1; + dump_block_addrs_opt = 1; return 1; } static int __init set_llscselt(char *str) @@ -179,55 +189,39 @@ printk (" Test options:\n"); printk (" llsctest=\t%d\tTest number to run (all = -1)\n", llsctest_number); printk (" llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off"); - printk (" llscxflush \t%s\tEnable explicit FC in test\n", autotest_explicit_flush ? "on" : "off"); printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); + printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); + printk (" SEMFIX: %s\n", IA64_SEMFIX); printk ("\n"); } __setup("autotest", autotest_enable); __setup("llsctest=", set_llsctest); __setup("llscerrstop", set_llscerrstop); -__setup("llscxflush", set_llscxflush); __setup("llscfail", set_llscfail); __setup("llscselt", set_llscselt); +__setup("llscblkadr", set_llscblkadr); -extern inline void -flush_buddy(void *p) -{ - long lp; - - if (autotest_explicit_flush) { - lp = (long)p; - lp ^= 0x40; - asm volatile ("fc %0" :: "r"(lp) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - } -} - -static int +extern inline int set_lock(uint *lock, uint id) { uint old; - flush_buddy(lock); old = cmpxchg_acq(lock, 0, id); return (old == 0); } -static int +extern inline int clr_lock(uint *lock, uint id) { uint old; - flush_buddy(lock); old = cmpxchg_rel(lock, id, 0); return (old == id); } -static void +extern inline void zero_lock(uint *lock) { - flush_buddy(lock); *lock = 0; } @@ -322,7 +316,6 @@ return 1; } if (correct_errors) { - flush_buddy(privp); tp->private[linei] = *privp; } errs++; @@ -343,7 +336,6 @@ errs++; } pval++; - flush_buddy(privp); *privp = pval; tp->private[linei] = pval; break; @@ -425,9 +417,7 @@ errs++; } - flush_buddy(sharep); *sharep = lockpat; - flush_buddy(sharecopy); *sharecopy = lockpat; @@ -471,7 +461,7 @@ static int rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int linei, int exp, int found, int stillbad) { - int cpu; + int cpu, i; long synerr; int selt; @@ -487,6 +477,11 @@ } spin(1); + i = 100; + while (i && set_lock(&errlock, 1) != 1) { + spin(1); + i--; + } printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n", msg, k_testnumber, thread, linei, pass, pass, jiffies, exp, found); @@ -512,6 +507,7 @@ printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); spin(2); printk("\n\n"); + clr_lock(&errlock, 1); if (errstop_enabled) { local_irq_disable(); @@ -639,8 +635,10 @@ testnumber = llsctest_number; } else { testnumber++; - if (autotest_table[testnumber].passes == 0) + if (autotest_table[testnumber].passes == 0) { testnumber = 0; + dump_block_addrs_opt = 0; + } } k_passes = autotest_table[testnumber].passes; k_linepad = autotest_table[testnumber].linepad; @@ -704,6 +702,22 @@ } static void +dump_block_addrs(void) +{ + int i; + + printk("LLSC TestNumber %ld\n", k_testnumber); + + for (i=0; ithreadstate == TS_KILLED) { @@ -717,6 +731,7 @@ build_mem_map(unsigned long start, unsigned long end, void *arg) { long lstart; + long align = 8*MB; /* * HACK - skip the kernel on the first node */ @@ -731,9 +746,11 @@ while (lstart > start && (!PageReserved(virt_to_page(lstart-PAGE_SIZE)) && virt_to_page(lstart-PAGE_SIZE)->count.counter == 0)) lstart -= PAGE_SIZE; - printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); + lstart = (lstart + align -1) /align * align; + end = end / align * align; if (lstart >= end) return 0; + printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); memmap[memmapx].vstart = lstart; memmap[memmapx].vend = end; @@ -812,6 +829,8 @@ if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT; k_linecount = k_linecount & ~1; setup_block_addresses(); + if (dump_block_addrs_opt) + dump_block_addrs(); k_currentpass = pass++; k_go = ST_RUN; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/machvec.c linux.ac/arch/ia64/sn/sn1/machvec.c --- linux.vanilla/arch/ia64/sn/sn1/machvec.c Sat Aug 12 03:09:06 2000 +++ linux.ac/arch/ia64/sn/sn1/machvec.c Tue Apr 10 18:12:08 2001 @@ -1,2 +1,18 @@ #define MACHVEC_PLATFORM_NAME sn1 #include +#include +#include +void* +sn1_mk_io_addr_MACRO + +dma_addr_t +sn1_pci_map_single_MACRO + +int +sn1_pci_map_sg_MACRO + +unsigned long +sn1_virt_to_phys_MACRO + +void * +sn1_phys_to_virt_MACRO diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/mm.c linux.ac/arch/ia64/sn/sn1/mm.c --- linux.vanilla/arch/ia64/sn/sn1/mm.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/mm.c Tue Apr 10 18:12:08 2001 @@ -1,7 +1,7 @@ /* - * Copyright, 2000, Silicon Graphics. + * Copyright, 2000-2001, Silicon Graphics. * Copyright Srinivasa Thirumalachar (sprasad@engr.sgi.com) - * Copyright 2000 Kanoj Sarcar (kanoj@sgi.com) + * Copyright 2000-2001 Kanoj Sarcar (kanoj@sgi.com) */ #include @@ -11,32 +11,23 @@ #include #include -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#define DONE_NOTHING 0 +#define DONE_FINDING 1 +#define DONE_BUILDING 2 -/* - * Note that the nodemem[] data structure does not support arbitrary - * memory types and memory descriptors inside the node. For example, - * you can not have multiple efi-mem-type segments in the node and - * expect the OS not to use specific mem-types. Currently, the - * assumption is that "start" is the start of virtual/physical memory - * on the node. PROM can reserve some memory _only_ at the beginning. - * This is tracked via the "usable" field, that maintains where the - * os can start using memory from on a node (ie end of PROM memory). - * setup_node_bootmem() is passed the above "usable" value, and is - * expected to make bootmem calls that ensure lower memory is not used. - * Note that the bootmem for a node is initialized on the entire node, - * without regards to any holes - then we reserve the holes in - * setup_sn1_bootmem(), to make sure the holes are not handed out by - * alloc_bootmem, as well as the corresponding mem_map entries are not - * considered allocatable by the page_alloc routines. - */ struct nodemem_s { - u64 start ; - u64 end ; - u64 hole[SN1_MAX_BANK_PER_NODE] ; - u64 usable; -} nodemem[MAXNODES] ; + u64 start; /* start of kernel usable memory */ + u64 end; /* end of kernel usable memory */ + u64 mtot; /* total kernel usable memory */ + u64 done; /* state of bootmem initialization */ + u64 bstart; /* where should the bootmem area be */ + u64 bsize; /* bootmap size */ + u64 hole[SN1_MAX_BANK_PER_NODE]; +} nodemem[MAXNODES]; + static int nodemem_valid = 0; static int __init @@ -46,7 +37,7 @@ unsigned long count = 0; if (start >= end) - return 0 ; + return 0; /* * Get the memmap ptrs to the start and end of the holes. @@ -54,31 +45,33 @@ * Can we do virt_to_page(end), if end is on the next node? */ - page = virt_to_page(start-1); - page++ ; - pageend = virt_to_page(end) ; + page = virt_to_page(start - 1); + page++; + pageend = virt_to_page(end); printk("hpage=0x%lx, hpageend=0x%lx\n", (u64)page, (u64)pageend) ; free_bootmem_node(NODE_DATA(nid), __pa(page), (u64)pageend - (u64)page); - return count ; + return count; } -void +static void __init free_unused_memmap_node(int nid) { - u64 i = 0 ; - u64 holestart = -1 ; + u64 i = 0; + u64 holestart = -1; + u64 start = nodemem[nid].start; + start = ((start >> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); do { - holestart = nodemem[nid].hole[i] ; - i++ ; + holestart = nodemem[nid].hole[i]; + i++; while ((i < SN1_MAX_BANK_PER_NODE) && - (nodemem[nid].hole[i] == (u64)-1)) - i++ ; + (nodemem[nid].hole[i] == (u64)-1)) + i++; if (i < SN1_MAX_BANK_PER_NODE) free_unused_memmap_hole(nid, holestart, - nodemem[nid].start + (i<> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); - nodesize = nodemem[nid].end - nodemem[nid].start ; + nodesize = nodemem[nid].end - start ; numpfn = nodesize >> PAGE_SHIFT; - bank0size = nodemem[nid].hole[0] - nodemem[nid].start ; + bank0size = nodemem[nid].hole[0] - start ; /* If nid == master node && no kernel text replication */ bank0size -= 0xA00000 ; /* Kernel text + stuff */ bank0size -= ((numpfn + 7) >> 3); @@ -163,198 +158,198 @@ #ifdef CONFIG_DISCONTIGMEM -extern bootmem_data_t bdata[] ; -static int curnodeid ; +extern bootmem_data_t bdata[]; +/* + * This assumes there will be a hole in kernel-usable memory between nodes + * (due to prom). The memory descriptors invoked via efi_memmap_walk are + * in increasing order. It tries to identify first suitable free area to + * put the bootmem for the node in. When presented with the md holding + * the kernel, it only searches at the end of the kernel area. + */ static int __init -setup_node_bootmem(unsigned long start, unsigned long end, unsigned long nodefree) +find_node_bootmem(unsigned long start, unsigned long end, void *arg) { + int nasid = GetNasId(__pa(start)); + int cnodeid = NASID_TO_CNODEID(nasid); + unsigned long nodesize; extern char _end; - int i; - unsigned long kernelend = PAGE_ALIGN((unsigned long)(&_end)); - unsigned long pkernelend = __pa(kernelend); - unsigned long bootmap_start, bootmap_size; - unsigned long pstart, pend; - - pstart = __pa(start) ; - pend = __pa(end) ; - - /* If we are past a node mem boundary, on simulated dig numa - * increment current node id. */ - - curnodeid = NASID_TO_CNODEID(GetNasId(pstart)) ; - - /* - * Make sure we are being passed page aligned addresses. - */ - if ((start & (PAGE_SIZE - 1)) || (end & (PAGE_SIZE - 1))) - panic("setup_node_bootmem:align"); + unsigned long kaddr = (unsigned long)&_end; - - /* For now, just go to the lower CHUNK alignment so that - * chunktonid of 0-8MB and other lower mem pages get initted. */ - - pstart &= CHUNKMASK ; - pend = (pend+CHUNKSZ-1) & CHUNKMASK; - - /* If pend == 0, both addrs below 8 MB, special case it - * FIX: CHUNKNUM(pend-1) broken if pend == 0 - * both addrs within 8MB */ - - if (pend == 0) { - chunktonid[0] = 0; - return 0; - } - - /* Fill up the chunktonid array first. */ - - for (i = PCHUNKNUM(pstart); i <= PCHUNKNUM(pend-1); i++) - chunktonid[i] = curnodeid; - - /* This check is bogus for now till MAXCHUNKS is properly - * defined to say if it includes holes or not. */ - - if ((CHUNKTONID(PCHUNKNUM(pend)) > MAXCHUNKS) || - (PCHUNKNUM(pstart) >= PCHUNKNUM(pend))) { - printk("Ign 0x%lx-0x%lx, ", __pa(start), __pa(end)); + /* + * Track memory available to kernel. + */ + nodemem[cnodeid].mtot += ((end - start) >> PAGE_SHIFT); + if (nodemem[cnodeid].done != DONE_NOTHING) return(0); - } + nodesize = nodemem[cnodeid].end - ((nodemem[cnodeid].start >> + SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); + nodesize >>= PAGE_SHIFT; - /* This routine gets called many times in node 0. - * The first one to reach here would be the one after - * kernelend to end of first node. */ - - NODE_DATA(curnodeid)->bdata = &(bdata[curnodeid]); - - if (curnodeid == 0) { - /* for master node, forcibly assign these values - * This gets called many times on dig but we - * want these exact values - * Also on softsdv, the memdesc for 0 is missing */ - NODE_START(curnodeid) = PAGE_OFFSET; - NODE_SIZE(curnodeid) = (end - PAGE_OFFSET); - } else { - /* This gets called only once for non zero nodes - * If it does not, then NODE_STARt should be - * LOCAL_BASE(nid) */ + /* + * Adjust limits for the md holding the kernel. + */ + if ((start < kaddr) && (end > kaddr)) + start = PAGE_ALIGN(kaddr); - NODE_START(curnodeid) = start; - NODE_SIZE(curnodeid) = (end - start); + /* + * We need space for mem_map, bootmem map plus a few more pages + * to satisfy alloc_bootmems out of node 0. + */ + if ((end - start) > ((nodesize * sizeof(struct page)) + (nodesize/8) + + (10 * PAGE_SIZE))) { + nodemem[cnodeid].bstart = start; + nodemem[cnodeid].done = DONE_FINDING; } + return(0); +} - /* if end < kernelend do not do anything below this */ - if (pend < pkernelend) - return 0 ; +/* + * This assumes there will be a hole in kernel-usable memory between nodes + * (due to prom). The memory descriptors invoked via efi_memmap_walk are + * in increasing order. + */ +static int __init +build_node_bootmem(unsigned long start, unsigned long end, void *arg) +{ + int nasid = GetNasId(__pa(start)); + int curnodeid = NASID_TO_CNODEID(nasid); + int i; + unsigned long pstart, pend; + extern char _end, _stext; + unsigned long kaddr = (unsigned long)&_end; - /* - * Handle the node that contains kernel text/data. It would - * be nice if the loader loads the kernel at a "chunk", ie - * not in memory that the kernel will ignore (else free_initmem - * has to worry about not freeing memory that the kernel ignores). - * Note that we assume the space from the node start to - * KERNEL_START can not hold all the bootmem data, but from kernel - * end to node end can. - */ - - /* TBD: This may be bogus in light of the above check. */ - - if ((pstart < pkernelend) && (pend >= pkernelend)) { - bootmap_start = pkernelend; - } else { - bootmap_start = __pa(start); /* chunk & page aligned */ + if (nodemem[curnodeid].done == DONE_FINDING) { + /* + * This is where we come to know the node is present. + * Do node wide tasks. + */ + nodemem[curnodeid].done = DONE_BUILDING; + NODE_DATA(curnodeid)->bdata = &(bdata[curnodeid]); + + /* + * Update the chunktonid array as a node wide task. There + * are too many smalls mds on first node to do this per md. + */ + pstart = __pa(nodemem[curnodeid].start); + pend = __pa(nodemem[curnodeid].end); + pstart &= CHUNKMASK; + pend = (pend + CHUNKSZ - 1) & CHUNKMASK; + /* Possible check point to enforce minimum node size */ + if (nodemem[curnodeid].bstart == -1) { + printk("No valid bootmem area on node %d\n", curnodeid); + while(1); + } + for (i = PCHUNKNUM(pstart); i <= PCHUNKNUM(pend - 1); i++) + chunktonid[i] = curnodeid; + if ((CHUNKTONID(PCHUNKNUM(pend)) > MAXCHUNKS) || + (PCHUNKNUM(pstart) >= PCHUNKNUM(pend))) { + printk("Ign 0x%lx-0x%lx, ", __pa(start), __pa(end)); + return(0); + } + + /* + * NODE_START and NODE_SIZE determine the physical range + * on the node that mem_map array needs to be set up for. + */ + NODE_START(curnodeid) = ((nodemem[curnodeid].start >> + SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); + NODE_SIZE(curnodeid) = (nodemem[curnodeid].end - + NODE_START(curnodeid)); + + nodemem[curnodeid].bsize = + init_bootmem_node(NODE_DATA(curnodeid), + (__pa(nodemem[curnodeid].bstart) >> PAGE_SHIFT), + (__pa((nodemem[curnodeid].start >> SN1_NODE_ADDR_SHIFT) + << SN1_NODE_ADDR_SHIFT) >> PAGE_SHIFT), + (__pa(nodemem[curnodeid].end) >> PAGE_SHIFT)); + + } else if (nodemem[curnodeid].done == DONE_NOTHING) { + printk("build_node_bootmem: node %d weirdness\n", curnodeid); + while(1); /* Paranoia */ } /* - * Low memory is reserved for PROM use on SN1. The current node - * memory model is [PROM mem ... kernel ... free], where the - * first two components are optional on a node. + * Free the entire md. */ - if (bootmap_start < __pa(nodefree)) - bootmap_start = __pa(nodefree); - -/* XXX TBD */ -/* For curnodeid of 0, this gets called many times because of many - * < 8MB segments. start gets bumped each time. We want to fix it - * to 0 now. - */ - if (curnodeid == 0) - start=PAGE_OFFSET; -/* - * This makes sure that in free_area_init_core - paging_init - * idx is the entire node page range and for loop goes thro - * all pages. test_bit for kernel pages should remain reserved - * because free available mem takes care of kernel_start and end - */ - - bootmap_size = init_bootmem_node(NODE_DATA(curnodeid), - (bootmap_start >> PAGE_SHIFT), - (__pa(start) >> PAGE_SHIFT), (__pa(end) >> PAGE_SHIFT)); + free_bootmem_node(NODE_DATA(curnodeid), __pa(start), (end - start)); - free_bootmem_node(NODE_DATA(curnodeid), bootmap_start + bootmap_size, - __pa(end) - (bootmap_start + bootmap_size)); + /* + * Reclaim back the bootmap and kernel areas. + */ + if ((start <= nodemem[curnodeid].bstart) && (end > + nodemem[curnodeid].bstart)) + reserve_bootmem_node(NODE_DATA(curnodeid), + __pa(nodemem[curnodeid].bstart), nodemem[curnodeid].bsize); + if ((start <= kaddr) && (end > kaddr)) + reserve_bootmem_node(NODE_DATA(curnodeid), + __pa(&_stext), (&_end - &_stext)); return(0); } -void +void __init setup_sn1_bootmem(int maxnodes) { int i; - for (i=0;i> SN1_NODE_ADDR_SHIFT) << - SN1_NODE_ADDR_SHIFT); - nodemem_valid = 1 ; + nodemem_valid = 1; - /* After building the nodemem map, check if the page table + /* + * After building the nodemem map, check if the node memmap * will fit in the first bank of each node. If not change - * the node end addr till it fits. We dont want to do this - * in mm/page_alloc.c + * the node end addr till it fits. */ - for (i=0;i> PAGE_SHIFT; + for (i = 0; i < numnodes; i++) { + unsigned long startpfn = __pa((void *)NODE_START(i)) >> PAGE_SHIFT; + unsigned long numpfn = NODE_SIZE(i) >> PAGE_SHIFT; + memset(zones_size, 0, sizeof(zones_size)); + memset(holes_size, 0, sizeof(holes_size)); + holes_size[ZONE_DMA] = numpfn - nodemem[i].mtot; + + if ((startpfn + numpfn) < max_dma) { + zones_size[ZONE_DMA] = numpfn; + } else if (startpfn > max_dma) { + zones_size[ZONE_NORMAL] = numpfn; + panic("discontig_paging_init: %d\n", i); + } else { + zones_size[ZONE_DMA] = (max_dma - startpfn); + zones_size[ZONE_NORMAL] = numpfn - zones_size[ZONE_DMA]; + panic("discontig_paging_init: %d\n", i); + } + free_area_init_node(i, NODE_DATA(i), NULL, zones_size, startpfn< ") ; for (j=0;j + +/* + * ia64_sn_probe_io_slot + * This function will probe a physical address to determine if + * the address can be read. If reading the address causes a BUS + * error, an error is returned. If the probe succeeds, the contents + * of the memory location is returned. + * + * Calling sequence: + * ia64_probe_io_slot(paddr, size, data_ptr) + * + * Input: + * paddr Physical address to probe + * size Number bytes to read (1,2,4,8) + * data_ptr Address to store value read by probe + * (-1 returned if probe fails) + * + * Output: + * Status + * 0 - probe successful + * 1 - probe failed (generated MCA) + * 2 - Bad arg + * <0 - PAL error + */ + + +u64 +ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr) +{ + struct ia64_sal_retval isrv; + + SAL_CALL(isrv, SN_SAL_PROBE, paddr, size, 0, 0, 0, 0, 0); + + if (data_ptr) { + switch (size) { + case 1: + *((u8*)data_ptr) = (u8)isrv.v0; + break; + case 2: + *((u16*)data_ptr) = (u16)isrv.v0; + break; + case 4: + *((u32*)data_ptr) = (u32)isrv.v0; + break; + case 8: + *((u64*)data_ptr) = (u64)isrv.v0; + break; + default: + isrv.status = 2; + } + } + + return isrv.status; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/setup.c linux.ac/arch/ia64/sn/sn1/setup.c --- linux.vanilla/arch/ia64/sn/sn1/setup.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/sn1/setup.c Tue Apr 10 18:12:08 2001 @@ -15,12 +15,30 @@ #include #include #include +#include #include #include +#include #include #include #include +#include +#include + + +/* + * This is the address of the RRegs in the HSpace of the global + * master. It is used by a hack in serial.c (serial_[in|out], + * printk.c (early_printk), and kdb_io.c to put console output on that + * node's Bedrock UART. It is initialized here to 0, so that + * early_printk won't try to access the UART before + * master_node_bedrock_address is properly calculated. + */ +u64 master_node_bedrock_address = 0UL; + +static void sn_fix_ivt_for_partitioned_system(void); + /* * The format of "screen_info" is strange, and due to early i386-setup @@ -58,31 +76,169 @@ #endif } +#if defined(BRINGUP) && defined(CONFIG_IA64_EARLY_PRINTK) +void __init +early_sn1_setup(void) +{ + master_node_bedrock_address = + (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); + printk("early_sn1_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); +} +#endif /* BRINGUP && CONFIG_IA64_EARLY_PRINTK */ + void __init sn1_setup(char **cmdline_p) { - extern void init_sn1_smp_config(void); +#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) + struct serial_struct req; +#endif + + MAX_DMA_ADDRESS = PAGE_OFFSET + 0x10000000000UL; + master_node_bedrock_address = + (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); + printk("sn1_setup: setting master_node_bedrock_address to 0x%lx\n", + master_node_bedrock_address); + +#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) + /* + * We do early_serial_setup() to clean out the rs-table[] from the + * statically compiled in version. + */ + memset(&req, 0, sizeof(struct serial_struct)); + req.line = 0; + req.baud_base = 124800; + req.port = 0; + req.port_high = 0; + req.irq = 0; + req.flags = (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST); + req.io_type = SERIAL_IO_MEM; + req.hub6 = 0; + req.iomem_base = (u8 *)(master_node_bedrock_address + 0x80); + req.iomem_reg_shift = 3; + req.type = 0; + req.xmit_fifo_size = 0; + req.custom_divisor = 0; + req.closing_wait = 0; + early_serial_setup(&req); +#endif /* CONFIG_SERIAL && !CONFIG_SERIAL_SGI_L1_PROTOCOL */ + ROOT_DEV = to_kdev_t(0x0301); /* default to first IDE drive */ + sn_fix_ivt_for_partitioned_system(); - init_sn1_smp_config(); -#ifdef ZZZ -#if !defined (CONFIG_IA64_SOFTSDV_HACKS) - /* - * Program the timer to deliver timer ticks. 0x40 is the I/O port - * address of PIT counter 0, 0x43 is the I/O port address of the - * PIT control word. - */ - request_region(0x40,0x20,"timer"); - outb(0x34, 0x43); /* Control word */ - outb(LATCH & 0xff , 0x40); /* LSB */ - outb(LATCH >> 8, 0x40); /* MSB */ - printk("PIT: LATCH at 0x%x%x for %d HZ\n", LATCH >> 8, LATCH & 0xff, HZ); -#endif -#endif #ifdef CONFIG_SMP init_smp_config(); #endif screen_info = sn1_screen_info; +} + + +/* + * sn_fix_ivt_for_partitioned_system + * + * This is an ugly hack that is needed for partitioned systems. + * + * On a partitioned system, most partitions do NOT have a physical address 0. + * Unfortunately, the exception handling code in ivt.S has a couple of physical + * addresses of kernel structures hardcoded into "movl" instructions. + * These addresses are correct on partition 0 only. On all other partitions, + * the addresses must be changed to reference the correct address. + * + * This routine scans the ivt code and replaces the hardcoded addresses with + * the correct address. + * + * Note that we could have made the ivt.S code dynamically determine the correct + * address but this would add code to performance critical pathes. This option + * was rejected. + */ + +#define TEMP_mlx 4 /* template type that contains movl instruction */ +#define TEMP_mlX 5 /* template type that contains movl instruction */ + +typedef union { /* Instruction encoding for movl instruction */ + struct { + unsigned long qp:6; + unsigned long r1:7; + unsigned long imm7b:7; + unsigned long vc:1; + unsigned long ic:1; + unsigned long imm5c:5; + unsigned long imm9d:9; + unsigned long i:1; + unsigned long op:4; + unsigned long fill:23; + } b; + unsigned long l; +} movl_instruction_t; + +#define MOVL_OPCODE 6 +#define MOVL_ARG(a,b) (((long)a.i<<63) | ((long)b<<22) | ((long)a.ic<<21) | \ + ((long)a.imm5c<<16) | ((long)a.imm9d<<7) | ((long)a.imm7b)) + +typedef struct { /* Instruction bundle */ + unsigned long template:5; + unsigned long ins2:41; + unsigned long ins1l:18; + unsigned long ins1u:23; + unsigned long ins0:41; +} instruction_bundle_t; + + +static void __init +sn_fix_ivt_for_partitioned_system(void) +{ + extern int ia64_ivt; + instruction_bundle_t *p, *pend; + movl_instruction_t ins0, ins1, ins2; + long new_ins1, phys_offset; + unsigned long val; + + /* + * Setup to scan the ivt code. + */ + p = (instruction_bundle_t*)&ia64_ivt; + pend = p + 0x8000/sizeof(instruction_bundle_t); + phys_offset = __pa(p) & ~0x1ffffffffUL; + + /* + * Hunt for movl instructions that contain the node 0 physical address + * of "SWAPPER_PGD_ADDR". These addresses must be relocated to reference the + * actual node that the kernel is loaded on. + */ + for (; p < pend; p++) { + if (p->template != TEMP_mlx && p->template != TEMP_mlX) + continue; + ins0.l = p->ins0; + if (ins0.b.op != MOVL_OPCODE) + continue; + ins1.l = ((long)p->ins1u<<18) | p->ins1l; + ins2.l = p->ins2; + val = MOVL_ARG(ins0.b, ins1.l); + + /* + * Test for correct address. SWAPPER_PGD_ADDR will + * always be a node 0 virtual address. Note that we cant + * use the __pa or __va macros here since they may contain + * debug code that gets fooled here. + */ + if ((PAGE_OFFSET | val) != SWAPPER_PGD_ADDR) + continue; + + /* + * We found an instruction that needs to be fixed. The following + * inserts the NASID of the ivt into the movl instruction. + */ + new_ins1 = ins1.l | (phys_offset>>22); + p->ins1l = new_ins1 & 0x3ffff; + p->ins1u = (new_ins1>>18) & 0x7fffff; + ia64_fc(p); + } + + /* + * Do necessary serialization. + */ + ia64_sync_i(); + ia64_srlz_i(); + } int diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/smp.c linux.ac/arch/ia64/sn/sn1/smp.c --- linux.vanilla/arch/ia64/sn/sn1/smp.c Thu Jan 4 21:00:15 2001 +++ linux.ac/arch/ia64/sn/sn1/smp.c Tue Apr 10 18:12:08 2001 @@ -124,10 +124,10 @@ #ifdef CONFIG_SMP +#ifdef PTC_NOTYET static void __init process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain) { -#ifdef PTC_NOTYET ia64_sal_ptc_domain_proc_entry_t *pe; int i, sapicid, cpuid; @@ -138,7 +138,6 @@ sn_sapicid_info[cpuid].domain = domain; sn_sapicid_info[cpuid].sapicid = sapicid; } -#endif } @@ -153,6 +152,7 @@ process_sal_ptc_domain_info(di, i); } } +#endif void __init @@ -179,7 +179,7 @@ { #ifdef PTC_NOTYET - sn_sapicid_info[0].sapicid = hard_processor_sapicid(); + sn_sapicid_info[0].sapicid = hard_smp_processor_id(); #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/sn1_asm.S linux.ac/arch/ia64/sn/sn1/sn1_asm.S --- linux.vanilla/arch/ia64/sn/sn1/sn1_asm.S Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/sn1_asm.S Tue Apr 10 18:12:08 2001 @@ -4,3 +4,146 @@ * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) */ +#include +#ifdef CONFIG_IA64_SGI_AUTOTEST + +// Testing only. +// Routine will cause MCAs +// zzzmsa(n) +// n=0 MCA via duplicate TLB dropin +// n=0 MCA via read of garbage address +// + +#define ITIR(key, ps) ((key<<8) | (ps<<2)) +#define TLB_PAGESIZE 28 // Use 256MB pages for now. + + .global zzzmca + .proc zzzmca +zzzmca: + alloc loc4 = ar.pfs,2,8,1,0;; + cmp.ne p6,p0=r32,r0;; + movl r2=0x2dead + movl r3=0x3dead + movl r15=0x15dead + movl r16=0x16dead + movl r31=0x31dead + movl loc0=0x34beef + movl loc1=0x35beef + movl loc2=0x36beef + movl loc3=0x37beef + movl out0=0x42beef + + movl r20=0x32feed;; + mov ar32=r20 + movl r20=0x36feed;; + mov ar36=r20 + movl r20=0x65feed;; + mov ar65=r20 + movl r20=0x66feed;; + mov ar66=r20 + +(p6) br.cond.sptk 1f + + rsm 0x2000;; + srlz.d; + mov r11 = 1 + mov r3 = ITIR(0,TLB_PAGESIZE);; + mov cr.itir = r3 + mov r10 = 0;; + itr.d dtr[r11] = r10;; + mov r11 = 2 + + itr.d dtr[r11] = r10;; + br 9f + +1: movl r8=0xfe00000048;; + ld8 r9=[r8];; + mf + mf.a + srlz.d + +9: mov ar.pfs=loc4 + br.ret.sptk rp + + .endp zzzmca + + .global zzzspec + .proc zzzspec +zzzspec: + mov r8=r32 + movl r9=0xe000000000000000 + movl r10=0x4000;; + ld8.s r16=[r8];; + ld8.s r17=[r9];; + add r8=r8,r10;; + ld8.s r18=[r8];; + add r8=r8,r10;; + ld8.s r19=[r8];; + add r8=r8,r10;; + ld8.s r20=[r8];; + mov r8=r0 + tnat.nz p6,p0=r16 + tnat.nz p7,p0=r17 + tnat.nz p8,p0=r18 + tnat.nz p9,p0=r19 + tnat.nz p10,p0=r20;; + (p6) dep r8=-1,r8,0,1;; + (p7) dep r8=-1,r8,1,1;; + (p8) dep r8=-1,r8,2,1;; + (p9) dep r8=-1,r8,3,1;; + (p10) dep r8=-1,r8,4,1;; + br.ret.sptk rp + .endp zzzspec + + .global zzzspec2 + .proc zzzspec2 +zzzspec2: + cmp.eq p6,p7=r2,r2 + movl r16=0xc0000a0001000020 + ;; + mf + ;; + ld8 r9=[r16] + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + ld8 r9=[r16];; + cmp.ne p6,p7=r9,r16 + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + ld8 r9=[r33];; + cmp.ne p6,p7=r9,r33 + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + tpa r23=r32 + add r20=512,r33 + add r21=1024,r33;; + ld8 r9=[r20] + ld8 r10=[r21];; + nop.i 0 + { .mib + nop.m 0 + cmp.ne p6,p7=r10,r33 + (p6) br.spnt 1f + } + ld8 r10=[r32] + ;; + 1: mf.a + mf + br.ret.sptk rp + + .endp zzzspec + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/sn1_ksyms.c linux.ac/arch/ia64/sn/sn1/sn1_ksyms.c --- linux.vanilla/arch/ia64/sn/sn1/sn1_ksyms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/sn1/sn1_ksyms.c Tue Apr 10 18:12:08 2001 @@ -0,0 +1,39 @@ +/* + * 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. + * + * Copyright (C) 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 Jesse Barnes (jbarnes@sgi.com) + */ + + +/* + * Architecture-specific kernel symbols + */ + +#include + +#include + +/* + * I/O routines + */ +EXPORT_SYMBOL(sn1_outb); +EXPORT_SYMBOL(sn1_outl); +EXPORT_SYMBOL(sn1_outw); +EXPORT_SYMBOL(sn1_inw); +EXPORT_SYMBOL(sn1_inb); +EXPORT_SYMBOL(sn1_inl); + +/* + * other stuff (more to be added later, cleanup then) + */ +EXPORT_SYMBOL(sn1_pci_map_sg); +EXPORT_SYMBOL(sn1_pci_unmap_sg); +EXPORT_SYMBOL(sn1_pci_alloc_consistent); +EXPORT_SYMBOL(sn1_pci_free_consistent); +EXPORT_SYMBOL(sn1_dma_address); + +#include +EXPORT_SYMBOL(alloc_pages); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/sv.c linux.ac/arch/ia64/sn/sn1/sv.c --- linux.vanilla/arch/ia64/sn/sn1/sv.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ia64/sn/sn1/sv.c Tue Apr 10 18:12:08 2001 @@ -0,0 +1,551 @@ +/* + * 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. + * + * Copyright (C) 2000 Silicon Graphics, Inc. All rights reserved + * + * This implemenation of synchronization variables is heavily based on + * one done by Steve Lord + * + * Paul Cassella + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* Define this to have sv_test() run some simple tests. + kernel_thread() must behave as expected when this is called. */ +#undef RUN_SV_TEST + +#define DEBUG + +/* Set up some macros so sv_wait(), sv_signal(), and sv_broadcast() + can sanity check interrupt state on architectures where we know + how. */ +#ifdef DEBUG + #define SV_DEBUG_INTERRUPT_STATE + #ifdef __mips64 + #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x1) != 0) + #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x1) == 0) + #define SV_INTERRUPT_TEST_WORKERS 31 + #elif defined(__ia64) + #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x4000) != 0) + #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x4000) == 0) + #define SV_INTERRUPT_TEST_WORKERS 4 /* simulator's slow */ + #else + #undef SV_DEBUG_INTERRUPT_STATE + #define SV_INTERRUPT_TEST_WORKERS 4 /* reasonable? default. */ + #endif /* __mips64 */ +#endif /* DEBUG */ + + +/* XXX FIXME hack hack hack. Our mips64 tree is from before the + switch to WQ_FLAG_EXCLUSIVE, and our ia64 tree is from after it. */ +#ifdef TASK_EXCLUSIVE + #undef EXCLUSIVE_IN_QUEUE +#else + #define EXCLUSIVE_IN_QUEUE + #define TASK_EXCLUSIVE 0 /* for the set_current_state() in sv_wait() */ +#endif + + +static inline void sv_lock(sv_t *sv) { + spin_lock(&sv->sv_lock); +} + +static inline void sv_unlock(sv_t *sv) { + spin_unlock(&sv->sv_lock); +} + +/* up() is "extern inline", so we can't pass its address to sv_wait. + Use this function's address instead. */ +static void up_wrapper(struct semaphore *sem) { + up(sem); +} + +/* spin_unlock() is sometimes a macro. */ +static void spin_unlock_wrapper(spinlock_t *s) { + spin_unlock(s); +} + +/* XXX Perhaps sv_wait() should do the switch() each time and avoid + the extra indirection and the need for the _wrapper functions? */ + +static inline void sv_set_mon_type(sv_t *sv, int type) { + switch (type) { + case SV_MON_SPIN: + sv->sv_mon_unlock_func = + (sv_mon_unlock_func_t)spin_unlock_wrapper; + break; + case SV_MON_SEMA: + sv->sv_mon_unlock_func = + (sv_mon_unlock_func_t)up_wrapper; + if(sv->sv_flags & SV_INTS) { + printk(KERN_ERR "sv_set_mon_type: The monitor lock " + "cannot be shared with interrupts if it is a " + "semaphore!\n"); + BUG(); + } + if(sv->sv_flags & SV_BHS) { + printk(KERN_ERR "sv_set_mon_type: The monitor lock " + "cannot be shared with bottom-halves if it is " + "a semaphore!\n"); + BUG(); + } + break; +#if 0 + /* + * If needed, and will need to think about interrupts. This + * may be needed, for example, if someone wants to use sv's + * with something like dev_base; writers need to hold two + * locks. + */ + case SV_MON_CUSTOM: + { + struct sv_mon_custom *c = lock; + sv->sv_mon_unlock_func = c->sv_mon_unlock_func; + sv->sv_mon_lock = c->sv_mon_lock; + break; + } +#endif + + default: + printk(KERN_ERR "sv_set_mon_type: unknown type %d (0x%x)! " + "(flags 0x%x)\n", type, type, sv->sv_flags); + BUG(); + break; + } + sv->sv_flags |= type; +} + +static inline void sv_set_ord(sv_t *sv, int ord) { + if (!ord) + ord = SV_ORDER_DEFAULT; + + if (ord != SV_ORDER_FIFO && ord != SV_ORDER_LIFO) { + printk(KERN_EMERG "sv_set_ord: unknown order %d (0x%x)! ", + ord, ord); + BUG(); + } + + sv->sv_flags |= ord; +} + +void sv_init(sv_t *sv, sv_mon_lock_t *lock, int flags) +{ + int ord = flags & SV_ORDER_MASK; + int type = flags & SV_MON_MASK; + + /* Copy all non-order, non-type flags */ + sv->sv_flags = (flags & ~(SV_ORDER_MASK | SV_MON_MASK)); + + if((sv->sv_flags & (SV_INTS | SV_BHS)) == (SV_INTS | SV_BHS)) { + printk(KERN_ERR "sv_init: do not set both SV_INTS and SV_BHS, only SV_INTS.\n"); + BUG(); + } + + sv_set_ord(sv, ord); + sv_set_mon_type(sv, type); + + /* If lock is NULL, we'll get it from sv_wait_compat() (and + ignore it in sv_signal() and sv_broadcast()). */ + sv->sv_mon_lock = lock; + + spin_lock_init(&sv->sv_lock); + init_waitqueue_head(&sv->sv_waiters); +} + +/* + * The associated lock must be locked on entry. It is unlocked on return. + * + * Return values: + * + * n < 0 : interrupted, -n jiffies remaining on timeout, or -1 if timeout == 0 + * n = 0 : timeout expired + * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0 + */ +signed long sv_wait(sv_t *sv, int sv_wait_flags, unsigned long timeout) +{ + DECLARE_WAITQUEUE( wait, current ); + unsigned long flags; + signed long ret = 0; + +#ifdef SV_DEBUG_INTERRUPT_STATE + { + unsigned long flags; + __save_flags(flags); + + if(sv->sv_flags & SV_INTS) { + if(SV_TEST_INTERRUPTS_ENABLED(flags)) { + printk(KERN_ERR "sv_wait: SV_INTS and interrupts " + "enabled (flags: 0x%lx)\n", flags); + BUG(); + } + } else { + if (SV_TEST_INTERRUPTS_DISABLED(flags)) { + printk(KERN_WARNING "sv_wait: !SV_INTS and interrupts " + "disabled! (flags: 0x%lx)\n", flags); + } + } + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + + sv->sv_mon_unlock_func(sv->sv_mon_lock); + + /* Add ourselves to the wait queue and set the state before + * releasing the sv_lock so as to avoid racing with the + * wake_up() in sv_signal() and sv_broadcast(). + */ + + /* don't need the _irqsave part, but there is no wq_write_lock() */ + wq_write_lock_irqsave(&sv->sv_waiters.lock, flags); + +#ifdef EXCLUSIVE_IN_QUEUE + wait.flags |= WQ_FLAG_EXCLUSIVE; +#endif + + switch(sv->sv_flags & SV_ORDER_MASK) { + case SV_ORDER_FIFO: + __add_wait_queue_tail(&sv->sv_waiters, &wait); + break; + case SV_ORDER_FILO: + __add_wait_queue(&sv->sv_waiters, &wait); + break; + default: + printk(KERN_ERR "sv_wait: unknown order! (sv: 0x%p, flags: 0x%x)\n", + sv, sv->sv_flags); + BUG(); + } + wq_write_unlock_irqrestore(&sv->sv_waiters.lock, flags); + + if(sv_wait_flags & SV_WAIT_SIG) + set_current_state(TASK_EXCLUSIVE | TASK_INTERRUPTIBLE ); + else + set_current_state(TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE); + + spin_unlock(&sv->sv_lock); + + if(sv->sv_flags & SV_INTS) + local_irq_enable(); + else if(sv->sv_flags & SV_BHS) + local_bh_enable(); + + if (timeout) + ret = schedule_timeout(timeout); + else + schedule(); + + if(current->state != TASK_RUNNING) /* XXX Is this possible? */ { + printk(KERN_ERR "sv_wait: state not TASK_RUNNING after " + "schedule().\n"); + set_current_state(TASK_RUNNING); + } + + remove_wait_queue(&sv->sv_waiters, &wait); + + /* Return cases: + - woken by a sv_signal/sv_broadcast + - woken by a signal + - woken by timeout expiring + */ + + /* XXX This isn't really accurate; we may have been woken + before the signal anyway.... */ + if(signal_pending(current)) + return timeout ? -ret : -1; + return timeout ? ret : 1; +} + + +void sv_signal(sv_t *sv) +{ + /* If interrupts can acquire this lock, they can also acquire the + sv_mon_lock, which we must already have to have called this, so + interrupts must be disabled already. If interrupts cannot + contend for this lock, we don't have to worry about it. */ + +#ifdef SV_DEBUG_INTERRUPT_STATE + if(sv->sv_flags & SV_INTS) { + unsigned long flags; + __save_flags(flags); + if(SV_TEST_INTERRUPTS_ENABLED(flags)) + printk(KERN_ERR "sv_signal: SV_INTS and " + "interrupts enabled! (flags: 0x%lx)\n", flags); + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + wake_up(&sv->sv_waiters); + sv_unlock(sv); +} + +void sv_broadcast(sv_t *sv) +{ +#ifdef SV_DEBUG_INTERRUPT_STATE + if(sv->sv_flags & SV_INTS) { + unsigned long flags; + __save_flags(flags); + if(SV_TEST_INTERRUPTS_ENABLED(flags)) + printk(KERN_ERR "sv_broadcast: SV_INTS and " + "interrupts enabled! (flags: 0x%lx)\n", flags); + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + wake_up_all(&sv->sv_waiters); + sv_unlock(sv); +} + +void sv_destroy(sv_t *sv) +{ + if(!spin_trylock(&sv->sv_lock)) { + printk(KERN_ERR "sv_destroy: someone else has sv 0x%p locked!\n", sv); + BUG(); + } + + /* XXX Check that the waitqueue is empty? + Mark the sv destroyed? + */ +} + + +#ifdef RUN_SV_TEST + +static DECLARE_MUTEX_LOCKED(talkback); +static DECLARE_MUTEX_LOCKED(sem); +sv_t sv; +sv_t sv_filo; + +static int sv_test_1_w(void *arg) +{ + printk("sv_test_1_w: acquiring spinlock 0x%p...\n", arg); + + spin_lock((spinlock_t*)arg); + printk("sv_test_1_w: spinlock acquired, waking sv_test_1_s.\n"); + + up(&sem); + + printk("sv_test_1_w: sv_spin_wait()'ing.\n"); + + sv_spin_wait(&sv, arg); + + printk("sv_test_1_w: talkback.\n"); + up(&talkback); + + printk("sv_test_1_w: exiting.\n"); + return 0; +} + +static int sv_test_1_s(void *arg) +{ + printk("sv_test_1_s: waiting for semaphore.\n"); + down(&sem); + printk("sv_test_1_s: semaphore acquired. Acquiring spinlock.\n"); + spin_lock((spinlock_t*)arg); + printk("sv_test_1_s: spinlock acquired. sv_signaling.\n"); + sv_signal(&sv); + printk("sv_test_1_s: talkback.\n"); + up(&talkback); + printk("sv_test_1_s: exiting.\n"); + return 0; + +} + +static int count; +static DECLARE_MUTEX(monitor); + +static int sv_test_2_w(void *arg) +{ + int dummy = count++; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + up(&talkback); + printk("sv_test_2_w: thread %d started, sv_waiting.\n", dummy); + sv_sema_wait(sv, &monitor); + printk("sv_test_2_w: thread %d woken, exiting.\n", dummy); + up(&sem); + return 0; +} + +static int sv_test_2_s_1(void *arg) +{ + int i; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + for(i = 0; i < 3; i++) { + printk("sv_test_2_s_1: waking one thread.\n"); + sv_signal(sv); + down(&sem); + } + + printk("sv_test_2_s_1: signaling and broadcasting again. Nothing should happen.\n"); + sv_signal(sv); + sv_broadcast(sv); + sv_signal(sv); + sv_broadcast(sv); + + printk("sv_test_2_s_1: talkbacking.\n"); + up(&talkback); + up(&monitor); + return 0; +} + +static int sv_test_2_s(void *arg) +{ + int i; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + for(i = 0; i < 3; i++) { + printk("sv_test_2_s: waking one thread (should be %d.)\n", i); + sv_signal(sv); + down(&sem); + } + + printk("sv_test_3_s: waking remaining threads with broadcast.\n"); + sv_broadcast(sv); + for(; i < 10; i++) + down(&sem); + + printk("sv_test_3_s: sending talkback.\n"); + up(&talkback); + + printk("sv_test_3_s: exiting.\n"); + up(&monitor); + return 0; +} + + +static void big_test(sv_t *sv) +{ + int i; + + count = 0; + + for(i = 0; i < 3; i++) { + printk("big_test: spawning thread %d.\n", i); + kernel_thread(sv_test_2_w, sv, 0); + down(&talkback); + } + + printk("big_test: spawning first wake-up thread.\n"); + kernel_thread(sv_test_2_s_1, sv, 0); + + down(&talkback); + printk("big_test: talkback happened.\n"); + + + for(i = 3; i < 13; i++) { + printk("big_test: spawning thread %d.\n", i); + kernel_thread(sv_test_2_w, sv, 0); + down(&talkback); + } + + printk("big_test: spawning wake-up thread.\n"); + kernel_thread(sv_test_2_s, sv, 0); + + down(&talkback); +} + +sv_t int_test_sv; +spinlock_t int_test_spin = SPIN_LOCK_UNLOCKED; +int int_test_ready; +static int irqtestcount; + +static int interrupt_test_worker(void *unused) +{ + int id = ++irqtestcount; + int it = 0; + unsigned long flags, flags2; + + printk("ITW: thread %d started.\n", id); + + while(1) { + __save_flags(flags2); + if(jiffies % 3) { + printk("ITW %2d %5d: irqsaving (%lx)\n", id, it, flags2); + spin_lock_irqsave(&int_test_spin, flags); + } else { + printk("ITW %2d %5d: spin_lock_irqing (%lx)\n", id, it, flags2); + spin_lock_irq(&int_test_spin); + } + + __save_flags(flags2); + printk("ITW %2d %5d: locked, sv_waiting (%lx).\n", id, it, flags2); + sv_wait(&int_test_sv, 0, 0); + + __save_flags(flags2); + printk("ITW %2d %5d: wait finished (%lx), pausing\n", id, it, flags2); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(jiffies & 0xf); + if(current->state != TASK_RUNNING) + printk("ITW: current->state isn't RUNNING after schedule!\n"); + it++; + } +} + +static void interrupt_test(void) +{ + int i; + + printk("interrupt_test: initing sv.\n"); + sv_init(&int_test_sv, &int_test_spin, SV_MON_SPIN | SV_INTS); + + for(i = 0; i < SV_INTERRUPT_TEST_WORKERS; i++) { + printk("interrupt_test: starting test thread %d.\n", i); + kernel_thread(interrupt_test_worker, 0, 0); + } + printk("interrupt_test: done with init part.\n"); + int_test_ready = 1; +} + +int sv_test(void) +{ + spinlock_t s = SPIN_LOCK_UNLOCKED; + + sv_init(&sv, &s, SV_MON_SPIN); + printk("sv_test: starting sv_test_1_w.\n"); + kernel_thread(sv_test_1_w, &s, 0); + printk("sv_test: starting sv_test_1_s.\n"); + kernel_thread(sv_test_1_s, &s, 0); + + printk("sv_test: waiting for talkback.\n"); + down(&talkback); down(&talkback); + printk("sv_test: talkback happened, sv_destroying.\n"); + sv_destroy(&sv); + + count = 0; + + printk("sv_test: beginning big_test on sv.\n"); + + sv_init(&sv, &monitor, SV_MON_SEMA); + big_test(&sv); + sv_destroy(&sv); + + printk("sv_test: beginning big_test on sv_filo.\n"); + sv_init(&sv_filo, &monitor, SV_MON_SEMA | SV_ORDER_FILO); + big_test(&sv_filo); + sv_destroy(&sv_filo); + + interrupt_test(); + + printk("sv_test: done.\n"); + return 0; +} + +__initcall(sv_test); + +#endif /* RUN_SV_TEST */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/sn/sn1/synergy.c linux.ac/arch/ia64/sn/sn1/synergy.c --- linux.vanilla/arch/ia64/sn/sn1/synergy.c Thu Jan 4 23:25:55 2001 +++ linux.ac/arch/ia64/sn/sn1/synergy.c Tue Apr 10 18:12:08 2001 @@ -8,9 +8,12 @@ +#include #include #include #include +#include +#include #include #include @@ -26,8 +29,6 @@ void setclear_mask_a(int irq, int cpuid, int set); void * kmalloc(size_t size, int flags); -extern struct sn1_cnode_action_list *sn1_node_actions[]; - void synergy_intr_alloc(int bit, int cpuid) { @@ -40,9 +41,7 @@ { int irq; unsigned is_b; -int nasid; -nasid = cpuid_to_nasid(cpuid); irq = bit_pos_to_irq(bit); is_b = (cpuid_to_slice(cpuid)) & 1; @@ -202,3 +201,229 @@ REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); } } + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + +/* + * Synergy perf registers. Multiplexed via timer_interrupt + */ +static struct proc_dir_entry *synergy_perf_proc = NULL; + +/* + * read handler for /proc/synergy + */ +static int +synergy_perf_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + cnodeid_t cnode; + nodepda_t *npdap; + synergy_perf_t *p; + int len = 0; + + len += sprintf(page+len, "# cnode module slot event synergy-A synergy-B\n"); + + /* walk the event list for each node */ + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + if (npdap->synergy_perf_enabled == 0) { + len += sprintf(page+len, "# DISABLED\n"); + break; + } + + spin_lock_irq(&npdap->synergy_perf_lock); + for (p = npdap->synergy_perf_first; p;) { + uint64_t cnt_a=0, cnt_b=0; + + if (p->intervals > 0) { + cnt_a = p->counts[0] * npdap->synergy_active_intervals / p->intervals; + cnt_b = p->counts[1] * npdap->synergy_active_intervals / p->intervals; + } + + len += sprintf(page+len, "%d %d %d %12lx %lu %lu\n", + (int)cnode, (int)npdap->module_id, (int)npdap->slotdesc, + p->modesel, cnt_a, cnt_b); + + p = p->next; + if (p == npdap->synergy_perf_first) + break; + } + spin_unlock_irq(&npdap->synergy_perf_lock); + } + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return len; +} + +static int +synergy_perf_append(uint64_t modesel) +{ + int cnode; + nodepda_t *npdap; + synergy_perf_t *p; + int err = 0; + + /* bit 45 is enable */ + modesel |= (1UL << 45); + + for (cnode=0; cnode < numnodes; cnode++) { + /* for each node, insert a new synergy_perf entry */ + if ((npdap = NODEPDA(cnode)) == NULL) { + printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, nodepda); + continue; + } + + /* XX use kmem_alloc_node() when it is implemented */ + p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL); + if (p == NULL) + err = -ENOMEM; + else { + memset(p, 0, sizeof(synergy_perf_t)); + p->modesel = modesel; + if (npdap->synergy_perf_data == NULL) { + /* circular list */ + p->next = p; + npdap->synergy_perf_data = p; + npdap->synergy_perf_first = p; + } + else { + /* + * Jumble up the insertion order so we get better sampling. + * Once the list is complete, "first" stays the same so the + * reporting order is consistent. + */ + p->next = npdap->synergy_perf_first->next; + npdap->synergy_perf_first->next = p; + npdap->synergy_perf_first = p->next; + } + } + } + + return err; +} + +static int +synergy_perf_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int cnode; + nodepda_t *npdap; + uint64_t modesel; + char cmd[64]; + extern long atoi(char *); + + if (count == sizeof(uint64_t)) { + if (copy_from_user(&modesel, buffer, sizeof(uint64_t))) + return -EFAULT; + synergy_perf_append(modesel); + } + else { + if (copy_from_user(cmd, buffer, count < sizeof(cmd) ? count : sizeof(cmd))) + return -EFAULT; + if (strncmp(cmd, "enable", 6) == 0) { + /* enable counting */ + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + npdap->synergy_perf_enabled = 1; + } + printk("NOTICE: synergy perf counting enabled\n"); + } + else + if (strncmp(cmd, "disable", 7) == 0) { + /* disable counting */ + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + npdap->synergy_perf_enabled = 0; + } + printk("NOTICE: synergy perf counting disabled\n"); + } + else + if (strncmp(cmd, "frequency", 9) == 0) { + /* set the update frequency (timer-interrupts per update) */ + int freq; + + if (count < 12) + return -EINVAL; + freq = atoi(cmd + 10); + if (freq <= 0 || freq > 100) + return -EINVAL; + for (cnode=0; cnode < numnodes; cnode++) { + npdap = NODEPDA(cnode); + npdap->synergy_perf_freq = (uint64_t)freq; + } + printk("NOTICE: synergy perf freq set to %d\n", freq); + } + else + return -EINVAL; + } + + return count; +} + +void +synergy_perf_update(int cpu) +{ + nasid_t nasid; + cnodeid_t cnode = cpuid_to_cnodeid(cpu); + struct nodepda_s *npdap; + extern struct nodepda_s *nodepda; + + if (nodepda == NULL || (npdap=NODEPDA(cnode)) == NULL || npdap->synergy_perf_enabled == 0 || + npdap->synergy_perf_data == NULL) { + /* I/O not initialized, or not enabled, or no events to monitor */ + return; + } + + if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) { + /* don't multiplex on every timer interrupt */ + return; + } + + /* + * Read registers for last interval and increment counters. + * Hold the per-node synergy_perf_lock so concurrent readers get + * consistent values. + */ + spin_lock_irq(&npdap->synergy_perf_lock); + + nasid = cpuid_to_nasid(cpu); + npdap->synergy_active_intervals++; + npdap->synergy_perf_data->intervals++; + + npdap->synergy_perf_data->counts[0] += 0xffffffffffUL & + REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A); + + npdap->synergy_perf_data->counts[1] += 0xffffffffffUL & + REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B); + + /* skip to next in circular list */ + npdap->synergy_perf_data = npdap->synergy_perf_data->next; + + spin_unlock_irq(&npdap->synergy_perf_lock); + + /* set the counter 0 selection modes for both A and B */ + REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel); + REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel); + + /* and reset the counter registers to zero */ + REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL); + REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL); +} + +void +synergy_perf_init(void) +{ + if ((synergy_perf_proc = create_proc_entry("synergy", 0644, NULL)) != NULL) { + synergy_perf_proc->read_proc = synergy_perf_read_proc; + synergy_perf_proc->write_proc = synergy_perf_write_proc; + printk("markgw: synergy_perf_init()\n"); + } +} + +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/tools/print_offsets.awk linux.ac/arch/ia64/tools/print_offsets.awk --- linux.vanilla/arch/ia64/tools/print_offsets.awk Sat Jul 15 00:08:12 2000 +++ linux.ac/arch/ia64/tools/print_offsets.awk Tue Apr 10 18:12:08 2001 @@ -28,6 +28,10 @@ inside_table = 0 } +/.*[.]rodata/ { + inside_table = 0 +} + { if (inside_table) { if ($1 == "//") getline; @@ -61,7 +65,7 @@ inside_table = 1 } -/tab#:/ { +/tab\#:/ { inside_table = 1 } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/tools/print_offsets.c linux.ac/arch/ia64/tools/print_offsets.c --- linux.vanilla/arch/ia64/tools/print_offsets.c Thu Jan 4 20:50:17 2001 +++ linux.ac/arch/ia64/tools/print_offsets.c Tue Apr 10 18:12:15 2001 @@ -1,8 +1,8 @@ /* * Utility to generate asm-ia64/offsets.h. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang * * Note that this file has dual use: when building the kernel * natively, the file is translated into a binary and executed. When @@ -45,9 +45,8 @@ { "IA64_PT_REGS_SIZE", sizeof (struct pt_regs) }, { "IA64_SWITCH_STACK_SIZE", sizeof (struct switch_stack) }, { "IA64_SIGINFO_SIZE", sizeof (struct siginfo) }, -#ifdef CONFIG_IA64_NEW_UNWIND + { "IA64_CPU_SIZE", sizeof (struct cpuinfo_ia64) }, { "UNW_FRAME_INFO_SIZE", sizeof (struct unw_frame_info) }, -#endif { "", 0 }, /* spacer */ { "IA64_TASK_PTRACE_OFFSET", offsetof (struct task_struct, ptrace) }, { "IA64_TASK_SIGPENDING_OFFSET", offsetof (struct task_struct, sigpending) }, @@ -58,6 +57,9 @@ #ifdef CONFIG_IA32_SUPPORT { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) }, #endif +#ifdef CONFIG_PERFMON + { "IA64_TASK_PFM_NOTIFY_OFFSET", offsetof(struct task_struct, thread.pfm_pend_notify) }, +#endif { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, { "IA64_PT_REGS_CR_IPSR_OFFSET", offsetof (struct pt_regs, cr_ipsr) }, @@ -157,6 +159,11 @@ { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, { "IA64_CLONE_VFORK", CLONE_VFORK }, { "IA64_CLONE_VM", CLONE_VM }, + { "IA64_CPU_IRQ_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) }, + { "IA64_CPU_BH_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) }, + { "IA64_CPU_SOFTIRQ_ACTIVE_OFFSET", offsetof (struct cpuinfo_ia64, softirq.active) }, + { "IA64_CPU_SOFTIRQ_MASK_OFFSET", offsetof (struct cpuinfo_ia64, softirq.mask) }, + { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET", offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) }, }; static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ia64/vmlinux.lds.S linux.ac/arch/ia64/vmlinux.lds.S --- linux.vanilla/arch/ia64/vmlinux.lds.S Sat Aug 12 03:09:06 2000 +++ linux.ac/arch/ia64/vmlinux.lds.S Tue Apr 10 18:12:15 2001 @@ -5,10 +5,18 @@ OUTPUT_FORMAT("elf64-ia64-little") OUTPUT_ARCH(ia64) -ENTRY(_start) +ENTRY(phys_start) SECTIONS { + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ + phys_start = _start - PAGE_OFFSET; . = KERNEL_START; @@ -16,11 +24,11 @@ _stext = .; .text : AT(ADDR(.text) - PAGE_OFFSET) { - *(__ivt_section) + *(.text.ivt) /* these are not really text pages, but the zero page needs to be in a fixed location: */ *(__special_page_section) __start_gate_section = .; - *(__gate_section) + *(.text.gate) __stop_gate_section = .; *(.text) } @@ -34,7 +42,7 @@ /* Read-only data */ - __gp = ALIGN(8) + 0x200000; + __gp = ALIGN(16) + 0x200000; /* gp must be 16-byte aligned for exc. table */ /* Global data */ _data = .; @@ -60,13 +68,19 @@ { *(__ksymtab) } __stop___ksymtab = .; - /* Unwind table */ + __start___kallsyms = .; /* All kernel symbols for debugging */ + __kallsyms : AT(ADDR(__kallsyms) - PAGE_OFFSET) + { *(__kallsyms) } + __stop___kallsyms = .; + + /* Unwind info & table: */ + .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) + { *(.IA_64.unwind_info*) } + . = ALIGN(8); ia64_unw_start = .; .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET) - { *(.IA_64.unwind) } + { *(.IA_64.unwind*) } ia64_unw_end = .; - .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) - { *(.IA_64.unwind_info) } .rodata : AT(ADDR(.rodata) - PAGE_OFFSET) { *(.rodata) } @@ -129,13 +143,6 @@ { *(.bss) *(COMMON) } . = ALIGN(64 / 8); _end = .; - - /* Sections to be discarded */ - /DISCARD/ : { - *(.text.exit) - *(.data.exit) - *(.exitcall.exit) - } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/amiga/config.c linux.ac/arch/m68k/amiga/config.c --- linux.vanilla/arch/m68k/amiga/config.c Thu Jan 4 21:00:55 2001 +++ linux.ac/arch/m68k/amiga/config.c Wed Apr 18 13:48:09 2001 @@ -769,20 +769,6 @@ return 0; } -void dbprintf(const char *fmt , ...) -{ - static char buf[1024]; - va_list args; - extern void console_print (const char *str); - extern int vsprintf(char * buf, const char * fmt, va_list args); - - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - - console_print (buf); -} - static NORET_TYPE void amiga_reset( void ) ATTRIB_NORET; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/config.in linux.ac/arch/m68k/config.in --- linux.vanilla/arch/m68k/config.in Thu Jan 4 21:00:55 2001 +++ linux.ac/arch/m68k/config.in Wed Apr 18 13:48:17 2001 @@ -4,6 +4,8 @@ # define_bool CONFIG_UID16 y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n mainmenu_name "Linux/68k Kernel Configuration" @@ -487,8 +489,10 @@ fi fi if [ "$CONFIG_APOLLO" = "y" ]; then - bool 'Support for DN serial port (dummy)' CONFIG_SERIAL + bool 'Support for DN serial port (dummy)' CONFIG_DN_SERIAL bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE + + define_tristate CONFIG_SERIAL $CONFIG_DN_SERIAL fi bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/ifpsp060/src/fpsp.S linux.ac/arch/m68k/ifpsp060/src/fpsp.S --- linux.vanilla/arch/m68k/ifpsp060/src/fpsp.S Tue Apr 3 17:31:54 2001 +++ linux.ac/arch/m68k/ifpsp060/src/fpsp.S Tue Apr 10 18:12:27 2001 @@ -19594,7 +19594,7 @@ # in the data register file. If it's actually out in memory, use one of # # the mem_read() routines to fetch it. If the mem_read() access returns # # a failing value, exit through the special facc_in() routine which # -# will create an acess error exception frame from the current exception # +# will create an access error exception frame from the current exception # # frame. # # Immediate data and regular data accesses are separated because # # if an immediate data access fails, the resulting fault status # @@ -24608,7 +24608,7 @@ # made out of the current exception stack frame. # # So, we first call restore() which makes sure that any updated # # -(an)+ register gets returned to its pre-exception value and then # -# we change the stack to an acess error stack frame. # +# we change the stack to an access error stack frame. # # # ######################################################################### diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/ifpsp060/src/pfpsp.S linux.ac/arch/m68k/ifpsp060/src/pfpsp.S --- linux.vanilla/arch/m68k/ifpsp060/src/pfpsp.S Tue Apr 3 17:31:54 2001 +++ linux.ac/arch/m68k/ifpsp060/src/pfpsp.S Tue Apr 10 18:12:39 2001 @@ -14568,7 +14568,7 @@ # made out of the current exception stack frame. # # So, we first call restore() which makes sure that any updated # # -(an)+ register gets returned to its pre-exception value and then # -# we change the stack to an acess error stack frame. # +# we change the stack to an access error stack frame. # # # ######################################################################### diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/kernel/semaphore.c linux.ac/arch/m68k/kernel/semaphore.c --- linux.vanilla/arch/m68k/kernel/semaphore.c Fri Dec 29 22:07:20 2000 +++ linux.ac/arch/m68k/kernel/semaphore.c Wed Apr 18 13:48:17 2001 @@ -130,111 +130,3 @@ { return waking_non_zero_trylock(sem); } - - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -void down_read_failed(struct rw_semaphore *sem) -{ - DECLARE_WAITQUEUE(wait, current); - - __up_read(sem); /* this takes care of granting the lock */ - - add_wait_queue(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(current, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - current->state = TASK_RUNNING; -} - -void down_read_failed_biased(struct rw_semaphore *sem) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) - break; - set_task_state(current, TASK_UNINTERRUPTIBLE); - if (!sem->read_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - current->state = TASK_RUNNING; -} - - -/* Wait for the lock to become unbiased. Since we're - * a writer, we'll make ourselves exclusive. - */ -void down_write_failed(struct rw_semaphore *sem) -{ - DECLARE_WAITQUEUE(wait, current); - - __up_write(sem); /* this takes care of granting the lock */ - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(current, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to acquire or bias the lock */ - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - current->state = TASK_RUNNING; -} - -void down_write_failed_biased(struct rw_semaphore *sem) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) - break; - set_task_state(current, TASK_UNINTERRUPTIBLE); - if (!sem->write_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - current->state = TASK_RUNNING; - - /* if the lock is currently unbiased, awaken the sleepers - * FIXME: this wakes up the readers early in a bit of a - * stampede -> bad! - */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); -} - - -/* Called when someone has done an up that transitioned from - * negative to non-negative, meaning that the lock has been - * granted to whomever owned the bias. - */ -void rwsem_wake_readers(struct rw_semaphore *sem) -{ - if (xchg(&sem->read_bias_granted, 1)) - BUG(); - wake_up(&sem->wait); -} - -void rwsem_wake_writer(struct rw_semaphore *sem) -{ - if (xchg(&sem->write_bias_granted, 1)) - BUG(); - wake_up(&sem->write_bias_wait); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/kernel/setup.c linux.ac/arch/m68k/kernel/setup.c --- linux.vanilla/arch/m68k/kernel/setup.c Thu Jan 4 21:00:55 2001 +++ linux.ac/arch/m68k/kernel/setup.c Wed Apr 18 13:48:26 2001 @@ -39,10 +39,6 @@ #include #endif -#ifndef CONFIG_AMIGA -#define dbprintf printk -#endif - unsigned long m68k_machtype; unsigned long m68k_cputype; unsigned long m68k_fputype; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/mm/init.c linux.ac/arch/m68k/mm/init.c --- linux.vanilla/arch/m68k/mm/init.c Mon Oct 16 20:58:51 2000 +++ linux.ac/arch/m68k/mm/init.c Tue Apr 3 17:54:32 2001 @@ -31,12 +31,11 @@ #ifdef CONFIG_ATARI #include #endif +#include -static unsigned long totalram_pages; +mmu_gather_t mmu_gathers[NR_CPUS]; -#ifdef CONFIG_SUN3 -void mmu_emu_reserve_pages(unsigned long max_page); -#endif +unsigned long totalram_pages = 0; int do_check_pgt_cache(int low, int high) { @@ -86,7 +85,7 @@ void show_mem(void) { unsigned long i; - int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0; + int free = 0, total = 0, reserved = 0, shared = 0; int cached = 0; printk("\nMem-info:\n"); @@ -101,15 +100,12 @@ cached++; else if (!page_count(mem_map+i)) free++; - else if (page_count(mem_map+i) == 1) - nonshared++; else shared += page_count(mem_map+i) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); - printk("%d pages nonshared\n",nonshared); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); @@ -137,17 +133,11 @@ #ifdef CONFIG_ATARI if (MACH_IS_ATARI) - atari_stram_reserve_pages( start_mem ); -#endif - -#ifdef CONFIG_SUN3 - /* reserve rom pages */ - mmu_emu_reserve_pages(max_mapnr); + atari_stram_mem_init_hook(); #endif /* this will put all memory onto the freelists */ totalram_pages = free_all_bootmem(); - printk("tp:%ld\n", totalram_pages); for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) { #if 0 @@ -201,13 +191,15 @@ #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { + int pages = 0; for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; + pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + printk ("Freeing initrd memory: %dk freed\n", pages); } #endif @@ -220,15 +212,8 @@ val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); - while (i-- > 0) { - if (PageReserved(mem_map+i)) - continue; - val->totalram++; - if (!page_count(mem_map+i)) - continue; - val->sharedram += page_count(mem_map+i) - 1; - } val->totalhigh = 0; val->freehigh = 0; + val->mem_unit = PAGE_SIZE; return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/mm/memory.c linux.ac/arch/m68k/mm/memory.c --- linux.vanilla/arch/m68k/mm/memory.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/m68k/mm/memory.c Tue Apr 3 17:54:32 2001 @@ -246,6 +246,10 @@ voff -= m68k_memory[i].size; } while (++i < m68k_num_memory); + /* As a special case allow `__pa(high_memory)'. */ + if (voff == 0) + return m68k_memory[i-1].addr + m68k_memory[i-1].size; + return mm_vtop_fallback(vaddr); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/mm/motorola.c linux.ac/arch/m68k/mm/motorola.c --- linux.vanilla/arch/m68k/mm/motorola.c Tue Aug 8 05:02:27 2000 +++ linux.ac/arch/m68k/mm/motorola.c Tue Apr 10 18:12:39 2001 @@ -286,6 +286,7 @@ } extern char __init_begin, __init_end; +extern unsigned long totalram_pages; void free_initmem(void) { @@ -296,6 +297,7 @@ virt_to_page(addr)->flags &= ~(1 << PG_reserved); set_page_count(virt_to_page(addr), 1); free_page(addr); + totalram_pages++; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/q40/config.c linux.ac/arch/m68k/q40/config.c --- linux.vanilla/arch/m68k/q40/config.c Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/m68k/q40/config.c Tue Apr 3 17:54:32 2001 @@ -238,7 +238,7 @@ mach_max_dma_address = 32*1024*1024; /* no DMA at all, but ide-scsi requires it.. */ -/* userfull for early debugging stages writes kernel messages into SRAM */ +/* useful for early debugging stages - writes kernel messages into SRAM */ if (!strncmp( m68k_debug_device,"mem",3 )) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/Makefile linux.ac/arch/mips/Makefile --- linux.vanilla/arch/mips/Makefile Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/Makefile Wed Apr 18 13:48:58 2001 @@ -17,8 +17,10 @@ # ifdef CONFIG_CPU_LITTLE_ENDIAN tool-prefix = mipsel-linux- +output-format = elf32-littlemips else tool-prefix = mips-linux- +output-format = elf32-bigmips endif ifdef CONFIG_CROSSCOMPILE @@ -26,16 +28,16 @@ endif # -# The ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC -# code in the kernel since it only slows down the whole thing. For the -# old GCC these options are just the defaults. At some point we might -# make use of global pointer optimizations. +# GCC uses -G0 -mabicalls -fpic as default. We don't want PIC in the kernel +# code since it only slows down the whole thing. At some point we might make +# use of global pointer optimizations but their use of $28 conflicts with +# the current pointer optimization. # # The DECStation requires an ECOFF kernel for remote booting, other MIPS # machines may also. Since BFD is incredibly buggy with respect to # crossformat linking we rely on the elf2ecoff tool for format conversion. # -CFLAGS += -G 0 -mno-abicalls -fno-pic +GCCFLAGS := -G 0 -mno-abicalls -fno-pic LINKFLAGS += -static -G 0 MODFLAGS += -mlong-calls @@ -47,37 +49,63 @@ # CPU-dependent compiler/assembler options for optimization. # ifdef CONFIG_CPU_R3000 -CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1 +GCCFLAGS += -mcpu=r3000 -mips1 +endif +ifdef CONFIG_CPU_R3912 +GCCFLAGS += -mcpu=r3000 -mips1 endif ifdef CONFIG_CPU_R6000 -CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r6000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R4300 -CFLAGS := $(CFLAGS) -mcpu=r4300 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r4300 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R4X00 -CFLAGS := $(CFLAGS) -mcpu=r4600 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap +endif +ifdef CONFIG_CPU_MIPS32 +GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R5000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap +endif +ifdef CONFIG_CPU_R5432 +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_NEVADA -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap -mmad +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap -mmad +endif +ifdef CONFIG_CPU_RM7000 +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R8000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R10000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif +ifdef CONFIG_MIPS_FPU_EMULATOR +CORE_FILES +=arch/mips/math-emu/fpu_emulator.o +SUBDIRS +=arch/mips/math-emu +endif + +# +# The pipe options is bad for my low-mem machine +# Uncomment this if you want this. +# +GCCFLAGS += -pipe + +CFLAGS := -I $(TOPDIR)/include/asm/gcc $(CFLAGS) $(GCCFLAGS) +AFLAGS += $(GCCFLAGS) + # # Board-dependent options and extra files # ifdef CONFIG_ALGOR_P4032 CORE_FILES += arch/mips/algor/algor.o SUBDIRS += arch/mips/algor -#LOADADDR += 0x80000000 +LOADADDR += 0x80000000 endif # @@ -90,6 +118,18 @@ LOADADDR += 0x80040000 endif +ifdef CONFIG_MIPS_ATLAS +LIBS += arch/mips/mips-boards/atlas/atlas.o arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/generic arch/mips/mips-boards/atlas +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_MALTA +LIBS += arch/mips/mips-boards/malta/malta.o arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/malta arch/mips/mips-boards/generic +LOADADDR += 0x80100000 +endif + # # Acer PICA 61, Mips Magnum 4000 and Olivetti M700. # @@ -100,12 +140,6 @@ LOADADDR += 0x80080000 endif -ifdef CONFIG_COBALT_MICRO_SERVER -ARCHIVES += arch/mips/cobalt/cobalt.o -SUBDIRS += arch/mips/cobalt -LOADADDR += 0x80000000 -endif - ifdef CONFIG_SNI_RM200_PCI CORE_FILES += arch/mips/sni/sni.o SUBDIRS += arch/mips/sni arch/mips/arc @@ -114,7 +148,8 @@ endif ifdef CONFIG_SGI_IP22 -LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a +CORE_FILES += arch/mips/sgi/kernel/ip22-kern.o +LIBS += arch/mips/arc/arclib.a SUBDIRS += arch/mips/sgi/kernel arch/mips/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, @@ -152,28 +187,74 @@ endif # -# Choosing incompatible machines durings configuration will result in -# error messages during linking. Select a default linkscript if -# none has been choosen above. # -ifndef LINKSCRIPT -ifndef CONFIG_CPU_LITTLE_ENDIAN -LINKSCRIPT = arch/mips/ld.script.big -else -LINKSCRIPT = arch/mips/ld.script.little +# NEC DDB Vrc-5476 +# +ifdef CONFIG_DDB5476 +SUBDIRS += arch/mips/ddb5476 +LIBS += arch/mips/ddb5476/ddb5476.a +LOADADDR += 0x80080000 endif + +# +# Galileo EV64120 Board +# +ifdef CONFIG_MIPS_EV64120 +LIBS += arch/mips/galileo-boards/ev64120/ev64120.o +SUBDIRS += arch/mips/galileo-boards/ev64120 +LOADADDR += 0x80100000 endif -LINKFLAGS += -T $(word 1,$(LINKSCRIPT)) -ifdef LOADADDR -LINKFLAGS += -Ttext $(word 1,$(LOADADDR)) +# +# Galileo EV96100 Board +# +ifdef CONFIG_MIPS_EV96100 +LIBS += arch/mips/galileo-boards/ev96100/ev96100.o arch/mips/galileo-boards/generic/galboards.o +SUBDIRS += arch/mips/galileo-boards/generic arch/mips/galileo-boards/ev96100 +LOADADDR += 0x80100000 endif # -# The pipe options is bad for my low-mem machine -# Uncomment this if you want this. +# Momentum Ocelot board +# +ifdef CONFIG_MOMENCO_OCELOT +LIBS += arch/mips/gt64120/common/gt64120.o arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o +SUBDIRS += arch/mips/gt64120/common arch/mips/gt64120/momenco_ocelot +LOADADDR += 0x80100000 +endif + # -CFLAGS += -pipe +# Philips Nino +# +ifdef CONFIG_NINO +CORE_FILES += arch/mips/philips/nino/nino.o \ + arch/mips/philips/drivers/drivers.o +SUBDIRS += arch/mips/philips/nino arch/mips/philips/drivers +LOADADDR += 0x80000000 +endif + +# +# ITE 8172 eval board with QED 5231 CPU +# +ifdef CONFIG_MIPS_ITE8172 +LIBS += arch/mips/ite-boards/qed-4n-s01b/ite.o \ + arch/mips/ite-boards/generic/it8172.o +SUBDIRS += arch/mips/ite-boards/generic \ + arch/mips/ite-boards/qed-4n-s01b +LOADADDR += 0x80100000 +endif + +# +# Choosing incompatible machines durings configuration will result in +# error messages during linking. Select a default linkscript if +# none has been choosen above. +# +vmlinux: arch/$(ARCH)/ld.script + +arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile + sed -e 's/@@OUTPUT_FORMAT@@/$(output-format)/' \ + -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@ +LINKFLAGS += -T arch/$(ARCH)/ld.script HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o @@ -197,8 +278,18 @@ $(ORIONBOOT) orionboot endif +ifdef CONFIG_MIPS_EV64120 +GALILEOBOOT = $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120 + +gboot: vmlinux + $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120/compressed +endif + MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +vmlinux.ecoff: vmlinux + @$(MAKEBOOT) $@ + zImage: vmlinux @$(MAKEBOOT) zImage @@ -209,7 +300,7 @@ archclean: @$(MAKEBOOT) clean - $(MAKE) -C arch/$(ARCH)/kernel clean + rm -f arch/$(ARCH)/ld.script $(MAKE) -C arch/$(ARCH)/tools clean $(MAKE) -C arch/mips/baget clean diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/Makefile linux.ac/arch/mips/arc/Makefile --- linux.vanilla/arch/mips/arc/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/Makefile Wed Apr 18 13:48:58 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ # # Makefile for the SGI arcs prom monitor library routines # under Linux. @@ -10,7 +9,10 @@ # Note 2! The CFLAGS definitions are now in the main makefile... L_TARGET = arclib.a -L_OBJS = console.o init.o printf.o memory.o tree.o env.o cmdline.o misc.o \ - time.o file.o identify.o + +obj-y += console.o init.o memory.o tree.o env.o cmdline.o misc.o \ + time.o file.o identify.o + +obj-$(CONFIG_ARC_CONSOLE) += arc_con.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/arc_con.c linux.ac/arch/mips/arc/arc_con.c --- linux.vanilla/arch/mips/arc/arc_con.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/arc_con.c Wed Apr 18 13:48:58 2001 @@ -0,0 +1,69 @@ +/* + * Wrap-around code for a console using the + * ARC io-routines. + * + * Copyright (c) 1998 Harald Koerfgen + */ + +#include +#include +#include +#include +#include +#include + +extern char prom_getchar (void); +extern void prom_printf (char *, ...); + +static void prom_console_write(struct console *co, const char *s, + unsigned count) +{ + unsigned i; + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + if (*s == 10) + prom_printf("%c", 13); + prom_printf("%c", *s++); + } +} + +static int prom_console_wait_key(struct console *co) +{ + return prom_getchar(); +} + +static int __init prom_console_setup(struct console *co, char *options) +{ + return 0; +} + +static kdev_t prom_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console arc_cons = { + "ttyS", + prom_console_write, + NULL, + prom_console_device, + prom_console_wait_key, + NULL, + prom_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ + +void __init arc_console_init(void) +{ + register_console(&arc_cons); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/cmdline.c linux.ac/arch/mips/arc/cmdline.c --- linux.vanilla/arch/mips/arc/cmdline.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/cmdline.c Wed Apr 18 13:48:58 2001 @@ -2,8 +2,6 @@ * cmdline.c: Kernel command line creation using ARCS argc/argv. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: cmdline.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ */ #include #include @@ -12,9 +10,9 @@ #include #include -/* #define DEBUG_CMDLINE */ +#undef DEBUG_CMDLINE -char arcs_cmdline[CL_SIZE]; +char arcs_cmdline[COMMAND_LINE_SIZE]; char * __init prom_getcmdline(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/console.c linux.ac/arch/mips/arc/console.c --- linux.vanilla/arch/mips/arc/console.c Mon Feb 28 15:18:20 2000 +++ linux.ac/arch/mips/arc/console.c Wed Apr 18 13:48:58 2001 @@ -1,50 +1,99 @@ /* - * console.c: SGI arcs console code. + * 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. * * Copyright (C) 1996 David S. Miller (dm@sgi.com) * Compability with board caches, Ulf Carlsson - * - * $Id: console.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ #include #include +#include #include #include +#include +#include +#include + +#ifdef CONFIG_ARC_CONSOLE +#define __init +#endif -/* The romvec is not compatible with board caches. Thus we disable it during - * romvec action. Since r4xx0.c is always compiled and linked with your kernel, - * this shouldn't cause any harm regardless what MIPS processor you have. +/* + * IP22 boardcache is not compatible with board caches. Thus we disable it + * during romvec action. Since r4xx0.c is always compiled and linked with your + * kernel, this shouldn't cause any harm regardless what MIPS processor you + * have. * - * The romvec write and read functions seem to interfere with the serial lines + * The ARC write and read functions seem to interfere with the serial lines * in some way. You should be careful with them. */ -extern struct bcache_ops *bcops; -#ifdef CONFIG_SGI_PROM_CONSOLE -void prom_putchar(char c) -#else void __init prom_putchar(char c) -#endif { long cnt; char it = c; - bcops->bc_disable(); + bc_disable(); romvec->write(1, &it, 1, &cnt); - bcops->bc_enable(); + bc_enable(); } -#ifdef CONFIG_SGI_PROM_CONSOLE -char prom_getchar(void) -#else char __init prom_getchar(void) -#endif { long cnt; char c; - bcops->bc_disable(); + bc_disable(); romvec->read(0, &c, 1, &cnt); - bcops->bc_enable(); + bc_enable(); + return c; +} + +static char ppbuf[1024]; + +void __init prom_printf(char *fmt, ...) +{ + va_list args; + char ch, *bptr; + int i; + + va_start(args, fmt); + i = vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while ((ch = *(bptr++)) != 0) { + if (ch == '\n') + prom_putchar('\r'); + + prom_putchar(ch); + } + va_end(args); +} + +static void +arc_console_write(struct console *con, const char *s, unsigned n) +{ + prom_printf("%s", s); +} + +static kdev_t +arc_console_dev(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console arc_prom_console = { + name: "prom", + write: arc_console_write, + device: arc_console_dev, + flags: CON_PRINTBUFFER, + index: -1, +}; + +__init void arc_setup_console(void) +{ + register_console(&arc_prom_console); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/identify.c linux.ac/arch/mips/arc/identify.c --- linux.vanilla/arch/mips/arc/identify.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/identify.c Wed Apr 18 13:48:58 2001 @@ -6,8 +6,6 @@ * This code is based on arch/mips/sgi/kernel/system.c, which is * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: identify.c,v 1.2 1999/02/25 21:04:13 tsbogend Exp $ */ #include #include @@ -19,50 +17,51 @@ #include struct smatch { - char *name; - int group; - int type; - int flags; + char *name; + int group; + int type; + int flags; }; static struct smatch mach_table[] = { - { "SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS }, - { "Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0 }, - { "PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0 }, - { "RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0 } + {"SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS}, + {"Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0}, + {"PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0}, + {"RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0} }; int prom_flags; -static struct smatch * __init string_to_mach(char *s) +static struct smatch *__init string_to_mach(char *s) { - int i; - - for (i = 0; i < sizeof (mach_table); i++) { - if(!strcmp(s, mach_table[i].name)) - return &mach_table[i]; - } - prom_printf("\nYeee, could not determine architecture type <%s>\n", s); - prom_printf("press a key to reboot\n"); - prom_getchar(); - romvec->imode(); - return NULL; + int i; + + for (i = 0; i < sizeof(mach_table); i++) { + if (!strcmp(s, mach_table[i].name)) + return &mach_table[i]; + } + prom_printf("\nYeee, could not determine architecture type <%s>\n", + s); + prom_printf("press a key to reboot\n"); + prom_getchar(); + romvec->imode(); + return NULL; } void __init prom_identify_arch(void) { - pcomponent *p; - struct smatch *mach; - - /* The root component tells us what machine architecture we - * have here. - */ - p = prom_getchild(PROM_NULL_COMPONENT); - printk("ARCH: %s\n", p->iname); - mach = string_to_mach(p->iname); - - mips_machgroup = mach->group; - mips_machtype = mach->type; - prom_flags = mach->flags; -} + pcomponent *p; + struct smatch *mach; + /* + * The root component tells us what machine architecture we + * have here. + */ + p = prom_getchild(PROM_NULL_COMPONENT); + printk("ARCH: %s\n", p->iname); + mach = string_to_mach(p->iname); + + mips_machgroup = mach->group; + mips_machtype = mach->type; + prom_flags = mach->flags; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/init.c linux.ac/arch/mips/arc/init.c --- linux.vanilla/arch/mips/arc/init.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/init.c Wed Apr 18 13:48:58 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.5 2000/03/07 15:45:27 ralf Exp $ +/* * 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. @@ -23,7 +23,9 @@ extern void prom_testtree(void); -int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +extern void arc_setup_console(void); + +void __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { struct linux_promblock *pb; @@ -33,7 +35,20 @@ prom_argv = argv; prom_envp = envp; - if(pb->magic != 0x53435241) { +#if 0 + /* arc_printf should not use prom_printf as soon as we free + * the prom buffers - This horribly breaks on Indys with framebuffer + * as it simply stops after initialising swap - On the Indigo2 serial + * console you will get A LOT illegal instructions - Only enable + * this for early init crashes - This also brings up artefacts of + * printing everything twice on serial console and on GFX Console + * this has the effect of having the prom printing everything + * in the small rectangle and the kernel printing around. + */ + + arc_setup_console(); +#endif + if (pb->magic != 0x53435241) { prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic); while(1) ; @@ -55,5 +70,4 @@ romvec->imode(); } #endif - return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/memory.c linux.ac/arch/mips/arc/memory.c --- linux.vanilla/arch/mips/arc/memory.c Tue Aug 8 05:02:27 2000 +++ linux.ac/arch/mips/arc/memory.c Wed Apr 18 13:48:58 2001 @@ -3,8 +3,6 @@ * given to us from the ARCS firmware. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: memory.c,v 1.10 2000/01/27 23:21:57 ralf Exp $ */ #include #include @@ -47,31 +45,25 @@ "LoadedProgram", "FirmwareTemporary", "FirmwarePermanent", - "FreeContigiuous" + "FreeContiguous" }; #define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc] #endif -static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS]; - -#define MEMTYPE_DONTUSE 0 -#define MEMTYPE_PROM 1 -#define MEMTYPE_FREE 2 - static inline int memtype_classify_arcs (union linux_memtypes type) { switch (type.arcs) { case arcs_fcontig: case arcs_free: - return MEMTYPE_FREE; + return BOOT_MEM_RAM; case arcs_atmp: - return MEMTYPE_PROM; + return BOOT_MEM_ROM_DATA; case arcs_eblock: case arcs_rvpage: case arcs_bmem: case arcs_prog: case arcs_aperm: - return MEMTYPE_DONTUSE; + return BOOT_MEM_RESERVED; default: BUG(); } @@ -83,15 +75,15 @@ switch (type.arc) { case arc_free: case arc_fcontig: - return MEMTYPE_FREE; + return BOOT_MEM_RAM; case arc_atmp: - return MEMTYPE_PROM; + return BOOT_MEM_ROM_DATA; case arc_eblock: case arc_rvpage: case arc_bmem: case arc_prog: case arc_aperm: - return MEMTYPE_DONTUSE; + return BOOT_MEM_RESERVED; default: BUG(); } @@ -106,50 +98,13 @@ return memtype_classify_arc(type); } -static inline unsigned long find_max_low_pfn(void) -{ - struct prom_pmemblock *p, *highest; - unsigned long pfn; - - p = pblocks; - highest = 0; - while (p->size != 0) { - if (!highest || p->base > highest->base) - highest = p; - p++; - } - - pfn = (highest->base + highest->size) >> PAGE_SHIFT; -#ifdef DEBUG - prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn); -#endif - return pfn; -} - -static inline struct prom_pmemblock *find_largest_memblock(void) -{ - struct prom_pmemblock *p, *largest; - - p = pblocks; - largest = 0; - while (p->size != 0) { - if (!largest || p->size > largest->size) - largest = p; - p++; - } - - return largest; -} - void __init prom_meminit(void) { - struct prom_pmemblock *largest; - unsigned long bootmap_size; struct linux_mdesc *p; - int totram; - int i = 0; #ifdef DEBUG + int i = 0; + prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); p = ArcGetMemoryDescriptor(PROM_NULL_MDESC); while(p) { @@ -160,77 +115,36 @@ } #endif - totram = 0; - i = 0; p = PROM_NULL_MDESC; while ((p = ArcGetMemoryDescriptor(p))) { - pblocks[i].type = prom_memtype_classify(p->type); - pblocks[i].base = p->base << PAGE_SHIFT; - pblocks[i].size = p->pages << PAGE_SHIFT; - - switch (pblocks[i].type) { - case MEMTYPE_FREE: - totram += pblocks[i].size; -#ifdef DEBUG - prom_printf("free_chunk[%d]: base=%08lx size=%x\n", - i, pblocks[i].base, - pblocks[i].size); -#endif - i++; - break; - case MEMTYPE_PROM: -#ifdef DEBUG - prom_printf("prom_chunk[%d]: base=%08lx size=%x\n", - i, pblocks[i].base, - pblocks[i].size); -#endif - i++; - break; - default: - break; - } - } - pblocks[i].size = 0; - - max_low_pfn = find_max_low_pfn(); - - largest = find_largest_memblock(); - bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn); + unsigned long base, size; + long type; - for (i = 0; pblocks[i].size; i++) - if (pblocks[i].type == MEMTYPE_FREE) - free_bootmem(pblocks[i].base, pblocks[i].size); + base = p->base << PAGE_SHIFT; + size = p->pages << PAGE_SHIFT; + type = prom_memtype_classify(p->type); - /* This test is simpleminded. It will fail if the bootmem bitmap - falls into multiple adjacent ARC memory areas. */ - if (bootmap_size > largest->size) { - prom_printf("CRITIAL: overwriting PROM data.\n"); - BUG(); + add_memory_region(base, size, type); } - - /* Reserve the memory bootmap itself */ - reserve_bootmem(largest->base, bootmap_size); - - printk("PROMLIB: Total free ram %dK / %dMB.\n", - totram >> 10, totram >> 20); } void __init prom_free_prom_memory (void) { - struct prom_pmemblock *p; unsigned long freed = 0; unsigned long addr; + int i; - for (p = pblocks; p->size != 0; p++) { - if (p->type != MEMTYPE_PROM) + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) continue; - addr = PAGE_OFFSET + p->base; - while (addr < p->base + p->size) { - ClearPageReserved(virt_to_page(addr)); - set_page_count(virt_to_page(addr), 1); - free_page(addr); + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(__va(addr))); + set_page_count(virt_to_page(__va(addr)), 1); + free_page((unsigned long)__va(addr)); addr += PAGE_SIZE; freed += PAGE_SIZE; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/misc.c linux.ac/arch/mips/arc/misc.c --- linux.vanilla/arch/mips/arc/misc.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/arc/misc.c Wed Apr 18 13:48:58 2001 @@ -1,5 +1,4 @@ -/* $Id: misc.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $ - * +/* * misc.c: Miscellaneous ARCS PROM routines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -13,13 +12,12 @@ #include #include -extern unsigned long mips_cputype; extern void *sgiwd93_host; extern void reset_wd33c93(void *instance); void prom_halt(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -29,7 +27,7 @@ void prom_powerdown(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -40,7 +38,7 @@ /* XXX is this a soft reset basically? XXX */ void prom_restart(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -50,7 +48,7 @@ void prom_reboot(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); @@ -60,7 +58,7 @@ void prom_imode(void) { - bcops->bc_disable(); + bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/arc/printf.c linux.ac/arch/mips/arc/printf.c --- linux.vanilla/arch/mips/arc/printf.c Mon Feb 28 15:18:20 2000 +++ linux.ac/arch/mips/arc/printf.c Thu Jan 1 01:00:00 1970 @@ -1,40 +0,0 @@ -/* - * printf.c: Putting things on the screen using SGI arcs - * PROM facilities. - * - * Copyright (C) 1996 David S. Miller (dm@sgi.com) - * - * $Id: printf.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ - */ -#include -#include -#include - -#include - -static char ppbuf[1024]; - -#ifdef CONFIG_SGI_PROM_CONSOLE -void prom_printf(char *fmt, ...) -#else -void __init prom_printf(char *fmt, ...) -#endif -{ - va_list args; - char ch, *bptr; - int i; - - va_start(args, fmt); - i = vsprintf(ppbuf, fmt, args); - - bptr = ppbuf; - - while((ch = *(bptr++)) != 0) { - if(ch == '\n') - prom_putchar('\r'); - - prom_putchar(ch); - } - va_end(args); - return; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/baget/Makefile linux.ac/arch/mips/baget/Makefile --- linux.vanilla/arch/mips/baget/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/baget/Makefile Wed Apr 18 13:48:58 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.3 1999/08/13 17:07:26 harald Exp $ # # Makefile for the Baget specific kernel interface routines # under Linux. @@ -12,22 +11,12 @@ all: baget.a O_TARGET := baget.a -O_OBJS := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o wbflush.o -ifeq ($(CONFIG_SERIAL),y) - OX_OBJS += vacserial.o -else - ifeq ($(CONFIG_SERIAL),m) - MX_OBJS += vacserial.o - endif -endif -ifeq ($(CONFIG_VAC_RTC),y) - OX_OBJS += vacrtc.o -else - ifeq ($(CONFIG_VAC_RTC),m) - MX_OBJS += vacrtc.o - endif -endif +export-objs := vacserial.o vacrtc.o +obj-y := baget.o print.o setup.o time.o irq.o bagetIRQ.o \ + reset.o wbflush.o +obj-$(CONFIG_SERIAL) += vacserial.o +obj-$(CONFIG_VAC_RTC) += vacrtc.o bagetIRQ.o : bagetIRQ.S $(CC) $(CFLAGS) -c -o $@ $< diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/baget/prom/Makefile linux.ac/arch/mips/baget/prom/Makefile --- linux.vanilla/arch/mips/baget/prom/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/baget/prom/Makefile Wed Apr 18 13:48:58 2001 @@ -1,4 +1,4 @@ -# $Id$ +# # Makefile for the Baget/MIPS prom emulator library routines. # # Note! Dependencies are done automagically by 'make dep', which also @@ -7,9 +7,8 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -O_TARGET := bagetlib.a -O_OBJS := init.o +L_TARGET := bagetlib.a -all: $(O_TARGET) +obj-y := init.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/config.in linux.ac/arch/mips/config.in --- linux.vanilla/arch/mips/config.in Thu Nov 16 20:51:28 2000 +++ linux.ac/arch/mips/config.in Wed Apr 18 13:49:30 2001 @@ -28,6 +28,9 @@ bool 'Support for SGI IP22' CONFIG_SGI_IP22 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n + # # Select some configuration options automatically for certain systems. # @@ -233,7 +236,7 @@ if [ "$CONFIG_DECSTATION" != "y" -a \ "$CONFIG_SGI_IP22" != "y" ]; then - source drivers/i2o/Config.in + source drivers/message/i2o/Config.in fi if [ "$CONFIG_NET" = "y" ]; then @@ -329,7 +332,10 @@ # if [ "$CONFIG_ACCESSBUS" = "y" ]; then # bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE # fi - bool 'Enhanced Real Time Clock Support' CONFIG_RTC + bool 'Enhanced Real Time Clock Support' CONFIG_MIPS_RTC + + define_tristate CONFIG_RTC $CONFIG_MIPS_RTC + endmenu fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/Makefile linux.ac/arch/mips/ddb5074/Makefile --- linux.vanilla/arch/mips/ddb5074/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/Makefile Wed Apr 18 13:50:31 2001 @@ -8,8 +8,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... # -# $Id$ -# .S.s: $(CPP) $(CFLAGS) $< -o $*.s @@ -17,6 +15,7 @@ $(CC) $(CFLAGS) -c $< -o $*.o O_TARGET = ddb5074.a -O_OBJS = setup.o irq.o time.o prom.o pci.o pci-dma.o int-handler.o nile4.o + +obj-y := setup.o irq.o time.o prom.o pci.o int-handler.o nile4.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/int-handler.S linux.ac/arch/mips/ddb5074/int-handler.S --- linux.vanilla/arch/mips/ddb5074/int-handler.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/int-handler.S Wed Apr 18 13:50:31 2001 @@ -7,54 +7,50 @@ * * Copyright (C) 2000 Geert Uytterhoeven * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: int-handler.S,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include #include #include #include - /* A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop - * and moving across all the pending IRQ bits in the cause - * register is _NOT_ the answer, the common case is one - * pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register - * IRQ mask, that would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs - * off, nothing in between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the INDY look basically (barring - * software IRQs which we don't use at all) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Local IRQ level zero - * 3 Local IRQ level one - * 4 8254 Timer zero - * 5 8254 Timer one - * 6 Bus Error - * 7 R4k timer (what we use) - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Local IRQ zero - * Local IRQ one - * Bus Error - * 8254 Timer zero - * Lowest ---- 8254 Timer one - * - * then we just return, if multiple IRQs are pending then - * we will just take another exception, big deal. - */ +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the INDY look basically (barring software IRQs + * which we don't use at all) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Local IRQ level zero + * 3 Local IRQ level one + * 4 8254 Timer zero + * 5 8254 Timer one + * 6 Bus Error + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Local IRQ zero + * Local IRQ one + * Bus Error + * 8254 Timer zero + * Lowest ---- 8254 Timer one + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ .text .set noreorder diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/irq.c linux.ac/arch/mips/ddb5074/irq.c --- linux.vanilla/arch/mips/ddb5074/irq.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/irq.c Wed Apr 18 13:50:31 2001 @@ -3,10 +3,7 @@ * * Copyright (C) 2000 Geert Uytterhoeven * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include #include #include @@ -14,6 +11,7 @@ #include #include #include + #include #include #include @@ -27,7 +25,7 @@ extern asmlinkage void ddbIRQ(void); extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); -extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs); +extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); void no_action(int cpl, void *dev_id, struct pt_regs *regs) @@ -55,177 +53,174 @@ static void m1543_irq_setup(void) { - /* - * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all - * the possible IO sources in the M1543 are in use by us. We will - * use the following mapping: - * - * IRQ1 - keyboard (default set by M1543) - * IRQ3 - reserved for UART B (default set by M1543) (note that - * the schematics for the DDB Vrc-5074 board seem to - * indicate that IRQ3 is connected to the DS1386 - * watchdog timer interrupt output so we might have - * a conflict) - * IRQ4 - reserved for UART A (default set by M1543) - * IRQ5 - parallel (default set by M1543) - * IRQ8 - DS1386 time of day (RTC) interrupt - * IRQ12 - mouse - */ - - /* - * Assing mouse interrupt to IRQ12 - */ - - /* Enter configuration mode */ - outb(0x51, M1543_PNP_CONFIG); - outb(0x23, M1543_PNP_CONFIG); - - /* Select logical device 7 (Keyboard) */ - outb(0x07, M1543_PNP_INDEX); - outb(0x07, M1543_PNP_DATA); - - /* Select IRQ12 */ - outb(0x72, M1543_PNP_INDEX); - outb(0x0c, M1543_PNP_DATA); - - /* Leave configration mode */ - outb(0xbb, M1543_PNP_CONFIG); + /* + * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all + * the possible IO sources in the M1543 are in use by us. We will + * use the following mapping: + * + * IRQ1 - keyboard (default set by M1543) + * IRQ3 - reserved for UART B (default set by M1543) (note that + * the schematics for the DDB Vrc-5074 board seem to + * indicate that IRQ3 is connected to the DS1386 + * watchdog timer interrupt output so we might have + * a conflict) + * IRQ4 - reserved for UART A (default set by M1543) + * IRQ5 - parallel (default set by M1543) + * IRQ8 - DS1386 time of day (RTC) interrupt + * IRQ12 - mouse + */ + + /* + * Assing mouse interrupt to IRQ12 + */ + + /* Enter configuration mode */ + outb(0x51, M1543_PNP_CONFIG); + outb(0x23, M1543_PNP_CONFIG); + + /* Select logical device 7 (Keyboard) */ + outb(0x07, M1543_PNP_INDEX); + outb(0x07, M1543_PNP_DATA); + + /* Select IRQ12 */ + outb(0x72, M1543_PNP_INDEX); + outb(0x0c, M1543_PNP_DATA); + + /* Leave configration mode */ + outb(0xbb, M1543_PNP_CONFIG); - /* Initialize the 8259 PIC in the M1543 */ - i8259_init(); + /* Initialize the 8259 PIC in the M1543 */ + i8259_init(); - /* Enable the interrupt cascade */ - nile4_enable_irq(NILE4_INT_INTE); + /* Enable the interrupt cascade */ + nile4_enable_irq(NILE4_INT_INTE); - request_region(M1543_PNP_CONFIG, 2, "M1543 config"); - request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR"); + request_region(M1543_PNP_CONFIG, 2, "M1543 config"); + request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR"); } static void nile4_irq_setup(void) { - int i; + int i; - /* Map all interrupts to CPU int #0 */ - nile4_map_irq_all(0); + /* Map all interrupts to CPU int #0 */ + nile4_map_irq_all(0); - /* PCI INTA#-E# must be level triggered */ - nile4_set_pci_irq_level_or_edge(0, 1); - nile4_set_pci_irq_level_or_edge(1, 1); - nile4_set_pci_irq_level_or_edge(2, 1); - nile4_set_pci_irq_level_or_edge(3, 1); - nile4_set_pci_irq_level_or_edge(4, 1); - - /* PCI INTA#-D# must be active low, INTE# must be active high */ - nile4_set_pci_irq_polarity(0, 0); - nile4_set_pci_irq_polarity(1, 0); - nile4_set_pci_irq_polarity(2, 0); - nile4_set_pci_irq_polarity(3, 0); - nile4_set_pci_irq_polarity(4, 1); + /* PCI INTA#-E# must be level triggered */ + nile4_set_pci_irq_level_or_edge(0, 1); + nile4_set_pci_irq_level_or_edge(1, 1); + nile4_set_pci_irq_level_or_edge(2, 1); + nile4_set_pci_irq_level_or_edge(3, 1); + nile4_set_pci_irq_level_or_edge(4, 1); + + /* PCI INTA#-D# must be active low, INTE# must be active high */ + nile4_set_pci_irq_polarity(0, 0); + nile4_set_pci_irq_polarity(1, 0); + nile4_set_pci_irq_polarity(2, 0); + nile4_set_pci_irq_polarity(3, 0); + nile4_set_pci_irq_polarity(4, 1); - for (i = 0; i < 16; i++) - nile4_clear_irq(i); + for (i = 0; i < 16; i++) + nile4_clear_irq(i); - /* Enable CPU int #0 */ - nile4_enable_irq_output(0); + /* Enable CPU int #0 */ + nile4_enable_irq_output(0); - request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4"); + request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4"); } /* * IRQ2 is cascade interrupt to second interrupt controller */ - -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; void disable_irq(unsigned int irq_nr) { - if (is_i8259_irq(irq_nr)) - i8259_disable_irq(irq_nr); - else - nile4_disable_irq(irq_to_nile4(irq_nr)); + if (is_i8259_irq(irq_nr)) + i8259_disable_irq(irq_nr); + else + nile4_disable_irq(irq_to_nile4(irq_nr)); } void enable_irq(unsigned int irq_nr) { - if (is_i8259_irq(irq_nr)) - i8259_enable_irq(irq_nr); - else - nile4_enable_irq(irq_to_nile4(irq_nr)); + if (is_i8259_irq(irq_nr)) + i8259_enable_irq(irq_nr); + else + nile4_enable_irq(irq_to_nile4(irq_nr)); } int table[16] = { 0, }; void ddb_local0_irqdispatch(struct pt_regs *regs) { - u32 mask; - int nile4_irq; + u32 mask; + int nile4_irq; #if 1 - volatile static int nesting = 0; - if (nesting++ == 0) - ddb5074_led_d3(1); - ddb5074_led_hex(nesting < 16 ? nesting : 15); + volatile static int nesting = 0; + if (nesting++ == 0) + ddb5074_led_d3(1); + ddb5074_led_hex(nesting < 16 ? nesting : 15); #endif - mask = nile4_get_irq_stat(0); - nile4_clear_irq_mask(mask); + mask = nile4_get_irq_stat(0); + nile4_clear_irq_mask(mask); - /* Handle the timer interrupt first */ - if (mask & (1<>= 1) - if (mask & 1) { - nile4_disable_irq(nile4_irq); - if (nile4_irq == NILE4_INT_INTE) { - int i8259_irq = nile4_i8259_iack(); - i8259_do_irq(i8259_irq, regs); - } else - do_IRQ(nile4_to_irq(nile4_irq), regs); - nile4_enable_irq(nile4_irq); + /* Handle the timer interrupt first */ + if (mask & (1 << NILE4_INT_GPT)) { + nile4_disable_irq(NILE4_INT_GPT); + do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); + nile4_enable_irq(NILE4_INT_GPT); + mask &= ~(1 << NILE4_INT_GPT); } - + for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) + if (mask & 1) { + nile4_disable_irq(nile4_irq); + if (nile4_irq == NILE4_INT_INTE) { + int i8259_irq = nile4_i8259_iack(); + i8259_do_irq(i8259_irq, regs); + } else + do_IRQ(nile4_to_irq(nile4_irq), regs); + nile4_enable_irq(nile4_irq); + } #if 1 - if (--nesting == 0) - ddb5074_led_d3(0); - ddb5074_led_hex(nesting < 16 ? nesting : 15); + if (--nesting == 0) + ddb5074_led_d3(0); + ddb5074_led_hex(nesting < 16 ? nesting : 15); #endif } void ddb_local1_irqdispatch(void) { - printk("ddb_local1_irqdispatch called\n"); + printk("ddb_local1_irqdispatch called\n"); } void ddb_buserror_irq(void) { - printk("ddb_buserror_irq called\n"); + printk("ddb_buserror_irq called\n"); } void ddb_8254timer_irq(void) { - printk("ddb_8254timer_irq called\n"); + printk("ddb_8254timer_irq called\n"); } void __init ddb_irq_setup(void) { #ifdef CONFIG_REMOTE_DEBUG - if (remote_debug) - set_debug_traps(); - breakpoint(); /* you may move this line to whereever you want :-) */ + if (remote_debug) + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ #endif - request_region(0x20, 0x20, "pic1"); - request_region(0xa0, 0x20, "pic2"); - i8259_setup_irq(2, &irq2); + request_region(0x20, 0x20, "pic1"); + request_region(0xa0, 0x20, "pic2"); + i8259_setup_irq(2, &irq2); - nile4_irq_setup(); - m1543_irq_setup(); + nile4_irq_setup(); + m1543_irq_setup(); - set_except_vector(0, ddbIRQ); + set_except_vector(0, ddbIRQ); } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/nile4.c linux.ac/arch/mips/ddb5074/nile4.c --- linux.vanilla/arch/mips/ddb5074/nile4.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/nile4.c Wed Apr 18 13:50:31 2001 @@ -3,292 +3,290 @@ * * Copyright (C) 2000 Geert Uytterhoeven * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id$ */ - #include #include + #include - /* - * Physical Device Address Registers - * - * Note: 32 bit addressing only! - */ - -void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, int on_memory_bus, - int visible) -{ - u32 maskbits; - u32 widthbits; - - if (pdar > NILE4_BOOTCS || (pdar & 7)) { - printk("nile4_set_pdar: invalid pdar %d\n", pdar); - return; - } - if (pdar == NILE4_INTCS && size != 0x00200000) { - printk("nile4_set_pdar: INTCS size must be 2 MB\n"); - return; - } - switch (size) { -#if 0 /* We don't support 4 GB yet */ +/* + * Physical Device Address Registers + * + * Note: 32 bit addressing only! + */ +void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, + int on_memory_bus, int visible) +{ + u32 maskbits; + u32 widthbits; + + if (pdar > NILE4_BOOTCS || (pdar & 7)) { + printk("nile4_set_pdar: invalid pdar %d\n", pdar); + return; + } + if (pdar == NILE4_INTCS && size != 0x00200000) { + printk("nile4_set_pdar: INTCS size must be 2 MB\n"); + return; + } + switch (size) { +#if 0 /* We don't support 4 GB yet */ case 0x100000000: /* 4 GB */ - maskbits = 4; - break; + maskbits = 4; + break; #endif case 0x80000000: /* 2 GB */ - maskbits = 5; - break; + maskbits = 5; + break; case 0x40000000: /* 1 GB */ - maskbits = 6; - break; + maskbits = 6; + break; case 0x20000000: /* 512 MB */ - maskbits = 7; - break; + maskbits = 7; + break; case 0x10000000: /* 256 MB */ - maskbits = 8; - break; + maskbits = 8; + break; case 0x08000000: /* 128 MB */ - maskbits = 9; - break; + maskbits = 9; + break; case 0x04000000: /* 64 MB */ - maskbits = 10; - break; + maskbits = 10; + break; case 0x02000000: /* 32 MB */ - maskbits = 11; - break; + maskbits = 11; + break; case 0x01000000: /* 16 MB */ - maskbits = 12; - break; + maskbits = 12; + break; case 0x00800000: /* 8 MB */ - maskbits = 13; - break; + maskbits = 13; + break; case 0x00400000: /* 4 MB */ - maskbits = 14; - break; + maskbits = 14; + break; case 0x00200000: /* 2 MB */ - maskbits = 15; - break; - case 0: /* OFF */ - maskbits = 0; - break; + maskbits = 15; + break; + case 0: /* OFF */ + maskbits = 0; + break; default: - printk("nile4_set_pdar: unsupported size %p\n", (void *)size); - return; - } - switch (width) { + printk("nile4_set_pdar: unsupported size %p\n", (void *) size); + return; + } + switch (width) { case 8: - widthbits = 0; - break; + widthbits = 0; + break; case 16: - widthbits = 1; - break; + widthbits = 1; + break; case 32: - widthbits = 2; - break; + widthbits = 2; + break; case 64: - widthbits = 3; - break; + widthbits = 3; + break; default: - printk("nile4_set_pdar: unsupported width %d\n", width); - return; - } - nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | - (visible ? 0x20 : 0) | (widthbits << 6) | - (phys & 0xffe00000)); - nile4_out32(pdar+4, 0); - /* - * When programming a PDAR, the register should be read immediately after - * writing it. This ensures that address decoders are properly configured. - */ - (void)nile4_in32(pdar); - (void)nile4_in32(pdar+4); + printk("nile4_set_pdar: unsupported width %d\n", width); + return; + } + nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | + (visible ? 0x20 : 0) | (widthbits << 6) | + (phys & 0xffe00000)); + nile4_out32(pdar + 4, 0); + /* + * When programming a PDAR, the register should be read immediately + * after writing it. This ensures that address decoders are properly + * configured. + */ + nile4_in32(pdar); + nile4_in32(pdar + 4); } - /* - * PCI Master Registers - * - * Note: 32 bit addressing only! - */ - +/* + * PCI Master Registers + * + * Note: 32 bit addressing only! + */ void nile4_set_pmr(u32 pmr, u32 type, u32 addr) { - if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { - printk("nile4_set_pmr: invalid pmr %d\n", pmr); - return; - } - switch (type) { + if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { + printk("nile4_set_pmr: invalid pmr %d\n", pmr); + return; + } + switch (type) { case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */ case NILE4_PCICMD_IO: /* PCI I/O Space */ case NILE4_PCICMD_MEM: /* PCI Memory Space */ case NILE4_PCICMD_CFG: /* PCI Configuration Space */ - break; + break; default: - printk("nile4_set_pmr: invalid type %d\n", type); - return; - } - nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); - nile4_out32(pmr+4, 0); + printk("nile4_set_pmr: invalid type %d\n", type); + return; + } + nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); + nile4_out32(pmr + 4, 0); } - /* - * Interrupt Programming - */ - +/* + * Interrupt Programming + */ void nile4_map_irq(int nile4_irq, int cpu_irq) { - u32 offset, t; + u32 offset, t; - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t &= ~(7 << (nile4_irq*4)); - t |= cpu_irq << (nile4_irq*4); - nile4_out32(offset, t); + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(7 << (nile4_irq * 4)); + t |= cpu_irq << (nile4_irq * 4); + nile4_out32(offset, t); } void nile4_map_irq_all(int cpu_irq) { - u32 all, t; - - all = cpu_irq; - all |= all << 4; - all |= all << 8; - all |= all << 16; - t = nile4_in32(NILE4_INTCTRL); - t &= 0x88888888; - t |= all; - nile4_out32(NILE4_INTCTRL, t); - t = nile4_in32(NILE4_INTCTRL+4); - t &= 0x88888888; - t |= all; - nile4_out32(NILE4_INTCTRL+4, t); + u32 all, t; + + all = cpu_irq; + all |= all << 4; + all |= all << 8; + all |= all << 16; + t = nile4_in32(NILE4_INTCTRL); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL, t); + t = nile4_in32(NILE4_INTCTRL + 4); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL + 4, t); } void nile4_enable_irq(int nile4_irq) { - u32 offset, t; + u32 offset, t; - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t |= 8 << (nile4_irq*4); - nile4_out32(offset, t); + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t |= 8 << (nile4_irq * 4); + nile4_out32(offset, t); } void nile4_disable_irq(int nile4_irq) { - u32 offset, t; + u32 offset, t; - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t &= ~(8 << (nile4_irq*4)); - nile4_out32(offset, t); + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(8 << (nile4_irq * 4)); + nile4_out32(offset, t); } void nile4_disable_irq_all(void) { - nile4_out32(NILE4_INTCTRL, 0); - nile4_out32(NILE4_INTCTRL+4, 0); + nile4_out32(NILE4_INTCTRL, 0); + nile4_out32(NILE4_INTCTRL + 4, 0); } u16 nile4_get_irq_stat(int cpu_irq) { - return nile4_in16(NILE4_INTSTAT0+cpu_irq*2); + return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2); } void nile4_enable_irq_output(int cpu_irq) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTSTAT1+4); - t |= 1 << (16+cpu_irq); - nile4_out32(NILE4_INTSTAT1, t); + t = nile4_in32(NILE4_INTSTAT1 + 4); + t |= 1 << (16 + cpu_irq); + nile4_out32(NILE4_INTSTAT1, t); } void nile4_disable_irq_output(int cpu_irq) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTSTAT1+4); - t &= ~(1 << (16+cpu_irq)); - nile4_out32(NILE4_INTSTAT1, t); + t = nile4_in32(NILE4_INTSTAT1 + 4); + t &= ~(1 << (16 + cpu_irq)); + nile4_out32(NILE4_INTSTAT1, t); } void nile4_set_pci_irq_polarity(int pci_irq, int high) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTPPES); - if (high) - t &= ~(1 << (pci_irq*2)); - else - t |= 1 << (pci_irq*2); - nile4_out32(NILE4_INTPPES, t); + t = nile4_in32(NILE4_INTPPES); + if (high) + t &= ~(1 << (pci_irq * 2)); + else + t |= 1 << (pci_irq * 2); + nile4_out32(NILE4_INTPPES, t); } void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) { - u32 t; + u32 t; - t = nile4_in32(NILE4_INTPPES); - if (level) - t |= 2 << (pci_irq*2); - else - t &= ~(2 << (pci_irq*2)); - nile4_out32(NILE4_INTPPES, t); + t = nile4_in32(NILE4_INTPPES); + if (level) + t |= 2 << (pci_irq * 2); + else + t &= ~(2 << (pci_irq * 2)); + nile4_out32(NILE4_INTPPES, t); } void nile4_clear_irq(int nile4_irq) { - nile4_out32(NILE4_INTCLR, 1 << nile4_irq); + nile4_out32(NILE4_INTCLR, 1 << nile4_irq); } void nile4_clear_irq_mask(u32 mask) { - nile4_out32(NILE4_INTCLR, mask); + nile4_out32(NILE4_INTCLR, mask); } u8 nile4_i8259_iack(void) { - u8 irq; + u8 irq; - /* Set window 0 for interrupt acknowledge */ - nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); - irq = *(volatile u8 *)NILE4_PCI_IACK_BASE; - /* Set window 0 for PCI I/O space */ - nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); - return irq; + /* Set window 0 for interrupt acknowledge */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); + irq = *(volatile u8 *) NILE4_PCI_IACK_BASE; + /* Set window 0 for PCI I/O space */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + return irq; } #if 0 void nile4_dump_irq_status(void) { - printk("CPUSTAT = %p:%p\n", (void *)nile4_in32(NILE4_CPUSTAT+4), - (void *)nile4_in32(NILE4_CPUSTAT)); - printk("INTCTRL = %p:%p\n", (void *)nile4_in32(NILE4_INTCTRL+4), - (void *)nile4_in32(NILE4_INTCTRL)); - printk("INTSTAT0 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT0+4), - (void *)nile4_in32(NILE4_INTSTAT0)); - printk("INTSTAT1 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT1+4), - (void *)nile4_in32(NILE4_INTSTAT1)); - printk("INTCLR = %p:%p\n", (void *)nile4_in32(NILE4_INTCLR+4), - (void *)nile4_in32(NILE4_INTCLR)); - printk("INTPPES = %p:%p\n", (void *)nile4_in32(NILE4_INTPPES+4), - (void *)nile4_in32(NILE4_INTPPES)); + printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4), + (void *) nile4_in32(NILE4_CPUSTAT)); + printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4), + (void *) nile4_in32(NILE4_INTCTRL)); + printk("INTSTAT0 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT0 + 4), + (void *) nile4_in32(NILE4_INTSTAT0)); + printk("INTSTAT1 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT1 + 4), + (void *) nile4_in32(NILE4_INTSTAT1)); + printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4), + (void *) nile4_in32(NILE4_INTCLR)); + printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4), + (void *) nile4_in32(NILE4_INTPPES)); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/pci-dma.c linux.ac/arch/mips/ddb5074/pci-dma.c --- linux.vanilla/arch/mips/ddb5074/pci-dma.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/pci-dma.c Thu Jan 1 01:00:00 1970 @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2000 Ani Joshi - * - * - * Dynamic DMA mapping support. - * - * swiped from i386, and cloned for MIPS by Geert. - * - */ - -#include -#include -#include -#include -#include - -void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - void *ret; - int gfp = GFP_ATOMIC; - - if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) - gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - } - return ret; -} - -void pci_free_consistent(struct pci_dev *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/pci.c linux.ac/arch/mips/ddb5074/pci.c --- linux.vanilla/arch/mips/ddb5074/pci.c Tue Nov 28 01:51:34 2000 +++ linux.ac/arch/mips/ddb5074/pci.c Wed Apr 18 13:50:31 2001 @@ -4,313 +4,325 @@ * Copyright (C) 2000 Geert Uytterhoeven * Albert Dorofeev * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $ */ - #include #include #include #include #include #include -#include + +#include static u32 nile4_pre_pci_access0(int slot_num) { - u32 pci_addr = 0; - u32 virt_addr = NILE4_PCI_CFG_BASE; + u32 pci_addr = 0; + u32 virt_addr = NILE4_PCI_CFG_BASE; - /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */ - nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, 0); - if (slot_num > 2) - pci_addr = 0x00040000 << slot_num; - else - virt_addr += 0x00040000 << slot_num; - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); - return virt_addr; + /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, + 0); + if (slot_num > 2) + pci_addr = 0x00040000 << slot_num; + else + virt_addr += 0x00040000 << slot_num; + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); + return virt_addr; } static void nile4_post_pci_access0(void) { - /* Set window 1 back to address 8000000 - 64 bit - 128 MB (PCI IO space) */ - nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 64, - 1, 1); - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + /* + * Set window 1 back to address 8000000 - 64 bit - 128 MB + * (PCI IO space) + */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), + 0x08000000, 64, 1, 1); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); } -static int nile4_pci_read_config_dword( struct pci_dev *dev, - int where, u32 *val) +static int nile4_pci_read_config_dword(struct pci_dev *dev, + int where, u32 * val) { - int slot_num, func_num; - u32 base; - - /* - * For starters let's do configuration cycle 0 only (one bus only) - */ - if (dev->bus->number) - return PCIBIOS_FUNC_NOT_SUPPORTED; + int slot_num, func_num; + u32 base; - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - if (slot_num == 5) { /* - * This is Nile 4 and it will crash if we access it like other - * devices + * For starters let's do configuration cycle 0 only (one bus only) */ - *val = nile4_in32(NILE4_PCI_BASE + where); + if (dev->bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access it like other + * devices + */ + *val = nile4_in32(NILE4_PCI_BASE + where); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *val = + *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))); + nile4_post_pci_access0(); return PCIBIOS_SUCCESSFUL; - } - base = nile4_pre_pci_access0(slot_num); - *val = *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))); - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; } static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, u32 val) { - int slot_num, func_num; - u32 base; + int slot_num, func_num; + u32 base; - /* - * For starters let's do configuration cycle 0 only (one bus only) - */ - if (dev->bus->number) - return PCIBIOS_FUNC_NOT_SUPPORTED; - - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - if (slot_num == 5) { /* - * This is Nile 4 and it will crash if we access it like other - * devices + * For starters let's do configuration cycle 0 only (one bus only) */ - nile4_out32(NILE4_PCI_BASE + where, val); + if (dev->bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access it like other + * devices + */ + nile4_out32(NILE4_PCI_BASE + where, val); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))) = + val; + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + result >>= 16; + *val = result & 0xffff; return PCIBIOS_SUCCESSFUL; - } - base = nile4_pre_pci_access0(slot_num); - *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))) = val; - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_word(struct pci_dev *dev, int where, u16 *val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - result >>= 16; - *val = result & 0xffff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 1) - result >>= 8; - if (where & 2) - result >>= 16; - *val = result & 0xff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_write_config_word(struct pci_dev *dev, int where, u16 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where, result); -} - -static int nile4_pci_write_config_byte( struct pci_dev *dev, int where, u8 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where, result); +} + +static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 1) + result >>= 8; + if (where & 2) + result >>= 16; + *val = result & 0xff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where, result); +} + +static int nile4_pci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where, result); } struct pci_ops nile4_pci_ops = { - nile4_pci_read_config_byte, - nile4_pci_read_config_word, - nile4_pci_read_config_dword, - nile4_pci_write_config_byte, - nile4_pci_write_config_word, - nile4_pci_write_config_dword + nile4_pci_read_config_byte, + nile4_pci_read_config_word, + nile4_pci_read_config_dword, + nile4_pci_write_config_byte, + nile4_pci_write_config_word, + nile4_pci_write_config_dword }; struct { - struct resource ram; - struct resource flash; - struct resource isa_io; - struct resource pci_io; - struct resource isa_mem; - struct resource pci_mem; - struct resource nile4; - struct resource boot; + struct resource ram; + struct resource flash; + struct resource isa_io; + struct resource pci_io; + struct resource isa_mem; + struct resource pci_mem; + struct resource nile4; + struct resource boot; } ddb5074_resources = { - { "RAM", 0x00000000, 0x03ffffff, - IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, - { "Flash ROM", 0x04000000, 0x043fffff }, - { "Nile4 ISA I/O", 0x06000000, 0x060fffff }, - { "Nile4 PCI I/O", 0x06100000, 0x07ffffff }, - { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM }, - { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM }, - { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, - IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, - { "Boot ROM", 0x1fc00000, 0x1fffffff } + { "RAM", 0x00000000, 0x03ffffff, + IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64}, + { "Flash ROM", 0x04000000, 0x043fffff}, + { "Nile4 ISA I/O", 0x06000000, 0x060fffff}, + { "Nile4 PCI I/O", 0x06100000, 0x07ffffff}, + { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, + { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM}, + { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, + IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64}, + { "Boot ROM", 0x1fc00000, 0x1fffffff} }; static void __init ddb5074_pci_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev; - pci_for_each_dev(dev) { - if (dev->vendor == PCI_VENDOR_ID_NEC && - dev->device == PCI_DEVICE_ID_NEC_NILE4) { - /* - * The first 64-bit PCI base register should point to the Nile4 - * control registers. Unfortunately this isn't the case, so we fix - * it ourselves. This allows the serial driver to find the UART. - */ - dev->resource[0] = ddb5074_resources.nile4; - request_resource(&iomem_resource, &dev->resource[0]); - /* - * The second 64-bit PCI base register points to the first memory - * bank. Unfortunately the address is wrong, so we fix it (again). - */ - dev->resource[2] = ddb5074_resources.ram; - request_resource(&iomem_resource, &dev->resource[2]); - } else if (dev->vendor == PCI_VENDOR_ID_AL && - dev->device == PCI_DEVICE_ID_AL_M7101) { - /* - * It's nice to have the LEDs on the GPIO pins available for - * debugging - */ - extern struct pci_dev *pci_pmu; - u8 t8; - - pci_pmu = dev; /* for LEDs D2 and D3 */ - /* Program the lines for LEDs D2 and D3 to output */ - nile4_pci_read_config_byte(dev, 0x7d, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7d, t8); - /* Turn LEDs D2 and D3 off */ - nile4_pci_read_config_byte(dev, 0x7e, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7e, t8); + pci_for_each_dev(dev) { + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_NILE4) { + /* + * The first 64-bit PCI base register should point to + * the Nile4 control registers. Unfortunately this + * isn't the case, so we fix it ourselves. This allows + * the serial driver to find the UART. + */ + dev->resource[0] = ddb5074_resources.nile4; + request_resource(&iomem_resource, + &dev->resource[0]); + /* + * The second 64-bit PCI base register points to the + * first memory bank. Unfortunately the address is + * wrong, so we fix it (again). + */ + dev->resource[2] = ddb5074_resources.ram; + request_resource(&iomem_resource, + &dev->resource[2]); + } else if (dev->vendor == PCI_VENDOR_ID_AL + && dev->device == PCI_DEVICE_ID_AL_M7101) { + /* + * It's nice to have the LEDs on the GPIO pins + * available for debugging + */ + extern struct pci_dev *pci_pmu; + u8 t8; + + pci_pmu = dev; /* for LEDs D2 and D3 */ + /* Program the lines for LEDs D2 and D3 to output */ + nile4_pci_read_config_byte(dev, 0x7d, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7d, t8); + /* Turn LEDs D2 and D3 off */ + nile4_pci_read_config_byte(dev, 0x7e, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7e, t8); + } } - } } static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; - int slot_num; + struct pci_dev *dev; + int slot_num; - pci_for_each_dev(dev) { - slot_num = PCI_SLOT(dev->devfn); - switch (slot_num) { - case 0: - dev->irq = nile4_to_irq(NILE4_INT_INTE); - break; - case 1: - dev->irq = nile4_to_irq(NILE4_INT_INTA); - break; - case 2: /* slot 1 */ - dev->irq = nile4_to_irq(NILE4_INT_INTA); - break; - case 3: /* slot 2 */ - dev->irq = nile4_to_irq(NILE4_INT_INTB); - break; - case 4: /* slot 3 */ - dev->irq = nile4_to_irq(NILE4_INT_INTC); - break; - case 5: - /* - * Fixup so the serial driver can use the UART - */ - dev->irq = nile4_to_irq(NILE4_INT_UART); - break; - case 13: - dev->irq = nile4_to_irq(NILE4_INT_INTE); - break; - default: - break; + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + switch (slot_num) { + case 0: + dev->irq = nile4_to_irq(NILE4_INT_INTE); + break; + case 1: + dev->irq = nile4_to_irq(NILE4_INT_INTA); + break; + case 2: /* slot 1 */ + dev->irq = nile4_to_irq(NILE4_INT_INTA); + break; + case 3: /* slot 2 */ + dev->irq = nile4_to_irq(NILE4_INT_INTB); + break; + case 4: /* slot 3 */ + dev->irq = nile4_to_irq(NILE4_INT_INTC); + break; + case 5: + /* + * Fixup so the serial driver can use the UART + */ + dev->irq = nile4_to_irq(NILE4_INT_UART); + break; + case 13: + dev->irq = nile4_to_irq(NILE4_INT_INTE); + break; + default: + break; + } } - } } void __init pcibios_init(void) { - printk("PCI: Probing PCI hardware\n"); - ioport_resource.end = 0x1ffffff; /* 32 MB */ - iomem_resource.end = 0x1fffffff; /* 512 MB */ - /* `ram' and `nile4' are requested through the Nile4 pci_dev */ - request_resource(&iomem_resource, &ddb5074_resources.flash); - request_resource(&iomem_resource, &ddb5074_resources.isa_io); - request_resource(&iomem_resource, &ddb5074_resources.pci_io); - request_resource(&iomem_resource, &ddb5074_resources.isa_mem); - request_resource(&iomem_resource, &ddb5074_resources.pci_mem); - request_resource(&iomem_resource, &ddb5074_resources.boot); - - pci_scan_bus(0, &nile4_pci_ops, NULL); - ddb5074_pci_fixup(); - pci_assign_unassigned_resources(); - pcibios_fixup_irqs(); + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = 0x1ffffff; /* 32 MB */ + iomem_resource.end = 0x1fffffff; /* 512 MB */ + /* `ram' and `nile4' are requested through the Nile4 pci_dev */ + request_resource(&iomem_resource, &ddb5074_resources.flash); + request_resource(&iomem_resource, &ddb5074_resources.isa_io); + request_resource(&iomem_resource, &ddb5074_resources.pci_io); + request_resource(&iomem_resource, &ddb5074_resources.isa_mem); + request_resource(&iomem_resource, &ddb5074_resources.pci_mem); + request_resource(&iomem_resource, &ddb5074_resources.boot); + + pci_scan_bus(0, &nile4_pci_ops, NULL); + ddb5074_pci_fixup(); + pci_assign_unassigned_resources(); + pcibios_fixup_irqs(); } void __init pcibios_fixup_bus(struct pci_bus *bus) { - bus->resource[1] = &ddb5074_resources.pci_mem; + bus->resource[1] = &ddb5074_resources.pci_mem; } -char *pcibios_setup (char *str) +char *pcibios_setup(char *str) { - return str; + return str; } void __init pcibios_update_irq(struct pci_dev *dev, int irq) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) { - ranges->io_start -= bus->resource[0]->start; - ranges->io_end -= bus->resource[0]->start; - ranges->mem_start -= bus->resource[1]->start; - ranges->mem_end -= bus->resource[1]->start; + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; } int pcibios_enable_resources(struct pci_dev *dev) @@ -323,15 +335,15 @@ * Don't touch the Nile 4 */ if (dev->vendor == PCI_VENDOR_ID_NEC && - dev->device == PCI_DEVICE_ID_NEC_NILE4) - return 0; + dev->device == PCI_DEVICE_ID_NEC_NILE4) return 0; pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for(idx=0; idx<6; idx++) { + for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", dev->slot_name); return -EINVAL; } if (r->flags & IORESOURCE_IO) @@ -340,7 +352,8 @@ cmd |= PCI_COMMAND_MEMORY; } if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + printk("PCI: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); } return 0; @@ -348,7 +361,7 @@ int pcibios_enable_device(struct pci_dev *dev) { - return pcibios_enable_resources(dev); + return pcibios_enable_resources(dev); } void pcibios_update_resource(struct pci_dev *dev, struct resource *root, @@ -359,18 +372,23 @@ new = res->start | (res->flags & PCI_REGION_FLAG_MASK); if (resource < 6) { - reg = PCI_BASE_ADDRESS_0 + 4*resource; + reg = PCI_BASE_ADDRESS_0 + 4 * resource; } else if (resource == PCI_ROM_RESOURCE) { res->flags |= PCI_ROM_ADDRESS_ENABLE; reg = dev->rom_base_reg; } else { - /* Somebody might have asked allocation of a non-standard resource */ + /* + * Somebody might have asked allocation of a non-standard + * resource + */ return; } - + pci_write_config_dword(dev, reg, new); pci_read_config_dword(dev, reg, &check); - if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + if ((new ^ check) & + ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : + PCI_BASE_ADDRESS_MEM_MASK)) { printk(KERN_ERR "PCI: Error while updating region " "%s/%d (%08x != %08x)\n", dev->slot_name, resource, new, check); @@ -400,5 +418,4 @@ } -struct pci_fixup pcibios_fixups[] = {}; - +struct pci_fixup pcibios_fixups[] = { }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/prom.c linux.ac/arch/mips/ddb5074/prom.c --- linux.vanilla/arch/mips/ddb5074/prom.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/prom.c Wed Apr 18 13:50:31 2001 @@ -3,58 +3,32 @@ * * Copyright (C) 2000 Geert Uytterhoeven * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: prom.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include #include #include #include + #include #include -char arcs_cmdline[CL_SIZE]; - -extern char _end; - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) - +char arcs_cmdline[COMMAND_LINE_SIZE]; void __init prom_init(const char *s) { - int i = 0; - unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size; + int i = 0; -// _serinit(); + if (s != (void *) -1) + while (*s && i < sizeof(arcs_cmdline) - 1) + arcs_cmdline[i++] = *s++; + arcs_cmdline[i] = '\0'; - if (s != (void *)-1) - while (*s && i < sizeof(arcs_cmdline)-1) - arcs_cmdline[i++] = *s++; - arcs_cmdline[i] = '\0'; - - mips_machgroup = MACH_GROUP_NEC_DDB; - mips_machtype = MACH_NEC_DDB5074; - /* 64 MB non-upgradable */ - mem_size = 64 << 20; - - free_start = PHYSADDR(PFN_ALIGN(&_end)); - free_end = mem_size; - start_pfn = PFN_UP((unsigned long)&_end); - - /* Register all the contiguous memory with the bootmem allocator - and free it. Be careful about the bootmem freemap. */ - bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); - - /* Free the entire available memory after the _end symbol. */ - free_start += bootmap_size; - free_bootmem(free_start, free_end-free_start); -} + mips_machgroup = MACH_GROUP_NEC_DDB; + mips_machtype = MACH_NEC_DDB5074; -void __init prom_fixup_mem_map(unsigned long start, unsigned long end) -{ + /* 64 MB non-upgradable */ + add_memory_region(0, 64 << 20, BOOT_MEM_RAM); } void __init prom_free_prom_memory(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/setup.c linux.ac/arch/mips/ddb5074/setup.c --- linux.vanilla/arch/mips/ddb5074/setup.c Mon Jul 10 06:18:15 2000 +++ linux.ac/arch/mips/ddb5074/setup.c Wed Apr 18 13:50:31 2001 @@ -3,10 +3,7 @@ * * Copyright (C) 2000 Geert Uytterhoeven * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: setup.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include #include #include @@ -42,85 +39,83 @@ extern struct ide_ops std_ide_ops; extern struct rtc_ops ddb_rtc_ops; -static void (*back_to_prom)(void) = (void (*)(void))0xbfc00000; +static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; static void ddb_machine_restart(char *command) { - u32 t; + u32 t; - /* PCI cold reset */ - t = nile4_in32(NILE4_PCICTRL+4); - t |= 0x40000000; - nile4_out32(NILE4_PCICTRL+4, t); - /* CPU cold reset */ - t = nile4_in32(NILE4_CPUSTAT); - t |= 1; - nile4_out32(NILE4_CPUSTAT, t); - /* Call the PROM */ - back_to_prom(); + /* PCI cold reset */ + t = nile4_in32(NILE4_PCICTRL + 4); + t |= 0x40000000; + nile4_out32(NILE4_PCICTRL + 4, t); + /* CPU cold reset */ + t = nile4_in32(NILE4_CPUSTAT); + t |= 1; + nile4_out32(NILE4_CPUSTAT, t); + /* Call the PROM */ + back_to_prom(); } static void ddb_machine_halt(void) { - printk("DDB Vrc-5074 halted.\n"); - do {} while (1); + printk("DDB Vrc-5074 halted.\n"); + do { + } while (1); } static void ddb_machine_power_off(void) { - printk("DDB Vrc-5074 halted. Please turn off the power.\n"); - do {} while (1); + printk("DDB Vrc-5074 halted. Please turn off the power.\n"); + do { + } while (1); } extern void ddb_irq_setup(void); -void (*board_time_init)(struct irqaction *irq); +void (*board_time_init) (struct irqaction * irq); static void __init ddb_time_init(struct irqaction *irq) { - /* set the clock to 1 Hz */ - nile4_out32(NILE4_T2CTRL, 1000000); - /* enable the General-Purpose Timer */ - nile4_out32(NILE4_T2CTRL+4, 0x00000001); - /* reset timer */ - nile4_out32(NILE4_T2CNTR, 0); - /* enable interrupt */ - nile4_enable_irq(NILE4_INT_GPT); - i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); - set_cp0_status(ST0_IM, IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); + /* set the clock to 1 Hz */ + nile4_out32(NILE4_T2CTRL, 1000000); + /* enable the General-Purpose Timer */ + nile4_out32(NILE4_T2CTRL + 4, 0x00000001); + /* reset timer */ + nile4_out32(NILE4_T2CNTR, 0); + /* enable interrupt */ + nile4_enable_irq(NILE4_INT_GPT); + i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); + change_cp0_status(ST0_IM, + IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); } void __init ddb_setup(void) { - extern int panic_timeout; + extern int panic_timeout; - irq_setup = ddb_irq_setup; - mips_io_port_base = NILE4_PCI_IO_BASE; - isa_slot_offset = NILE4_PCI_MEM_BASE; - request_region(0x00, 0x20, "dma1"); - request_region(0x40, 0x20, "timer"); - request_region(0x70, 0x10, "rtc"); - request_region(0x80, 0x10, "dma page reg"); - request_region(0xc0, 0x20, "dma2"); - board_time_init = ddb_time_init; - - _machine_restart = ddb_machine_restart; - _machine_halt = ddb_machine_halt; - _machine_power_off = ddb_machine_power_off; + irq_setup = ddb_irq_setup; + mips_io_port_base = NILE4_PCI_IO_BASE; + isa_slot_offset = NILE4_PCI_MEM_BASE; + request_region(0x00, 0x20, "dma1"); + request_region(0x40, 0x20, "timer"); + request_region(0x70, 0x10, "rtc"); + request_region(0x80, 0x10, "dma page reg"); + request_region(0xc0, 0x20, "dma2"); + board_time_init = ddb_time_init; + + _machine_restart = ddb_machine_restart; + _machine_halt = ddb_machine_halt; + _machine_power_off = ddb_machine_power_off; #ifdef CONFIG_BLK_DEV_IDE - ide_ops = &std_ide_ops; + ide_ops = &std_ide_ops; #endif - rtc_ops = &ddb_rtc_ops; + rtc_ops = &ddb_rtc_ops; - /* Reboot on panic */ - panic_timeout = 180; -} - -int __init page_is_ram(unsigned long pagenr) -{ - return 1; + /* Reboot on panic */ + panic_timeout = 180; } @@ -133,12 +128,12 @@ #define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8) static inline u8 ns16550_in(u32 reg) { - return *(volatile u8 *)(NS16550_BASE+reg); + return *(volatile u8 *) (NS16550_BASE + reg); } static inline void ns16550_out(u32 reg, u8 val) { - *(volatile u8 *)(NS16550_BASE+reg) = val; + *(volatile u8 *) (NS16550_BASE + reg) = val; } #endif @@ -168,87 +163,84 @@ void _serinit(void) { #if USE_NILE4_SERIAL - ns16550_out(NS16550_LCR, 0x80); - ns16550_out(NS16550_DLM, 0x00); - ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ - ns16550_out(NS16550_LCR, 0x00); - ns16550_out(NS16550_LCR, 0x03); - ns16550_out(NS16550_FCR, 0x47); + ns16550_out(NS16550_LCR, 0x80); + ns16550_out(NS16550_DLM, 0x00); + ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ + ns16550_out(NS16550_LCR, 0x00); + ns16550_out(NS16550_LCR, 0x03); + ns16550_out(NS16550_FCR, 0x47); #else - /* done by PMON */ + /* done by PMON */ #endif } void _putc(char c) { - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, c); - if (c == '\n') { while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, '\r'); - } + ns16550_out(NS16550_THR, c); + if (c == '\n') { + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, '\r'); + } } void _puts(const char *s) { - char c; - while ((c = *s++)) - _putc(c); + char c; + while ((c = *s++)) + _putc(c); } char _getc(void) { - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); - return ns16550_in(NS16550_RBR); + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); + return ns16550_in(NS16550_RBR); } int _testc(void) { - return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; + return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; } - /* - * Hexadecimal 7-segment LED - */ - +/* + * Hexadecimal 7-segment LED + */ void ddb5074_led_hex(int hex) { - outb(hex, 0x80); + outb(hex, 0x80); } - /* - * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 - */ - +/* + * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 + */ struct pci_dev *pci_pmu = NULL; void ddb5074_led_d2(int on) { - u8 t; + u8 t; - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0x7f; - else - t |= 0x80; - pci_write_config_byte(pci_pmu, 0x7e, t); - } + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0x7f; + else + t |= 0x80; + pci_write_config_byte(pci_pmu, 0x7e, t); + } } void ddb5074_led_d3(int on) { - u8 t; + u8 t; - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0xbf; - else - t |= 0x40; - pci_write_config_byte(pci_pmu, 0x7e, t); - } + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0xbf; + else + t |= 0x40; + pci_write_config_byte(pci_pmu, 0x7e, t); + } } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5074/time.c linux.ac/arch/mips/ddb5074/time.c --- linux.vanilla/arch/mips/ddb5074/time.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/ddb5074/time.c Wed Apr 18 13:50:31 2001 @@ -3,33 +3,30 @@ * * Copyright (C) 2000 Geert Uytterhoeven * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id* */ - #include #include static unsigned char ddb_rtc_read_data(unsigned long addr) { - outb_p(addr, RTC_PORT(0)); - return inb_p(RTC_PORT(1)); + outb_p(addr, RTC_PORT(0)); + + return inb_p(RTC_PORT(1)); } static void ddb_rtc_write_data(unsigned char data, unsigned long addr) { - outb_p(addr, RTC_PORT(0)); - outb_p(data, RTC_PORT(1)); + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); } static int ddb_rtc_bcd_mode(void) { - return 1; + return 1; } struct rtc_ops ddb_rtc_ops = { - ddb_rtc_read_data, - ddb_rtc_write_data, - ddb_rtc_bcd_mode + ddb_rtc_read_data, + ddb_rtc_write_data, + ddb_rtc_bcd_mode }; - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/Makefile linux.ac/arch/mips/ddb5476/Makefile --- linux.vanilla/arch/mips/ddb5476/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/Makefile Wed Apr 18 13:50:31 2001 @@ -0,0 +1,23 @@ +# +# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines +# under Linux. +# +# 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 definitions are now in the main makefile... +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET = ddb5476.a + +obj-y += setup.o irq.o time.o prom.o pci.o \ + int-handler.o nile4.o +obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/dbg_io.c linux.ac/arch/mips/ddb5476/dbg_io.c --- linux.vanilla/arch/mips/ddb5476/dbg_io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/dbg_io.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,125 @@ + +#include + +#if (defined(CONFIG_DDB5476) && defined(CONFIG_REMOTE_DEBUG)) + +/* --- CONFIG --- */ + +/* we need uint32 uint8 */ +/* #include "types.h" */ +typedef unsigned char uint8; +typedef unsigned int uint32; + +/* --- END OF CONFIG --- */ + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* ----------------------------------------------------- */ + +/* === CONFIG === */ + +/* [jsun] we use the second serial port for kdb */ +#define BASE 0xa60002f8 +#define MAX_BAUD 115200 + +/* === END OF CONFIG === */ + +/* register offset */ +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 +#define OFS_INTR_ENABLE 1 +#define OFS_INTR_ID 2 +#define OFS_DATA_FORMAT 3 +#define OFS_LINE_CONTROL 3 +#define OFS_MODEM_CONTROL 4 +#define OFS_RS232_OUTPUT 4 +#define OFS_LINE_STATUS 5 +#define OFS_MODEM_STATUS 6 +#define OFS_RS232_INPUT 6 +#define OFS_SCRATCH_PAD 7 + +#define OFS_DIVISOR_LSB 0 +#define OFS_DIVISOR_MSB 1 + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) +#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + +static int remoteDebugInitialized = 0; + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_38400, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +int putDebugChar(uint8 byte) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_9600, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/int-handler.S linux.ac/arch/mips/ddb5476/int-handler.S --- linux.vanilla/arch/mips/ddb5476/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/int-handler.S Wed Apr 18 13:50:31 2001 @@ -0,0 +1,125 @@ +/* + * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler + * + * Based on arch/mips/sgi/kernel/indyIRQ.S + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include +#include +#include +#include + +/* + * A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the INDY look basically (barring software IRQs + * which we don't use at all) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Local IRQ level zero + * 3 Local IRQ level one + * 4 8254 Timer zero + * 5 8254 Timer one + * 6 Bus Error + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Local IRQ zero + * Local IRQ one + * Bus Error + * 8254 Timer zero + * Lowest ---- 8254 Timer one + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(ddbIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + mfc0 s1, CP0_CAUSE # get irq mask + +#if 1 + mfc0 t2,CP0_STATUS # get enabled interrupts + and s0, s1, t2 # isolate allowed ones +#endif + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP3 # delay slot, check local level one + + /* Wheee, local level zero interrupt. */ + jal ddb_local0_irqdispatch + move a0, sp # delay slot + + j ret_from_irq + nop # delay slot + +1: + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP6 # delay slot, check bus error + + /* Wheee, local level one interrupt. */ + move a0, sp + jal ddb_local1_irqdispatch + nop + + j ret_from_irq + nop + +1: + beq a0, zero, 1f + nop + + /* Wheee, an asynchronous bus error... */ + move a0, sp + jal ddb_buserror_irq + nop + + j ret_from_irq + nop + +1: + /* Here by mistake? This is possible, what can happen + * is that by the time we take the exception the IRQ + * pin goes low, so just leave if this is the case. + */ + andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) + beq a0, zero, 1f + + /* Must be one of the 8254 timers... */ + move a0, sp + jal ddb_8254timer_irq + nop +1: + /* phamtom interrupt */ + move a0, s1 + jal ddb_phantom_irq + nop + j ret_from_irq + nop + END(ddbIRQ) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/irq.c linux.ac/arch/mips/ddb5476/irq.c --- linux.vanilla/arch/mips/ddb5476/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/irq.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,251 @@ +/* + * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern void __init i8259_init(void); +extern void i8259_disable_irq(unsigned int irq_nr); +extern void i8259_enable_irq(unsigned int irq_nr); + +extern asmlinkage void ddbIRQ(void); +extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); +extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); + + +void no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ +} + + +#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ +#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ +#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ + +#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ +#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ +#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ + +#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ +#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ + +#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ +#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ + +#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */ +#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */ + +static struct { + struct resource m1543_config; + struct resource pic_elcr; +} m1543_ioport = { + { "M1543 config", M1543_PNP_CONFIG, M1543_PNP_CONFIG + 1, + IORESOURCE_BUSY}, + { "pic ELCR", M1543_INT1_MASTER_ELCR, M1543_INT1_MASTER_ELCR + 1, + IORESOURCE_BUSY} +}; + +static void m1543_irq_setup(void) +{ + /* + * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all + * the possible IO sources in the M1543 are in use by us. We will + * use the following mapping: + * + * IRQ1 - keyboard (default set by M1543) + * IRQ3 - reserved for UART B (default set by M1543) (note that + * the schematics for the DDB Vrc-5476 board seem to + * indicate that IRQ3 is connected to the DS1386 + * watchdog timer interrupt output so we might have + * a conflict) + * IRQ4 - reserved for UART A (default set by M1543) + * IRQ5 - parallel (default set by M1543) + * IRQ8 - DS1386 time of day (RTC) interrupt + * IRQ9 - USB (hardwired in ddb_setup) + * IRQ10 - PMU (hardwired in ddb_setup) + * IRQ12 - mouse + * IRQ14,15 - IDE controller (need to be confirmed, jsun) + */ + + /* + * Assing mouse interrupt to IRQ12 + */ + + /* Enter configuration mode */ + outb(0x51, M1543_PNP_CONFIG); + outb(0x23, M1543_PNP_CONFIG); + + /* Select logical device 7 (Keyboard) */ + outb(0x07, M1543_PNP_INDEX); + outb(0x07, M1543_PNP_DATA); + + /* Select IRQ12 */ + outb(0x72, M1543_PNP_INDEX); + outb(0x0c, M1543_PNP_DATA); + + /* Leave configration mode */ + outb(0xbb, M1543_PNP_CONFIG); + + + /* Initialize the 8259 PIC in the M1543 */ + i8259_init(); + + /* Enable the interrupt cascade from M1543 */ + nile4_enable_irq(NILE4_INT_INTC); + + /* request io ports */ + if (request_resource(&ioport_resource, &m1543_ioport.m1543_config) + || request_resource(&ioport_resource, &m1543_ioport.pic_elcr)) { + printk("m1543_irq_setup : requesting io ports failed.\n"); + for (;;); + } +} + +static void nile4_irq_setup(void) +{ + int i; + + /* Map all interrupts to CPU int #0 */ + nile4_map_irq_all(0); + + /* PCI INTA#-E# must be level triggered */ + nile4_set_pci_irq_level_or_edge(0, 1); + nile4_set_pci_irq_level_or_edge(1, 1); + nile4_set_pci_irq_level_or_edge(2, 1); + nile4_set_pci_irq_level_or_edge(3, 1); + + /* PCI INTA#, B#, D# must be active low, INTC# must be active high */ + nile4_set_pci_irq_polarity(0, 0); + nile4_set_pci_irq_polarity(1, 0); + nile4_set_pci_irq_polarity(2, 1); + nile4_set_pci_irq_polarity(3, 0); + + for (i = 0; i < 16; i++) + nile4_clear_irq(i); + + /* Enable CPU int #0 */ + nile4_enable_irq_output(0); + + /* memory resource acquire in ddb_setup */ +} + + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; + + +void disable_irq(unsigned int irq_nr) +{ + if (is_i8259_irq(irq_nr)) + i8259_disable_irq(irq_nr); + else + nile4_disable_irq(irq_to_nile4(irq_nr)); +} + +void enable_irq(unsigned int irq_nr) +{ + if (is_i8259_irq(irq_nr)) + i8259_enable_irq(irq_nr); + else + nile4_enable_irq(irq_to_nile4(irq_nr)); +} + +int table[16] = { 0, }; + +void ddb_local0_irqdispatch(struct pt_regs *regs) +{ + u32 mask; + int nile4_irq; +#if 0 + volatile static int nesting = 0; + if (nesting++ == 0) + ddb5476_led_d3(1); + ddb5476_led_hex(nesting < 16 ? nesting : 15); +#endif + + mask = nile4_get_irq_stat(0); + nile4_clear_irq_mask(mask); + + /* Handle the timer interrupt first */ + if (mask & (1 << NILE4_INT_GPT)) { + nile4_disable_irq(NILE4_INT_GPT); + do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); + nile4_enable_irq(NILE4_INT_GPT); + mask &= ~(1 << NILE4_INT_GPT); + } + for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) + if (mask & 1) { + nile4_disable_irq(nile4_irq); + if (nile4_irq == NILE4_INT_INTC) { + int i8259_irq = nile4_i8259_iack(); + i8259_do_irq(i8259_irq, regs); + } else { + do_IRQ(nile4_to_irq(nile4_irq), regs); + } + nile4_enable_irq(nile4_irq); + } +#if 0 + if (--nesting == 0) + ddb5476_led_d3(0); + ddb5476_led_hex(nesting < 16 ? nesting : 15); +#endif +} + +void ddb_local1_irqdispatch(void) +{ + printk("ddb_local1_irqdispatch called\n"); +} + +void ddb_buserror_irq(void) +{ + printk("ddb_buserror_irq called\n"); +} + +void ddb_8254timer_irq(void) +{ + printk("ddb_8254timer_irq called\n"); +} + +void ddb_phantom_irq(unsigned long cause) +{ + printk("phantom interrupts detected : \n"); + printk("\tcause \t\t0x%08x\n", cause); + printk("\tcause reg\t0x%08x\n", + read_32bit_cp0_register(CP0_CAUSE)); + printk("\tstatus reg\t0x%08x\n", + read_32bit_cp0_register(CP0_STATUS)); +} + +void __init ddb_irq_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + printk("Wait for gdb client connection ...\n"); + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ +#endif + i8259_setup_irq(2, &irq2); + + nile4_irq_setup(); + m1543_irq_setup(); + + /* we pin #0 - #4 (no internal timer) */ + change_cp0_status(ST0_IM, + IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); + + set_except_vector(0, ddbIRQ); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/nile4.c linux.ac/arch/mips/ddb5476/nile4.c --- linux.vanilla/arch/mips/ddb5476/nile4.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/nile4.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,293 @@ +/* + * arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include +#include + +#include + + +/* + * Physical Device Address Registers + * + * Note: 32 bit addressing only! + */ +void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, + int on_memory_bus, int visible) +{ + u32 maskbits; + u32 widthbits; + + if (pdar > NILE4_BOOTCS || (pdar & 7)) { + printk("nile4_set_pdar: invalid pdar %d\n", pdar); + return; + } + if (pdar == NILE4_INTCS && size != 0x00200000) { + printk("nile4_set_pdar: INTCS size must be 2 MB\n"); + return; + } + switch (size) { +#if 0 /* We don't support 4 GB yet */ + case 0x100000000: /* 4 GB */ + maskbits = 4; + break; +#endif + case 0x80000000: /* 2 GB */ + maskbits = 5; + break; + case 0x40000000: /* 1 GB */ + maskbits = 6; + break; + case 0x20000000: /* 512 MB */ + maskbits = 7; + break; + case 0x10000000: /* 256 MB */ + maskbits = 8; + break; + case 0x08000000: /* 128 MB */ + maskbits = 9; + break; + case 0x04000000: /* 64 MB */ + maskbits = 10; + break; + case 0x02000000: /* 32 MB */ + maskbits = 11; + break; + case 0x01000000: /* 16 MB */ + maskbits = 12; + break; + case 0x00800000: /* 8 MB */ + maskbits = 13; + break; + case 0x00400000: /* 4 MB */ + maskbits = 14; + break; + case 0x00200000: /* 2 MB */ + maskbits = 15; + break; + case 0: /* OFF */ + maskbits = 0; + break; + default: + printk("nile4_set_pdar: unsupported size %p\n", + (void *) size); + return; + } + switch (width) { + case 8: + widthbits = 0; + break; + case 16: + widthbits = 1; + break; + case 32: + widthbits = 2; + break; + case 64: + widthbits = 3; + break; + default: + printk("nile4_set_pdar: unsupported width %d\n", width); + return; + } + nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | + (visible ? 0x20 : 0) | (widthbits << 6) | + (phys & 0xffe00000)); + nile4_out32(pdar + 4, 0); + /* + * When programming a PDAR, the register should be read immediately + * after writing it. This ensures that address decoders are properly + * configured. + */ + nile4_in32(pdar); + nile4_in32(pdar + 4); +} + + +/* + * PCI Master Registers + * + * Note: 32 bit addressing only! + */ +void nile4_set_pmr(u32 pmr, u32 type, u32 addr) +{ + if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { + printk("nile4_set_pmr: invalid pmr %d\n", pmr); + return; + } + switch (type) { + case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */ + case NILE4_PCICMD_IO: /* PCI I/O Space */ + case NILE4_PCICMD_MEM: /* PCI Memory Space */ + case NILE4_PCICMD_CFG: /* PCI Configuration Space */ + break; + default: + printk("nile4_set_pmr: invalid type %d\n", type); + return; + } + nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); + nile4_out32(pmr + 4, 0); +} + + +/* + * Interrupt Programming + */ +void nile4_map_irq(int nile4_irq, int cpu_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(7 << (nile4_irq * 4)); + t |= cpu_irq << (nile4_irq * 4); + nile4_out32(offset, t); +} + +void nile4_map_irq_all(int cpu_irq) +{ + u32 all, t; + + all = cpu_irq; + all |= all << 4; + all |= all << 8; + all |= all << 16; + t = nile4_in32(NILE4_INTCTRL); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL, t); + t = nile4_in32(NILE4_INTCTRL + 4); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL + 4, t); +} + +void nile4_enable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t |= 8 << (nile4_irq * 4); + nile4_out32(offset, t); +} + +void nile4_disable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(8 << (nile4_irq * 4)); + nile4_out32(offset, t); +} + +void nile4_disable_irq_all(void) +{ + nile4_out32(NILE4_INTCTRL, 0); + nile4_out32(NILE4_INTCTRL + 4, 0); +} + +u16 nile4_get_irq_stat(int cpu_irq) +{ + return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2); +} + +void nile4_enable_irq_output(int cpu_irq) +{ + u32 t; + + t = nile4_in32(NILE4_INTSTAT1 + 4); + t |= 1 << (16 + cpu_irq); + nile4_out32(NILE4_INTSTAT1, t); +} + +void nile4_disable_irq_output(int cpu_irq) +{ + u32 t; + + t = nile4_in32(NILE4_INTSTAT1 + 4); + t &= ~(1 << (16 + cpu_irq)); + nile4_out32(NILE4_INTSTAT1, t); +} + +void nile4_set_pci_irq_polarity(int pci_irq, int high) +{ + u32 t; + + t = nile4_in32(NILE4_INTPPES); + if (high) + t &= ~(1 << (pci_irq * 2)); + else + t |= 1 << (pci_irq * 2); + nile4_out32(NILE4_INTPPES, t); +} + +void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) +{ + u32 t; + + t = nile4_in32(NILE4_INTPPES); + if (level) + t |= 2 << (pci_irq * 2); + else + t &= ~(2 << (pci_irq * 2)); + nile4_out32(NILE4_INTPPES, t); +} + +void nile4_clear_irq(int nile4_irq) +{ + nile4_out32(NILE4_INTCLR, 1 << nile4_irq); +} + +void nile4_clear_irq_mask(u32 mask) +{ + nile4_out32(NILE4_INTCLR, mask); +} + +u8 nile4_i8259_iack(void) +{ + u8 irq; + + /* Set window 0 for interrupt acknowledge */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); + irq = *(volatile u8 *) NILE4_PCI_IACK_BASE; + /* Set window 0 for PCI I/O space */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + return irq; +} + +#if 0 +void nile4_dump_irq_status(void) +{ + printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4), + (void *) nile4_in32(NILE4_CPUSTAT)); + printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4), + (void *) nile4_in32(NILE4_INTCTRL)); + printk("INTSTAT0 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT0 + 4), + (void *) nile4_in32(NILE4_INTSTAT0)); + printk("INTSTAT1 = %p:%p\n", + (void *) nile4_in32(NILE4_INTSTAT1 + 4), + (void *) nile4_in32(NILE4_INTSTAT1)); + printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4), + (void *) nile4_in32(NILE4_INTCLR)); + printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4), + (void *) nile4_in32(NILE4_INTPPES)); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/pci.c linux.ac/arch/mips/ddb5476/pci.c --- linux.vanilla/arch/mips/ddb5476/pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/pci.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,495 @@ +/* + * arch/mips/ddb5476/pci.c -- NEC DDB Vrc-5074 PCI access routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Albert Dorofeev + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include +#include +#include +#include +#include +#include + +#include + + +static u32 nile4_pre_pci_access0(int slot_num) +{ + u32 pci_addr = 0; + u32 virt_addr = NILE4_PCI_CFG_BASE; + + /* work around the bug for Vrc5476 */ + if (slot_num == 13) + return NILE4_BASE + NILE4_PCI_BASE; + + /* Set window 1 address 08000000 - 32 bit - 128 MB (PCI config space) */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x08000000, 32, 0, + 0); + + // [jsun] we start scanning from addr:10, + // with 128M we can go up to addr:26 (slot 16) + if (slot_num <= 16) { + virt_addr += 0x00000400 << slot_num; + } else { + /* for high slot, we have to set higher PCI base addr */ + pci_addr = 0x00000400 << slot_num; + } + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); + return virt_addr; +} + +static void nile4_post_pci_access0(void) +{ + /* + * Set window 1 back to address 08000000 - 32 bit - 128 MB + * (PCI IO space) + */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), + 0x08000000, 32, 1, 1); + // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); +} + + +static int nile4_pci_read_config_dword(struct pci_dev *dev, + int where, u32 * val) +{ + int slot_num, func_num; + u32 base; + u32 addr; + + /* + * Do we need to generate type 1 configure transaction? + */ + if (dev->bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* + * the largest type 1 configuration addr is 16M, < 256M + * config space + */ + slot_num = 0; + addr = + (dev->bus->number << 16) | (dev->devfn < + 8) | where | 1; + } else { + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + addr = (func_num << 8) + where; + } + + base = nile4_pre_pci_access0(slot_num); + *val = *(volatile u32 *) (base + addr); + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, + u32 val) +{ + int slot_num, func_num; + u32 base; + u32 addr; + + /* + * Do we need to generate type 1 configure transaction? + */ + if (dev->bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* the largest type 1 configuration addr is 16M, < 256M config space */ + slot_num = 0; + addr = + (dev->bus->number << 16) | (dev->devfn < + 8) | where | 1; + } else { + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + addr = (func_num << 8) + where; + } + + base = nile4_pre_pci_access0(slot_num); + *(volatile u32 *) (base + addr) = val; + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + result >>= 16; + *val = result & 0xffff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 1) + result >>= 8; + if (where & 2) + result >>= 16; + *val = result & 0xff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where & ~3, result); +} + +static int nile4_pci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where & ~3, result); +} + +struct pci_ops nile4_pci_ops = { + nile4_pci_read_config_byte, + nile4_pci_read_config_word, + nile4_pci_read_config_dword, + nile4_pci_write_config_byte, + nile4_pci_write_config_word, + nile4_pci_write_config_dword +}; + +struct { + struct resource ram; + struct resource flash; + struct resource isa_io; + struct resource pci_io; + struct resource isa_mem; + struct resource pci_mem; + struct resource nile4; + struct resource boot; +} ddb5476_resources = { + // { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, + { + "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM}, { + "Flash ROM", 0x04000000, 0x043fffff}, { + "Nile4 ISA I/O", 0x06000000, 0x060fffff}, { + "Nile4 PCI I/O", 0x06100000, 0x07ffffff}, { + "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, { + "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM}, + // { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, + { + "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM}, { + "Boot ROM", 0x1fc00000, 0x1fffffff} +}; + +struct resource M5229_resources[5] = { + {"M5229 BAR0", 0x1f0, 0x1f3, IORESOURCE_IO}, + {"M5229 BAR1", 0x3f4, 0x3f7, IORESOURCE_IO}, + {"M5229 BAR2", 0x170, 0x173, IORESOURCE_IO}, + {"M5229 BAR3", 0x374, 0x377, IORESOURCE_IO}, + {"M5229 BAR4", 0xf000, 0xf00f, IORESOURCE_IO} +}; + +static void __init ddb5476_pci_fixup(void) +{ + struct pci_dev *dev; + + pci_for_each_dev(dev) { + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_VRC5476) { + /* + * The first 64-bit PCI base register should point to + * the Nile4 control registers. Unfortunately this + * isn't the case, so we fix it ourselves. This allows + * the serial driver to find the UART. + */ + dev->resource[0] = ddb5476_resources.nile4; + request_resource(&iomem_resource, + &dev->resource[0]); + /* + * The second 64-bit PCI base register points to the + * first memory bank. Unfortunately the address is + * wrong, so we fix it (again). + */ + + /* [jsun] We cannot request the resource anymore, + * because kernel/setup.c has already reserved "System + * RAM" resource at the same spot. + * The fundamental problem here is that PCI host + * controller should not put system RAM mapping in BAR + * and make subject to PCI resource assignement. + * Current fix is a total hack. We set parent to 1 so + * so that PCI resource assignement code is fooled to + * think the resource is assigned, and will not attempt + * to mess with it. + */ + dev->resource[2] = ddb5476_resources.ram; + if (request_resource(&iomem_resource, + &dev->resource[2]) ) { + dev->resource[2].parent = 0x1; + } + + } else if (dev->vendor == PCI_VENDOR_ID_AL + && dev->device == PCI_DEVICE_ID_AL_M7101) { + /* + * It's nice to have the LEDs on the GPIO pins + * available for debugging + */ + extern struct pci_dev *pci_pmu; + u8 t8; + + pci_pmu = dev; /* for LEDs D2 and D3 */ + /* Program the lines for LEDs D2 and D3 to output */ + nile4_pci_read_config_byte(dev, 0x7d, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7d, t8); + /* Turn LEDs D2 and D3 off */ + nile4_pci_read_config_byte(dev, 0x7e, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7e, t8); + } else if (dev->vendor == PCI_VENDOR_ID_AL && + dev->device == 0x5229) { + int i; + for (i = 0; i < 5; i++) { + dev->resource[i] = M5229_resources[i]; + request_resource(&ioport_resource, + &dev->resource[i]); + } + } + } +} + +static void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev; + int slot_num; + + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + switch (slot_num) { + case 3: /* re-programmed to USB */ + dev->irq = 9; /* hard-coded; see irq.c */ + break; + case 4: /* re-programmed to PMU */ + dev->irq = 10; /* hard-coded; see irq.c */ + break; + case 6: /* on-board pci-pci bridge */ + dev->irq = 0xff; + break; + case 7: /* on-board ether */ + dev->irq = nile4_to_irq(NILE4_INT_INTB); + break; + case 8: /* ISA-PCI bridge */ + dev->irq = nile4_to_irq(NILE4_INT_INTC); + break; + case 9: /* ext slot #3 */ + dev->irq = nile4_to_irq(NILE4_INT_INTD); + break; + case 10: /* ext slot #4 */ + dev->irq = nile4_to_irq(NILE4_INT_INTA); + break; + case 13: /* Vrc5476 */ + dev->irq = 0xff; + break; + case 14: /* HD controller, M5229 */ + dev->irq = 14; + break; + default: + printk + ("JSUN : in pcibios_fixup_irqs - unkown slot %d\n", + slot_num); + panic + ("JSUN : in pcibios_fixup_irqs - unkown slot.\n"); + } + } +} + +void __init pcibios_init(void) +{ + printk("PCI: Emulate bios initialization \n"); + /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ + *(long *) (NILE4_BASE + NILE4_BAR0) = 0x8; + + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = 0x1ffffff; /* 32 MB */ + iomem_resource.end = 0x1fffffff; /* 512 MB */ + + /* `ram' and `nile4' are requested through the Nile4 pci_dev */ + request_resource(&iomem_resource, &ddb5476_resources.flash); + request_resource(&iomem_resource, &ddb5476_resources.isa_io); + request_resource(&iomem_resource, &ddb5476_resources.pci_io); + request_resource(&iomem_resource, &ddb5476_resources.isa_mem); + request_resource(&iomem_resource, &ddb5476_resources.pci_mem); + request_resource(&iomem_resource, &ddb5476_resources.boot); + + pci_scan_bus(0, &nile4_pci_ops, NULL); + ddb5476_pci_fixup(); + pci_assign_unassigned_resources(); + pcibios_fixup_irqs(); +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + /* [jsun] we don't know how to fix sub-buses yet */ + if (bus->number == 0) { + bus->resource[1] = &ddb5476_resources.pci_mem; + } +} + +char *pcibios_setup(char *str) +{ + return str; +} + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, + struct pbus_set_ranges_data *ranges) +{ + /* + * our caller figure out range by going through the dev structures. + * I guess this is the place to fix things up if the bus is using a + * different view of the addressing space. + */ + +#if 0 /* original DDB5074 code */ + if (bus->number == 0) { + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; + } +#endif +} + +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + /* + * Don't touch the Nile 4 + */ + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_VRC5476) return 0; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + return pcibios_enable_resources(dev); +} + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4 * resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* + * Somebody might have asked allocation of a non-standard + * resource + */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & + ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : + PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + /* We need to avoid collisions with `mirrored' VGA ports + and other strange ISA hardware, so we always want the + addresses kilobyte aligned. */ + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + start = (start + 1024 - 1) & ~(1024 - 1); + res->start = start; + } +} + +struct pci_fixup pcibios_fixups[] = { {0} }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/prom.c linux.ac/arch/mips/ddb5476/prom.c --- linux.vanilla/arch/mips/ddb5476/prom.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/prom.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,43 @@ +/* + * arch/mips/ddb5476/prom.c -- NEC DDB Vrc-5476 PROM routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + * + * Jun Sun - modified for DDB5476. + */ +#include +#include +#include +#include + +#include +#include + + +char arcs_cmdline[COMMAND_LINE_SIZE]; + +/* [jsun@junsun.net] PMON passes arguments in C main() style */ +void __init prom_init(int argc, const char **arg) +{ + int i; + + /* arg[0] is "g", the rest is boot parameters */ + arcs_cmdline[0] = '\0'; + for (i = 1; i < argc; i++) { + if (strlen(arcs_cmdline) + strlen(arg[i] + 1) + >= sizeof(arcs_cmdline)) + break; + strcat(arcs_cmdline, arg[i]); + strcat(arcs_cmdline, " "); + } + + mips_machgroup = MACH_GROUP_NEC_DDB; + mips_machtype = MACH_NEC_DDB5476; + /* 64 MB non-upgradable */ + add_memory_region(0, 64 << 20, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/setup.c linux.ac/arch/mips/ddb5476/setup.c --- linux.vanilla/arch/mips/ddb5476/setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/setup.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,375 @@ +/* + * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +extern void breakpoint(void); +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) +extern void console_setup(char *); +#endif + +extern struct ide_ops std_ide_ops; +extern struct rtc_ops ddb_rtc_ops; +extern struct kbd_ops std_kbd_ops; + +static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; + +static void ddb_machine_restart(char *command) +{ + u32 t; + + /* PCI cold reset */ + t = nile4_in32(NILE4_PCICTRL + 4); + t |= 0x40000000; + nile4_out32(NILE4_PCICTRL + 4, t); + /* CPU cold reset */ + t = nile4_in32(NILE4_CPUSTAT); + t |= 1; + nile4_out32(NILE4_CPUSTAT, t); + /* Call the PROM */ + back_to_prom(); +} + +static void ddb_machine_halt(void) +{ + printk("DDB Vrc-5476 halted.\n"); + while (1); +} + +static void ddb_machine_power_off(void) +{ + printk("DDB Vrc-5476 halted. Please turn off the power.\n"); + while (1); +} + +extern void ddb_irq_setup(void); + +void (*board_time_init) (struct irqaction * irq); + + +static void __init ddb_time_init(struct irqaction *irq) +{ + /* set the clock to 1 Hz */ + nile4_out32(NILE4_T2CTRL, 1000000); + /* enable the General-Purpose Timer */ + nile4_out32(NILE4_T2CTRL + 4, 0x00000001); + /* reset timer */ + nile4_out32(NILE4_T2CNTR, 0); + /* enable interrupt */ + nile4_enable_irq(NILE4_INT_GPT); + i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); +} + +static struct { + struct resource dma1; + struct resource pic1; + struct resource timer; + struct resource rtc; + struct resource dma_page_reg; + struct resource pic2; + struct resource dma2; +} ddb5476_ioport = { + { + "dma1", 0x00, 0x1f, IORESOURCE_BUSY}, { + "pic1", 0x20, 0x3f, IORESOURCE_BUSY}, { + "timer", 0x40, 0x5f, IORESOURCE_BUSY}, { + "rtc", 0x70, 0x7f, IORESOURCE_BUSY}, { + "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY}, { + "pic2", 0xa0, 0xbf, IORESOURCE_BUSY}, { + "dma2", 0xc0, 0xdf, IORESOURCE_BUSY} +}; + +static struct { + struct resource nile4; +} ddb5476_iomem = { + { "Nile 4", NILE4_BASE, NILE4_BASE + NILE4_SIZE - 1, IORESOURCE_BUSY} +}; + +void __init ddb_setup(void) +{ + extern int panic_timeout; + + irq_setup = ddb_irq_setup; + mips_io_port_base = NILE4_PCI_IO_BASE; + isa_slot_offset = NILE4_PCI_MEM_BASE; + board_time_init = ddb_time_init; + + _machine_restart = ddb_machine_restart; + _machine_halt = ddb_machine_halt; + _machine_power_off = ddb_machine_power_off; + + /* request io port/mem resources */ + if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) || + request_resource(&ioport_resource, &ddb5476_ioport.pic1) || + request_resource(&ioport_resource, &ddb5476_ioport.timer) || + request_resource(&ioport_resource, &ddb5476_ioport.rtc) || + request_resource(&ioport_resource, + &ddb5476_ioport.dma_page_reg) + || request_resource(&ioport_resource, &ddb5476_ioport.pic2) + || request_resource(&ioport_resource, &ddb5476_ioport.dma2) + || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) { + printk + ("ddb_setup - requesting oo port resources failed.\n"); + for (;;); + } +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif + rtc_ops = &ddb_rtc_ops; + +#ifdef CONFIG_PC_KEYB + kbd_ops = &std_kbd_ops; +#endif + + /* Reboot on panic */ + panic_timeout = 180; + + /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ + /* *(long*)0xbfa00218 = 0x8; */ + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + + /* board initialization stuff - non-fundamental, but need to be set + * before kernel runs */ + + /* setup I/O space */ + nile4_set_pdar(NILE4_PCIW0, + PHYSADDR(NILE4_PCI_IO_BASE), 0x02000000, 32, 0, 0); + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + + /* map config space to 0xa8000000, 128MB */ + nile4_set_pdar(NILE4_PCIW1, + PHYSADDR(NILE4_PCI_CFG_BASE), 0x08000000, 32, 0, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, 0x0); + + /* ----- M1543 PCI setup ------ */ + + /* we know M1543 PCI-ISA controller is at addr:18 */ + /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */ + *(volatile unsigned char *) 0xa8040072 &= 0xf0; + *(volatile unsigned char *) 0xa8040072 |= 0xa; + + /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001) + * no IOCHRDY signal, (bit 7 - 1) + * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1) + * Bypass USB Master INTAJ level to edge conversion (bit 4 - 0) + */ + *(unsigned char *) 0xa8040074 = 0xc1; + + /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011) + * SCI routing to IRQ 13 disabled (bit 7 - 1) + * SCI interrupt level to edge conversion bypassed (bit 4 - 0) + */ + *(unsigned char *) 0xa8040076 = 0x83; + + /* setup IDE controller + * enable IDE controller (bit 6 - 1) + * IDE IDSEL to be addr:24 (bit 4:5 - 11) + * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0) + * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0) + * primary IRQ is 14, secondary is 15 (bit 1:0 - 01 + */ + // *(unsigned char*)0xa8040058 = 0x71; + // *(unsigned char*)0xa8040058 = 0x79; + // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state + *(unsigned char *) 0xa8040058 = 0x75; // primary tri-state + +#if 0 + /* this is not necessary if M5229 does not use SIRQ */ + *(unsigned char *) 0xa8040044 = 0x0d; // primary to IRQ 14 + *(unsigned char *) 0xa8040075 = 0x0d; // secondary to IRQ 14 +#endif + + /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */ + /* M5229 IDSEL is addr:24; see above setting */ + *(unsigned char *) 0xa9000050 |= 0x1; + + /* enable bus master (bit 2) and IO decoding (bit 0) */ + *(unsigned char *) 0xa9000004 |= 0x5; + + /* enable native, copied from arch/ppc/k2boot/head.S */ + /* TODO - need volatile, need to be portable */ + *(unsigned char *) 0xa9000009 = 0xff; + + /* ----- end of M1543 PCI setup ------ */ + + /* ----- reset on-board ether chip ------ */ + *((volatile u32 *) 0xa8020004) |= 1; /* decode I/O */ + *((volatile u32 *) 0xa8020010) = 0; /* set BAR address */ + + /* send reset command */ + *((volatile u32 *) 0xa6000000) = 1; /* do a soft reset */ + + /* disable ether chip */ + *((volatile u32 *) 0xa8020004) = 0; /* disable any decoding */ + + /* put it into sleep */ + *((volatile u32 *) 0xa8020040) = 0x80000000; + + /* ----- end of reset on-board ether chip ------ */ + + /* ----- set pci window 1 to pci memory space -------- */ + nile4_set_pdar(NILE4_PCIW1, + PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 32, 0, 0); + // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); + +} + +#define USE_NILE4_SERIAL 0 + +#if USE_NILE4_SERIAL +#define ns16550_in(reg) nile4_in8((reg)*8) +#define ns16550_out(reg, val) nile4_out8((reg)*8, (val)) +#else +#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8) +static inline u8 ns16550_in(u32 reg) +{ + return *(volatile u8 *) (NS16550_BASE + reg); +} + +static inline void ns16550_out(u32 reg, u8 val) +{ + *(volatile u8 *) (NS16550_BASE + reg) = val; +} +#endif + +#define NS16550_RBR 0 +#define NS16550_THR 0 +#define NS16550_DLL 0 +#define NS16550_IER 1 +#define NS16550_DLM 1 +#define NS16550_FCR 2 +#define NS16550_IIR 2 +#define NS16550_LCR 3 +#define NS16550_MCR 4 +#define NS16550_LSR 5 +#define NS16550_MSR 6 +#define NS16550_SCR 7 + +#define NS16550_LSR_DR 0x01 /* Data ready */ +#define NS16550_LSR_OE 0x02 /* Overrun */ +#define NS16550_LSR_PE 0x04 /* Parity error */ +#define NS16550_LSR_FE 0x08 /* Framing error */ +#define NS16550_LSR_BI 0x10 /* Break */ +#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */ +#define NS16550_LSR_TEMT 0x40 /* Xmitter empty */ +#define NS16550_LSR_ERR 0x80 /* Error */ + + +void _serinit(void) +{ +#if USE_NILE4_SERIAL + ns16550_out(NS16550_LCR, 0x80); + ns16550_out(NS16550_DLM, 0x00); + ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ + ns16550_out(NS16550_LCR, 0x00); + ns16550_out(NS16550_LCR, 0x03); + ns16550_out(NS16550_FCR, 0x47); +#else + /* done by PMON */ +#endif +} + +void _putc(char c) +{ + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, c); + if (c == '\n') { + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, '\r'); + } +} + +void _puts(const char *s) +{ + char c; + + while ((c = *s++)) + _putc(c); +} + +char _getc(void) +{ + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); + + return ns16550_in(NS16550_RBR); +} + +int _testc(void) +{ + return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; +} + + +/* + * Hexadecimal 7-segment LED + */ +void ddb5476_led_hex(int hex) +{ + outb(hex, 0x80); +} + + +/* + * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 + */ +struct pci_dev *pci_pmu = NULL; + +void ddb5476_led_d2(int on) +{ + u8 t; + + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0x7f; + else + t |= 0x80; + pci_write_config_byte(pci_pmu, 0x7e, t); + } +} + +void ddb5476_led_d3(int on) +{ + u8 t; + + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0xbf; + else + t |= 0x40; + pci_write_config_byte(pci_pmu, 0x7e, t); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ddb5476/time.c linux.ac/arch/mips/ddb5476/time.c --- linux.vanilla/arch/mips/ddb5476/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ddb5476/time.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,32 @@ +/* + * arch/mips/ddb5074/time.c -- Timer routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include + +#include + +static unsigned char ddb_rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void ddb_rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +static int ddb_rtc_bcd_mode(void) +{ + return 1; +} + +struct rtc_ops ddb_rtc_ops = { + ddb_rtc_read_data, + ddb_rtc_write_data, + ddb_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/dec/Makefile linux.ac/arch/mips/dec/Makefile --- linux.vanilla/arch/mips/dec/Makefile Fri Feb 25 06:52:30 2000 +++ linux.ac/arch/mips/dec/Makefile Wed Apr 18 13:50:31 2001 @@ -7,30 +7,20 @@ # .S.s: - $(CPP) $(CFLAGS) $< -o $*.s + $(CPP) $(AFLAGS) $< -o $@ .S.o: - $(CC) $(CFLAGS) -c $< -o $*.o + $(CC) $(AFLAGS) -c $< -o $@ -all: dec.o O_TARGET := dec.o -O_OBJS := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o -ifdef CONFIG_PROM_CONSOLE -O_OBJS += promcon.o -endif +all: dec.o -ifdef CONFIG_SERIAL -O_OBJS += serial.o -endif +export-objs := wbflush.o +obj-y := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o -ifeq ($(CONFIG_MODULES),y) - OX_OBJS = wbflush.o -else - O_OBJS += wbflush.o -endif +obj-$(CONFIG_PROM_CONSOLE) += promcon.o +obj-$(CONFIG_SERIAL) += serial.o int-handler.o: int-handler.S - -clean: include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/dec/boot/Makefile linux.ac/arch/mips/dec/boot/Makefile --- linux.vanilla/arch/mips/dec/boot/Makefile Sat Jun 26 01:40:12 1999 +++ linux.ac/arch/mips/dec/boot/Makefile Wed Apr 18 13:50:31 2001 @@ -18,7 +18,8 @@ all: dec_boot.o O_TARGET := dec_boot.o -O_OBJS := decstation.o + +obj-y := decstation.o clean: rm -f nbImage diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig linux.ac/arch/mips/defconfig --- linux.vanilla/arch/mips/defconfig Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/mips/defconfig Wed Apr 18 13:50:31 2001 @@ -16,16 +16,17 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set CONFIG_SGI_IP22=y # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_PC_KEYB=y CONFIG_SGI=y # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -84,17 +85,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -111,10 +118,8 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -131,6 +136,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -152,6 +158,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 @@ -192,14 +199,14 @@ # 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_SIM710 is not set # CONFIG_SCSI_NCR53C7xx 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_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_DEBUG is not set @@ -229,6 +236,8 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -283,8 +292,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -299,11 +306,13 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -334,6 +343,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-cobalt linux.ac/arch/mips/defconfig-cobalt --- linux.vanilla/arch/mips/defconfig-cobalt Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-cobalt Wed Apr 18 13:50:31 2001 @@ -17,18 +17,18 @@ CONFIG_COBALT_28=y # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set -# CONFIG_ISA is not set CONFIG_COBALT_27=y CONFIG_COBALT_LCD=y CONFIG_COBALT_SERIAL=y CONFIG_PCI=y # CONFIG_ISA is not set +# CONFIG_EISA is not set # # Loadable module support @@ -85,22 +85,26 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_BOOT is not set -# CONFIG_AUTODETECT_RAID is not set CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_INITRD is not set # +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_LVM is not set + +# # Networking options # # CONFIG_PACKET is not set @@ -112,13 +116,11 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set CONFIG_IP_MROUTE=y # CONFIG_IP_PIMSM_V1 is not set # CONFIG_IP_PIMSM_V2 is not set -CONFIG_IP_ALIAS=y # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -130,13 +132,13 @@ # CONFIG_IPX=m # CONFIG_IPX_INTERN is not set -# CONFIG_SPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -171,6 +173,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 @@ -194,15 +197,14 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -# CONFIG_AIC7XXX_PROC_STATS is not set CONFIG_AIC7XXX_RESET_DELAY=5 # 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_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA is not set @@ -214,8 +216,6 @@ # 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_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set CONFIG_SCSI_NCR53C8XX=y # CONFIG_SCSI_SYM53C8XX is not set @@ -233,6 +233,8 @@ # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set @@ -265,6 +267,7 @@ CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -277,6 +280,7 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -284,8 +288,9 @@ # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -326,6 +331,7 @@ CONFIG_ISDN_PPP=y CONFIG_ISDN_PPP_VJ=y CONFIG_ISDN_MPP=y +# CONFIG_ISDN_PPP_BSDCOMP is not set CONFIG_ISDN_AUDIO=y # CONFIG_ISDN_TTY_FAX is not set @@ -353,6 +359,7 @@ # CONFIG_HISAX_NO_LLC is not set # CONFIG_HISAX_NO_KEYPAD is not set CONFIG_HISAX_1TR6=y +# CONFIG_HISAX_NI1 is not set # # HiSax supported cards @@ -374,6 +381,7 @@ # CONFIG_HISAX_SPORTSTER is not set # CONFIG_HISAX_MIC is not set # CONFIG_HISAX_NETJET is not set +# CONFIG_HISAX_NETJET_U is not set # CONFIG_HISAX_NICCY is not set # CONFIG_HISAX_ISURF is not set # CONFIG_HISAX_HSTSAPHIR is not set @@ -383,6 +391,7 @@ # CONFIG_HISAX_HFC_PCI is not set # CONFIG_HISAX_W6692 is not set # CONFIG_HISAX_HFC_SX is not set +# CONFIG_HISAX_SEDLBAUER_CS is not set # # Active ISDN cards @@ -393,8 +402,8 @@ # CONFIG_ISDN_DRV_ACT2000 is not set # CONFIG_ISDN_DRV_EICON is not set # CONFIG_ISDN_CAPI is not set -# CONFIG_ISDN_CAPI_MIDDLEWARE is not set # CONFIG_HYSDN is not set +# CONFIG_HYSDN_CAPI is not set # # Old CD-ROM drivers (not SCSI, not IDE) @@ -425,6 +434,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -434,11 +447,6 @@ # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set CONFIG_RTC=y - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -447,8 +455,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -456,6 +469,8 @@ CONFIG_QUOTA=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -503,6 +518,7 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set @@ -510,8 +526,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -520,6 +534,7 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y CONFIG_NLS=y # @@ -569,6 +584,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-ddb5476 linux.ac/arch/mips/defconfig-ddb5476 --- linux.vanilla/arch/mips/defconfig-ddb5476 Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/defconfig-ddb5476 Wed Apr 18 13:50:31 2001 @@ -0,0 +1,541 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +# CONFIG_SMP is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +CONFIG_DDB5476=y +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_I8259=y +CONFIG_ISA=y +CONFIG_PCI=y +CONFIG_PC_KEYB=y +CONFIG_ROTTEN_IRQ=y +CONFIG_EISA=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R3912 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +CONFIG_CPU_R5432=y +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_MIPS_FPU_EMULATOR=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_PCI_NAMES is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PCMCIA is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD7409 is not set +# CONFIG_AMD7409_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_BLK_DEV_OSB4 is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_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 +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PM is not set +# CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +CONFIG_NE2K_PCI=y +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS 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_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_LL_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-decstation linux.ac/arch/mips/defconfig-decstation --- linux.vanilla/arch/mips/defconfig-decstation Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-decstation Wed Apr 18 13:50:31 2001 @@ -16,13 +16,14 @@ # CONFIG_COBALT_MICRO_SERVER is not set CONFIG_DECSTATION=y # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -80,17 +81,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -107,10 +114,8 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -127,6 +132,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -148,6 +154,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -170,6 +177,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -186,14 +194,14 @@ # 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_SIM710 is not set # CONFIG_SCSI_NCR53C7xx 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_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_DEBUG is not set @@ -224,6 +232,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -278,8 +288,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -294,17 +302,24 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set CONFIG_ULTRIX_PARTITION=y # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-ip22 linux.ac/arch/mips/defconfig-ip22 --- linux.vanilla/arch/mips/defconfig-ip22 Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-ip22 Wed Apr 18 13:50:31 2001 @@ -16,16 +16,17 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set CONFIG_SGI_IP22=y # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_PC_KEYB=y CONFIG_SGI=y # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -84,17 +85,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -111,10 +118,8 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -131,6 +136,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -152,6 +158,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 @@ -175,6 +182,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -191,14 +199,14 @@ # 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_SIM710 is not set # CONFIG_SCSI_NCR53C7xx 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_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_DEBUG is not set @@ -228,6 +236,8 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -282,8 +292,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -298,11 +306,13 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -333,6 +343,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-it8172 linux.ac/arch/mips/defconfig-it8172 --- linux.vanilla/arch/mips/defconfig-it8172 Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/defconfig-it8172 Wed Apr 18 13:50:31 2001 @@ -0,0 +1,569 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +# CONFIG_SMP is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +CONFIG_MIPS_ITE8172=y +# CONFIG_IT8172_REVC is not set +CONFIG_QTRONIX_KEYBOARD=y +CONFIG_IT8172_CIR=y +# CONFIG_IT8172_SCR0 is not set +# CONFIG_IT8172_SCR1 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_PCI=y +CONFIG_IT8712=y +CONFIG_PC_KEYB=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_I8259 is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R3912 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +CONFIG_CPU_NEVADA=y +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_MIPS_FPU_EMULATOR=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# CONFIG_PCMCIA is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# RAM/ROM Device Drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_MTDRAM is not set + +# +# Linearly Mapped Flash Device Drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_JEDEC is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=8000000 +CONFIG_MTD_PHYSMAP_LEN=2000000 +CONFIG_MTD_PHYSMAP_BUSWIDTH=4 + +# +# Drivers for chip mappings +# +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_VMAX is not set + +# +# User modules and translation layers for MTD devices +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLOCK is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +# CONFIG_UNIX is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD7409 is not set +# CONFIG_AMD7409_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_IT8172=y +CONFIG_IT8172_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_BLK_DEV_OSB4 is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_IDE_CHIPSETS=y + +# +# Note: most of these also require special kernel boot parameters +# +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_PDC4030 is not set +# CONFIG_BLK_DEV_QD6580 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_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 +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PM is not set +# CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139TOO=y +# CONFIG_RTL8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS 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_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_MIPS_FPE_MODULE is not set +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_LL_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-orion linux.ac/arch/mips/defconfig-orion --- linux.vanilla/arch/mips/defconfig-orion Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-orion Wed Apr 18 13:50:31 2001 @@ -16,13 +16,14 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -CONFIG_ORION=y # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set # CONFIG_ISA is not set +# CONFIG_EISA is not set # CONFIG_PCI is not set # @@ -79,18 +80,24 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -113,6 +120,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET_AUNUDP is not set # CONFIG_ECONET_NATIVE is not set # CONFIG_WAN_ROUTER is not set @@ -180,6 +188,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -189,11 +201,6 @@ # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -202,8 +209,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -211,6 +223,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -265,6 +279,7 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -276,6 +291,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/defconfig-rm200 linux.ac/arch/mips/defconfig-rm200 --- linux.vanilla/arch/mips/defconfig-rm200 Fri Jul 28 02:36:54 2000 +++ linux.ac/arch/mips/defconfig-rm200 Wed Apr 18 13:50:31 2001 @@ -16,16 +16,17 @@ # CONFIG_COBALT_MICRO_SERVER is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_ORION is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set CONFIG_SNI_RM200_PCI=y +# CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_PCI=y CONFIG_ISA=y CONFIG_PC_KEYB=y +CONFIG_EISA=y # # Loadable module support @@ -88,17 +89,23 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -113,10 +120,8 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -133,6 +138,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -211,6 +217,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -220,11 +230,6 @@ # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set CONFIG_RTC=y - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -233,8 +238,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -242,6 +252,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -296,8 +308,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -312,11 +322,13 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -339,6 +351,11 @@ # USB support # # CONFIG_USB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/Makefile linux.ac/arch/mips/ite-boards/generic/Makefile --- linux.vanilla/arch/mips/ite-boards/generic/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/Makefile Wed Apr 18 13:50:31 2001 @@ -0,0 +1,36 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or support@mvista.com +# +# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files. +# +# 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.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: it8172.o + +O_TARGET := it8172.o + +obj-y := it8172_rtc.o it8172_setup.o irq.o int-handler.o pmon_prom.o time.o lpc.o puts.o reset.o + +ifdef CONFIG_PCI +obj-y += it8172_pci.o +endif + +ifdef CONFIG_IT8172_CIR +obj-y += it8172_cir.o +endif + +ifdef CONFIG_REMOTE_DEBUG + obj-y += dbg_io.o +endif + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/dbg_io.c linux.ac/arch/mips/ite-boards/generic/dbg_io.c --- linux.vanilla/arch/mips/ite-boards/generic/dbg_io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/dbg_io.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,127 @@ + +#include + +#ifdef CONFIG_REMOTE_DEBUG + +/* --- CONFIG --- */ + +/* we need uint32 uint8 */ +/* #include "types.h" */ +typedef unsigned char uint8; +typedef unsigned int uint32; + +/* --- END OF CONFIG --- */ + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* ----------------------------------------------------- */ + +/* === CONFIG === */ + +/* [stevel] we use the IT8712 serial port for kgdb */ +#define DEBUG_BASE 0xB40003F8 /* 8712 serial port 1 base address */ +#define MAX_BAUD 115200 + +/* === END OF CONFIG === */ + +/* register offset */ +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 +#define OFS_INTR_ENABLE 1 +#define OFS_INTR_ID 2 +#define OFS_DATA_FORMAT 3 +#define OFS_LINE_CONTROL 3 +#define OFS_MODEM_CONTROL 4 +#define OFS_RS232_OUTPUT 4 +#define OFS_LINE_STATUS 5 +#define OFS_MODEM_STATUS 6 +#define OFS_RS232_INPUT 6 +#define OFS_SCRATCH_PAD 7 + +#define OFS_DIVISOR_LSB 0 +#define OFS_DIVISOR_MSB 1 + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint8*)(DEBUG_BASE + y))) +#define UART16550_WRITE(y,z) ((*((volatile uint8*)(DEBUG_BASE + y))) = z) + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + +static int remoteDebugInitialized = 0; + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_115200, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +int putDebugChar(uint8 byte) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_115200, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/int-handler.S linux.ac/arch/mips/ite-boards/generic/int-handler.S --- linux.vanilla/arch/mips/ite-boards/generic/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/int-handler.S Wed Apr 18 13:50:31 2001 @@ -0,0 +1,61 @@ +#include +#include +#include +#include + + .text + .set macro + .set noat + .align 5 + +NESTED(it8172_IRQ, PT_SIZE, sp) + SAVE_ALL + CLI # Important: mark KERNEL mode ! + + /* We're working with 'reorder' set at this point. */ + /* + * Get pending interrupts + */ + + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t1,CP0_STATUS # get enabled interrupts + and t0,t1 # isolate allowed ones + + andi t0,0xff00 # isolate pending bits + beqz t0, 3f # spurious interrupt + + andi a0, t0, CAUSEF_IP7 + beq a0, zero, 1f + move a0, sp + jal mips_timer_interrupt + j ret_from_irq + nop + +1: + andi a0, t0, CAUSEF_IP2 # the only int we expect at this time + beq a0, zero, 3f + move a0,sp + jal it8172_hw0_irqdispatch + + mfc0 t0,CP0_STATUS # disable interrupts + ori t0,1 + xori t0,1 + mtc0 t0,CP0_STATUS + nop + nop + nop + + la a1, ret_from_irq + jr a1 + nop + +3: + move a0, sp + jal mips_spurious_interrupt + nop + la a1, ret_from_irq + jr a1 + nop + +END(it8172_IRQ) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/irq.c linux.ac/arch/mips/ite-boards/generic/irq.c --- linux.vanilla/arch/mips/ite-boards/generic/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/irq.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,540 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE 8172G interrupt/setup routines. + * + * Copyright 2000,2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * Part of this file was derived from Carsten Langgaard's + * arch/mips/mips-boards/atlas/atlas_int.c. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG_IRQ +#ifdef DEBUG_IRQ +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef CONFIG_REMOTE_DEBUG +extern void breakpoint(void); +#endif + +/* revisit */ +#define EXT_IRQ0_TO_IP 2 /* IP 2 */ +#define EXT_IRQ5_TO_IP 7 /* IP 7 */ + +extern void set_debug_traps(void); +extern void mips_timer_interrupt(int irq, struct pt_regs *regs); +extern asmlinkage void it8172_IRQ(void); +irq_cpustat_t irq_stat [NR_CPUS]; +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +unsigned long spurious_count = 0; +irq_desc_t irq_desc[NR_IRQS]; +irq_desc_t *irq_desc_base=&irq_desc[0]; + +struct it8172_intc_regs volatile *it8172_hw0_icregs + = (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE)); + +/* Function for careful CP0 interrupt mask access */ +static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) +{ + unsigned long status = read_32bit_cp0_register(CP0_STATUS); + status &= ~((clr_mask & 0xFF) << 8); + status |= (set_mask & 0xFF) << 8; + write_32bit_cp0_register(CP0_STATUS, status); +} + +static inline void mask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(irq_nr, 0); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(0, irq_nr); +} + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + mask_irq(irq_nr); + restore_flags(flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + unmask_irq(irq_nr); + restore_flags(flags); +} + + +void disable_it8172_irq(unsigned int irq_nr) +{ + unsigned short mask; + + DPRINTK("disable_it8172_irq %d\n", irq_nr); + + if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { + /* LPC interrupt */ + DPRINTK("disable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + it8172_hw0_icregs->lpc_mask |= (1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + DPRINTK("disable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + } + else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { + /* Local Bus interrupt */ + DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask); + it8172_hw0_icregs->lb_mask |= (1 << (irq_nr - IT8172_LB_IRQ_BASE)); + DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask); + } + else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { + /* PCI and other interrupts */ + DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask); + it8172_hw0_icregs->pci_mask |= (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask); + } + else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { + /* NMI interrupts */ + DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + it8172_hw0_icregs->nmi_mask |= (1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + } + else { + panic("disable_it8172_irq: bad irq %d\n", irq_nr); + } +} + + +void enable_it8172_irq(unsigned int irq_nr) +{ + DPRINTK("enable_it8172_irq %d\n", irq_nr); + if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { + /* LPC interrupt */ + DPRINTK("enable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + it8172_hw0_icregs->lpc_mask &= ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + DPRINTK("enable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + } + else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { + /* Local Bus interrupt */ + DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask); + it8172_hw0_icregs->lb_mask &= ~(1 << (irq_nr - IT8172_LB_IRQ_BASE)); + DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask); + } + else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { + /* PCI and other interrupts */ + DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask); + it8172_hw0_icregs->pci_mask &= ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask); + } + else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { + /* NMI interrupts */ + DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + it8172_hw0_icregs->nmi_mask &= ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + } + else { + panic("enable_it8172_irq: bad irq %d\n", irq_nr); + } +} + +static unsigned int startup_ite_irq(unsigned int irq) +{ + enable_it8172_irq(irq); + return 0; +} + +#define shutdown_ite_irq disable_it8172_irq +#define mask_and_ack_ite_irq disable_it8172_irq + +static void end_ite_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_it8172_irq(irq); +} + +static struct hw_interrupt_type it8172_irq_type = { + "ITE8172", + startup_ite_irq, + shutdown_ite_irq, + enable_it8172_irq, + disable_it8172_irq, + mask_and_ack_ite_irq, + end_ite_irq, + NULL +}; + + +int get_irq_list(char *buf) +{ + int i, len = 0, j; + struct irqaction * action; + + len += sprintf(buf+len, " "); + for (j=0; jhandler ) + continue; + len += sprintf(buf+len, "%3d: ", i); + len += sprintf(buf+len, "%10u ", kstat_irqs(i)); + if ( irq_desc[i].handler ) + len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); + else + len += sprintf(buf+len, " None "); + len += sprintf(buf+len, " %s",action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ", %s", action->name); + } + len += sprintf(buf+len, "\n"); + } + len += sprintf(buf+len, "BAD: %10lu\n", spurious_count); + return len; +} + +asmlinkage void do_IRQ(int irq, struct pt_regs *regs) +{ + struct irqaction *action; + int cpu; + + cpu = smp_processor_id(); + irq_enter(cpu, irq); + + kstat.irqs[cpu][irq]++; +#if 0 + if (irq_desc[irq].handler && irq_desc[irq].handler->ack) { + // printk("invoking ack handler\n"); + irq_desc[irq].handler->ack(irq); + } +#endif + + action = irq_desc[irq].action; + + if (action && action->handler) + { + //mask_irq(1<handler %x\n", action->handler); + disable_it8172_irq(irq); + //if (!(action->flags & SA_INTERRUPT)) __sti(); /* reenable ints */ + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while ( action ); + //__cli(); /* disable ints */ + if (irq_desc[irq].handler) + { + } + //unmask_irq(1<cp0_cause); + disable_it8172_irq(irq); + //disable_irq(1<= NR_IRQS) + return -EINVAL; + + if (!handler) + { + /* Free */ + for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) + { + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + disable_it8172_irq(irq); + //disable_irq(1<handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->dev_id = dev_id; + action->next = NULL; + + p = &irq_desc[irq].action; + + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & action->flags & SA_SHIRQ)) + return -EBUSY; + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + } + *p = action; + enable_it8172_irq(irq); + restore_flags(flags); +#if 0 + printk("request_irq: status %x cause %x\n", + read_32bit_cp0_register(CP0_STATUS), read_32bit_cp0_register(CP0_CAUSE)); +#endif + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + request_irq(irq, NULL, 0, NULL, dev_id); +} + +void enable_cpu_timer(void) +{ + enable_irq(1<lb_mask = 0xffff; + it8172_hw0_icregs->lpc_mask = 0xffff; + it8172_hw0_icregs->pci_mask = 0xffff; + it8172_hw0_icregs->nmi_mask = 0xffff; + + /* make all interrupts level triggered */ + it8172_hw0_icregs->lb_trigger = 0; + it8172_hw0_icregs->lpc_trigger = 0; + it8172_hw0_icregs->pci_trigger = 0; + it8172_hw0_icregs->nmi_trigger = 0; + + /* active level setting */ + /* uart, keyboard, and mouse are active high */ + it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000); + it8172_hw0_icregs->lb_level |= 0x20; + + /* keyboard and mouse are edge triggered */ + it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000); + + +#if 0 + // Enable this piece of code to make internal USB interrupt + // edge triggered. + it8172_hw0_icregs->pci_trigger |= + (1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE)); + it8172_hw0_icregs->pci_level &= + ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE)); +#endif + + for (i = 0; i <= IT8172_INT_END; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &it8172_irq_type; + } + + /* + * Enable external int line 2 + * All ITE interrupts are masked for now. + */ + enable_irq(1<cp0_epc, regs->cp0_badvaddr); +// while(1); +#endif +} + +void it8172_hw0_irqdispatch(struct pt_regs *regs) +{ + int irq; + unsigned short intstatus, status; + + intstatus = it8172_hw0_icregs->intstatus; + if (intstatus & 0x8) { + panic("Got NMI interrupt\n"); + } + else if (intstatus & 0x4) { + /* PCI interrupt */ + irq = 0; + status = it8172_hw0_icregs->pci_req; + while (!(status & 0x1)) { + irq++; + status >>= 1; + } + irq += IT8172_PCI_DEV_IRQ_BASE; + //printk("pci int %d\n", irq); + } + else if (intstatus & 0x1) { + /* Local Bus interrupt */ + irq = 0; + status = it8172_hw0_icregs->lb_req; + while (!(status & 0x1)) { + irq++; + status >>= 1; + } + irq += IT8172_LB_IRQ_BASE; + //printk("lb int %d\n", irq); + } + else if (intstatus & 0x2) { + /* LPC interrupt */ + /* Since some lpc interrupts are edge triggered, + * we could lose an interrupt this way because + * we acknowledge all ints at onces. Revisit. + */ + status = it8172_hw0_icregs->lpc_req; + it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */ + irq = 0; + while (!(status & 0x1)) { + irq++; + status >>= 1; + } + irq += IT8172_LPC_IRQ_BASE; + //printk("LPC int %d\n", irq); + } + else { + return; + } + do_IRQ(irq, regs); +} + +void show_pending_irqs(void) +{ + fputs("intstatus: "); + put32(it8172_hw0_icregs->intstatus); + puts(""); + + fputs("pci_req: "); + put32(it8172_hw0_icregs->pci_req); + puts(""); + + fputs("lb_req: "); + put32(it8172_hw0_icregs->lb_req); + puts(""); + + fputs("lpc_req: "); + put32(it8172_hw0_icregs->lpc_req); + puts(""); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_cir.c linux.ac/arch/mips/ite-boards/generic/it8172_cir.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_cir.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_cir.c Wed Apr 18 13:50:31 2001 @@ -0,0 +1,171 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 Consumer IR port generic routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#ifdef CONFIG_IT8172_CIR + +#include +#include +#include +#include + +#include +#include + + +volatile struct it8172_cir_regs *cir_regs[NUM_CIR_PORTS] = { + (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR0_BASE)), + (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR1_BASE))}; + + +/* + * Initialize Consumer IR Port. + */ +int cir_port_init(struct cir_port *cir) +{ + int port = cir->port; + unsigned char data; + + /* set baud rate */ + cir_regs[port]->bdlr = cir->baud_rate & 0xff; + cir_regs[port]->bdhr = (cir->baud_rate >> 8) & 0xff; + + /* set receiver control register */ + cir_regs[port]->rcr = (CIR_SET_RDWOS(cir->rdwos) | CIR_SET_RXDCR(cir->rxdcr)); + + /* set carrier frequency register */ + cir_regs[port]->cfr = (CIR_SET_CF(cir->cfq) | CIR_SET_HS(cir->hcfs)); + + /* set fifo threshold */ + data = cir_regs[port]->mstcr & 0xf3; + data |= CIR_SET_FIFO_TL(cir->fifo_tl); + cir_regs[port]->mstcr = data; + + clear_fifo(cir); + enable_receiver(cir); + disable_rx_demodulation(cir); + + set_rx_active(cir); + int_enable(cir); + rx_int_enable(cir); + + return 0; +} + + +void clear_fifo(struct cir_port *cir) +{ + cir_regs[cir->port]->mstcr |= CIR_FIFO_CLEAR; +} + +void enable_receiver(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr |= CIR_RXEN; +} + +void disable_receiver(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr &= ~CIR_RXEN; +} + +void enable_rx_demodulation(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr |= CIR_RXEND; +} + +void disable_rx_demodulation(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr &= ~CIR_RXEND; +} + +void set_rx_active(struct cir_port *cir) +{ + cir_regs[cir->port]->rcr |= CIR_RXACT; +} + +void int_enable(struct cir_port *cir) +{ + cir_regs[cir->port]->ier |= CIR_IEC; +} + +void rx_int_enable(struct cir_port *cir) +{ + cir_regs[cir->port]->ier |= CIR_RDAIE; +} + +void dump_regs(struct cir_port *cir) +{ + printk("mstcr %x ier %x iir %x cfr %x rcr %x tcr %x tfsr %x rfsr %x\n", + cir_regs[cir->port]->mstcr, + cir_regs[cir->port]->ier, + cir_regs[cir->port]->iir, + cir_regs[cir->port]->cfr, + cir_regs[cir->port]->rcr, + cir_regs[cir->port]->tcr, + cir_regs[cir->port]->tfsr, + cir_regs[cir->port]->rfsr); + + while (cir_regs[cir->port]->iir & CIR_RDAI) { + printk("data %x\n", cir_regs[cir->port]->dr); + } +} + +void dump_reg_addr(struct cir_port *cir) +{ + printk("dr %x mstcr %x ier %x iir %x cfr %x rcr %x tcr %x bdlr %x bdhr %x tfsr %x rfsr %x\n", + (unsigned)&cir_regs[cir->port]->dr, + (unsigned)&cir_regs[cir->port]->mstcr, + (unsigned)&cir_regs[cir->port]->ier, + (unsigned)&cir_regs[cir->port]->iir, + (unsigned)&cir_regs[cir->port]->cfr, + (unsigned)&cir_regs[cir->port]->rcr, + (unsigned)&cir_regs[cir->port]->tcr, + (unsigned)&cir_regs[cir->port]->bdlr, + (unsigned)&cir_regs[cir->port]->bdhr, + (unsigned)&cir_regs[cir->port]->tfsr, + (unsigned)&cir_regs[cir->port]->rfsr); +} + +int cir_get_rx_count(struct cir_port *cir) +{ + return cir_regs[cir->port]->rfsr & CIR_RXFBC_MASK; +} + +char cir_read_data(struct cir_port *cir) +{ + return cir_regs[cir->port]->dr; +} + +char get_int_status(struct cir_port *cir) +{ + return cir_regs[cir->port]->iir; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_pci.c linux.ac/arch/mips/ite-boards/generic/it8172_pci.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_pci.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,276 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller specific pci support. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#undef DEBUG +#undef DEBUG_CONFIG_CYCLES + +static int +it8172_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, + unsigned char where, u32 *data) +{ + /* + * config cycles are on 4 byte boundary only + */ + unsigned char bus = dev->bus->number; + unsigned char dev_fn = dev->devfn; + +#ifdef DEBUG_CONFIG_CYCLES + printk("it config: type %d dev %x bus %d dev_fn %x data %x\n", + access_type, dev, bus, dev_fn, *data); + +#endif + + /* Setup address */ + IT_WRITE(IT_CONFADDR, (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | (where & ~0x3)); + + + if (access_type == PCI_ACCESS_WRITE) { + IT_WRITE(IT_CONFDATA, *data); + } + else { + IT_READ(IT_CONFDATA, *data); + } + + /* + * Revisit: check for master or target abort. + */ + return 0; + + +} + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int +it8172_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) +{ + u32 data = 0; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xff; +#ifdef DEBUG + printk("cfg read byte: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); +#endif + + return PCIBIOS_SUCCESSFUL; +} + + +static int +it8172_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xffff; +#ifdef DEBUG + printk("cfg read word: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); +#endif + + return PCIBIOS_SUCCESSFUL; +} + +static int +it8172_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) +{ + u32 data = 0; + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = data; +#ifdef DEBUG + printk("cfg read dword: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); +#endif + + return PCIBIOS_SUCCESSFUL; +} + + +static int +it8172_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int +it8172_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + +static int +it8172_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops it8172_pci_ops = { + it8172_pcibios_read_config_byte, + it8172_pcibios_read_config_word, + it8172_pcibios_read_config_dword, + it8172_pcibios_write_config_byte, + it8172_pcibios_write_config_word, + it8172_pcibios_write_config_dword +}; + +void __init pcibios_init(void) +{ + + printk("PCI: Probing PCI hardware on host bus 0.\n"); + pci_scan_bus(0, &it8172_pci_ops, NULL); +} + +int __init +pcibios_enable_device(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + + +void __init +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ + printk("pcibios_align_resource\n"); +} + +char * __init +pcibios_setup(char *str) +{ + /* Nothing to do for now. */ + + return str; +} + +void __init +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + unsigned long where, size; + u32 reg; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); +} + +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + printk("pcibios_fixup_bus\n"); +} +#endif /* CONFIG_PCI */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_rtc.c linux.ac/arch/mips/ite-boards/generic/it8172_rtc.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_rtc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_rtc.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,63 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * RTC routines for ITE8172 MC146818-compatible rtc chip. + * + */ +#include +#include +#include + +#define IT8172_RTC_ADR_REG (IT8172_PCI_IO_BASE + IT_RTC_BASE) +#define IT8172_RTC_DAT_REG (IT8172_RTC_ADR_REG + 1) + +static volatile char *rtc_adr_reg = KSEG1ADDR((volatile char *)IT8172_RTC_ADR_REG); +static volatile char *rtc_dat_reg = KSEG1ADDR((volatile char *)IT8172_RTC_DAT_REG); + +unsigned char it8172_rtc_read_data(unsigned long addr) +{ + unsigned char retval; + + *rtc_adr_reg = addr; + retval = *rtc_dat_reg; + return retval; +} + +void it8172_rtc_write_data(unsigned char data, unsigned long addr) +{ + *rtc_adr_reg = addr; + *rtc_dat_reg = data; +} + +static int it8172_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops it8172_rtc_ops = { + &it8172_rtc_read_data, + &it8172_rtc_write_data, + &it8172_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/it8172_setup.c linux.ac/arch/mips/ite-boards/generic/it8172_setup.c --- linux.vanilla/arch/mips/ite-boards/generic/it8172_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/it8172_setup.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,310 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172/QED5231 board setup. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PC_KEYB +#include +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +extern struct rtc_ops it8172_rtc_ops; +extern struct resource ioport_resource; +extern unsigned long mips_io_port_base; +#ifdef CONFIG_BLK_DEV_IDE +extern struct ide_ops std_ide_ops; +extern struct ide_ops *ide_ops; +#endif +#ifdef CONFIG_PC_KEYB +extern struct kbd_ops std_kbd_ops; +int init_8712_keyboard(void); +#endif + +extern int SearchIT8712(void); +extern void InitLPCInterface(void); +extern char * __init prom_getcmdline(void); +extern void it8172_restart(void); +extern void it8172_halt(void); +extern void it8172_power_off(void); + +#ifdef CONFIG_IT8172_REVC +struct { + struct resource ram; + struct resource pci_mem; + struct resource pci_io; + struct resource flash; + struct resource boot; +} it8172_resources = { + { "RAM", 0, 0, IORESOURCE_MEM }, /* to be initted */ + { "PCI Mem", 0x10000000, 0x13FFFFFF, IORESOURCE_MEM }, + { "PCI I/O", 0x14000000, 0x17FFFFFF }, + { "Flash", 0x08000000, 0x0CFFFFFF }, + { "Boot ROM", 0x1FC00000, 0x1FFFFFFF } +}; +#else +struct { + struct resource ram; + struct resource pci_mem0; + struct resource pci_mem1; + struct resource pci_io; + struct resource pci_mem2; + struct resource pci_mem3; + struct resource flash; + struct resource boot; +} it8172_resources = { + { "RAM", 0, 0, IORESOURCE_MEM }, /* to be initted */ + { "PCI Mem0", 0x0C000000, 0x0FFFFFFF, IORESOURCE_MEM }, + { "PCI Mem1", 0x10000000, 0x13FFFFFF, IORESOURCE_MEM }, + { "PCI I/O", 0x14000000, 0x17FFFFFF }, + { "PCI Mem2", 0x1A000000, 0x1BFFFFFF, IORESOURCE_MEM }, + { "PCI Mem3", 0x1C000000, 0x1FBFFFFF, IORESOURCE_MEM }, + { "Flash", 0x08000000, 0x0CFFFFFF }, + { "Boot ROM", 0x1FC00000, 0x1FFFFFFF } +}; +#endif + + +void __init it8172_init_ram_resource(unsigned long memsize) +{ + it8172_resources.ram.end = memsize; +} + +void __init it8172_setup(void) +{ +#ifdef CONFIG_BLK_DEV_IT8172 + unsigned short dsr; +#endif + char *argptr; + + argptr = prom_getcmdline(); +#ifdef CONFIG_SERIAL_CONSOLE + if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) { + strcpy(serial_console, "ttyS0,115200"); + console_setup(serial_console, NULL); + } +#endif + + rtc_ops = &it8172_rtc_ops; + + _machine_restart = it8172_restart; + _machine_halt = it8172_halt; + _machine_power_off = it8172_power_off; + + /* + * IO/MEM resources. + * + * revisit this area. + */ + mips_io_port_base = KSEG1; + ioport_resource.start = it8172_resources.pci_io.start; + ioport_resource.end = it8172_resources.pci_io.end; +#ifdef CONFIG_IT8172_REVC + iomem_resource.start = it8172_resources.pci_mem.start; + iomem_resource.end = it8172_resources.pci_mem.end; +#else + iomem_resource.start = it8172_resources.pci_mem0.start; + iomem_resource.end = it8172_resources.pci_mem3.end; +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); +#endif + +#ifdef CONFIG_BLK_DEV_IT8172 + /* + * Pull IDE device out of standby mode. + */ + IT_IO_READ16(IT_PM_DSR, dsr); + dsr &= ~IT_PM_DSR_IDESB; + IT_IO_WRITE16(IT_PM_DSR, dsr); + + ide_ops = &std_ide_ops; +#endif + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + InitLPCInterface(); + +#ifdef CONFIG_MIPS_ITE8172 + if (SearchIT8712()) { + printk("Found IT8712 Super IO\n"); + // enable IT8712 serial port + LPCSetConfig(LDN_SERIAL1, 0x30, 0x01); /* enable */ + LPCSetConfig(LDN_SERIAL1, 0x23, 0x01); /* clock selection */ +#ifdef CONFIG_PC_KEYB + if (init_8712_keyboard()) { + printk("Unable to initialize keyboard\n"); + LPCSetConfig(LDN_KEYBOARD, 0x30, 0x0); /* disable keyboard */ + } + else { + LPCSetConfig(LDN_KEYBOARD, 0x30, 0x1); /* enable keyboard */ + LPCSetConfig(LDN_KEYBOARD, 0xf0, 0x2); + LPCSetConfig(LDN_KEYBOARD, 0x71, 0x3); + + LPCSetConfig(LDN_MOUSE, 0x30, 0x1); /* enable mouse */ + + LPCSetConfig(0x4, 0x30, 0x1); + LPCSetConfig(0x4, 0xf4, LPCGetConfig(0x4, 0xf4) | 0x80); + + if ((LPCGetConfig(LDN_KEYBOARD, 0x30) == 0) || + (LPCGetConfig(LDN_MOUSE, 0x30) == 0)) + printk("Error: keyboard or mouse not enabled\n"); + + kbd_ops = &std_kbd_ops; + } +#endif + } + else { + printk("IT8712 Super IO not found\n"); + } +#endif + +#ifdef CONFIG_IT8172_CIR + { + unsigned long data; + //printk("Enabling CIR0\n"); + IT_IO_READ16(IT_PM_DSR, data); + data &= ~IT_PM_DSR_CIR0SB; + IT_IO_WRITE16(IT_PM_DSR, data); + //printk("DSR register: %x\n", (unsigned)IT_IO_READ16(IT_PM_DSR, data)); + } +#endif +#ifdef CONFIG_IT8172_SCR0 + { + unsigned i; + /* Enable Smart Card Reader 0 */ + /* First power it up */ + IT_IO_READ16(IT_PM_DSR, i); + i &= ~IT_PM_DSR_SCR0SB; + IT_IO_WRITE16(IT_PM_DSR, i); + /* Then initialize its registers */ + outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT + |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT + |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT + |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT + |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT), + IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SFR); + outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT, + IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SCDR); + } +#endif /* CONFIG_IT8172_SCR0 */ +#ifdef CONFIG_IT8172_SCR1 + { + unsigned i; + /* Enable Smart Card Reader 1 */ + /* First power it up */ + IT_IO_READ16(IT_PM_DSR, i); + i &= ~IT_PM_DSR_SCR1SB; + IT_IO_WRITE16(IT_PM_DSR, i); + /* Then initialize its registers */ + outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT + |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT + |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT + |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT + |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT), + IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SFR); + outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT, + IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SCDR); + } +#endif /* CONFIG_IT8172_SCR1 */ +} + + +#ifdef CONFIG_PC_KEYB +/* + * According to the ITE Special BIOS Note for waking up the + * keyboard controller... + */ +int init_8712_keyboard() +{ + unsigned int cmd_port = 0x14000064; + unsigned int data_port = 0x14000060; + unsigned char data; + int i; + + printk("8712 keyboard init"); + + outb(0xaa, cmd_port); /* send self-test cmd */ + i = 0; + while (!(inb(cmd_port) & 0x1)) { /* wait output buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + + data = inb(data_port); + outb(0xcb, cmd_port); /* set ps2 mode */ + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + outb(0x01, data_port); + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + + outb(0x60, cmd_port); /* write 8042 command byte */ + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + outb(0x45, data_port); /* at interface, keyboard enabled, system flag */ + while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ + i++; + if (i > 0xffffff) + return 1; + } + + outb(0xae, cmd_port); /* enable interface */ + return 0; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/lpc.c linux.ac/arch/mips/ite-boards/generic/lpc.c --- linux.vanilla/arch/mips/ite-boards/generic/lpc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/lpc.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,144 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE Semi IT8712 Super I/O functions. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +void LPCEnterMBPnP() +{ + int i; + unsigned char key[4] = {0x87, 0x01, 0x55, 0x55}; + + for (i = 0; i<4; i++) + outb(key[i], LPC_KEY_ADDR); + +} + +void LPCExitMBPnP() +{ + outb(0x02, LPC_KEY_ADDR); + outb(0x02, LPC_DATA_ADDR); +} + +void LPCSetConfig(char LdnNumber, char Index, char data) +{ + LPCEnterMBPnP(); // Enter IT8712 MB PnP mode + outb(0x07, LPC_KEY_ADDR); + outb(LdnNumber, LPC_DATA_ADDR); + outb(Index, LPC_KEY_ADDR); + outb(data, LPC_DATA_ADDR); + LPCExitMBPnP(); +} + +char LPCGetConfig(char LdnNumber, char Index) +{ + char rtn; + + LPCEnterMBPnP(); // Enter IT8712 MB PnP mode + outb(0x07, LPC_KEY_ADDR); + outb(LdnNumber, LPC_DATA_ADDR); + outb(Index, LPC_KEY_ADDR); + rtn = inb(LPC_DATA_ADDR); + LPCExitMBPnP(); + return rtn; +} + +int SearchIT8712() +{ + unsigned char Id1, Id2; + unsigned short Id; + + LPCEnterMBPnP(); + outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */ + Id1 = inb(LPC_DATA_ADDR); + outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */ + Id2 = inb(LPC_DATA_ADDR); + Id = (Id1 << 8) | Id2; + LPCExitMBPnP(); + if (Id == 0x8712) + return TRUE; + else + return FALSE; +} + +void InitLPCInterface() +{ + unsigned char bus, dev_fn; + unsigned long data; + + bus = 0; + dev_fn = 1<<3 | 4; + + + /* pci cmd, SERR# Enable */ + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x4 / 4) << IT_REGNUM_SHF)); + IT_READ(IT_CONFDATA, data); + data |= 0x0100; + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x4 / 4) << IT_REGNUM_SHF)); + IT_WRITE(IT_CONFDATA, data); + + /* setup serial irq control register */ + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x48 / 4) << IT_REGNUM_SHF)); + IT_READ(IT_CONFDATA, data); + data = (data & 0xffff00ff) | 0xc400; + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x48 / 4) << IT_REGNUM_SHF)); + IT_WRITE(IT_CONFDATA, data); + + + /* Enable I/O Space Subtractive Decode */ + /* default 0x4C is 0x3f220000 */ + IT_WRITE(IT_CONFADDR, + (bus << IT_BUSNUM_SHF) | + (dev_fn << IT_FUNCNUM_SHF) | + ((0x4C / 4) << IT_REGNUM_SHF)); + IT_WRITE(IT_CONFDATA, 0x3f2200f3); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/pmon_prom.c linux.ac/arch/mips/ite-boards/generic/pmon_prom.c --- linux.vanilla/arch/mips/ite-boards/generic/pmon_prom.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/pmon_prom.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,138 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PROM library initialisation code, assuming a version of + * pmon is the boot code. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/xx files. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include + +/* #define DEBUG_CMDLINE */ + +char arcs_cmdline[COMMAND_LINE_SIZE]; +int prom_argc; +char **prom_argv, **prom_envp; + +typedef struct +{ + char *name; +/* char *val; */ +}t_env_var; + + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; + +} + + +char *prom_getenv(char *envname) +{ + /* + * Return a pointer to the given environment variable. + * Environment variables are stored in the form of "memsize=64". + */ + + t_env_var *env = (t_env_var *)prom_envp; + int i; + + i = strlen(envname); + + while(env->name) { + if(strncmp(envname, env->name, i) == 0) { + return(env->name + strlen(envname) + 1); + } + env++; + } + return(NULL); +} + +static inline unsigned char str2hexnum(unsigned char c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; /* foo */ +} + +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + +void prom_free_prom_memory (void) +{ +} + +unsigned long __init prom_get_memsize(void) +{ + char *memsize_str; + unsigned int memsize; + + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + printk("memsize unknown: setting to 32MB\n"); + memsize = 32; + } else { +#ifdef DEBUG + printk("prom_memsize: %s\n", memsize_str); +#endif + memsize = simple_strtol(memsize_str, NULL, 0); + } + return memsize; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/puts.c linux.ac/arch/mips/ite-boards/generic/puts.c --- linux.vanilla/arch/mips/ite-boards/generic/puts.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/puts.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,144 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Low level uart routines to directly access a 16550 uart. + * + * Copyright 2000,2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#define SERIAL_BASE 0xB4011800 /* it8172 */ +#define SER_CMD 5 +#define SER_DATA 0x00 +#define TX_BUSY 0x20 + +#define TIMEOUT 0xffff +#undef SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; +static volatile unsigned char * const com1 = (unsigned char *)SERIAL_BASE; + + +#ifdef SLOW_DOWN +static inline void slow_down() +{ + int k; + for (k=0; k<10000; k++); +} +#else +#define slow_down() +#endif + +void +putch(const unsigned char c) +{ + unsigned char ch; + int i = 0; + + do { + ch = com1[SER_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SER_DATA] = c; +} + +void +puts(unsigned char *cp) +{ + unsigned char ch; + int i = 0; + + while (*cp) { + do { + ch = com1[SER_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SER_DATA] = *cp++; + } + putch('\r'); + putch('\n'); +} + +void +fputs(unsigned char *cp) +{ + unsigned char ch; + int i = 0; + + while (*cp) { + + do { + ch = com1[SER_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SER_DATA] = *cp++; + } +} + + +void +put64(uint64_t ul) +{ + int cnt; + unsigned ch; + + cnt = 16; /* 16 nibbles in a 64 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(ul >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} + +void +put32(unsigned u) +{ + int cnt; + unsigned ch; + + cnt = 8; /* 8 nibbles in a 32 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(u >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/reset.c linux.ac/arch/mips/ite-boards/generic/reset.c --- linux.vanilla/arch/mips/ite-boards/generic/reset.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/reset.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,61 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE 8172 reset routines. + * + * Copyright (C) 1997, 2001 Ralf Baechle + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +void it8172_restart(char *command) +{ + set_cp0_status(ST0_BEV | ST0_ERL); + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); +} + +void it8172_halt(void) +{ + printk(KERN_NOTICE "\n** You can safely turn off the power\n"); + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +void it8172_power_off(void) +{ + it8172_halt(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/generic/time.c linux.ac/arch/mips/ite-boards/generic/time.c --- linux.vanilla/arch/mips/ite-boards/generic/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/generic/time.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,378 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Setting up the clock on the MIPS boards. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +extern void enable_cpu_timer(void); +extern volatile unsigned long wall_jiffies; +extern rwlock_t xtime_lock; + +unsigned long missed_heart_beats = 0; +static long last_rtc_update = 0; +static unsigned long r4k_offset; /* Amount to increment compare reg each time */ +static unsigned long r4k_cur; /* What counter should be at next timer irq */ +static unsigned int timer_tick_count=0; + +static inline void ack_r4ktimer(unsigned long newval) +{ + write_32bit_cp0_register(CP0_COMPARE, newval); +} + + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + + +/* + * There are a lot of conceptually broken versions of the MIPS timer interrupt + * handler floating around. This one is rather different, but the algorithm + * is provably more robust. + */ +void mips_timer_interrupt(struct pt_regs *regs) +{ + if (r4k_offset == 0) + goto null; + + do { + kstat.irqs[0][MIPS_CPU_TIMER_IRQ]++; + do_timer(regs); + + /* Historical comment/code: + * RTC time of day s updated approx. every 11 + * minutes. Because of how the numbers work out + * we need to make absolutely sure we do this update + * within 500ms before the * next second starts, + * thus the following code. + */ + read_lock(&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 + && xtime.tv_sec > last_rtc_update + 660 + && xtime.tv_usec >= 500000 - (tick >> 1) + && xtime.tv_usec <= 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else { + /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; + } + read_unlock(&xtime_lock); + + r4k_cur += r4k_offset; + ack_r4ktimer(r4k_cur); + + } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) + - r4k_cur) < 0x7fffffff); + + return; + +null: + ack_r4ktimer(0); +} + +/* + * Figure out the r4k offset, the amount to increment the compare + * register for each time tick. + * Use the RTC to calculate offset. + */ +static unsigned long __init cal_r4koff(void) +{ + unsigned long count; + unsigned int flags; + + __save_and_cli(flags); + + /* Start counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + /* Start r4k counter. */ + write_32bit_cp0_register(CP0_COUNT, 0); + + /* Read counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + count = read_32bit_cp0_register(CP0_COUNT); + + /* restore interrupts */ + __restore_flags(flags); + + return (count / HZ); +} + +static unsigned long __init get_mips_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char save_control; + + save_control = CMOS_READ(RTC_CONTROL); + + /* Freeze it. */ + CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL); + + /* Read regs. */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + + if (!(save_control & RTC_24H)) + { + if ((hour & 0xf) == 0xc) + hour &= 0x80; + if (hour & 0x80) + hour = (hour & 0xf) + 12; + } + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + /* Unfreeze clock. */ + CMOS_WRITE(save_control, RTC_CONTROL); + + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +void __init time_init(void) +{ + unsigned int est_freq, flags; + + /* Set Data mode - binary. */ + CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); + + printk("calculating r4koff... "); + r4k_offset = cal_r4koff(); + printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + + est_freq = 2*r4k_offset*HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq%10000; + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); + + write_32bit_cp0_register(CP0_COMPARE, r4k_cur); + + enable_cpu_timer(); + + /* Read time from the RTC chipset. */ + write_lock_irqsave (&xtime_lock, flags); + xtime.tv_sec = get_mips_time(); + xtime.tv_usec = 0; + write_unlock_irqrestore(&xtime_lock, flags); +} + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +/* Cycle counter value at the previous timer interrupt.. */ + +static unsigned int timerhi = 0, timerlo = 0; + +/* + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_fast_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies=0; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient=0; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY) + :"$1"); + cached_quotient = quotient; + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned int flags; + + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_fast_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; + + read_unlock_irqrestore (&xtime_lock, flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq (&xtime_lock); + + /* This is revolting. We need to set the xtime.tv_usec correctly. + * However, the value in this location is is value at the last tick. + * Discover what correction gettimeofday would have done, and then + * undo it! + */ + tv->tv_usec -= do_fast_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + 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); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/Makefile linux.ac/arch/mips/ite-boards/qed-4n-s01b/Makefile --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/Makefile Wed Apr 18 13:50:54 2001 @@ -0,0 +1,37 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or support@mvista.com +# +# Makefile for the ITE 8172 (qed-4n-s01b) board, board +# specific files. +# +# 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.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: ite.o + +O_TARGET := ite.o + +obj-y := init.o + +ifdef CONFIG_PCI +obj-y += pci_fixup.o +endif + +ifdef CONFIG_BLK_DEV_INITRD +obj-y += le_ramdisk.o +endif + + +dep: + $(CPP) -M *.c > .depend + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/README linux.ac/arch/mips/ite-boards/qed-4n-s01b/README --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/README Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/README Wed Apr 18 13:50:54 2001 @@ -0,0 +1,2 @@ +This is an ITE (www.iteusa.com) eval board for the ITE 8172G +system controller, with a QED 5231 CPU. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/init.c linux.ac/arch/mips/ite-boards/qed-4n-s01b/init.c --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/init.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,87 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172/QED5231 board setup. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int prom_argc; +char **prom_argv, **prom_envp; + +extern char _end; +extern void __init prom_init_cmdline(void); +extern unsigned long __init prom_get_memsize(void); +extern void __init it8172_init_ram_resource(unsigned long memsize); + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + + +int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ + unsigned long mem_size, free_start, free_end, bootmap_size; + unsigned long pcicr; + + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + puts("ITE board running..."); + + mips_machgroup = MACH_GROUP_ITE; + mips_machtype = MACH_QED_4N_S01B; /* ITE board name/number */ + + prom_init_cmdline(); + mem_size = prom_get_memsize(); + + printk("Memory size: %dMB\n", (unsigned)mem_size); + + mem_size <<= 20; /* MB */ + + /* + * make the entire physical memory visible to pci bus masters + */ + IT_READ(IT_MC_PCICR, pcicr); + pcicr &= ~0x1f; + pcicr |= (mem_size - 1) >> 22; + IT_WRITE(IT_MC_PCICR, pcicr); + + it8172_init_ram_resource(mem_size); + add_memory_region(0, 20 << 20, BOOT_MEM_RAM); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c linux.ac/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c --- linux.vanilla/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Wed Apr 18 13:50:54 2001 @@ -0,0 +1,197 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Board specific pci fixups. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * 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 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include +#include + +void __init board_int_line_fixup(struct pci_dev *dev) +{ + unsigned int slot, func; + unsigned char pin; + const int internal_func_irqs[7] = { + IT8172_AC97_IRQ, + IT8172_DMA_IRQ, + IT8172_CDMA_IRQ, + IT8172_USB_IRQ, + IT8172_BRIDGE_MASTER_IRQ, + IT8172_IDE_IRQ, + IT8172_MC68K_IRQ + }; + +#ifdef DEBUG + printk("board_int_line_fixup bus %d\n", dev->bus->number); +#endif + if (dev->bus->number != 0) + return; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + +#ifdef DEBUG + pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor); +#endif + + slot = PCI_SLOT(dev->devfn); + func = PCI_FUNC(dev->devfn); + + switch (slot) { + case 0x01: + /* + * Internal device 1 is actually 7 different internal + * devices on the IT8172G (a multi-function device). + */ + if (func < 7) + dev->irq = internal_func_irqs[func]; + break; + case 0x10: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x11: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x12: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x13: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x14: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + default: + return; + } + +#ifdef DEBUG + printk("irq fixup: slot %d, vendor %x, int line %d, int number %d\n", + slot, vendor, pin, dev->irq); +#endif + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + +} + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, board_int_line_fixup }, + { 0 } +}; +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/jazz/Makefile linux.ac/arch/mips/jazz/Makefile --- linux.vanilla/arch/mips/jazz/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/jazz/Makefile Wed Apr 18 13:50:54 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.5 1999/01/03 17:50:47 ralf Exp $ # # Makefile for the Jazz family specific parts of the kernel # @@ -8,17 +7,17 @@ # .S.s: - $(CPP) $(CFLAGS) $< -o $*.s + $(CPP) $(CFLAGS) $< -o $@ .S.o: - $(CC) $(CFLAGS) -c $< -o $*.o + $(CC) $(CFLAGS) -c $< -o $@ all: jazz.o + O_TARGET := jazz.o -O_OBJS := int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o floppy-jazz.o \ - kbd-jazz.o -int-handler.o: int-handler.S +obj-y := int-handler.o irq.o jazzdma.o reset.o rtc-jazz.o setup.o \ + floppy-jazz.o kbd-jazz.o -clean: +int-handler.o: int-handler.S include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/branch.c linux.ac/arch/mips/kernel/branch.c --- linux.vanilla/arch/mips/kernel/branch.c Wed Dec 10 18:31:09 1997 +++ linux.ac/arch/mips/kernel/branch.c Wed Apr 18 13:50:54 2001 @@ -5,15 +5,19 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1997 by Ralf Baechle + * Copyright (C) 1996, 97, 2000 by Ralf Baechle */ +#include #include #include #include #include +#include #include #include #include +#include +#include /* * Compute the return address and do emulate branch simulation, if required. @@ -65,7 +69,7 @@ switch (insn.i_format.rt) { case bltz_op: case bltzl_op: - if (regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -74,7 +78,7 @@ case bgez_op: case bgezl_op: - if (regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -84,7 +88,7 @@ case bltzal_op: case bltzall_op: regs->regs[31] = epc + 8; - if (regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -94,7 +98,7 @@ case bgezal_op: case bgezall_op: regs->regs[31] = epc + 8; - if (regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -142,7 +146,7 @@ case blez_op: /* not really i_format */ case blezl_op: /* rt field assumed to be zero */ - if (regs->regs[insn.i_format.rs] <= 0) + if ((long)regs->regs[insn.i_format.rs] <= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -152,7 +156,7 @@ case bgtz_op: case bgtzl_op: /* rt field assumed to be zero */ - if (regs->regs[insn.i_format.rs] > 0) + if ((long)regs->regs[insn.i_format.rs] > 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -163,6 +167,11 @@ * And now the FPA/cp1 branch instructions. */ case cop1_op: +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + fcr31 = current->thread.fpu.soft.sr; + else +#endif asm ("cfc1\t%0,$31":"=r" (fcr31)); bit = (insn.i_format.rt >> 2); bit += (bit != 0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/process.c linux.ac/arch/mips/kernel/process.c --- linux.vanilla/arch/mips/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/kernel/process.c Wed Apr 18 13:50:54 2001 @@ -1,12 +1,12 @@ -/* $Id: process.c,v 1.18 2000/01/29 01:41:59 ralf Exp $ - * +/* * 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. * - * Copyright (C) 1994 - 1999 by Ralf Baechle and others. + * Copyright (C) 1994 - 2000 by Ralf Baechle and others. * Copyright (C) 1999 Silicon Graphics, Inc. */ +#include #include #include #include @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -55,7 +56,7 @@ { /* Forget lazy fpu state */ if (last_task_used_math == current) { - set_cp0_status(ST0_CU1, ST0_CU1); + set_cp0_status(ST0_CU1); __asm__ __volatile__("cfc1\t$0,$31"); last_task_used_math = NULL; } @@ -65,7 +66,7 @@ { /* Forget lazy fpu state */ if (last_task_used_math == current) { - set_cp0_status(ST0_CU1, ST0_CU1); + set_cp0_status(ST0_CU1); __asm__ __volatile__("cfc1\t$0,$31"); last_task_used_math = NULL; } @@ -81,9 +82,13 @@ childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32; - if (last_task_used_math == current) { - set_cp0_status(ST0_CU1, ST0_CU1); - save_fp(p); + if (last_task_used_math == current) +#ifdef CONFIG_MIPS_FPU_EMULATOR + if (mips_cpu.options & MIPS_CPU_FPU) +#endif + { + set_cp0_status(ST0_CU1); + save_fp(p); } /* set up new TSS. */ childregs = (struct pt_regs *) childksp - 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/ptrace.c linux.ac/arch/mips/kernel/ptrace.c --- linux.vanilla/arch/mips/kernel/ptrace.c Mon Jul 10 06:18:15 2000 +++ linux.ac/arch/mips/kernel/ptrace.c Wed Apr 18 13:50:54 2001 @@ -1,14 +1,16 @@ -/* $Id: ptrace.c,v 1.17 1999/09/28 22:25:47 ralf Exp $ - * +/* * 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. * * Copyright (C) 1992 Ross Biro * Copyright (C) Linus Torvalds - * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle * Copyright (C) 1996 David S. Miller + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999 MIPS Technologies, Inc. */ +#include #include #include #include @@ -24,6 +26,8 @@ #include #include #include +#include +#include asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { @@ -131,13 +135,22 @@ break; case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { + unsigned long long *fregs + = (unsigned long long *) + &child->thread.fpu.hard.fp_regs[0]; +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) { + fregs = (unsigned long long *) + &child->thread.fpu.soft.regs[0]; + } else +#endif if (last_task_used_math == child) { enable_cp1(); save_fp(child); disable_cp1(); last_task_used_math = NULL; } - tmp = child->thread.fpu.hard.fp_regs[addr - 32]; + tmp = (unsigned long) fregs[(addr - 32)]; } else { tmp = -1; /* FP not yet used */ } @@ -158,6 +171,11 @@ tmp = regs->lo; break; case FPC_CSR: +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + tmp = child->thread.fpu.soft.sr; + else +#endif tmp = child->thread.fpu.hard.control; break; case FPC_EIR: { /* implementation / version register */ @@ -198,9 +216,17 @@ regs->regs[addr] = data; break; case FPR_BASE ... FPR_BASE + 31: { - unsigned int *fregs; + unsigned long long *fregs; + fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0]; if (child->used_math) { - if (last_task_used_math == child) { + if (last_task_used_math == child) +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) { + fregs = (unsigned long long *) + &child->thread.fpu.soft.regs[0]; + } else +#endif + { enable_cp1(); save_fp(child); disable_cp1(); @@ -213,7 +239,6 @@ sizeof(child->thread.fpu.hard)); child->thread.fpu.hard.control = 0; } - fregs = child->thread.fpu.hard.fp_regs; fregs[addr - FPR_BASE] = data; break; } @@ -227,6 +252,11 @@ regs->lo = data; break; case FPC_CSR: +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + child->thread.fpu.soft.sr = data; + else +#endif child->thread.fpu.hard.control = data; break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r2300_fpu.S linux.ac/arch/mips/kernel/r2300_fpu.S --- linux.vanilla/arch/mips/kernel/r2300_fpu.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r2300_fpu.S Wed Apr 18 13:50:54 2001 @@ -1,7 +1,4 @@ -/* $Id: r2300_fpu.S,v 1.6 1999/08/09 19:43:14 harald Exp $ - * - * r2300_fpu.S: Save/restore floating point context for signal handlers. - * +/* * 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. @@ -30,7 +27,7 @@ .set noreorder .set mips1 /* Save floating point context */ -LEAF(save_fp_context) +LEAF(_save_fp_context) li v0, 0 # assume success cfc1 t1,fcr31 EX(swc1 $f0,(SC_FPREGS+0)(a0)) @@ -65,13 +62,13 @@ EX(swc1 $f29,(SC_FPREGS+232)(a0)) EX(swc1 $f30,(SC_FPREGS+240)(a0)) EX(swc1 $f31,(SC_FPREGS+248)(a0)) - EX(sw t1,SC_FPC_CSR(a0)) + EX(sw t1,(SC_FPC_CSR)(a0)) cfc1 t0,$0 # implementation/version jr ra .set nomacro - EX(sw t0,SC_FPC_EIR(a0)) + EX(sw t0,(SC_FPC_EIR)(a0)) .set macro - END(save_fp_context) + END(_save_fp_context) /* * Restore FPU state: @@ -82,9 +79,9 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ -LEAF(restore_fp_context) +LEAF(_restore_fp_context) li v0, 0 # assume success - EX(lw t0,SC_FPC_CSR(a0)) + EX(lw t0,(SC_FPC_CSR)(a0)) EX(lwc1 $f0,(SC_FPREGS+0)(a0)) EX(lwc1 $f1,(SC_FPREGS+8)(a0)) EX(lwc1 $f2,(SC_FPREGS+16)(a0)) @@ -119,7 +116,7 @@ EX(lwc1 $f31,(SC_FPREGS+248)(a0)) jr ra ctc1 t0,fcr31 - END(restore_fp_context) + END(_restore_fp_context) .type fault@function .ent fault diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r2300_switch.S linux.ac/arch/mips/kernel/r2300_switch.S --- linux.vanilla/arch/mips/kernel/r2300_switch.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r2300_switch.S Wed Apr 18 13:50:54 2001 @@ -9,7 +9,7 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * Further modifications to make this work: - * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 1998-2000 Harald Koerfgen */ #include #include @@ -30,13 +30,11 @@ .align 5 /* - * task_struct *r4xx0_resume(task_struct *prev, - * task_struct *next) + * task_struct *resume(task_struct *prev, + * task_struct *next) */ LEAF(resume) - .set reorder mfc0 t1, CP0_STATUS - .set noreorder sw t1, THREAD_STATUS(a0) CPU_SAVE_NONSCRATCH(a0) sw ra, THREAD_REG31(a0) @@ -57,8 +55,10 @@ and a2, a3 or a2, t1 mtc0 a2, CP0_STATUS + .set noreorder jr ra move v0, a0 + .set reorder END(resume) /* @@ -74,19 +74,16 @@ or t0, t3 mtc0 t0, CP0_STATUS + .set noreorder beqz a0, 2f # Save floating point state nor t3, zero, t3 .set reorder lw t1, ST_OFF(a0) # last thread looses fpu - .set noreorder and t1, t3 sw t1, ST_OFF(a0) - swc1 $f0, (THREAD_FPU + 0x00)(a0) FPU_SAVE_SINGLE(a0, t1) # clobbers t1 2: - lwc1 $f0, (THREAD_FPU + 0x00)($28) - .set reorder FPU_RESTORE_SINGLE($28, t0) # clobbers t0 jr ra END(lazy_fpu_switch) @@ -94,14 +91,20 @@ /* * Save a thread's fp context. */ - .set noreorder LEAF(save_fp) FPU_SAVE_SINGLE(a0, t1) # clobbers t1 jr ra - swc1 $f0, (THREAD_FPU + 0x00)(a0) END(save_fp) /* + * Restore a thread's fp context. + */ +LEAF(restore_fp) + FPU_RESTORE_SINGLE(a0, t1) # clobbers t1 + jr ra + END(restore_fp) + +/* * Load the FPU with signalling NANS. This bit pattern we're using has * the property that no matter wether considered as single or as double * precission represents signaling NANS. @@ -153,6 +156,8 @@ mtc1 t0, $f28 mtc1 t0, $f29 mtc1 t0, $f30 + .set noreorder jr ra mtc1 t0, $f31 + .set reorder END(init_fpu) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r4k_fpu.S linux.ac/arch/mips/kernel/r4k_fpu.S --- linux.vanilla/arch/mips/kernel/r4k_fpu.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r4k_fpu.S Wed Apr 18 13:50:54 2001 @@ -1,15 +1,15 @@ -/* $Id: r4k_fpu.S,v 1.8 1999/09/28 22:25:47 ralf Exp $ - * - * r4k_fpu.S: Save/restore floating point context for signal handlers. - * +/* * 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. * - * Copyright (C) 1996, 1998 by Ralf Baechle + * Copyright (C) 1996, 1998, 2000 by Ralf Baechle * * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. */ #include #include @@ -19,7 +19,7 @@ #include #define EX(a,b) \ -9: a,##b; \ +9: a,b; \ .section __ex_table,"a"; \ PTR 9b, fault; \ .previous @@ -27,7 +27,7 @@ .set noreorder .set mips3 /* Save floating point context */ -LEAF(save_fp_context) +LEAF(_save_fp_context) li v0, 0 # assume success cfc1 t1,fcr31 @@ -55,7 +55,7 @@ .set nomacro EX(sw t0,SC_FPC_EIR(a0)) .set macro - END(save_fp_context) + END(_save_fp_context) /* * Restore FPU state: @@ -66,7 +66,7 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ -LEAF(restore_fp_context) +LEAF(_restore_fp_context) li v0, 0 # assume success EX(lw t0,SC_FPC_CSR(a0)) @@ -92,7 +92,7 @@ EX(ldc1 $f30,(SC_FPREGS+240)(a0)) jr ra ctc1 t0,fcr31 - END(restore_fp_context) + END(_restore_fp_context) .type fault@function .ent fault diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r4k_misc.S linux.ac/arch/mips/kernel/r4k_misc.S --- linux.vanilla/arch/mips/kernel/r4k_misc.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r4k_misc.S Wed Apr 18 13:50:54 2001 @@ -7,6 +7,13 @@ * Multi-cpu abstraction and reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ +/************************************************************************** + * 14 Nov, 2000. + * Made support for MIPS32 CPUs. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ #include #include #include @@ -102,7 +109,6 @@ sw pte, (ptr); .set noreorder - .set mips3 /* * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0: @@ -147,7 +153,9 @@ tlbwi 1: nop + .set mips3 eret + .set mips0 #endif nopage_tlbl: @@ -169,7 +177,9 @@ tlbwi 1: nop + .set mips3 eret + .set mips0 #endif nopage_tlbs: @@ -201,7 +211,9 @@ tlbwi 1: nop + .set mips3 eret + .set mips0 #endif nowrite_mod: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r4k_switch.S linux.ac/arch/mips/kernel/r4k_switch.S --- linux.vanilla/arch/mips/kernel/r4k_switch.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r4k_switch.S Wed Apr 18 13:50:54 2001 @@ -9,6 +9,14 @@ * Copyright (C) 1994, 1995, 1996, by Andreas Busse * Copyright (C) 1999 Silicon Graphics, Inc. */ +/************************************************************************** + * 13 Nov, 2000. + * Made support for MIPS32 CPUs and restoring of fp registers. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + #include #include #include @@ -24,8 +32,6 @@ #include - .set mips3 - /* * task_struct *r4xx0_resume(task_struct *prev, task_struct *next) */ @@ -95,6 +101,14 @@ END(save_fp) /* + * Restore a thread's fp context. + */ +LEAF(restore_fp) + FPU_RESTORE_DOUBLE(a0, t1) # clobbers t1 + jr ra + END(restore_fp) + +/* * Load the FPU with signalling NANS. This bit pattern we're using has * the property that no matter whether considered as single or as double * precision represents signaling NANS. @@ -105,6 +119,7 @@ #define FPU_DEFAULT 0x00000000 LEAF(init_fpu) + .set mips3 mfc0 t0, CP0_STATUS li t1, 0x20000000 or t0, t1 @@ -135,3 +150,4 @@ dmtc1 t0, $f30 .set reorder END(init_fpu) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/r6000_fpu.S linux.ac/arch/mips/kernel/r6000_fpu.S --- linux.vanilla/arch/mips/kernel/r6000_fpu.S Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/kernel/r6000_fpu.S Wed Apr 18 13:50:54 2001 @@ -9,8 +9,6 @@ * * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: r6000_fpu.S,v 1.5 1999/05/01 22:40:37 ralf Exp $ */ #include #include @@ -21,7 +19,7 @@ .set noreorder .set mips2 /* Save floating point context */ - LEAF(save_fp_context) + LEAF(_save_fp_context) mfc0 t0,CP0_STATUS sll t0,t0,2 bgez t0,1f @@ -49,7 +47,7 @@ sw t0,SC_FPC_CSR(a0) 1: jr ra nop - END(save_fp_context) + END(_save_fp_context) /* Restore FPU state: * - fp gp registers @@ -59,7 +57,7 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ - LEAF(restore_fp_context) + LEAF(_restore_fp_context) mfc0 t0,CP0_STATUS sll t0,t0,2 @@ -86,4 +84,4 @@ ctc1 t0,fcr31 1: jr ra nop - END(restore_fp_context) + END(_restore_fp_context) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/semaphore.c linux.ac/arch/mips/kernel/semaphore.c --- linux.vanilla/arch/mips/kernel/semaphore.c Sun Nov 12 03:02:40 2000 +++ linux.ac/arch/mips/kernel/semaphore.c Wed Apr 18 13:50:54 2001 @@ -127,112 +127,3 @@ { return waking_non_zero_trylock(sem); } - -/* - * RW Semaphores - */ -void -__down_read(struct rw_semaphore *sem, int count) -{ - DOWN_VAR; - - retry_down: - if (count < 0) { - /* Wait for the lock to become unbiased. Readers - are non-exclusive. */ - - /* This takes care of granting the lock. */ - up_read(sem); - - add_wait_queue(&sem->wait, &wait); - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - mb(); - count = atomic_dec_return(&sem->count); - if (count <= 0) - goto retry_down; - } else { - add_wait_queue(&sem->wait, &wait); - - while (1) { - if (test_and_clear_bit(0, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((sem->granted & 1) == 0) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - } -} - -void -__down_write(struct rw_semaphore *sem, int count) -{ - DOWN_VAR; - - retry_down: - if (count + RW_LOCK_BIAS < 0) { - up_write(sem); - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= RW_LOCK_BIAS) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - mb(); - count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (count != 0) - goto retry_down; - } else { - /* Put ourselves at the end of the list. */ - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); - - while (1) { - if (test_and_clear_bit(1, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((sem->granted & 2) == 0) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* If the lock is currently unbiased, awaken the sleepers. - FIXME: This wakes up the readers early in a bit of a - stampede -> bad! */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); - } -} - -void -__rwsem_wake(struct rw_semaphore *sem, unsigned long readers) -{ - if (readers) { - if (test_and_set_bit(0, &sem->granted)) - BUG(); - wake_up(&sem->wait); - } else { - if (test_and_set_bit(1, &sem->granted)) - BUG(); - wake_up(&sem->write_bias_wait); - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/setup.c linux.ac/arch/mips/kernel/setup.c --- linux.vanilla/arch/mips/kernel/setup.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/kernel/setup.c Wed Apr 18 13:51:25 2001 @@ -4,8 +4,9 @@ * for more details. * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 Ralf Baechle * Copyright (C) 1996 Stoned Elipot + * Copyright (C) 2000 Maciej W. Rozycki */ #include #include @@ -36,10 +37,10 @@ #include #include #include +#include #include #include #include -#include #ifdef CONFIG_SGI_IP22 #include #endif @@ -152,64 +153,171 @@ #endif } +/* declaration of the global struct */ +struct mips_cpu mips_cpu = {PRID_IMP_UNKNOWN, CPU_UNKNOWN, 0, 0, 0, + {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}}; + +/* Shortcut for assembler access to mips_cpu.options */ +int *cpuoptions = &mips_cpu.options; + +#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \ + | MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX) + static inline void cpu_probe(void) { - unsigned int prid = read_32bit_cp0_register(CP0_PRID); - switch(prid & 0xff00) { + unsigned long config1; + + mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID); + switch (mips_cpu.processor_id & 0xff00) { case PRID_IMP_R2000: - mips_cputype = CPU_R2000; + mips_cpu.cputype = CPU_R2000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; break; case PRID_IMP_R3000: - if((prid & 0xff) == PRID_REV_R3000A) - if(cpu_has_confreg()) - mips_cputype = CPU_R3081E; + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A) + if (cpu_has_confreg()) + mips_cpu.cputype = CPU_R3081E; else - mips_cputype = CPU_R3000A; + mips_cpu.cputype = CPU_R3000A; else - mips_cputype = CPU_R3000; + mips_cpu.cputype = CPU_R3000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; break; case PRID_IMP_R4000: - if((prid & 0xff) == PRID_REV_R4400) - mips_cputype = CPU_R4400SC; + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400) + mips_cpu.cputype = CPU_R4400SC; else - mips_cputype = CPU_R4000SC; + mips_cpu.cputype = CPU_R4000SC; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_WATCH | MIPS_CPU_VCE; + mips_cpu.tlbsize = 48; break; case PRID_IMP_R4600: - mips_cputype = CPU_R4600; + mips_cpu.cputype = CPU_R4600; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; break; +/* + * This processor doesn't have an MMU, so it's not "real easy" to + * run Linux on it. It is left purely for documentation. + * case PRID_IMP_R4650: - mips_cputype = CPU_R4650; + mips_cpu.cputype = CPU_R4650; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; + break; + */ + case PRID_IMP_R3912: + mips_cpu.cputype = CPU_R3912; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 32; break; case PRID_IMP_R4700: - mips_cputype = CPU_R4700; + mips_cpu.cputype = CPU_R4700; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; break; case PRID_IMP_R5000: - mips_cputype = CPU_R5000; + mips_cpu.cputype = CPU_R5000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R5432: + mips_cpu.cputype = CPU_R5432; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; break; case PRID_IMP_NEVADA: - mips_cputype = CPU_NEVADA; + mips_cpu.cputype = CPU_NEVADA; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_DIVEC; + mips_cpu.tlbsize = 48; + mips_cpu.icache.ways = 2; + mips_cpu.dcache.ways = 2; break; case PRID_IMP_R6000: - mips_cputype = CPU_R6000; + mips_cpu.cputype = CPU_R6000; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; break; case PRID_IMP_R6000A: - mips_cputype = CPU_R6000A; + mips_cpu.cputype = CPU_R6000A; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_RM7000: + mips_cpu.cputype = CPU_RM7000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; break; case PRID_IMP_R8000: - mips_cputype = CPU_R8000; + mips_cpu.cputype = CPU_R8000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 384; /* has wierd TLB: 3-way x 128 */ break; case PRID_IMP_R10000: - mips_cputype = CPU_R10000; - break; - case PRID_IMP_RM7000: - mips_cputype = CPU_R5000; + mips_cpu.cputype = CPU_R10000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_COUNTER | MIPS_CPU_WATCH; + mips_cpu.tlbsize = 64; + break; +#ifdef CONFIG_CPU_MIPS32 + case PRID_IMP_4KC: + mips_cpu.cputype = CPU_4KC; + mips_cpu.isa_level = MIPS_CPU_ISA_M32; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; + case PRID_IMP_5KC: + mips_cpu.cputype = CPU_5KC; + mips_cpu.isa_level = MIPS_CPU_ISA_M64; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; break; +#endif default: - mips_cputype = CPU_UNKNOWN; + mips_cpu.cputype = CPU_UNKNOWN; } } -asmlinkage void __init init_arch(int argc, char **argv, char **envp, int *prom_vec) +asmlinkage void __init +init_arch(int argc, char **argv, char **envp, int *prom_vec) { unsigned int s; @@ -232,18 +340,13 @@ */ loadmmu(); - /* Disable coprocessors */ + /* Disable coprocessors and set FPU for 16 FPRs */ s = read_32bit_cp0_register(CP0_STATUS); - s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX); + s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_FR); s |= ST0_CU0; write_32bit_cp0_register(CP0_STATUS, s); - /* - * Main should never return here, but - * just in case, we know what happens. - */ - for(;;) - start_kernel(); + start_kernel(); } static void __init default_irq_setup(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/signal.c linux.ac/arch/mips/kernel/signal.c --- linux.vanilla/arch/mips/kernel/signal.c Wed Jan 24 23:20:59 2001 +++ linux.ac/arch/mips/kernel/signal.c Wed Apr 18 13:51:25 2001 @@ -31,8 +31,9 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); -extern asmlinkage int save_fp_context(struct sigcontext *sc); -extern asmlinkage int restore_fp_context(struct sigcontext *sc); + +extern asmlinkage int (*save_fp_context)(struct sigcontext *sc); +extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc); extern asmlinkage void syscall_trace(void); @@ -74,12 +75,12 @@ /* * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage inline int -sys_sigsuspend(struct pt_regs regs) +save_static_function(sys_sigsuspend); +static_unused int +_sys_sigsuspend(struct pt_regs regs) { sigset_t *uset, saveset, newset; - save_static(®s); uset = (sigset_t *) regs.regs[4]; if (copy_from_user(&newset, uset, sizeof(sigset_t))) return -EFAULT; @@ -101,14 +102,14 @@ } } -asmlinkage int -sys_rt_sigsuspend(struct pt_regs regs) + +save_static_function(sys_rt_sigsuspend); +static_unused int +_sys_rt_sigsuspend(struct pt_regs regs) { sigset_t *unewset, saveset, newset; size_t sigsetsize; - save_static(®s); - /* XXX Don't preclude handling different sized sigset_t's. */ sigsetsize = regs.regs[5]; if (sigsetsize != sizeof(sigset_t)) @@ -353,7 +354,7 @@ err |= __put_user(owned_fp, &sc->sc_ownedfp); if (current->used_math) { /* fp is active. */ - set_cp0_status(ST0_CU1, ST0_CU1); + set_cp0_status(ST0_CU1); err |= save_fp_context(sc); last_task_used_math = NULL; regs->cp0_status &= ~ST0_CU1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/kernel/traps.c linux.ac/arch/mips/kernel/traps.c --- linux.vanilla/arch/mips/kernel/traps.c Mon Dec 4 01:48:19 2000 +++ linux.ac/arch/mips/kernel/traps.c Wed Apr 18 13:51:25 2001 @@ -7,6 +7,9 @@ * Modified for R3000 by Paul M. Antoine, 1995, 1996 * Complete output from die() by Ulf Carlsson, 1998 * Copyright (C) 1999 Silicon Graphics, Inc. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ #include #include @@ -16,12 +19,15 @@ #include #include +#include #include +#include #include +#include #include #include #include -#include +#include #include #include #include @@ -51,13 +57,15 @@ extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); +extern int fpu_emulator_cop1Handler(int, struct pt_regs *); + static char *cpu_names[] = CPU_NAMES; char watch_available = 0; char dedicated_iv_available = 0; -char vce_available = 0; void (*ibe_board_handler)(struct pt_regs *regs); void (*dbe_board_handler)(struct pt_regs *regs); @@ -308,9 +316,11 @@ */ void do_fpe(struct pt_regs *regs, unsigned long fcr31) { - unsigned long pc; - unsigned int insn; - extern void simfp(unsigned int); + +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) + panic("Floating Point Exception with No FPU"); +#endif #ifdef CONFIG_MIPS_FPE_MODULE if (fpe_handler != NULL) { @@ -318,12 +328,52 @@ return; } #endif - if (fcr31 & 0x20000) { + + if (fcr31 & FPU_CSR_UNI_X) { +#ifdef CONFIG_MIPS_FPU_EMULATOR + extern void save_fp(struct task_struct *); + extern void restore_fp(struct task_struct *); + int sig; + /* + * Unimplemented operation exception. If we've got the + * Full software emulator on-board, let's use it... + * + * Force FPU to dump state into task/thread context. + * We're moving a lot of data here for what is probably + * a single instruction, but the alternative is to + * pre-decode the FP register operands before invoking + * the emulator, which seems a bit extreme for what + * should be an infrequent event. + */ + save_fp(current); + + /* Run the emulator */ + sig = fpu_emulator_cop1Handler(0, regs); + + /* + * We can't allow the emulated instruction to leave the + * Unimplemented Operation bit set in the FCR31 fp-register. + */ + current->thread.fpu.soft.sr &= ~FPU_CSR_UNI_X; + + /* Restore the hardware register state */ + restore_fp(current); + + /* If something went wrong, signal */ + if (sig) + force_sig(sig, current); +#else + /* Else use mini-emulator */ + + extern void simfp(int); + unsigned long pc; + unsigned int insn; + /* Retry instruction with flush to zero ... */ if (!(fcr31 & (1<<24))) { printk("Setting flush to zero for %s.\n", current->comm); - fcr31 &= ~0x20000; + fcr31 &= ~FPU_CSR_UNI_X; fcr31 |= (1<<24); __asm__ __volatile__( "ctc1\t%0,$31" @@ -332,20 +382,26 @@ return; } pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); - if (get_user(insn, (unsigned int *)pc)) { + if(pc & 0x80000000) insn = *(unsigned int *)pc; + else if (get_user(insn, (unsigned int *)pc)) { /* XXX Can this happen? */ force_sig(SIGSEGV, current); } printk(KERN_DEBUG "Unimplemented exception for insn %08x at 0x%08lx in %s.\n", insn, regs->cp0_epc, current->comm); - simfp(insn); + simfp(MIPSInst(insn)); + compute_return_epc(regs); +#endif /* CONFIG_MIPS_FPU_EMULATOR */ + + return; } if (compute_return_epc(regs)) return; - //force_sig(SIGFPE, current); - printk(KERN_DEBUG "Should send SIGFPE to %s\n", current->comm); + + force_sig(SIGFPE, current); + printk(KERN_DEBUG "Sent send SIGFPE to %s\n", current->comm); } static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) @@ -382,12 +438,28 @@ * (A short test says that IRIX 5.3 sends SIGTRAP for all break * insns, even for break codes that indicate arithmetic failures. * Weird ...) + * But should we continue the brokenness??? --macro */ - force_sig(SIGTRAP, current); + switch (bcode) { + case 6: + case 7: + if (bcode == 7) + info.si_code = FPE_INTDIV; + else + info.si_code = FPE_INTOVF; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_addr = (void *)compute_return_epc(regs); + force_sig_info(SIGFPE, &info, current); + break; + default: + force_sig(SIGTRAP, current); + } } void do_tr(struct pt_regs *regs) { + siginfo_t info; unsigned int opcode, bcode; if (get_insn_opcode(regs, &opcode)) @@ -398,8 +470,23 @@ * (A short test says that IRIX 5.3 sends SIGTRAP for all break * insns, even for break codes that indicate arithmetic failures. * Weird ...) + * But should we continue the brokenness??? --macro */ - force_sig(SIGTRAP, current); + switch (bcode) { + case 6: + case 7: + if (bcode == 7) + info.si_code = FPE_INTDIV; + else + info.si_code = FPE_INTOVF; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_addr = (void *)compute_return_epc(regs); + force_sig_info(SIGFPE, &info, current); + break; + default: + force_sig(SIGTRAP, current); + } } #if !defined(CONFIG_CPU_HAS_LLSC) @@ -520,10 +607,32 @@ unsigned int cpid; extern void lazy_fpu_switch(void*); extern void init_fpu(void); - +#ifdef CONFIG_MIPS_FPU_EMULATOR + void fpu_emulator_init_fpu(void); + int sig; +#endif cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; if (cpid != 1) goto bad_cid; + +#ifdef CONFIG_MIPS_FPU_EMULATOR + if(!(mips_cpu.options & MIPS_CPU_FPU)) { + if (last_task_used_math != current) { + if(!current->used_math) { + fpu_emulator_init_fpu(); + current->used_math = 1; + } + } + sig = fpu_emulator_cop1Handler(0, regs); + last_task_used_math = current; + if(sig) { + force_sig(sig, current); + } + return; + } +#else + if(!(mips_cpu.options & MIPS_CPU_FPU)) goto bad_cid; +#endif regs->cp0_status |= ST0_CU1; if (last_task_used_math == current) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/lib/Makefile linux.ac/arch/mips/lib/Makefile --- linux.vanilla/arch/mips/lib/Makefile Wed Dec 6 07:15:12 2000 +++ linux.ac/arch/mips/lib/Makefile Wed Apr 18 13:51:25 2001 @@ -9,26 +9,23 @@ L_TARGET = lib.a -L_OBJS = csum_partial.o csum_partial_copy.o \ - rtc-std.o rtc-no.o memcpy.o memset.o watch.o\ - strlen_user.o strncpy_user.o strnlen_user.o +obj-y += csum_partial.o csum_partial_copy.o \ + rtc-std.o rtc-no.o memcpy.o memset.o \ + watch.o strlen_user.o strncpy_user.o \ + strnlen_user.o ifdef CONFIG_CPU_R3000 - L_OBJS += r3k_dump_tlb.o + obj-y += r3k_dump_tlb.o else - L_OBJS += dump_tlb.o + ifdef CONFIG_CPU_R3912 + obj-y += r3k_dump_tlb.o + else + obj-y += dump_tlb.o + endif endif -ifdef CONFIG_BLK_DEV_FD - L_OBJS += floppy-no.o floppy-std.o -endif - -ifdef CONFIG_IDE - L_OBJS += ide-std.o ide-no.o -endif - -ifdef CONFIG_PC_KEYB - L_OBJS += kbd-std.o kbd-no.o -endif +obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o +obj-$(CONFIG_IDE) += ide-std.o ide-no.o +obj-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/lib/kbd-std.c linux.ac/arch/mips/lib/kbd-std.c --- linux.vanilla/arch/mips/lib/kbd-std.c Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/lib/kbd-std.c Wed Apr 18 13:51:25 2001 @@ -8,6 +8,7 @@ * * Copyright (C) 1998, 1999 by Ralf Baechle */ +#include #include #include #include @@ -19,11 +20,17 @@ static void std_kbd_request_region(void) { +#ifdef CONFIG_MIPS_ITE8172 + printk("std_kbd_request_region\n"); + request_region(0x14000060, 16, "keyboard"); +#else request_region(0x60, 16, "keyboard"); +#endif } static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) { + printk("std_kbd_request_irq\n"); return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/Makefile linux.ac/arch/mips/math-emu/Makefile --- linux.vanilla/arch/mips/math-emu/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/Makefile Wed Apr 18 13:51:25 2001 @@ -0,0 +1,24 @@ +# +# Makefile for the Linux/MIPS kernel FPU emulation. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +EXTRA_ASFLAGS = -mips2 -mcpu=r4000 + +O_TARGET:= fpu_emulator.o + +obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \ + ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \ + dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \ + dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \ + sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \ + sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \ + dp_sqrt.o sp_sqrt.o kernel_linkage.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/cp1emu.c linux.ac/arch/mips/math-emu/cp1emu.c --- linux.vanilla/arch/mips/math-emu/cp1emu.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/cp1emu.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,1811 @@ +/* + * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator + * + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * A complete emulator for MIPS coprocessor 1 instructions. This is + * required for #float(switch) or #float(trap), where it catches all + * COP1 instructions via the "CoProcessor Unusable" exception. + * + * More surprisingly it is also required for #float(ieee), to help out + * the hardware fpu at the boundaries of the IEEE-754 representation + * (denormalised values, infinities, underflow, etc). It is made + * quite nasty because emulation of some non-COP1 instructions is + * required, e.g. in branch delay slots. + * + * Notes: + * 1) the IEEE754 library (-le) performs the actual arithmetic; + * 2) if you know that you won't have an fpu, then you'll get much + * better performance by compiling with -msoft-float! */ + +/************************************************************************** + * Nov 7, 2000 + * Massive changes to integrate with Linux kernel. + * + * Replace use of kernel data area with use of user stack + * for execution of instructions in branch delay slots. + * + * Replace use of static kernel variables with thread_struct elements. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ieee754.h" + +/* Strap kernel emulator for full MIPS IV emulation */ + +#ifdef __mips +#undef __mips +#endif +#define __mips 4 + +typedef void *vaddr_t; + +/* Function which emulates the instruction in a branch delay slot. */ + +static int mips_dsemul(struct pt_regs *, mips_instruction, vaddr_t); + +/* Function which emulates a floating point instruction. */ + +static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *, + mips_instruction); + +#if __mips >= 4 && __mips != 32 +static int fpux_emu(struct pt_regs *, + struct mips_fpu_soft_struct *, mips_instruction); +#endif + +/* Further private data for which no space exists in mips_fpu_soft_struct */ + +struct mips_fpu_emulator_private fpuemuprivate; + +/* Control registers */ + +#define FPCREG_RID 0 /* $0 = revision id */ +#define FPCREG_CSR 31 /* $31 = csr */ + +/* Convert Mips rounding mode (0..3) to IEEE library modes. */ +static const unsigned char ieee_rm[4] = { + IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD +}; + +#if __mips >= 4 +/* convert condition code register number to csr bit */ +static const unsigned int fpucondbit[8] = { + FPU_CSR_COND0, + FPU_CSR_COND1, + FPU_CSR_COND2, + FPU_CSR_COND3, + FPU_CSR_COND4, + FPU_CSR_COND5, + FPU_CSR_COND6, + FPU_CSR_COND7 +}; +#endif + + + +/* + * Redundant with logic already in kernel/branch.c, + * embedded in compute_return_epc. At some point, + * a single subroutine should be used across both + * modules. + */ +static int isBranchInstr(mips_instruction * i) +{ + switch (MIPSInst_OPCODE(*i)) { + case spec_op: + switch (MIPSInst_FUNC(*i)) { + case jalr_op: + case jr_op: + return 1; + } + break; + + case bcond_op: + switch (MIPSInst_RT(*i)) { + case bltz_op: + case bgez_op: + case bltzl_op: + case bgezl_op: + case bltzal_op: + case bgezal_op: + case bltzall_op: + case bgezall_op: + return 1; + } + break; + + case j_op: + case jal_op: + case jalx_op: + case beq_op: + case bne_op: + case blez_op: + case bgtz_op: + case beql_op: + case bnel_op: + case blezl_op: + case bgtzl_op: + return 1; + + case cop0_op: + case cop1_op: + case cop2_op: + case cop1x_op: + if (MIPSInst_RS(*i) == bc_op) + return 1; + break; + } + + return 0; +} + +#define REG_TO_VA (vaddr_t) +#define VA_TO_REG (unsigned long) + +static unsigned long +mips_get_word(struct pt_regs *xcp, void *va, int *perr) +{ + unsigned long temp; + + if (!user_mode(xcp)) { + *perr = 0; + return (*(unsigned long *) va); + } else { + /* Use kernel get_user() macro */ + *perr = (int) get_user(temp, (unsigned long *) va); + return temp; + } +} + +static unsigned long long +mips_get_dword(struct pt_regs *xcp, void *va, int *perr) +{ + unsigned long long temp; + + if (!user_mode(xcp)) { + *perr = 0; + return (*(unsigned long long *) va); + } else { + /* Use kernel get_user() macro */ + *perr = (int) get_user(temp, (unsigned long long *) va); + return temp; + } +} + +static int mips_put_word(struct pt_regs *xcp, void *va, unsigned long val) +{ + if (!user_mode(xcp)) { + *(unsigned long *) va = val; + return 0; + } else { + /* Use kernel get_user() macro */ + return (int) put_user(val, (unsigned long *) va); + } +} + +static int mips_put_dword(struct pt_regs *xcp, void *va, long long val) +{ + if (!user_mode(xcp)) { + *(unsigned long long *) va = val; + return 0; + } else { + /* Use kernel get_user() macro */ + return (int) put_user(val, (unsigned long long *) va); + } +} + + +/* + * In the Linux kernel, we support selection of FPR format on the + * basis of the Status.FR bit. This does imply that, if a full 32 + * FPRs are desired, there needs to be a flip-flop that can be written + * to one at that bit position. In any case, normal MIPS ABI uses + * only the even FPRs (Status.FR = 0). + */ + +#define CP0_STATUS_FR_SUPPORT + +/* + * Emulate the single floating point instruction pointed at by EPC. + * Two instructions if the instruction is in a branch delay slot. + */ + +static int +cop1Emulate(int xcptno, struct pt_regs *xcp, + struct mips_fpu_soft_struct *ctx) +{ + mips_instruction ir; + vaddr_t emulpc; + vaddr_t contpc; + unsigned int cond; + int err = 0; + + + ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + + /* XXX NEC Vr54xx bug workaround */ + if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) + xcp->cp0_cause &= ~CAUSEF_BD; + + if (xcp->cp0_cause & CAUSEF_BD) { + /* + * The instruction to be emulated is in a branch delay slot + * which means that we have to emulate the branch instruction + * BEFORE we do the cop1 instruction. + * + * This branch could be a COP1 branch, but in that case we + * would have had a trap for that instruction, and would not + * come through this route. + * + * Linux MIPS branch emulator operates on context, updating the + * cp0_epc. + */ + emulpc = REG_TO_VA(xcp->cp0_epc + 4); /* Snapshot emulation target */ + + if (__compute_return_epc(xcp)) { +#ifdef CP1DBG + printk("failed to emulate branch at %p\n", + REG_TO_VA(xcp->cp0_epc)); +#endif + return SIGILL;; + } + ir = mips_get_word(xcp, emulpc, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + contpc = REG_TO_VA xcp->cp0_epc; + } else { + emulpc = REG_TO_VA xcp->cp0_epc; + contpc = REG_TO_VA xcp->cp0_epc + 4; + } + + emul: + fpuemuprivate.stats.emulated++; + switch (MIPSInst_OPCODE(ir)) { +#ifdef CP0_STATUS_FR_SUPPORT + /* R4000+ 64-bit fpu registers */ +#ifndef SINGLE_ONLY_FPU + case ldc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + int ft = MIPSInst_RT(ir); + if (!(xcp->cp0_status & ST0_FR)) + ft &= ~1; + ctx->regs[ft] = mips_get_dword(xcp, va, &err); + fpuemuprivate.stats.loads++; + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + + case sdc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + int ft = MIPSInst_RT(ir); + if (!(xcp->cp0_status & ST0_FR)) + ft &= ~1; + fpuemuprivate.stats.stores++; + if (mips_put_dword(xcp, va, ctx->regs[ft])) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; +#endif + + case lwc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + fpureg_t val; + int ft = MIPSInst_RT(ir); + fpuemuprivate.stats.loads++; + val = mips_get_word(xcp, va, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + if (xcp->cp0_status & ST0_FR) { + /* load whole register */ + ctx->regs[ft] = val; + } else if (ft & 1) { + /* load to m.s. 32 bits */ +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + ctx->regs[(ft & ~1)] &= 0xffffffff; + ctx->regs[(ft & ~1)] |= val << 32; +#endif + } else { + /* load to l.s. 32 bits */ + ctx->regs[ft] &= ~0xffffffffLL; + ctx->regs[ft] |= val; + } + } + break; + + case swc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int val; + int ft = MIPSInst_RT(ir); + fpuemuprivate.stats.stores++; + if (xcp->cp0_status & ST0_FR) { + /* store whole register */ + val = ctx->regs[ft]; + } else if (ft & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + /* store from m.s. 32 bits */ + val = ctx->regs[(ft & ~1)] >> 32; +#endif + } else { + /* store from l.s. 32 bits */ + val = ctx->regs[ft]; + } + if (mips_put_word(xcp, va, val)) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; +#else /* old 32-bit fpu registers */ + case lwc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + ctx->regs[MIPSInst_RT(ir)] = + mips_get_word(xcp, va, &err); + fpuemuprivate.stats.loads++; + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + + case swc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + fpuemuprivate.stats.stores++; + if (mips_put_word + (xcp, va, ctx->regs[MIPSInst_RT(ir)])) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + case ldc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int rt = MIPSInst_RT(ir) & ~1; + int errs = 0; + fpuemuprivate.stats.loads++; +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) + ctx->regs[rt + 1] = + mips_get_word(xcp, va + 0, &err); + errs += err; + ctx->regs[rt + 0] = + mips_get_word(xcp, va + 4, &err); + errs += err; +#else + ctx->regs[rt + 0] = + mips_get_word(xcp, va + 0, &err); + errs += err; + ctx->regs[rt + 1] = + mips_get_word(xcp, va + 4, &err); + errs += err; +#endif + if (err) + return SIGBUS; + } + break; + + case sdc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int rt = MIPSInst_RT(ir) & ~1; + fpuemuprivate.stats.stores++; +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) + if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1])) + return SIGBUS; + if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0])) + return SIGBUS; +#else + if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0])) + return SIGBUS; + if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1])) + return SIGBUS; +#endif + } + break; +#endif + + case cop1_op: + switch (MIPSInst_RS(ir)) { + +#ifdef CP0_STATUS_FR_SUPPORT +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case dmfc_op: + /* copregister fs -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + int fs = MIPSInst_RD(ir); + if (!(xcp->cp0_status & ST0_FR)) + fs &= ~1; + xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs]; + } + break; + + case dmtc_op: + /* copregister fs <- rt */ + { + fpureg_t value; + int fs = MIPSInst_RD(ir); + if (!(xcp->cp0_status & ST0_FR)) + fs &= ~1; + value = + (MIPSInst_RT(ir) == + 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + ctx->regs[fs] = value; + } + break; +#endif + + case mfc_op: + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + /* default value from l.s. 32 bits */ + int value = ctx->regs[MIPSInst_RD(ir)]; + if (MIPSInst_RD(ir) & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + if (!(xcp->cp0_status & ST0_FR)) { + /* move from m.s. 32 bits */ + value = + ctx-> + regs[MIPSInst_RD(ir) & + ~1] >> 32; + } +#endif + } + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case mtc_op: + /* copregister rd <- rt */ + { + fpureg_t value; + if (MIPSInst_RT(ir) == 0) + value = 0; + else + value = + (unsigned int) xcp-> + regs[MIPSInst_RT(ir)]; + if (MIPSInst_RD(ir) & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + if (!(xcp->cp0_status & ST0_FR)) { + /* move to m.s. 32 bits */ + ctx-> + regs[ + (MIPSInst_RD(ir) & + ~1)] &= + 0xffffffff; + ctx-> + regs[ + (MIPSInst_RD(ir) & + ~1)] |= + value << 32; + break; + } +#endif + } + /* move to l.s. 32 bits */ + ctx->regs[MIPSInst_RD(ir)] &= + ~0xffffffffLL; + ctx->regs[MIPSInst_RD(ir)] |= value; + } + break; +#else + + case mfc_op: + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + unsigned value = + ctx->regs[MIPSInst_RD(ir)]; + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case mtc_op: + /* copregister rd <- rt */ + { + unsigned value; + value = + (MIPSInst_RT(ir) == + 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + ctx->regs[MIPSInst_RD(ir)] = value; + } + break; +#endif + + case cfc_op: + /* cop control register rd -> gpr[rt] */ + { + unsigned value; + + if (MIPSInst_RD(ir) == FPCREG_CSR) { + value = ctx->sr; +#ifdef CSRTRACE + printk + ("%p gpr[%d]<-csr=%08x\n", + REG_TO_VA(xcp->cp0_epc), + MIPSInst_RT(ir), value); +#endif + } else if (MIPSInst_RD(ir) == FPCREG_RID) + value = 0; + else + value = 0; + if (MIPSInst_RT(ir)) + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case ctc_op: + /* copregister rd <- rt */ + { + unsigned value; + + if (MIPSInst_RT(ir) == 0) + value = 0; + else + value = xcp->regs[MIPSInst_RT(ir)]; + + /* we only have one writable control reg + */ + if (MIPSInst_RD(ir) == FPCREG_CSR) { +#ifdef CSRTRACE + printk + ("%p gpr[%d]->csr=%08x\n", + REG_TO_VA(xcp->cp0_epc), + MIPSInst_RT(ir), value); +#endif + ctx->sr = value; + /* copy new rounding mode to ieee library state! */ + ieee754_csr.rm = + ieee_rm[value & 0x3]; + } + } + break; + + case bc_op: + if (xcp->cp0_cause & CAUSEF_BD) { + return SIGILL; + } + { + int likely = 0; + +#if __mips >= 4 + cond = + ctx-> + sr & fpucondbit[MIPSInst_RT(ir) >> 2]; +#else + cond = ctx->sr & FPU_CSR_COND; +#endif + switch (MIPSInst_RT(ir) & 3) { + case bcfl_op: + likely = 1; + case bcf_op: + cond = !cond; + break; + case bctl_op: + likely = 1; + case bct_op: + break; + default: + /* thats an illegal instruction */ + return SIGILL; + } + + xcp->cp0_cause |= CAUSEF_BD; + if (cond) { + /* branch taken: emulate dslot instruction */ + xcp->cp0_epc += 4; + contpc = + REG_TO_VA xcp->cp0_epc + + (MIPSInst_SIMM(ir) << 2); + + ir = + mips_get_word(xcp, + REG_TO_VA(xcp-> + cp0_epc), + &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + + switch (MIPSInst_OPCODE(ir)) { + case lwc1_op: + case swc1_op: +#if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU) + case ldc1_op: + case sdc1_op: +#endif + case cop1_op: +#if __mips >= 4 && __mips != 32 + case cop1x_op: +#endif + /* its one of ours */ + goto emul; +#if __mips >= 4 + case spec_op: + if (MIPSInst_FUNC(ir) == + movc_op) goto emul; + break; +#endif + } + + /* single step the non-cp1 instruction in the dslot */ + return mips_dsemul(xcp, ir, + contpc); + } else { + /* branch not taken */ + if (likely) + /* branch likely nullifies dslot if not taken */ + xcp->cp0_epc += 4; + /* else continue & execute dslot as normal insn */ + } + } + break; + + default: + if (!(MIPSInst_RS(ir) & 0x10)) { + return SIGILL; + } + /* a real fpu computation instruction */ + { + int sig; + if ((sig = fpu_emu(xcp, ctx, ir))) + return sig; + } + } + break; + +#if __mips >= 4 && __mips != 32 + case cop1x_op: + { + int sig; + if ((sig = fpux_emu(xcp, ctx, ir))) + return sig; + } + break; +#endif + +#if __mips >= 4 + case spec_op: + if (MIPSInst_FUNC(ir) != movc_op) + return SIGILL; + cond = fpucondbit[MIPSInst_RT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != + ((MIPSInst_RT(ir) & 1) != 0)) return 0; + xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; + break; +#endif + + default: + return SIGILL; + } + + /* we did it !! */ + xcp->cp0_epc = VA_TO_REG(contpc); + xcp->cp0_cause &= ~CAUSEF_BD; + return 0; +} + +/* + * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when + * we have to emulate the instruction in a COP1 branch delay slot. Do + * not change cp0_epc due to the instruction + * + * According to the spec: + * 1) it shouldnt be a branch :-) + * 2) it can be a COP instruction :-( + * 3) if we are tring to run a protected memory space we must take + * special care on memory access instructions :-( + */ + +/* + * "Trampoline" return routine to catch exception following + * execution of delay-slot instruction execution. + */ + +int do_dsemulret(struct pt_regs *xcp) +{ +#ifdef DSEMUL_TRACE + printk("desemulret\n"); +#endif + /* Set EPC to return to post-branch instruction */ + xcp->cp0_epc = current->thread.dsemul_epc; + /* + * Clear the state that got us here. + */ + current->thread.dsemul_aerpc = (unsigned long) 0; + + return 0; +} + + +#define AdELOAD 0x8c000001 /* lw $0,1($0) */ + +static int +mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc) +{ + mips_instruction *dsemul_insns; + mips_instruction forcetrap; + extern asmlinkage void handle_dsemulret(void); + + if (ir == 0) { /* a nop is easy */ + xcp->cp0_epc = VA_TO_REG(cpc); + return 0; + } +#ifdef DSEMUL_TRACE + printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc); +#endif + + /* + * The strategy is to push the instruction onto the user stack + * and put a trap after it which we can catch and jump to + * the required address any alternative apart from full + * instruction emulation!!. + */ + dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3); + dsemul_insns -= 3; /* Two instructions, plus one for luck ;-) */ + /* Verify that the stack pointer is not competely insane */ + if (verify_area + (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 2)) + return SIGBUS; + + if (mips_put_word(xcp, &dsemul_insns[0], ir)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + /* + * Algorithmics used a system call instruction, and + * borrowed that vector. MIPS/Linux version is a bit + * more heavyweight in the interests of portability and + * multiprocessor support. We flag the thread for special + * handling in the unaligned access handler and force an + * address error excpetion. + */ + + /* If one is *really* paranoid, one tests for a bad stack pointer */ + if ((xcp->regs[29] & 0x3) == 0x3) + forcetrap = AdELOAD - 1; + else + forcetrap = AdELOAD; + + if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + /* Set thread state to catch and handle the exception */ + current->thread.dsemul_epc = (unsigned long) cpc; + current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1]; + xcp->cp0_epc = VA_TO_REG & dsemul_insns[0]; + + /* What we'd really like to do is just flush the line(s) of the */ + /* icache containing the dsemulret instructions, but there's no */ + /* mechanism to do this yet... */ + flush_cache_all(); + return SIGILL; /* force out of emulation loop */ +} + +/* + * Conversion table from MIPS compare ops 48-63 + * cond = ieee754dp_cmp(x,y,IEEE754_UN); + */ +static const unsigned char cmptab[8] = { + 0, /* cmp_0 (sig) cmp_sf */ + IEEE754_CUN, /* cmp_un (sig) cmp_ngle */ + IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */ + IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */ + IEEE754_CLT, /* cmp_olt (sig) cmp_lt */ + IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */ + IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */ + IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ +}; + +#define SIFROMREG(si,x) ((si) = ctx->regs[x]) +#define SITOREG(si,x) (ctx->regs[x] = (int)(si)) + +#if __mips64 && !defined(SINGLE_ONLY_FPU) +#define DIFROMREG(di,x) ((di) = ctx->regs[x]) +#define DITOREG(di,x) (ctx->regs[x] = (di)) +#endif + +#define SPFROMREG(sp,x) ((sp).bits = ctx->regs[x]) +#define SPTOREG(sp,x) (ctx->regs[x] = (sp).bits) + +#ifdef CP0_STATUS_FR_SUPPORT +#define DPFROMREG(dp,x) ((dp).bits = \ + ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]) +#define DPTOREG(dp,x) (ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]\ + = (dp).bits) +#else +/* Beware: MIPS COP1 doubles are always little_word endian in registers */ +#define DPFROMREG(dp,x) \ + ((dp).bits = ((unsigned long long)ctx->regs[(x)+1] << 32) | ctx->regs[x]) +#define DPTOREG(dp,x) \ + (ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32) +#endif + +#if __mips >= 4 && __mips != 32 + +/* + * Additional MIPS4 instructions + */ + +static ieee754dp fpemu_dp_recip(ieee754dp d) +{ + return ieee754dp_div(ieee754dp_one(0), d); +} + +static ieee754dp fpemu_dp_rsqrt(ieee754dp d) +{ + return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); +} + +static ieee754sp fpemu_sp_recip(ieee754sp s) +{ + return ieee754sp_div(ieee754sp_one(0), s); +} + +static ieee754sp fpemu_sp_rsqrt(ieee754sp s) +{ + return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); +} + + +static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_add(ieee754dp_mul(s, t), r); +} + +static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_sub(ieee754dp_mul(s, t), r); +} + +static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r)); +} + +static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r)); +} + + +static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_add(ieee754sp_mul(s, t), r); +} + +static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_sub(ieee754sp_mul(s, t), r); +} + +static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r)); +} + +static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r)); +} + +static int +fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, + mips_instruction ir) +{ + unsigned rcsr = 0; /* resulting csr */ + + fpuemuprivate.stats.cp1xops++; + + switch (MIPSInst_FMA_FFMT(ir)) { + case s_fmt: /* 0 */ + { + ieee754sp(*handler) (ieee754sp, ieee754sp, + ieee754sp); + ieee754sp fd, fr, fs, ft; + + switch (MIPSInst_FUNC(ir)) { + case lwxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + fpureg_t val; + int err = 0; + val = mips_get_word(xcp, va, &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + if (xcp->cp0_status & ST0_FR) { + /* load whole register */ + ctx-> + regs[MIPSInst_FD(ir)] = + val; + } else if (MIPSInst_FD(ir) & 1) { + /* load to m.s. 32 bits */ +#if defined(SINGLE_ONLY_FPU) + /* illegal register in single-float mode */ + return SIGILL; +#else + ctx-> + regs[ + (MIPSInst_FD(ir) & + ~1)] &= + 0xffffffff; + ctx-> + regs[ + (MIPSInst_FD(ir) & + ~1)] |= + val << 32; +#endif + } else { + /* load to l.s. 32 bits */ + ctx-> + regs[MIPSInst_FD(ir)] + &= ~0xffffffffLL; + ctx-> + regs[MIPSInst_FD(ir)] + |= val; + } + } + break; + + case swxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + unsigned int val; + if (xcp->cp0_status & ST0_FR) { + /* store whole register */ + val = + ctx-> + regs[MIPSInst_FS(ir)]; + } else if (MIPSInst_FS(ir) & 1) { +#if defined(SINGLE_ONLY_FPU) + /* illegal register in single-float mode */ + return SIGILL; +#else + /* store from m.s. 32 bits */ + val = + ctx-> + regs[ + (MIPSInst_FS(ir) & + ~1)] >> 32; +#endif + } else { + /* store from l.s. 32 bits */ + val = + ctx-> + regs[MIPSInst_FS(ir)]; + } + if (mips_put_word(xcp, va, val)) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case madd_s_op: + handler = fpemu_sp_madd; + goto scoptop; + case msub_s_op: + handler = fpemu_sp_msub; + goto scoptop; + case nmadd_s_op: + handler = fpemu_sp_nmadd; + goto scoptop; + case nmsub_s_op: + handler = fpemu_sp_nmsub; + goto scoptop; + + scoptop: + SPFROMREG(fr, MIPSInst_FR(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + fd = (*handler) (fr, fs, ft); + SPTOREG(fd, MIPSInst_FD(ir)); + + copcsr: + if (ieee754_cxtest(IEEE754_INEXACT)) + rcsr |= + FPU_CSR_INE_X | FPU_CSR_INE_S; + if (ieee754_cxtest(IEEE754_UNDERFLOW)) + rcsr |= + FPU_CSR_UDF_X | FPU_CSR_UDF_S; + if (ieee754_cxtest(IEEE754_OVERFLOW)) + rcsr |= + FPU_CSR_OVF_X | FPU_CSR_OVF_S; + if (ieee754_cxtest + (IEEE754_INVALID_OPERATION)) rcsr |= + FPU_CSR_INV_X | FPU_CSR_INV_S; + + ctx->sr = + (ctx->sr & ~FPU_CSR_ALL_X) | rcsr; + if ((ctx->sr >> 5) & ctx-> + sr & FPU_CSR_ALL_E) { + /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */ + return SIGFPE; + } + + break; + + default: + return SIGILL; + } + } + break; + +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: /* 1 */ + { + ieee754dp(*handler) (ieee754dp, ieee754dp, + ieee754dp); + ieee754dp fd, fr, fs, ft; + + switch (MIPSInst_FUNC(ir)) { + case ldxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + int err = 0; + ctx->regs[MIPSInst_FD(ir)] = + mips_get_dword(xcp, va, &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case sdxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + if (mips_put_dword + (xcp, va, + ctx->regs[MIPSInst_FS(ir)])) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case madd_d_op: + handler = fpemu_dp_madd; + goto dcoptop; + case msub_d_op: + handler = fpemu_dp_msub; + goto dcoptop; + case nmadd_d_op: + handler = fpemu_dp_nmadd; + goto dcoptop; + case nmsub_d_op: + handler = fpemu_dp_nmsub; + goto dcoptop; + + dcoptop: + DPFROMREG(fr, MIPSInst_FR(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + fd = (*handler) (fr, fs, ft); + DPTOREG(fd, MIPSInst_FD(ir)); + goto copcsr; + + default: + return SIGILL; + } + } + break; +#endif + + case 0x7: /* 7 */ + { + if (MIPSInst_FUNC(ir) != pfetch_op) { + return SIGILL; + } + /* ignore prefx operation */ + } + break; + + default: + return SIGILL; + } + + return 0; +} +#endif + + + +/* + * Emulate a single COP1 arithmetic instruction. + */ +static int +fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, + mips_instruction ir) +{ + int rfmt; /* resulting format */ + unsigned rcsr = 0; /* resulting csr */ + unsigned cond; + union { + ieee754dp d; + ieee754sp s; + int w; +#if __mips64 + long long l; +#endif + } rv; /* resulting value */ + + fpuemuprivate.stats.cp1ops++; + switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { + + case s_fmt:{ /* 0 */ + ieee754sp(*handler) (); + + switch (MIPSInst_FUNC(ir)) { + /* binary ops */ + case fadd_op: + handler = ieee754sp_add; + goto scopbop; + case fsub_op: + handler = ieee754sp_sub; + goto scopbop; + case fmul_op: + handler = ieee754sp_mul; + goto scopbop; + case fdiv_op: + handler = ieee754sp_div; + goto scopbop; + + /* unary ops */ +#if __mips >= 2 || __mips64 + case fsqrt_op: + handler = ieee754sp_sqrt; + goto scopuop; +#endif +#if __mips >= 4 && __mips != 32 + case frsqrt_op: + handler = fpemu_sp_rsqrt; + goto scopuop; + case frecip_op: + handler = fpemu_sp_recip; + goto scopuop; +#endif +#if __mips >= 4 + case fmovc_op: + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != + ((MIPSInst_FT(ir) & 1) != 0)) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fmovz_op: + if (xcp->regs[MIPSInst_FT(ir)] != 0) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fmovn_op: + if (xcp->regs[MIPSInst_FT(ir)] == 0) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; +#endif + case fabs_op: + handler = ieee754sp_abs; + goto scopuop; + case fneg_op: + handler = ieee754sp_neg; + goto scopuop; + case fmov_op: + /* an easy one */ + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + /* binary op on handler */ +scopbop: + { + ieee754sp fs, ft; + + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + + rv.s = (*handler) (fs, ft); + goto copcsr; + } +scopuop: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = (*handler) (fs); + goto copcsr; + } +copcsr: + if (ieee754_cxtest(IEEE754_INEXACT)) + rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; + if (ieee754_cxtest(IEEE754_UNDERFLOW)) + rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; + if (ieee754_cxtest(IEEE754_OVERFLOW)) + rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; + if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) + rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; + if (ieee754_cxtest + (IEEE754_INVALID_OPERATION)) rcsr |= + FPU_CSR_INV_X | FPU_CSR_INV_S; + break; + + /* unary conv ops */ + case fcvts_op: + return SIGILL; /* not defined */ + case fcvtd_op: +#if defined(SINGLE_ONLY_FPU) + return SIGILL; /* not defined */ +#else + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fsp(fs); + rfmt = d_fmt; + goto copcsr; + } +#endif + case fcvtw_op: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754sp_tint(fs); + rfmt = w_fmt; + goto copcsr; + } + +#if __mips >= 2 || __mips64 + case fround_op: + case ftrunc_op: + case fceil_op: + case ffloor_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.w = ieee754sp_tint(fs); + ieee754_csr.rm = oldrm; + rfmt = w_fmt; + goto copcsr; + } +#endif /* __mips >= 2 */ + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case fcvtl_op: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754sp_tlong(fs); + rfmt = l_fmt; + goto copcsr; + } + + case froundl_op: + case ftruncl_op: + case fceill_op: + case ffloorl_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.l = ieee754sp_tlong(fs); + ieee754_csr.rm = oldrm; + rfmt = l_fmt; + goto copcsr; + } +#endif /* __mips64 && !fpu(single) */ + + default: + if (MIPSInst_FUNC(ir) >= fcmp_op) { + unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + ieee754sp fs, ft; + + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]); + rfmt = -1; + if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + } else { + return SIGILL; + } + break; + } + break; + } + +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: { + ieee754dp(*handler) (); + + switch (MIPSInst_FUNC(ir)) { + /* binary ops */ + case fadd_op: + handler = ieee754dp_add; + goto dcopbop; + case fsub_op: + handler = ieee754dp_sub; + goto dcopbop; + case fmul_op: + handler = ieee754dp_mul; + goto dcopbop; + case fdiv_op: + handler = ieee754dp_div; + goto dcopbop; + + /* unary ops */ +#if __mips >= 2 || __mips64 + case fsqrt_op: + handler = ieee754dp_sqrt; + goto dcopuop; +#endif +#if __mips >= 4 && __mips != 32 + case frsqrt_op: + handler = fpemu_dp_rsqrt; + goto dcopuop; + case frecip_op: + handler = fpemu_dp_recip; + goto dcopuop; +#endif +#if __mips >= 4 + case fmovc_op: + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0)) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fmovz_op: + if (xcp->regs[MIPSInst_FT(ir)] != 0) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fmovn_op: + if (xcp->regs[MIPSInst_FT(ir)] == 0) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; +#endif + case fabs_op: + handler = ieee754dp_abs; + goto dcopuop; + case fneg_op: + handler = ieee754dp_neg; + goto dcopuop; + case fmov_op: + /* an easy one */ + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + + /* binary op on handler */ +dcopbop: + { + ieee754dp fs, ft; + + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + + rv.d = (*handler) (fs, ft); + goto copcsr; + } +dcopuop: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = (*handler) (fs); + goto copcsr; + } + + /* unary conv ops */ + case fcvts_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fdp(fs); + rfmt = s_fmt; + goto copcsr; + } + case fcvtd_op: + return SIGILL; /* not defined */ + case fcvtw_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754dp_tint(fs); /* wrong */ + rfmt = w_fmt; + goto copcsr; + } + +#if __mips >= 2 || __mips64 + case fround_op: + case ftrunc_op: + case fceil_op: + case ffloor_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.w = ieee754dp_tint(fs); + ieee754_csr.rm = oldrm; + rfmt = w_fmt; + goto copcsr; + } +#endif + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case fcvtl_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754dp_tlong(fs); + rfmt = l_fmt; + goto copcsr; + } + + case froundl_op: + case ftruncl_op: + case fceill_op: + case ffloorl_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.l = ieee754dp_tlong(fs); + ieee754_csr.rm = oldrm; + rfmt = l_fmt; + goto copcsr; + } +#endif /* __mips >= 3 && !fpu(single) */ + + default: + if (MIPSInst_FUNC(ir) >= fcmp_op) { + unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + ieee754dp fs, ft; + + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]); + rfmt = -1; + if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + } else { + return SIGILL; + } + break; + } + break; + } +#endif /* !defined(SINGLE_ONLY_FPU) */ + + case w_fmt: { + switch (MIPSInst_FUNC(ir)) { + case fcvts_op: + /* convert word to single precision real */ + rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = s_fmt; + goto copcsr; +#if !defined(SINGLE_ONLY_FPU) + case fcvtd_op: + /* convert word to double precision real */ + rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = d_fmt; + goto copcsr; +#endif + default: + return SIGILL; + } + break; + } + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case l_fmt: { + switch (MIPSInst_FUNC(ir)) { + case fcvts_op: + /* convert long to single precision real */ + rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = s_fmt; + goto copcsr; + case fcvtd_op: + /* convert long to double precision real */ + rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = d_fmt; + goto copcsr; + default: + return SIGILL; + } + break; + } +#endif + + default: + return SIGILL; + } + + /* + * Update the fpu CSR register for this operation. + * If an exception is required, generate a tidy SIGFPE exception, + * without updating the result register. + * Note: cause exception bits do not accumulate, they are rewritten + * for each op; only the flag/sticky bits accumulate. + */ + ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr; + if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) { + /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */ + return SIGFPE; + } + + /* + * Now we can safely write the result back to the register file. + */ + switch (rfmt) { + case -1: { +#if __mips >= 4 + cond = fpucondbit[MIPSInst_FD(ir) >> 2]; +#else + cond = FPU_CSR_COND; +#endif + if (rv.w) + ctx->sr |= cond; + else + ctx->sr &= ~cond; + break; + } +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: + DPTOREG(rv.d, MIPSInst_FD(ir)); + break; +#endif + case s_fmt: + SPTOREG(rv.s, MIPSInst_FD(ir)); + break; + case w_fmt: + SITOREG(rv.w, MIPSInst_FD(ir)); + break; +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case l_fmt: + DITOREG(rv.l, MIPSInst_FD(ir)); + break; +#endif + default: + return SIGILL; + } + + return 0; +} + + +/* + * Emulate the floating point instruction at EPC, and continue + * to run until we hit a non-fp instruction, or a backward + * branch. This cuts down dramatically on the per instruction + * exception overhead. + */ +int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp) +{ + struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft; + unsigned long oldepc, prevepc; + unsigned int insn; + int sig = 0; + int err = 0; + + oldepc = xcp->cp0_epc; + do { + prevepc = xcp->cp0_epc; + insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + if (insn != 0) + sig = cop1Emulate(xcptno, xcp, ctx); + else + xcp->cp0_epc += 4; /* skip nops */ + } while (xcp->cp0_epc > prevepc && sig == 0); + + /* SIGILL indicates a non-fpu instruction */ + if (sig == SIGILL && xcp->cp0_epc != oldepc) + /* but if epc has advanced, then ignore it */ + sig = 0; + + return sig; +} + + +#ifdef NOTDEF +/* + * Patch up the hardware fpu state when an f.p. exception occurs. + */ +static int cop1Patcher(int xcptno, struct pt_regs *xcp) +{ + struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft; + unsigned sr; + int sig; + + /* reenable Cp1, else fpe_save() will get nested exception */ + sr = mips_bissr(ST0_CU1); + + /* get fpu registers and status, then clear pending exceptions */ + fpe_save(ctx); + fpe_setsr(ctx->sr &= ~FPU_CSR_ALL_X); + + /* get current rounding mode for IEEE library, and emulate insn */ + ieee754_csr.rm = ieee_rm[ctx->sr & 0x3]; + sig = cop1Emulate(xcptno, xcp, ctx); + + /* don't return with f.p. exceptions pending */ + ctx->sr &= ~FPU_CSR_ALL_X; + fpe_restore(ctx); + + mips_setsr(sr); + return sig; +} + +void _cop1_init(int emulate) +{ + extern int _nofpu; + + if (emulate) { + /* + * Install cop1 emulator to handle "coprocessor unusable" exception + */ + xcption(XCPTCPU, cop1Handler); + fpuemuactive = 1; /* tell dbg.c that we are in charge */ + _nofpu = 0; /* tell setjmp() it "has" an fpu */ + } else { + /* + * Install cop1 emulator for floating point exceptions only, + * i.e. denormalised results, underflow, overflow etc, which + * must be emulated in s/w. + */ +#ifdef 1 + /* r4000 or above use dedicate exception */ + xcption(XCPTFPE, cop1Patcher); +#else + /* r3000 et al use interrupt */ + extern int _sbd_getfpuintr(void); + int intno = _sbd_getfpuintr(); + intrupt(intno, cop1Patcher, 0); + mips_bissr(SR_IM0 << intno); +#endif + +#if (#cpu(r4640) || #cpu(r4650)) && !defined(SINGLE_ONLY_FPU) + /* For R4640/R4650 compiled *without* the -msingle-float flag, + then we share responsibility: the h/w handles the single + precision operations, and the trap emulator handles the + double precision. We set fpuemuactive so that dbg.c first + fetches the s/w state before saving the h/w state. */ + fpuemuactive = 1; + { + int i; + /* initialise the unused d.p high order words to be NaN */ + for (i = 0; i < 32; i++) + current->thread.fpu.soft.regs[i] = + 0x7ff80bad00000000LL; + } +#endif /* (r4640 || r4650) && !fpu(single) */ + } +} +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_add.c linux.ac/arch/mips/math-emu/dp_add.c --- linux.vanilla/arch/mips/math-emu/dp_add.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_add.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,186 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + CLEARCX; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "add", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "add", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "add", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs == ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + else + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + /* FALL THROUGH */ + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + ym = XDPSRS(ym, s); + ye += s; + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + xm = XDPSRS(xm, s); + xe += s; + } + assert(xe == ye); + assert(xe <= DP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + * leaving result in xm,xs,xe + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + xm = XDPSRS1(xm); + xe++; + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + /* normalize to rounding precision */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + + } + DPNORMRET2(xs, xe, xm, "add", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_cmp.c linux.ac/arch/mips/math-emu/dp_cmp.c --- linux.vanilla/arch/mips/math-emu/dp_cmp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_cmp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp) +{ + CLEARCX; + + if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { + if (cmp & IEEE754_CUN) + return 1; + if (cmp & (IEEE754_CLT | IEEE754_CGT)) { + if (SETCX(IEEE754_INVALID_OPERATION)) + return ieee754si_xcpt(0, "fcmpf", x); + } + return 0; + } else { + long long int vx = x.bits; + long long int vy = y.bits; + + if (vx < 0) + vx = -vx ^ DP_SIGN_BIT; + if (vy < 0) + vy = -vy ^ DP_SIGN_BIT; + + if (vx < vy) + return (cmp & IEEE754_CLT) != 0; + else if (vx == vy) + return (cmp & IEEE754_CEQ) != 0; + else + return (cmp & IEEE754_CGT) != 0; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_div.c linux.ac/arch/mips/math-emu/dp_div.c --- linux.vanilla/arch/mips/math-emu/dp_div.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_div.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,160 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "div", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "div", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "div", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return ieee754dp_zero(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return ieee754dp_inf(xs ^ ys); + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + SETCX(IEEE754_ZERO_DIVIDE); + return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ieee754dp_zero(xs == ys ? 0 : 1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* provide rounding space */ + xm <<= 3; + ym <<= 3; + + { + /* now the dirty work */ + + unsigned long long rm = 0; + int re = xe - ye; + unsigned long long bm; + + for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; + } + xm <<= 1; + } + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ + + assert(rm); + + /* normalise rm to rounding precision ? + */ + while ((rm >> (DP_MBITS + 3)) == 0) { + rm <<= 1; + re--; + } + + DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_fint.c linux.ac/arch/mips/math-emu/dp_fint.c --- linux.vanilla/arch/mips/math-emu/dp_fint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_fint.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,78 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_fint(int x) +{ + COMPXDP; + + CLEARCX; + + if (x == 0) + return ieee754dp_zero(0); + if (x == 1 || x == -1) + return ieee754dp_one(x < 0); + if (x == 10 || x == -10) + return ieee754dp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1 << 31)) + xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + +#if 1 + /* normalize - result can never be inexact or overflow */ + xe = DP_MBITS; + while ((xm >> DP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +#else + /* normalize */ + xe = DP_MBITS + 3; + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + DPNORMRET1(xs, xe, xm, "fint", x); +#endif +} + +ieee754dp ieee754dp_funs(unsigned int u) +{ + if ((int) u < 0) + return ieee754dp_add(ieee754dp_1e31(), + ieee754dp_fint(u & ~(1 << 31))); + return ieee754dp_fint(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_flong.c linux.ac/arch/mips/math-emu/dp_flong.c --- linux.vanilla/arch/mips/math-emu/dp_flong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_flong.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,76 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_flong(long long x) +{ + COMPXDP; + + CLEARCX; + + if (x == 0) + return ieee754dp_zero(0); + if (x == 1 || x == -1) + return ieee754dp_one(x < 0); + if (x == 10 || x == -10) + return ieee754dp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1ULL << 63)) + xm = (1ULL << 63); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + + /* normalize */ + xe = DP_MBITS + 3; + if (xm >> (DP_MBITS + 1 + 3)) { + /* shunt out overflow bits */ + while (xm >> (DP_MBITS + 1 + 3)) { + XDPSRSX1(); + } + } else { + /* normalize in grs extended double precision */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + DPNORMRET1(xs, xe, xm, "dp_flong", x); +} + +ieee754dp ieee754dp_fulong(unsigned long long u) +{ + if ((long long) u < 0) + return ieee754dp_add(ieee754dp_1e63(), + ieee754dp_flong(u & ~(1ULL << 63))); + return ieee754dp_flong(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_frexp.c linux.ac/arch/mips/math-emu/dp_frexp.c --- linux.vanilla/arch/mips/math-emu/dp_frexp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_frexp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,53 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +/* close to ieeep754dp_logb +*/ +ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr) +{ + COMPXDP; + CLEARCX; + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *eptr = 0; + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + *eptr = xe + 1; + return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_fsp.c linux.ac/arch/mips/math-emu/dp_fsp.c --- linux.vanilla/arch/mips/math-emu/dp_fsp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_fsp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,70 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_fsp(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(builddp(xs, + DP_EMAX + 1 + DP_EBIAS, + ((unsigned long long) xm + << (DP_MBITS - + SP_MBITS))), "fsp", + x); + case IEEE754_CLASS_INF: + return ieee754dp_inf(xs); + case IEEE754_CLASS_ZERO: + return ieee754dp_zero(xs); + case IEEE754_CLASS_DNORM: + /* normalize */ + while ((xm >> SP_MBITS) == 0) { + xm <<= 1; + xe--; + } + break; + case IEEE754_CLASS_NORM: + break; + } + + /* CANT possibly overflow,underflow, or need rounding + */ + + /* drop the hidden bit */ + xm &= ~SP_HIDDEN_BIT; + + return builddp(xs, xe + DP_EBIAS, + (unsigned long long) xm << (DP_MBITS - SP_MBITS)); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_logb.c linux.ac/arch/mips/math-emu/dp_logb.c --- linux.vanilla/arch/mips/math-emu/dp_logb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_logb.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,54 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_logb(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(x, "logb", x); + case IEEE754_CLASS_QNAN: + return x; + case IEEE754_CLASS_INF: + return ieee754dp_inf(0); + case IEEE754_CLASS_ZERO: + return ieee754dp_inf(1); + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + return ieee754dp_fint(xe); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_modf.c linux.ac/arch/mips/math-emu/dp_modf.c --- linux.vanilla/arch/mips/math-emu/dp_modf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_modf.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,80 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +/* modf function is always exact for a finite number +*/ +ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *ip = x; + return x; + case IEEE754_CLASS_DNORM: + /* far to small */ + *ip = ieee754dp_zero(xs); + return x; + case IEEE754_CLASS_NORM: + break; + } + if (xe < 0) { + *ip = ieee754dp_zero(xs); + return x; + } + if (xe >= DP_MBITS) { + *ip = x; + return ieee754dp_zero(xs); + } + /* generate ipart mantissa by clearing bottom bits + */ + *ip = builddp(xs, xe + DP_EBIAS, + ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) & + ~DP_HIDDEN_BIT); + + /* generate fpart mantissa by clearing top bits + * and normalizing (must be able to normalize) + */ + xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe)); + if (xm == 0) + return ieee754dp_zero(xs); + + while ((xm >> DP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_mul.c linux.ac/arch/mips/math-emu/dp_mul.c --- linux.vanilla/arch/mips/math-emu/dp_mul.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_mul.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,180 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "mul", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754dp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return ieee754dp_zero(xs ^ ys); + + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* rm = xm * ym, re = xe+ye basicly */ + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + { + int re = xe + ye; + int rs = xs ^ ys; + unsigned long long rm; + + /* shunt to top of word */ + xm <<= 64 - (DP_MBITS + 1); + ym <<= 64 - (DP_MBITS + 1); + + /* multiply 32bits xm,ym to give high 32bits rm with stickness + */ + + /* 32 * 32 => 64 */ +#define DPXMULT(x,y) ((unsigned long long)(x) * (unsigned long long)y) + + { + unsigned lxm = xm; + unsigned hxm = xm >> 32; + unsigned lym = ym; + unsigned hym = ym >> 32; + unsigned long long lrm; + unsigned long long hrm; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + { + unsigned long long t = DPXMULT(lxm, hym); + { + unsigned long long at = + lrm + (t << 32); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 32); + } + + { + unsigned long long t = DPXMULT(hxm, lym); + { + unsigned long long at = + lrm + (t << 32); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 32); + } + rm = hrm | (lrm != 0); + } + + /* + * sticky shift down to normal rounding precision + */ + if ((signed long long) rm < 0) { + rm = + (rm >> (64 - (DP_MBITS + 1 + 3))) | + ((rm << (DP_MBITS + 1 + 3)) != 0); + re++; + } else { + rm = + (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) | + ((rm << (DP_MBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (DP_HIDDEN_BIT << 3)); + DPNORMRET2(rs, re, rm, "mul", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_scalb.c linux.ac/arch/mips/math-emu/dp_scalb.c --- linux.vanilla/arch/mips/math-emu/dp_scalb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_scalb.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_scalb(ieee754dp x, int n) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(x, "scalb", x, n); + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); +} + + +ieee754dp ieee754dp_ldexp(ieee754dp x, int n) +{ + return ieee754dp_scalb(x, n); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_simple.c linux.ac/arch/mips/math-emu/dp_simple.c --- linux.vanilla/arch/mips/math-emu/dp_simple.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_simple.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,66 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_finite(ieee754dp x) +{ + return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; +} + +ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y) +{ + CLEARCX; + DPSIGN(x) = DPSIGN(y); + return x; +} + + +ieee754dp ieee754dp_neg(ieee754dp x) +{ + CLEARCX; + + if (ieee754dp_isnan(x)) /* but not infinity */ + return ieee754dp_nanxcpt(x, "neg", x); + + /* quick fix up */ + DPSIGN(x) ^= 1; + return x; +} + + +ieee754dp ieee754dp_abs(ieee754dp x) +{ + CLEARCX; + + if (ieee754dp_isnan(x)) /* but not infinity */ + return ieee754dp_nanxcpt(x, "abs", x); + + /* quick fix up */ + DPSIGN(x) = 0; + return x; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_sqrt.c linux.ac/arch/mips/math-emu/dp_sqrt.c --- linux.vanilla/arch/mips/math-emu/dp_sqrt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_sqrt.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,167 @@ +/* IEEE754 floating point arithmetic + * double precision square root + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +static const struct ieee754dp_konst knan = { +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) + 0, 0, DP_EBIAS + DP_EMAX + 1, 0 +#else + 0, DP_EBIAS + DP_EMAX + 1, 0, 0 +#endif +}; + +#define nan ((ieee754dp)knan) + +static const unsigned table[] = { + 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, + 29598, 36145, 43202, 50740, 58733, 67158, 75992, + 85215, 83599, 71378, 60428, 50647, 41945, 34246, + 27478, 21581, 16499, 12183, 8588, 5674, 3403, + 1742, 661, 130 +}; + +ieee754dp ieee754dp_sqrt(ieee754dp x) +{ + struct ieee754_csr oldcsr; + ieee754dp y, z, t; + unsigned scalx, yh; + COMPXDP; + + EXPLODEXDP; + + /* x == INF or NAN? */ + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + /* sqrt(Nan) = Nan */ + return ieee754dp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_ZERO: + /* sqrt(0) = 0 */ + return x; + case IEEE754_CLASS_INF: + if (xs) + /* sqrt(-Inf) = Nan */ + return ieee754dp_nanxcpt(nan, "sqrt"); + /* sqrt(+Inf) = Inf */ + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + /* fall through */ + case IEEE754_CLASS_NORM: + if (xs) + /* sqrt(-x) = Nan */ + return ieee754dp_nanxcpt(nan, "sqrt"); + break; + } + + /* save old csr; switch off INX enable & flag; set RN rounding */ + oldcsr = ieee754_csr; + ieee754_csr.mx &= ~IEEE754_INEXACT; + ieee754_csr.sx &= ~IEEE754_INEXACT; + ieee754_csr.rm = IEEE754_RN; + + /* adjust exponent to prevent overflow */ + scalx = 0; + if (xe > 512) { /* x > 2**-512? */ + xe -= 512; /* x = x / 2**512 */ + scalx += 256; + } else if (xe < -512) { /* x < 2**-512? */ + xe += 512; /* x = x * 2**512 */ + scalx -= 256; + } + + y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + + /* magic initial approximation to almost 8 sig. bits */ + yh = y.bits >> 32; + yh = (yh >> 1) + 0x1ff80000; + yh = yh - table[(yh >> 15) & 31]; + y.bits = ((unsigned long long) yh << 32) | (y.bits & 0xffffffff); + + /* Heron's rule once with correction to improve to ~18 sig. bits */ + /* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */ + t = ieee754dp_div(x, y); + y = ieee754dp_add(y, t); + y.bits -= 0x0010000600000000LL; + y.bits &= 0xffffffff00000000LL; + + /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ + /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ + z = t = ieee754dp_mul(y, y); + t.parts.bexp += 0x001; + t = ieee754dp_add(t, z); + z = ieee754dp_mul(ieee754dp_sub(x, z), y); + + /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ + t = ieee754dp_div(z, ieee754dp_add(t, x)); + t.parts.bexp += 0x001; + y = ieee754dp_add(y, t); + + /* twiddle last bit to force y correctly rounded */ + + /* set RZ, clear INEX flag */ + ieee754_csr.rm = IEEE754_RZ; + ieee754_csr.sx &= ~IEEE754_INEXACT; + + /* t=x/y; ...chopped quotient, possibly inexact */ + t = ieee754dp_div(x, y); + + if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) { + + if (!(ieee754_csr.sx & IEEE754_INEXACT)) + /* t = t-ulp */ + t.bits -= 1; + + /* add inexact to result status */ + oldcsr.cx |= IEEE754_INEXACT; + oldcsr.sx |= IEEE754_INEXACT; + + switch (oldcsr.rm) { + case IEEE754_RP: + y.bits += 1; + /* drop through */ + case IEEE754_RN: + t.bits += 1; + break; + } + + /* y=y+t; ...chopped sum */ + y = ieee754dp_add(y, t); + + /* adjust scalx for correctly rounded sqrt(x) */ + scalx -= 1; + } + + /* py[n0]=py[n0]+scalx; ...scale back y */ + y.parts.bexp += scalx; + + /* restore rounding mode, possibly set inexact */ + ieee754_csr = oldcsr; + + return y; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_sub.c linux.ac/arch/mips/math-emu/dp_sub.c --- linux.vanilla/arch/mips/math-emu/dp_sub.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_sub.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,193 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "sub", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs != ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + return ieee754dp_inf(ys ^ 1); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs != ys) + return x; + else + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + /* quick fix up */ + DPSIGN(y) ^= 1; + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + /* FAAL THOROUGH */ + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + /* normalize ym,ye */ + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + /* normalize xm,xe */ + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* flip sign of y and handle as add */ + ys ^= 1; + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + + /* provide guard,round and stick bit dpace */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + ym = XDPSRS(ym, s); + ye += s; + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + xm = XDPSRS(xm, s); + xe += s; + } + assert(xe == ye); + assert(xe <= DP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + xm = XDPSRS1(xm); /* shift preserving sticky */ + xe++; + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + if (ieee754_csr.rm == IEEE754_RD) + return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ + else + return ieee754dp_zero(0); /* other round modes => sign = 1 */ + + /* normalize to rounding precision + */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + DPNORMRET2(xs, xe, xm, "sub", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_tint.c linux.ac/arch/mips/math-emu/dp_tint.c --- linux.vanilla/arch/mips/math-emu/dp_tint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_tint.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,88 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include +#include "ieee754dp.h" + +int ieee754dp_tint(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fixdp", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 31) { + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fix", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fix", x); + } + /* oh gawd */ + if (xe > DP_MBITS) { + xm <<= xe - DP_MBITS; + } else if (xe < DP_MBITS) { + /* XXX no rounding + */ + xm >>= DP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned int ieee754dp_tuns(ieee754dp x) +{ + ieee754dp hb = ieee754dp_1e31(); + + /* what if x < 0 ?? */ + if (ieee754dp_lt(x, hb)) + return (unsigned) ieee754dp_tint(x); + + return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) | + ((unsigned) 1 << 31); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/dp_tlong.c linux.ac/arch/mips/math-emu/dp_tlong.c --- linux.vanilla/arch/mips/math-emu/dp_tlong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/dp_tlong.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,141 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +long long ieee754dp_tlong(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much too small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "dp_tlong", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 63) { + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + } + if (xe < 0) { + if (ieee754_csr.rm == IEEE754_RU) { + if (xs) { /* Negative */ + return 0x0000000000000000LL; + } else { /* Positive */ + return 0x0000000000000001LL; + } + } else if (ieee754_csr.rm == IEEE754_RD) { + if (xs) { /* Negative , return -1 */ + return 0xffffffffffffffffLL; + } else { /* Positive */ + return 0x0000000000000000LL; + } + } else { + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "dp_tlong", x); + } + } + /* oh gawd */ + if (xe > DP_MBITS) { + xm <<= xe - DP_MBITS; + } else if (xe < DP_MBITS) { + unsigned long long residue; + unsigned long long mask = 0; + int i; + int round; + int sticky; + int odd; + + /* compute mask */ + for (i = 0; i < DP_MBITS - xe; i++) { + mask = mask << 1; + mask = mask | 0x1; + } + residue = (xm & mask) << (64 - (DP_MBITS - xe)); + round = + ((0x8000000000000000LL & residue) != + 0x0000000000000000LL); + sticky = + ((0x7fffffffffffffffLL & residue) != + 0x0000000000000000LL); + + xm >>= DP_MBITS - xe; + + odd = ((xm & 0x1) != 0x0000000000000000LL); + + /* Do the rounding */ + if (!round && sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs)) { + xm++; + } + } else if (round && !sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs) + || (ieee754_csr.rm == IEEE754_RN && odd)) { + xm++; + } + } else if (round && sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs) + || (ieee754_csr.rm == IEEE754_RN)) { + xm++; + } + } + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned long long ieee754dp_tulong(ieee754dp x) +{ + ieee754dp hb = ieee754dp_1e63(); + + /* what if x < 0 ?? */ + if (ieee754dp_lt(x, hb)) + return (unsigned long long) ieee754dp_tlong(x); + + return (unsigned long long) ieee754dp_tlong(ieee754dp_sub(x, hb)) | + (1ULL << 63); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754.c linux.ac/arch/mips/math-emu/ieee754.c --- linux.vanilla/arch/mips/math-emu/ieee754.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,138 @@ +/* ieee754 floating point arithmetic + * single and double precision + * + * BUGS + * not much dp done + * doesnt generate IEEE754_INEXACT + * + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 + +/* indexed by class */ +const char *const ieee754_cname[] = { + "Normal", + "Zero", + "Denormal", + "Infinity", + "QNaN", + "SNaN", +}; + +/* the control status register +*/ +struct ieee754_csr ieee754_csr; + +/* special constants +*/ + + +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) +#define SPSTR(s,b,m) {m,b,s} +#define DPSTR(s,b,mh,ml) {ml,mh,b,s} +#endif + +#ifdef __MIPSEB__ +#define SPSTR(s,b,m) {s,b,m} +#define DPSTR(s,b,mh,ml) {s,b,mh,ml} +#endif + +const struct ieee754dp_konst __ieee754dp_spcvals[] = { + DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */ + DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */ + DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */ + DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */ + DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */ + DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ + DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ + DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ + DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x40000, 0), /* + indef quiet Nan */ + DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ + DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ + DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ + DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0), /* - min normal */ + DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */ + DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */ + DPSTR(0, 31 + DP_EBIAS, 0, 0), /* + 1.0e31 */ + DPSTR(0, 63 + DP_EBIAS, 0, 0), /* + 1.0e63 */ +}; + +const struct ieee754sp_konst __ieee754sp_spcvals[] = { + SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */ + SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */ + SPSTR(0, SP_EBIAS, 0), /* + 1.0 */ + SPSTR(1, SP_EBIAS, 0), /* - 1.0 */ + SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */ + SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ + SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ + SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ + SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x200000), /* + indef quiet Nan */ + SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ + SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ + SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ + SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */ + SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */ + SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */ + SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */ + SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */ +}; + + +int ieee754si_xcpt(int r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + ax.op = op; + ax.rt = IEEE754_RT_SI; + ax.rv.si = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.si; +} + +long long ieee754di_xcpt(long long r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + ax.op = op; + ax.rt = IEEE754_RT_DI; + ax.rv.di = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.di; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754.h linux.ac/arch/mips/math-emu/ieee754.h --- linux.vanilla/arch/mips/math-emu/ieee754.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754.h Wed Apr 18 13:51:25 2001 @@ -0,0 +1,490 @@ +/* single and double precision fp ops + * missing extended precision. +*/ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Modification to allow integration with Linux kernel + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#ifdef __KERNEL__ +/* Going from Algorithmics to Linux native environment, add this */ +#include + +/* + * Not very pretty, but the Linux kernel's normal va_list definition + * does not allow it to be used as a structure element, as it is here. + */ +#ifndef _STDARG_H +#include +#endif + +#else + +/* Note that __KERNEL__ is taken to mean Linux kernel */ + +#if #system(OpenBSD) +#include +#endif +#include + +#endif /* __KERNEL__ */ + +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) +struct ieee754dp_konst { + unsigned mantlo:32; + unsigned manthi:20; + unsigned bexp:11; + unsigned sign:1; +}; +struct ieee754sp_konst { + unsigned mant:23; + unsigned bexp:8; + unsigned sign:1; +}; + +typedef union _ieee754dp { + struct ieee754dp_konst oparts; + struct { + unsigned long long mant:52; + unsigned int bexp:11; + unsigned int sign:1; + } parts; + unsigned long long bits; + double d; +} ieee754dp; + +typedef union _ieee754sp { + struct ieee754sp_konst parts; + float f; + unsigned long bits; +} ieee754sp; +#endif + +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) +struct ieee754dp_konst { + unsigned sign:1; + unsigned bexp:11; + unsigned manthi:20; + unsigned mantlo:32; +}; +typedef union _ieee754dp { + struct ieee754dp_konst oparts; + struct { + unsigned int sign:1; + unsigned int bexp:11; + unsigned long long mant:52; + } parts; + double d; + unsigned long long bits; +} ieee754dp; + +struct ieee754sp_konst { + unsigned sign:1; + unsigned bexp:8; + unsigned mant:23; +}; + +typedef union _ieee754sp { + struct ieee754sp_konst parts; + float f; + unsigned long bits; +} ieee754sp; +#endif + +/* + * single precision (often aka float) +*/ +int ieee754sp_finite(ieee754sp x); +int ieee754sp_class(ieee754sp x); + +ieee754sp ieee754sp_abs(ieee754sp x); +ieee754sp ieee754sp_neg(ieee754sp x); +ieee754sp ieee754sp_scalb(ieee754sp x, int); +ieee754sp ieee754sp_logb(ieee754sp x); + +/* x with sign of y */ +ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y); + +ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y); + +ieee754sp ieee754sp_fint(int x); +ieee754sp ieee754sp_funs(unsigned x); +ieee754sp ieee754sp_flong(long long x); +ieee754sp ieee754sp_fulong(unsigned long long x); +ieee754sp ieee754sp_fdp(ieee754dp x); + +int ieee754sp_tint(ieee754sp x); +unsigned int ieee754sp_tuns(ieee754sp x); +long long ieee754sp_tlong(ieee754sp x); +unsigned long long ieee754sp_tulong(ieee754sp x); + +int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop); +/* + * basic sp math + */ +ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip); +ieee754sp ieee754sp_frexp(ieee754sp x, int *exp); +ieee754sp ieee754sp_ldexp(ieee754sp x, int exp); + +ieee754sp ieee754sp_ceil(ieee754sp x); +ieee754sp ieee754sp_floor(ieee754sp x); +ieee754sp ieee754sp_trunc(ieee754sp x); + +ieee754sp ieee754sp_sqrt(ieee754sp x); + +/* + * double precision (often aka double) +*/ +int ieee754dp_finite(ieee754dp x); +int ieee754dp_class(ieee754dp x); + +/* x with sign of y */ +ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); + +ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); + +ieee754dp ieee754dp_abs(ieee754dp x); +ieee754dp ieee754dp_neg(ieee754dp x); +ieee754dp ieee754dp_scalb(ieee754dp x, int); + +/* return exponent as integer in floating point format + */ +ieee754dp ieee754dp_logb(ieee754dp x); + +ieee754dp ieee754dp_fint(int x); +ieee754dp ieee754dp_funs(unsigned x); +ieee754dp ieee754dp_flong(long long x); +ieee754dp ieee754dp_fulong(unsigned long long x); +ieee754dp ieee754dp_fsp(ieee754sp x); + +ieee754dp ieee754dp_ceil(ieee754dp x); +ieee754dp ieee754dp_floor(ieee754dp x); +ieee754dp ieee754dp_trunc(ieee754dp x); + +int ieee754dp_tint(ieee754dp x); +unsigned int ieee754dp_tuns(ieee754dp x); +long long ieee754dp_tlong(ieee754dp x); +unsigned long long ieee754dp_tulong(ieee754dp x); + +int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop); +/* + * basic sp math + */ +ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip); +ieee754dp ieee754dp_frexp(ieee754dp x, int *exp); +ieee754dp ieee754dp_ldexp(ieee754dp x, int exp); + +ieee754dp ieee754dp_ceil(ieee754dp x); +ieee754dp ieee754dp_floor(ieee754dp x); +ieee754dp ieee754dp_trunc(ieee754dp x); + +ieee754dp ieee754dp_sqrt(ieee754dp x); + + + +/* 5 types of floating point number +*/ +#define IEEE754_CLASS_NORM 0x00 +#define IEEE754_CLASS_ZERO 0x01 +#define IEEE754_CLASS_DNORM 0x02 +#define IEEE754_CLASS_INF 0x03 +#define IEEE754_CLASS_SNAN 0x04 +#define IEEE754_CLASS_QNAN 0x05 +extern const char *const ieee754_cname[]; + +/* exception numbers */ +#define IEEE754_INEXACT 0x01 +#define IEEE754_UNDERFLOW 0x02 +#define IEEE754_OVERFLOW 0x04 +#define IEEE754_ZERO_DIVIDE 0x08 +#define IEEE754_INVALID_OPERATION 0x10 + +/* cmp operators +*/ +#define IEEE754_CLT 0x01 +#define IEEE754_CEQ 0x02 +#define IEEE754_CGT 0x04 +#define IEEE754_CUN 0x08 + +/* rounding mode +*/ +#define IEEE754_RN 0 /* round to nearest */ +#define IEEE754_RZ 1 /* round toward zero */ +#define IEEE754_RD 2 /* round toward -Infinity */ +#define IEEE754_RU 3 /* round toward +Infinity */ + +/* other naming */ +#define IEEE754_RM IEEE754_RD +#define IEEE754_RP IEEE754_RU + +/* "normal" comparisons +*/ +static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CEQ); +} + +static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN); +} + +static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CLT); +} + +static __inline int ieee754sp_le(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ); +} + +static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CGT); +} + + +static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ); +} + +static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CEQ); +} + +static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN); +} + +static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CLT); +} + +static __inline int ieee754dp_le(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ); +} + +static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CGT); +} + +static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ); +} + + +/* like strtod +*/ +ieee754dp ieee754dp_fstr(const char *s, char **endp); +char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); + + +/* the control status register +*/ +struct ieee754_csr { + unsigned pad:13; + unsigned noq:1; /* set 1 for no quiet NaN's */ + unsigned nod:1; /* set 1 for no denormalised numbers */ + unsigned cx:5; /* exceptions this operation */ + unsigned mx:5; /* exception enable mask */ + unsigned sx:5; /* exceptions total */ + unsigned rm:2; /* current rounding mode */ +}; +extern struct ieee754_csr ieee754_csr; + +static __inline unsigned ieee754_getrm(void) +{ + return (ieee754_csr.rm); +} +static __inline unsigned ieee754_setrm(unsigned rm) +{ + return (ieee754_csr.rm = rm); +} + +/* + * get current exceptions + */ +static __inline unsigned ieee754_getcx(void) +{ + return (ieee754_csr.cx); +} + +/* test for current exception condition + */ +static __inline int ieee754_cxtest(unsigned n) +{ + return (ieee754_csr.cx & n); +} + +/* + * get sticky exceptions + */ +static __inline unsigned ieee754_getsx(void) +{ + return (ieee754_csr.sx); +} + +/* clear sticky conditions +*/ +static __inline unsigned ieee754_clrsx(void) +{ + return (ieee754_csr.sx = 0); +} + +/* test for sticky exception condition + */ +static __inline int ieee754_sxtest(unsigned n) +{ + return (ieee754_csr.sx & n); +} + +/* debugging */ +ieee754sp ieee754sp_dump(char *s, ieee754sp x); +ieee754dp ieee754dp_dump(char *s, ieee754dp x); + +#define IEEE754_SPCVAL_PZERO 0 +#define IEEE754_SPCVAL_NZERO 1 +#define IEEE754_SPCVAL_PONE 2 +#define IEEE754_SPCVAL_NONE 3 +#define IEEE754_SPCVAL_PTEN 4 +#define IEEE754_SPCVAL_NTEN 5 +#define IEEE754_SPCVAL_PINFINITY 6 +#define IEEE754_SPCVAL_NINFINITY 7 +#define IEEE754_SPCVAL_INDEF 8 +#define IEEE754_SPCVAL_PMAX 9 /* +max norm */ +#define IEEE754_SPCVAL_NMAX 10 /* -max norm */ +#define IEEE754_SPCVAL_PMIN 11 /* +min norm */ +#define IEEE754_SPCVAL_NMIN 12 /* +min norm */ +#define IEEE754_SPCVAL_PMIND 13 /* +min denorm */ +#define IEEE754_SPCVAL_NMIND 14 /* +min denorm */ +#define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ +#define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ + +extern const struct ieee754dp_konst __ieee754dp_spcvals[]; +extern const struct ieee754sp_konst __ieee754sp_spcvals[]; +#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) +#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) + +/* return infinity with given sign +*/ +#define ieee754dp_inf(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) +#define ieee754dp_zero(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) +#define ieee754dp_one(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) +#define ieee754dp_ten(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) +#define ieee754dp_indef() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754dp_max(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) +#define ieee754dp_min(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) +#define ieee754dp_mind(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) +#define ieee754dp_1e31() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31]) +#define ieee754dp_1e63() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63]) + +#define ieee754sp_inf(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) +#define ieee754sp_zero(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) +#define ieee754sp_one(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) +#define ieee754sp_ten(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) +#define ieee754sp_indef() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754sp_max(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) +#define ieee754sp_min(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) +#define ieee754sp_mind(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) +#define ieee754sp_1e31() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31]) +#define ieee754sp_1e63() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63]) + +/* indefinite integer value +*/ +#define ieee754si_indef() INT_MIN +#ifdef LONG_LONG_MIN +#define ieee754di_indef() LONG_LONG_MIN +#else +#define ieee754di_indef() (-9223372036854775807LL-1) +#endif + +/* IEEE exception context, passed to handler */ +struct ieee754xctx { + const char *op; /* operation name */ + int rt; /* result type */ + union { + ieee754sp sp; /* single precision */ + ieee754dp dp; /* double precision */ +#ifdef IEEE854_XP + ieee754xp xp; /* extended precision */ +#endif + int si; /* standard signed integer (32bits) */ + long long di; /* extended signed integer (64bits) */ + } rv; /* default result format implied by op */ + va_list ap; +}; + +/* result types for xctx.rt */ +#define IEEE754_RT_SP 0 +#define IEEE754_RT_DP 1 +#define IEEE754_RT_XP 2 +#define IEEE754_RT_SI 3 +#define IEEE754_RT_DI 4 + +extern void ieee754_xcpt(struct ieee754xctx *xcp); + +/* compat */ +#define ieee754dp_fix(x) ieee754dp_tint(x) +#define ieee754sp_fix(x) ieee754sp_tint(x) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754d.c linux.ac/arch/mips/math-emu/ieee754d.c --- linux.vanilla/arch/mips/math-emu/ieee754d.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754d.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,142 @@ +/* some debug functions +*/ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Modified to build and operate in Linux kernel environment. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#include "ieee754.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 +#define DP_FBITS 52 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 +#define SP_FBITS 23 + +#define DP_MBIT(x) ((unsigned long long)1 << (x)) +#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) +#define DP_SIGN_BIT DP_MBIT(63) + + +#define SP_MBIT(x) ((unsigned long)1 << (x)) +#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) +#define SP_SIGN_BIT SP_MBIT(31) + + +#define SPSIGN(sp) (sp.parts.sign) +#define SPBEXP(sp) (sp.parts.bexp) +#define SPMANT(sp) (sp.parts.mant) + +#define DPSIGN(dp) (dp.parts.sign) +#define DPBEXP(dp) (dp.parts.bexp) +#define DPMANT(dp) (dp.parts.mant) + +ieee754dp ieee754dp_dump(char *m, ieee754dp x) +{ + int i; + + printk("%s", m); + printk("<%08x,%08x>\n", (unsigned) (x.bits >> 32), + (unsigned) x.bits); + printk("\t="); + switch (ieee754dp_class(x)) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + printk("Nan %c", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + break; + case IEEE754_CLASS_INF: + printk("%cInfinity", DPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_ZERO: + printk("%cZero", DPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_DNORM: + printk("%c0.", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + printk("e%d", DPBEXP(x) - DP_EBIAS); + break; + case IEEE754_CLASS_NORM: + printk("%c1.", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + printk("e%d", DPBEXP(x) - DP_EBIAS); + break; + default: + printk("Illegal/Unknown IEEE754 value class"); + } + printk("\n"); + return x; +} + +ieee754sp ieee754sp_dump(char *m, ieee754sp x) +{ + int i; + + printk("%s=", m); + printk("<%08x>\n", (unsigned) x.bits); + printk("\t="); + switch (ieee754sp_class(x)) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + printk("Nan %c", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + break; + case IEEE754_CLASS_INF: + printk("%cInfinity", SPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_ZERO: + printk("%cZero", SPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_DNORM: + printk("%c0.", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + printk("e%d", SPBEXP(x) - SP_EBIAS); + break; + case IEEE754_CLASS_NORM: + printk("%c1.", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + printk("e%d", SPBEXP(x) - SP_EBIAS); + break; + default: + printk("Illegal/Unknown IEEE754 value class"); + } + printk("\n"); + return x; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754dp.c linux.ac/arch/mips/math-emu/ieee754dp.c --- linux.vanilla/arch/mips/math-emu/ieee754dp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754dp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,197 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_class(ieee754dp x) +{ + COMPXDP; + EXPLODEXDP; + return xc; +} + +int ieee754dp_isnan(ieee754dp x) +{ + return ieee754dp_class(x) >= IEEE754_CLASS_SNAN; +} + +int ieee754dp_issnan(ieee754dp x) +{ + assert(ieee754dp_isnan(x)); + if (ieee754_csr.noq) + return 1; + return !(DPMANT(x) & DP_MBIT(DP_MBITS - 1)); +} + + +ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...) +{ + struct ieee754xctx ax; + if (!TSTX()) + return r; + + ax.op = op; + ax.rt = IEEE754_RT_DP; + ax.rv.dp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.dp; +} + +ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...) +{ + struct ieee754xctx ax; + + assert(ieee754dp_isnan(r)); + + if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ + return r; + + if (!SETCX(IEEE754_INVALID_OPERATION)) { + /* not enabled convert to a quiet NaN */ + if (ieee754_csr.noq) + return r; + DPMANT(r) |= DP_MBIT(DP_MBITS - 1); + return r; + } + + ax.op = op; + ax.rt = 0; + ax.rv.dp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.dp; +} + +ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y) +{ + assert(ieee754dp_isnan(x)); + assert(ieee754dp_isnan(y)); + + if (DPMANT(x) > DPMANT(y)) + return x; + else + return y; +} + + +/* generate a normal/denormal number with over,under handeling + * sn is sign + * xe is an unbiased exponent + * xm is 3bit extended precision value. + */ +ieee754dp ieee754dp_format(int sn, int xe, unsigned long long xm) +{ + assert(xm); /* we dont gen exact zeros (probably should) */ + + assert((xm >> (DP_MBITS + 1 + 3)) == 0); /* no execess */ + assert(xm & (DP_HIDDEN_BIT << 3)); + + if (xe < DP_EMIN) { + /* strip lower bits */ + int es = DP_EMIN - xe; + + if (ieee754_csr.nod) { + SETCX(IEEE754_UNDERFLOW); + return ieee754dp_zero(sn); + } + + /* sticky right shift es bits + */ + xm = XDPSRS(xm, es); + xe += es; + + assert((xm & (DP_HIDDEN_BIT << 3)) == 0); + assert(xe == DP_EMIN); + } + if (xm & (DP_MBIT(3) - 1)) { + SETCX(IEEE754_INEXACT); + /* inexact must round of 3 bits + */ + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + /* adjust exponent for rounding add overflowing + */ + if (xm >> (DP_MBITS + 3 + 1)) { /* add causes mantissa overflow */ + xm >>= 1; + xe++; + } + } + /* strip grs bits */ + xm >>= 3; + + assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert(xe >= DP_EMIN); + + if (xe > DP_EMAX) { + SETCX(IEEE754_OVERFLOW); + /* -O can be table indexed by (rm,sn) */ + switch (ieee754_csr.rm) { + case IEEE754_RN: + return ieee754dp_inf(sn); + case IEEE754_RZ: + return ieee754dp_max(sn); + case IEEE754_RU: /* toward +Infinity */ + if (sn == 0) + return ieee754dp_inf(0); + else + return ieee754dp_max(1); + case IEEE754_RD: /* toward -Infinity */ + if (sn == 0) + return ieee754dp_max(0); + else + return ieee754dp_inf(1); + } + } + /* gen norm/denorm/zero */ + + if ((xm & DP_HIDDEN_BIT) == 0) { + /* we underflow (tiny/zero) */ + assert(xe == DP_EMIN); + SETCX(IEEE754_UNDERFLOW); + return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); + } else { + assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert(xm & DP_HIDDEN_BIT); + + return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754dp.h linux.ac/arch/mips/math-emu/ieee754dp.h --- linux.vanilla/arch/mips/math-emu/ieee754dp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754dp.h Wed Apr 18 13:51:25 2001 @@ -0,0 +1,83 @@ +/* + * IEEE754 floating point + * double precision internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define assert(expr) ((void)0) + +/* 3bit extended double precision sticky right shift */ +#define XDPSRS(v,rs) \ + ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) + +#define XDPSRSX1() \ + (xe++, (xm = (xm >> 1) | (xm & 1))) + +#define XDPSRS1(v) \ + (((v) >> 1) | ((v) & 1)) + +/* convert denormal to normalized with extended exponent */ +#define DPDNORMx(m,e) \ + while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } +#define DPDNORMX DPDNORMx(xm,xe) +#define DPDNORMY DPDNORMx(ym,ye) + +static __inline ieee754dp builddp(int s, int bx, unsigned long long m) +{ + ieee754dp r; + + assert((s) == 0 || (s) == 1); + assert((bx) >= DP_EMIN - 1 + DP_EBIAS + && (bx) <= DP_EMAX + 1 + DP_EBIAS); + assert(((m) >> DP_MBITS) == 0); + + r.parts.sign = s; + r.parts.bexp = bx; + r.parts.mant = m; + return r; +} + +extern int ieee754dp_isnan(ieee754dp); +extern int ieee754dp_issnan(ieee754dp); +extern int ieee754si_xcpt(int, const char *, ...); +extern long long ieee754di_xcpt(long long, const char *, ...); +extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...); +extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...); +extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp); +extern ieee754dp ieee754dp_format(int, int, unsigned long long); + + +#define DPNORMRET2(s,e,m,name,a0,a1) \ +{ \ + ieee754dp V = ieee754dp_format(s,e,m); \ + if(TSTX()) \ + return ieee754dp_xcpt(V,name,a0,a1); \ + else \ + return V; \ +} + +#define DPNORMRET1(s,e,m,name,a0) DPNORMRET2(s,e,m,name,a0,a0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754int.h linux.ac/arch/mips/math-emu/ieee754int.h --- linux.vanilla/arch/mips/math-emu/ieee754int.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754int.h Wed Apr 18 13:51:25 2001 @@ -0,0 +1,135 @@ +/* + * IEEE754 floating point + * common internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 +#define DP_MBITS 52 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 +#define SP_MBITS 23 + +#define DP_MBIT(x) ((unsigned long long)1 << (x)) +#define DP_HIDDEN_BIT DP_MBIT(DP_MBITS) +#define DP_SIGN_BIT DP_MBIT(63) + +#define SP_MBIT(x) ((unsigned long)1 << (x)) +#define SP_HIDDEN_BIT SP_MBIT(SP_MBITS) +#define SP_SIGN_BIT SP_MBIT(31) + + +#define SPSIGN(sp) (sp.parts.sign) +#define SPBEXP(sp) (sp.parts.bexp) +#define SPMANT(sp) (sp.parts.mant) + +#define DPSIGN(dp) (dp.parts.sign) +#define DPBEXP(dp) (dp.parts.bexp) +#define DPMANT(dp) (dp.parts.mant) + +#define CLPAIR(x,y) ((x)*6+(y)) + +#define CLEARCX \ + (ieee754_csr.cx = 0) + +#define SETCX(x) \ + (ieee754_csr.cx |= (x),ieee754_csr.sx |= (x),ieee754_csr.mx & (x)) + +#define TSTX() \ + (ieee754_csr.cx & ieee754_csr.mx) + + +#define COMPXSP \ + unsigned xm; int xe; int xs; int xc + +#define COMPYSP \ + unsigned ym; int ye; int ys; int yc + +#define EXPLODESP(v,vc,vs,ve,vm) \ +{\ + vs = SPSIGN(v);\ + ve = SPBEXP(v);\ + vm = SPMANT(v);\ + if(ve == SP_EMAX+1+SP_EBIAS){\ + if(vm == 0)\ + vc = IEEE754_CLASS_INF;\ + else if(vm & SP_MBIT(SP_MBITS-1)) \ + vc = IEEE754_CLASS_QNAN;\ + else \ + vc = IEEE754_CLASS_SNAN;\ + } else if(ve == SP_EMIN-1+SP_EBIAS) {\ + if(vm) {\ + ve = SP_EMIN;\ + vc = IEEE754_CLASS_DNORM;\ + } else\ + vc = IEEE754_CLASS_ZERO;\ + } else {\ + ve -= SP_EBIAS;\ + vm |= SP_HIDDEN_BIT;\ + vc = IEEE754_CLASS_NORM;\ + }\ +} +#define EXPLODEXSP EXPLODESP(x,xc,xs,xe,xm) +#define EXPLODEYSP EXPLODESP(y,yc,ys,ye,ym) + + +#define COMPXDP \ +unsigned long long xm; int xe; int xs; int xc + +#define COMPYDP \ +unsigned long long ym; int ye; int ys; int yc + +#define EXPLODEDP(v,vc,vs,ve,vm) \ +{\ + vm = DPMANT(v);\ + vs = DPSIGN(v);\ + ve = DPBEXP(v);\ + if(ve == DP_EMAX+1+DP_EBIAS){\ + if(vm == 0)\ + vc = IEEE754_CLASS_INF;\ + else if(vm & DP_MBIT(DP_MBITS-1)) \ + vc = IEEE754_CLASS_QNAN;\ + else \ + vc = IEEE754_CLASS_SNAN;\ + } else if(ve == DP_EMIN-1+DP_EBIAS) {\ + if(vm) {\ + ve = DP_EMIN;\ + vc = IEEE754_CLASS_DNORM;\ + } else\ + vc = IEEE754_CLASS_ZERO;\ + } else {\ + ve -= DP_EBIAS;\ + vm |= DP_HIDDEN_BIT;\ + vc = IEEE754_CLASS_NORM;\ + }\ +} +#define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm) +#define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754m.c linux.ac/arch/mips/math-emu/ieee754m.c --- linux.vanilla/arch/mips/math-emu/ieee754m.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754m.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,56 @@ +/* + * floor, trunc, ceil + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754.h" + +ieee754dp ieee754dp_floor(ieee754dp x) +{ + ieee754dp i; + + if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) + return ieee754dp_sub(i, ieee754dp_one(0)); + else + return i; +} + +ieee754dp ieee754dp_ceil(ieee754dp x) +{ + ieee754dp i; + + if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) + return ieee754dp_add(i, ieee754dp_one(0)); + else + return i; +} + +ieee754dp ieee754dp_trunc(ieee754dp x) +{ + ieee754dp i; + + (void) ieee754dp_modf(x, &i); + return i; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754sp.c linux.ac/arch/mips/math-emu/ieee754sp.c --- linux.vanilla/arch/mips/math-emu/ieee754sp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754sp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,197 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_class(ieee754sp x) +{ + COMPXSP; + EXPLODEXSP; + return xc; +} + +int ieee754sp_isnan(ieee754sp x) +{ + return ieee754sp_class(x) >= IEEE754_CLASS_SNAN; +} + +int ieee754sp_issnan(ieee754sp x) +{ + assert(ieee754sp_isnan(x)); + if (ieee754_csr.noq) + return 1; + return !(SPMANT(x) & SP_MBIT(SP_MBITS - 1)); +} + + +ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + + ax.op = op; + ax.rt = IEEE754_RT_SP; + ax.rv.sp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.sp; +} + +ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...) +{ + struct ieee754xctx ax; + + assert(ieee754sp_isnan(r)); + + if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ + return r; + + if (!SETCX(IEEE754_INVALID_OPERATION)) { + /* not enabled convert to a quiet NaN */ + if (ieee754_csr.noq) + return r; + SPMANT(r) |= SP_MBIT(SP_MBITS - 1); + return r; + } + + ax.op = op; + ax.rt = 0; + ax.rv.sp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.sp; +} + +ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y) +{ + assert(ieee754sp_isnan(x)); + assert(ieee754sp_isnan(y)); + + if (SPMANT(x) > SPMANT(y)) + return x; + else + return y; +} + + +/* generate a normal/denormal number with over,under handeling + * sn is sign + * xe is an unbiased exponent + * xm is 3bit extended precision value. + */ +ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) +{ + assert(xm); /* we dont gen exact zeros (probably should) */ + + assert((xm >> (SP_MBITS + 1 + 3)) == 0); /* no execess */ + assert(xm & (SP_HIDDEN_BIT << 3)); + + if (xe < SP_EMIN) { + /* strip lower bits */ + int es = SP_EMIN - xe; + + if (ieee754_csr.nod) { + SETCX(IEEE754_UNDERFLOW); + return ieee754sp_zero(sn); + } + + /* sticky right shift es bits + */ + SPXSRSXn(es); + + assert((xm & (SP_HIDDEN_BIT << 3)) == 0); + assert(xe == SP_EMIN); + } + if (xm & (SP_MBIT(3) - 1)) { + SETCX(IEEE754_INEXACT); + /* inexact must round of 3 bits + */ + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + /* adjust exponent for rounding add overflowing + */ + if (xm >> (SP_MBITS + 1 + 3)) { /* add causes mantissa overflow */ + xm >>= 1; + xe++; + } + } + /* strip grs bits */ + xm >>= 3; + + assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert(xe >= SP_EMIN); + + if (xe > SP_EMAX) { + SETCX(IEEE754_OVERFLOW); + /* -O can be table indexed by (rm,sn) */ + switch (ieee754_csr.rm) { + case IEEE754_RN: + return ieee754sp_inf(sn); + case IEEE754_RZ: + return ieee754sp_max(sn); + case IEEE754_RU: /* toward +Infinity */ + if (sn == 0) + return ieee754sp_inf(0); + else + return ieee754sp_max(1); + case IEEE754_RD: /* toward -Infinity */ + if (sn == 0) + return ieee754sp_max(0); + else + return ieee754sp_inf(1); + } + } + /* gen norm/denorm/zero */ + + if ((xm & SP_HIDDEN_BIT) == 0) { + /* we underflow (tiny/zero) */ + assert(xe == SP_EMIN); + SETCX(IEEE754_UNDERFLOW); + return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); + } else { + assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert(xm & SP_HIDDEN_BIT); + + return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754sp.h linux.ac/arch/mips/math-emu/ieee754sp.h --- linux.vanilla/arch/mips/math-emu/ieee754sp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754sp.h Wed Apr 18 13:51:25 2001 @@ -0,0 +1,89 @@ +/* + * IEEE754 floating point + * double precision internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define assert(expr) ((void)0) + +/* 3bit extended single precision sticky right shift */ +#define SPXSRSXn(rs) \ + (xe += rs, \ + xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) + +#define SPXSRSX1() \ + (xe++, (xm = (xm >> 1) | (xm & 1))) + +#define SPXSRSYn(rs) \ + (ye+=rs, \ + ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) + +#define SPXSRSY1() \ + (ye++, (ym = (ym >> 1) | (ym & 1))) + +/* convert denormal to normalized with extended exponent */ +#define SPDNORMx(m,e) \ + while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } +#define SPDNORMX SPDNORMx(xm,xe) +#define SPDNORMY SPDNORMx(ym,ye) + +static __inline ieee754sp buildsp(int s, int bx, unsigned m) +{ + ieee754sp r; + + assert((s) == 0 || (s) == 1); + assert((bx) >= SP_EMIN - 1 + SP_EBIAS + && (bx) <= SP_EMAX + 1 + SP_EBIAS); + assert(((m) >> SP_MBITS) == 0); + + r.parts.sign = s; + r.parts.bexp = bx; + r.parts.mant = m; + + return r; +} + +extern int ieee754sp_isnan(ieee754sp); +extern int ieee754sp_issnan(ieee754sp); +extern int ieee754si_xcpt(int, const char *, ...); +extern long long ieee754di_xcpt(long long, const char *, ...); +extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...); +extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...); +extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp); +extern ieee754sp ieee754sp_format(int, int, unsigned); + + +#define SPNORMRET2(s,e,m,name,a0,a1) \ +{ \ + ieee754sp V = ieee754sp_format(s,e,m); \ + if(TSTX()) \ + return ieee754sp_xcpt(V,name,a0,a1); \ + else \ + return V; \ +} + +#define SPNORMRET1(s,e,m,name,a0) SPNORMRET2(s,e,m,name,a0,a0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/ieee754xcpt.c linux.ac/arch/mips/math-emu/ieee754xcpt.c --- linux.vanilla/arch/mips/math-emu/ieee754xcpt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/ieee754xcpt.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,48 @@ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Added preprocessor hacks to map to Linux kernel diagnostics. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#include "ieee754.h" + +/* + * Very naff exception handler (you can plug in your own and + * override this). + */ + +static const char *const rtnames[] = { + "sp", "dp", "xp", "si", "di" +}; + +void ieee754_xcpt(struct ieee754xctx *xcp) +{ + printk("floating point exception in \"%s\", type=%s\n", + xcp->op, rtnames[xcp->rt]); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/kernel_linkage.c linux.ac/arch/mips/math-emu/kernel_linkage.c --- linux.vanilla/arch/mips/math-emu/kernel_linkage.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/kernel_linkage.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,95 @@ +/************************************************************************** + * + * arch/mips/math_emu/kernel_linkage.c + * + * Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + *************************************************************************/ +/* + * Routines corresponding to Linux kernel FP context + * manipulation primitives for the Algorithmics MIPS + * FPU Emulator + */ + +#include +#include +#include +#include + +#include + +extern struct mips_fpu_emulator_private fpuemuprivate; + +#define SIGNALLING_NAN 0x7ff800007ff80000LL + +void fpu_emulator_init_fpu(void) +{ + static int first = 1; + int i; + + if (first) { + first = 0; + printk("Algorithmics/MIPS FPU Emulator v1.4\n"); + } + + current->thread.fpu.soft.sr = 0; + for (i = 0; i < 32; i++) { + current->thread.fpu.soft.regs[i] = SIGNALLING_NAN; + } +} + + +/* + * Emulator context save/restore to/from a signal context + * presumed to be on the user stack, and therefore accessed + * with appropriate macros from uaccess.h + */ + +int fpu_emulator_save_context(struct sigcontext *sc) +{ + int i; + int err = 0; + + for (i = 0; i < 32; i++) { + err |= + __put_user(current->thread.fpu.soft.regs[i], + &sc->sc_fpregs[i]); + } + err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); + err |= __put_user(fpuemuprivate.eir, &sc->sc_fpc_eir); + + return err; +} + +int fpu_emulator_restore_context(struct sigcontext *sc) +{ + int i; + int err = 0; + + for (i = 0; i < 32; i++) { + err |= + __get_user(current->thread.fpu.soft.regs[i], + &sc->sc_fpregs[i]); + } + err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); + err |= __get_user(fpuemuprivate.eir, &sc->sc_fpc_eir); + + return err; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_add.c linux.ac/arch/mips/math-emu/sp_add.c --- linux.vanilla/arch/mips/math-emu/sp_add.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_add.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,180 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + CLEARCX; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "add", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "add", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "add", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs == ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + else + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + SPXSRSYn(s); + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + SPXSRSXn(s); + } + assert(xe == ye); + assert(xe <= SP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + * leaving result in xm,xs,xe + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + /* normalize in extended single precision */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + + } + SPNORMRET2(xs, xe, xm, "add", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_cmp.c linux.ac/arch/mips/math-emu/sp_cmp.c --- linux.vanilla/arch/mips/math-emu/sp_cmp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_cmp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp) +{ + CLEARCX; + + if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { + if (cmp & IEEE754_CUN) + return 1; + if (cmp & (IEEE754_CLT | IEEE754_CGT)) { + if (SETCX(IEEE754_INVALID_OPERATION)) + return ieee754si_xcpt(0, "fcmpf", x); + } + return 0; + } else { + int vx = x.bits; + int vy = y.bits; + + if (vx < 0) + vx = -vx ^ SP_SIGN_BIT; + if (vy < 0) + vy = -vy ^ SP_SIGN_BIT; + + if (vx < vy) + return (cmp & IEEE754_CLT) != 0; + else if (vx == vy) + return (cmp & IEEE754_CEQ) != 0; + else + return (cmp & IEEE754_CGT) != 0; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_div.c linux.ac/arch/mips/math-emu/sp_div.c --- linux.vanilla/arch/mips/math-emu/sp_div.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_div.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,160 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "div", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "div", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "div", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return ieee754sp_zero(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return ieee754sp_inf(xs ^ ys); + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + SETCX(IEEE754_ZERO_DIVIDE); + return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ieee754sp_zero(xs == ys ? 0 : 1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* provide rounding space */ + xm <<= 3; + ym <<= 3; + + { + /* now the dirty work */ + + unsigned rm = 0; + int re = xe - ye; + unsigned bm; + + for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; + } + xm <<= 1; + } + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ + + assert(rm); + + /* normalise rm to rounding precision ? + */ + while ((rm >> (SP_MBITS + 3)) == 0) { + rm <<= 1; + re--; + } + + SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_fdp.c linux.ac/arch/mips/math-emu/sp_fdp.c --- linux.vanilla/arch/mips/math-emu/sp_fdp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_fdp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,69 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_fdp(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(buildsp(xs, + SP_EMAX + 1 + SP_EBIAS, + (unsigned long) + (xm >> + (DP_MBITS - SP_MBITS))), + "fdp", x); + case IEEE754_CLASS_INF: + return ieee754sp_inf(xs); + case IEEE754_CLASS_ZERO: + return ieee754sp_zero(xs); + case IEEE754_CLASS_DNORM: + /* cant possibly be sp representable */ + SETCX(IEEE754_UNDERFLOW); + return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); + case IEEE754_CLASS_NORM: + break; + } + + { + unsigned long rm; + + /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift + */ + rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) | + ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0); + + SPNORMRET1(xs, xe, rm, "fdp", x); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_fint.c linux.ac/arch/mips/math-emu/sp_fint.c --- linux.vanilla/arch/mips/math-emu/sp_fint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_fint.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,78 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_fint(int x) +{ + COMPXSP; + + CLEARCX; + + if (x == 0) + return ieee754sp_zero(0); + if (x == 1 || x == -1) + return ieee754sp_one(x < 0); + if (x == 10 || x == -10) + return ieee754sp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1 << 31)) + xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + xe = SP_MBITS + 3; + + if (xm >> (SP_MBITS + 1 + 3)) { + /* shunt out overflow bits + */ + while (xm >> (SP_MBITS + 1 + 3)) { + SPXSRSX1(); + } + } else { + /* normalize in grs extended single precision + */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET1(xs, xe, xm, "fint", x); +} + + +ieee754sp ieee754sp_funs(unsigned int u) +{ + if ((int) u < 0) + return ieee754sp_add(ieee754sp_1e31(), + ieee754sp_fint(u & ~(1 << 31))); + return ieee754sp_fint(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_flong.c linux.ac/arch/mips/math-emu/sp_flong.c --- linux.vanilla/arch/mips/math-emu/sp_flong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_flong.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,77 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_flong(long long x) +{ + COMPXDP; /* <--- need 64-bit mantissa temp */ + + CLEARCX; + + if (x == 0) + return ieee754sp_zero(0); + if (x == 1 || x == -1) + return ieee754sp_one(x < 0); + if (x == 10 || x == -10) + return ieee754sp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1ULL << 63)) + xm = (1ULL << 63); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + xe = SP_MBITS + 3; + + if (xm >> (SP_MBITS + 1 + 3)) { + /* shunt out overflow bits + */ + while (xm >> (SP_MBITS + 1 + 3)) { + SPXSRSX1(); + } + } else { + /* normalize in grs extended single precision */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET1(xs, xe, xm, "sp_flong", x); +} + + +ieee754sp ieee754sp_fulong(unsigned long long u) +{ + if ((long long) u < 0) + return ieee754sp_add(ieee754sp_1e63(), + ieee754sp_flong(u & ~(1ULL << 63))); + return ieee754sp_flong(u); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_frexp.c linux.ac/arch/mips/math-emu/sp_frexp.c --- linux.vanilla/arch/mips/math-emu/sp_frexp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_frexp.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,53 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +/* close to ieeep754sp_logb +*/ +ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr) +{ + COMPXSP; + CLEARCX; + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *eptr = 0; + return x; + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + *eptr = xe + 1; + return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_logb.c linux.ac/arch/mips/math-emu/sp_logb.c --- linux.vanilla/arch/mips/math-emu/sp_logb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_logb.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,54 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_logb(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(x, "logb", x); + case IEEE754_CLASS_QNAN: + return x; + case IEEE754_CLASS_INF: + return ieee754sp_inf(0); + case IEEE754_CLASS_ZERO: + return ieee754sp_inf(1); + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + return ieee754sp_fint(xe); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_modf.c linux.ac/arch/mips/math-emu/sp_modf.c --- linux.vanilla/arch/mips/math-emu/sp_modf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_modf.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,80 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +/* modf function is always exact for a finite number +*/ +ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *ip = x; + return x; + case IEEE754_CLASS_DNORM: + /* far to small */ + *ip = ieee754sp_zero(xs); + return x; + case IEEE754_CLASS_NORM: + break; + } + if (xe < 0) { + *ip = ieee754sp_zero(xs); + return x; + } + if (xe >= SP_MBITS) { + *ip = x; + return ieee754sp_zero(xs); + } + /* generate ipart mantissa by clearing bottom bits + */ + *ip = buildsp(xs, xe + SP_EBIAS, + ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) & + ~SP_HIDDEN_BIT); + + /* generate fpart mantissa by clearing top bits + * and normalizing (must be able to normalize) + */ + xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe)); + if (xm == 0) + return ieee754sp_zero(xs); + + while ((xm >> SP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_mul.c linux.ac/arch/mips/math-emu/sp_mul.c --- linux.vanilla/arch/mips/math-emu/sp_mul.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_mul.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,174 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "mul", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754sp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return ieee754sp_zero(xs ^ ys); + + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* rm = xm * ym, re = xe+ye basicly */ + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + { + int re = xe + ye; + int rs = xs ^ ys; + unsigned rm; + + /* shunt to top of word */ + xm <<= 32 - (SP_MBITS + 1); + ym <<= 32 - (SP_MBITS + 1); + + /* multiply 32bits xm,ym to give high 32bits rm with stickness + */ + { + unsigned short lxm = xm & 0xffff; + unsigned short hxm = xm >> 16; + unsigned short lym = ym & 0xffff; + unsigned short hym = ym >> 16; + unsigned lrm; + unsigned hrm; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + { + unsigned t = lxm * hym; /* 16 * 16 => 32 */ + { + unsigned at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 16); + } + + { + unsigned t = hxm * lym; /* 16 * 16 => 32 */ + { + unsigned at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 16); + } + rm = hrm | (lrm != 0); + } + + /* + * sticky shift down to normal rounding precision + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_MBITS + 1 + 3))) | + ((rm << (SP_MBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) | + ((rm << (SP_MBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (SP_HIDDEN_BIT << 3)); + + SPNORMRET2(rs, re, rm, "mul", x, y); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_scalb.c linux.ac/arch/mips/math-emu/sp_scalb.c --- linux.vanilla/arch/mips/math-emu/sp_scalb.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_scalb.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_scalb(ieee754sp x, int n) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(x, "scalb", x, n); + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + return x; + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); +} + + +ieee754sp ieee754sp_ldexp(ieee754sp x, int n) +{ + return ieee754sp_scalb(x, n); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_simple.c linux.ac/arch/mips/math-emu/sp_simple.c --- linux.vanilla/arch/mips/math-emu/sp_simple.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_simple.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,66 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_finite(ieee754sp x) +{ + return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; +} + +ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y) +{ + CLEARCX; + SPSIGN(x) = SPSIGN(y); + return x; +} + + +ieee754sp ieee754sp_neg(ieee754sp x) +{ + CLEARCX; + + if (ieee754sp_isnan(x)) /* but not infinity */ + return ieee754sp_nanxcpt(x, "neg", x); + + /* quick fix up */ + SPSIGN(x) ^= 1; + return x; +} + + +ieee754sp ieee754sp_abs(ieee754sp x) +{ + CLEARCX; + + if (ieee754sp_isnan(x)) /* but not infinity */ + return ieee754sp_nanxcpt(x, "abs", x); + + /* quick fix up */ + SPSIGN(x) = 0; + return x; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_sqrt.c linux.ac/arch/mips/math-emu/sp_sqrt.c --- linux.vanilla/arch/mips/math-emu/sp_sqrt.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_sqrt.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,115 @@ +/* IEEE754 floating point arithmetic + * single precision square root + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +static const struct ieee754sp_konst knan = { + 0, SP_EBIAS + SP_EMAX + 1, 0 +}; + +#define nan ((ieee754sp)knan) + +ieee754sp ieee754sp_sqrt(ieee754sp x) +{ + int sign = (int) 0x80000000; + int ix, s, q, m, t, i; + unsigned int r; + COMPXDP; + + /* take care of Inf and NaN */ + + EXPLODEXDP; + + /* x == INF or NAN? */ + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + /* sqrt(Nan) = Nan */ + return ieee754sp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_ZERO: + /* sqrt(0) = 0 */ + return x; + case IEEE754_CLASS_INF: + if (xs) + /* sqrt(-Inf) = Nan */ + return ieee754sp_nanxcpt(nan, "sqrt"); + /* sqrt(+Inf) = Inf */ + return x; + case IEEE754_CLASS_DNORM: + case IEEE754_CLASS_NORM: + if (xs) + /* sqrt(-x) = Nan */ + return ieee754sp_nanxcpt(nan, "sqrt"); + break; + } + + ix = x.bits; + + /* normalize x */ + m = (ix >> 23); + if (m == 0) { /* subnormal x */ + for (i = 0; (ix & 0x00800000) == 0; i++) + ix <<= 1; + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if (m & 1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s + r; + if (t <= ix) { + s = t + r; + ix -= t; + q += r; + } + ix += ix; + r >>= 1; + } + + if (ix != 0) { + switch (ieee754_csr.rm) { + case IEEE754_RP: + q += 2; + break; + case IEEE754_RN: + q += (q & 1); + break; + } + } + ix = (q >> 1) + 0x3f000000; + ix += (m << 23); + x.bits = ix; + return x; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_sub.c linux.ac/arch/mips/math-emu/sp_sub.c --- linux.vanilla/arch/mips/math-emu/sp_sub.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_sub.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,187 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "sub", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs != ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + return ieee754sp_inf(ys ^ 1); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs != ys) + return x; + else + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + /* quick fix up */ + DPSIGN(y) ^= 1; + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* flip sign of y and handle as add */ + ys ^= 1; + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + SPXSRSYn(s); + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + SPXSRSXn(s); + } + assert(xe == ye); + assert(xe <= SP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); /* shift preserving sticky */ + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + if (ieee754_csr.rm == IEEE754_RD) + return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ + else + return ieee754sp_zero(0); /* other round modes => sign = 1 */ + + /* normalize to rounding precision + */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET2(xs, xe, xm, "sub", x, y); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_tint.c linux.ac/arch/mips/math-emu/sp_tint.c --- linux.vanilla/arch/mips/math-emu/sp_tint.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_tint.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,88 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include +#include "ieee754sp.h" + +int ieee754sp_tint(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fixsp", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 31) { + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fix", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fix", x); + } + /* oh gawd */ + if (xe > SP_MBITS) { + xm <<= xe - SP_MBITS; + } else if (xe < SP_MBITS) { + /* XXX no rounding + */ + xm >>= SP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned int ieee754sp_tuns(ieee754sp x) +{ + ieee754sp hb = ieee754sp_1e31(); + + /* what if x < 0 ?? */ + if (ieee754sp_lt(x, hb)) + return (unsigned) ieee754sp_tint(x); + + return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) | + ((unsigned) 1 << 31); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/math-emu/sp_tlong.c linux.ac/arch/mips/math-emu/sp_tlong.c --- linux.vanilla/arch/mips/math-emu/sp_tlong.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/math-emu/sp_tlong.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,87 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +long long ieee754sp_tlong(ieee754sp x) +{ + COMPXDP; /* <-- need 64-bit mantissa tmp */ + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "sp_tlong", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 63) { + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "sp_tlong", x); + } + /* oh gawd */ + if (xe > SP_MBITS) { + xm <<= xe - SP_MBITS; + } else if (xe < SP_MBITS) { + /* XXX no rounding + */ + xm >>= SP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned long long ieee754sp_tulong(ieee754sp x) +{ + ieee754sp hb = ieee754sp_1e63(); + + /* what if x < 0 ?? */ + if (ieee754sp_lt(x, hb)) + return (unsigned long long) ieee754sp_tlong(x); + + return (unsigned long long) ieee754sp_tlong(ieee754sp_sub(x, hb)) | + (1ULL << 63); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/Makefile linux.ac/arch/mips/mips-boards/atlas/Makefile --- linux.vanilla/arch/mips/mips-boards/atlas/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/Makefile Wed Apr 18 13:51:25 2001 @@ -0,0 +1,42 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# ######################################################################## +# +# This program is free software; you can distribute it 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 it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# ####################################################################### +# +# Makefile for the MIPS Atlas specific kernel interface routines +# under Linux. +# +# 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 definitions are now in the main makefile... + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: atlas.o + +O_TARGET := atlas.o + +obj-y := atlas_int.o atlas_rtc.o atlas_setup.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/atlas_int.c linux.ac/arch/mips/mips-boards/atlas/atlas_int.c --- linux.vanilla/arch/mips/mips-boards/atlas/atlas_int.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/atlas_int.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,248 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Routines for generic manipulation of the interrupts found on the MIPS + * Atlas board. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +struct atlas_ictrl_regs *atlas_hw0_icregs + = (struct atlas_ictrl_regs *)ATLAS_ICTRL_REGS_BASE; + +extern asmlinkage void mipsIRQ(void); +extern void do_IRQ(int irq, struct pt_regs *regs); + +unsigned long spurious_count = 0; +irq_desc_t irq_desc[NR_IRQS]; + +#if 0 +#define DEBUG_INT(x...) printk(x) +#else +#define DEBUG_INT(x...) +#endif + +void disable_atlas_irq(unsigned int irq_nr) +{ + atlas_hw0_icregs->intrsten = (1 << irq_nr); +} + +void enable_atlas_irq(unsigned int irq_nr) +{ + atlas_hw0_icregs->intseten = (1 << irq_nr); +} + +static unsigned int startup_atlas_irq(unsigned int irq) +{ + enable_atlas_irq(irq); + return 0; /* never anything pending */ +} + +#define shutdown_atlas_irq disable_atlas_irq + +#define mask_and_ack_atlas_irq disable_atlas_irq + +static void end_atlas_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_atlas_irq(irq); +} + +static struct hw_interrupt_type atlas_irq_type = { + "Atlas", + startup_atlas_irq, + shutdown_atlas_irq, + enable_atlas_irq, + disable_atlas_irq, + mask_and_ack_atlas_irq, + end_atlas_irq, + NULL +}; + +int get_irq_list(char *buf) +{ + int i, len = 0; + int num = 0; + struct irqaction *action; + + for (i = 0; i < ATLASINT_END; i++, num++) { + action = irq_desc[i].action; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + num, kstat.irqs[0][num], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, " [hw0]\n"); + } + return len; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + struct irqaction *action; + + DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname); + + if (irq >= ATLASINT_END) + 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->dev_id = dev_id; + action->next = 0; + irq_desc[irq].action = action; + enable_atlas_irq(irq); + + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action; + + if (irq >= ATLASINT_END) { + printk("Trying to free IRQ%d\n",irq); + return; + } + + action = irq_desc[irq].action; + irq_desc[irq].action = NULL; + disable_atlas_irq(irq); + kfree(action); +} + +static inline int ls1bit32(unsigned int x) +{ + int b = 31, s; + + s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; + s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; + s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; + s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; + s = 1; if (x << 1 == 0) s = 0; b -= s; + + return b; +} + +void atlas_hw0_irqdispatch(struct pt_regs *regs) +{ + struct irqaction *action; + unsigned long int_status; + int irq, cpu = smp_processor_id(); + + int_status = atlas_hw0_icregs->intstatus; + + /* if int_status == 0, then the interrupt has already been cleared */ + if (int_status == 0) + return; + + irq = ls1bit32(int_status); + action = irq_desc[irq].action; + + DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); + + /* if action == NULL, then we don't have a handler for the irq */ + if ( action == NULL ) { + printk("No handler for hw0 irq: %i\n", irq); + spurious_count++; + return; + } + + irq_enter(cpu, irq); + kstat.irqs[0][irq]++; + action->handler(irq, action->dev_id, regs); + irq_exit(cpu, irq); + + return; +} + +unsigned long probe_irq_on (void) +{ + return 0; +} + + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +#ifdef CONFIG_REMOTE_DEBUG +extern void breakpoint(void); +extern int remote_debug; +#endif + +void __init init_IRQ(void) +{ + int i; + + /* + * Mask out all interrupt by writing "1" to all bit position in + * the interrupt reset reg. + */ + atlas_hw0_icregs->intrsten = 0xffffffff; + + /* Now safe to set the exception vector. */ + set_except_vector(0, mipsIRQ); + + for (i = 0; i <= ATLASINT_END; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &atlas_irq_type; + } + +#ifdef CONFIG_REMOTE_DEBUG + if (remote_debug) { + set_debug_traps(); + breakpoint(); + } +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/atlas_rtc.c linux.ac/arch/mips/mips-boards/atlas/atlas_rtc.c --- linux.vanilla/arch/mips/mips-boards/atlas/atlas_rtc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/atlas_rtc.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,58 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * RTC routines for Atlas style attached Dallas chip. + * + */ +#include +#include +#include + + +static unsigned char atlas_rtc_read_data(unsigned long addr) +{ + volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG; + volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG; + + *rtc_adr_reg = addr; + + return *rtc_dat_reg; +} + +static void atlas_rtc_write_data(unsigned char data, unsigned long addr) +{ + volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG; + volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG; + + *rtc_adr_reg = addr; + *rtc_dat_reg = data; +} + +static int atlas_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops atlas_rtc_ops = { + &atlas_rtc_read_data, + &atlas_rtc_write_data, + &atlas_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/atlas/atlas_setup.c linux.ac/arch/mips/mips-boards/atlas/atlas_setup.c --- linux.vanilla/arch/mips/mips-boards/atlas/atlas_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/atlas/atlas_setup.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,115 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Atlas specific setup. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +extern void saa9730_kgdb_hook(void); +extern void breakpoint(void); +int remote_debug = 0; +#endif + +extern struct rtc_ops atlas_rtc_ops; + +extern void mips_reboot_setup(void); + +void __init atlas_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + int rs_putDebugChar(char); + char rs_getDebugChar(void); + int saa9730_putDebugChar(char); + char saa9730_getDebugChar(void); + extern int (*putDebugChar)(char); + extern char (*getDebugChar)(void); +#endif + char *argptr; + + ioport_resource.end = 0x7fffffff; + +#ifdef CONFIG_SERIAL_CONSOLE + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) { + int i = 0; + char *s = prom_getenv("modetty0"); + while(s[i] >= '0' && s[i] <= '9') + i++; + strcpy(serial_console, "ttyS0,"); + strncpy(serial_console + 6, s, i); + prom_printf("Config serial console: %s\n", serial_console); + console_setup(serial_console, NULL); + } +#endif + +#ifdef CONFIG_REMOTE_DEBUG + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { + int line; + argptr += strlen("kgdb=ttyS"); + if (*argptr != '0' && *argptr != '1') + printk("KGDB: Uknown serial line /dev/ttyS%c, " + "falling back to /dev/ttyS1\n", *argptr); + line = *argptr == '0' ? 0 : 1; + printk("KGDB: Using serial line /dev/ttyS%d for session\n", + line ? 1 : 0); + + if(line == 0) { + rs_kgdb_hook(line); + putDebugChar = rs_putDebugChar; + getDebugChar = rs_getDebugChar; + } else { + saa9730_kgdb_hook(); + putDebugChar = saa9730_putDebugChar; + getDebugChar = saa9730_getDebugChar; + } + + prom_printf("KGDB: Using serial line /dev/ttyS%d for session, " + "please connect your debugger\n", line ? 1 : 0); + + remote_debug = 1; + /* Breakpoints and stuff are in atlas_irq_setup() */ + } +#endif + argptr = prom_getcmdline(); + + if ((argptr = strstr(argptr, "nofpu")) != NULL) + mips_cpu.options &= ~MIPS_CPU_FPU; + + rtc_ops = &atlas_rtc_ops; + + mips_reboot_setup(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/Makefile linux.ac/arch/mips/mips-boards/generic/Makefile --- linux.vanilla/arch/mips/mips-boards/generic/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/Makefile Wed Apr 18 13:51:25 2001 @@ -0,0 +1,41 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# ######################################################################## +# +# This program is free software; you can distribute it 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 it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# ####################################################################### +# +# Makefile for the MIPS boards generic routines under Linux. +# +# 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 definitions are now in the main makefile... + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := mipsboards.o + +obj-y := mipsIRQ.o pci.o reset.o display.o init.o \ + memory.o printf.o cmdline.o time.o +obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/cmdline.c linux.ac/arch/mips/mips-boards/generic/cmdline.c --- linux.vanilla/arch/mips/mips-boards/generic/cmdline.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/cmdline.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,53 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Kernel command line creation using the prom monitor (YAMON) argc/argv. + */ +#include +#include + +#include + +extern int prom_argc; +extern char **prom_argv; + +char arcs_cmdline[COMMAND_LINE_SIZE]; + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/display.c linux.ac/arch/mips/mips-boards/generic/display.c --- linux.vanilla/arch/mips/mips-boards/generic/display.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/display.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,47 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Display routines for display messages in MIPS boards ascii display. + * + */ + +#include + + +void mips_display_message(const char *str) +{ + volatile unsigned int *display = (void *)ASCII_DISPLAY_POS_BASE; + int i; + + for (i = 0; i <= 14; i=i+2) { + if (*str) + display[i] = *str++; + else + display[i] = ' '; + } +} + +void mips_display_word(unsigned int num) +{ + volatile unsigned int *display = (void *)ASCII_DISPLAY_WORD_BASE; + + *display = num; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/gdb_hook.c linux.ac/arch/mips/mips-boards/generic/gdb_hook.c --- linux.vanilla/arch/mips/mips-boards/generic/gdb_hook.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/gdb_hook.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,205 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * This is the interface to the remote debugger stub. + * + */ + +#include +#include +#include + +#include +#include + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +static struct async_struct kdb_port_info = {0}; + +int (*putDebugChar)(char); +char (*getDebugChar)(void); + +static __inline__ unsigned int serial_in(struct async_struct *info, int offset) +{ + return inb(info->port + offset); +} + +static __inline__ void serial_out(struct async_struct *info, int offset, + int value) +{ + outb(value, info->port+offset); +} + +void rs_kgdb_hook(int tty_no) { + int t; + struct serial_state *ser = &rs_table[tty_no]; + + kdb_port_info.state = ser; + kdb_port_info.magic = SERIAL_MAGIC; + kdb_port_info.port = ser->port; + kdb_port_info.flags = ser->flags; + + /* + * Clear all interrupts + */ + serial_in(&kdb_port_info, UART_LSR); + serial_in(&kdb_port_info, UART_RX); + serial_in(&kdb_port_info, UART_IIR); + serial_in(&kdb_port_info, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + if (kdb_port_info.flags & ASYNC_FOURPORT) { + kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS; + t = UART_MCR_DTR | UART_MCR_OUT1; + } else { + kdb_port_info.MCR + = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + t = UART_MCR_DTR | UART_MCR_RTS; + } + + kdb_port_info.MCR = t; /* no interrupts, please */ + serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR); + + /* + * and set the speed of the serial port + * (currently hardwired to 9600 8N1 + */ + + /* baud rate is fixed to 9600 (is this sufficient?)*/ + t = kdb_port_info.state->baud_base / 9600; + /* set DLAB */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */ + serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */ + /* reset DLAB */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); +} + +int rs_putDebugChar(char c) +{ + + if (!kdb_port_info.state) { /* need to init device first */ + return 0; + } + + while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0) + ; + + serial_out(&kdb_port_info, UART_TX, c); + + return 1; +} + +char rs_getDebugChar(void) +{ + if (!kdb_port_info.state) { /* need to init device first */ + return 0; + } + + while (!(serial_in(&kdb_port_info, UART_LSR) & 1)) + ; + + return(serial_in(&kdb_port_info, UART_RX)); +} + + +#ifdef CONFIG_MIPS_ATLAS + +#include +#include + +#define INB(a) inb((unsigned long)a) +#define OUTB(x,a) outb(x,(unsigned long)a) + +/* + * This is the interface to the remote debugger stub + * if the Philips part is used for the debug port, + * called from the platform setup code. + * + * PCI init will not have been done yet, we make a + * universal assumption about the way the bootloader (YAMON) + * have located and set up the chip. + */ +static t_uart_saa9730_regmap *kgdb_uart = (void *)(ATLAS_SAA9730_REG + SAA9730_UART_REGS_ADDR); + +static int saa9730_kgdb_active = 0; + +void saa9730_kgdb_hook(void) +{ + volatile unsigned char t; + + /* + * Clear all interrupts + */ + t = INB(&kgdb_uart->Lsr); + t += INB(&kgdb_uart->Msr); + t += INB(&kgdb_uart->Thr_Rbr); + t += INB(&kgdb_uart->Iir_Fcr); + + /* + * Now, initialize the UART + */ + /* 8 data bits, one stop bit, no parity */ + OUTB(SAA9730_LCR_DATA8, &kgdb_uart->Lcr); + + /* baud rate is fixed to 9600 (is this sufficient?)*/ + OUTB(0, &kgdb_uart->BaudDivMsb); /* HACK - Assumes standard crystal */ + OUTB(23, &kgdb_uart->BaudDivLsb); /* HACK - known for MIPS Atlas */ + + /* Set RTS/DTR active */ + OUTB(SAA9730_MCR_DTR | SAA9730_MCR_RTS, &kgdb_uart->Mcr); + saa9730_kgdb_active = 1; +} + +int saa9730_putDebugChar(char c) +{ + + if (!saa9730_kgdb_active) { /* need to init device first */ + return 0; + } + + while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_THRE)) + ; + OUTB(c, &kgdb_uart->Thr_Rbr); + + return 1; +} + +char saa9730_getDebugChar(void) +{ + char c; + + if (!saa9730_kgdb_active) { /* need to init device first */ + return 0; + } + while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_DR)) + ; + + c = INB(&kgdb_uart->Thr_Rbr); + return(c); +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/init.c linux.ac/arch/mips/mips-boards/generic/init.c --- linux.vanilla/arch/mips/mips-boards/generic/init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/init.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,139 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * PROM library initialisation code. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Environment variable */ +typedef struct +{ + char *name; + char *val; +} t_env_var; + +int prom_argc; +char **prom_argv, **prom_envp; + +int init_debug = 0; + +char *prom_getenv(char *envname) +{ + /* + * Return a pointer to the given environment variable. + */ + + t_env_var *env = (t_env_var *)prom_envp; + int i; + + i = strlen(envname); + + while(env->name) { + if(strncmp(envname, env->name, i) == 0) { + return(env->val); + } + env++; + } + return(NULL); +} + +static inline unsigned char str2hexnum(unsigned char c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; /* foo */ +} + +static inline void str2eaddr(unsigned char *ea, unsigned char *str) +{ + int i; + + for(i = 0; i < 6; i++) { + unsigned char num; + + if((*str == '.') || (*str == ':')) + str++; + num = str2hexnum(*str++) << 4; + num |= (str2hexnum(*str++)); + ea[i] = num; + } +} + +int get_ethernet_addr(char *ethernet_addr) +{ + char *ethaddr_str; + + ethaddr_str = prom_getenv("ethaddr"); + if (!ethaddr_str) { + printk("ethaddr not set in boot prom\n"); + return -1; + } + str2eaddr(ethernet_addr, ethaddr_str); + + if (init_debug > 1) { + int i; + printk("get_ethernet_addr: "); + for (i=0; i<5; i++) + printk("%02x:", (unsigned char)*(ethernet_addr+i)); + printk("%02x\n", *(ethernet_addr+i)); + } + + return 0; +} + +int __init prom_init(int argc, char **argv, char **envp) +{ + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + mips_display_message("LINUX"); + + /* + * Setup the North bridge to do Master byte-lane swapping when + * running in bigendian. + */ +#if defined(__MIPSEL__) + GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT | + GT_PCI0_CMD_SBYTESWAP_BIT); +#else + GT_WRITE(GT_PCI0_CMD_OFS, 0); +#endif + +#if defined(CONFIG_MIPS_MALTA) + mips_io_port_base = MALTA_PORT_BASE; +#else + mips_io_port_base = KSEG1; +#endif + setup_prom_printf(0); + prom_printf("\nLINUX started...\n"); + prom_init_cmdline(); + prom_meminit(); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/memory.c linux.ac/arch/mips/mips-boards/generic/memory.c --- linux.vanilla/arch/mips/mips-boards/generic/memory.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/memory.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,169 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * PROM library functions for acquiring/using memory descriptors given to + * us from the YAMON. + * + */ +#include +#include +#include +#include + +#include +#include + +#include + +/*#define DEBUG*/ + +enum yamon_memtypes { + yamon_dontuse, + yamon_prom, + yamon_free, +}; +struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; + +#ifdef DEBUG +static char *mtypes[3] = { + "Dont use memory", + "YAMON PROM memory", + "Free memmory", +}; +#endif + + +struct prom_pmemblock * __init prom_getmdesc(void) +{ + char *memsize_str; + unsigned int memsize; + + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); + memsize = 0x02000000; + } else { +#ifdef DEBUG + prom_printf("prom_memsize = %s\n", memsize_str); +#endif + memsize = simple_strtol(memsize_str, NULL, 0); + } + + memset(mdesc, 0, sizeof(mdesc)); + + mdesc[0].type = yamon_dontuse; + mdesc[0].base = 0x00000000; + mdesc[0].size = 0x00001000; + + mdesc[1].type = yamon_prom; + mdesc[1].base = 0x00001000; + mdesc[1].size = 0x000ef000; + +#if (CONFIG_MIPS_MALTA) + /* + * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the + * south bridge and PCI access always forwarded to the ISA Bus and + * BIOSCS# is always generated. + * This mean that this area can't be used as DMA memory for PCI + * devices. + */ + mdesc[2].type = yamon_dontuse; + mdesc[2].base = 0x000f0000; + mdesc[2].size = 0x00010000; +#else + mdesc[2].type = yamon_prom; + mdesc[2].base = 0x000f0000; + mdesc[2].size = 0x00010000; +#endif + + mdesc[3].type = yamon_free; + mdesc[3].base = 0x00100000; + mdesc[3].size = memsize - mdesc[3].base; + + return &mdesc[0]; +} + +static int __init prom_memtype_classify (unsigned int type) +{ + switch (type) { + case yamon_free: + return BOOT_MEM_RAM; + case yamon_prom: + return BOOT_MEM_ROM_DATA; + default: + return BOOT_MEM_RESERVED; + } +} + +void __init prom_meminit(void) +{ + struct prom_pmemblock *p; + +#ifdef DEBUG + int i = 0; + + prom_printf("YAMON MEMORY DESCRIPTOR dump:\n"); + p = prom_getmdesc(); + while (p->size) { + prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n", + i, p, p->base, p->size, mtypes[p->type]); + p++; + i++; + } +#endif + p = prom_getmdesc(); + while (p->size) { + unsigned long base, size; + long type; + + type = prom_memtype_classify (p->type); + base = p->base; + size = p->size; + + add_memory_region(base, size, type); + + p++; + } +} + +void prom_free_prom_memory (void) +{ + int i; + struct prom_pmemblock *p; + unsigned long freed = 0; + unsigned long addr; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) + continue; + + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(phys_to_virt(addr))); + set_page_count(virt_to_page(phys_to_virt(addr)), 1); + free_page(phys_to_virt(addr)); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } + } + printk("Freeing prom memory: %ldkb freed\n", freed >> 10); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/mipsIRQ.S linux.ac/arch/mips/mips-boards/generic/mipsIRQ.S --- linux.vanilla/arch/mips/mips-boards/generic/mipsIRQ.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/mipsIRQ.S Wed Apr 18 13:51:25 2001 @@ -0,0 +1,122 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Interrupt exception dispatch code. + * + */ +#include + +#include +#include +#include +#include + +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the MIPS board look basically (barring software + * IRQs which we don't use at all and all external interrupt sources are + * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Combined hardware interrupt (hw0) + * 3 Hardware (ignored) + * 4 Hardware (ignored) + * 5 Hardware (ignored) + * 6 Hardware (ignored) + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Lowest ---- Combined hardware interrupt + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(mipsIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + + mfc0 s0, CP0_CAUSE # get irq mask + + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP7 + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt + + /* Wheee, a timer interrupt. */ + move a0, sp + jal mips_timer_interrupt + nop + + j ret_from_irq + nop + +1: + beq a0, zero, 1f + nop + + /* Wheee, combined hardware level zero interrupt. */ +#if defined(CONFIG_MIPS_ATLAS) + jal atlas_hw0_irqdispatch +#elif defined(CONFIG_MIPS_MALTA) + jal malta_hw0_irqdispatch +#else +#error "MIPS board not supported\n" +#endif + move a0, sp # delay slot + + j ret_from_irq + nop # delay slot + +1: + /* + * Here by mistake? This is possible, what can happen is that by the + * time we take the exception the IRQ pin goes low, so just leave if + * this is the case. + */ + move a1,s0 + PRINT("Got interrupt: c0_cause = %08x\n") + mfc0 a1, CP0_EPC + PRINT("c0_epc = %08x\n") + + j ret_from_irq + nop + END(mipsIRQ) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/pci.c linux.ac/arch/mips/mips-boards/generic/pci.c --- linux.vanilla/arch/mips/mips-boards/generic/pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/pci.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,328 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * MIPS boards specific PCI support. + * + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include +#ifdef CONFIG_MIPS_MALTA +#include +#endif + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +static int +mips_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, + unsigned char where, u32 *data) +{ + unsigned char bus = dev->bus->number; + unsigned char dev_fn = dev->devfn; + u32 intr; + + if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0))) + return -1; /* Because of a bug in the galileo (for slot 31). */ + + /* Clear cause register bits */ + GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT)); + + /* Setup address */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (dev_fn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + + if (access_type == PCI_ACCESS_WRITE) { + if (bus == 0 && dev_fn == 0) { + /* + * Galileo is acting differently than other devices. + */ + GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); + } else { + GT_PCI_WRITE(GT_PCI0_CFGDATA_OFS, *data); + } + } else { + if (bus == 0 && dev_fn == 0) { + /* + * Galileo is acting differently than other devices. + */ + GT_READ(GT_PCI0_CFGDATA_OFS, *data); + } else { + GT_PCI_READ(GT_PCI0_CFGDATA_OFS, *data); + } + } + + /* Check for master or target abort */ + GT_READ(GT_INTRCAUSE_OFS, intr); + + if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) + { + /* Error occured */ + + /* Clear bits */ + GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT) ); + + return -1; + } + + return 0; +} + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int +mips_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) +{ + u32 data = 0; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xff; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +mips_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int +mips_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) +{ + u32 data = 0; + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int +mips_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + +static int +mips_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops mips_pci_ops = { + mips_pcibios_read_config_byte, + mips_pcibios_read_config_word, + mips_pcibios_read_config_dword, + mips_pcibios_write_config_byte, + mips_pcibios_write_config_word, + mips_pcibios_write_config_dword +}; + +void __init pcibios_init(void) +{ +#ifdef CONFIG_MIPS_MALTA + struct pci_dev *pdev; + unsigned char reg_val; +#endif + + printk("PCI: Probing PCI hardware on host bus 0.\n"); + pci_scan_bus(0, &mips_pci_ops, NULL); + + /* + * Due to a bug in the Galileo system controller, we need to setup + * the PCI BAR for the Galileo internal registers. + * This should be done in the bios/bootprom and will be fixed in + * a later revision of YAMON (the MIPS boards boot prom). + */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ + (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 device */ + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0 */ + ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4 */ + GT_PCI0_CFGADDR_CONFIGEN_BIT ); + + /* Perform the write */ + GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE)); + +#ifdef CONFIG_MIPS_MALTA + pci_for_each_dev(pdev) { + if ((pdev->vendor == PCI_VENDOR_ID_INTEL) + && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB) + && (PCI_SLOT(pdev->devfn) == 0x0a)) { + /* + * IDE Decode enable. + */ + pci_read_config_byte(pdev, 0x41, ®_val); + pci_write_config_byte(pdev, 0x41, reg_val | 0x80); + pci_read_config_byte(pdev, 0x43, ®_val); + pci_write_config_byte(pdev, 0x43, reg_val | 0x80); + } + + if ((pdev->vendor == PCI_VENDOR_ID_INTEL) + && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB_0) + && (PCI_SLOT(pdev->devfn) == 0x0a)) { + /* + * Set top of main memory accessible by ISA or DMA + * devices to 16 Mb. + */ + pci_read_config_byte(pdev, 0x69, ®_val); + pci_write_config_byte(pdev, 0x69, reg_val | 0xf0); + } + } + + /* + * Activate Floppy Controller in the SMSC FDC37M817 Super I/O + * Controller. + * This should be done in the bios/bootprom and will be fixed in + * a later revision of YAMON (the MIPS boards boot prom). + */ + /* Entering config state. */ + SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG); + + /* Activate floppy controller. */ + SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG); + SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG); + SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG); + SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG); + + /* Exit config state. */ + SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG); +#endif +} + +int __init +pcibios_enable_device(struct pci_dev *dev) +{ + /* Not needed, since we enable all devices at startup. */ + return 0; +} + +void __init +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ +} + +char * __init +pcibios_setup(char *str) +{ + /* Nothing to do for now. */ + + return str; +} + +struct pci_fixup pcibios_fixups[] = { + { 0 } +}; + +void __init +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + unsigned long where, size; + u32 reg; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); +} + +/* + * Called after each bus is probed, but before its children + * are examined. + */ +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + pci_read_bridge_bases(b); +} + +#endif /* CONFIG_PCI */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/printf.c linux.ac/arch/mips/mips-boards/generic/printf.c --- linux.vanilla/arch/mips/mips-boards/generic/printf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/printf.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,140 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Putting things on the screen/serial line using YAMONs facilities. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_MIPS_ATLAS +/* + * Atlas registers are memory mapped on 64-bit aligned boundaries and + * only word access are allowed. + * When reading the UART 8 bit registers only the LSB are valid. + */ +unsigned int atlas_serial_in(struct async_struct *info, int offset) +{ + return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff); +} + +void atlas_serial_out(struct async_struct *info, int offset, int value) +{ + *(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value; +} + +#define serial_in atlas_serial_in +#define serial_out atlas_serial_out + +#else + +static unsigned int serial_in(struct async_struct *info, int offset) +{ + return inb(info->port + offset); +} + +static void serial_out(struct async_struct *info, int offset, + int value) +{ + outb(value, info->port + offset); +} +#endif + +static struct serial_state rs_table[] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +/* + * Hooks to fake "prom" console I/O before devices + * are fully initialized. + */ +static struct async_struct prom_port_info = {0}; + +void __init setup_prom_printf(int tty_no) { + struct serial_state *ser = &rs_table[tty_no]; + + prom_port_info.state = ser; + prom_port_info.magic = SERIAL_MAGIC; + prom_port_info.port = ser->port; + prom_port_info.flags = ser->flags; + + /* No setup of UART - assume YAMON left in sane state */ +} + +int putPromChar(char c) +{ + if (!prom_port_info.state) { /* need to init device first */ + return 0; + } + + while ((serial_in(&prom_port_info, UART_LSR) & UART_LSR_THRE) == 0) + ; + + serial_out(&prom_port_info, UART_TX, c); + + return 1; +} + +char getPromChar(void) +{ + if (!prom_port_info.state) { /* need to init device first */ + return 0; + } + + while (!(serial_in(&prom_port_info, UART_LSR) & 1)) + ; + + return(serial_in(&prom_port_info, UART_RX)); +} + +static char buf[1024]; + +void __init prom_printf(char *fmt, ...) +{ + va_list args; + int l; + char *p, *buf_end; + long flags; + + int putPromChar(char); + + /* Low level, brute force, not SMP safe... */ + save_and_cli(flags); + va_start(args, fmt); + l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */ + va_end(args); + + buf_end = buf + l; + + for (p = buf; p < buf_end; p++) { + /* Crude cr/nl handling is better than none */ + if(*p == '\n')putPromChar('\r'); + putPromChar(*p); + } + restore_flags(flags); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/reset.c linux.ac/arch/mips/mips-boards/generic/reset.c --- linux.vanilla/arch/mips/mips-boards/generic/reset.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/reset.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,72 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Reset the MIPS boards. + * + */ +#include + +#include +#include +#if defined(CONFIG_MIPS_ATLAS) +#include +#endif + +static void mips_machine_restart(char *command); +static void mips_machine_halt(void); +#if defined(CONFIG_MIPS_ATLAS) +static void atlas_machine_power_off(void); +#endif + +static void mips_machine_restart(char *command) +{ + volatile unsigned int *softres_reg = (void *)SOFTRES_REG; + + *softres_reg = GORESET; +} + +static void mips_machine_halt(void) +{ + volatile unsigned int *softres_reg = (void *)SOFTRES_REG; + + *softres_reg = GORESET; +} + +#if defined(CONFIG_MIPS_ATLAS) +static void atlas_machine_power_off(void) +{ + volatile unsigned int *psustby_reg = (void *)ATLAS_PSUSTBY_REG; + + *psustby_reg = ATLAS_GOSTBY; +} +#endif + +void mips_reboot_setup(void) +{ + _machine_restart = mips_machine_restart; + _machine_halt = mips_machine_halt; +#if defined(CONFIG_MIPS_ATLAS) + _machine_power_off = atlas_machine_power_off; +#endif +#if defined(CONFIG_MIPS_MALTA) + _machine_power_off = mips_machine_halt; +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/generic/time.c linux.ac/arch/mips/mips-boards/generic/time.c --- linux.vanilla/arch/mips/mips-boards/generic/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/generic/time.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,410 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Setting up the clock on the MIPS boards. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +extern volatile unsigned long wall_jiffies; +static long last_rtc_update = 0; +unsigned long missed_heart_beats = 0; + +static unsigned long r4k_offset; /* Amount to increment compare reg each time */ +static unsigned long r4k_cur; /* What counter should be at next timer irq */ +extern rwlock_t xtime_lock; + +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) + +#if defined(CONFIG_MIPS_ATLAS) +static char display_string[] = " LINUX ON ATLAS "; +#endif +#if defined(CONFIG_MIPS_MALTA) +static char display_string[] = " LINUX ON MALTA "; +#endif +static unsigned int display_count = 0; +#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) + +static unsigned int timer_tick_count=0; + + +static inline void ack_r4ktimer(unsigned long newval) +{ + write_32bit_cp0_register(CP0_COMPARE, newval); +} + + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + +/* + * There are a lot of conceptually broken versions of the MIPS timer interrupt + * handler floating around. This one is rather different, but the algorithm + * is provably more robust. + */ +void mips_timer_interrupt(struct pt_regs *regs) +{ + int irq = 7; + + if (r4k_offset == 0) + goto null; + + do { + kstat.irqs[0][irq]++; + do_timer(regs); + + /* Historical comment/code: + * RTC time of day s updated approx. every 11 + * minutes. Because of how the numbers work out + * we need to make absolutely sure we do this update + * within 500ms before the * next second starts, + * thus the following code. + */ + read_lock(&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 + && xtime.tv_sec > last_rtc_update + 660 + && xtime.tv_usec >= 500000 - (tick >> 1) + && xtime.tv_usec <= 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; + read_unlock(&xtime_lock); + + if ((timer_tick_count++ % HZ) == 0) { + mips_display_message(&display_string[display_count++]); + if (display_count == MAX_DISPLAY_COUNT) + display_count = 0; + } + + r4k_cur += r4k_offset; + ack_r4ktimer(r4k_cur); + + } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) + - r4k_cur) < 0x7fffffff); + + return; + +null: + ack_r4ktimer(0); +} + +/* + * Figure out the r4k offset, the amount to increment the compare + * register for each time tick. + * Use the RTC to calculate offset. + */ +static unsigned long __init cal_r4koff(void) +{ + unsigned long count; + unsigned int flags; + + __save_and_cli(flags); + + /* Start counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + /* Start r4k counter. */ + write_32bit_cp0_register(CP0_COUNT, 0); + + /* Read counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + count = read_32bit_cp0_register(CP0_COUNT); + + /* restore interrupts */ + __restore_flags(flags); + + return (count / HZ); +} + +static unsigned long __init get_mips_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char save_control; + + save_control = CMOS_READ(RTC_CONTROL); + + /* Freeze it. */ + CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL); + + /* Read regs. */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + + if (!(save_control & RTC_24H)) + { + if ((hour & 0xf) == 0xc) + hour &= 0x80; + if (hour & 0x80) + hour = (hour & 0xf) + 12; + } + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + /* Unfreeze clock. */ + CMOS_WRITE(save_control, RTC_CONTROL); + + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +void __init time_init(void) +{ + unsigned int est_freq, flags; + + /* Set Data mode - binary. */ + CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); + + printk("calculating r4koff... "); + r4k_offset = cal_r4koff(); + printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + + est_freq = 2*r4k_offset*HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq%10000; + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); + + write_32bit_cp0_register(CP0_COMPARE, r4k_cur); + change_cp0_status(ST0_IM, ALLINTS); + + /* Read time from the RTC chipset. */ + write_lock_irqsave (&xtime_lock, flags); + xtime.tv_sec = get_mips_time(); + xtime.tv_usec = 0; + write_unlock_irqrestore(&xtime_lock, flags); +} + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) +#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff) + +/* Cycle counter value at the previous timer interrupt.. */ + +static unsigned int timerhi = 0, timerlo = 0; + +/* + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_fast_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies=0; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient=0; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; +#ifdef CONFIG_CPU_MIPS32 + if (last_jiffies != 0) { + unsigned long r0; + do_div64_32(r0, timerhi, timerlo, tmp); + do_div64_32(quotient, USECS_PER_JIFFY, + USECS_PER_JIFFY_FRAC, r0); + cached_quotient = quotient; + } +#else + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY) + :"$1"); + cached_quotient = quotient; +#endif + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned int flags; + + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_fast_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; + + read_unlock_irqrestore (&xtime_lock, flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq (&xtime_lock); + + /* This is revolting. We need to set the xtime.tv_usec correctly. + * However, the value in this location is is value at the last tick. + * Discover what correction gettimeofday would have done, and then + * undo it! + */ + tv->tv_usec -= do_fast_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + 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); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/Makefile linux.ac/arch/mips/mips-boards/malta/Makefile --- linux.vanilla/arch/mips/mips-boards/malta/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/Makefile Wed Apr 18 13:51:25 2001 @@ -0,0 +1,40 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. +# +# ######################################################################## +# +# This program is free software; you can distribute it 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 it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# ####################################################################### +# +# Makefile for the MIPS Malta specific kernel interface routines +# under Linux. +# +# 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 definitions are now in the main makefile... + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := malta.o + +obj-y := malta_int.o malta_rtc.o malta_setup.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/malta_int.c linux.ac/arch/mips/mips-boards/malta/malta_int.c --- linux.vanilla/arch/mips/mips-boards/malta/malta_int.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/malta_int.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,378 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Routines for generic manipulation of the interrupts found on the MIPS + * Malta board. + * The interrupt controller is located in the South Bridge a PIIX4 device + * with two internal 82C95 interrupt controllers. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern asmlinkage void mipsIRQ(void); + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +unsigned long spurious_count = 0; + +static struct irqaction *hw0_irq_action[MALTAINT_END] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +static struct irqaction r4ktimer_action = { + NULL, 0, 0, "R4000 timer/counter", NULL, NULL, +}; + +static struct irqaction *irq_action[8] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, &r4ktimer_action +}; + +#if 0 +#define DEBUG_INT(x...) printk(x) +#else +#define DEBUG_INT(x...) +#endif + +/* + * This contains the interrupt mask for both 82C59 interrupt controllers. + */ +static unsigned int cached_int_mask = 0xffff; + + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + if(irq_nr >= MALTAINT_END) { + printk("whee, invalid irq_nr %d\n", irq_nr); + panic("IRQ, you lose..."); + } + + save_and_cli(flags); + cached_int_mask |= (1 << irq_nr); + if (irq_nr & 8) { + outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); + } else { + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + } + restore_flags(flags); +} + + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + if(irq_nr >= MALTAINT_END) { + printk("whee, invalid irq_nr %d\n", irq_nr); + panic("IRQ, you lose..."); + } + + save_and_cli(flags); + cached_int_mask &= ~(1 << irq_nr); + if (irq_nr & 8) { + outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); + + /* Enable irq 2 (cascade interrupt). */ + cached_int_mask &= ~(1 << 2); + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + } else { + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + } + restore_flags(flags); +} + + +int get_irq_list(char *buf) +{ + int i, len = 0; + int num = 0; + struct irqaction *action; + + for (i = 0; i < 8; i++, num++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + num, kstat.irqs[0][num], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, " [on-chip]\n"); + } + for (i = 0; i < MALTAINT_END; i++, num++) { + action = hw0_irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + num, kstat.irqs[0][num], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, " [hw0]\n"); + } + return len; +} + + +static int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + + p = &hw0_irq_action[irq]; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + *p = new; + if (!shared) + enable_irq(irq); + + return 0; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + struct irqaction *action; + int retval; + + DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname); + + if (irq >= MALTAINT_END) + 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->dev_id = dev_id; + action->next = 0; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + + return retval; +} + + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action, **p; + + if (irq >= MALTAINT_END) { + printk("Trying to free IRQ%d\n",irq); + return; + } + + for (p = &hw0_irq_action[irq]; (action = *p) != NULL; + p = &action->next) + { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + *p = action->next; + kfree(action); + if (!hw0_irq_action[irq]) + disable_irq(irq); + return; + } + printk("Trying to free IRQ%d\n",irq); +} + +void __init init_IRQ(void) +{ + irq_setup(); +} + +static inline int get_int(int *irq) +{ + /* + * Determine highest priority pending interrupt by performing + * a PCI Interrupt Acknowledge cycle. + */ + GT_READ(GT_PCI0_IACK_OFS, *irq); + *irq &= 0xFF; + + /* + * IRQ7 is used to detect spurious interrupts. + * The interrupt acknowledge cycle returns IRQ7, if no + * interrupts is requested. + * We can differentiate between this situation and a + * "Normal" IRQ7 by reading the ISR. + */ + if (*irq == 7) + { + outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, PIIX4_ICTLR1_OCW3); + if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) + return -1; /* Spurious interrupt. */ + } + + return 0; +} + +static inline void ack_int(int irq) +{ + if (irq & 8) { + /* Specific EOI to cascade */ + outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI | PIIX4_OCW2_ILS_2, + PIIX4_ICTLR1_OCW2); + + /* Non specific EOI to cascade */ + outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR2_OCW2); + } else { + /* Non specific EOI to cascade */ + outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR1_OCW2); + } +} + +void malta_hw0_irqdispatch(struct pt_regs *regs) +{ + struct irqaction *action; + int irq=0, cpu = smp_processor_id(); + + DEBUG_INT("malta_hw0_irqdispatch\n"); + + if (get_int(&irq)) + return; /* interrupt has already been cleared */ + + disable_irq(irq); + ack_int(irq); + + DEBUG_INT("malta_hw0_irqdispatch: irq=%d\n", irq); + action = hw0_irq_action[irq]; + + /* + * if action == NULL, then we don't have a handler + * for the irq + */ + if ( action == NULL ) + return; + + irq_enter(cpu, irq); + kstat.irqs[0][irq + 8]++; + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + + enable_irq(irq); + irq_exit(cpu, irq); +} + + +unsigned long probe_irq_on (void) +{ + unsigned int i, irqs = 0; + unsigned long delay; + + /* first, enable any unassigned irqs */ + for (i = MALTAINT_END-1; i > 0; i--) { + if (!hw0_irq_action[i]) { + enable_irq(i); + irqs |= (1 << i); + } + } + + /* wait for spurious interrupts to mask themselves out again */ + for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) + /* about 100ms delay */; + + /* now filter out any obviously spurious interrupts */ + return irqs & ~cached_int_mask; +} + + +int probe_irq_off (unsigned long irqs) +{ + unsigned int i; + + irqs &= cached_int_mask; + if (!irqs) + return 0; + i = ffz(~irqs); + if (irqs != (irqs & (1 << i))) + i = -i; + + return i; +} + + +void __init maltaint_init(void) +{ + /* + * Mask out all interrupt by writing "1" to all bit position in + * the IMR register. + */ + outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); + outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); + + /* Now safe to set the exception vector. */ + set_except_vector(0, mipsIRQ); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/malta_rtc.c linux.ac/arch/mips/mips-boards/malta/malta_rtc.c --- linux.vanilla/arch/mips/mips-boards/malta/malta_rtc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/malta_rtc.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,51 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * RTC routines for Malta style attached PIIX4 device, which contains a + * Motorola MC146818A-compatible Real Time Clock. + * + */ +#include +#include +#include + +static unsigned char malta_rtc_read_data(unsigned long addr) +{ + outb(addr, MALTA_RTC_ADR_REG); + return inb(MALTA_RTC_DAT_REG); +} + +static void malta_rtc_write_data(unsigned char data, unsigned long addr) +{ + outb(addr, MALTA_RTC_ADR_REG); + outb(data, MALTA_RTC_DAT_REG); +} + +static int malta_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops malta_rtc_ops = { + &malta_rtc_read_data, + &malta_rtc_write_data, + &malta_rtc_bcd_mode +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mips-boards/malta/malta_setup.c linux.ac/arch/mips/mips-boards/malta/malta_setup.c --- linux.vanilla/arch/mips/mips-boards/malta/malta_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/mips-boards/malta/malta_setup.c Wed Apr 18 13:51:25 2001 @@ -0,0 +1,159 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it 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 it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Malta specific setup, including init of the feature struct. + * + */ +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_IDE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_FD +#include +#endif +#include + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +#ifdef CONFIG_REMOTE_DEBUG +extern void set_debug_traps(void); +extern void rs_kgdb_hook(int); +extern void breakpoint(void); +static int remote_debug = 0; +#endif + +#ifdef CONFIG_BLK_DEV_IDE +extern struct ide_ops std_ide_ops; +#endif +#ifdef CONFIG_BLK_DEV_FD +extern struct fd_ops std_fd_ops; +#endif +extern struct rtc_ops malta_rtc_ops; + +extern void mips_reboot_setup(void); + +struct resource standard_io_resources[] = { + { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, + { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, + { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, + { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, + { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, +}; + +#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) + +static void __init malta_irq_setup(void) +{ + maltaint_init(); + +#ifdef CONFIG_REMOTE_DEBUG + if (remote_debug) { + set_debug_traps(); + breakpoint(); + } +#endif +} + + +void __init malta_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + int rs_putDebugChar(char); + char rs_getDebugChar(void); + extern int (*putDebugChar)(char); + extern char (*getDebugChar)(void); +#endif + char *argptr; + int i; + + irq_setup = malta_irq_setup; + + /* Request I/O space for devices used on the Malta board. */ + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, standard_io_resources+i); + + /* + * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge. + */ + enable_dma(4); + +#ifdef CONFIG_SERIAL_CONSOLE + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "console=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS0,38400"); + } +#endif + +#ifdef CONFIG_REMOTE_DEBUG + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { + int line; + argptr += strlen("kgdb=ttyS"); + if (*argptr != '0' && *argptr != '1') + printk("KGDB: Uknown serial line /dev/ttyS%c, " + "falling back to /dev/ttyS1\n", *argptr); + line = *argptr == '0' ? 0 : 1; + printk("KGDB: Using serial line /dev/ttyS%d for session\n", + line ? 1 : 0); + + rs_kgdb_hook(line); + putDebugChar = rs_putDebugChar; + getDebugChar = rs_getDebugChar; + + prom_printf("KGDB: Using serial line /dev/ttyS%d for session, " + "please connect your debugger\n", line ? 1 : 0); + + remote_debug = 1; + /* Breakpoints and stuff are in malta_irq_setup() */ + } +#endif + + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "nofpu")) != NULL) + mips_cpu.options &= ~MIPS_CPU_FPU; + + rtc_ops = &malta_rtc_ops; +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif +#ifdef CONFIG_BLK_DEV_FD + fd_ops = &std_fd_ops; +#endif + mips_reboot_setup(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mm/Makefile linux.ac/arch/mips/mm/Makefile --- linux.vanilla/arch/mips/mm/Makefile Fri Feb 25 06:52:30 2000 +++ linux.ac/arch/mips/mm/Makefile Wed Apr 18 13:51:25 2001 @@ -8,34 +8,20 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := extable.o init.o fault.o loadmmu.o -ifdef CONFIG_CPU_R3000 -O_OBJS += r2300.o -endif +export-objs += umap.o +obj-y += extable.o init.o fault.o loadmmu.o -ifdef CONFIG_CPU_R4300 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_R4X00 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_R5000 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_NEVADA -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_SGI_IP22 -O_OBJS += umap.o -endif - -ifdef CONFIG_BAGET_MIPS -O_OBJS += umap.o -endif +obj-$(CONFIG_CPU_R3000) += r2300.o +obj-$(CONFIG_CPU_R3912) += r2300.o +obj-$(CONFIG_CPU_R4300) += r4xx0.o +obj-$(CONFIG_CPU_R4X00) += r4xx0.o +obj-$(CONFIG_CPU_R5000) += r4xx0.o +obj-$(CONFIG_CPU_NEVADA) += r4xx0.o +obj-$(CONFIG_CPU_R5432) += r5432.o +obj-$(CONFIG_CPU_RM7000) += rm7k.o +obj-$(CONFIG_CPU_MIPS32) += mips32.o +obj-$(CONFIG_SGI_IP22) += umap.o +obj-$(CONFIG_BAGET_MIPS) += umap.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/mm/init.c linux.ac/arch/mips/mm/init.c --- linux.vanilla/arch/mips/mm/init.c Mon Oct 16 20:58:51 2000 +++ linux.ac/arch/mips/mm/init.c Tue Apr 3 17:54:33 2001 @@ -38,6 +38,9 @@ #include #endif #include +#include + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/Makefile linux.ac/arch/mips/orion/Makefile --- linux.vanilla/arch/mips/orion/Makefile Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/Makefile Thu Jan 1 01:00:00 1970 @@ -1,48 +0,0 @@ -# -# 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. -# -# -# Produce a bootimage for the IPSX -# Copyright (C) 2000 Cort Dougan -# - -.S.s: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -OBJS = promcon.o char.o serial.8530.o orion.hw.init.o setup.o irq.o int-handler.o - -all: orionkern.a - -orionkern.a: $(OBJS) initrd.o #no_initrd.o - $(AR) rcs orionkern.a $(OBJS) initrd.o #no_initrd.o - sync - -initrd.c: piggyback ramdisk.image.gz - ./piggyback initrd < ramdisk.image.gz > initrd.c - -piggyback: piggyback.c - $(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c - -orionboot: orion.ctl - -patchapp: patchapp.c - $(HOSTCC) -o $@ $^ - -orion.ctl: patchapp ../../../vmlinux - $(OBJCOPY) -Obinary ../../../vmlinux orion.nosym - ./patchapp orion.nosym orion - cp -f orion.bin orion.ctl - -# Don't build dependencies, this may die if $(CC) isn't gcc -dep: - -clean: - rm -f patchapp orion.bin orion.nosym orion.ctl initrd.c - -dummy: - -include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/int-handler.S linux.ac/arch/mips/orion/int-handler.S --- linux.vanilla/arch/mips/orion/int-handler.S Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/int-handler.S Thu Jan 1 01:00:00 1970 @@ -1,53 +0,0 @@ -#include -#include -#include -#include - - .text - .set mips1 - .set reorder - .set macro - .set noat - .align 5 - -NESTED(orionIRQ, PT_SIZE, sp) - SAVE_ALL - CLI # Important: mark KERNEL mode ! - /* - * Get pending interrupts - */ - mfc0 t0,CP0_CAUSE # get pending interrupts - mfc0 t1,CP0_STATUS # get enabled interrupts - and t0,t1 # isolate allowed ones - andi t0,0xff00 # isolate pending bits - sll t0,16 # shift the pending bits down - beqz t0,3f # no pending intrs, then spurious - nop # delay slot - - /* - * Find irq with highest priority - * FIXME: This is slow - use binary search - */ - la a0,7 -1: bltz t0,2f # found pending irq - subu a0,1 - sll t0,1 - b 1b - nop # delay slot - -call_do_IRQ: -2: move a1,sp - jal do_IRQ - nop # delay slot - - mfc0 t0,CP0_STATUS # disable interrupts - ori t0,1 - xori t0,1 - mtc0 t0,CP0_STATUS - - la a1, ret_from_irq - jr a1 - -3: j spurious_interrupt -END(orionIRQ) - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/irq.c linux.ac/arch/mips/orion/irq.c --- linux.vanilla/arch/mips/orion/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/orion/irq.c Thu Jan 1 01:00:00 1970 @@ -1,281 +0,0 @@ -/* - * Code to handle irqs on Orion boards - * -- Cort - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -void (*board_time_init)(struct irqaction *irq); -extern asmlinkage void orionIRQ(void); -unsigned long spurious_count = 0; -irq_desc_t irq_desc[NR_IRQS]; - -static void galileo_ack(unsigned int irq_nr) -{ - *((unsigned long *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC18) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; -} - -struct hw_interrupt_type galileo_pic = { - " Galileo ", - NULL, - NULL, - NULL, /* unmask_irq */ - NULL, /* mask_irq */ - galileo_ack, /* mask_and_ack */ - 0 -}; - -/* Function for careful CP0 interrupt mask access */ -static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) -{ - unsigned long status = read_32bit_cp0_register(CP0_STATUS); - status &= ~((clr_mask & 0xFF) << 8); - status |= (set_mask & 0xFF) << 8; - write_32bit_cp0_register(CP0_STATUS, status); -} - -static inline void mask_irq(unsigned int irq_nr) -{ - modify_cp0_intmask(irq_nr, 0); -} - -static inline void unmask_irq(unsigned int irq_nr) -{ - modify_cp0_intmask(0, irq_nr); -} - -void disable_irq(unsigned int irq_nr) -{ - unsigned long flags; - - save_and_cli(flags); - mask_irq(irq_nr); - restore_flags(flags); -} - -void enable_irq(unsigned int irq_nr) -{ - unsigned long flags; - - save_and_cli(flags); - unmask_irq(irq_nr); - restore_flags(flags); -} - -/*static struct irqaction *irq_action[NR_IRQS] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; -*/ -void __init orion_time_init(struct irqaction *irq) -{ - __u32 timer_count; - - irq_desc[2].handler = &galileo_pic; - irq_desc[2].action = irq; - - /* This code was provided by the CoSine guys and despite its - * appearance init's the timer. - * -- Cort - */ - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x864) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x850) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; - - timer_count = 300000000/100; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x850) ) = (((( timer_count )&0xff)<<24)+ ((( timer_count )&0xff00)<<8)+ ((( timer_count )&0xff0000)>>8)+ ((( timer_count )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC1C) ) = (((( 0x100 )&0xff)<<24)+ ((( 0x100 )&0xff00)<<8)+ ((( 0x100 )&0xff0000)>>8)+ ((( 0x100 )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x864) ) = (((( 0x03 )&0xff)<<24)+ ((( 0x03 )&0xff00)<<8)+ ((( 0x03 )&0xff0000)>>8)+ ((( 0x03 )&0xff000000)>>24)) ; - - *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC18) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ; -} - -int get_irq_list(char *buf) -{ - int i, len = 0, j; - struct irqaction * action; - - len += sprintf(buf+len, " "); - for (j=0; jhandler ) - continue; - len += sprintf(buf+len, "%3d: ", i); - len += sprintf(buf+len, "%10u ", kstat_irqs(i)); - if ( irq_desc[i].handler ) - len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); - else - len += sprintf(buf+len, " None "); - len += sprintf(buf+len, " %s",action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); - } - len += sprintf(buf+len, "BAD: %10lu\n", spurious_count); - return len; -} - -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) -{ - struct irqaction *action; - int do_random, cpu; - int status; - - cpu = smp_processor_id(); - irq_enter(cpu); - kstat.irqs[cpu][irq]++; - status = 0; - - if (irq_desc[irq].handler->ack) - irq_desc[irq].handler->ack(irq); - - action = irq_desc[irq].action; - if (action && action->handler) - { - if (!(action->flags & SA_INTERRUPT)) - __sti(); - do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while ( action ); - __cli(); - if (irq_desc[irq].handler) - { - if (irq_desc[irq].handler->end) - irq_desc[irq].handler->end(irq); - else if (irq_desc[irq].handler->enable) - irq_desc[irq].handler->enable(irq); - } - } - - irq_exit(cpu); - - if (softirq_active(cpu)&softirq_mask(cpu)) - do_softirq(); - - /* unmasking and bottom half handling is done magically for us. */ -} - -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - struct irqaction *old, **p, *action; - unsigned long flags; - - if (irq >= NR_IRQS) - return -EINVAL; - if (!handler) - { - /* Free */ - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - restore_flags(flags); - kfree(action); - return 0; - } - return -ENOENT; - } - - action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - save_flags(flags); - cli(); - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->dev_id = dev_id; - action->next = NULL; - enable_irq(irq); - - p = &irq_desc[irq].action; - - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & action->flags & SA_SHIRQ)) - return -EBUSY; - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - } - *p = action; - - restore_flags(flags); - return 0; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} - - -unsigned long probe_irq_on (void) -{ - return 0; -} - -int probe_irq_off (unsigned long irqs) -{ - return 0; -} - -int (*irq_cannonicalize)(int irq); - -int orion_irq_cannonicalize(int i) -{ - return i; -} - -void __init init_IRQ(void) -{ - - irq_cannonicalize = orion_irq_cannonicalize; - set_except_vector(0, orionIRQ); -} - -EXPORT_SYMBOL(irq_cannonicalize); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/ld.script.orion linux.ac/arch/mips/orion/ld.script.orion --- linux.vanilla/arch/mips/orion/ld.script.orion Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/ld.script.orion Thu Jan 1 01:00:00 1970 @@ -1,113 +0,0 @@ -OUTPUT_FORMAT("elf32-bigmips") -OUTPUT_ARCH(mips) -ENTRY(kernel_entry) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0x80100000; - /* app_header is needed for the Orion bootloader -- Cort */ - .app_header : { *(.app_header) } - .init : { *(.init) } =0 - .text : - { - _ftext = . ; - *(.text) - *(.rodata) - *(.rodata1) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0 - _etext = .; - PROVIDE (etext = .); - - . = ALIGN(8192); - .data.init_task : { *(.data.init_task) } - - /* Startup code */ - . = ALIGN(4096); - __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); /* Align double page for init_task_union */ - __init_end = .; - - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - .fini : { *(.fini) } =0 - .reginfo : { *(.reginfo) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. It would - be more correct to do this: - . = .; - The current expression does not correctly handle the case of a - text segment ending precisely at the end of a page; it causes the - data segment to skip a page. The above expression does not have - this problem, but it will currently (2/95) cause BFD to allocate - a single segment, combining both text and data, for this case. - This will prevent the text segment from being shared among - multiple executions of the program; I think that is more - important than losing a page of the virtual address space (note - that no actual memory is lost; the page which is skipped can not - be referenced). */ - . = .; - .data : - { - _fdata = . ; - *(.data) - CONSTRUCTORS - } - .data1 : { *(.data1) } - _gp = . + 0x8000; - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - .got : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - PROVIDE (edata = .); - - __bss_start = .; - _fbss = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - _end = . ; - PROVIDE (end = .); - } - /* These are needed for ELF backends which have not yet been - converted to the new style linker. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - /* DWARF debug sections. - Symbols in the .debug DWARF section are relative to the beginning of the - section so we begin .debug at 0. It's not clear yet what needs to happen - for the others. */ - .debug 0 : { *(.debug) } - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - .debug_sfnames 0 : { *(.debug_sfnames) } - .line 0 : { *(.line) } - /* These must appear regardless of . */ - .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } - .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/misc.c linux.ac/arch/mips/orion/misc.c --- linux.vanilla/arch/mips/orion/misc.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/orion/misc.c Thu Jan 1 01:00:00 1970 @@ -1,100 +0,0 @@ -/* - * Catch-all for Orion-specify code that doesn't fit easily elsewhere. - * -- Cort - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif -#include -#ifdef CONFIG_RTC -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -char arcs_cmdline[CL_SIZE] = {0, }; -extern int _end; - -static unsigned char orion_rtc_read_data(unsigned long addr) -{ - return 0; -} - -static void orion_rtc_write_data(unsigned char data, unsigned long addr) -{ -} - -static int orion_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops orion_rtc_ops = { - &orion_rtc_read_data, - &orion_rtc_write_data, - &orion_rtc_bcd_mode -}; - -extern void InitCIB(void); -extern void InitQpic(void); -extern void InitCupid(void); - -void __init orion_setup(void) -{ - InitCIB(); - InitQpic(); - InitCupid(); -} - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) - - - -int orion_sysinit(void) -{ - unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size; - - mips_machgroup = MACH_GROUP_ORION; - /* 64 MB non-upgradable */ - mem_size = 32 << 20; - - free_start = PHYSADDR(PFN_ALIGN(&_end)); - free_end = mem_size; - start_pfn = PFN_UP((unsigned long)&_end); - - /* Register all the contiguous memory with the bootmem allocator - and free it. Be careful about the bootmem freemap. */ - bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); - - /* Free the entire available memory after the _end symbol. */ - free_start += bootmap_size; - free_bootmem(free_start, free_end-free_start); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/no_initrd.c linux.ac/arch/mips/orion/no_initrd.c --- linux.vanilla/arch/mips/orion/no_initrd.c Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/no_initrd.c Thu Jan 1 01:00:00 1970 @@ -1,2 +0,0 @@ -unsigned long *orion_initrd_start = 0; -unsigned long orion_initrd_size = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/piggyback.c linux.ac/arch/mips/orion/piggyback.c --- linux.vanilla/arch/mips/orion/piggyback.c Tue Jul 11 19:14:48 2000 +++ linux.ac/arch/mips/orion/piggyback.c Thu Jan 1 01:00:00 1970 @@ -1,59 +0,0 @@ -#include -#include - -extern long ce_exec_config[]; - -int main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 2) - { - fprintf(stderr, "usage: %s name out-file\n", - argv[0]); - exit(1); - } - fprintf(stdout, "/*\n"); - fprintf(stdout, "* Miscellaneous data structures:\n"); - fprintf(stdout, "* WARNING - this file is automatically generated!\n"); - fprintf(stdout, "*/\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "unsigned long orion_%s_start[] = {\n", argv[1]); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, ", /* %x */\n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - pos += len; - } - fprintf(stdout, "0 };\n"); - fprintf(stdout, "unsigned long orion_%s_size = 0x%x;\n", argv[1], pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/promcon.c linux.ac/arch/mips/orion/promcon.c --- linux.vanilla/arch/mips/orion/promcon.c Thu Oct 12 22:20:48 2000 +++ linux.ac/arch/mips/orion/promcon.c Thu Jan 1 01:00:00 1970 @@ -1,168 +0,0 @@ -/* - * Wrap-around code for a console using the - * SGI PROM io-routines. - * - * Copyright (c) 1999 Ulf Carlsson - * - * Derived from DECstation promcon.c - * Copyright (c) 1998 Harald Koerfgen - */ - -#include -#include -#include -#include -#include -#include -/* -#include -*/ -extern void prom_printf(char *fmt, ...); -unsigned long splx(unsigned long mask){return 0;} -#if 0 -unsigned long ramsize=0x100000; -unsigned long RamSize(){return ramsize;} -extern void prom_printf(char *fmt, ...); -unsigned long splx(unsigned long mask){return 0;} -long PssSetIntHandler(unsigned long intnum, void *handler){} -long PssEnableInt(unsigned long intnum){} -long PssDisableInt(unsigned long intnum){} -unsigned long t_ident(char name[4], unsigned long node, unsigned long *tid){} -#endif - -extern void SerialPollConout(unsigned char c); -static void prom_console_write(struct console *co, const char *s, - unsigned count) -{ - unsigned i; - - /* - * Now, do each character - */ - for (i = 0; i < count; i++) { - if (*s == 10) - SerialPollConout(13); - SerialPollConout(*s++); - } -} -extern int prom_getchar(void); -static int prom_console_wait_key(struct console *co) -{ - return prom_getchar(); -} - -extern void SerialPollInit(void); -extern void SerialSetup(unsigned long baud, unsigned long console, unsigned long host, unsigned long intr_desc); -static int __init prom_console_setup(struct console *co, char *options) -{ - SerialSetup(19200,1,1,3); - SerialPollInit(); - SerialPollOn(); - return 0; -} - -static kdev_t prom_console_device(struct console *c) -{ - return MKDEV(TTY_MAJOR, 64 + c->index); -} - -static struct console sercons = -{ - name: "ttyS", - write: prom_console_write, - device: prom_console_device, - wait_key: prom_console_wait_key, - setup: prom_console_setup, - flags: CON_PRINTBUFFER, - index: -1, -}; - -/* - * Register console. - */ - -void serial_console_init(void) -{ - register_console(&sercons); -} - -extern void prom_putchar(int mychar); - -static char ppbuf[1000]; - - -void prom_printf(char *fmt, ...) -{ - va_list args; - char ch, *bptr; - int i; - - va_start(args, fmt); - i = vsprintf(ppbuf, fmt, args); - - bptr = ppbuf; - - while((ch = *(bptr++)) != 0) { - if(ch == '\n') - prom_putchar('\r'); - - prom_putchar(ch); - } - va_end(args); - return; -} - - - -void prom_putchar(int mychar){} -int prom_getchar(void){return 0;} -struct app_header_s { - unsigned long MAGIC_JMP; - unsigned long MAGIC_NOP; - unsigned long header_tag; - unsigned long header_flags; - unsigned long header_length; - unsigned long header_cksum; - - void *load_addr; - void *end_addr; - void *start_addr; - char *app_name_p; - char *version_p; - char *date_p; - char *time_p; - unsigned long type; - unsigned long crc; - unsigned long reserved; -}; -typedef struct app_header_s app_header_t; -char linked_app_name[]="linux"; -char *linked_app_name_p=&linked_app_name[0]; - -char linked_app_ver[]="2.4 -test1"; -char *linked_app_ver_p=&linked_app_ver[0]; - -char linked_app_date[]="today"; -char *linked_app_date_p=&linked_app_date[0]; - -char linked_app_time[]="now"; -char *linked_app_time_p=&linked_app_time[0]; -extern void *__bss_start; -extern void *kernel_entry; - -app_header_t app_header __attribute__ ((section (".app_header"))) = { - (0x10000000 | (((sizeof(app_header_t)>>2)-1) & 0xffff)) , - 0 , - (((( 0x4321 ) & 0xFFFF) << 16) | (( 0x0100 ) & 0xFFFF)) , - 0x80000000 , - sizeof(app_header_t), - 0, - &app_header, - &__bss_start, - &kernel_entry, - linked_app_name, - linked_app_ver, - linked_app_date, - linked_app_time, - 0 -}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/orion/setup.c linux.ac/arch/mips/orion/setup.c --- linux.vanilla/arch/mips/orion/setup.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/mips/orion/setup.c Thu Jan 1 01:00:00 1970 @@ -1,125 +0,0 @@ -/* - * Catch-all for Orion-specific code that doesn't fit easily elsewhere. - * -- Cort - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BLK_DEV_RAM -#include -#endif -#include -#ifdef CONFIG_RTC -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -char arcs_cmdline[CL_SIZE] = { "console=ttyS0,19200" }; -extern int _end; - -static unsigned char orion_rtc_read_data(unsigned long addr) -{ - return 0; -} - -static void orion_rtc_write_data(unsigned char data, unsigned long addr) -{ -} - -static int orion_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops orion_rtc_ops = { - &orion_rtc_read_data, - &orion_rtc_write_data, - &orion_rtc_bcd_mode -}; - -extern void InitCIB(void); -extern void InitQpic(void); -extern void InitCupid(void); - -void __init orion_setup(void) -{ - extern void (*board_time_init)(struct irqaction *irq); - void orion_time_init(struct irqaction *); - - rtc_ops = &orion_rtc_ops; - board_time_init = orion_time_init; - mips_io_port_base = GT64120_BASE; - - InitCIB(); - InitQpic(); - InitCupid(); -} - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) - -unsigned long mem_size; -int __init prom_init(int a, char **b, char **c, int *d) -{ - unsigned long free_start, free_end, start_pfn, bootmap_size; - extern unsigned long orion_initrd_start[], orion_initrd_size; - - mips_machgroup = MACH_GROUP_ORION; - /* 64 MB non-upgradable */ - mem_size = 64 << 20; - - free_start = PHYSADDR(PFN_ALIGN(&_end)); - free_end = mem_size; - start_pfn = PFN_UP((unsigned long)&_end); - - /* Register all the contiguous memory with the bootmem allocator - and free it. Be careful about the bootmem freemap. */ - bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); - - /* Free the entire available memory after the _end symbol. */ - free_start += bootmap_size; - free_bootmem(free_start, free_end-free_start); - - initrd_start = (ulong)orion_initrd_start; - initrd_end = (ulong)orion_initrd_start + (ulong)orion_initrd_size; - initrd_below_start_ok = 1; - - return 0; -} - -void prom_free_prom_memory (void) -{ -} - -int page_is_ram(unsigned long pagenr) -{ - if ( pagenr < (mem_size >> PAGE_SHIFT) ) - return 1; - return 0; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/sgi/kernel/Makefile linux.ac/arch/mips/sgi/kernel/Makefile --- linux.vanilla/arch/mips/sgi/kernel/Makefile Mon Jul 10 06:18:15 2000 +++ linux.ac/arch/mips/sgi/kernel/Makefile Wed Apr 18 13:51:39 2001 @@ -13,21 +13,13 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -OBJS = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \ - system.o indyIRQ.o reset.o setup.o time.o -ifdef CONFIG_SGI_PROM_CONSOLE -OBJS += promcon.o -endif +O_TARGET := ip22-kern.o -all: sgikern.a +all: ip22-kern.o indyIRQ.o -sgikern.a: $(OBJS) - $(AR) rcs sgikern.a $(OBJS) - sync +obj-y += indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \ + indyIRQ.o reset.o setup.o time.o indyIRQ.o: indyIRQ.S - -dep: - $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips/sni/Makefile linux.ac/arch/mips/sni/Makefile --- linux.vanilla/arch/mips/sni/Makefile Sat May 13 16:29:14 2000 +++ linux.ac/arch/mips/sni/Makefile Wed Apr 18 13:51:39 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.3 1999/01/04 16:03:57 ralf Exp $ # # Makefile for the SNI specific part of the kernel # @@ -12,12 +11,12 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -all: sni.o +all: sni.o int-handler.o + O_TARGET := sni.o -O_OBJS := dma.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o -int-handler.o: int-handler.S +obj-y := int-handler.o io.o irq.o pci.o pcimt_scache.o reset.o setup.o -clean: +int-handler.o: int-handler.S include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/config.in linux.ac/arch/mips64/config.in --- linux.vanilla/arch/mips64/config.in Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/config.in Wed Apr 18 13:51:45 2001 @@ -25,6 +25,9 @@ fi endmenu +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n + # # Select some configuration options automatically based on user selections # @@ -163,7 +166,7 @@ fi endmenu -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/defconfig linux.ac/arch/mips64/defconfig --- linux.vanilla/arch/mips64/defconfig Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/mips64/defconfig Wed Apr 18 13:51:53 2001 @@ -120,6 +120,11 @@ # CONFIG_BRIDGE is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set @@ -422,6 +427,7 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/defconfig-ip22 linux.ac/arch/mips64/defconfig-ip22 --- linux.vanilla/arch/mips64/defconfig-ip22 Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/defconfig-ip22 Wed Apr 18 13:51:53 2001 @@ -110,6 +110,11 @@ # CONFIG_BRIDGE is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/defconfig-ip27 linux.ac/arch/mips64/defconfig-ip27 --- linux.vanilla/arch/mips64/defconfig-ip27 Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/defconfig-ip27 Wed Apr 18 13:52:04 2001 @@ -120,6 +120,11 @@ # CONFIG_BRIDGE is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set @@ -165,6 +170,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -421,6 +427,7 @@ # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/kernel/semaphore.c linux.ac/arch/mips64/kernel/semaphore.c --- linux.vanilla/arch/mips64/kernel/semaphore.c Sun Nov 12 03:02:40 2000 +++ linux.ac/arch/mips64/kernel/semaphore.c Wed Apr 18 13:52:14 2001 @@ -127,112 +127,3 @@ { return waking_non_zero_trylock(sem); } - -/* - * RW Semaphores - */ -void -__down_read(struct rw_semaphore *sem, int count) -{ - DOWN_VAR; - - retry_down: - if (count < 0) { - /* Wait for the lock to become unbiased. Readers - are non-exclusive. */ - - /* This takes care of granting the lock. */ - up_read(sem); - - add_wait_queue(&sem->wait, &wait); - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - mb(); - count = atomic_dec_return(&sem->count); - if (count <= 0) - goto retry_down; - } else { - add_wait_queue(&sem->wait, &wait); - - while (1) { - if (test_and_clear_bit(0, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((sem->granted & 1) == 0) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - } -} - -void -__down_write(struct rw_semaphore *sem, int count) -{ - DOWN_VAR; - - retry_down: - if (count + RW_LOCK_BIAS < 0) { - up_write(sem); - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= RW_LOCK_BIAS) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - mb(); - count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (count != 0) - goto retry_down; - } else { - /* Put ourselves at the end of the list. */ - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); - - while (1) { - if (test_and_clear_bit(1, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((sem->granted & 2) == 0) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* If the lock is currently unbiased, awaken the sleepers. - FIXME: This wakes up the readers early in a bit of a - stampede -> bad! */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); - } -} - -void -__rwsem_wake(struct rw_semaphore *sem, unsigned long readers) -{ - if (readers) { - if (test_and_set_bit(0, &sem->granted)) - BUG(); - wake_up(&sem->wait); - } else { - if (test_and_set_bit(1, &sem->granted)) - BUG(); - wake_up(&sem->write_bias_wait); - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/mm/Makefile linux.ac/arch/mips64/mm/Makefile --- linux.vanilla/arch/mips64/mm/Makefile Mon Feb 5 05:48:46 2001 +++ linux.ac/arch/mips64/mm/Makefile Wed Apr 18 13:52:14 2001 @@ -4,7 +4,8 @@ O_TARGET := mm.o -obj-y := extable.o init.o fault.o loadmmu.o +export-objs += umap.o +obj-y := extable.o init.o fault.o loadmmu.o obj-$(CONFIG_CPU_R4300) += r4xx0.o obj-$(CONFIG_CPU_R4X00) += r4xx0.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/mm/fault.c linux.ac/arch/mips64/mm/fault.c --- linux.vanilla/arch/mips64/mm/fault.c Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/mips64/mm/fault.c Tue Apr 3 17:54:33 2001 @@ -6,6 +6,7 @@ * Copyright (C) 1995 - 2000 by Ralf Baechle * Copyright (C) 1999, 2000 by Silicon Graphics, Inc. */ +#include #include #include #include @@ -31,6 +32,7 @@ #define development_version (LINUX_VERSION_CODE & 0x100) extern void die(char *, struct pt_regs *, unsigned long write); +extern int console_loglevel; /* * Macro for exception fixup code to access integer registers. @@ -57,17 +59,34 @@ printk("Got exception 0x%lx at 0x%lx\n", retaddr, regs.cp0_epc); } -extern spinlock_t console_lock, timerlist_lock; +extern spinlock_t timerlist_lock; /* * Unlock any spinlocks which will prevent us from getting the - * message out (timerlist_lock is acquired through the + * message out (timerlist_lock is aquired through the * console unblank code) */ -void bust_spinlocks(void) +void bust_spinlocks(int yes) { - spin_lock_init(&console_lock); spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + global_irq_lock = 0; /* Many serial drivers do __global_cli() */ +#endif + } else { + int loglevel_save = console_loglevel; + unblank_screen(); + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } } /* @@ -195,7 +214,7 @@ * terminate things with extreme prejudice. */ - bust_spinlocks(); + bust_spinlocks(1); printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at " "address %08lx, epc == %08x, ra == %08x\n", @@ -203,6 +222,7 @@ (unsigned int) regs->regs[31]); die("Oops", regs, write); do_exit(SIGKILL); + bust_spinlocks(0); /* * We ran out of memory, or some other thing happened to us that made diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/mm/init.c linux.ac/arch/mips64/mm/init.c --- linux.vanilla/arch/mips64/mm/init.c Mon Oct 16 20:58:51 2000 +++ linux.ac/arch/mips64/mm/init.c Tue Apr 3 17:54:33 2001 @@ -37,6 +37,9 @@ #include #endif #include +#include + +mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long totalram_pages; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/mips64/tools/Makefile linux.ac/arch/mips64/tools/Makefile --- linux.vanilla/arch/mips64/tools/Makefile Mon Jul 10 06:18:16 2000 +++ linux.ac/arch/mips64/tools/Makefile Wed Apr 18 13:52:38 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1999/08/18 21:46:53 ralf Exp $ # # Makefile for MIPS kernel build tools. # diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/Makefile linux.ac/arch/parisc/Makefile --- linux.vanilla/arch/parisc/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/Makefile Tue Apr 3 17:54:33 2001 @@ -39,6 +39,8 @@ # No fixed-point multiply CFLAGS += -mdisable-fpregs +ASFLAGS := -D__ASSEMBLY__ -traditional + HEAD = arch/parisc/kernel/head.o SUBDIRS := $(SUBDIRS) $(addprefix arch/parisc/, tools kernel mm lib hpux) @@ -85,6 +87,7 @@ install: archclean: + $(MAKE) -C arch/$(ARCH)/tools clean archmrproper: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/config.common linux.ac/arch/parisc/config.common --- linux.vanilla/arch/parisc/config.common Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/config.common Tue Apr 3 17:54:33 2001 @@ -0,0 +1,159 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# + +mainmenu_name "Linux Kernel Configuration" + +define_bool CONFIG_PARISC y +define_bool CONFIG_UID16 n + +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 '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 + +mainmenu_option next_comment +comment 'General options' + +bool 'Symmetric multi-processing support' CONFIG_SMP + +bool 'Kernel Debugger support' CONFIG_KWDB +# define_bool CONFIG_KWDB n + +bool 'GSC/Gecko bus support' CONFIG_GSC y + +bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y +bool 'LASI I/O support' CONFIG_GSC_LASI y +bool 'WAX support' CONFIG_GSC_WAX y + +bool 'PCI or EISA bus support' CONFIG_PCI y + +if [ "$CONFIG_PCI" = "y" ]; then + bool ' GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y + bool ' LBA/Elroy PCI support' CONFIG_PCI_LBA n +# bool ' EPIC PCI support' CONFIG_PCI_EPIC n + dep_bool ' WAX EISA support' CONFIG_WAX_EISA y $CONFIG_GSC_WAX + bool ' SuperIO support' CONFIG_SUPERIO n +fi + +if [ "$CONFIG_PCI_LBA" = "y" ]; then + define_bool CONFIG_IOSAPIC y + define_bool CONFIG_IOMMU_SBA y +fi + +source drivers/pci/Config.in + +bool 'Chassis LCD and LED support' CONFIG_CHASSIS_LCD_LED y + +endmenu + +mainmenu_option next_comment +comment 'General setup' + +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +bool 'Networking support' CONFIG_NET + +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +define_bool CONFIG_KCORE_ELF y +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + +# anyone want to get ACPI working on PA/RISC? +define_bool CONFIG_PM n + +endmenu + +source drivers/parport/Config.in + +source drivers/block/Config.in + +source drivers/md/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +# when SuckyIO is working, put the IDE stuff in here. + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in +fi +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi + fi + endmenu +fi + +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in +source drivers/char/Config.in + +source drivers/media/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + source drivers/video/Config.in + + bool 'STI console' CONFIG_STI_CONSOLE + if [ "$CONFIG_GSC_PS2" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + if [ "$CONFIG_STI_CONSOLE" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + endmenu +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +# when SuckyIO is working +#source drivers/usb/Config.in + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/config.in linux.ac/arch/parisc/config.in --- linux.vanilla/arch/parisc/config.in Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/config.in Wed Apr 18 13:52:38 2001 @@ -3,206 +3,6 @@ # see the Configure script. # -mainmenu_name "Linux Kernel Configuration" - -define_bool CONFIG_PARISC y -define_bool CONFIG_UID16 n - -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 'General options' - -# bool 'Symmetric multi-processing support' CONFIG_SMP -define_bool CONFIG_SMP n - -bool 'Kernel Debugger support' CONFIG_KWDB -# define_bool CONFIG_KWDB n - -# bool 'GSC/Gecko bus support' CONFIG_GSC y -define_bool CONFIG_GSC y - -bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y -bool 'LASI I/O support' CONFIG_GSC_LASI y - -bool 'PCI bus support' CONFIG_PCI y - -if [ "$CONFIG_PCI" = "y" ]; then - bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y - bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n -fi - -if [ "$CONFIG_PCI_LBA" = "y" ]; then - define_bool CONFIG_IOSAPIC y - define_bool CONFIG_IOMMU_SBA y -fi - -# -# if [ "$CONFIG_PCI_EPIC" = "y" ]; then... -# - -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 - -mainmenu_option next_comment -comment 'General setup' - -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 SOM binaries' CONFIG_BINFMT_SOM -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF -tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA -fi - -endmenu - -##source drivers/parport/Config.in -mainmenu_option next_comment -comment 'Parallel port support' - -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - if [ "$CONFIG_PCI" = "y" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO - fi - fi - fi - if [ "$CONFIG_GSC_LASI" = "y" ]; then - dep_tristate ' LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT - else - define_tristate CONFIG_PARPORT_GSC 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. - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - - bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 -fi -endmenu - - -source drivers/block/Config.in - -if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in -fi - -mainmenu_option next_comment -comment 'SCSI support' - -tristate 'SCSI support' CONFIG_SCSI - -if [ "$CONFIG_SCSI" != "n" ]; then - comment 'SCSI support type (disk, tape, CDrom)' - - dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then - int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 - fi - - dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR - int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 - fi - dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI - - comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' - bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN - bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS - - mainmenu_option next_comment - comment 'SCSI low-level drivers' - if [ "$CONFIG_GSC_LASI" = "y" ]; then - dep_tristate 'Lasi SCSI support' CONFIG_SCSI_LASI $CONFIG_SCSI - dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_SCSI - fi - if [ "$CONFIG_PCI" = "y" ]; then - dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI - fi - if [ "$CONFIG_SCSI_ZALON" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then - int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 - int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 - int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 - bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE - bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED - fi - endmenu -fi -endmenu - -if [ "$CONFIG_NET" = "y" ]; then - mainmenu_option next_comment - comment 'Network device support' - - bool 'Network device support' CONFIG_NETDEVICES - - if [ "$CONFIG_NETDEVICES" = "y" ]; then - if [ "$CONFIG_GSC_LASI" = "y" ]; then - tristate 'Lasi ethernet' CONFIG_LASI_82596 - fi - source drivers/net/Config.in - fi - endmenu -fi - -source drivers/char/Config.in - -source fs/Config.in - -mainmenu_option next_comment -comment 'Sound Drivers' -tristate 'Sound card support' CONFIG_SOUND -if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in -fi -endmenu - -if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - source drivers/video/Config.in - -# bool 'IODC console' CONFIG_IODC_CONSOLE - bool 'STI console' CONFIG_STI_CONSOLE - if [ "$CONFIG_IODC_CONSOLE" = "n" ]; then - if [ "$CONFIG_GSC_PS2" = "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - fi - fi - if [ "$CONFIG_STI_CONSOLE" = "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - fi - endmenu -fi -# endmenu - -mainmenu_option next_comment -comment 'Kernel hacking' - -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -endmenu +define_bool CONFIG_PARISC32 y +source arch/parisc/config.common diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/defconfig linux.ac/arch/parisc/defconfig --- linux.vanilla/arch/parisc/defconfig Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/defconfig Tue Apr 3 17:54:33 2001 @@ -1,6 +1,7 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # +CONFIG_PARISC32=y CONFIG_PARISC=y # CONFIG_UID16 is not set @@ -10,6 +11,11 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +# CONFIG_MODULES is not set + +# # General options # # CONFIG_SMP is not set @@ -17,37 +23,41 @@ CONFIG_GSC=y CONFIG_IOMMU_CCIO=y CONFIG_GSC_LASI=y +CONFIG_GSC_WAX=y CONFIG_PCI=y CONFIG_GSC_DINO=y CONFIG_PCI_LBA=y +CONFIG_WAX_EISA=y +# CONFIG_SUPERIO is not set CONFIG_IOSAPIC=y CONFIG_IOMMU_SBA=y - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +CONFIG_PCI_NAMES=y +CONFIG_CHASSIS_LCD_LED=y # # General setup # +CONFIG_HOTPLUG=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -CONFIG_BINFMT_SOM=y +CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_SOM=y # CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set +# CONFIG_PM is not set # # Parallel port support # CONFIG_PARPORT=y # CONFIG_PARPORT_PC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set CONFIG_PARPORT_GSC=y +# CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set # CONFIG_PARPORT_1284 is not set @@ -67,6 +77,20 @@ CONFIG_BLK_DEV_INITRD=y # +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID5=y +# CONFIG_MD_BOOT is not set +# CONFIG_AUTODETECT_RAID is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_LVM_PROC_FS is not set + +# # Networking options # # CONFIG_PACKET is not set @@ -87,6 +111,10 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -109,33 +137,92 @@ # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set # CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers # +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# 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 +# CONFIG_SCSI_AIC7XXX is not set +# 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_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D 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_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set CONFIG_SCSI_LASI=y CONFIG_SCSI_ZALON=y +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set CONFIG_SCSI_SYM53C8XX=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT 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 is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set # # Network device support # CONFIG_NETDEVICES=y -CONFIG_LASI_82596=y # # ARCnet devices @@ -151,6 +238,7 @@ # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +CONFIG_LASI_82596=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set @@ -162,27 +250,28 @@ CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set -# CONFIG_DE4X5 is not set CONFIG_TULIP=y +# CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set -# CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # @@ -217,6 +306,16 @@ # CONFIG_WAN is not set # +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# # Character devices # CONFIG_VT=y @@ -249,6 +348,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -269,6 +372,17 @@ # CONFIG_FTAPE is not set # CONFIG_AGP is not set # CONFIG_DRM is not set +CONFIG_PCMCIA_SERIAL=y + +# +# PCMCIA character device support +# +# CONFIG_PCMCIA_SERIAL_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -330,8 +444,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -340,14 +452,10 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # -# Sound Drivers -# -# CONFIG_SOUND is not set - -# # Console drivers # @@ -356,6 +464,12 @@ # # CONFIG_FB is not set # CONFIG_STI_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set # # Kernel hacking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/Makefile linux.ac/arch/parisc/hpux/Makefile --- linux.vanilla/arch/parisc/hpux/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/Makefile Tue Apr 3 17:54:33 2001 @@ -7,10 +7,7 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -all: hpux.o O_TARGET = hpux.o -O_OBJS = entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o - -.o.S: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o +obj-y := entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/fs.c linux.ac/arch/parisc/hpux/fs.c --- linux.vanilla/arch/parisc/hpux/fs.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/fs.c Tue Apr 3 17:54:33 2001 @@ -52,7 +52,8 @@ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) -static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +static int filldir(void * __buf, const char * name, int namlen, off_t offset, + ino_t ino, unsigned int d_type) { struct hpux_dirent * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/gate.S linux.ac/arch/parisc/hpux/gate.S --- linux.vanilla/arch/parisc/hpux/gate.S Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/hpux/gate.S Tue Apr 3 17:54:33 2001 @@ -8,7 +8,6 @@ * sorry about the wall, puffin.. */ -#define __ASSEMBLY__ #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/ioctl.c linux.ac/arch/parisc/hpux/ioctl.c --- linux.vanilla/arch/parisc/hpux/ioctl.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/ioctl.c Tue Apr 3 17:54:33 2001 @@ -54,10 +54,6 @@ case 't': result = hpux_ioctl_t(fd, cmd, arg); break; - default: - /* If my mother ever sees this, I hope she disowns me. - * Take this out after NYLWE. */ - result = sys_ioctl(fd, cmd, arg); } return result; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/hpux/wrappers.S linux.ac/arch/parisc/hpux/wrappers.S --- linux.vanilla/arch/parisc/hpux/wrappers.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/hpux/wrappers.S Tue Apr 3 17:54:33 2001 @@ -29,7 +29,6 @@ .level 1.1 .text -#define __ASSEMBLY__ #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/Makefile linux.ac/arch/parisc/kernel/Makefile --- linux.vanilla/arch/parisc/kernel/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/Makefile Tue Apr 3 17:54:33 2001 @@ -8,25 +8,23 @@ # Note 2! The CFLAGS definitions are now in the main makefile... all: kernel.o init_task.o pdc_cons.o process.o head.o -O_TARGET = kernel.o -O_OBJS = -# Object file lists. +O_TARGET = kernel.o obj-y := obj-m := obj-n := obj- := -obj-y += cache.o setup.o traps.o time.o irq.o \ +obj-y += cache.o pacache.o setup.o traps.o time.o irq.o \ syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \ inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \ - signal.o hpmc.o \ - real1.o real2.o led.o parisc_ksyms.o + signal.o hpmc.o real1.o real2.o parisc_ksyms.o export-objs := parisc_ksyms.o +obj-$(CONFIG_SMP) += smp.o irq_smp.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_VT) += keyboard.o obj-$(CONFIG_PCI_LBA) += lba_pci.o @@ -37,16 +35,7 @@ # Only use one of them: ccio-rm-dma is for PCX-W systems *only* # obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o - -.o.S: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o - -# Translate to Rules.make lists. - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) -MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) +obj-$(CONFIG_CHASSIS_LCD_LED) += led.o +obj-$(CONFIG_SUPERIO) += superio.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/cache.c linux.ac/arch/parisc/kernel/cache.c --- linux.vanilla/arch/parisc/kernel/cache.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/cache.c Tue Apr 3 17:54:33 2001 @@ -21,170 +21,38 @@ #include #include #include +#include + +int split_tlb; +int dcache_stride; +int icache_stride; struct pdc_cache_info cache_info; #ifndef __LP64__ static struct pdc_btlb_info btlb_info; #endif +/* flushes EVERYTHING (tlb & cache) */ -void __flush_page_to_ram(unsigned long address) +void +flush_all_caches(void) { - __flush_dcache_range(address, PAGE_SIZE); - __flush_icache_range(address, PAGE_SIZE); + flush_instruction_cache(); + flush_data_cache(); + flush_tlb_all(); } - - -void flush_data_cache(void) -{ - register unsigned long base = cache_info.dc_base; - register unsigned long count = cache_info.dc_count; - register unsigned long loop = cache_info.dc_loop; - register unsigned long stride = cache_info.dc_stride; - register unsigned long addr; - register long i, j; - - for(i=0,addr=base; imapping && + test_bit(PG_dcache_dirty, &page->flags)) { -void flush_data_tlb(void) -{ - unsigned long base = cache_info.dt_sp_base; - unsigned long count = cache_info.dt_sp_count; - unsigned long stride = cache_info.dt_sp_stride; - unsigned long space; - unsigned long old_sr1; - long i; - - old_sr1 = mfsp(1); - - for(i=0,space=base; iflags); } - - mtsp(old_sr1, 1); -} - -static inline void flush_instruction_tlb_space(void) -{ - unsigned long base = cache_info.it_off_base; - unsigned long count = cache_info.it_off_count; - unsigned long stride = cache_info.it_off_stride; - unsigned long loop = cache_info.it_loop; - - unsigned long addr; - long i,j; - - for(i=0,addr=base; i #include #include +#define PCI_DEBUG #include +#undef PCI_DEBUG #include #include /* for L1_CACHE_BYTES */ #include #include #include - +#include #include #include /* for gsc_writeN()... */ +#include /* for register_module() */ /* ** Choose "ccio" since that's what HP-UX calls it. @@ -55,12 +58,11 @@ */ #define MODULE_NAME "ccio" -/* -#define DEBUG_CCIO_RES -#define DEBUG_CCIO_RUN -#define DEBUG_CCIO_INIT -#define DUMP_RESMAP -*/ +#undef DEBUG_CCIO_RES +#undef DEBUG_CCIO_RUN +#undef DEBUG_CCIO_INIT +#undef DEBUG_CCIO_RUN_SG +#undef ASSERT_PDIR_SANITY #include #include /* for proc_runway_root */ @@ -83,8 +85,15 @@ #define DBG_RES(x...) #endif +#ifdef DEBUG_CCIO_RUN_SG +#define DBG_RUN_SG(x...) printk(x) +#else +#define DBG_RUN_SG(x...) +#endif + #define CCIO_INLINE /* inline */ -#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) +#define WRITE_U32(value, addr) gsc_writel(value, (u32 *)(addr)) +#define READ_U32(addr) gsc_readl((u32 *)(addr)) #define U2_IOA_RUNWAY 0x580 #define U2_BC_GSC 0x501 @@ -92,46 +101,22 @@ #define UTURN_BC_GSC 0x502 /* We *can't* support JAVA (T600). Venture there at your own risk. */ -static void dump_resmap(void); static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *); static struct pa_iodc_driver ccio_drivers_for[] = { - - {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback}, - - {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback}, - -/* -** FIXME: The following claims the GSC bus port, not the IOA. -** And there are two busses below a single I/O TLB. -** -** These should go away once we have a real PA bus walk. -** Firmware wants to tell the PA bus walk code about the GSC ports -** since they are not "architected" PA I/O devices. Ie a PA bus walk -** wouldn't discover them. But the PA bus walk code could check -** the "fixed module table" to add such devices to an I/O Tree -** and proceed with the recursive, depth first bus walk. -*/ - {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xc, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "U2 GSC+ BC", (void *) ccio_driver_callback}, - - {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xc, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "Uturn GSC+ BC", (void *) ccio_driver_callback}, - - {0,0,0,0,0,0, - 0, - (char *) NULL, (char *) NULL, (void *) NULL } + {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION + + DRIVER_CHECK_HWTYPE, MODULE_NAME, "U2 I/O MMU", + (void *)ccio_driver_callback}, + + {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION + + DRIVER_CHECK_HWTYPE, MODULE_NAME, "Uturn I/O MMU", + (void *)ccio_driver_callback}, + + {0,0,0,0,0,0,0, + (char *)NULL, (char *)NULL, (void *)NULL} }; @@ -176,41 +161,57 @@ volatile uint32_t io_io_high; /* Offset 15 */ }; +struct ioc { + struct ioa_registers *ioc_hpa; /* I/O MMU base address */ + u8 *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + + u32 res_hint; /* next available IOVP - + circular search */ + u32 res_size; /* size of resource map in bytes */ + spinlock_t res_lock; -struct ccio_device { - struct ccio_device *next; /* list of LBA's in system */ - struct hp_device *iodc; /* data about dev from firmware */ - spinlock_t ccio_lock; +#ifdef CONFIG_PROC_FS +#define CCIO_SEARCH_SAMPLE 0x100 + unsigned long avg_search[CCIO_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; - struct ioa_registers *ccio_hpa; /* base address */ - u64 *pdir_base; /* physical base address */ - char *res_map; /* resource map, bit == pdir entry */ - - int res_hint; /* next available IOVP - circular search */ - int res_size; /* size of resource map in bytes */ - int chainid_shift; /* specify bit location of chain_id */ - int flags; /* state/functionality enabled */ -#ifdef DELAYED_RESOURCE_CNT - dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; + unsigned short cujo20_bug; #endif /* STUFF We don't need in performance path */ - int pdir_size; /* in bytes, determined by IOV Space size */ - int hw_rev; /* HW revision of chip */ + u32 pdir_size; /* in bytes, determined by IOV Space size */ + u32 chainid_shift; /* specify bit location of chain_id */ + struct ccio_device *ioa; + struct hp_device *iodc; /* data about dev from firmware */ }; +struct ccio_device { + struct ccio_device *next; /* list of LBA's in system */ + spinlock_t ccio_lock; -/* Ratio of Host MEM to IOV Space size */ -static unsigned long ccio_mem_ratio = 4; -static struct ccio_device *ccio_list = NULL; + /* STUFF We don't need in performance path */ + int hw_rev; /* HW revision of chip */ + int flags; /* state/functionality enabled */ + unsigned short num_ioc; /* number of on-board IOC's */ +#define MAX_IOC 2 + struct ioc ioc[MAX_IOC]; +}; -static int ccio_proc_info(char *buffer, char **start, off_t offset, int length); -static unsigned long ccio_used_bytes = 0; -static unsigned long ccio_used_pages = 0; -static int ccio_cujo_bug = 0; -static unsigned long ccio_alloc_size = 0; -static unsigned long ccio_free_size = 0; +/* Ratio of Host MEM to IOV Space size */ +static unsigned long ccio_mem_ratio = 32; +static struct ccio_device *ccio_list; +static int ccio_count; /************************************************************** * @@ -239,16 +240,78 @@ #define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) #define MKIOVP(pdir_idx) ((long)(pdir_idx) << IOVP_SHIFT) #define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) +#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) -/* CUJO20 KLUDGE start */ -#define CUJO_20_BITMASK 0x0ffff000 /* upper nibble is a don't care */ -#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ -#define CUJO_20_BADPAGE1 0x01003000 /* pages that hpmc on raven U+ */ -#define CUJO_20_BADPAGE2 0x01607000 /* pages that hpmc on firehawk U+ */ -#define CUJO_20_BADHVERS 0x6821 /* low nibble 1 is cujo rev 2.0 */ -#define CUJO_RAVEN_LOC 0xf1000000UL /* cujo location on raven U+ */ -#define CUJO_FIREHAWK_LOC 0xf1604000UL /* cujo location on firehawk U+ */ -/* CUJO20 KLUDGE end */ +#ifdef ASSERT_PDIR_SANITY +static void +ccio_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) +{ + /* start printing from lowest pde in rval */ + u64 *ptr = &(ioc->pdir_base[pide & (~0UL * BITS_PER_LONG)]); + unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); + uint rcnt; + + printk("ccio: %s rp %p bit %d rval 0x%lx\n", msg, + rptr, pide & (BITS_PER_LONG - 1), *rptr); + + rcnt = 0; + while(rcnt < BITS_PER_LONG) { + printk("%s %2d %p %016Lx\n", + (rcnt == (pide & (BITS_PER_LONG - 1))) + ? " -->" : " ", + rcnt, ptr, *ptr ); + rcnt++; + ptr++; + } + printk(msg); +} + +static int +ccio_check_pdir(struct ioc *ioc, char *msg) +{ + int i, j; + u32 *res_ptr = (u32 *)ioc->res_map; + u32 *pptr = (u32 *)ioc->pdir_base; + u32 pmap; + char buf1[512] = {0}; + char buf2[512] = {0}; + + ++pptr; + + printk(msg); + for(i = 0; i < (ioc->res_size / sizeof(u32)); ++i, ++res_ptr) { + if((i & 15) == 0) { + printk("%s\n", buf1); + buf1[0] = '\0'; + printk("%s\n", buf2); + buf2[0] = '\0'; + printk("\n"); + } + for(j = 0, pmap = 0; j < 32; ++j, ++pptr, ++pptr) { + pmap |= (*pptr & 0x1) << (31 - j); + } + sprintf(buf1, "%s %08x", buf1, *res_ptr); + sprintf(buf2, "%s %08x", buf2, pmap); + } + printk("%s\n", buf1); + printk("%s\n", buf2); + printk("\n"); + return 0; +} + +static void +ccio_dump_sg(struct ioc *ioc, struct scatterlist *startsg, int nents) +{ + while(nents-- > 0) { + printk(" %d : %08lx/%05x %p/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), + sg_dma_len(startsg), + startsg->address, startsg->length); + startsg++; + } +} + +#endif /* ASSERT_PDIR_SANITY */ /* ** Don't worry about the 150% average search length on a miss. @@ -256,26 +319,24 @@ ** cause the kernel to panic anyhow. */ -/* ioa->res_hint = idx + (size >> 3); \ */ -#define CCIO_SEARCH_LOOP(ioa, idx, mask, size) \ - for(; res_ptr < res_end; ++res_ptr) \ - { \ - if(0 == ((*res_ptr) & mask)) { \ - *res_ptr |= mask; \ - idx = (int)((unsigned long)res_ptr - (unsigned long)ioa->res_map); \ - ioa->res_hint = 0;\ +#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size) \ + for(; res_ptr < res_end; ++res_ptr) { \ + if(0 == (*res_ptr & *mask_ptr)) { \ + *res_ptr |= *mask_ptr; \ + res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ + ioc->res_hint = res_idx + (size >> 3); \ goto resource_found; \ } \ } -#define CCIO_FIND_FREE_MAPPING(ioa, idx, mask, size) { \ - u##size *res_ptr = (u##size *)&((ioa)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ - u##size *res_end = (u##size *)&(ioa)->res_map[ioa->res_size]; \ - CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ - res_ptr = (u##size *)&(ioa)->res_map[0]; \ - CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ -} +#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ + u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ + u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \ + u##size *mask_ptr = (u##size *)&mask; \ + CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \ + res_ptr = (u##size *)&(ioc)->res_map[0]; \ + CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size); /* ** Find available bit in this ioa's resource map. @@ -291,23 +352,24 @@ ** (eg > 16 pages) mappings. */ static int -ccio_alloc_range(struct ccio_device *ioa, size_t size) +ccio_alloc_range(struct ioc *ioc, size_t size) { int res_idx; - unsigned long mask, flags; - unsigned int pages_needed = size >> PAGE_SHIFT; - + unsigned long pages_needed = (size >> IOVP_SHIFT); + unsigned long mask = ~0L; +#ifdef CONFIG_PROC_FS + unsigned long cr_start = mfctl(16); +#endif + ASSERT(pages_needed); ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); - - mask = (unsigned long) -1L; - mask >>= BITS_PER_LONG - pages_needed; + ASSERT(pages_needed < BITS_PER_LONG); + ASSERT(0 == (size & ~IOVP_MASK)); - DBG_RES(__FUNCTION__ " size: %d pages_needed %d pages_mask 0x%08lx\n", - size, pages_needed, mask); - - spin_lock_irqsave(&ioa->ccio_lock, flags); + mask = ~(mask >> pages_needed); + + DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", + __FUNCTION__, size, pages_needed, mask); /* ** "seek and ye shall find"...praying never hurts either... @@ -315,98 +377,93 @@ */ if(pages_needed <= 8) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 8); + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8); } else if(pages_needed <= 16) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 16); + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16); } else if(pages_needed <= 32) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 32); + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32); #ifdef __LP64__ } else if(pages_needed <= 64) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 64) + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64); #endif } else { - panic(__FILE__ ":" __FUNCTION__ "() Too many pages to map.\n"); + panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n", __FUNCTION__, pages_needed); } -#ifdef DUMP_RESMAP - dump_resmap(); +#ifdef ASSERT_PDIR_SANITY + ccio_check_pdir(ioc, "bummer"); #endif - panic(__FILE__ ":" __FUNCTION__ "() I/O MMU is out of mapping resources\n"); + panic(__FILE__ ": %s() I/O MMU is out of mapping resources.\n", __FUNCTION__); resource_found: - DBG_RES(__FUNCTION__ " res_idx %d mask 0x%08lx res_hint: %d\n", - res_idx, mask, ioa->res_hint); - - ccio_used_pages += pages_needed; - ccio_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1); + DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n", + __FUNCTION__, res_idx, mask, ioc->res_hint); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); +#ifdef CONFIG_PROC_FS + { + unsigned long cr_end = mfctl(16); + unsigned long tmp = cr_end - cr_start; + /* check for roll over */ + cr_start = (cr_end < cr_start) ? -(tmp) : (tmp); + } + ioc->avg_search[ioc->avg_idx++] = cr_start; + ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; -#ifdef DUMP_RESMAP - dump_resmap(); + ioc->used_pages += pages_needed; #endif /* - ** return the bit address (convert from byte to bit). + ** return the bit address. */ - return (res_idx << 3); + return res_idx << 3; } - -#define CCIO_FREE_MAPPINGS(ioa, idx, mask, size) \ - u##size *res_ptr = (u##size *)&((ioa)->res_map[idx + (((size >> 3) - 1) & ~((size >> 3) - 1))]); \ - ASSERT((*res_ptr & mask) == mask); \ - *res_ptr &= ~mask; +#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \ + u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \ + u##size *mask_ptr = (u##size *)&mask; \ + ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \ + *res_ptr &= ~(*mask_ptr); /* ** clear bits in the ioa's resource map */ static void -ccio_free_range(struct ccio_device *ioa, dma_addr_t iova, size_t size) +ccio_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) { - unsigned long mask, flags; + unsigned long mask = ~0L; unsigned long iovp = CCIO_IOVP(iova); - unsigned int res_idx = PDIR_INDEX(iovp)>>3; - unsigned int pages_mapped = (size >> IOVP_SHIFT) + !!(size & ~IOVP_MASK); + unsigned int res_idx = PDIR_INDEX(iovp) >> 3; + unsigned int pages_mapped = (size >> IOVP_SHIFT); - ASSERT(pages_needed); - ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); + ASSERT(pages_mapped); + ASSERT((pages_mapped * IOVP_SIZE) < DMA_CHUNK_SIZE); + ASSERT(pages_mapped < BITS_PER_LONG); - mask = (unsigned long) -1L; - mask >>= BITS_PER_LONG - pages_mapped; + mask = ~(mask >> pages_mapped); - DBG_RES(__FUNCTION__ " res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", - res_idx, size, pages_mapped, mask); + DBG_RES("%s(): res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", + __FUNCTION__, res_idx, size, pages_mapped, mask); - spin_lock_irqsave(&ioa->ccio_lock, flags); +#ifdef CONFIG_PROC_FS + ioc->used_pages -= pages_mapped; +#endif if(pages_mapped <= 8) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 8); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8); } else if(pages_mapped <= 16) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 16); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16); } else if(pages_mapped <= 32) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 32); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32); #ifdef __LP64__ } else if(pages_mapped <= 64) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 64); + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64); #endif } else { - panic(__FILE__ ":" __FUNCTION__ "() Too many pages to unmap.\n"); + panic(__FILE__ ":%s() Too many pages to unmap.\n", __FUNCTION__); } - - ccio_used_pages -= (pages_mapped ? pages_mapped : 1); - ccio_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1); - - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - -#ifdef DUMP_RESMAP - dump_resmap(); -#endif } - /**************************************************************** ** ** CCIO dma_ops support routines @@ -500,7 +557,7 @@ /* We currently only support kernel addresses */ ASSERT(sid == 0); - ASSERT(((unsigned long) vba & 0xf0000000UL) == 0xc0000000UL); + ASSERT(((unsigned long) vba & 0xc0000000UL) == 0xc0000000UL); mtsp(sid,1); @@ -556,27 +613,25 @@ asm volatile("sync"); } - /* ** Remove stale entries from the I/O TLB. ** Need to do this whenever an entry in the PDIR is marked invalid. */ static CCIO_INLINE void -ccio_clear_io_tlb( struct ccio_device *d, dma_addr_t iovp, size_t byte_cnt) +ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt) { - u32 chain_size = 1 << d->chainid_shift; + u32 chain_size = 1 << ioc->chainid_shift; iovp &= ~(IOVP_SIZE-1); /* clear offset bits, just want pagenum */ byte_cnt += chain_size; - while (byte_cnt > chain_size) { - WRITE_U32(CMD_TLB_PURGE | iovp, &d->ccio_hpa->io_command); - iovp += chain_size; + while(byte_cnt > chain_size) { + WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_hpa->io_command); + iovp += chain_size; byte_cnt -= chain_size; - } + } } - /*********************************************************** * * Mark the I/O Pdir entries invalid and blow away the @@ -590,23 +645,21 @@ * (We do need to maker I/O PDIR entries invalid regardless). ***********************************************************/ static CCIO_INLINE void -ccio_mark_invalid(struct ccio_device *d, dma_addr_t iova, size_t byte_cnt) +ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) { - u32 iovp = (u32) CCIO_IOVP(iova); + u32 iovp = (u32)CCIO_IOVP(iova); size_t saved_byte_cnt; /* round up to nearest page size */ - saved_byte_cnt = byte_cnt = (byte_cnt + IOVP_SIZE - 1) & IOVP_MASK; + saved_byte_cnt = byte_cnt = (byte_cnt + ~IOVP_MASK) & IOVP_MASK; - while (byte_cnt > 0) { + while(byte_cnt > 0) { /* invalidate one page at a time */ unsigned int idx = PDIR_INDEX(iovp); - char *pdir_ptr = (char *) &(d->pdir_base[idx]); - - ASSERT( idx < (d->pdir_size/sizeof(u64))); - - pdir_ptr[7] = 0; /* clear only VALID bit */ + char *pdir_ptr = (char *) &(ioc->pdir_base[idx]); + ASSERT(idx < (ioc->pdir_size / sizeof(u64))); + pdir_ptr[7] = 0; /* clear only VALID bit */ /* ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) ** PCX-U/U+ do. (eg C200/C240) @@ -622,67 +675,44 @@ } asm volatile("sync"); - ccio_clear_io_tlb(d, CCIO_IOVP(iova), saved_byte_cnt); + ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); } - /**************************************************************** ** ** CCIO dma_ops ** *****************************************************************/ -void __init ccio_init(void) -{ - register_driver(ccio_drivers_for); -} - - -static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask) +static int +ccio_dma_supported(struct pci_dev *dev, dma_addr_t mask) { - if (dev == NULL) { + if(dev == NULL) { printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); BUG(); - return(0); + return 0; } dev->dma_mask = mask; /* save it */ /* only support 32-bit devices (ie PCI/GSC) */ - return((int) (mask >= 0xffffffffUL)); -} - -/* -** Dump a hex representation of the resource map. -*/ - -#ifdef DUMP_RESMAP -static -void dump_resmap() -{ - struct ccio_device *ioa = ccio_list; - unsigned long *res_ptr = (unsigned long *)ioa->res_map; - unsigned long i = 0; - - printk("res_map: "); - for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) - printk("%08lx ", *res_ptr); - - printk("\n"); + return (int)(mask >= 0xffffffffUL); } -#endif /* ** map_single returns a fully formed IOVA */ -static dma_addr_t ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) + +static dma_addr_t +ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) { - struct ccio_device *ioa = ccio_list; /* FIXME : see Multi-IOC below */ + int idx; + struct ioc *ioc = &ccio_list->ioc[0]; + unsigned long flags; dma_addr_t iovp; dma_addr_t offset; u64 *pdir_start; unsigned long hint = hint_lookup[direction]; - int idx; ASSERT(size > 0); @@ -690,41 +720,49 @@ offset = ((dma_addr_t) addr) & ~IOVP_MASK; /* round up to nearest IOVP_SIZE */ - size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; + size = (size + offset + ~IOVP_MASK) & IOVP_MASK; - idx = ccio_alloc_range(ioa, size); - iovp = (dma_addr_t) MKIOVP(idx); + spin_lock_irqsave(&ioc->res_lock, flags); - DBG_RUN(__FUNCTION__ " 0x%p -> 0x%lx", addr, (long) iovp | offset); +#ifdef CONFIG_PROC_FS + ioc->msingle_calls++; + ioc->msingle_pages += size >> IOVP_SHIFT; +#endif + + idx = ccio_alloc_range(ioc, size); + iovp = (dma_addr_t)MKIOVP(idx); - pdir_start = &(ioa->pdir_base[idx]); + pdir_start = &(ioc->pdir_base[idx]); + + DBG_RUN("%s() 0x%p -> 0x%lx", __FUNCTION__, addr, (long)iovp | offset); /* If not cacheline aligned, force SAFE_DMA on the whole mess */ - if ((size % L1_CACHE_BYTES) || ((unsigned long) addr % L1_CACHE_BYTES)) + if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES)) hint |= HINT_SAFE_DMA; /* round up to nearest IOVP_SIZE */ - size = (size + IOVP_SIZE - 1) & IOVP_MASK; - - while (size > 0) { + size = (size + ~IOVP_MASK) & IOVP_MASK; + while(size > 0) { ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint); DBG_RUN(" pdir %p %08x%08x\n", pdir_start, (u32) (((u32 *) pdir_start)[0]), - (u32) (((u32 *) pdir_start)[1]) - ); + (u32) (((u32 *) pdir_start)[1])); + ++pdir_start; addr += IOVP_SIZE; size -= IOVP_SIZE; - pdir_start++; } + + spin_unlock_irqrestore(&ioc->res_lock, flags); + /* form complete address */ return CCIO_IOVA(iovp, offset); } - -static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) +static void +ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) { #ifdef FIXME /* Multi-IOC (ie N-class) : need to lookup IOC from dev @@ -737,117 +775,362 @@ #else struct ccio_device *ioa = ccio_list; #endif - dma_addr_t offset; + struct ioc *ioc = &ioa->ioc[0]; + unsigned long flags; + dma_addr_t offset = iova & ~IOVP_MASK; - offset = iova & ~IOVP_MASK; - - /* round up to nearest IOVP_SIZE */ - size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; + DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long)iova, size); - /* Mask off offset */ - iova &= IOVP_MASK; + iova ^= offset; /* clear offset bits */ + size += offset; + size = ROUNDUP(size, IOVP_SIZE); - DBG_RUN(__FUNCTION__ " iovp 0x%lx\n", (long) iova); + spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef DELAYED_RESOURCE_CNT - if (ioa->saved_cnt < DELAYED_RESOURCE_CNT) { - ioa->saved_iova[ioa->saved_cnt] = iova; - ioa->saved_size[ioa->saved_cnt] = size; - ccio_saved_cnt++; - } else { - do { +#ifdef CONFIG_PROC_FS + ioc->usingle_calls++; + ioc->usingle_pages += size >> IOVP_SHIFT; #endif - ccio_mark_invalid(ioa, iova, size); - ccio_free_range(ioa, iova, size); -#ifdef DELAYED_RESOURCE_CNT - d->saved_cnt--; - iova = ioa->saved_iova[ioa->saved_cnt]; - size = ioa->saved_size[ioa->saved_cnt]; - } while (ioa->saved_cnt) - } -#endif + ccio_mark_invalid(ioc, iova, size); + ccio_free_range(ioc, iova, size); + spin_unlock_irqrestore(&ioc->res_lock, flags); } - -static void * ccio_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +static void * +ccio_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_handle) { - void *ret; - unsigned long flags; - struct ccio_device *ioa = ccio_list; - - DBG_RUN(__FUNCTION__ " size 0x%x\n", size); - + void *ret; #if 0 /* GRANT Need to establish hierarchy for non-PCI devs as well ** and then provide matching gsc_map_xxx() functions for them as well. */ - if (!hwdev) { + if(!hwdev) { /* only support PCI */ *dma_handle = 0; return 0; } #endif - spin_lock_irqsave(&ioa->ccio_lock, flags); - ccio_alloc_size += get_order(size); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); if (ret) { memset(ret, 0, size); - *dma_handle = ccio_map_single(hwdev, ret, size, PCI_DMA_BIDIRECTIONAL); + *dma_handle = ccio_map_single(dev, ret, size, PCI_DMA_BIDIRECTIONAL); } - DBG_RUN(__FUNCTION__ " ret %p\n", ret); return ret; } +static void +ccio_free_consistent(struct pci_dev *dev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + ccio_unmap_single(dev, dma_handle, size, 0); + free_pages((unsigned long)vaddr, get_order(size)); +} + +/* +** Since 0 is a valid pdir_base index value, can't use that +** to determine if a value is valid or not. Use a flag to indicate +** the SG list entry contains a valid pdir index. +*/ +#define PIDE_FLAG 0x80000000UL -static void ccio_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +static CCIO_INLINE int +ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, unsigned long hint) { - unsigned long flags; - struct ccio_device *ioa = ccio_list; + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + int n_mappings = 0; + u64 *pdirp = 0; + unsigned long dma_offset = 0; + + dma_sg--; + while (nents-- > 0) { + int cnt = sg_dma_len(startsg); + sg_dma_len(startsg) = 0; + + DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), cnt, + startsg->address, startsg->length + ); - spin_lock_irqsave(&ioa->ccio_lock, flags); - ccio_free_size += get_order(size); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); + /* + ** Look for the start of a new DMA stream + */ + if(sg_dma_address(startsg) & PIDE_FLAG) { + u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + sg_dma_address(startsg) = 0; + dma_sg++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + n_mappings++; + } - ccio_unmap_single(hwdev, dma_handle, size, 0); - free_pages((unsigned long) vaddr, get_order(size)); + /* + ** Look for a VCONTIG chunk + */ + if (cnt) { + unsigned long vaddr = (unsigned long)startsg->address; + ASSERT(pdirp); + + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ + sg_dma_len(dma_sg) += cnt; + cnt += dma_offset; + dma_offset=0; /* only want offset on first chunk */ + cnt = ROUNDUP(cnt, IOVP_SIZE); +#ifdef CONFIG_PROC_FS + ioc->msg_pages += cnt >> IOVP_SHIFT; +#endif + do { + ccio_io_pdir_entry(pdirp, KERNEL_SPACE, (void *)vaddr, hint); + vaddr += IOVP_SIZE; + cnt -= IOVP_SIZE; + pdirp++; + } while (cnt > 0); + } + startsg++; + } + return(n_mappings); } -static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +/* +** Two address ranges are DMA contiguous *iff* "end of prev" and +** "start of next" are both on a page boundry. +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + + +/* +** First pass is to walk the SG list and determine where the breaks are +** in the DMA stream. Allocates PDIR entries but does not fill them. +** Returns the number of DMA chunks. +** +** Doing the fill seperate from the coalescing/allocation keeps the +** code simpler. Future enhancement could make one pass through +** the sglist do both. +*/ + +static CCIO_INLINE int +ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents) { - int tmp = nents; + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + int n_mappings = 0; + + while (nents > 0) { - DBG_RUN(KERN_WARNING __FUNCTION__ " START\n"); + /* + ** Prepare for first/next DMA stream + */ + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = startsg->length; + vcontig_end += (unsigned long) startsg->address; + dma_offset = (unsigned long) startsg->address & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; - /* KISS: map each buffer seperately. */ - while (nents) { - sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); - sg_dma_len(sglist) = sglist->length; - nents--; - sglist++; + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while(--nents > 0) { + unsigned long startsg_end; + + startsg++; + startsg_end = (unsigned long)startsg->address + startsg->length; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** First look for virtually contiguous blocks. + ** PARISC needs this since it's cache is virtually + ** indexed and we need the associated virtual + ** address for each I/O address we map. + ** + ** 1) Can we prepend the next transaction? + ** Only if they are on the same page. + ** And we don't mind DMA order wrong. NOT. + ** Feasible but requires substantial work. + */ + + /* + ** 2) or append the next transaction? + */ + if(vcontig_end == (unsigned long) startsg->address) { + vcontig_len += startsg->length; + vcontig_end += startsg->length; + dma_len += startsg->length; + continue; + } + + /* + ** Not virtually contigous. + ** Terminate prev chunk. + ** Start a new chunk. + ** + ** Once we start a new VCONTIG chunk, dma_offset + ** can't change. And we need the offset from the first + ** chunk - not the last one. Ergo Successive chunks + ** must start on page boundaries and dove tail + ** with it's predecessor. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + + vcontig_sg = startsg; + vcontig_len = startsg->length; + + /* + ** 3) do the entries end/start on page boundaries? + ** Don't update vcontig_end until we've checked. + */ + if (DMA_CONTIG(vcontig_end, startsg->address)) { + vcontig_end = vcontig_len + (unsigned long)startsg->address; + dma_len += vcontig_len; + continue; + } else { + break; + } + } + + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; + sg_dma_address(dma_sg) = + PIDE_FLAG + | (ccio_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset; + n_mappings++; } - DBG_RUN(KERN_WARNING __FUNCTION__ " DONE\n"); - return tmp; + return n_mappings; } -static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +/* +** And this algorithm still generally only ends up coalescing entries +** that happens to be on the same page due to how sglists are assembled. +*/ +static int +ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) { - DBG_RUN(KERN_WARNING __FUNCTION__ " : unmapping %d entries\n", nents); - while (nents) { - ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); - nents--; - sglist++; + struct ioc *ioc = &ccio_list->ioc[0]; + int coalesced, filled = 0; + unsigned long flags; + unsigned long hint = hint_lookup[direction]; + + DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + + /* Fast path single entry scatterlists. */ + if(nents == 1) { + sg_dma_address(sglist)= ccio_map_single(dev, sglist->address, + sglist->length, direction); + sg_dma_len(sglist)= sglist->length; + return 1; + } + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef ASSERT_PDIR_SANITY + if(ccio_check_pdir(ioc, "Check before ccio_map_sg()")) { + ccio_dump_sg(ioc, sglist, nents); + panic("Check before ccio_map_sg()"); + } +#endif + +#ifdef CONFIG_PROC_FS + ioc->msg_calls++; +#endif + + /* + ** First coalesce the chunks and allocate I/O pdir space + ** + ** If this is one DMA stream, we can properly map using the + ** correct virtual address associated with each DMA page. + ** w/o this association, we wouldn't have coherent DMA! + ** Access to the virtual address is what forces a two pass algorithm. + */ + coalesced = ccio_coalesce_chunks(ioc, sglist, nents); + + /* + ** Program the I/O Pdir + ** + ** map the virtual addresses to the I/O Pdir + ** o dma_address will contain the pdir index + ** o dma_len will contain the number of bytes to map + ** o address contains the virtual address. + */ + filled = ccio_fill_pdir(ioc, sglist, nents, hint); + +#ifdef ASSERT_PDIR_SANITY + if(ccio_check_pdir(ioc, "Check after ccio_map_sg()")) { + ccio_dump_sg(ioc, sglist, nents); + panic("Check after ccio_map_sg()\n"); } - return; +#endif + + spin_unlock_irqrestore(&ioc->res_lock, flags); + + ASSERT(coalesced == filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + + return filled; } +static void +ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + struct ioc *ioc = &ccio_list->ioc[0]; /* FIXME : see Multi-IOC below */ +#ifdef ASSERT_PDIR_SANITY + unsigned long flags; +#endif + + DBG_RUN_SG("%s() START %d entries, %p,%x\n", + __FUNCTION__, nents, sglist->address, sglist->length); + +#ifdef CONFIG_PROC_FS + ioc->usg_calls++; +#endif + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + ccio_check_pdir(ioc,"Check before ccio_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + + while(sg_dma_len(sglist) && nents--) { + +#ifdef CONFIG_PROC_FS + ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; +#endif + ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); + ++sglist; + } + + DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + ccio_check_pdir(ioc,"Check after ccio_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif +} static struct pci_dma_ops ccio_ops = { ccio_dma_supported, @@ -861,6 +1144,181 @@ NULL, /* dma_sync_sg : ditto */ }; +#ifdef CONFIG_PROC_FS +static int +ccio_proc_info(char *buf, char **start, off_t offset, int len) +{ + int i, j; + struct ccio_device *ioa = ccio_list; + unsigned long avg = 0, min, max; + + buf[0] = '\0'; + do { + for(i = 0; i < MAX_IOC; ++i) { + + struct ioc *ioc = &ioa->ioc[i]; + unsigned int total_pages = ioc->res_size << 3; + + sprintf(buf, "%s%s rev %d.%d\n", buf, + parisc_getHWdescription(ioc->iodc->hw_type, ioc->iodc->hversion, + ioc->iodc->sversion), + (ioc->ioa->hw_rev & 0x7) + 1, (ioc->ioa->hw_rev & 0x18) >> 3); + + sprintf(buf, "%sCujo 2.0 bug : %s\n", + buf, (ioc->cujo20_bug ? "yes" : "no")); + + sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", + buf, ((ioc->res_size << 3) * sizeof(u64)), total_pages); + + sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", + buf, ((ioc->res_size << 3) * sizeof(u64)), total_pages); + + sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, + total_pages - ioc->used_pages, ioc->used_pages, + (int)(ioc->used_pages * 100 / total_pages)); + + sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", + buf, ioc->res_size, ioc->res_size << 3); + + min = max = ioc->avg_search[0]; + for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) { + avg += ioc->avg_search[j]; + if(ioc->avg_search[j] > max) + max = ioc->avg_search[j]; + if(ioc->avg_search[j] < min) + min = ioc->avg_search[j]; + } + avg /= CCIO_SEARCH_SAMPLE; + sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", + buf, min, avg, max); + + sprintf(buf, "%spci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", + buf, ioc->msingle_calls, ioc->msingle_pages, + (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); + + /* KLUGE - unmap_sg calls unmap_single for each mapped page */ + min = ioc->usingle_calls - ioc->usg_calls; + max = ioc->usingle_pages - ioc->usg_pages; + sprintf(buf, "%spci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", + buf, min, max, (int)((max * 1000)/min)); + + sprintf(buf, "%spci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + buf, ioc->msg_calls, ioc->msg_pages, + (int)((ioc->msg_pages * 1000)/ioc->msg_calls)); + + sprintf(buf, "%spci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n", + buf, ioc->usg_calls, ioc->usg_pages, + (int)((ioc->usg_pages * 1000)/ioc->usg_calls)); + } + ioa = ioa->next; + + } while(NULL != ioa); + + return strlen(buf); +} + +static int +ccio_resource_map(char *buf, char **start, off_t offset, int len) +{ + int i, j; + struct ccio_device *ioa = ccio_list; + + buf[0] = '\0'; + do { + for(i = 0; i < MAX_IOC; ++i) { + struct ioc *ioc = &ioa->ioc[i]; + u32 *res_ptr = (u32 *)ioc->res_map; + + for(j = 0; j < (ioc->res_size / sizeof(u32)); ++j, ++res_ptr) { + if((j & 7) == 0) + strcat(buf,"\n "); + sprintf(buf, "%s %08x", buf, *res_ptr); + } + strcat(buf, "\n\n"); + } + ioa = ioa->next; + + } while(NULL != ioa); + + return strlen(buf); +} +#endif + + +/* CUJO20 KLUDGE start */ +static struct { + u16 hversion; + u8 spa; + u8 type; + u32 foo[3]; /* 16 bytes total */ +} cujo_iodc __attribute__ ((aligned (64))); + +static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; + +/* +** CUJO 2.0 incorrectly decodes a memory access for specific +** pages (every page at specific iotlb locations dependent +** upon where the cujo is flexed - diff on raven/firehawk. +** resulting in an hpmc and/or silent data corruption. +** Workaround is to prevent use of those I/O TLB entries +** by marking the suspect bitmap range entries as busy. +*/ + +/* CUJO20 KLUDGE start */ +#define CUJO_20_BITMASK 0x0ffff000 /* upper nibble is a don't care */ +#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ +#define CUJO_20_BADPAGE1 0x01003000 /* pages that hpmc on raven U+ */ +#define CUJO_20_BADPAGE2 0x01607000 /* pages that hpmc on firehawk U+ */ +#define CUJO_20_BADHVERS 0x6821 /* low nibble 1 is cujo rev 2.0 */ +#define CUJO_RAVEN_LOC 0xf1000000UL /* cujo location on raven U+ */ +#define CUJO_FIREHAWK_LOC 0xf1604000UL /* cujo location on firehawk U+ */ +/* CUJO20 KLUDGE end */ + +static void +ccio_cujo20_hack(struct ioc *ioc) +{ + u32 iovp = 0, io_io_low; + unsigned int idx; + unsigned long status, mask; + u8 *res_ptr = ioc->res_map; + + /* only test IOC that have the potential to be bad. */ + io_io_low = READ_U32(&ioc->ioc_hpa->io_io_low) << 16; + if(!(CUJO_RAVEN_LOC == io_io_low || CUJO_FIREHAWK_LOC == io_io_low)) + return; + + status = pdc_iodc_read(&cujo_result, (void *)CUJO_RAVEN_LOC, 0, &cujo_iodc, 16); + if(0 == status) { + if(CUJO_20_BADHVERS == cujo_iodc.hversion) + iovp = CUJO_20_BADPAGE1; + } else { + status = pdc_iodc_read(&cujo_result, (void *)CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16); + if(0 == status) { + if(CUJO_20_BADHVERS == cujo_iodc.hversion) + iovp = CUJO_20_BADPAGE2; + } else { + /* not a defective system */ + return; + } + } + + printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n"); +#ifdef CONFIG_PROC_FS + ioc->cujo20_bug = 1; +#endif + /* + ** mark bit entries that match "bad page" + */ + idx = PDIR_INDEX(iovp)>>3; + mask = 0xff; + + while(idx * sizeof(u8) < ioc->res_size) { + res_ptr[idx] |= mask; + idx += (PDIR_INDEX(CUJO_20_STEP)>>3); + } +} +/* CUJO20 KLUDGE end */ + #if 0 /* GRANT - is this needed for U2 or not? */ @@ -878,7 +1336,7 @@ ccio_get_iotlb_size(struct hp_device *d) { if(d->spa_shift == 0) { - panic(__FUNCTION__ ": Can't determine I/O TLB size.\n"); + panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__); } return(1 << d->spa_shift); } @@ -887,22 +1345,14 @@ /* Uturn supports 256 TLB entries */ #define CCIO_CHAINID_SHIFT 8 #define CCIO_CHAINID_MASK 0xff - #endif /* 0 */ - -/* -** Figure out how big the I/O PDIR should be and alloc it. -** Also sets variables which depend on pdir size. -*/ static void -ccio_alloc_pdir(struct ccio_device *ioa) +ccio_ioc_init(struct ioc *ioc) { + int i, iov_order; extern unsigned long mem_max; /* arch.../setup.c */ - - u32 iova_space_size = 0; - void * pdir_base; - int pdir_size, iov_order; + u32 iova_space_size; /* ** Determine IOVA Space size from memory size. @@ -915,15 +1365,16 @@ ** methods still require some "extra" to support PCI ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). */ + /* limit IOVA space size to 1MB-1GB */ - if (mem_max < (ccio_mem_ratio*1024*1024)) { - iova_space_size = 1024*1024; + if(mem_max < (ccio_mem_ratio * 1024 * 1024)) { + iova_space_size = 1024 * 1024; #ifdef __LP64__ - } else if (mem_max > (ccio_mem_ratio*512*1024*1024)) { - iova_space_size = 512*1024*1024; + } else if(mem_max > (ccio_mem_ratio * 512 * 1024 * 1024)) { + iova_space_size = 512 * 1024 * 1024; #endif } else { - iova_space_size = (u32) (mem_max/ccio_mem_ratio); + iova_space_size = (u32)(mem_max / ccio_mem_ratio); } /* @@ -933,207 +1384,92 @@ /* We could use larger page sizes in order to *decrease* the number ** of mappings needed. (ie 8k pages means 1/2 the mappings). - ** + ** ** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either ** since the pages must also be physically contiguous - typically ** this is the case under linux." */ - iov_order = get_order(iova_space_size); + iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT); ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ iova_space_size = 1 << (iov_order + IOVP_SHIFT); - ioa->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); + ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); - ASSERT(pdir_size < 4*1024*1024); /* max pdir size < 4MB */ + ASSERT(ioc->pdir_size < 4 * 1024 * 1024); /* max pdir size < 4MB */ /* Verify it's a power of two */ - ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT)); + ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT)); - DBG_INIT(__FUNCTION__ " hpa 0x%p mem %dMB IOV %dMB (%d bits)\n PDIR size 0x%0x", - ioa->ccio_hpa, (int) (mem_max>>20), iova_space_size>>20, - iov_order + PAGE_SHIFT, pdir_size); - - ioa->pdir_base = - pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size)); - if (NULL == pdir_base) - { - panic(__FILE__ ":" __FUNCTION__ "() could not allocate I/O Page Table\n"); + DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x", + __FUNCTION__, ioc->ioc_hpa, mem_max>>20, iova_space_size>>20, + iov_order + PAGE_SHIFT, ioc->pdir_size); + + ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, get_order(ioc->pdir_size)); + if(NULL == ioc->pdir_base) { + panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__); + } + memset(ioc->pdir_base, 0, ioc->pdir_size); + + ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base); + DBG_INIT(" base %p", ioc->pdir_base); + + /* resource map size dictated by pdir_size */ + ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3; + DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size); + + ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, get_order(ioc->res_size)); + if(NULL == ioc->res_map) { + panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__); } - memset(pdir_base, 0, pdir_size); + memset(ioc->res_map, 0, ioc->res_size); - ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base); + /* Initialize the res_hint to 16 */ + ioc->res_hint = 16; - DBG_INIT(" base %p", pdir_base); + /* Initialize the spinlock */ + spin_lock_init(&ioc->res_lock); /* ** Chainid is the upper most bits of an IOVP used to determine ** which TLB entry an IOVP will use. */ - ioa->chainid_shift = get_order(iova_space_size)+PAGE_SHIFT-CCIO_CHAINID_SHIFT; - - DBG_INIT(" chainid_shift 0x%x\n", ioa->chainid_shift); -} - - -static void -ccio_hw_init(struct ccio_device *ioa) -{ - int i; + ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT; + DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift); /* ** Initialize IOA hardware */ - WRITE_U32(CCIO_CHAINID_MASK << ioa->chainid_shift, &ioa->ccio_hpa->io_chain_id_mask); - WRITE_U32(virt_to_phys(ioa->pdir_base), &ioa->ccio_hpa->io_pdir_base); + WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, + &ioc->ioc_hpa->io_chain_id_mask); + WRITE_U32(virt_to_phys(ioc->pdir_base), + &ioc->ioc_hpa->io_pdir_base); /* ** Go to "Virtual Mode" */ - WRITE_U32(IOA_NORMAL_MODE, &ioa->ccio_hpa->io_control); + WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control); /* ** Initialize all I/O TLB entries to 0 (Valid bit off). */ - WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_m); - WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_l); + WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m); + WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l); - for (i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { - WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioa->chainid_shift)), - &ioa->ccio_hpa->io_command); + for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { + WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)), + &ioc->ioc_hpa->io_command); } -} - - -static void -ccio_resmap_init(struct ccio_device *ioa) -{ - u32 res_size; - /* - ** Ok...we do more than just init resource map + ** See if we need the cujo 2.0 work around. */ - ioa->ccio_lock = SPIN_LOCK_UNLOCKED; - - ioa->res_hint = 16; /* next available IOVP - circular search */ - - /* resource map size dictated by pdir_size */ - res_size = ioa->pdir_size/sizeof(u64); /* entries */ - res_size >>= 3; /* convert bit count to byte count */ - DBG_INIT(__FUNCTION__ "() res_size 0x%x\n", res_size); - - ioa->res_size = res_size; - ioa->res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); - if (NULL == ioa->res_map) - { - panic(__FILE__ ":" __FUNCTION__ "() could not allocate resource map\n"); - } - memset(ioa->res_map, 0, res_size); -} - -/* CUJO20 KLUDGE start */ -static struct { - u16 hversion; - u8 spa; - u8 type; - u32 foo[3]; /* 16 bytes total */ -} cujo_iodc __attribute__ ((aligned (64))); -static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; - -/* -** CUJO 2.0 incorrectly decodes a memory access for specific -** pages (every page at specific iotlb locations dependent -** upon where the cujo is flexed - diff on raven/firehawk. -** resulting in an hpmc and/or silent data corruption. -** Workaround is to prevent use of those I/O TLB entries -** by marking the suspect bitmap range entries as busy. -*/ -static void -ccio_cujo20_hack(struct ccio_device *ioa) -{ - unsigned long status; - unsigned int idx; - u8 *res_ptr = ioa->res_map; - u32 iovp=0x0; - unsigned long mask; - - status = pdc_iodc_read( &cujo_result, (void *) CUJO_RAVEN_LOC, 0, &cujo_iodc, 16); - if (status == 0) { - if (cujo_iodc.hversion==CUJO_20_BADHVERS) - iovp = CUJO_20_BADPAGE1; - } else { - status = pdc_iodc_read( &cujo_result, (void *) CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16); - if (status == 0) { - if (cujo_iodc.hversion==CUJO_20_BADHVERS) - iovp = CUJO_20_BADPAGE2; - } else { - /* not a defective system */ - return; - } - } - - printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n"); - ccio_cujo_bug = 1; - - /* - ** mark bit entries that match "bad page" - */ - idx = PDIR_INDEX(iovp)>>3; - mask = 0xff; - - while(idx * sizeof(u8) < ioa->res_size) { - res_ptr[idx] |= mask; - idx += (PDIR_INDEX(CUJO_20_STEP)>>3); - ccio_used_pages += 8; - ccio_used_bytes += 1; - } -} -/* CUJO20 KLUDGE end */ - -#ifdef CONFIG_PROC_FS -static int ccio_proc_info(char *buf, char **start, off_t offset, int len) -{ - unsigned long i = 0; - struct ccio_device *ioa = ccio_list; - unsigned long *res_ptr = (unsigned long *)ioa->res_map; - unsigned long total_pages = ioa->res_size << 3; /* 8 bits per byte */ - - sprintf(buf, "%s\nCujo 2.0 bug : %s\n", - parisc_getHWdescription(ioa->iodc->hw_type, ioa->iodc->hversion, - ioa->iodc->sversion), - (ccio_cujo_bug ? "yes" : "no")); - - sprintf(buf, "%sIO pdir size : %d bytes (%d entries)\n", - buf, ((ioa->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ - ioa->res_size << 3); /* 8 bits per byte */ - - sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", - buf, ioa->res_size, ioa->res_size << 3); /* 8 bits per byte */ - - strcat(buf, " total: free: used: % used:\n"); - sprintf(buf, "%sblocks %8d %8ld %8ld %8ld%%\n", buf, ioa->res_size, - ioa->res_size - ccio_used_bytes, ccio_used_bytes, - (ccio_used_bytes * 100) / ioa->res_size); - - sprintf(buf, "%spages %8ld %8ld %8ld %8ld%%\n", buf, total_pages, - total_pages - ccio_used_pages, ccio_used_pages, - (ccio_used_pages * 100 / total_pages)); - - sprintf(buf, "%sconsistent %8ld %8ld\n", buf, - ccio_alloc_size, ccio_free_size); - - strcat(buf, "\nResource bitmap:\n"); - - for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) - len += sprintf(buf, "%s%08lx ", buf, *res_ptr); - - strcat(buf, "\n"); - return strlen(buf); + /* CUJO20 KLUDGE start */ + ccio_cujo20_hack(ioc); + /* CUJO20 KLUDGE end */ } -#endif /* ** Determine if ccio should claim this chip (return 0) or not (return 1). @@ -1143,67 +1479,64 @@ static int ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) { - struct ccio_device *ioa; + int i; + struct ccio_device *ioa = ccio_list; printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); - if (ccio_list) { - printk(MODULE_NAME ": already initialized one device\n"); - return(0); + if(NULL == ccio_list) { + create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info); + create_proc_info_entry(MODULE_NAME"-bitmap", 0, proc_runway_root, + ccio_resource_map); + + ccio_list = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); + if(NULL == ccio_list) { + printk(MODULE_NAME " - couldn't alloc ccio_device\n"); + return 1; + } + memset(ccio_list, 0, sizeof(struct ccio_device)); + ioa = ccio_list; + ++ccio_count; } - ioa = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); - if (NULL == ioa) - { - printk(MODULE_NAME " - couldn't alloc ccio_device\n"); - return(1); + for(i = 0; i < (ccio_count - 1); ++i) { + ioa = ioa->next; } - memset(ioa, 0, sizeof(struct ccio_device)); - - /* - ** ccio list is used mainly as a kluge to support a single instance. - ** Eventually, with core dumps, it'll be useful for debugging. - */ - ccio_list = ioa; - ioa->iodc = d; -#if 1 -/* KLUGE: determine IOA hpa based on GSC port value. -** Needed until we have a PA bus walk. Can only discover IOA via -** walking the architected PA MMIO space as described by the I/O ACD. -** "Legacy" PA Firmware only tells us about unarchitected devices -** that can't be detected by PA/EISA/PCI bus walks. -*/ - switch((long) d->hpa) { - case 0xf3fbf000L: /* C110 IOA0 LBC (aka GSC port) */ - /* ccio_hpa same as C200 IOA0 */ - case 0xf203f000L: /* C180/C200/240/C360 IOA0 LBC (aka GSC port) */ - ioa->ccio_hpa = (struct ioa_registers *) 0xfff88000L; - break; - case 0xf103f000L: /* C180/C200/240/C360 IOA1 LBC (aka GSC port) */ - ioa->ccio_hpa = (struct ioa_registers *) 0xfff8A000L; - break; - default: - panic("ccio-dma.c doesn't know this GSC port Address!\n"); - break; - }; -#else - ioa->ccio_hpa = d->hpa; -#endif + for(i = 0; i < MAX_IOC; ++i) { + if(NULL == ioa->ioc[i].ioc_hpa) + break; + } - ccio_alloc_pdir(ioa); - ccio_hw_init(ioa); - ccio_resmap_init(ioa); + if(MAX_IOC == i) { + ioa->next = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); + ioa = ioa->next; + if(NULL == ioa) { + printk(MODULE_NAME " - couldn't alloc ccio_device\n"); + return 1; + } + memset(ioa, 0, sizeof(struct ccio_device)); + ++ccio_count; + i = 0; + } - /* CUJO20 KLUDGE start */ - ccio_cujo20_hack(ioa); - /* CUJO20 KLUDGE end */ + ioa->ioc[i].iodc = d; + ioa->ioc[i].ioc_hpa = d->hpa; + ioa->ioc[i].ioa = ioa; + ccio_ioc_init(&ioa->ioc[i]); hppa_dma_ops = &ccio_ops; - create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info); - return(0); + printk("io_io_high: 0x%08x io_io_low: 0x%08x\n", + READ_U32(&ioa->ioc[i].ioc_hpa->io_io_high) << 16, + READ_U32(&ioa->ioc[i].ioc_hpa->io_io_low) << 16); + return 0; } - - +void __init +ccio_init(void) +{ + ccio_list = (struct ccio_device *)NULL; + ccio_count = 0; + register_driver(ccio_drivers_for); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/drivers.c linux.ac/arch/parisc/kernel/drivers.c --- linux.vanilla/arch/parisc/kernel/drivers.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/drivers.c Tue Apr 3 17:54:33 2001 @@ -1,12 +1,9 @@ -/* +/* drivers.c -drivers.c - -Copyright (c) 1999 The Puffin Group - -This is a collection of routines intended to register all the devices -in a system, and register device drivers. + Copyright (c) 1999 The Puffin Group + This is a collection of routines intended to register all the devices + in a system, and register device drivers. */ #include @@ -17,57 +14,58 @@ #include -extern struct hp_hardware *parisc_get_reference( - unsigned short hw_type, unsigned long hversion, - unsigned long sversion ); - - -/* I'm assuming there'll never be 64 devices. We should probably make +/* I'm assuming there'll never be 64 devices. We should probably make this more flexible. */ #define MAX_DEVICES 64 -unsigned int num_devices = 0; +static int num_devices; +static struct hp_device pa_devices[MAX_DEVICES]; -struct hp_device devices[MAX_DEVICES]; +static struct pa_iodc_driver *pa_drivers = NULL; static unsigned long pdc_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; static u8 iodc_data[32] __attribute__ ((aligned (64))); -/* - * XXX should we be using a locked array ? - */ - + +static int compare_spec( struct hp_device * hp_dev, + struct pa_iodc_driver *driver) +{ + if ((driver->check & DRIVER_CHECK_HWTYPE) + && (driver->hw_type != hp_dev->hw_type)) return 0; + if ((driver->check & DRIVER_CHECK_HVERSION) + && (driver->hversion != hp_dev->hversion)) return 0; + if ((driver->check & DRIVER_CHECK_HVERSION_REV) + && (driver->hversion_rev != hp_dev->hversion_rev)) return 0; + if ((driver->check & DRIVER_CHECK_SVERSION) + && (driver->sversion != hp_dev->sversion)) return 0; + if ((driver->check & DRIVER_CHECK_SVERSION_REV) + && (driver->sversion_rev != hp_dev->sversion_rev)) return 0; + if ((driver->check & DRIVER_CHECK_OPT) + && (driver->opt != hp_dev->opt)) return 0; + + return 1; +} + int register_driver(struct pa_iodc_driver *driver) { - unsigned int i; + int i; struct hp_device * device; - for (;driver->check;driver++) { + for(;driver->check;driver++) { + /* link driver to the head of the global list. + ** The list gets built in reverse order...ideally, it shouldn't + ** matter but reality will eventually rear it's ugly head. + */ + driver->next = pa_drivers; + pa_drivers = driver; - for (i=0;imanaged) continue; + if (device->managed) continue; + if (0 == compare_spec(device, driver)) continue; - if ((driver->check & DRIVER_CHECK_HWTYPE) && - (driver->hw_type != device->hw_type)) - continue; - if ((driver->check & DRIVER_CHECK_HVERSION) && - (driver->hversion != device->hversion)) - continue; - if ((driver->check & DRIVER_CHECK_HVERSION_REV) && - (driver->hversion_rev != device->hversion_rev)) - continue; - if ((driver->check & DRIVER_CHECK_SVERSION) && - (driver->sversion != device->sversion)) - continue; - if ((driver->check & DRIVER_CHECK_SVERSION_REV) && - (driver->sversion_rev != device->sversion_rev)) - continue; - if ((driver->check & DRIVER_CHECK_OPT) && - (driver->opt != device->opt)) - continue; if ( (*driver->callback)(device,driver) ==0) { device->managed=1; } else { @@ -83,52 +81,113 @@ } -struct hp_device * register_module(void *hpa) +/* this function adds an address to the list of additional addresses of a module */ +int add_pa_dev_addr(struct hp_device *hp_device, unsigned long addr) { + if (!hp_device || !addr) + return 0; + if (hp_device->num_addrs >= MAX_ADD_ADDRS) { + printk(KERN_ERR "%s: Too many additional addresses. " + "Increase the value of MAX_ADD_ADDRS in harware.h !\n", + __FUNCTION__ ); + return 0; + } + + hp_device->addr[hp_device->num_addrs] = addr; + hp_device->num_addrs++; + + return hp_device->num_addrs; +} + + +struct hp_device *alloc_pa_dev(unsigned long hpa) +{ + int i, status; struct hp_device * d; - int status; - d = &devices[num_devices]; - status = pdc_iodc_read(&pdc_result,hpa,0,&iodc_data,32 ); - if (status !=PDC_RET_OK) { + d = &pa_devices[num_devices]; + status = pdc_iodc_read(&pdc_result, (void *)hpa, 0, &iodc_data, 32); + if (status != PDC_RET_OK) { /* There is no device here, so we'll skip it */ - return 0; + return NULL; + } + + /* Check to make sure this device has not already been added -Ryan */ + for(i = 0; i < num_devices; ++i) { + if((unsigned long)pa_devices[i].hpa == hpa) + return NULL; } d->hw_type = iodc_data[3]&0x1f; d->hversion = (iodc_data[0]<<4)|((iodc_data[1]&0xf0)>>4); - d->sversion = + d->sversion = ((iodc_data[4]&0x0f)<<16)|(iodc_data[5]<<8)|(iodc_data[6]); d->hversion_rev = iodc_data[1]&0x0f; d->sversion_rev = iodc_data[4]>>4; d->opt = iodc_data[7]; - d->hpa = hpa; - d->managed=0; - d->reference = parisc_get_reference(d->hw_type, d->hversion, - d->sversion); - - num_devices++; + d->hpa = (void *) hpa; + d->managed = 0; + d->reference = parisc_get_reference(d->hw_type, + d->hversion, d->sversion); + + /* add the hpa of this module as the first additional address */ + add_pa_dev_addr(d, hpa); + + num_devices++; return d; -} +} -void print_devices(char * buf) { - int i; +/* Return status if device is managed */ +int register_pa_dev(struct hp_device *hp_dev) +{ + struct pa_iodc_driver *driver = pa_drivers; + + while ((0 == hp_dev->managed) && (NULL != driver)) { + + if (compare_spec(hp_dev,driver)) + hp_dev->managed = + ((*driver->callback)(hp_dev,driver) == 0); + + driver = driver->next; + } + + return hp_dev->managed; +} + +struct hp_device *get_pa_dev(unsigned int index) +{ + if (index >= num_devices) + return NULL; + + return &pa_devices[index]; +} + + +void print_pa_devices(char * buf) +{ + int i, k; struct hp_device *d; + printk("Found devices:\n"); - for (i=0;ireference) ? d->reference->name : "Unknown device", - d->hw_type,d->hpa, d->hversion, d->hversion_rev, + d->hw_type, d->hpa, d->hversion, d->hversion_rev, d->sversion, d->sversion_rev, d->opt); + if (d->num_addrs>1) { + printk(", additional addresses: "); + for (k=1; knum_addrs; k++) + printk("0x%lx ", d->addr[k]); + } + + printk("\n"); } - printk("That's a total of %d devices.\n",num_devices); + printk("That's a total of %d devices.\n", num_devices); } - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/entry.S linux.ac/arch/parisc/kernel/entry.S --- linux.vanilla/arch/parisc/kernel/entry.S Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/entry.S Mon Apr 16 12:37:04 2001 @@ -38,9 +38,10 @@ #ifdef __LP64__ .level 2.0w +#else + .level 2.0 #endif -#define __ASSEMBLY__ #include /* for LDREG/STREG defines */ #include #include @@ -69,14 +70,15 @@ mtctl %r1, %cr22 mtctl %r0, %cr17 mtctl %r0, %cr17 - ldil L%.+28, %r1 - ldo R%.+24(%r1), %r1 + ldil L%4f, %r1 + ldo R%4f(%r1), %r1 LDIL_FIXUP(%r1) mtctl %r1, %cr18 ldo 4(%r1), %r1 mtctl %r1, %cr18 \rfi_type nop +4: .endm .macro get_stack @@ -179,8 +181,8 @@ /* Register definitions for tlb miss handler macros */ - va = r8 /* virtual address for which the trap occured */ - spc = r24 /* space for which the trap occured */ + va = r8 /* virtual address for which the trap occurred */ + spc = r24 /* space for which the trap occurred */ #ifndef __LP64__ @@ -298,37 +300,27 @@ .endm #ifndef __LP64__ - /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) - * - * Note: nadtlb misses will be treated - * as an ordinary dtlb miss for now. - * - */ + /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro nadtlb_11 code mfctl %isr,spc - b dtlb_miss_11 + b nadtlb_miss_11 mfctl %ior,va .align 32 .endm #endif - /* nadtlb miss interruption handler (parisc 2.0) - * - * Note: nadtlb misses will be treated - * as an ordinary dtlb miss for now. - * - */ + /* nadtlb miss interruption handler (parisc 2.0) */ .macro nadtlb_20 code mfctl %isr,spc #ifdef __LP64__ - b dtlb_miss_20w + b nadtlb_miss_20w #else - b dtlb_miss_20 + b nadtlb_miss_20 #endif mfctl %ior,va @@ -402,7 +394,11 @@ def 13 def 14 dtlb_20 15 +#if 0 naitlb_20 16 +#else + def 16 +#endif nadtlb_20 17 def 18 def 19 @@ -446,7 +442,11 @@ def 13 def 14 dtlb_11 15 +#if 0 naitlb_11 16 +#else + def 16 +#endif nadtlb_11 17 def 18 def 19 @@ -811,11 +811,11 @@ */ t0 = r1 /* temporary register 0 */ - va = r8 /* virtual address for which the trap occured */ + va = r8 /* virtual address for which the trap occurred */ t1 = r9 /* temporary register 1 */ pte = r16 /* pte/phys page # */ prot = r17 /* prot bits */ - spc = r24 /* space for which the trap occured */ + spc = r24 /* space for which the trap occurred */ ptp = r25 /* page directory/page table pointer */ #ifdef __LP64__ @@ -838,14 +838,101 @@ ldd,s t1(ptp),ptp extrd,u va,42,9,t0 /* get second-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w + depdi 0,63,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + ldd,s t0(ptp),ptp + extrd,u va,51,9,t0 /* get third-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w + depdi 0,63,12,ptp /* clear prot bits */ + + /* Third level page table lookup */ + + shladd t0,3,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldd 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,*<> t1,pte,%r0 /* test and nullify if already set */ + std t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,32,pte + idtlbt pte,prot + + rfir + nop + +dtlb_check_alias_20w: + + /* Check to see if fault is in the temporary alias region */ + + cmpib,<>,n 0,spc,dtlb_fault /* forward */ + ldil L%(TMPALIAS_MAP_START),t0 + LDIL_FIXUP(t0) + copy va,t1 + depdi 0,63,23,t1 + cmpb,*<>,n t0,t1,dtlb_fault /* forward */ + ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot + depd,z prot,8,7,prot + + /* + * OK, it is in the temp alias region, check whether "from" or "to". + * Check "subtle" note in pacache.S re: r23/r26. + */ + + extrd,u,*= va,41,1,r0 + or,*tr %r23,%r0,pte /* If "from" use "from" page */ + or,* %r26,%r0,pte /* else "to", use "to" page */ + + idtlbt pte,prot + + rfir + nop + +nadtlb_miss_20w: + + extrd,u spc,31,7,t1 /* adjust va */ + depd t1,31,7,va /* adjust va */ + depdi 0,31,7,spc /* adjust space */ + mfctl %cr25,ptp /* Assume user space miss */ + or,*<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extrd,u va,33,9,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,*= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,nadtlb_fault /* forward */ + + /* First level page table lookup */ + + ldd,s t1(ptp),ptp + extrd,u va,42,9,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate depdi 0,63,12,ptp /* clear prot bits */ /* Second level page table lookup */ ldd,s t0(ptp),ptp extrd,u va,51,9,t0 /* get third-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate depdi 0,63,12,ptp /* clear prot bits */ /* Third level page table lookup */ @@ -853,7 +940,7 @@ shladd t0,3,ptp,ptp ldi _PAGE_ACCESSED,t1 ldd 0(ptp),pte - bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_emulate /* Check whether the "accessed" bit was set, otherwise do so */ @@ -875,10 +962,11 @@ depdi 0,63,12,pte extrd,u pte,56,32,pte - idtlbt %r16,%r17 + idtlbt pte,prot rfir nop + #else dtlb_miss_11: @@ -895,7 +983,7 @@ ldwx,s t1(ptp),ptp extru va,19,10,t0 /* get second-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11 depi 0,31,12,ptp /* clear prot bits */ /* Second level page table lookup */ @@ -903,7 +991,7 @@ sh2addl t0,ptp,ptp ldi _PAGE_ACCESSED,t1 ldw 0(ptp),pte - bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11 /* Check whether the "accessed" bit was set, otherwise do so */ @@ -937,9 +1025,90 @@ rfir nop -dtlb_miss_20: - .level 2.0 +dtlb_check_alias_11: + /* Check to see if fault is in the temporary alias region */ + + cmpib,<>,n 0,spc,dtlb_fault /* forward */ + ldil L%(TMPALIAS_MAP_START),t0 + copy va,t1 + depwi 0,31,23,t1 + cmpb,<>,n t0,t1,dtlb_fault /* forward */ + ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot + depw,z prot,8,7,prot + + /* + * OK, it is in the temp alias region, check whether "from" or "to". + * Check "subtle" note in pacache.S re: r23/r26. + */ + + extrw,u,= va,9,1,r0 + or,tr %r23,%r0,pte /* If "from" use "from" page */ + or %r26,%r0,pte /* else "to", use "to" page */ + + idtlba pte,(va) + idtlbp prot,(va) + + rfir + nop + +nadtlb_miss_11: + mfctl %cr25,ptp /* Assume user space miss */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,nadtlb_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_emulate + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + dep pte,8,7,prot + + extru,= pte,_PAGE_NO_CACHE_BIT,1,r0 + depi 1,12,1,prot + extru,= pte,_PAGE_USER_BIT,1,r0 + depi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extru,= pte,_PAGE_GATEWAY_BIT,1,r0 + depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlba */ + + depi 0,31,12,pte + extru pte,24,25,pte + + mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ + mtsp spc,%sr1 + + idtlba pte,(%sr1,va) + idtlbp prot,(%sr1,va) + + mtsp t0, %sr1 /* Restore sr1 */ + + rfir + nop + +dtlb_miss_20: mfctl %cr25,ptp /* Assume user space miss */ or,<> %r0,spc,%r0 /* If it is user space, nullify */ mfctl %cr24,ptp /* Load kernel pgd instead */ @@ -953,7 +1122,7 @@ ldwx,s t1(ptp),ptp extru va,19,10,t0 /* get second-level index */ - bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20 depi 0,31,12,ptp /* clear prot bits */ /* Second level page table lookup */ @@ -961,7 +1130,7 @@ sh2addl t0,ptp,ptp ldi _PAGE_ACCESSED,t1 ldw 0(ptp),pte - bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20 /* Check whether the "accessed" bit was set, otherwise do so */ @@ -983,14 +1152,128 @@ depdi 0,63,12,pte extrd,u pte,56,25,pte - idtlbt %r16,%r17 + idtlbt pte,prot + + rfir + nop + +dtlb_check_alias_20: - .level 1.1 + /* Check to see if fault is in the temporary alias region */ + + cmpib,<>,n 0,spc,dtlb_fault /* forward */ + ldil L%(TMPALIAS_MAP_START),t0 + copy va,t1 + depwi 0,31,23,t1 + cmpb,<>,n t0,t1,dtlb_fault /* forward */ + ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot + depd,z prot,8,7,prot + + /* + * OK, it is in the temp alias region, check whether "from" or "to". + * Check "subtle" note in pacache.S re: r23/r26. + */ + + extrw,u,= va,9,1,r0 + or,tr %r23,%r0,pte /* If "from" use "from" page */ + or %r26,%r0,pte /* else "to", use "to" page */ + + idtlbt pte,prot + + rfir + nop + +nadtlb_miss_20: + mfctl %cr25,ptp /* Assume user space miss */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,nadtlb_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_emulate + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,25,pte + idtlbt pte,prot rfir nop #endif +nadtlb_emulate: + + /* + * Non access misses can be caused by fdc,fic,pdc,lpa,probe and + * probei instructions. We don't want to fault for these + * instructions (not only does it not make sense, it can cause + * deadlocks, since some flushes are done with the mmap + * semaphore held). If the translation doesn't exist, we can't + * insert a translation, so have to emulate the side effects + * of the instruction. Since we don't insert a translation + * we can get a lot of faults during a flush loop, so it makes + * sense to try to do it here with minimum overhead. We only + * emulate fdc,fic & pdc instructions whose base and index + * registers are not shadowed. We defer everything else to the + * "slow" path. + */ + + mfctl %cr19,%r9 /* Get iir */ + ldi 0x280,%r16 + and %r9,%r16,%r17 + cmpb,<>,n %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */ + bb,>=,n %r9,26,nadtlb_nullify /* m bit not set, just nullify */ + b,l get_register,%r25 + extrw,u %r9,15,5,%r8 /* Get index register # */ + cmpib,=,n -1,%r1,nadtlb_fault /* have to use slow path */ + copy %r1,%r24 + b,l get_register,%r25 + extrw,u %r9,10,5,%r8 /* Get base register # */ + cmpib,=,n -1,%r1,nadtlb_fault /* have to use slow path */ + b,l set_register,%r25 + add,l %r1,%r24,%r1 /* doesn't affect c/b bits */ + +nadtlb_nullify: + mfctl %cr22,%r8 /* Get ipsw */ + ldil L%PSW_N,%r9 + or %r8,%r9,%r8 /* Set PSW_N */ + mtctl %r8,%cr22 + + rfir + nop + #ifdef __LP64__ itlb_miss_20w: @@ -1053,7 +1336,7 @@ depdi 0,63,12,pte extrd,u pte,56,32,pte - iitlbt %r16,%r17 + iitlbt pte,prot rfir nop @@ -1169,8 +1452,6 @@ copy spc,prot /* init prot with faulting space */ - .level 2.0 - depd pte,8,7,prot extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 depdi 1,12,1,prot @@ -1183,8 +1464,7 @@ depdi 0,63,12,pte extrd,u pte,56,25,pte - iitlbt %r16,%r17 - .level 1.1 + iitlbt pte,prot rfir nop @@ -1252,7 +1532,7 @@ depdi 0,63,12,pte extrd,u pte,56,32,pte - idtlbt %r16,%r17 + idtlbt pte,prot rfir nop @@ -1344,8 +1624,6 @@ copy spc,prot /* init prot with faulting space */ - .level 2.0 - depd pte,8,7,prot extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 depdi 1,12,1,prot @@ -1358,9 +1636,7 @@ depdi 0,63,12,pte extrd,u pte,56,25,pte - idtlbt %r16,%r17 - - .level 1.1 + idtlbt pte,prot rfir nop @@ -1380,6 +1656,10 @@ b tlb_fault ldi 6,%r1 +nadtlb_fault: + b tlb_fault + ldi 17,%r1 + dtlb_fault: ldi 15,%r1 @@ -1666,6 +1946,11 @@ STREG %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30) + /* Seems to me that dp could be wrong here, if the syscall involved + * calling a module, and nothing got round to restoring dp on return. + */ + loadgp + syscall_check_bh: /* #ifdef NOTNOW */ @@ -1774,21 +2059,28 @@ syscall_restore_rfi: ldo -1(%r0),%r2 /* Set recovery cntr to -1 */ mtctl %r2,%cr0 /* for immediate trap */ - copy %r0,%r2 /* Create a reasonable PSW */ + LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */ + ldi 0x0b,%r20 /* Create new PSW */ + depi -1,13,1,%r20 /* C, Q, D, and I bits */ + bb,>=,n %r19,15,try_tbit /* PT_SINGLESTEP */ + depi -1,27,1,%r20 /* R bit */ +try_tbit: + bb,>=,n %r19,14,psw_setup /* PT_BLOCKSTEP, see ptrace.c */ + depi -1,7,1,%r20 /* T bit */ +psw_setup: + STREG %r20,TASK_PT_PSW(%r1) /* XXX W bit??? */ - depi -1,13,1,%r2 - depi -1,28,1,%r2 - depi -1,30,1,%r2 - depi -1,31,1,%r2 - bb,<,n %r19,15,set_rbit /* PT_SINGLESTEP */ - bb,>=,n %r19,14,set_nobit /* PT_BLOCKSTEP, see ptrace.c */ -set_tbit: - depi -1,7,1,%r2 - b,n set_nobit -set_rbit: - depi -1,27,1,%r2 -set_nobit: - STREG %r2,TASK_PT_PSW(%r1) + /* Now if old D bit is clear, it means we didn't save all registers + * on syscall entry, so do that now. This only happens on TRACEME + * calls, or if someone attached to us while we were on a syscall. + * We could make this more efficient by not saving r3-r18, but + * then we wouldn't be able to use the common intr_restore path. + * It is only for traced processes anyway, so performance is not + * an issue. + */ + bb,< %r2,30,pt_regs_ok /* Branch if D set */ + ldo TASK_REGS(%r1),%r25 + reg_save %r25 /* Save r3 to r18 */ STREG %r1,TASK_PT_CR30(%r1) mfsp %sr0,%r2 STREG %r2,TASK_PT_SR0(%r1) @@ -1804,13 +2096,12 @@ STREG %r2,TASK_PT_SR7(%r1) STREG %r2,TASK_PT_IASQ0(%r1) STREG %r2,TASK_PT_IASQ1(%r1) +pt_regs_ok: LDREG TASK_PT_GR31(%r1),%r2 depi 3,31,2,%r2 /* ensure return to user mode. */ STREG %r2,TASK_PT_IAOQ0(%r1) ldo 4(%r2),%r2 STREG %r2,TASK_PT_IAOQ1(%r1) - ldo TASK_REGS(%r1),%r25 - reg_save %r25 /* Save r3 to r18 */ copy %r25,%r16 b intr_restore nop @@ -1849,6 +2140,160 @@ b,n syscall_restore + /* + * get_register is used by the non access tlb miss handlers to + * copy the value of the general register specified in r8 into + * r1. This routine can't be used for shadowed registers, since + * the rfir will restore the original value. So, for the shadowed + * registers we put a -1 into r1 to indicate that the register + * should not be used (the register being copied could also have + * a -1 in it, but that is OK, it just means that we will have + * to use the slow path instead). + */ + +get_register: + blr %r8,%r0 + nop + bv %r0(%r25) /* r0 */ + copy %r0,%r1 + bv %r0(%r25) /* r1 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r2 */ + copy %r2,%r1 + bv %r0(%r25) /* r3 */ + copy %r3,%r1 + bv %r0(%r25) /* r4 */ + copy %r4,%r1 + bv %r0(%r25) /* r5 */ + copy %r5,%r1 + bv %r0(%r25) /* r6 */ + copy %r6,%r1 + bv %r0(%r25) /* r7 */ + copy %r7,%r1 + bv %r0(%r25) /* r8 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r9 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r10 */ + copy %r10,%r1 + bv %r0(%r25) /* r11 */ + copy %r11,%r1 + bv %r0(%r25) /* r12 */ + copy %r12,%r1 + bv %r0(%r25) /* r13 */ + copy %r13,%r1 + bv %r0(%r25) /* r14 */ + copy %r14,%r1 + bv %r0(%r25) /* r15 */ + copy %r15,%r1 + bv %r0(%r25) /* r16 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r17 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r18 */ + copy %r18,%r1 + bv %r0(%r25) /* r19 */ + copy %r19,%r1 + bv %r0(%r25) /* r20 */ + copy %r20,%r1 + bv %r0(%r25) /* r21 */ + copy %r21,%r1 + bv %r0(%r25) /* r22 */ + copy %r22,%r1 + bv %r0(%r25) /* r23 */ + copy %r23,%r1 + bv %r0(%r25) /* r24 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r25 - shadowed */ + ldi -1,%r1 + bv %r0(%r25) /* r26 */ + copy %r26,%r1 + bv %r0(%r25) /* r27 */ + copy %r27,%r1 + bv %r0(%r25) /* r28 */ + copy %r28,%r1 + bv %r0(%r25) /* r29 */ + copy %r29,%r1 + bv %r0(%r25) /* r30 */ + copy %r30,%r1 + bv %r0(%r25) /* r31 */ + copy %r31,%r1 + + /* + * set_register is used by the non access tlb miss handlers to + * copy the value of r1 into the general register specified in + * r8. + */ + +set_register: + blr %r8,%r0 + nop + bv %r0(%r25) /* r0 (silly, but it is a place holder) */ + copy %r1,%r0 + bv %r0(%r25) /* r1 */ + copy %r1,%r1 + bv %r0(%r25) /* r2 */ + copy %r1,%r2 + bv %r0(%r25) /* r3 */ + copy %r1,%r3 + bv %r0(%r25) /* r4 */ + copy %r1,%r4 + bv %r0(%r25) /* r5 */ + copy %r1,%r5 + bv %r0(%r25) /* r6 */ + copy %r1,%r6 + bv %r0(%r25) /* r7 */ + copy %r1,%r7 + bv %r0(%r25) /* r8 */ + copy %r1,%r8 + bv %r0(%r25) /* r9 */ + copy %r1,%r9 + bv %r0(%r25) /* r10 */ + copy %r1,%r10 + bv %r0(%r25) /* r11 */ + copy %r1,%r11 + bv %r0(%r25) /* r12 */ + copy %r1,%r12 + bv %r0(%r25) /* r13 */ + copy %r1,%r13 + bv %r0(%r25) /* r14 */ + copy %r1,%r14 + bv %r0(%r25) /* r15 */ + copy %r1,%r15 + bv %r0(%r25) /* r16 */ + copy %r1,%r16 + bv %r0(%r25) /* r17 */ + copy %r1,%r17 + bv %r0(%r25) /* r18 */ + copy %r1,%r18 + bv %r0(%r25) /* r19 */ + copy %r1,%r19 + bv %r0(%r25) /* r20 */ + copy %r1,%r20 + bv %r0(%r25) /* r21 */ + copy %r1,%r21 + bv %r0(%r25) /* r22 */ + copy %r1,%r22 + bv %r0(%r25) /* r23 */ + copy %r1,%r23 + bv %r0(%r25) /* r24 */ + copy %r1,%r24 + bv %r0(%r25) /* r25 */ + copy %r1,%r25 + bv %r0(%r25) /* r26 */ + copy %r1,%r26 + bv %r0(%r25) /* r27 */ + copy %r1,%r27 + bv %r0(%r25) /* r28 */ + copy %r1,%r28 + bv %r0(%r25) /* r29 */ + copy %r1,%r29 + bv %r0(%r25) /* r30 */ + copy %r1,%r30 + bv %r0(%r25) /* r31 */ + copy %r1,%r31 + + #ifdef __LP64__ unimplemented_64bitirq: ssm PSW_SM_Q+PSW_SM_I, %r0 @@ -1865,3 +2310,4 @@ b,n . nop #endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/hardware.c linux.ac/arch/parisc/kernel/hardware.c --- linux.vanilla/arch/parisc/kernel/hardware.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/hardware.c Tue Apr 3 17:54:33 2001 @@ -218,6 +218,23 @@ {HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"}, {HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"}, {HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"}, + {HPHW_NPROC,0x5CC,0x4,0x91,"Prelude W 440"}, + {HPHW_NPROC,0x5CD,0x4,0x91,"SPP2600"}, + {HPHW_NPROC,0x5CE,0x4,0x91,"M2600"}, + {HPHW_NPROC,0x5CF,0x4,0x81,"Alegro W+"}, + {HPHW_NPROC,0x5D0,0x4,0x81,"Kazoo W+"}, + {HPHW_NPROC,0x5D1,0x4,0x91,"Forte W+ 2w"}, + {HPHW_NPROC,0x5D2,0x4,0x91,"Forte W+ 4w"}, + {HPHW_NPROC,0x5D3,0x4,0x91,"Prelude W+ 540"}, + {HPHW_NPROC,0x5D4,0x4,0x91,"Duet W+"}, + {HPHW_NPROC,0x5D5,0x4,0x91,"Crescendo 550"}, + {HPHW_NPROC,0x5D6,0x4,0x81,"Crescendo DC- 440"}, + {HPHW_NPROC,0x5D7,0x4,0x91,"Keystone W+"}, + {HPHW_NPROC,0x5D8,0x4,0x91,"Rhapsody wave 2 W+ DC-"}, + {HPHW_NPROC,0x5D9,0x4,0x91,"Rhapsody wave 2 W+"}, + {HPHW_NPROC,0x5DA,0x4,0x91,"Marcato W+ DC-"}, + {HPHW_NPROC,0x5DB,0x4,0x91,"Marcato W+"}, + {HPHW_NPROC,0x5DE,0x4,0x81,"Piccolo W+"}, {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"}, {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"}, {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"}, @@ -694,8 +711,8 @@ {HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"}, {HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"}, {HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"}, - {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ wSE FWSCSI Core Centronics"}, - {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ wDiff FWSCSI Core Centronics"}, + {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ w SE FWSCSI Core Centronics"}, + {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ w Diff FWSCSI Core Centronics"}, {HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"}, {HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"}, {HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"}, @@ -1370,7 +1387,20 @@ { 0x05ba, 0x0fff, pcxu_ }, /* 0x05ba - 0x05ba */ { 0x05bb, 0x0fff, pcxw }, /* 0x05bb - 0x05bb */ { 0x05bc, 0x0ffc, pcxw }, /* 0x05bc - 0x05bf */ - { 0x05c0, 0x0fc0, pcxw }, /* 0x05c0 - 0x05ff */ + { 0x05c0, 0x0ffc, pcxw }, /* 0x05c0 - 0x05c3 */ + { 0x05c4, 0x0ffe, pcxw }, /* 0x05c4 - 0x05c5 */ + { 0x05c6, 0x0fff, pcxw }, /* 0x05c6 - 0x05c6 */ + { 0x05c7, 0x0fff, pcxw_ }, /* 0x05c7 - 0x05c7 */ + { 0x05c8, 0x0ffc, pcxw }, /* 0x05c8 - 0x05cb */ + { 0x05cc, 0x0ffe, pcxw }, /* 0x05cc - 0x05cd */ + { 0x05ce, 0x0ffe, pcxw_ }, /* 0x05ce - 0x05cf */ + { 0x05d0, 0x0ffc, pcxw_ }, /* 0x05d0 - 0x05d3 */ + { 0x05d4, 0x0ffe, pcxw_ }, /* 0x05d4 - 0x05d5 */ + { 0x05d6, 0x0fff, pcxw }, /* 0x05d6 - 0x05d6 */ + { 0x05d7, 0x0fff, pcxw_ }, /* 0x05d7 - 0x05d7 */ + { 0x05d8, 0x0ff8, pcxw_ }, /* 0x05d8 - 0x05df */ + { 0x05e0, 0x0ff0, pcxw_ }, /* 0x05e0 - 0x05ef */ + { 0x05f0, 0x0ff0, pcxw_ }, /* 0x05f0 - 0x05ff */ { 0x0600, 0x0ff0, pcxl }, /* 0x0600 - 0x060f */ { 0x0610, 0x0ff0, pcxl }, /* 0x0610 - 0x061f */ { 0x0000, 0x0000, pcx } /* terminate table */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/head.S linux.ac/arch/parisc/kernel/head.S --- linux.vanilla/arch/parisc/kernel/head.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/head.S Tue Apr 3 17:54:33 2001 @@ -8,17 +8,14 @@ * Copyright 1999 SuSE GmbH (Philipp Rumpf) * Copyright 1999 Philipp Rumpf (prumpf@tux.org) * - * Initial Version 04-23-1999 by Helge Deller (helge.deller@ruhr-uni-bochum.de) + * Initial Version 04-23-1999 by Helge Deller */ +#include /* for CONFIG_SMP */ #include #include -#define __ASSEMBLY__ -/********* -#include -*********/ #include #include @@ -52,43 +49,97 @@ .callinfo /* Make sure sr4-sr7 are set to zero for the kernel address space */ - - mtsp %r0,%sr4 - mtsp %r0,%sr5 - mtsp %r0,%sr6 - mtsp %r0,%sr7 + mtsp %r0,%sr4 + mtsp %r0,%sr5 + mtsp %r0,%sr6 + mtsp %r0,%sr7 /* Initialize startup VM. Just map first 8 MB of memory */ - ldil L%PA(pg0),%r1 ldo R%PA(pg0)(%r1),%r1 ldo _PAGE_TABLE(%r1),%r3 + ldil L%PA(swapper_pg_dir),%r4 ldo R%PA(swapper_pg_dir)(%r4),%r4 mtctl %r4,%cr24 /* Initialize kernel root pointer */ mtctl %r4,%cr25 /* Initialize user root pointer */ - stw %r3,0xc00(%r4) /* Hardwired 0xc0000000 kernel vaddr start */ + + stw %r3,0xc00(%r4) /* Hardwired 0xc... kernel Vaddr start*/ ldo 0x1000(%r3),%r3 stw %r3,0xc04(%r4) - ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0x0 phys addr start */ + ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */ $pgt_fill_loop: stwm %r3,4(%r1) ldo 0x1000(%r3),%r3 bb,>= %r3,8,$pgt_fill_loop nop + + /* Load the return address...er...crash 'n burn */ + copy %r0,%r2 + + /* And the RFI Target address too */ + ldil L%start_parisc,%r11 + ldo R%start_parisc(%r11),%r11 + + /* And the stack pointer too */ + ldil L%init_task_union+TASK_SZ_ALGN,%sp + ldo R%init_task_union+TASK_SZ_ALGN(%sp),%sp + +#ifdef CONFIG_SMP + /* Set the smp rendevous address into page zero. + ** It would be safer to do this in init_smp_config() but + ** it's just way easier to deal with here because + ** of 64-bit function ptrs and the address is local to this file. + */ + ldil L%PA(smp_slave_stext),%r10 + ldo R%PA(smp_slave_stext)(%r10),%r10 + stw %r10,0x10(%r0) /* MEM_RENDEZ */ + stw %r0,0x28(%r0) /* MEM_RENDEZ_HI - assume addr < 4GB */ + + /* FALLTHROUGH */ + .procend + + /* + ** Code Common to both Monarch and Slave processors. + ** Entry: + ** %r11 must contain RFI target address. + ** %r25/%r26 args to pass to target function + ** %r2 in case rfi target decides it didn't like something + ** + ** Caller must init: SR4-7, %sp, %r10, %cr24/25, + */ +common_stext: + .proc + .callinfo +#else + /* Clear PDC entry point - we won't use it */ + stw %r0,0x10(%r0) /* MEM_RENDEZ */ + stw %r0,0x28(%r0) /* MEM_RENDEZ_HI */ +#endif + + /* PARANOID: clear user scratch/user space SR's */ + mtsp %r0,%sr0 + mtsp %r0,%sr1 + mtsp %r0,%sr2 + mtsp %r0,%sr3 + + /* Initialize Protection Registers */ + mtctl %r0,%cr8 + mtctl %r0,%cr9 + mtctl %r0,%cr12 + mtctl %r0,%cr13 + /* Initialize the global data pointer */ ldil L%$global$,%dp ldo R%$global$(%dp),%dp - - /* And the stack pointer, physical too */ - ldil L%init_task_union+TASK_SZ_ALGN,%sp - ldo R%init_task_union+TASK_SZ_ALGN(%sp),%sp - /* we need this to take interruptions directly after the rfi below */ - /* (which we need for PA2.0 boxes) */ + /* Clear the current task register. + ** We need this to take interruptions directly after the rfi below + ** (required for PA2.0 boxes) + */ mtctl %r0, %cr30 - + /* * Set up our interrupt table. HPMCs might not work after this! * @@ -96,7 +147,6 @@ * following short sequence of instructions can determine this * (without being illegal on a PA1.1 machine). */ - ldi 32,%r10 mtctl %r10,%cr11 .level 2.0 @@ -116,34 +166,103 @@ /* Disable (most) interruptions */ mtsm %r0 - + /* kernel PSW: - * - no interruptions except for HPMC and TOC (which are handled by PDC) + * - no interruptions except HPMC and TOC (which are handled by PDC) * - Q bit set (IODC / PDC interruptions) * - big-endian * - virtually mapped */ - ldil L%KERNEL_PSW,%r10 ldo R%KERNEL_PSW(%r10),%r10 mtctl %r10,%ipsw - - /* Set the space pointers for the post-RFI world */ - mtctl %r0,%cr17 /* Clear two-level IIA Space Queue */ - mtctl %r0,%cr17 /* effectively setting kernel space. */ - - /* And the return address(es) too */ - ldil L%start_parisc,%r10 - ldo R%start_parisc(%r10),%r10 - mtctl %r10,%cr18 - ldo 4(%r10),%r10 - mtctl %r10,%cr18 + + /* Set the space pointers for the post-RFI world + ** Clear the two-level IIA Space Queue, effectively setting + ** Kernel space. + */ + mtctl %r0,%cr17 + mtctl %r0,%cr17 + + /* Load RFI target into PC queue */ + mtctl %r11,%cr18 + ldo 4(%r11),%r11 + mtctl %r11,%cr18 /* Jump to hyperspace */ rfi nop .procend + + +#ifdef CONFIG_SMP + + .import smp_init_current_idle_task,data + .import smp_callin,code + +smp_callin_rtn: + .proc + .callinfo + break 1,1 /* Break if returned from start_secondary */ + nop + nop + .procend + +/*************************************************************************** +* +* smp_slave_stext is executed by all non-monarch Processors when the Monarch +* pokes the slave CPUs in smp.c:smp_boot_cpus(). +* +* Once here, registers values are initialized in order to branch to virtual +* mode. Once all available/eligible CPUs are in virtual mode, all are +* released and start out by executing their own idle task. +*****************************************************************************/ + + +smp_slave_stext: + .proc + .callinfo + + /* + ** Initialize Space registers + */ + mtsp %r0,%sr4 + mtsp %r0,%sr5 + mtsp %r0,%sr6 + mtsp %r0,%sr7 + + /* Initialize the SP - monarch sets up smp_init_current_idle_task */ + ldil L%PA(smp_init_current_idle_task),%sp + ldo R%PA(smp_init_current_idle_task)(%sp),%sp +#ifdef __LP64__ + ldd 0(%sp),%sp /* load task address */ +#else + ldw 0(%sp),%sp /* load task address */ +#endif + addil L%TASK_SZ_ALGN,%sp /* stack is above task */ + ldo R%TASK_SZ_ALGN(%r1),%sp + + /* point CPU to kernel page tables */ + ldil L%PA(swapper_pg_dir),%r4 + ldo R%PA(swapper_pg_dir)(%r4),%r4 + mtctl %r4,%cr24 /* Initialize kernel root pointer */ + mtctl %r4,%cr25 /* Initialize user root pointer */ + + /* Load RFI *return* address in case smp_callin bails */ + ldil L%smp_callin_rtn,%r2 + ldo R%smp_callin_rtn(%r2),%r2 + + /* Load RFI target address. */ + ldil L%smp_callin,%r11 + ldo R%smp_callin(%r11),%r11 + + /* ok...common code can handle the rest */ + b common_stext + nop + + .procend +#endif /* CONFIG_SMP */ .data diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/hpmc.S linux.ac/arch/parisc/kernel/hpmc.S --- linux.vanilla/arch/parisc/kernel/hpmc.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/hpmc.S Tue Apr 3 17:54:34 2001 @@ -43,7 +43,6 @@ .level 1.1 .data -#define __ASSEMBLY__ #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/inventory.c linux.ac/arch/parisc/kernel/inventory.c --- linux.vanilla/arch/parisc/kernel/inventory.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/inventory.c Tue Apr 3 17:54:34 2001 @@ -1,40 +1,36 @@ - /* Copyright (c) 1999 The Puffin Group */ /* Written by David Kennedy and Alex deVries */ #include #include +#include #include #include #include +#include /* ** Debug options -** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices. +** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices. */ #undef DEBUG_PAT -extern char *parisc_getHWtype(unsigned short hw_type); - -extern struct hp_device * register_module(void *hpa); -extern void print_devices(char * buf); - - -int pdc_hpa_processor(void *address); -#ifndef __LP64__ -static u8 iodc_data[32] __attribute__ ((aligned (64))); -static struct pdc_model model __attribute__ ((aligned (8))); +#ifndef __LP64__ +static u8 iodc_data[32 * sizeof(long)] __attribute__ ((aligned(64))); +static struct pdc_memory_map r_addr __attribute__ ((aligned(8))); +static struct pdc_model model __attribute__ ((aligned(8))); #endif -static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; -static struct pdc_hpa processor_hpa __attribute__ ((aligned (8))); -static struct pdc_system_map module_result __attribute__ ((aligned (8))); -static struct pdc_module_path module_path __attribute__ ((aligned (8))); +static unsigned long pdc_result[32] __attribute__ ((aligned(8))); +static struct pdc_hpa processor_hpa __attribute__ ((aligned(8))); +static struct pdc_system_map_mod_info module_result __attribute__ ((aligned(8))); +static struct pdc_system_map_addr_info addr_result __attribute__ ((aligned(8))); +static struct pdc_module_path module_path __attribute__ ((aligned(8))); #ifdef __LP64__ #include -int pdc_pat = 0; +int pdc_pat; /* ** The module object is filled via PDC_PAT_CELL[Return Cell Module]. @@ -47,26 +43,25 @@ ** */ -static int -pat_query_module( ulong pcell_loc, ulong mod_index) +static int pat_query_module(ulong pcell_loc, ulong mod_index) { - extern int num_devices; - extern struct hp_device devices[]; - pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; - struct hp_device * dev = &devices[num_devices]; - uint64_t temp; /* 64-bit scratch value */ - long status; /* PDC return value status */ + unsigned long temp; /* 64-bit scratch value */ + long status; /* PDC return value status */ + struct hp_device *dev; /* return cell module (PA or Processor view) */ - status = pdc_pat_cell_module(& pdc_result, pcell_loc, mod_index, - PA_VIEW, & pa_pdc_cell); + status = pdc_pat_cell_module(&pdc_result, pcell_loc, mod_index, + PA_VIEW, &pa_pdc_cell); if (status != PDC_RET_OK) { /* no more cell modules or error */ return status; } + temp = pa_pdc_cell.cba; + dev = alloc_pa_dev(PAT_GET_CBA(temp)); /* sets dev->hpa */ + /* ** save parameters in the hp_device ** (The idea being the device driver will call pdc_pat_cell_module() @@ -81,8 +76,7 @@ dev->pmod_loc = pa_pdc_cell.mod_location; dev->mod_path = pa_pdc_cell.mod_path; - temp = pa_pdc_cell.cba; - register_module((void *) PAT_GET_CBA(temp)); /* fills in dev->hpa */ + register_pa_dev(dev); /* advertise device */ #ifdef DEBUG_PAT /* dump what we see so far... */ @@ -90,37 +84,36 @@ ulong i; case PAT_ENTITY_PROC: - printk ("PAT_ENTITY_PROC: id_eid 0x%lx\n", pa_pdc_cell.mod[0]); + printk("PAT_ENTITY_PROC: id_eid 0x%lx\n", + pa_pdc_cell.mod[0]); break; case PAT_ENTITY_MEM: - printk ("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n", - pa_pdc_cell.mod[0], - pa_pdc_cell.mod[1], - pa_pdc_cell.mod[2]); + printk("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n", + pa_pdc_cell.mod[0], pa_pdc_cell.mod[1], + pa_pdc_cell.mod[2]); break; case PAT_ENTITY_CA: - printk ("PAT_ENTITY_CA: %ld\n",pcell_loc); + printk("PAT_ENTITY_CA: %ld\n", pcell_loc); break; case PAT_ENTITY_PBC: - printk ("PAT_ENTITY_PBC: "); + printk("PAT_ENTITY_PBC: "); goto print_ranges; case PAT_ENTITY_SBA: - printk ("PAT_ENTITY_SBA: "); + printk("PAT_ENTITY_SBA: "); goto print_ranges; case PAT_ENTITY_LBA: - printk ("PAT_ENTITY_LBA: "); + printk("PAT_ENTITY_LBA: "); -print_ranges: - printk ("ranges %ld\n", pa_pdc_cell.mod[1]); + print_ranges: + printk("ranges %ld\n", pa_pdc_cell.mod[1]); for (i = 0; i < pa_pdc_cell.mod[1]; i++) { - printk (" %ld: 0x%016lx 0x%016lx 0x%016lx\n", i, - pa_pdc_cell.mod[2+i*3], /* type */ - pa_pdc_cell.mod[3+i*3], /* start */ - pa_pdc_cell.mod[4+i*3]); /* finish (ie end) */ + printk(" %ld: 0x%016lx 0x%016lx 0x%016lx\n", i, pa_pdc_cell.mod[2 + i * 3], /* type */ + pa_pdc_cell.mod[3 + i * 3], /* start */ + pa_pdc_cell.mod[4 + i * 3]); /* finish (ie end) */ } printk("\n"); break; @@ -132,14 +125,13 @@ static int do_pat_inventory(void) { - ulong mod_index=0; + ulong mod_index = 0; int status; ulong cell_num; ulong pcell_loc; pdc_pat = (pdc_pat_cell_get_number(&pdc_result) == PDC_OK); - if (!pdc_pat) - { + if (!pdc_pat) { return 0; } @@ -152,9 +144,8 @@ printk("CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_num, pcell_loc); #endif - status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num); - if (status == PDC_BAD_OPTION) - { + status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num); + if (status == PDC_BAD_OPTION) { /* Prelude (and it's successors: Lclass, A400/500) only ** implement PDC_PAT_CELL sub-options 0 and 2. ** "Home cook'n is best anyhow!" @@ -166,45 +157,134 @@ panic("WTF? CELL_GET_NUMBER give me invalid cell number?"); } - while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index)) - { + while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index)) { mod_index++; } return mod_index; } -#endif /* __LP64__ */ +#endif /* __LP64__ */ + +/* Fixed Physical Address - Location of the Central Bus */ +#define FPA (unsigned long)(signed int)0xFFF80000 + +/* The fixed portion is contained in hpa[14..19] for 32 bit and hpa[46..51] for 64 bit. +** The maximum number of native devices is 2^6 (64) and the offset between devices is +** 2^12 (0x1000). +** - Ryan +*/ +#define MAX_NATIVE_DEVICES 64 +#define NATIVE_DEVICE_OFFSET 0x1000 + +static int do_native_bus_walk(unsigned long hpa) +{ + int num = 0; + struct hp_device *hp_device; + unsigned long hpa_end = + hpa + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET); + + for (; hpa < hpa_end; hpa += NATIVE_DEVICE_OFFSET) { + hp_device = alloc_pa_dev(hpa); + if (!hp_device) + continue; + + register_pa_dev(hp_device); + ++num; + } + return num; +} static int do_newer_workstation_inventory(void) { + int i, j, num; long status; - int i, num = 0; + struct hp_device *hp_device; /* So the idea here is to simply try one SYSTEM_MAP call. If - that one works, great, otherwise do it another way */ - - status = pdc_system_map_find_mods(&module_result,&module_path,0); - - if (status == PDC_RET_OK) { - /* This is for newer non-PDC-PAT boxes */ + ** that one works, great, otherwise do it another way + */ + status = pdc_system_map_find_mods(&module_result, &module_path, 0); + if (status != PDC_RET_OK) + return 0; - printk("a newer box...\n"); - for(i=0, status=PDC_RET_OK; status != PDC_RET_NE_PROC && - status != PDC_RET_NE_MOD ;i++) { + /* This is for newer non-PDC-PAT boxes */ + printk("a newer box...\n"); + num = 0; + for (i = 0; status != PDC_RET_NE_PROC && status != PDC_RET_NE_MOD; ++i) { + + status = pdc_system_map_find_mods(&module_result, &module_path, i); + if (status != PDC_RET_OK) + continue; + + hp_device = alloc_pa_dev((unsigned long) module_result.mod_addr); + if (!hp_device) + continue; + + register_pa_dev(hp_device); + ++num; + + /* if available, get the additional addresses for a module */ + if (!module_result.add_addrs) + continue; - status = pdc_system_map_find_mods(&module_result,&module_path,i); + for (j = 1; j <= module_result.add_addrs; ++j) { + status = pdc_system_map_find_addrs(&addr_result, i, j); if (status == PDC_RET_OK) { - num++; - register_module(module_result.mod_addr); + add_pa_dev_addr(hp_device, (unsigned long) + addr_result.mod_addr); + } else { + printk("Bad PDC_FIND_ADDRESS status return (%ld) for index %d\n", + status, j); + status = PDC_RET_OK; /* reset status for outer loop */ } } - } + } /* end of main loop */ + /* Walk the system bus */ + num += do_native_bus_walk(FPA); return (num > 0); } + #ifndef __LP64__ -static struct pdc_memory_map r_addr __attribute__ ((aligned (8))); + +/* The following checks to see if the system is a 715/old. This might +** sound a bit unusual, but there are some workarounds required for these +** machines. These machines are the 715/33, 715/50 and 715/75. +** +** This function returns 1 if we are a 715/old, and 0 if we're not. +*/ +static int check_if_715old(void) +{ + /* To do this check, I'm going to look at the CPU's hversion and + ** and sversion. I'm taking the following from documentation. Here's + ** the table of machines to skip (CPU_HVERSIONs from hardware.c): + ** + ** Machine CPU_HVERSION real life verification + ** + ** Scorpio (715/50): 0x310 Yes + ** Scorpio Jr.(715/33) 0x311 Yes + ** Strider-50 (715S/50) 0x312 No + ** Strider-33 (715S/33) 0x313 No + ** Trailways-50 (715T/50) 0x314 No + ** Trailways-33 (715T/33) 0x315 No + ** Scorpio Sr.(715/75) 0x316 Yes + ** + */ + + switch (CPU_HVERSION) { + case 0x310: + case 0x311: + case 0x312: + case 0x313: + case 0x314: + case 0x315: + case 0x316: + return 1; + } + return 0; +} + static int really_do_oldhw_inventory(void) { @@ -214,184 +294,205 @@ unsigned int func; /* This is undocumented at the time of writing, but basically - we're setting up mod_path so that bc[0..4]=0xff, and step - through mod to get the "Path Structure for GSC Modules". If - it works, use the returned HPA and determine the hardware type. */ + ** we're setting up mod_path so that bc[0..4]=0xff, and step + ** through mod to get the "Path Structure for GSC Modules". If + ** it works, use the returned HPA and determine the hardware type. + */ - for (i=0;i<6;i++) module_path.bc[i]=0xff; + memset(module_path.bc, 0xff, sizeof(module_path.bc)); - for (mod=0;mod<16;mod++) { + for (mod = 0; mod < 16; mod++) { char *stype = NULL; - - module_path.mod=mod; + + module_path.mod = mod; + status = pdc_mem_map_hpa(&r_addr, &module_path); - if (status!=PDC_RET_OK) continue; - - status = pdc_iodc_read(&pdc_result,(void *) r_addr.hpa, - 0, &iodc_data,32 ); - if (status!=PDC_RET_OK) continue; - hw_type = iodc_data[3]&0x1f; - - switch (hw_type) - { - case HPHW_NPROC: /* 0 */ - stype="Processor"; break; - - case HPHW_MEMORY: /* 1 */ - stype="Memory"; break; - - case HPHW_B_DMA: /* 2 */ - stype="Type B DMA"; break; - - case HPHW_A_DMA: /* 4 */ - stype="Type A DMA"; break; - - case HPHW_A_DIRECT: /* 5 */ - stype="Type A Direct"; break; - - case HPHW_BCPORT: /* 7 */ - stype="Bus Converter Port"; break; - - case HPHW_CONSOLE: /* 9 */ - stype="Console"; break; - - case HPHW_FIO: /* 10 - Graphics */ - stype="Foreign I/O (Graphics)"; break; - - case HPHW_BA: /* 11 - Bus Adapter */ - stype="Bus Adapter"; break; - - case HPHW_IOA: /* 12 */ - stype="I/O Adapter"; break; - - case HPHW_BRIDGE: /* 13 */ - stype="Bridge"; break; - - case HPHW_FABRIC: /* 14 */ - stype="Fabric"; break; - - case HPHW_FAULTY: /* 31 */ - stype="Faulty HW"; break; + if (status != PDC_RET_OK) + continue; + + /* On 715/old systems, pdc_iodc_read() seems to fail + ** and simply hang the system when querying the onboard + ** graphics cards, which are at location 0xf800000. Because + ** of this, I'm going to skip them. We might have to rewrite + ** an exception to this so it ends up in the inventory table. + ** In any case, this is where the hook is. + */ + if (r_addr.hpa == 0xf8000000 && check_if_715old()) { + printk("Using Alex's odd 715/old exception, onboard graphics won't be inventoried!\n"); + continue; + } + status = pdc_iodc_read(&pdc_result, (void *) r_addr.hpa, 0, + &iodc_data, 32); + if (status != PDC_RET_OK) + continue; + + hw_type = iodc_data[3] & 0x1f; + switch (hw_type) { + case HPHW_NPROC: + stype = "Processor"; + break; /* 0 */ + case HPHW_MEMORY: + stype = "Memory"; + break; /* 1 */ + case HPHW_B_DMA: + stype = "Type B DMA"; + break; /* 2 */ + case HPHW_A_DMA: + stype = "Type A DMA"; + break; /* 4 */ + case HPHW_A_DIRECT: + stype = "Type A Direct"; + break; /* 5 */ + case HPHW_BCPORT: + stype = "Bus Converter Port"; + break; /* 7 */ + case HPHW_CONSOLE: + stype = "Console"; + break; /* 9 */ + case HPHW_FIO: + stype = "Foreign I/O (Graphics)"; + break; /* 10 */ + case HPHW_BA: + stype = "Bus Adapter"; + break; /* 11 */ + case HPHW_IOA: + stype = "I/O Adapter"; + break; /* 12 */ + case HPHW_BRIDGE: + stype = "Bridge"; + break; /* 13 */ + case HPHW_FABRIC: + stype = "Fabric"; + break; /* 14 */ + case HPHW_FAULTY: + stype = "Faulty HW"; + break; /* 31 */ case HPHW_OTHER: /* 42 */ - default: + default: printk("Don't know this hw_type: %d\n", hw_type); break; - } + } /* switch() */ - // This is kluged. But don't want to replicate code for - // most of the above cases. + /* This is kluged. But don't want to replicate code for + ** most of the above cases. + */ if (stype) { -#ifdef DBG_PDC_QUERY - // parisc/kernel/drivers.c - extern int num_devices; - extern struct hp_device devices[]; - struct hp_hardware *h; -#endif + struct hp_device *hp_dev; status = pdc_mem_map_hpa(&r_addr, &module_path); - if (status==PDC_RET_OK && register_module((void *) r_addr.hpa) != NULL) - num++; + if (status == PDC_RET_OK + && (hp_dev = alloc_pa_dev(r_addr.hpa))) { + + register_pa_dev(hp_dev); + ++num; + } + if (hw_type == HPHW_BA) { + /* Now, we're checking for devices for each + ** module. I seem to think that the + ** modules in question are Lasi (2), 2nd Lasi (6) + ** Wax (5). To do this, set bc[5]=0, and set + ** bc[4] to the module, and step through the + ** functions. + */ + + for (i = 0; i < 4; i++) { + module_path.bc[i] = 0xff; + } + + module_path.bc[4] = mod; + for (func = 0; func < 16; func++) { + module_path.mod = func; + module_path.bc[5] = 0; + + status = pdc_mem_map_hpa(&r_addr, + &module_path); + if (status != PDC_RET_OK) + continue; + + hp_dev = alloc_pa_dev(r_addr.hpa); + if (hp_dev) { + register_pa_dev(hp_dev); + ++num; + } + } - if (hw_type == HPHW_BA) { - /* Now, we're checking for devices for each - module. I seem to think that the - modules in question are Lasi (2), 2nd Lasi (6) - Wax (5). To do this, set bc[5]=0, and set - bc[4] to the module, and step through the - functions. */ - - for (i=0;i<4;i++) module_path.bc[i]=0xff; - module_path.bc[4]=mod; - for (func=0;func<16;func++) { - module_path.mod = func; - module_path.bc[5]=0; - status = pdc_mem_map_hpa(&r_addr, &module_path); - if (status!=PDC_RET_OK) continue; - if (register_module((void *) r_addr.hpa) != NULL) - num++; } - } - // reset module_path.bc[] - for (i=0;i<6;i++) module_path.bc[i]=0xff; + /* hw_type == HPHW_BA */ + /* reset module_path.bc[] */ + memset(module_path.bc, 0xff, + sizeof(module_path.bc)); -#ifdef DBG_PDC_QUERY -// -// Let print_devices() dump everything which is registered. -// - h = devices[num_devices-1].reference; + } /* if (stype) */ + } /* for() */ - if (h) stype = h->name; - printk("Found %s at %d\n", stype, module_path.mod); -#endif - } - } return num; } -static int -do_old_inventory(void) +static int do_old_inventory(void) { - unsigned int bus_id; + unsigned int bus_id; long status; - int ok = 0; printk(" an older box...\n"); /* Here, we're going to check the model, and decide - if we should even bother trying. */ + ** if we should even bother trying. + */ status = pdc_model_info(&model); - bus_id = (model.hversion >> (4+7) ) &0x1f; + bus_id = (model.hversion >> (4 + 7)) & 0x1f; /* Here, we're checking the HVERSION of the CPU. - We're only checking the 0th CPU, since it'll - be the same on an SMP box. */ + ** We're only checking the 0th CPU, since it'll + ** be the same on an SMP box. + */ switch (bus_id) { - case 0x4: /* 720, 730, 750, 735, 755 */ - case 0x6: /* 705, 710 */ - case 0x7: /* 715, 725 */ - case 0x8: /* 745, 747, 742 */ - case 0xA: /* 712 and similiar */ - case 0xC: /* 715/64, at least */ + case 0x4: /* 720, 730, 750, 735, 755 */ + case 0x6: /* 705, 710 */ + case 0x7: /* 715, 725 */ + case 0x8: /* 745, 747, 742 */ + case 0xA: /* 712 and similiar */ + case 0xC: /* 715/64, at least */ /* Do inventory using MEM_MAP */ - really_do_oldhw_inventory(); - ok = 1; - break; - default: /* Everything else */ - printk("This is a very very old machine, with a bus_id of 0x%x.\n",bus_id); + return really_do_oldhw_inventory(); + + default: /* Everything else */ + printk("This is a very very old machine, with a bus_id of 0x%x.\n", + bus_id); panic("This will probably never run Linux.\n"); } - return ok; + return 0; } #endif /* !__LP64__ */ -void do_inventory(void){ - if((pdc_hpa_processor(&processor_hpa))<0){ - printk(KERN_INFO "Couldn't get the HPA of the processor.\n" ); +void do_inventory(void) +{ + if (pdc_hpa_processor(&processor_hpa) < 0) { + printk(KERN_INFO + "Couldn't get the HPA of the processor.\n"); } printk("Searching for devices in PDC firmware... "); printk("processor hpa 0x%lx\n", processor_hpa.hpa); - if (!( - do_newer_workstation_inventory() + if (!(do_newer_workstation_inventory() #ifdef __LP64__ - || do_pat_inventory() -#else /* __LP64__ */ - || do_old_inventory() -#endif /* __LP64__ */ - )) - { - panic("I can't get the hardware inventory on this machine"); + || do_pat_inventory() +#else /* __LP64__ */ + || do_old_inventory() +#endif /* __LP64__ */ + )) { + panic("I can't get the hardware inventory on this machine"); } - print_devices(NULL); + + print_pa_devices(NULL); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/iosapic.c linux.ac/arch/parisc/kernel/iosapic.c --- linux.vanilla/arch/parisc/kernel/iosapic.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/iosapic.c Tue Apr 3 17:54:34 2001 @@ -714,7 +714,8 @@ vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8); ASSERT(vi->vi_txn_data < 256); /* matches 8 above */ - tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi); + tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, + vi->vi_name, vi); ASSERT(tmp == 0); vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI; @@ -1034,6 +1035,7 @@ } memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors); + sprintf(isi->isi_name, "IO-SAPIC%02d", iosapic_count++); /* ** Initialize vector array @@ -1041,11 +1043,12 @@ for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { vip->vi_irqline = (unsigned char) cnt; vip->vi_ios = isi; + sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt); } isi->isi_region = alloc_irq_region(isi->isi_num_vectors, &iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK, - "I/O Sapic", (void *) isi->isi_vector); + isi->isi_name, (void *) isi->isi_vector); ASSERT(NULL != isi->isi_region); return ((void *) isi); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/iosapic_private.h linux.ac/arch/parisc/kernel/iosapic_private.h --- linux.vanilla/arch/parisc/kernel/iosapic_private.h Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/iosapic_private.h Tue Apr 3 17:54:34 2001 @@ -111,11 +111,12 @@ struct irt_entry *vi_irte; /* IRT entry */ u32 *vi_eoi_addr; /* precalculate EOI reg address */ u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */ - u8 vi_status; /* status/flags */ - u8 vi_irqline; /* INTINn(IRQ) */ int vi_txn_irq; /* virtual IRQ number for processor */ ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */ ulong vi_txn_data; /* IA64: vector PA: EIR bit */ + u8 vi_status; /* status/flags */ + u8 vi_irqline; /* INTINn(IRQ) */ + char vi_name[32]; /* user visible identity */ }; @@ -127,6 +128,8 @@ int isi_num_vectors; /* size of IRdT array */ int isi_status; /* status/flags */ unsigned int isi_version; /* DEBUG: data fr version reg */ + /* round up to next cacheline */ + char isi_name[20]; /* identify region for users */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/irq.c linux.ac/arch/parisc/kernel/irq.c --- linux.vanilla/arch/parisc/kernel/irq.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/irq.c Tue Apr 3 17:54:34 2001 @@ -2,12 +2,10 @@ * * Code to handle x86 style IRQs plus some generic interrupt stuff. * - * This is not in any way SMP-clean. - * * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle - * Copyright (C) 1999 SuSE GmbH (Author: Philipp Rumpf, prumpf@tux.org) - * Copyright (C) 2000 Hewlett Packard Corp (Co-Author: Grant Grundler, grundler@cup.hp.com) + * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org) + * Copyright (C) 1999-2000 Grant Grundler * * 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 @@ -23,9 +21,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include +#include #include #include #include @@ -39,13 +37,16 @@ #include #include #include +#include #include #undef DEBUG_IRQ extern void timer_interrupt(int, void *, struct pt_regs *); +#ifdef CONFIG_SMP extern void ipi_interrupt(int, void *, struct pt_regs *); +#endif #ifdef DEBUG_IRQ #define DBG_IRQ(x...) printk(x) @@ -53,9 +54,11 @@ #define DBG_IRQ(x...) #endif /* DEBUG_IRQ */ -#define EIEM_MASK(irq) (1L<<(MAX_CPU_IRQ-IRQ_OFFSET(irq))) -#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq)) -#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq)) +#define EIEM_MASK(irq) (1UL<<(MAX_CPU_IRQ-IRQ_OFFSET(irq))) +#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq)) +#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq)) + +static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; /* protect IRQ regions */ static void disable_cpu_irq(void *unused, int irq) { @@ -72,17 +75,19 @@ static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = { [IRQ_OFFSET(TIMER_IRQ)] { timer_interrupt, 0, 0, "timer", NULL, NULL }, +#ifdef CONFIG_SMP [IRQ_OFFSET(IPI_IRQ)] { ipi_interrupt, 0, 0, "IPI", NULL, NULL }, +#endif }; struct irq_region cpu_irq_region = { { disable_cpu_irq, enable_cpu_irq, NULL, NULL }, - { &cpu_data[0], "PA-PIC", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)}, + { &cpu_data[0], "PA-CPU-00", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)}, cpu_irq_actions }; struct irq_region *irq_region[NR_IRQ_REGS] = { - [ 0 ] NULL, /* abuse will data page fault (aka code 15) */ + [ 0 ] NULL, /* abuse will data page fault (aka code 15) */ [ CPU_IRQ_REGION ] &cpu_irq_region, }; @@ -95,7 +100,7 @@ static inline void mask_irq(int irq) { struct irq_region *region; - + #ifdef DEBUG_IRQ if (irq != TIMER_IRQ) #endif @@ -144,7 +149,7 @@ BUG(); } -void enable_irq(int irq) +void enable_irq(int irq) { struct irq_region *region; @@ -164,30 +169,36 @@ { #ifdef CONFIG_PROC_FS char *p = buf; - int i, j; - int regnr, irq_no; + int i; + int regnr; struct irq_region *region; - struct irqaction *action, *mainaction; + struct irqaction *action; p += sprintf(p, " "); - for (j=0; jaction) + + if (!region || !region->action) continue; - - mainaction = region->action; for (i = 0; i <= MAX_CPU_IRQ; i++) { - action = mainaction++; - if (!action || !action->name) + unsigned int irq_no; +#ifdef CONFIG_SMP + int j; +#endif + action = &(region->action[i]); + if (!action->handler) continue; - + irq_no = IRQ_FROM_REGION(regnr) + i; - + p += sprintf(p, "%3d: ", irq_no); #ifndef CONFIG_SMP p += sprintf(p, "%10u ", kstat_irqs(irq_no)); @@ -196,30 +207,20 @@ p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][irq_no]); #endif - p += sprintf(p, " %14s", + p += sprintf(p, " %14s", region->data.name ? region->data.name : "N/A"); p += sprintf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - p += sprintf(p, ", %s", action->name); *p++ = '\n'; - } - } + } + } + spin_unlock(&irq_lock); p += sprintf(p, "\n"); -#if CONFIG_SMP - p += sprintf(p, "LOC: "); - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); - p += sprintf(p, "\n"); -#endif - return p - buf; #else /* CONFIG_PROC_FS */ - return 0; + return 0; #endif /* CONFIG_PROC_FS */ } @@ -283,7 +284,7 @@ ** V-class (EPIC): 6 bits ** N/L-class/A500: 8 bits (iosapic) ** PCI 2.2 MSI: 16 bits (I think) -** Existing PCI devices: 32-bits (NCR c720/ATM/GigE/HyperFabric) +** Existing PCI devices: 32-bits (all Symbios SCSI/ATM/HyperFabric) ** ** On the service provider side: ** o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register) @@ -318,21 +319,23 @@ int cpu = smp_processor_id(); irq_enter(cpu, irq); + ++kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)]; #ifdef DEBUG_IRQ if (irq != TIMER_IRQ) #endif DBG_IRQ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)); + if (action->handler == NULL) - printk(KERN_ERR "No handler for interrupt %d !\n", irq); + printk(KERN_ERR "IRQ: CPU:%d No handler for IRQ %d !\n", cpu, irq); for(; action && action->handler; action = action->next) { action->handler(irq, action->dev_id, regs); } - + irq_exit(cpu, irq); - /* don't need to care about unmasking and stuff */ + /* do_irq_mask() deals with IRQ unmasking and stuff */ do_softirq(); } @@ -340,7 +343,6 @@ { unsigned long bit; int irq; - int cpu = smp_processor_id(); #ifdef DEBUG_IRQ if (mask != (1L << MAX_CPU_IRQ)) @@ -354,17 +356,13 @@ irq_num = region->data.irqbase + irq; - ++kstat.irqs[cpu][IRQ_FROM_REGION(CPU_IRQ_REGION) | irq]; - if (IRQ_REGION(irq_num) != CPU_IRQ_REGION) - ++kstat.irqs[cpu][irq_num]; - mask_irq(irq_num); do_irq(®ion->action[irq], irq_num, regs); unmask_irq(irq_num); } } -static inline int alloc_irqregion(void) +static inline int find_free_region(void) { int irqreg; @@ -383,13 +381,13 @@ struct irq_region *region; int index; - index = alloc_irqregion(); + index = find_free_region(); if((IRQ_REGION(count-1))) return NULL; - + if (count < IRQ_PER_REGION) { - DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", + DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", IRQ_PER_REGION, name, count); count = IRQ_PER_REGION; } @@ -397,7 +395,7 @@ if(flags & IRQ_REG_MASK) if(!(ops->mask_irq && ops->unmask_irq)) return NULL; - + if(flags & IRQ_REG_DIS) if(!(ops->disable_irq && ops->enable_irq)) return NULL; @@ -426,14 +424,14 @@ return irq_region[index]; } - - + + /* FIXME: SMP, flags, bottom halves, rest */ -int request_irq(unsigned int irq, +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, + unsigned long irqflags, const char * devname, void *dev_id) { @@ -442,6 +440,7 @@ #if 0 printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id); #endif + if(!handler) { printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n", irq); @@ -459,16 +458,28 @@ return -EINVAL; } - action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]; + /* + ** We don't allow request_irq()/free_irq() called from an + ** interrupt context. We aren't aware of a need for it at + ** the moment. If that changes, replace all usage of irq_lock + ** with *irqsave locking variants. + ** - ggg + */ + if (in_interrupt()) BUG(); + spin_lock(&irq_lock); + action = &(irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]); + + /* First one is preallocated. */ if(action->handler) { + /* But it's in use...find the tail and allocate a new one */ while(action->next) action = action->next; - action->next = kmalloc(sizeof *action, GFP_ATOMIC); + action->next = kmalloc(sizeof(*action), GFP_ATOMIC); action = action->next; - } + } if(!action) { printk(KERN_ERR "request_irq():Augh! No action!\n") ; @@ -481,6 +492,7 @@ action->name = devname; action->next = NULL; action->dev_id = dev_id; + spin_unlock(&irq_lock); enable_irq(irq); return 0; @@ -490,6 +502,10 @@ { struct irqaction *action, **p; + /* See comments in request_irq() about interrupt context */ + if (in_interrupt()) BUG(); + + spin_lock(&irq_lock); action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]; if(action->dev_id == dev_id) { @@ -498,6 +514,7 @@ else memcpy(action, action->next, sizeof *action); + spin_unlock(&irq_lock); return; } @@ -512,9 +529,11 @@ *p = action->next; kfree(action); + spin_unlock(&irq_lock); return; } + spin_unlock(&irq_lock); printk(KERN_ERR "Trying to free free IRQ%d\n",irq); } @@ -528,11 +547,16 @@ return 0; } - void __init init_IRQ(void) { + local_irq_disable(); /* PARANOID - should already be disabled */ + set_eiem(-1L); /* enable all EIR bits */ + mtctl(-1L, 23); /* EIRR : clear all pending interrupts */ } +#ifdef CONFIG_PROC_FS +/* called from kernel/sysctl.c:sysctl_init() */ void init_irq_proc(void) { } +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/irq_smp.c linux.ac/arch/parisc/kernel/irq_smp.c --- linux.vanilla/arch/parisc/kernel/irq_smp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/irq_smp.c Tue Apr 3 17:54:34 2001 @@ -0,0 +1,233 @@ +/* + * linux/arch/parisc/kernel/irq_smp.c + * (90% stolen from alpha port, 9% from ia64, rest is mine -ggg) + * + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 Grant Grundler + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +int global_irq_holder = NO_PROC_ID; /* Who has global_irq_lock. */ +spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; /* protects IRQ's. */ +atomic_t global_irq_count; /* global count of IRQ active */ + + +/* Global IRQ locking depth. */ +static void *previous_irqholder = NULL; + +#define MAXCOUNT 100000000 + + +static void +show(char * str, void *where) +{ + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d: %p\n", str, cpu, where); + printk("irq: %d [%d %d]\n", + irqs_running(), + local_irq_count(0), + local_irq_count(1)); + + printk("bh: %d [%d %d]\n", + spin_is_locked(&global_bh_lock) ? 1 : 0, + local_bh_count(0), + local_bh_count(1)); +} + +static inline void +wait_on_irq(int cpu, void *where) +{ + int count = MAXCOUNT; + + for (;;) { + + /* + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. + */ + if (!irqs_running()) { + if (local_bh_count(cpu) + || !spin_is_locked(&global_bh_lock)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + spin_unlock(&global_irq_lock); + + for (;;) { + if (!--count) { + show("wait_on_irq", where); + count = MAXCOUNT; + } + __sti(); + udelay(1); /* make sure to run pending irqs */ + __cli(); + + if (irqs_running()) + continue; + if (spin_is_locked(&global_irq_lock)) + continue; + if (!local_bh_count(cpu) + && spin_is_locked(&global_bh_lock)) + continue; + if (spin_trylock(&global_irq_lock)) + break; + } + } +} + +static inline void +get_irqlock(int cpu, void* where) +{ + if (!spin_trylock(&global_irq_lock)) { + /* Do we already hold the lock? */ + if (cpu == global_irq_holder) + return; + /* Uhhuh.. Somebody else got it. Wait. */ + spin_lock(&global_irq_lock); + } + + /* + * Ok, we got the lock bit. + * But that's actually just the easy part.. Now + * we need to make sure that nobody else is running + * in an interrupt context. + */ + wait_on_irq(cpu, where); + + /* + * Finally. + */ +#if DEBUG_SPINLOCK + global_irq_lock.task = current; + global_irq_lock.previous = where; +#endif + global_irq_holder = cpu; + previous_irqholder = where; +} + + +/* +** A global "cli()" while in an interrupt context +** turns into just a local cli(). Interrupts +** should use spinlocks for the (very unlikely) +** case that they ever want to protect against +** each other. +** +** If we already have local interrupts disabled, +** this will not turn a local disable into a +** global one (problems with spinlocks: this makes +** save_flags+cli+sti usable inside a spinlock). +*/ +void +__global_cli(void) +{ + if (in_interrupt()) + { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count(cpu)) + { + void *where = __builtin_return_address(0); + get_irqlock(cpu, where); + } + } +} + +void +__global_sti(void) +{ + int cpu = smp_processor_id(); + + if (!local_irq_count(cpu)) + release_irqlock(cpu); + __sti(); +} + +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ +unsigned long +__global_save_flags(void) +{ + int retval; + int local_enabled; + unsigned long flags; + int cpu = smp_processor_id(); + + __save_flags(flags); + local_enabled = (!(flags & 7)); + /* default to local */ + retval = 2 + local_enabled; + + /* Check for global flags if we're not in an interrupt. */ + if (!local_irq_count(cpu)) { + if (local_enabled) + retval = 1; + if (global_irq_holder == cpu) + retval = 0; + } + return retval; +} + +void +__global_restore_flags(unsigned long flags) +{ + switch (flags) { + case 0: + __global_cli(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + printk(KERN_ERR "global_restore_flags: %08lx (%p)\n", + flags, __builtin_return_address(0)); + } +} + +/* + * From its use, I infer that synchronize_irq() stalls a thread until + * the effects of a command to an external device are known to have + * taken hold. Typically, the command is to stop sending interrupts. + * The strategy here is wait until there is at most one processor + * (this one) in an irq. The memory barrier serializes the write to + * the device and the subsequent accesses of global_irq_count. + * --jmartin + */ +#define DEBUG_SYNCHRONIZE_IRQ 0 + +void +synchronize_irq(void) +{ + /* Jay's version. */ + if (irqs_running()) { + cli(); + sti(); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/lasimap.map linux.ac/arch/parisc/kernel/lasimap.map --- linux.vanilla/arch/parisc/kernel/lasimap.map Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/lasimap.map Thu Jan 1 01:00:00 1970 @@ -1,322 +0,0 @@ -# HP 712 kernel keymap. This uses 7 modifier combinations. - -keymaps 0-2,4-5,8,12 -# ie, plain, Shift, AltGr, Control, Control+Shift, Alt and Control+Alt - - -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 83 = Boot -# altgr control keycode 111 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 100 = Alt -# -keycode 1 = F9 F19 Console_21 - control keycode 1 = F9 - alt keycode 1 = Console_9 - control alt keycode 1 = Console_9 -keycode 2 = -keycode 3 = F5 F15 Console_17 - control keycode 3 = F5 - alt keycode 3 = Console_5 - control alt keycode 3 = Console_5 -keycode 4 = F3 F13 Console_15 - control keycode 4 = F3 - alt keycode 4 = Console_3 - control alt keycode 4 = Console_3 -keycode 5 = F1 F11 Console_13 - control keycode 5 = F1 - alt keycode 5 = Console_1 - control alt keycode 5 = Console_1 -keycode 6 = F2 F12 Console_14 - control keycode 6 = F2 - alt keycode 6 = Console_2 - control alt keycode 6 = Console_2 -keycode 7 = F12 F12 Console_24 - control keycode 7 = F12 - alt keycode 7 = Console_12 - control alt keycode 7 = Console_12 -keycode 8 = -keycode 9 = F10 F20 Console_22 - control keycode 9 = F10 - alt keycode 9 = Console_10 - control alt keycode 9 = Console_10 -keycode 10 = F8 F18 Console_20 - control keycode 10 = F8 - alt keycode 10 = Console_8 - control alt keycode 10 = Console_8 -keycode 11 = F6 F16 Console_18 - control keycode 11 = F6 - alt keycode 11 = Console_6 - control alt keycode 11 = Console_6 -keycode 12 = F4 F14 Console_16 - control keycode 12 = F4 - alt keycode 12 = Console_4 - control alt keycode 12 = Console_4 -keycode 13 = Tab Tab - alt keycode 13 = Meta_Tab -keycode 14 = grave asciitilde - control keycode 14 = nul - alt keycode 14 = Meta_grave -keycode 15 = -keycode 16 = -keycode 17 = Alt -keycode 18 = Shift -keycode 19 = -keycode 20 = Control -keycode 21 = q -keycode 22 = one exclam exclam -keycode 23 = -keycode 24 = -keycode 25 = -keycode 26 = z -keycode 27 = s -keycode 28 = a - altgr keycode 28 = Hex_A -keycode 29 = w -keycode 30 = two at at -keycode 31 = -keycode 32 = -keycode 33 = c - altgr keycode 46 = Hex_C -keycode 34 = x -keycode 35 = d - altgr keycode 35 = Hex_D -keycode 36 = e - altgr keycode 36 = Hex_E -keycode 37 = four dollar -keycode 38 = three numbersign -keycode 39 = -keycode 40 = -keycode 41 = -keycode 42 = v -keycode 43 = f - altgr keycode 43 = Hex_F -keycode 44 = t -keycode 45 = r -keycode 46 = five percent -keycode 47 = -keycode 48 = -keycode 49 = n -keycode 50 = b - altgr keycode 50 = Hex_B -keycode 51 = h -keycode 52 = g -keycode 53 = y -keycode 54 = six asciicircum -keycode 55 = -keycode 56 = -keycode 57 = -keycode 58 = m -keycode 59 = j -keycode 60 = u -keycode 61 = seven ampersand -keycode 62 = eight asterisk asterisk -keycode 63 = -keycode 64 = -keycode 65 = comma less - alt keycode 65 = Meta_comma -keycode 66 = k -keycode 67 = i -keycode 68 = o -keycode 69 = zero parenright bracketright -keycode 70 = nine parenleft bracketleft -keycode 71 = -keycode 72 = -keycode 73 = period greater - control keycode 73 = Compose - alt keycode 73 = Meta_period -keycode 74 = slash question - control keycode 74 = Delete - alt keycode 53 = Meta_slash -keycode 75 = l -keycode 76 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 77 = p -keycode 78 = minus underscore -keycode 79 = -keycode 80 = -keycode 81 = -keycode 82 = apostrophe quotedbl - control keycode 82 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 83 = -keycode 84 = bracketleft braceleft - control keycode 84 = Escape - alt keycode 26 = Meta_bracketleft -keycode 85 = equal plus -keycode 86 = -keycode 87 = -keycode 88 = Caps_Lock -keycode 88 = -keycode 89 = -keycode 89 = -keycode 89 = -keycode 90 = Return - alt keycode 90 = Meta_Control_m -keycode 91 = bracketright braceright asciitilde - control keycode 91 = Control_bracketright - alt keycode 91 = Meta_bracketright -keycode 92 = -keycode 93 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 94 = -keycode 95 = -keycode 96 = -keycode 97 = -keycode 98 = -keycode 99 = -keycode 100 = -keycode 101 = -keycode 102 = BackSpace -keycode 103 = -keycode 104 = -keycode 105 = KP_1 - alt keycode 105 = Ascii_1 - altgr keycode 105 = Hex_1 -keycode 106 = -keycode 107 = KP_4 - alt keycode 107 = Ascii_4 - altgr keycode 107 = Hex_4 -keycode 108 = KP_7 - alt keycode 108 = Ascii_7 - altgr keycode 108 = Hex_7 -keycode 109 = -keycode 110 = -keycode 111 = -keycode 112 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 113 = KP_Period -keycode 114 = KP_2 - alt keycode 114 = Ascii_2 - altgr keycode 114 = Hex_2 -keycode 115 = KP_5 - alt keycode 115 = Ascii_5 - altgr keycode 115 = Hex_5 -keycode 116 = KP_6 - alt keycode 116 = Ascii_6 - altgr keycode 116 = Hex_6 -keycode 117 = KP_8 - alt keycode 117 = Ascii_8 - altgr keycode 117 = Hex_8 -keycode 118 = Escape -keycode 119 = -keycode 120 = F11 -keycode 121 = KP_Add -keycode 122 = KP_3 - alt keycode 122 = Ascii_3 - altgr keycode 122 = Hex_3 -keycode 123 = KP_Subtract -keycode 124 = KP_Multiply -keycode 125 = KP_9 - alt keycode 125 = Ascii_9 - altgr keycode 125 = Hex_9 -keycode 126 = -# 131!! -keycode 127 = F7 F17 Console_19 - control keycode 127 = F7 - alt keycode 127 = Console_7 - control alt keycode 127 = Console_7 - -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'Ŕ' -compose '`' 'a' to 'ŕ' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ă' -compose '~' 'a' to 'ă' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Ĺ' -compose 'o' 'a' to 'ĺ' -compose '0' 'A' to 'Ĺ' -compose '0' 'a' to 'ĺ' -compose 'A' 'A' to 'Ĺ' -compose 'a' 'a' to 'ĺ' -compose 'A' 'E' to 'Ć' -compose 'a' 'e' to 'ć' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'Č' -compose '`' 'e' to 'č' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ę' -compose '^' 'e' to 'ę' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ě' -compose '`' 'i' to 'ě' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ď' -compose '"' 'i' to 'ď' -compose '-' 'D' to 'Đ' -compose '-' 'd' to 'đ' -compose '~' 'N' to 'Ń' -compose '~' 'n' to 'ń' -compose '`' 'O' to 'Ň' -compose '`' 'o' to 'ň' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Ő' -compose '~' 'o' to 'ő' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ř' -compose '/' 'o' to 'ř' -compose '`' 'U' to 'Ů' -compose '`' 'u' to 'ů' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Ű' -compose '^' 'u' to 'ű' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Ţ' -compose 't' 'h' to 'ţ' -compose 's' 's' to 'ß' -compose '"' 'y' to '˙' -compose 's' 'z' to 'ß' -compose 'i' 'j' to '˙' diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/led.c linux.ac/arch/parisc/kernel/led.c --- linux.vanilla/arch/parisc/kernel/led.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/led.c Tue Apr 3 17:54:34 2001 @@ -9,15 +9,25 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * TODO: + * - stop all LED activity at kernel shutdown/halt (add to notifier chain) + * - LCD functionality is completely untested (lack of hardware :-() + * - add procfs entry to (maybe partially) enable & disable LEDs + * - speed-up calculations with inlined assembler + * - modularization */ -#include +#define DEBUG 1 /* undefine for production */ + #include #include #include #include #include #include +#include +#include +#include #include #include #include @@ -25,12 +35,17 @@ #include /* HZ */ #include - -/* define to disable all LED functions */ -#undef DISABLE_LEDS +/* The control of the LEDs and LCDs on PARISC-machines have to be done + completely in software. The necessary calculations are done during every + interrupt and since the calculations may consume relatively much CPU-time + some of the calculations can be turned off with the following defines */ +#undef NO_HEARTBEAT +#undef NO_DISKIO +#undef NO_LAN_RXTX -#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF) +#define CALC_ADD(val, comp, add) \ + (val<=(comp/8) ? add/16 : val<=(comp/4) ? add/8 : val<=(comp/2) ? add/4 : add) struct lcd_block { @@ -40,8 +55,10 @@ }; /* Structure returned by PDC_RETURN_CHASSIS_INFO */ +/* NOTE: we use unsigned long:16 two times, since the following member + lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */ struct pdc_chassis_lcd_info_ret_block { - unsigned long model:16; /* DISPLAY_MODEL_XXXX (see below) */ + unsigned long model:16; /* DISPLAY_MODEL_XXXX */ unsigned long lcd_width:16; /* width of the LCD in chars (DISPLAY_MODEL_LCD only) */ char *lcd_cmd_reg_addr; /* ptr to LCD cmd-register & data ptr for LED */ char *lcd_data_reg_addr; /* ptr to LCD data-register (LCD only) */ @@ -56,20 +73,10 @@ char _pad; }; -/* values for pdc_chassis_lcd_info_ret_block.model: */ -#define DISPLAY_MODEL_LCD 0 /* KittyHawk LED or LCD */ -#define DISPLAY_MODEL_NONE 1 /* no LED or LCD */ -#define DISPLAY_MODEL_LASI 2 /* LASI style 8 bit LED */ -#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */ - /* LCD_CMD and LCD_DATA for KittyHawk machines */ -#ifdef __LP64__ -#define KITTYHAWK_LCD_CMD 0xfffffffff0190000L -#else -#define KITTYHAWK_LCD_CMD 0xf0190000 -#endif -#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1) +#define KITTYHAWK_LCD_CMD (0xfffffffff0190000UL) /* 64bit-ready */ +#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1) /* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's */ @@ -92,6 +99,8 @@ #define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */ +/* ptr to LCD/LED-specific function */ +static void (*led_func_ptr) (unsigned char); /* @@ -141,7 +150,6 @@ ** TODO: check the value of "min_cmd_delay" against the value of HZ. ** */ - static void led_LCD_driver(unsigned char leds) { static int last_index; /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */ @@ -178,179 +186,239 @@ } /* now update the vars for the next interrupt iteration */ - if (++last_was_cmd == 2) { + if (++last_was_cmd == 2) { /* switch between cmd & data */ last_was_cmd = 0; - if (++last_index == 4) - last_index = 0; + if (++last_index == 4) + last_index = 0; /* switch back to heartbeat index */ + } +} + + +/* + ** + ** led_get_net_stats() + ** + ** calculate the TX- & RX-troughput on the network interfaces in + ** the system for usage in the LED code + ** + */ +#ifndef NO_LAN_RXTX +static unsigned long led_net_rx_counter, led_net_tx_counter; + +static void led_get_net_stats(int addvalue) +{ + static unsigned long rx_total_last, tx_total_last; + unsigned long rx_total, tx_total; + struct net_device *dev; + struct net_device_stats *stats; + + rx_total = tx_total = 0; + + /* are we really allowed to lock dev during the interrupt this way ? */ + read_lock(&dev_base_lock); + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev->get_stats) { /* && dev->if_port!=IF_PORT_UNKNOWN */ + stats = dev->get_stats(dev); + rx_total += stats->rx_packets; + tx_total += stats->tx_packets; + } } + read_unlock(&dev_base_lock); + + rx_total -= rx_total_last; + tx_total -= tx_total_last; + + if (rx_total) + led_net_rx_counter += CALC_ADD(rx_total, tx_total, addvalue); + + if (tx_total) + led_net_tx_counter += CALC_ADD(tx_total, rx_total, addvalue); + + rx_total_last += rx_total; + tx_total_last += tx_total; } +#endif /* NO_LAN_RXTX */ + +/* + ** + ** led_get_diskio_stats() + ** + ** calculate the disk-io througput in the system + ** (analog to linux/fs/proc/proc_misc.c) + ** + */ +#ifndef NO_DISKIO +static unsigned long led_diskio_counter; +static void led_get_diskio_stats(int addvalue) +{ + static unsigned int diskio_total_last, diskio_max; + int major, disk, total; + + total = 0; + for (major = 0; major < DK_MAX_MAJOR; major++) { + for (disk = 0; disk < DK_MAX_DISK; disk++) + total += kstat.dk_drive[major][disk]; + } + total -= diskio_total_last; + + if (total) { + if (total >= diskio_max) { + led_diskio_counter += addvalue; + diskio_max = total; /* new maximum value found */ + } else + led_diskio_counter += CALC_ADD(total, diskio_max, addvalue); + } + + diskio_total_last += total; +} +#endif /* NO_DISKIO */ -static char currentleds; /* stores current value of the LEDs */ -static void (*led_func_ptr) (unsigned char); /* ptr to LCD/LED-specific function */ /* ** led_interrupt_func() ** ** is called at every timer interrupt from time.c, ** updates the chassis LCD/LED + + TODO: + - display load average (older machines like 715/64 have 4 "free" LED's for that!) + - optimizations (we are still in an interrupt-function !!!) + */ -#define HEARTBEAT_LEN (HZ/16) +static unsigned char currentleds; /* stores current value of the LEDs */ + +#define HEARTBEAT_LEN (HZ*6/100) +#define HEARTBEAT_2ND_RANGE_START (HZ*22/100) +#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN) void led_interrupt_func(void) { -#ifndef DISABLE_LEDS - static int count; - static int lastleds = -1; - static int nr; + static unsigned int count, count_HZ; + static unsigned char lastleds; /* exit, if not initialized */ if (!led_func_ptr) return; - /* increment the local counter */ - if (count == (HZ-1)) - count = 0; - else - count++; - - /* calculate the Heartbeat */ - if ((count % (HZ/2)) < HEARTBEAT_LEN) + /* increment the local counters */ + ++count; + if (++count_HZ == HZ) + count_HZ = 0; + +#ifndef NO_HEARTBEAT + /* flash heartbeat-LED like a real heart (2 x short then a long delay) */ + if (count_HZ=HEARTBEAT_2ND_RANGE_START && count_HZ= 2) - nr = 0; - currentleds &= ~7; - currentleds |= (1 << nr); + /* gather network and diskio statistics and flash LEDs respectively */ + +#ifndef NO_LAN_RXTX + if ((count & 31) == 0) + led_get_net_stats(30); + + if (led_net_rx_counter) { + led_net_rx_counter--; + currentleds |= LED_LAN_RCV; + } + else + currentleds &= ~LED_LAN_RCV; + + if (led_net_tx_counter) { + led_net_tx_counter--; + currentleds |= LED_LAN_TX; } + else + currentleds &= ~LED_LAN_TX; +#endif + +#ifndef NO_DISKIO + /* avoid to calculate diskio-stats at same irq as netio-stats ! */ + if ((count & 31) == 15) + led_get_diskio_stats(30); + + if (led_diskio_counter) { + led_diskio_counter--; + currentleds |= LED_DISK_IO; + } + else + currentleds &= ~LED_DISK_IO; +#endif - /* now update the LEDs */ + /* update the LCD/LEDs */ if (currentleds != lastleds) { led_func_ptr(currentleds); lastleds = currentleds; } -#endif } /* ** register_led_driver() ** - ** All information in lcd_info needs to be set up prior - ** calling this function. + ** registers an external LED or LCD for usage by this driver. + ** currently only LCD-, LASI- and ASP-style LCD/LED's are supported. + ** */ -static void __init register_led_driver(void) +int __init register_led_driver( int model, char *cmd_reg, char *data_reg ) { -#ifndef DISABLE_LEDS + static int initialized; + + if (initialized || !data_reg) + return 1; + + lcd_info.model = model; /* store the values */ + LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? NULL : cmd_reg; + switch (lcd_info.model) { case DISPLAY_MODEL_LCD: - printk(KERN_INFO "LCD display at (%p,%p)\n", - LCD_CMD_REG , LCD_DATA_REG); + LCD_DATA_REG = data_reg; led_func_ptr = led_LCD_driver; + printk(KERN_INFO "LCD display at %p,%p registered\n", + LCD_CMD_REG , LCD_DATA_REG); + lcd_print( "Linux " UTS_RELEASE ); break; case DISPLAY_MODEL_LASI: - printk(KERN_INFO "LED display at %p\n", - LED_DATA_REG); + LED_DATA_REG = data_reg; led_func_ptr = led_LASI_driver; + printk(KERN_INFO "LED display at %p registered\n", LED_DATA_REG); break; case DISPLAY_MODEL_OLD_ASP: - printk(KERN_INFO "LED (ASP-style) display at %p\n", - LED_DATA_REG); + LED_DATA_REG = data_reg; led_func_ptr = led_ASP_driver; + printk(KERN_INFO "LED (ASP-style) display at %p registered\n", + LED_DATA_REG); break; default: printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n", __FUNCTION__, lcd_info.model); - return; + return 1; } -#endif -} - -/* - * XXX - could this move to lasi.c ?? - */ - -/* - ** lasi_led_init() - ** - ** lasi_led_init() is called from lasi.c with the base hpa - ** of the lasi controller chip. - ** Since Mirage and Electra machines use a different LED - ** address register, we need to check for these machines - ** explicitly. - */ - -#ifdef CONFIG_GSC_LASI -void __init lasi_led_init(unsigned long lasi_hpa) -{ - if (lcd_info.model != DISPLAY_MODEL_NONE || - lasi_hpa == 0) - return; - - printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); - - /* Mirage and Electra machines need special offsets */ - switch (CPU_HVERSION) { - case 0x60A: /* Mirage Jr (715/64) */ - case 0x60B: /* Mirage 100 */ - case 0x60C: /* Mirage 100+ */ - case 0x60D: /* Electra 100 */ - case 0x60E: /* Electra 120 */ - LED_DATA_REG = (char *) (lasi_hpa - 0x00020000); - break; - default: - LED_DATA_REG = (char *) (lasi_hpa + 0x0000C000); - break; - } /* switch() */ - - lcd_info.model = DISPLAY_MODEL_LASI; - register_led_driver(); -} -#endif - - -/* - ** asp_led_init() - ** - ** asp_led_init() is called from asp.c with the ptr - ** to the LED display. - */ - -#ifdef CONFIG_GSC_LASI -void __init asp_led_init(unsigned long led_ptr) -{ - if (lcd_info.model != DISPLAY_MODEL_NONE || - led_ptr == 0) - return; - - lcd_info.model = DISPLAY_MODEL_OLD_ASP; - LED_DATA_REG = (char *) led_ptr; - - register_led_driver(); + + initialized++; /* mark the LCD/LED driver now as initialized */ + + return 0; } -#endif - - - /* ** register_led_regions() ** - ** Simple function, which registers the LCD/LED regions for /procfs. + ** register_led_regions() registers the LCD/LED regions for /procfs. ** At bootup - where the initialisation of the LCD/LED normally happens - ** not all internal structures of request_region() are properly set up, - ** so that we delay the registration until busdevice.c is executed. + ** so that we delay the led-registration until after busdevices_init() + ** has been executed. ** */ @@ -369,6 +437,42 @@ } +/* + ** + ** lcd_print() + ** + ** Displays the given string on the LCD-Display of newer machines + ** + ** TODO: + ** + ** - _NEVER_ execute at the same time as led_LCD_driver() !!!! + ** - + */ +int lcd_print( char *str ) +{ + int i; + + if (lcd_info.model != DISPLAY_MODEL_LCD || !led_func_ptr) + return 0; + + /* Set LCD Cursor to 1st character */ + gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG); + udelay(lcd_info.min_cmd_delay); + + /* Print the string */ + for (i=0; i < lcd_info.lcd_width; i++) { + if (str && *str) + gsc_writeb(*str++, LCD_DATA_REG); + else + gsc_writeb(' ', LCD_DATA_REG); + udelay(lcd_info.min_cmd_delay); + } + + return lcd_info.lcd_width; +} + + + /* ** led_init() @@ -384,11 +488,8 @@ int __init led_init(void) { -#ifndef DISABLE_LEDS long pdc_result[32]; - printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); - /* Work around the buggy PDC of KittyHawk-machines */ switch (CPU_HVERSION) { case 0x580: /* KittyHawk DC2-100 (K100) */ @@ -396,7 +497,8 @@ case 0x582: /* KittyHawk DC3 100 (K400) */ case 0x583: /* KittyHawk DC3 120 (K410) */ case 0x58B: /* KittyHawk DC2 100 (K200) */ - printk("%s: KittyHawk-Machine found !!\n", __FUNCTION__); + printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, " + "LED detection skipped.\n", __FILE__, CPU_HVERSION); goto found; /* use the preinitialized values of lcd_info */ default: @@ -407,19 +509,25 @@ pdc_result[0] = pdc_result[1] = 0; if (pdc_chassis_info(&pdc_result, &lcd_info, sizeof(lcd_info)) == PDC_OK) { - printk("%s: chassis info: model %d, ret0=%d, ret1=%d\n", - __FUNCTION__, lcd_info.model, pdc_result[0], pdc_result[1]); + pr_debug("%s: chassis info: model=%d (%s), " + "lcd_width=%d, cmd_delay=%u, ret0=%ld, ret1=%ld\n", + __FUNCTION__, + lcd_info.model, + (lcd_info.model==DISPLAY_MODEL_LCD) ? "LCD" : + (lcd_info.model==DISPLAY_MODEL_LASI) ? "LED" : "unknown", + lcd_info.lcd_width, lcd_info.min_cmd_delay, + pdc_result[0], pdc_result[1]); /* check the results. Some machines have a buggy PDC */ if (pdc_result[0] <= 0 || pdc_result[0] != pdc_result[1]) goto not_found; switch (lcd_info.model) { - case DISPLAY_MODEL_LCD: /* LCD display */ + case DISPLAY_MODEL_LCD: /* LCD display */ if (pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) && pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - 1) goto not_found; - printk("%s: min_cmd_delay = %d uS\n", + pr_debug("%s: min_cmd_delay = %d uS\n", __FUNCTION__, lcd_info.min_cmd_delay); break; @@ -435,17 +543,16 @@ printk(KERN_WARNING "Unknown LCD/LED model %d\n", lcd_info.model); goto not_found; - } /* switch() */ + } /* switch() */ found: /* register the LCD/LED driver */ - register_led_driver(); + register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG); return 0; - } /* if() */ + } /* if() */ not_found: lcd_info.model = DISPLAY_MODEL_NONE; return 1; -#endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pacache.S linux.ac/arch/parisc/kernel/pacache.S --- linux.vanilla/arch/parisc/kernel/pacache.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/pacache.S Tue Apr 3 17:54:34 2001 @@ -0,0 +1,799 @@ +/* + * Parisc tlb and cache flushing support + * Copyright (C) 2000 Hewlett-Packard (John Marvin) + * + * 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, 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. + */ + +/* + * NOTE: fdc,fic, and pdc instructions that use base register modification + * should only use index and base registers that are not shadowed, + * so that the fast path emulation in the non access miss handler + * can be used. + */ + +#ifdef __LP64__ +#define ADDIB addib,* +#define ADDIBEQ addib,*= /* silly gnu cpp doesn't concatenate * and = */ +#define CMPB cmpb,* +#define ANDCM andcm,* + + .level 2.0w +#else +#define ADDIB addib, +#define ADDIBEQ addib,= /* silly gnu cpp doesn't concatenate * and = */ +#define CMPB cmpb, +#define ANDCM andcm + + .level 2.0 +#endif + +#include +#include +#include +#include + + .text + .align 128 + + .export __flush_tlb_all,code + +__flush_tlb_all: + .proc + .callinfo NO_CALLS + .entry + + /* + * The pitlbe and pdtlbe instructions should only be used to + * flush the entire tlb. Also, there needs to be no intervening + * tlb operations, e.g. tlb misses, so the operation needs + * to happen in real mode with all interruptions disabled. + */ + + /* + * Once again, we do the rfi dance ... some day we need examine + * all of our uses of this type of code and see what can be + * consolidated. + */ + + ssm 0,%r0 /* relied upon translation! */ + nop + nop + nop + nop + nop + nop + nop + + mtsm %r0 /* disable interruptions */ + ldil L%REAL_MODE_PSW, %r1 + ldo R%REAL_MODE_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%PA(1f),%r1 + ldo R%PA(1f)(%r1),%r1 + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +1: ldil L%PA(cache_info),%r1 + ldo R%PA(cache_info)(%r1),%r1 + + /* Flush Instruction Tlb */ + + LDREG ITLB_SID_BASE(%r1),%r20 + LDREG ITLB_SID_STRIDE(%r1),%r21 + LDREG ITLB_SID_COUNT(%r1),%r22 + LDREG ITLB_OFF_BASE(%r1),%arg0 + LDREG ITLB_OFF_STRIDE(%r1),%arg1 + LDREG ITLB_OFF_COUNT(%r1),%arg2 + LDREG ITLB_LOOP(%r1),%arg3 + + ADDIBEQ -1,%arg3,fitoneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fitdone /* If loop < 0, skip */ + copy %arg0,%r28 /* Init base addr */ + +fitmanyloop: /* Loop if LOOP >= 2 */ + mtsp %r20,%sr1 + add %r21,%r20,%r20 /* increment space */ + copy %arg2,%r29 /* Init middle loop count */ + +fitmanymiddle: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fitmanymiddle /* Adjusted inner loop decr */ + pitlbe 0(%sr1,%r28) + pitlbe,m %arg1(%sr1,%r28) /* Last pitlbe and addr adjust */ + ADDIB> -1,%r29,fitmanymiddle /* Middle loop decr */ + copy %arg3,%r31 /* Re-init inner loop count */ + + movb,tr %arg0,%r28,fitmanyloop /* Re-init base addr */ + ADDIB<=,n -1,%r22,fitdone /* Outer loop count decr */ + +fitoneloop: /* Loop if LOOP = 1 */ + mtsp %r20,%sr1 + copy %arg0,%r28 /* init base addr */ + copy %arg2,%r29 /* init middle loop count */ + +fitonemiddle: /* Loop if LOOP = 1 */ + ADDIB> -1,%r29,fitonemiddle /* Middle loop count decr */ + pitlbe,m %arg1(%sr1,%r28) /* pitlbe for one loop */ + + ADDIB> -1,%r22,fitoneloop /* Outer loop count decr */ + add %r21,%r20,%r20 /* increment space */ + +fitdone: + + /* Flush Data Tlb */ + + LDREG DTLB_SID_BASE(%r1),%r20 + LDREG DTLB_SID_STRIDE(%r1),%r21 + LDREG DTLB_SID_COUNT(%r1),%r22 + LDREG DTLB_OFF_BASE(%r1),%arg0 + LDREG DTLB_OFF_STRIDE(%r1),%arg1 + LDREG DTLB_OFF_COUNT(%r1),%arg2 + LDREG DTLB_LOOP(%r1),%arg3 + + ADDIBEQ -1,%arg3,fdtoneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fdtdone /* If loop < 0, skip */ + copy %arg0,%r28 /* Init base addr */ + +fdtmanyloop: /* Loop if LOOP >= 2 */ + mtsp %r20,%sr1 + add %r21,%r20,%r20 /* increment space */ + copy %arg2,%r29 /* Init middle loop count */ + +fdtmanymiddle: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fdtmanymiddle /* Adjusted inner loop decr */ + pdtlbe 0(%sr1,%r28) + pdtlbe,m %arg1(%sr1,%r28) /* Last pdtlbe and addr adjust */ + ADDIB> -1,%r29,fdtmanymiddle /* Middle loop decr */ + copy %arg3,%r31 /* Re-init inner loop count */ + + movb,tr %arg0,%r28,fdtmanyloop /* Re-init base addr */ + ADDIB<=,n -1,%r22,fdtdone /* Outer loop count decr */ + +fdtoneloop: /* Loop if LOOP = 1 */ + mtsp %r20,%sr1 + copy %arg0,%r28 /* init base addr */ + copy %arg2,%r29 /* init middle loop count */ + +fdtonemiddle: /* Loop if LOOP = 1 */ + ADDIB> -1,%r29,fdtonemiddle /* Middle loop count decr */ + pdtlbe,m %arg1(%sr1,%r28) /* pdtlbe for one loop */ + + ADDIB> -1,%r22,fdtoneloop /* Outer loop count decr */ + add %r21,%r20,%r20 /* increment space */ + +fdtdone: + + /* Switch back to virtual mode */ + + mtsm 0 /* clear Q bit */ + ldil L%KERNEL_PSW, %r1 + ldo R%KERNEL_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%(2f), %r1 + ldo R%(2f)(%r1), %r1 + LDIL_FIXUP(%r1) + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +2: bv %r0(%r2) + nop + .exit + + .procend + + .export flush_instruction_cache,code + .import cache_info,data + +flush_instruction_cache: + .proc + .callinfo NO_CALLS + .entry + + mtsp %r0,%sr1 + ldil L%cache_info,%r1 + ldo R%cache_info(%r1),%r1 + LDIL_FIXUP(%r1) + + /* Flush Instruction Cache */ + + LDREG ICACHE_BASE(%r1),%arg0 + LDREG ICACHE_STRIDE(%r1),%arg1 + LDREG ICACHE_COUNT(%r1),%arg2 + LDREG ICACHE_LOOP(%r1),%arg3 + ADDIBEQ -1,%arg3,fioneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fisync /* If loop < 0, do sync */ + +fimanyloop: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fimanyloop /* Adjusted inner loop decr */ + fice 0(%sr1,%arg0) + fice,m %arg1(%sr1,%arg0) /* Last fice and addr adjust */ + movb,tr %arg3,%r31,fimanyloop /* Re-init inner loop count */ + ADDIB<=,n -1,%arg2,fisync /* Outer loop decr */ + +fioneloop: /* Loop if LOOP = 1 */ + ADDIB> -1,%arg2,fioneloop /* Outer loop count decr */ + fice,m %arg1(%sr1,%arg0) /* Fice for one loop */ + +fisync: + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_data_cache,code + .import cache_info,data + +flush_data_cache: + .proc + .callinfo NO_CALLS + .entry + + mtsp %r0,%sr1 + ldil L%cache_info,%r1 + ldo R%cache_info(%r1),%r1 + LDIL_FIXUP(%r1) + + /* Flush Data Cache */ + + LDREG DCACHE_BASE(%r1),%arg0 + LDREG DCACHE_STRIDE(%r1),%arg1 + LDREG DCACHE_COUNT(%r1),%arg2 + LDREG DCACHE_LOOP(%r1),%arg3 + ADDIBEQ -1,%arg3,fdoneloop /* Preadjust and test */ + movb,<,n %arg3,%r31,fdsync /* If loop < 0, do sync */ + +fdmanyloop: /* Loop if LOOP >= 2 */ + ADDIB> -1,%r31,fdmanyloop /* Adjusted inner loop decr */ + fdce 0(%sr1,%arg0) + fdce,m %arg1(%sr1,%arg0) /* Last fdce and addr adjust */ + movb,tr %arg3,%r31,fdmanyloop /* Re-init inner loop count */ + ADDIB<=,n -1,%arg2,fdsync /* Outer loop decr */ + +fdoneloop: /* Loop if LOOP = 1 */ + ADDIB> -1,%arg2,fdoneloop /* Outer loop count decr */ + fdce,m %arg1(%sr1,%arg0) /* Fdce for one loop */ + +fdsync: + syncdma + sync + bv %r0(%r2) + nop + .exit + + .procend + +#if (TMPALIAS_MAP_START != 0xff000000UL) +#warning TMPALIAS_MAP_START changed. If > 32 bit, code in pacache.S is bogus +#endif + +/* + * NOTE: Code in copy_user_page and clear_user_page have hard coded + * dependencies on the maximum alias boundary being 4 Mb. We've + * been assured by the parisc chip designers that there will not + * ever be a parisc chip with a larger alias boundary (Never say + * never :-) ). + * + * Subtle: the dtlb miss handlers support the temp alias region by + * "knowing" that if a dtlb miss happens within the temp alias + * region it must have occurred while in copy_user_page or + * clear_user_page. Since these routines make use of processor + * local translations, we don't want to insert them into the + * kernel page table. Instead, we load up some general registers + * (they need to be registers which aren't shadowed) + * with the physical page numbers (preshifted for tlb insertion) + * needed to insert the translations. When we miss on the + * translation, the dtlb miss handler inserts the translation + * into the tlb using these values: + * + * %r26 physical page (shifted for tlb insert) of "to" translation + * %r23 physical page (shifted for tlb insert) of "from" translation + */ + + .export copy_user_page_asm,code + +copy_user_page_asm: + .proc + .callinfo NO_CALLS + .entry + + tophys %r26 + tophys %r25 + copy %r25,%r23 /* move into non shadowed register */ + + ldil L%(TMPALIAS_MAP_START),%r28 + LDIL_FIXUP(%r28) +#ifdef __LP64__ + extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */ + extrd,u %r23,56,32,%r23 /* convert phys addr to tlb insert format */ + depd %r24,63,22,%r28 /* Form aliased virtual address 'to' */ + depdi 0,63,12,%r28 /* Clear any offset bits */ + copy %r28,%r29 + depdi 1,41,1,%r29 /* Form aliased virtual address 'from' */ +#else + extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */ + extrw,u %r23,24,25,%r23 /* convert phys addr to tlb insert format */ + depw %r24,31,22,%r28 /* Form aliased virtual address 'to' */ + depwi 0,31,12,%r28 /* Clear any offset bits */ + copy %r28,%r29 + depwi 1,9,1,%r29 /* Form aliased virtual address 'from' */ +#endif + + /* Purge any old translations */ + + pdtlb 0(%r28) + pdtlb 0(%r29) + + ldi 64,%r1 + + /* + * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw + * bundles (very restricted rules for bundling). It probably + * does OK on PCXU and better, but we could do better with + * ldd/std instructions. Note that until (if) we start saving + * the full 64 bit register values on interrupt, we can't + * use ldd/std on a 32 bit kernel. + */ + + +1: + ldw 0(%r29),%r19 + ldw 4(%r29),%r20 + ldw 8(%r29),%r21 + ldw 12(%r29),%r22 + stw %r19,0(%r28) + stw %r20,4(%r28) + stw %r21,8(%r28) + stw %r22,12(%r28) + ldw 16(%r29),%r19 + ldw 20(%r29),%r20 + ldw 24(%r29),%r21 + ldw 28(%r29),%r22 + stw %r19,16(%r28) + stw %r20,20(%r28) + stw %r21,24(%r28) + stw %r22,28(%r28) + ldw 32(%r29),%r19 + ldw 36(%r29),%r20 + ldw 40(%r29),%r21 + ldw 44(%r29),%r22 + stw %r19,32(%r28) + stw %r20,36(%r28) + stw %r21,40(%r28) + stw %r22,44(%r28) + ldw 48(%r29),%r19 + ldw 52(%r29),%r20 + ldw 56(%r29),%r21 + ldw 60(%r29),%r22 + stw %r19,48(%r28) + stw %r20,52(%r28) + stw %r21,56(%r28) + stw %r22,60(%r28) + ldo 64(%r28),%r28 + ADDIB> -1,%r1,1b + ldo 64(%r29),%r29 + + bv %r0(%r2) + nop + .exit + + .procend + + .export clear_user_page_asm,code + +clear_user_page_asm: + .proc + .callinfo NO_CALLS + .entry + + tophys %r26 + + ldil L%(TMPALIAS_MAP_START),%r28 + LDIL_FIXUP(%r28) +#ifdef __LP64__ + extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */ + depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */ + depdi 0,63,12,%r28 /* Clear any offset bits */ +#else + extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */ + depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */ + depwi 0,31,12,%r28 /* Clear any offset bits */ +#endif + + /* Purge any old translation */ + + pdtlb 0(%r28) + + ldi 64,%r1 + +1: + stw %r0,0(%r28) + stw %r0,4(%r28) + stw %r0,8(%r28) + stw %r0,12(%r28) + stw %r0,16(%r28) + stw %r0,20(%r28) + stw %r0,24(%r28) + stw %r0,28(%r28) + stw %r0,32(%r28) + stw %r0,36(%r28) + stw %r0,40(%r28) + stw %r0,44(%r28) + stw %r0,48(%r28) + stw %r0,52(%r28) + stw %r0,56(%r28) + stw %r0,60(%r28) + ADDIB> -1,%r1,1b + ldo 64(%r28),%r28 + + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_kernel_dcache_page + +flush_kernel_dcache_page: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + +#ifdef __LP64__ + depdi,z 1,63-PAGE_SHIFT,1,%r25 +#else + depwi,z 1,31-PAGE_SHIFT,1,%r25 +#endif + add %r26,%r25,%r25 + sub %r25,%r23,%r25 + + +1: fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + fdc,m %r23(%r26) + CMPB<< %r26,%r25,1b + fdc,m %r23(%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export purge_kernel_dcache_page + +purge_kernel_dcache_page: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + +#ifdef __LP64__ + depdi,z 1,63-PAGE_SHIFT,1,%r25 +#else + depwi,z 1,31-PAGE_SHIFT,1,%r25 +#endif + add %r26,%r25,%r25 + sub %r25,%r23,%r25 + +1: pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + pdc,m %r23(%r26) + CMPB<< %r26,%r25,1b + pdc,m %r23(%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + +#if 0 + /* Currently not used, but it still is a possible alternate + * solution. + */ + + .export flush_alias_page + +flush_alias_page: + .proc + .callinfo NO_CALLS + .entry + + tophys %r26 + + ldil L%(TMPALIAS_MAP_START),%r28 + LDIL_FIXUP(%r28) +#ifdef __LP64__ + extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */ + depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */ + depdi 0,63,12,%r28 /* Clear any offset bits */ +#else + extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */ + depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */ + depwi 0,31,12,%r28 /* Clear any offset bits */ +#endif + + /* Purge any old translation */ + + pdtlb 0(%r28) + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + +#ifdef __LP64__ + depdi,z 1,63-PAGE_SHIFT,1,%r29 +#else + depwi,z 1,31-PAGE_SHIFT,1,%r29 +#endif + add %r28,%r29,%r29 + sub %r29,%r23,%r29 + +1: fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + fdc,m %r23(%r28) + CMPB<< %r28,%r29,1b + fdc,m %r23(%r28) + + sync + bv %r0(%r2) + nop + .exit + + .procend +#endif + + .export flush_user_dcache_range_asm + +flush_user_dcache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fdc,m %r23(%sr3,%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_kernel_dcache_range_asm + +flush_kernel_dcache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%dcache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fdc,m %r23(%r26) + + sync + syncdma + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_user_icache_range_asm + +flush_user_icache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%icache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%icache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fic,m %r23(%sr3,%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export flush_kernel_icache_range_asm + +flush_kernel_icache_range_asm: + .proc + .callinfo NO_CALLS + .entry + + ldil L%icache_stride,%r1 + LDIL_FIXUP(%r1) + ldw R%icache_stride(%r1),%r23 + ldo -1(%r23),%r21 + ANDCM %r26,%r21,%r26 + +1: CMPB<<,n %r26,%r25,1b + fic,m %r23(%r26) + + sync + bv %r0(%r2) + nop + .exit + + .procend + + .export disable_sr_hashing_asm,code + +disable_sr_hashing_asm: + .proc + .callinfo NO_CALLS + .entry + + /* Switch to real mode */ + + ssm 0,%r0 /* relied upon translation! */ + nop + nop + nop + nop + nop + nop + nop + + mtsm %r0 /* disable interruptions */ + ldil L%REAL_MODE_PSW, %r1 + ldo R%REAL_MODE_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%PA(1f),%r1 + ldo R%PA(1f)(%r1),%r1 + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +1: cmpib,=,n SRHASH_PCXST,%r26,srdis_pcxs + cmpib,=,n SRHASH_PCXL,%r26,srdis_pcxl + cmpib,=,n SRHASH_PA20,%r26,srdis_pa20 + b,n srdis_done + +srdis_pcxs: + + /* Disable Space Register Hashing for PCXS,PCXT,PCXT' */ + + .word 0x14031a00 /* mfdiag %dr0,%r3 */ + .word 0x14031a00 /* must issue twice */ + depwi 0,18,1,%r3 /* Clear DHE (dcache hash enable) */ + depwi 0,20,1,%r3 /* Clear IHE (icache hash enable) */ + .word 0x14031600 /* mtdiag %r3,%dr0 */ + .word 0x14031600 /* must issue twice */ + b,n srdis_done + +srdis_pcxl: + + /* Disable Space Register Hashing for PCXL */ + + .word 0x14030600 /* mfdiag %dr0,%r3 */ + depwi 0,28,2,%r3 /* Clear DHASH_EN & IHASH_EN */ + .word 0x14030240 /* mtdiag %r3,%dr0 */ + b,n srdis_done + +srdis_pa20: + + /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */ + + .word 0x144008a3 /* mfdiag %dr2,%r3 */ + depdi 0,54,1,%r3 /* clear DIAG_SPHASH_ENAB (bit 54) */ + .word 0x14431840 /* mtdiag %r3,%dr2 */ + +srdis_done: + + /* Switch back to virtual mode */ + + mtsm 0 /* clear Q bit */ + ldil L%KERNEL_PSW, %r1 + ldo R%KERNEL_PSW(%r1), %r1 + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%(2f), %r1 + ldo R%(2f)(%r1), %r1 + LDIL_FIXUP(%r1) + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + rfi + nop + +2: bv %r0(%r2) + nop + .exit + + .procend + + .end diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/parisc_ksyms.c linux.ac/arch/parisc/kernel/parisc_ksyms.c --- linux.vanilla/arch/parisc/kernel/parisc_ksyms.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/parisc_ksyms.c Tue Apr 3 17:54:34 2001 @@ -22,8 +22,10 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strtok); +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) #include EXPORT_SYMBOL(hppa_dma_ops); +#endif #include EXPORT_SYMBOL(enable_irq); @@ -33,18 +35,30 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(boot_cpu_data); +#include +EXPORT_SYMBOL(pm_power_off); + #ifdef CONFIG_SMP EXPORT_SYMBOL(synchronize_irq); #include EXPORT_SYMBOL(kernel_flag); +/* from asm/system.h */ #include EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); +#endif +#include +EXPORT_SYMBOL(__xchg8); +EXPORT_SYMBOL(__xchg32); +EXPORT_SYMBOL(__cmpxchg_u32); +#ifdef __LP64__ +EXPORT_SYMBOL(__xchg64); +EXPORT_SYMBOL(__cmpxchg_u64); #endif #include @@ -69,12 +83,24 @@ EXPORT_SYMBOL(gsc_alloc_irq); EXPORT_SYMBOL(pdc_iodc_read); +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) +#include +EXPORT_SYMBOL(inb); +EXPORT_SYMBOL(inw); +EXPORT_SYMBOL(inl); +EXPORT_SYMBOL(outb); +EXPORT_SYMBOL(outw); +EXPORT_SYMBOL(outl); +#endif + extern void $$divI(void); extern void $$divU(void); extern void $$remI(void); extern void $$remU(void); +#ifndef __LP64__ extern void $$mulI(void); extern void $$mulU(void); +#endif extern void $$divU_3(void); extern void $$divU_5(void); extern void $$divU_6(void); @@ -98,8 +124,10 @@ EXPORT_SYMBOL_NOVERS($$divU); EXPORT_SYMBOL_NOVERS($$remI); EXPORT_SYMBOL_NOVERS($$remU); +#ifndef __LP64__ EXPORT_SYMBOL_NOVERS($$mulI); EXPORT_SYMBOL_NOVERS($$mulU); +#endif EXPORT_SYMBOL_NOVERS($$divU_3); EXPORT_SYMBOL_NOVERS($$divU_5); EXPORT_SYMBOL_NOVERS($$divU_6); @@ -126,9 +154,11 @@ #ifdef __LP64__ extern void __divdi3(void); extern void __udivdi3(void); +extern void __umoddi3(void); EXPORT_SYMBOL_NOVERS(__divdi3); EXPORT_SYMBOL_NOVERS(__udivdi3); +EXPORT_SYMBOL_NOVERS(__umoddi3); #endif #ifndef __LP64__ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pci.c linux.ac/arch/parisc/kernel/pci.c --- linux.vanilla/arch/parisc/kernel/pci.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/pci.c Tue Apr 3 17:54:34 2001 @@ -75,7 +75,7 @@ ASSERT(pci_port); /* make sure services are defined */ \ ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \ if (parisc_pci_hba[b] == NULL) { \ - printk(KERN_WARNING "\nPCI Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \ + printk(KERN_WARNING "\nPCI or WAX Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \ } else { \ d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \ } \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pdc.c linux.ac/arch/parisc/kernel/pdc.c --- linux.vanilla/arch/parisc/kernel/pdc.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/pdc.c Tue Apr 3 17:54:34 2001 @@ -99,6 +99,13 @@ } #endif +int pdc_coproc_cfg(void *address) +{ + ASSERT_ALIGN(address, 8); + return mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(address)); +} + + int pdc_iodc_read(void *address, void * hpa, unsigned int index, void * iodc_data, unsigned int iodc_data_size) { @@ -109,11 +116,35 @@ } -int pdc_system_map_find_mods(void *pdc_mod_info, - void *mod_path, int index) +int pdc_psw_get_mask(void *mask_ret) +{ + return mem_pdc_call(PDC_PSW, PDC_PSW_MASK, __pa(mask_ret)); +} + + +int pdc_psw_get_defaults(void *psw_ret) +{ + return mem_pdc_call(PDC_PSW, PDC_PSW_GET_DEFAULTS, __pa(psw_ret)); +} + + +int pdc_psw_set_defaults(unsigned long psw_val) +{ + return mem_pdc_call(PDC_PSW, PDC_PSW_SET_DEFAULTS, psw_val); +} + +int pdc_system_map_find_mods(void *pdc_mod_info, + void *mod_path, long mod_index) { return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, - __pa(pdc_mod_info), __pa(mod_path), (long)index); + __pa(pdc_mod_info), __pa(mod_path), mod_index); +} + +int pdc_system_map_find_addrs(void *pdc_addr_info, + long mod_index, long addr_index) +{ + return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, + __pa(pdc_addr_info), mod_index, addr_index); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/pdc_cons.c linux.ac/arch/parisc/kernel/pdc_cons.c --- linux.vanilla/arch/parisc/kernel/pdc_cons.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/pdc_cons.c Tue Apr 3 17:54:34 2001 @@ -31,7 +31,6 @@ void pdc_putc(unsigned char c) { unsigned int n; - unsigned long flags; switch (c) { case '\n': @@ -110,7 +109,7 @@ wait_key: pdc_console_wait_key, unblank: NULL, setup: pdc_console_setup, - flags: CON_PRINTBUFFER|CON_ENABLED, // |CON_CONSDEV, + flags: CON_BOOT|CON_PRINTBUFFER|CON_ENABLED, // |CON_CONSDEV, index: -1, }; @@ -135,16 +134,20 @@ /* Unregister the pdc console with the printk console layer */ void pdc_console_die(void) { + extern unsigned long log_size; /* kernel/printk.c */ + printk("Switching from PDC console\n"); if (!pdc_console_initialized) return; --pdc_console_initialized; - + + /* Don't repeat what we've already printed */ + log_size = 0; + #ifdef CONFIG_VT_CONSOLE { /* fixme (needed?): Wait for console-tasklet to finish !*/ - extern struct tasklet_struct console_tasklet; - tasklet_schedule(&console_tasklet); + schedule_console_callback(); } #endif @@ -163,7 +166,7 @@ void pdc_console_restart(void) { struct console *console; - extern int log_size; + extern unsigned long log_size; /* kernel/printk.c */ if (pdc_console_initialized) return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/process.c linux.ac/arch/parisc/kernel/process.c --- linux.vanilla/arch/parisc/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/process.c Tue Apr 3 17:54:34 2001 @@ -50,6 +50,11 @@ int hlt_counter=0; +/* + * Power off function, if any + */ +void (*pm_power_off)(void); + void disable_hlt(void) { hlt_counter++; @@ -85,26 +90,74 @@ { } -struct notifier_block *mach_notifier; +#ifdef __LP64__ +#define COMMAND_GLOBAL 0xfffffffffffe0030UL +#else +#define COMMAND_GLOBAL 0xfffe0030 +#endif + +#define CMD_RESET 5 /* reset any module */ + +/* +** The Wright Brothers and Gecko systems have a H/W problem +** (Lasi...'nuf said) may cause a broadcast reset to lockup +** the system. An HVERSION dependent PDC call was developed +** to perform a "safe", platform specific broadcast reset instead +** of kludging up all the code. +** +** Older machines which do not implement PDC_BROADCAST_RESET will +** return (with an error) and the regular broadcast reset can be +** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET +** the PDC call will not return (the system will be reset). +*/ +void machine_restart(char *cmd) +{ +#ifdef FASTBOOT_SELFTEST_SUPPORT + /* + ** If user has modified the Firmware Selftest Bitmap, + ** run the tests specified in the bitmap after the + ** system is rebooted w/PDC_DO_RESET. + ** + ** ftc_bitmap = 0x1AUL "Skip destructive memory tests" + ** + ** Using "directed resets" at each processor with the MEM_TOC + ** vector cleared will also avoid running destructive + ** memory self tests. (Not implemented yet) + */ + if (ftc_bitmap) { + mem_pdc_call( PDC_BROADCAST_RESET, + PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC, + ftc_bitmap); + } +#endif + + /* "Normal" system reset */ + (void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET, + 0L, 0L, 0L); + + /* Nope...box should reset with just CMD_RESET now */ + gsc_writel(CMD_RESET, COMMAND_GLOBAL); + + /* Wait for RESET to lay us to rest. */ + while (1) ; -void machine_restart(char *ptr) -{ - notifier_call_chain(&mach_notifier, MACH_RESTART, ptr); } void machine_halt(void) { - notifier_call_chain(&mach_notifier, MACH_HALT, NULL); } void machine_power_on(void) { - notifier_call_chain(&mach_notifier, MACH_POWER_ON, NULL); } +/* This routine is called from sys_reboot to actually turn off the + * machine */ void machine_power_off(void) { - notifier_call_chain(&mach_notifier, MACH_POWER_OFF, NULL); + /* If there is a registered power off handler, call it. */ + if(pm_power_off) + pm_power_off(); } @@ -148,10 +201,54 @@ /* * Fill in the FPU structure for a core dump. */ + int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) { memcpy(r, regs->fr, sizeof *r); return 1; +} + +/* + * Fill in general registers in a core dump. This saves pretty + * much the same registers as hp-ux, although in a different order. + * Registers marked # below are not currently saved in pt_regs, so + * we use their current values here. + * + * gr0..gr31 + * sr0..sr7 + * iaoq0..iaoq1 + * iasq0..iasq1 + * cr11 (sar) + * cr19 (iir) + * cr20 (isr) + * cr21 (ior) + * # cr22 (ipsw) + * # cr0 (recovery counter) + * # cr24..cr31 (temporary registers) + * # cr8,9,12,13 (protection IDs) + * # cr10 (scr/ccr) + * # cr15 (ext int enable mask) + * + */ + +void +parisc_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst) +{ + memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ + memcpy(dst + 0, pt->gr, 32 * sizeof(elf_greg_t)); + memcpy(dst + 32, pt->sr, 8 * sizeof(elf_greg_t)); + memcpy(dst + 40, pt->iaoq, 2 * sizeof(elf_greg_t)); + memcpy(dst + 42, pt->iasq, 2 * sizeof(elf_greg_t)); + dst[44] = pt->sar; dst[45] = pt->iir; + dst[46] = pt->isr; dst[47] = pt->ior; + dst[48] = mfctl(22); dst[49] = mfctl(0); + dst[50] = mfctl(24); dst[51] = mfctl(25); + dst[52] = mfctl(26); dst[53] = mfctl(27); + dst[54] = mfctl(28); dst[55] = mfctl(29); + dst[56] = mfctl(30); dst[57] = mfctl(31); + dst[58] = mfctl( 8); dst[59] = mfctl( 9); + dst[60] = mfctl(12); dst[61] = mfctl(13); + dst[62] = mfctl(10); dst[63] = mfctl(15); } /* Note that "fork()" is implemented in terms of clone, with diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/ptrace.c linux.ac/arch/parisc/kernel/ptrace.c --- linux.vanilla/arch/parisc/kernel/ptrace.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/ptrace.c Tue Apr 3 17:54:34 2001 @@ -31,6 +31,9 @@ #define PT_SINGLESTEP 0x10000 #define PT_BLOCKSTEP 0x20000 +/* PSW bits we allow the degubber to modify */ +#define USER_PSW_BITS (PSW_N | PSW_V | PSW_CB) + long sys_ptrace(long request, pid_t pid, long addr, long data) { struct task_struct *child; @@ -146,19 +149,32 @@ ret = -EIO; if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs)) goto out_tsk; - /* XXX This test probably needs adjusting. We probably want to - * allow writes to some bits of PSW, and may want to block writes - * to (some) space registers. Some register values written here - * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is - * written with r31/r31+4, and not with the values in pt_regs. + /* Some register values written here may be ignored in + * entry.S:syscall_restore_rfi; e.g. iaoq is written with + * r31/r31+4, and not with the values in pt_regs. */ - /* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */ - if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR)) + if (addr == PT_PSW) { + /* Allow writing to Nullify, Divide-step-correction, + * and carry/borrow bits. + * BEWARE, if you set N, and then single step, it wont + * stop on the nullified instruction. + */ + data &= USER_PSW_BITS; + task_regs(child)->gr[0] &= ~USER_PSW_BITS; + task_regs(child)->gr[0] |= data; + ret = 0; + goto out_tsk; + } + else if ((addr >= PT_GR1 && addr <= PT_GR31) || + addr == PT_IAOQ0 || addr == PT_IAOQ1 || + (addr >= PT_FR0 && addr <= PT_FR31) || + addr == PT_SAR) { + *(unsigned long *) ((char *) task_regs(child) + addr) = data; + ret = 0; + goto out_tsk; + } + else goto out_tsk; - - *(unsigned long *) ((char *) task_regs(child) + addr) = data; - ret = 0; - goto out_tsk; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/real2.S linux.ac/arch/parisc/kernel/real2.S --- linux.vanilla/arch/parisc/kernel/real2.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/real2.S Tue Apr 3 17:54:34 2001 @@ -7,7 +7,6 @@ * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) * */ -#define __ASSEMBLY__ #include #include @@ -157,7 +156,7 @@ mtctl %r1, %cr18 ldo 4(%r1), %r1 mtctl %r1, %cr18 - load32 PDC_PSW, %r1 + load32 REAL_MODE_PSW, %r1 mtctl %r1, %cr22 rfi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/sba_iommu.c linux.ac/arch/parisc/kernel/sba_iommu.c --- linux.vanilla/arch/parisc/kernel/sba_iommu.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/sba_iommu.c Tue Apr 3 17:54:34 2001 @@ -237,14 +237,18 @@ char *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ - unsigned long *res_hint; /* next available IOVP - circular search */ + unsigned long *res_hint; /* next avail IOVP - circular search */ + spinlock_t res_lock; + unsigned long hint_mask_pdir; /* bits used for DMA hints */ unsigned int res_bitshift; /* from the LEFT! */ unsigned int res_size; /* size of resource map in bytes */ unsigned int hint_shift_pdir; - spinlock_t res_lock; - unsigned long hint_mask_pdir; /* bits used for DMA hints */ #ifdef DELAYED_RESOURCE_CNT - dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; + int saved_cnt; + struct sba_dma_pair { + dma_addr_t iova; + size_t size; + } saved[DELAYED_RESOURCE_CNT]; #endif #ifdef CONFIG_PROC_FS @@ -546,7 +550,6 @@ pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); pide <<= 3; /* convert to bit address */ pide += bitshiftcnt; - ASSERT(0 != pide); break; } mask >>= o; @@ -562,7 +565,7 @@ } /* wrapped ? */ - ioc->res_hint = (res_end == res_ptr) ? (unsigned long *) ioc->res_map : res_ptr; + ioc->res_hint = (res_end >= res_ptr) ? (unsigned long *) ioc->res_map : res_ptr; return (pide); } @@ -810,7 +813,7 @@ ASSERT(size > 0); /* save offset bits */ - offset = ((dma_addr_t) addr) & ~IOVP_MASK; + offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK; /* round up to nearest IOVP_SIZE */ size = (size + offset + ~IOVP_MASK) & IOVP_MASK; @@ -880,7 +883,10 @@ #else struct ioc *ioc = &sba_list->ioc[0]; #endif - +#ifdef DELAYED_RESOURCE_CNT + struct sba_dma_pair *d = &(ioc->saved[ioc->saved_cnt]); +#endif + unsigned long flags; dma_addr_t offset; offset = iova & ~IOVP_MASK; @@ -891,38 +897,43 @@ size += offset; size = ROUNDUP(size, IOVP_SIZE); - ASSERT(0 != iova); - spin_lock_irqsave(&ioc->res_lock, flags); #ifdef CONFIG_PROC_FS ioc->usingle_calls++; ioc->usingle_pages += size >> IOVP_SHIFT; #endif -#ifdef DELAYED_RESOURCE_CNT - if (ioc->saved_cnt < DELAYED_RESOURCE_CNT) { - ioc->saved_iova[ioc->saved_cnt] = iova; - ioc->saved_size[ioc->saved_cnt] = size; - ioc_saved_cnt++; - } else { - do { -#endif - sba_mark_invalid(ioc, iova, size); - sba_free_range(ioc, iova, size); #ifdef DELAYED_RESOURCE_CNT - ioc->saved_cnt--; - iova = ioc->saved_iova[ioc->saved_cnt]; - size = ioc->saved_size[ioc->saved_cnt]; - } while (ioc->saved_cnt) - + d->iova = iova; + d->size = size; + if (++ioc->saved_cnt >= DELAYED_RESOURCE_CNT) { + int cnt = ioc->saved_cnt; + while (cnt) { + sba_mark_invalid(ioc, d->iova, d->size); + sba_free_range(ioc, d->iova, d->size); + d--; + cnt--; + } + ioc->saved_cnt = 0; /* flush purges */ - (void) (volatile) READ_REG32(ioc->ioc_hpa+IOC_PCOM); + READ_REG32(ioc->ioc_hpa+IOC_PCOM); } #else + sba_mark_invalid(ioc, iova, size); + sba_free_range(ioc, iova, size); /* flush purges */ READ_REG32(ioc->ioc_hpa+IOC_PCOM); #endif spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* XXX REVISIT for 2.5 Linux - we need syncdma for kernel-user + ** space zero-copy support. For Astro based systems this isn't + ** a big deal WRT performance. + ** As long as 2.4 kernels copyin/copyout data from/to userspace, + ** we don't need the syncdma. The issue here is the cachelines + ** in the I/O MMU are *not* fully coherent - this is a bug. + asm volatile("syncdma"); + */ } @@ -955,27 +966,6 @@ free_pages((unsigned long) vaddr, get_order(size)); } -/* -** Two address ranges are "virtually contiguous" iff: -** 1) end of prev == start of next, or... append case -** 3) end of next == start of prev prepend case -** -** and they are DMA contiguous *iff*: -** 2) end of prev and start of next are both on a page boundry -** -** (shift left is a quick trick to mask off upper bits) -*/ -#define DMA_CONTIG(__X, __Y) \ - (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) - -/* -** Assumption is two transactions are mutually exclusive. -** ie both go to different parts of memory. -** If both are true, then both transaction are on the same page. -*/ -#define DMA_SAME_PAGE(s1,e1,s2,e2) \ - ( ((((s1) ^ (s2)) >> PAGE_SHIFT) == 0) \ - && ((((e1) ^ (e2)) >> PAGE_SHIFT) == 0) ) /* ** Since 0 is a valid pdir_base index value, can't use that @@ -1006,7 +996,7 @@ #ifdef DEBUG_LARGE_SG_ENTRIES if (dump_run_sg) - printk(" %d : %08lx/%05x %p/%05x\n", + printk(" %2d : %08lx/%05x %p/%05x\n", nents, (unsigned long) sg_dma_address(startsg), cnt, startsg->address, startsg->length @@ -1024,11 +1014,10 @@ if (sg_dma_address(startsg) & PIDE_FLAG) { u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; dma_offset = (unsigned long) pide & ~IOVP_MASK; - pide >>= IOVP_SHIFT; - pdirp = &(ioc->pdir_base[pide]); sg_dma_address(startsg) = 0; - ++dma_sg; - sg_dma_address(dma_sg) = (pide << IOVP_SHIFT) + dma_offset; + dma_sg++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); n_mappings++; } @@ -1039,6 +1028,9 @@ unsigned long vaddr = (unsigned long) startsg->address; ASSERT(pdirp); + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ sg_dma_len(dma_sg) += cnt; cnt += dma_offset; dma_offset=0; /* only want offset on first chunk */ @@ -1062,6 +1054,15 @@ } +/* +** Two address ranges are DMA contiguous *iff* "end of prev" and +** "start of next" are both on a page boundry. +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + /* ** First pass is to walk the SG list and determine where the breaks are @@ -1077,117 +1078,104 @@ struct scatterlist *startsg, int nents) { + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ int n_mappings = 0; while (nents > 0) { - struct scatterlist *dma_sg; /* next DMA stream head */ - unsigned long dma_offset, dma_len; /* start/len of DMA stream */ - struct scatterlist *chunksg; /* virtually contig chunk head */ - unsigned long chunk_addr, chunk_len; /* start/len of VCONTIG chunk */ /* ** Prepare for first/next DMA stream */ - dma_sg = chunksg = startsg; - dma_len = chunk_len = startsg->length; - chunk_addr = (unsigned long) startsg->address; - dma_offset = 0UL; + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = startsg->length; + vcontig_end += (unsigned long) startsg->address; + dma_offset = (unsigned long) startsg->address & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; /* ** This loop terminates one iteration "early" since ** it's always looking one "ahead". */ while (--nents > 0) { - /* ptr to coalesce prev and next */ - struct scatterlist *prev_sg = startsg; - unsigned long prev_end = (unsigned long) prev_sg->address + prev_sg->length; - unsigned long current_end; + unsigned long startsg_end; + + startsg++; + startsg_end = (unsigned long) startsg->address + startsg->length; /* PARANOID: clear entries */ sg_dma_address(startsg) = 0; sg_dma_len(startsg) = 0; - /* Now start looking ahead */ - startsg++; - current_end = (unsigned long) startsg->address + startsg->length; - /* ** First look for virtually contiguous blocks. ** PARISC needs this since it's cache is virtually ** indexed and we need the associated virtual ** address for each I/O address we map. ** - ** 1) can we *prepend* the next transaction? + ** 1) Can we prepend the next transaction? + ** Only if they are on the same page. + ** And we don't mind DMA order wrong. NOT. + ** Feasible but requires substantial work. */ - if (current_end == (unsigned long) prev_sg->address) - { - /* prepend : get new offset */ - chunksg = startsg; - chunk_addr = (unsigned long) prev_sg->address; - chunk_len += startsg->length; - dma_len += startsg->length; - continue; - } /* ** 2) or append the next transaction? */ - if (prev_end == (unsigned long) startsg->address) + if (vcontig_end == (unsigned long) startsg->address) { - chunk_len += startsg->length; - dma_len += startsg->length; + vcontig_len += startsg->length; + vcontig_end += startsg->length; + dma_len += startsg->length; continue; } #ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = (chunk_len > IOVP_SIZE); + dump_run_sg = (vcontig_len > IOVP_SIZE); #endif + /* ** Not virtually contigous. ** Terminate prev chunk. ** Start a new chunk. ** - ** Once we start a new VCONTIG chunk, the offset + ** Once we start a new VCONTIG chunk, dma_offset ** can't change. And we need the offset from the first ** chunk - not the last one. Ergo Successive chunks ** must start on page boundaries and dove tail ** with it's predecessor. */ - sg_dma_len(prev_sg) = chunk_len; + sg_dma_len(vcontig_sg) = vcontig_len; - chunk_len = startsg->length; - dma_offset |= (chunk_addr & ~IOVP_MASK); - ASSERT((0 == (chunk_addr & ~IOVP_MASK)) || - (dma_offset == (chunk_addr & ~IOVP_MASK))); + vcontig_sg = startsg; + vcontig_len = startsg->length; -#if 0 /* - ** 4) do the chunks end/start on page boundaries? - ** Easier than 3 since no offsets are involved. + ** 3) do the entries end/start on page boundaries? + ** Don't update vcontig_end until we've checked. */ - if (DMA_CONTIG(prev_end, startsg->address)) + if (DMA_CONTIG(vcontig_end, startsg->address)) { - /* - ** Yes. - ** Reset chunk ptr. - */ - chunksg = startsg; - chunk_addr = (unsigned long) startsg->address; - + vcontig_end = vcontig_len + (unsigned long) startsg->address; + dma_len += vcontig_len; continue; - } else -#endif - { + } else { break; } } /* ** End of DMA Stream - ** Terminate chunk. + ** Terminate last VCONTIG block. ** Allocate space for DMA stream. */ - sg_dma_len(startsg) = chunk_len; + sg_dma_len(vcontig_sg) = vcontig_len; dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; sg_dma_address(dma_sg) = PIDE_FLAG @@ -1295,10 +1283,11 @@ while (sg_dma_len(sglist) && nents--) { + sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); #ifdef CONFIG_PROC_FS - ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; + ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT; + ioc->usingle_calls--; /* kluge since call is unmap_sg() */ #endif - sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); ++sglist; } @@ -1625,8 +1614,8 @@ ); sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", buf, - ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ - total_pages); /* 8 bits per byte */ + (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ + total_pages); sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, total_pages - ioc->used_pages, ioc->used_pages, @@ -1645,22 +1634,22 @@ sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", buf, min, avg, max); - sprintf(buf, "%spci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n", buf, ioc->msingle_calls, ioc->msingle_pages, (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); /* KLUGE - unmap_sg calls unmap_single for each mapped page */ - min = ioc->usingle_calls - ioc->usg_calls; + min = ioc->usingle_calls; max = ioc->usingle_pages - ioc->usg_pages; - sprintf(buf, "%spci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n", buf, min, max, (int) ((max * 1000)/min)); - sprintf(buf, "%spci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n", buf, ioc->msg_calls, ioc->msg_pages, (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); - sprintf(buf, "%spci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", buf, ioc->usg_calls, ioc->usg_pages, (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); @@ -1672,13 +1661,14 @@ { struct sba_device *sba_dev = sba_list; struct ioc *ioc = &sba_dev->ioc[0]; - unsigned long *res_ptr = (unsigned long *)ioc->res_map; + unsigned int *res_ptr = (unsigned int *)ioc->res_map; int i; - for(i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr) { + buf[0] = '\0'; + for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) { if ((i & 7) == 0) strcat(buf,"\n "); - sprintf(buf, "%s %08lx", buf, *res_ptr); + sprintf(buf, "%s %08x", buf, *res_ptr); } strcat(buf, "\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/semaphore.c linux.ac/arch/parisc/kernel/semaphore.c --- linux.vanilla/arch/parisc/kernel/semaphore.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/semaphore.c Wed Apr 18 13:52:55 2001 @@ -9,6 +9,7 @@ #include #include +#include /* for xchg() definitions */ /* * Semaphores are implemented using a two-way counter: @@ -184,9 +185,9 @@ add_wait_queue_exclusive(&sem->wait, &wait); while (atomic_read(&sem->count) < 0) { - set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + set_task_state(current, TASK_UNINTERRUPTIBLE); if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to aquire or bias the lock */ + break; /* we must attempt to acquire or bias the lock */ schedule(); } @@ -203,7 +204,7 @@ for (;;) { if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) break; - set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + set_task_state(current, TASK_UNINTERRUPTIBLE); if (!sem->write_bias_granted) schedule(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/setup.c linux.ac/arch/parisc/kernel/setup.c --- linux.vanilla/arch/parisc/kernel/setup.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/kernel/setup.c Tue Apr 3 17:54:34 2001 @@ -1,9 +1,9 @@ /* $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $ * * Initial setup-routines for HP 9000 based hardware. - * + * * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Modifications for PA-RISC (C) 1999 Helge Deller + * Modifications for PA-RISC (C) 1999 Helge Deller * Modifications copyright 1999 SuSE GmbH (Philipp Rumpf) * Modifications copyright 2000 Martin K. Petersen * Modifications copyright 2000 Philipp Rumpf @@ -19,13 +19,14 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ +#include #include #include #include @@ -36,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -92,7 +92,7 @@ parent: &iomem_resource, sibling: &sysrom_resource, child: &pdcdata_resource}; extern char _text; /* start of kernel code, defined by linker */ -extern int data_start; +extern int data_start; extern char _edata; /* end of data, begin BSS, defined by linker */ extern char _end; /* end of BSS, defined by linker */ @@ -117,10 +117,6 @@ struct system_cpuinfo_parisc boot_cpu_data; struct cpuinfo_parisc cpu_data[NR_CPUS]; -extern void do_inventory(void); -extern void cache_init(void); -extern struct hp_device * register_module(void *hpa); - static int cpu_driver_callback(struct hp_device *, struct pa_iodc_driver *); static struct pa_iodc_driver cpu_drivers_for[] = { @@ -134,6 +130,9 @@ static long fallback_cpu_hpa[] = { 0xfffa0000L, 0xfffbe000L, 0x0 }; +/* This has to go somewhere in architecture specific code. */ + +int EISA_bus; /* ** PARISC CPU driver - claim "device" and initialize CPU data structures. @@ -143,15 +142,14 @@ ** change once the system has booted. ** ** The callback *should* do per-instance initialization of -** everything including the monarch. Some of the code that's -** in setup.c:start_parisc() should migrate here and start_parisc() -** should "register_driver(cpu_driver_for)" before calling -** do_inventory(). +** everything including the monarch. "Per CPU" init code in +** setup.c:start_parisc() has migrated here and start_parisc() +** will "register_driver(cpu_driver_for)" before calling do_inventory(). ** ** The goal of consolidating CPU initialization into one place is ** to make sure all CPU's get initialized the same way. -** It would be nice if the even the manarch through the exact same code path. -** (up to rendevous at least). +** The code path not shared is how PDC hands control of the CPU to the OS. +** The initialization of OS data structures is the same (done below). */ #undef ASSERT #define ASSERT(expr) \ @@ -160,6 +158,7 @@ panic(#expr); \ } + static int cpu_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) { @@ -167,6 +166,8 @@ extern int pdc_pat; /* arch/parisc/kernel/inventory.c */ static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; #endif + unsigned long txn_addr; + unsigned long cpuid; struct cpuinfo_parisc *p; #ifndef CONFIG_SMP @@ -176,16 +177,6 @@ } #endif - p = &cpu_data[boot_cpu_data.cpu_count]; - boot_cpu_data.cpu_count++; - -/* TODO: Enable FP regs - done early in start_parisc() now */ - - /* initialize counters */ - memset(p, 0, sizeof(struct cpuinfo_parisc)); - - p->hpa = (unsigned long) d->hpa; /* save CPU hpa */ - #ifdef __LP64__ if (pdc_pat) { ulong status; @@ -201,7 +192,7 @@ ASSERT(d->pmod_loc == pa_pdc_cell.mod_location); ASSERT(d->mod_path == pa_pdc_cell.mod_path); - p->txn_addr = pa_pdc_cell.mod[0]; /* id_eid for IO sapic */ + txn_addr = pa_pdc_cell.mod[0]; /* id_eid for IO sapic */ /* get the cpu number */ status = mem_pdc_call( PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER, @@ -209,20 +200,46 @@ ASSERT(PDC_RET_OK == status); - p->cpuid = pdc_result[0]; - + if(pdc_result[0] >= NR_CPUS) { + printk(KERN_WARNING "IGNORING CPU at 0x%p," + " cpu_slot_id > NR_CPUS" + " (%ld > %d)\n", + d->hpa, pdc_result[0], NR_CPUS); + /* Ignore CPU since it will only crash */ + boot_cpu_data.cpu_count--; + return(1); + } else { + cpuid = pdc_result[0]; + } } else #endif { - p->txn_addr = (unsigned long) d->hpa; /* for normal parisc */ + txn_addr = (unsigned long) d->hpa; /* for normal parisc */ /* logical CPU ID and update global counter */ - p->cpuid = boot_cpu_data.cpu_count - 1; + cpuid = boot_cpu_data.cpu_count; } + p = &cpu_data[cpuid]; + boot_cpu_data.cpu_count++; + + /* initialize counters */ + memset(p, 0, sizeof(struct cpuinfo_parisc)); + + p->dev = d; /* Save hp_device ref in case we want PDC data */ + p->hpa = (unsigned long) d->hpa; /* save CPU hpa */ + p->cpuid = cpuid; /* save CPU hpa */ + p->txn_addr = txn_addr; /* save CPU hpa */ + + /* + ** CONFIG_SMP: init_smp_config() will attempt to get CPU's into + ** OS control. RENDEZVOUS is the default state - see mem_set above. + ** p->state = STATE_RENDEZVOUS; + */ + /* ** itimer and ipi IRQ handlers are statically initialized in - ** arch/parisc/kernel/irq.c + ** arch/parisc/kernel/irq.c. ie Don't need to register them. */ p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)]; @@ -230,41 +247,32 @@ } -void __xchg_called_with_bad_pointer(void) -{ - printk(KERN_EMERG "xchg() called with bad pointer !\n"); -} - - /* Some versions of IODC don't list the CPU, and since we don't walk * the bus yet, we have to probe for processors at well known hpa - * addresses. + * addresses. */ void __init register_fallback_cpu (void) { struct hp_device *d = NULL; int i = 0; - -#ifdef CONFIG_SMP -#error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)" -#endif + printk ("No CPUs reported by firmware - probing...\n"); - + while (fallback_cpu_hpa[i]) { - - d = register_module ((void *) fallback_cpu_hpa[i]); - - if (d > 0) { + + d = alloc_pa_dev(fallback_cpu_hpa[i]); + + if (d && (HPHW_NPROC == d->hw_type)) { printk ("Found CPU at %lx\n", fallback_cpu_hpa[i]); - cpu_driver_callback (d, 0); + (void) register_pa_dev(d); return; } - + i++; } - - panic ("No CPUs found. System halted.\n"); + + panic ("Don't know where this CPU lives. System halted.\n"); return; } @@ -289,7 +297,7 @@ if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0) printk("cpuid %08lx\n", boot_cpu_data.pdc.cpuid.cpuid); - + printk("CPUID vers %ld rev %ld\n", (boot_cpu_data.pdc.cpuid.cpuid >> 5) & 127, boot_cpu_data.pdc.cpuid.cpuid & 31); @@ -300,7 +308,7 @@ boot_cpu_data.model_name = parisc_getHWdescription(HPHW_NPROC, boot_cpu_data.pdc.model.hversion>>4, boot_cpu_data.pdc.model.sversion>>8); - + boot_cpu_data.hversion = boot_cpu_data.pdc.model.hversion; boot_cpu_data.sversion = boot_cpu_data.pdc.model.sversion; @@ -312,71 +320,71 @@ } -#ifdef __LP64__ -#define COMMAND_GLOBAL 0xfffffffffffe0030UL -#else -#define COMMAND_GLOBAL 0xfffe0030 -#endif - -#define CMD_RESET 5 /* reset any module */ - /* -** The Wright Brothers and Gecko systems have a H/W problem -** (Lasi...'nuf said) may cause a broadcast reset to lockup -** the system. An HVERSION dependent PDC call was developed -** to perform a "safe", platform specific broadcast reset instead -** of kludging up all the code. +** Set width/Enable FP coprocessor +** +** REVISIT: this could be done in the "code 22" trap handler. +** (frowands idea - that way we know which processes need FP +** registers saved on the interrupt stack.) ** -** Older machines which do not implement PDC_BROADCAST_RESET will -** return (with an error) and the regular broadcast reset can be -** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET -** the PDC call will not return (the system will be reset). +** NEWS FLASH: wide kernels need FP coprocessor enabled to handle +** formatted printing of %lx for example (double divides I think) */ -static int -reset_parisc(struct notifier_block *self, unsigned long command, void *ptr) +int +init_per_cpu(int cpuid) { - printk("%s: %s(cmd=%lu)\n", __FILE__, __FUNCTION__, command); + unsigned long pdc_result[32] __attribute__ ((aligned (8))); + unsigned long ccr; + int ret; - switch(command) { - case MACH_RESTART: -#ifdef FASTBOOT_SELFTEST_SUPPORT - /* - ** If user has modified the Firmware Selftest Bitmap, - ** run the tests specified in the bitmap after the - ** system is rebooted w/PDC_DO_RESET. - ** - ** ftc_bitmap = 0x1AUL "Skip destructive memory tests" - ** - ** Using "directed resets" at each processor with the MEM_TOC - ** vector cleared will also avoid running destructive - ** memory self tests. (Not implemented yet) - */ - if (ftc_bitmap) { - mem_pdc_call( PDC_BROADCAST_RESET, - PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC, - ftc_bitmap); - } -#endif + /* + ** ret[0] == Functional Coprocessors + ** ret[1] == Coprocessors Present + ** ret[15] == FP test status + ** ret[17] == Revision + ** ret[18] == Model + */ + ret = pdc_coproc_cfg(&pdc_result); + ccr = pdc_result[0]; - /* "Normal" system reset */ - (void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET, - 0L, 0L, 0L); + if(ret >= 0 && ccr) { + mtctl(ccr, 10); /* 10 == Coprocessor Control Reg */ - /* Nope...box should reset with just CMD_RESET now */ - gsc_writel(CMD_RESET, COMMAND_GLOBAL); + /* FWIW, FP rev/model is a more accurate way to determine + ** CPU type. CPU rev/model has some ambiguous cases. + */ + cpu_data[cpuid].fp_rev = pdc_result[17]; + cpu_data[cpuid].fp_model = pdc_result[18]; - /* Wait for RESET to lay us to rest. */ - while (1) ; + printk(KERN_INFO "FP[%d] enabled: Rev %ld Model %ld\n", + cpuid, pdc_result[17], pdc_result[18]); - break; + /* + ** store status register to stack (hopefully aligned) + ** and clear the T-bit. + */ + asm volatile ("fstd %fr0,8(%sp)"); + + } else { + printk(KERN_WARNING "WARNING: No FP CoProcessor?!" + " (pdc_result[0] == 0x%lx, expected 0xc0)\n" +#ifdef __LP64__ + "Halting Machine - FP required\n" +#endif + ,ccr); +#ifdef __LP64__ + mdelay(100); /* previous chars get pushed to console */ + panic("FP CoProc not reported"); +#endif } - return NOTIFY_DONE; -} -static struct notifier_block parisc_block = { reset_parisc, NULL, 0 }; + /* FUTURE: Enable Performance Monitor : ccr bit 0x20 */ + return(ret); +} -/* start_parisc() will be called from head.S to setup our new memory_start + +/* start_parisc() will be called from head.S to setup our new memory_start and actually start our kernel ! Memory-Layout is: - Kernel-Image (code+data+BSS) @@ -395,11 +403,9 @@ void __init start_parisc(unsigned arg0, unsigned arg1, unsigned arg2, unsigned arg3) { - register unsigned long ccr; unsigned long memory_start; /* Clear BSS */ - { char *p = &_edata, *q = &_end; @@ -408,43 +414,22 @@ } } - - pdc_console_init(); - + printk("The " #ifdef __LP64__ - printk("The 64-bit Kernel has started...\n"); + "64" #else - printk("The 32-bit Kernel has started...\n"); + "32" #endif + "-bit Kernel has started...\n"); - /* - ** Enable FP coprocessor - ** - ** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0. - ** Hardcoding works for PA1.1 processors. - ** - ** REVISIT: this could be done in the "code 22" trap handler. - ** (frowands idea - that way we know which processes need FP - ** registers saved on the interrupt stack.) - ** - ** NEWS FLASH: wide kernels need FP coprocessor enabled to handle - ** formatted printing of %lx for example (double divides I think) - */ - ccr = 0xc0; - mtctl(ccr, 10); - printk("Enabled FP coprocessor\n"); - -#ifdef __LP64__ - printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n" - "32-bit millicode by mistake.\n"); -#endif + init_per_cpu(smp_processor_id()); /* Set Modes & Enable FP */ memory_start = (unsigned long) &_end; memory_start = (memory_start + PAGE_SIZE) & PAGE_MASK; printk("Free memory starts at: 0x%lx\n", memory_start); /* Collect stuff passed in from the boot loader */ - printk(KERN_WARNING "%s(0x%x,0x%x,0x%x,0x%x)\n", + printk(KERN_WARNING "%s(0x%x,0x%x,0x%x,0x%x)\n", __FUNCTION__, arg0, arg1, arg2, arg3); /* arg0 is free-mem start, arg1 is ptr to command line */ @@ -472,7 +457,9 @@ collect_boot_cpu_data(); /* initialize the LCD/LED after boot_cpu_data is available ! */ +#ifdef CONFIG_CHASSIS_LCD_LED led_init(); /* LCD/LED initialization */ +#endif do_inventory(); /* probe for hardware */ register_driver(cpu_drivers_for); /* claim all the CPUs */ @@ -480,14 +467,24 @@ if (boot_cpu_data.cpu_count == 0) register_fallback_cpu(); - printk("CPU(s): %d x %s at %d.%06d MHz\n", + printk("CPU(s): %d x %s at %d.%06d MHz\n", boot_cpu_data.cpu_count, boot_cpu_data.cpu_name, - boot_cpu_data.cpu_hz / 1000000, + boot_cpu_data.cpu_hz / 1000000, boot_cpu_data.cpu_hz % 1000000 ); switch (boot_cpu_data.cpu_type) { case pcx: + /* + * We've got way too many dependencies on 1.1 semantics + * to support 1.0 boxes at this point. + */ + printk("PA-RISC Linux currently only supports machines that conform to\n"); + printk("the PA-RISC 1.1 or 2.0 architecture specification.\n"); + for (;;) + ; + break; /* not reached */ + case pcxs: case pcxt: hppa_dma_ops = &pcx_dma_ops; @@ -501,12 +498,15 @@ break; } + /* Turn off space register hashing */ + + disable_sr_hashing(); + #if 1 /* KLUGE! this really belongs in kernel/resource.c! */ iomem_resource.end = ~0UL; #endif sysram_resource.end = mem_max - 1; - notifier_chain_register(&mach_notifier, &parisc_block); start_kernel(); /* now back to arch-generic code... */ } @@ -542,6 +542,8 @@ } #endif + EISA_bus = 0; + cache_init(); paging_init(); @@ -557,8 +559,6 @@ #elif CONFIG_VT #if defined(CONFIG_STI_CONSOLE) conswitchp = &dummy_con; /* we use take_over_console() later ! */ -#elif defined(CONFIG_IODC_CONSOLE) - conswitchp = &prom_con; /* it's currently really "prom_con" */ #elif defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; #endif @@ -578,18 +578,21 @@ for(n=0; nsa.sa_handler = SIG_DFL; @@ -539,7 +539,7 @@ #if DEBUG_SIG printk("sa_handler is %lx\n", ka->sa.sa_handler); #endif - if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) { + if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) @@ -547,7 +547,7 @@ continue; } - if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) { + if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; /* Init gets no signals it doesn't want. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/smp.c linux.ac/arch/parisc/kernel/smp.c --- linux.vanilla/arch/parisc/kernel/smp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/smp.c Tue Apr 3 17:54:34 2001 @@ -0,0 +1,885 @@ +/* +** SMP Support +** +** Copyright (C) 1999 Walt Drummond +** Copyright (C) 1999 David Mosberger-Tang +** Copyright (C) 2001 Grant Grundler +** +** Lots of stuff stolen from arch/alpha/kernel/smp.c +** ...and then parisc stole from arch/ia64/kernel/smp.c. Thanks David! :^) +** +** Thanks to John Curry and Ullas Ponnadi. I learned alot from their work. +** -grant (1/12/2001) +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +*/ +#define __KERNEL_SYSCALLS__ +#undef ENTRY_SYS_CPUS /* syscall support for iCOD-like functionality */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* for flush_tlb_all() proto/macro */ + +#include +#include /* for CPU_IRQ_REGION and friends */ +#include +#include +#include +#include +#include + +/* Enable debug msgs for now */ +#define kDEBUG 100 +#define STATIC + +extern void _start(void); + +spinlock_t smp_lock = SPIN_LOCK_UNLOCKED; + +volatile struct task_struct *smp_init_current_idle_task; +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; + +volatile int __cpu_number_map[NR_CPUS] = { -1, }; /* cpu # -> Logical cpu ID*/ +volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> cup # */ + +static volatile int smp_commenced = 0; /* Set when the idlers are all forked */ +static volatile int cpu_now_booting = 0; /* track which CPU is booting */ +static volatile unsigned long cpu_callin_map = 0; /* Bitmap of online CPUs */ +#define IS_LOGGED_IN(cpunum) (test_bit(cpunum, &cpu_callin_map)) + +int smp_num_cpus = 1; +int smp_threads_ready = 0; +static int max_cpus = -1; /* Command line */ +static unsigned long ipi_op[NR_CPUS]; +struct smp_call_struct { + void (*func) (void *info); + void *info; + long wait; + atomic_t unstarted_count; + atomic_t unfinished_count; +}; +static volatile struct smp_call_struct *smp_call_function_data; + +enum ipi_message_type { + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CPU_START, + IPI_CPU_STOP, + IPI_CPU_TEST +}; + + +/********** SMP inter processor interrupt and communication routines */ + +#if 0 +/* XXX REVISIT Ignore for now. Need this to register IPI handler +** once we have perCPU ExtIntr switch tables. +*/ +static void +ipi_init(int cpuid) +{ + + /* If CPU is present ... */ +#ifdef ENTRY_SYS_CPUS + /* *and* running (not stopped) ... */ +#error iCOD support wants state checked here. +#endif + if(IS_LOGGED_IN(cpuid) ) + { + switch_to_idle_task(current); + } + + return; +} +#endif + + +/* +** Yoink this CPU from the runnable list... +** +*/ +static void +halt_processor(void) +{ +#ifdef ENTRY_SYS_CPUS +#error halt_processor() needs rework +/* +** o migrate I/O interrupts off this CPU. +** o leave IPI enabled - __cli() will disable IPI. +** o leave CPU in online map - just change the state +*/ + cpu_data[this_cpu].state = STATE_STOPPED; + mark_bh(IPI_BH); +#else + /* REVISIT : redirect I/O Interrupts to another CPU? */ + /* REVISIT : does PM *know* this CPU isn't available? */ + clear_bit(smp_processor_id(), &cpu_callin_map); + __cli(); + for (;;) + ; +#endif +} + + +void +ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int this_cpu = smp_processor_id(); + unsigned long *pending_ipis = &ipi_op[this_cpu]; + unsigned long ops; + + /* Count this now; we may make a call that never returns. */ + cpu_data[this_cpu].ipi_count++; + + mb(); /* Order interrupt and bit testing. */ + while ((ops = xchg(pending_ipis, 0)) != 0) { + mb(); /* Order bit clearing and data access. */ + do { + unsigned long which; + +printk("ipi_interrupt(%d,...) on %d ops = 0x%lx ", irq, this_cpu, ops); + + which = ffz(~ops); + ops &= ~(1 << which); + +printk("(which = %ld)\n", which); + + switch (which) { + case IPI_RESCHEDULE: +#if (kDEBUG>=100) + printk("CPU:%d got reschedule interrupt\n",this_cpu); +#endif /* kDEBUG */ + /* + * Reschedule callback. Everything to be done is done by the + * interrupt return path. + */ + break; + + case IPI_CALL_FUNC: + { + volatile struct smp_call_struct *data; + void (*func)(void *info); + void *info; + int wait; + + data = smp_call_function_data; + func = data->func; + info = data->info; + wait = data->wait; + + mb(); + atomic_dec (&data->unstarted_count); + + /* At this point, *data may be gone unless wait is true. */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) + atomic_dec (&data->unfinished_count); + } + break; + + case IPI_CPU_START: +#ifdef ENTRY_SYS_CPUS + cpu_data[this_cpu].state = STATE_RUNNING; +#endif + break; + + case IPI_CPU_STOP: +#ifdef ENTRY_SYS_CPUS +#else + halt_processor(); +#endif + break; + + case IPI_CPU_TEST: +#if (kDEBUG>=100) + printk("CPU:%d is alive\n",this_cpu); +#endif /* kDEBUG */ + break; + + default: + printk(KERN_CRIT "Unknown IPI num on CPU %d: %lu\n", this_cpu, which); + return; + } /* Switch */ + } while (ops); + + mb(); /* Order data access and bit testing. */ + } + return; +} + + +static inline void +ipi_send(int cpu, enum ipi_message_type op) +{ + set_bit(1<< op, &(cpu_data[cpu].pending_ipi)); + + /* + ** Just in case it's directed at ourselves, we want to make + ** sure the interrupt doesn't get delivered until we are out + ** of real mode again. I think it's cheaper to disable IRQ's + ** briefly than test for it. + */ + local_irq_disable(); + gsc_writel(IRQ_OFFSET(IPI_IRQ), cpu_data[cpu].hpa); + local_irq_enable(); +} + + +static inline void +send_IPI_single(int dest_cpu, enum ipi_message_type op) +{ + if (dest_cpu == NO_PROC_ID) + return; + + ipi_send(dest_cpu, op); +} + +static inline void +send_IPI_allbutself(enum ipi_message_type op) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) { + int cpu_id = __cpu_logical_map[i]; + if (cpu_id != smp_processor_id()) + send_IPI_single(cpu_id, op); + } +} + +static inline void +send_IPI_all(enum ipi_message_type op) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) + send_IPI_single(__cpu_logical_map[i], op); +} + +static inline void +send_IPI_self(enum ipi_message_type op) +{ + send_IPI_single(smp_processor_id(), op); +} + +inline void +smp_send_stop(void) { send_IPI_allbutself(IPI_CPU_STOP); } + +static inline void +smp_send_start(void) { send_IPI_allbutself(IPI_CPU_START); } + +void +smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); } + + +/* + * Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, keep retrying until ready. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute + * or are or have executed. + */ + +int +smp_call_function (void (*func) (void *info), void *info, int retry, int wait) +{ + struct smp_call_struct data; + long timeout; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, smp_num_cpus - 1); + atomic_set(&data.unfinished_count, smp_num_cpus - 1); + + if (retry) { + while (1) { + if (smp_call_function_data) { + schedule (); /* Give a mate a go */ + continue; + } + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); /* Bad luck */ + continue; + } + /* Mine, all mine! */ + break; + } + } + else { + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); + return -EBUSY; + } + } + + smp_call_function_data = &data; + spin_unlock (&lock); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(IPI_CALL_FUNC); + + /* Wait for response */ + timeout = jiffies + HZ; + while ( (atomic_read (&data.unstarted_count) > 0) && + time_before (jiffies, timeout) ) + barrier (); + + if (atomic_read (&data.unstarted_count) > 0) { + smp_call_function_data = NULL; + return -ETIMEDOUT; + } + + while (wait && atomic_read (&data.unfinished_count) > 0) + barrier (); + + smp_call_function_data = NULL; + return 0; +} + + + +/* + * Setup routine for controlling SMP activation + * + * Command-line option of "nosmp" or "maxcpus=0" will disable SMP + * activation entirely (the MPS table probe still happens, though). + * + * Command-line option of "maxcpus=", where is an integer + * greater than 0, limits the maximum number of CPUs activated in + * SMP mode to . + */ + +static int __init nosmp(char *str) +{ + max_cpus = 0; + return 1; +} + +__setup("nosmp", nosmp); + +static int __init maxcpus(char *str) +{ + get_option(&str, &max_cpus); + return 1; +} + +__setup("maxcpus=", maxcpus); + + +void +proxy_flush_tlb_all(void) +{ + flush_tlb_all(); +} + +/* + * Flush all other CPU's tlb and then mine. Do this with smp_call_function() + * as we want to ensure all TLB's flushed before proceeding. + */ +void +smp_flush_tlb_all(void) +{ + smp_call_function((void (*)(void *))proxy_flush_tlb_all, NULL, 1, 1); + flush_tlb_all(); +} + + +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __init +smp_setup_percpu_timer(int cpunum) +{ + cpu_data[cpunum].prof_counter = 1; + cpu_data[cpunum].prof_multiplier = 1; +} + + +void +smp_do_timer(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + struct cpuinfo_parisc *data = &cpu_data[cpu]; + + if (!--data->prof_counter) { + irq_enter(cpu, TIMER_IRQ); + update_process_times(user_mode(regs)); + data->prof_counter = data->prof_multiplier; + irq_exit(cpu, TIMER_IRQ); + } +} + + +/* + * Called by secondaries to update state and initialize CPU registers. + */ +STATIC void __init +smp_cpu_init(int cpunum) +{ + extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */ + extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */ + + /* Set modes and Enable floating point coprocessor */ + (void) init_per_cpu(cpunum); + +#if 0 + flush_tlb_all(); + flush_cache_all(); +#endif + mb(); + + /* Well, support 2.4 linux scheme as well. */ + if (test_and_set_bit(cpunum, (unsigned long *) (&cpu_callin_map))) + { + extern void machine_halt(void); /* arch/parisc.../process.c */ + + printk("CPU#%d already initialized!\n", cpunum); + machine_halt(); + } + + init_IRQ(); /* make sure no IRQ's are enabled or pending */ +} + + +/* + * Slaves start using C here. Indirectly called from smp_slave_stext. + * Do what start_parisc() and main() do for boot strap processor (aka monarch) + */ +void __init smp_callin(unsigned long pdc_entry_point, long hpa) +{ + extern void cpu_idle(void); /* arch/parisc/kernel/process.c */ + int slave_id = cpu_now_booting; + + smp_cpu_init(slave_id); + + +printk("SMP: CPU:%d CR15 %lx CR22 %lx CR23 %lx\n", slave_id, + mfctl(15), mfctl(22), mfctl(23)); + + /* Slave's wait here until Big Poppa daddy say "jump" */ + mb(); /* PARANOID */ + while (!smp_commenced) ; + mb(); /* PARANOID */ + + local_irq_enable(); /* Interrupts have been off until now */ + +printk("SMP: CPU:%d CR15 %lx CR22 %lx CR23 %lx\n", slave_id, + mfctl(15), mfctl(22), mfctl(23)); + +mdelay(300); +/* spin_lock (&smp_lock); */ + +printk("SMP: CPU:%d calling cpu_idle()\n", slave_id); +mdelay(300); +/* spin_unlock (&smp_lock); */ + cpu_idle(); /* Wait for timer to schedule some work */ + /* NOTREACHED */ +panic("smp_callin() AAAAaaaaahhhh....\n"); +} + + + + +/* + * Create the idle task for a new Slave CPU. DO NOT use kernel_thread() + * because that could end up calling schedule(). If it did, the new idle + * task could get scheduled before we had a chance to remove it from the + * run-queue... + */ +#if 0 +STATIC struct task_struct *fork_by_hand(void) +{ + struct task_struct *p; + + /* Create the stack and task structure for this idle process */ + if(0 != (p = (struct task_struct *)alloc_task_struct())) + { + *p = init_task; + p->need_resched = 0; + p->thread.pg_tables = 0; /* REVISIT */ + return p; + } + return(NULL); +} +#else +STATIC int fork_by_hand(void) +{ + struct pt_regs regs; + + /* + * don't care about the regs settings since + * we'll never reschedule the forked task. + */ + return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); +} +#endif + + +/* + * Bring one cpu online. + */ +STATIC int smp_boot_one_cpu(int cpuid, int cpunum) +{ + struct task_struct *idle; + long timeout; + + /* + * Create an idle task for this CPU. Note the address wed* give + * to kernel_thread is irrelevant -- it's going to start + * where OS_BOOT_RENDEVZ vector in SAL says to start. But + * this gets all the other task-y sort of data structures set + * up like we wish. We need to pull the just created idle task + * off the run queue and stuff it into the init_tasks[] array. + * Sheesh . . . + */ + + if (fork_by_hand() < 0) + panic("SMP: fork failed for CPU:%d", cpuid); + + idle = init_task.prev_task; + if (!idle) + panic("SMP: No idle process for CPU:%d", cpuid); + +printk("sboc: task 0x%p for %d/%d\n", idle, cpuid, cpunum); + + __cpu_number_map[cpuid] = cpunum; + __cpu_logical_map[cpunum] = cpuid; + + init_tasks[cpunum] = idle; + del_from_runqueue(idle); + unhash_process(idle); + + idle->processor = cpunum; + idle->has_cpu = 1; /* Schedule the first task manually */ + +printk("sboc: CPU %d state 0x%lx flags 0x%lx\n", + cpunum, idle->state, idle->flags); + + /* Let _start know what logical CPU we're booting + ** (offset into init_tasks[],cpu_data[]) + */ + cpu_now_booting = cpunum; + + /* + ** boot strap code needs to know the task address since + ** it also contains the process stack. + */ + smp_init_current_idle_task = idle ; + mb(); + + /* + ** This gets PDC to release the CPU from a very tight loop. + ** See MEM_RENDEZ comments in head.S. + */ + gsc_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpunum].hpa); + mb(); + + /* + * OK, wait a bit for that CPU to finish staggering about. + * Slave will set a bit when it reaches smp_cpu_init() and then + * wait for smp_commenced to be 1. + * Once we see the bit change, we can move on. + */ + for (timeout = 0; timeout < 10000; timeout++) { + if(IS_LOGGED_IN(cpunum)) { + /* Which implies Slave has started up */ + cpu_now_booting = 0; + smp_init_current_idle_task = NULL; + goto alive ; + } + udelay(100); + barrier(); + } + + __cpu_logical_map[cpunum] = NO_PROC_ID; + __cpu_number_map[cpuid] = NO_PROC_ID; + init_tasks[cpunum] = NULL; + free_task_struct(idle); + + printk("SMP: CPU:%d is stuck.\n", cpuid); + return -1; + +alive: + /* Remember the Slave data */ +#if (kDEBUG>=100) + printk("SMP: CPU:%d (num %d) came alive after %ld _us\n", + cpuid, cpunum, timeout * 100); +#endif /* kDEBUG */ +#ifdef ENTRY_SYS_CPUS + cpu_data[cpunum].state = STATE_RUNNING; +#endif + return 0; +} + + + + +/* +** inventory.c:do_inventory() has already 'discovered' the additional CPU's. +** We are ready to wrest them from PDC's control now. +** Called by smp_init bring all the secondaries online and hold them. +** +** o Setup of the IPI irq handler is done in irq.c. +** o MEM_RENDEZ is initialzed in head.S:stext() +** +*/ +void __init smp_boot_cpus(void) +{ + int i, cpu_count = 1; + unsigned long bogosum = loops_per_jiffy; /* Count Monarch */ + + /* REVISIT - assumes first CPU reported by PAT PDC is BSP */ + int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */ + + /* Take care of some initial bookkeeping. */ + for(i=0;iprocessor = 0; /*These are set already*/ + cpu_callin_map = 1; /* Mark Boostrap processor as present */ + +#ifdef ENTRY_SYS_CPUS + cpu_data[0].state = STATE_RUNNING; +#endif + + init_idle(); + + /* Nothing to do when told not to. */ + if (max_cpus == 0) { + printk(KERN_INFO "SMP mode deactivated.\n"); + return; + } + + if (max_cpus != -1) + printk("Limiting CPUs to %d\n", max_cpus); + + /* We found more than one CPU.... */ + if (boot_cpu_data.cpu_count > 1) { + + for (i = 0; i < NR_CPUS; i++) { + if (cpu_data[i].cpuid == NO_PROC_ID || + cpu_data[i].cpuid == bootstrap_processor) + continue; + + if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0) + continue; + + bogosum += loops_per_jiffy; + cpu_count++; /* Count good CPUs only... */ + + /* Bail when we've started as many CPUS as told to */ + if (cpu_count == max_cpus) + break; + } + } + if (cpu_count == 1) { + printk("SMP: Bootstrap processor only.\n"); + } + + printk(KERN_INFO "SMP: Total %d of %d processors activated " + "(%lu.%02lu BogoMIPS noticed).\n", + cpu_count, boot_cpu_data.cpu_count, (bogosum + 25) / 5000, + ((bogosum + 25) / 50) % 100); + + smp_num_cpus = cpu_count; +#if 0 + ipi_init(); +#endif + return; +} + +/* + * Called from main.c by each Monarch Processor. + * After this, any CPU can schedule any task. + */ +void smp_commence(void) +{ +printk("SMP: BSP before\n"); +mdelay(1000); + + smp_commenced = 1; + mb(); + +mdelay(10000); +printk("SMP: BSP proceeding\n"); +mdelay(300); + return; +} + +#ifdef ENTRY_SYS_CPUS +/* Code goes along with: +** entry.s: ENTRY_NAME(sys_cpus) / * 215, for cpu stat * / +*/ +int sys_cpus(int argc, char **argv) +{ + int i,j=0; + extern int current_pid(int cpu); + + if( argc > 2 ) { + printk("sys_cpus:Only one argument supported\n"); + return (-1); + } + if ( argc == 1 ){ + +#ifdef DUMP_MORE_STATE + for(i=0;ipid)?"RUNNING ": + "IDLING ",current->pid); +#endif + } + else if((argc==2) && !(strcmp(argv[1],"-s"))){ +#ifdef DUMP_MORE_STATE + printk("\nCPUSTATE CPUID\n"); + for(i=0;ipid==0)?"RUNNING ":"IDLING "); +#endif + } + else { + printk("sys_cpus:Unknown request\n"); + return (-1); + } + return (0); +} +#endif /* ENTRY_SYS_CPUS */ + + +int sys_get_cpu(void) +{ + return(smp_processor_id()); +} + + +int sys_ipi_send(int cpu,int op) +{ + if(cpu!=NO_PROC_ID){ + if(cpu<0) goto sys_ipi_error; + if(cpu<0 || cpu > NR_CPUS) goto sys_ipi_error; + if(__cpu_number_map[cpu]==NO_PROC_ID) goto sys_ipi_error; + } + switch(op){ + case IPI_CALL_FUNC: + if(cpu!=NO_PROC_ID){ + printk("Note:Ignoring cpuid:%d and calling function on all CPUS\n",cpu); + } + smp_flush_tlb_all(); + break; + case IPI_RESCHEDULE: + case IPI_CPU_TEST: + case IPI_CPU_START: + case IPI_CPU_STOP: + default: + if(cpu!=NO_PROC_ID){ + send_IPI_single(cpu,op);break; + } + else{ + if(op == IPI_CPU_STOP){ /* we don't want to down this cpu also */ + send_IPI_allbutself(op); + } + else{ + send_IPI_all(op); + } + } + break; + } + return (0); +sys_ipi_error: + printk("CPU:%d cann't send IPI to CPU:%d\n",smp_processor_id(),cpu); + return (-1); +} + +#ifdef CONFIG_PROC_FS +int __init +setup_profiling_timer(unsigned int multiplier) +{ + return -EINVAL; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/superio.c linux.ac/arch/parisc/kernel/superio.c --- linux.vanilla/arch/parisc/kernel/superio.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/parisc/kernel/superio.c Tue Apr 3 17:54:34 2001 @@ -0,0 +1,394 @@ +/* National Semiconductor NS87560UBD Super I/O controller used in + * HP [BCJ]x000 workstations. + * + * This chip is a horrid piece of engineering, and National + * denies any knowledge of its existence. Thus no datasheet is + * available off www.national.com. + * + * (C) Copyright 2000 Linuxcare, Inc. + * (C) Copyright 2000 Linuxcare Canada, Inc. + * (C) Copyright 2000 Martin K. Petersen + * (C) Copyright 2000 Alex deVries + * + * 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. + * + * The initial version of this is by Martin Peterson. Alex deVries + * has spent a bit of time trying to coax it into working. + */ + + +/* NOTES: + * + * The following is what iostat reports on my J5000: + * + * 10/0/14/0 ext_bus IDE + * 10/0/14/0.0 target + * 10/0/14/0.0.0 disk TEAC CD-532E-B + * 10/0/14/0.7 target + * 10/0/14/0.7.0 ctl Initiator + * 10/0/14/1 ba PCI Core I/O Adapter + * 10/0/14/1/1 tty Built-in RS-232C + * 10/0/14/1/2 tty Built-in RS-232C + * 10/0/14/1/3 ext_bus Built-in Parallel Interface + * 10/0/14/2 usb Built-in USB Interface + * 10/0/14/2.1 usbhub USB Root Hub + * + * It appears IDE is on function 0, ttyS0, ttyS1 and the parallel port + * are on function 1, while USB is on function 2. + * + * PCI bus walk on my J5000: + * + * PCI: 00:60 [1011/0019] DEC 21142/21143 + * PCI: 00:68 [11d4/1889] Analog Devices 1889 Audio DAC + * PCI: 00:70 [100b/0002] National Semiconductor IDE + * PCI: 00:71 [100b/000e] National Semiconductor Legacy I/O + * PCI: 00:72 [100b/0012] National Semiconductor USB + * PCI: 00:78 [1000/000b] Symbios Logic 53c896 + * PCI: 00:79 [1000/000b] Symbios Logic 53c896 + * [...] + * + * It appears function 0 is identical to a PC87415 IDE controller + * cell. + * + * We must be incredibly careful during initialization. Since all + * interrupts are routed through function 1 (which is not allowed by + * the PCI spec), we need to program the PICs on the legacy I/O port + * *before* we attempt to set up IDE and USB. @#$!& + * + * According to HP, devices are only enabled by firmware if they have + * a physical device connected. + * + * Configuration register bits: + * 0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92 + * 0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Local prototypes */ +__init void superio_probe (void); +static void superio_init (struct pci_dev *pdev,int interrupt); + +static int superio_serial_init (void); + + +/* Offsets to configuration and base address registers */ +#define IC_PIC1 0x20 /* PCI I/O address of master 8259 */ +#define IC_PIC2 0xA0 /* PCI I/O address of slave */ +#define SIO_CR 0x5A /* Configuration Register */ +#define SIO_FDCBAR 0x90 /* Floppy Disk Controller BAR */ +#define SIO_SP1BAR 0x94 /* Serial 1 BAR */ +#define SIO_SP2BAR 0x98 /* Serial 2 BAR */ +#define SIO_PPBAR 0x9C /* Parallel BAR */ + +/* Interrupt triggers and routing */ +#define TRIGGER_1 0x67 /* Edge/level trigger register 1 */ +#define TRIGGER_2 0x68 /* Edge/level trigger register 2 */ +#define IR_SER 0x69 /* Serial 1 [0:3] and Serial 2 [4:7] */ +#define IR_PFD 0x6a /* Parallel [0:3] and Floppy [4:7] */ +#define IR_IDE 0x6b /* IDE1 [0:3] and IDE2 [4:7] */ +#define IR_USB 0x70 /* USB [4:7] */ +#define IR_LOW 0x69 /* Lowest interrupt routing reg */ +#define IR_HIGH 0x71 /* Highest interrupt routing reg */ + +/* 8259 operational control words */ +#define OCW2_EOI 0x20 /* Non-specific EOI */ +#define OCW2_SEOI 0x60 /* Specific EOI */ +#define OCW3_IIR 0x0A /* Read request register */ +#define OCW3_ISR 0x0B /* Read service register */ +#define OCW3_POLL 0x0C /* Poll the PIC for an interrupt vector */ + +/* Interrupt lines. Only PIC1 is used */ +#define USB_IRQ 1 /* USB */ +#define SP1_IRQ 3 /* Serial port 1 */ +#define SP2_IRQ 4 /* Serial port 2 */ +#define PAR_IRQ 5 /* Parallel port */ +#define FDC_IRQ 6 /* Floppy controller */ +#define IDE_IRQ 7 /* IDE (pri+sec) */ + + +static struct superio_device { + u16 fdc_base; + u16 sp1_base; + u16 sp2_base; + u16 pp_base; +} sio; + + +/* There can be only one... */ +static int found = 0; + +static void superio_interrupt(int irq, void *devp, struct pt_regs *regs); + +/* Probe for a Super I/O device and print info */ +void __init +superio_probe (void) +{ + struct pci_dev *pdev = NULL; + u8 hdr_type, interrupt; + int ret; + + printk ("superio: Probe\n"); + + /* Check whether we have PCI */ + if (!pci_present) + return; + + /* Only probe once */ + if (found) + return; + found++; + + if ((pdev = pci_find_device (PCI_VENDOR_ID_NS, 0x0002, NULL))) { + u16 word; + int i; + + for (i = 0 ; i < 12 ; i++) + printk ("IDE: %lx\n", pci_resource_start (pdev, i)); + + pci_read_config_word (pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, word); + ret = pci_read_config_byte(pdev,PCI_INTERRUPT_LINE,&interrupt); + printk ("Scanning: interrupt is %i ret is %i\n", interrupt,ret); + pci_set_master (pdev); + } + else + printk ("Could not find Superio IDE !\n"); + + if ((pdev = pci_find_device (PCI_VENDOR_ID_NS, 0x0012, NULL))) { + u16 word; + int i; + + for (i = 0 ; i < 12 ; i++) + printk ("USB: %lx\n", pci_resource_start (pdev, i)); + + pci_read_config_word (pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, word); + ret = pci_read_config_byte(pdev,PCI_INTERRUPT_LINE,&interrupt); + printk ("Scanning: interrupt is %i ret is %i\n", interrupt,ret); + } + else + printk ("Could not find Superio USB!\n"); + + if ((pdev = pci_find_device (PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, NULL))) { + + /* I'm setting interrupt randomly here because dev->irq is + set to zero, and I can't figure out why this is. */ + + interrupt = 69; + + superio_init (pdev,interrupt); + } else + printk ("Bah!\n"); +} + + +/* Initialize Super I/O device */ +static void +superio_init (struct pci_dev *pdev,int interrupt) +{ + u8 i; + u16 word; + + printk ("superio: Found NS87560 legacy I/O device at %s with irq of %i \n", + pdev->slot_name,pdev->irq); + + /* What's enabled */ + pci_read_config_word (pdev, SIO_CR, &word); + printk ("superio: CR = %x\n", word); + + /* Find our I/O devices */ + pci_read_config_word (pdev, SIO_SP1BAR, &sio.sp1_base); + printk ("superio: Serial port 1 at 0x%x\n", sio.sp1_base); + + pci_read_config_word (pdev, SIO_SP2BAR, &sio.sp2_base); + printk ("superio: Serial port 2 at 0x%x\n", sio.sp2_base); + + pci_read_config_word (pdev, SIO_PPBAR, &sio.pp_base); + printk ("superio: Parallel port at 0x%x\n", sio.pp_base); + + pci_read_config_word (pdev, SIO_FDCBAR, &sio.sp1_base); + printk ("superio: Floppy controller at 0x%x\n", sio.fdc_base); + + request_region (IC_PIC1, 0x1f, "pic1"); + request_region (IC_PIC2, 0x1f, "pic2"); + request_region (SIO_SP1BAR, 0xf, "serial"); + + /* Enable the legacy I/O function */ + pci_read_config_word (pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, word); + pci_set_master (pdev); + + /* Next project is programming the onboard interrupt + * controllers. PDC hasn't done this for us, since it's using + * polled I/O. + */ + + /* Set PIC interrupts to edge triggered */ + printk ("Set PIC interrupts to edge triggered\n"); + pci_write_config_byte (pdev, TRIGGER_1, 0x0); + pci_write_config_byte (pdev, TRIGGER_2, 0x0); + + /* Disable all interrupt routing */ + printk ("Disable all interrupt routing\n"); + for (i = IR_LOW ; i < IR_HIGH ; i++) + pci_write_config_byte (pdev, i, 0x0); + + /* PIC1 Initialization Command Word register programming */ + printk ("PIC1 Initialization Command Word register programming\n"); + outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */ + outb (0x00,IC_PIC1+1); /* ICW2: N/A */ + outb (0x04,IC_PIC1+1); /* ICW3: Cascade */ + outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */ + + /* PIC2 Initialization Command Word register programming */ + outb (0x11,IC_PIC2+0); /* ICW1: ICW4 write req | ICW1 */ + outb (0x00,IC_PIC2+1); /* ICW2: N/A */ + outb (0x02,IC_PIC2+1); /* ICW3: Slave ID code */ + outb (0x01,IC_PIC2+1); /* ICW4: x86 mode */ + + /* Program Operational Control Words */ + outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */ + outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */ + + /* Set up interrupt routing */ + pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */ + pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */ + pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */ + pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE 1 on IRQ7 */ + + /* Set USB and IDE to level triggered interrupts, rest to edge */ + pci_write_config_byte (pdev, TRIGGER_1, 0x81); /* IRQ 1 and 7 */ + + +#ifdef CONFIG_SERIAL +// hellow(); +// superio_serial_init(); +#endif +printk("superio: line %i\n",__LINE__); + + pci_enable_device(pdev); + + if (request_irq(interrupt,superio_interrupt,SA_INTERRUPT,"SuperIO",NULL)) { + printk("superio: could not get irq\n"); + return; + } +} + + +static void superio_interrupt(int irq, void *devp, struct pt_regs *regs) +{ + u8 results,isr,device_interrupting; + + printk("In superio interrupt!\n"); + + + /* Poll the 8259 to see if there's an interrupt. */ + outb (OCW3_POLL,IC_PIC1+0); /* ICW4: x86 mode */ + + results = inb(IC_PIC1+1); + + if ((results & 0x80) == 0) { + /* Not a real interrupt. */ + /* Check the In Service bit */ + } + + /* Check the last three three bits to check which device is prompting the interrupt */ + + device_interrupting = results & 0x7; + + if (device_interrupting ==2) { + /* Ah, it's the slave PIC that's interrupting */ + /* Figure out which one */ + + } + + /* Check the approprate ISR bit to see if the device is actually interrupting */ + + if (device_interrupting < 8) { + outb(OCW3_ISR,IC_PIC1); + isr = inb(IC_PIC1); + } else { + outb(OCW3_ISR,IC_PIC2); + isr = inb(IC_PIC2); + } + if ((isr & 0x80) == 0) { + return; + } + + /* Call the appropriate device's interrupt */ + + return; +} + +static int +superio_serial_init(void) +{ + struct serial_struct *serial; + int retval; + + serial = kmalloc (sizeof (struct serial_struct), GFP_KERNEL); + + if (!serial) + return -ENOMEM; + + memset (serial, 0, sizeof (struct serial_struct)); + + serial->type = PORT_16550A; + serial->line = 0; + serial->iomem_base = (unsigned char *) sio.sp1_base; + +#ifdef CONFIG_SERIAL_CONSOLE + serial->port = serial->iomem_base; +#endif + serial->irq = 0; + serial->io_type = 0; + serial->flags = 0; + serial->xmit_fifo_size = 16; + serial->custom_divisor = 0; + serial->baud_base = BASE_BAUD; + + retval = register_serial (serial); + + if (retval) { + kfree (serial); + return -ENODEV; + } + + return retval; +} + + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * c-set-style: "K&R" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/syscall.S linux.ac/arch/parisc/kernel/syscall.S --- linux.vanilla/arch/parisc/kernel/syscall.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/kernel/syscall.S Tue Apr 3 17:54:34 2001 @@ -12,7 +12,6 @@ #include #include -#define __ASSEMBLY__ #include #include #include @@ -66,7 +65,10 @@ /* Save some registers for sigcontext and potential task switch (see entry.S for the details of which ones are - saved/restored) */ + saved/restored). TASK_PT_PSW is zeroed so we can see whether + a process is on a syscall or not. For an interrupt the real + PSW value is stored. This is needed for gdb and sys_ptrace. */ + STREG %r0, TASK_PT_PSW(%r1) STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */ STREG %r19, TASK_PT_GR19(%r1) STREG %r20, TASK_PT_GR20(%r1) @@ -159,11 +161,17 @@ .Ltracesys: tracesys: /* Need to save more registers so the debugger can see where we - * are. + * are. This saves only the lower 8 bits of PSW, so that the C + * bit is still clear on syscalls, and the D bit is set if this + * full register save path has been executed. We check the D + * bit on syscall_return_rfi to determine which registers to + * restore. An interrupt results in a full PSW saved with the + * C bit set, a non-straced syscall entry results in C and D clear + * in the saved PSW. */ ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */ - ssm 0,%r2 /* Lower 8 bits only!! */ - STREG %r2,TASK_PT_PSW(%r1) + ssm 0,%r2 + STREG %r2,TASK_PT_PSW(%r1) /* Lower 8 bits only!! */ STREG %r1,TASK_PT_CR30(%r1) mfsp %sr0,%r2 STREG %r2,TASK_PT_SR0(%r1) @@ -282,13 +290,13 @@ * narrow palinux. Use ENTRY_DIFF for those where a 32-bit specific * implementation is required on wide palinux. */ -#define ENTRY_SAME(_name_) .dword sys_##_name_ -#define ENTRY_DIFF(_name_) .dword sys32_##_name_ -#define ENTRY_UHOH(_name_) .dword sys32_unimplemented +#define ENTRY_SAME(_name_) .dword sys_/**/_name_ +#define ENTRY_DIFF(_name_) .dword sys32_/**/_name_ +#define ENTRY_UHOH(_name_) .dword sys32_/**/unimplemented #else -#define ENTRY_SAME(_name_) .word sys_##_name_ -#define ENTRY_DIFF(_name_) .word sys_##_name_ -#define ENTRY_UHOH(_name_) .word sys_##_name_ +#define ENTRY_SAME(_name_) .word sys_/**/_name_ +#define ENTRY_DIFF(_name_) .word sys_/**/_name_ +#define ENTRY_UHOH(_name_) .word sys_/**/_name_ #endif .align 8 @@ -391,8 +399,8 @@ ENTRY_DIFF(getrlimit) ENTRY_DIFF(getrusage) /* struct timeval and timezone are maybe?? consistent wide and narrow */ - ENTRY_SAME(gettimeofday) - ENTRY_SAME(settimeofday) + ENTRY_DIFF(gettimeofday) + ENTRY_DIFF(settimeofday) ENTRY_SAME(getgroups) /* 80 */ ENTRY_SAME(setgroups) /* struct socketaddr... */ @@ -402,11 +410,12 @@ ENTRY_DIFF(newlstat) ENTRY_SAME(readlink) /* 85 */ /* suspect we'll need some work for narrow shlibs on wide kernel */ + /* NOTE this doesn't get used when I boot 32-bit userspace */ + /* containing working shlib apps -- can this be nuked? */ ENTRY_UHOH(uselib) ENTRY_SAME(swapon) ENTRY_SAME(reboot) - /* argh! struct dirent contains a long */ - ENTRY_UHOH(old_readdir) + ENTRY_SAME(ni_syscall) /* I'm not certain about off_t... */ ENTRY_SAME(mmap) /* 90 */ ENTRY_SAME(munmap) @@ -461,12 +470,11 @@ ENTRY_SAME(delete_module) /* struct kernel_sym contains a long. Linus never heard of size_t? */ ENTRY_DIFF(get_kernel_syms) /* 130 */ - ENTRY_SAME(quotactl) + /* time_t inside struct dqblk */ + ENTRY_UHOH(quotactl) ENTRY_SAME(getpgid) ENTRY_SAME(fchdir) - /* bdflush(func, addr) where func has least-significant-bit set means - * addr is a pointer to long :-( */ - ENTRY_UHOH(bdflush) + ENTRY_SAME(bdflush) ENTRY_SAME(sysfs) /* 135 */ ENTRY_SAME(personality) ENTRY_SAME(ni_syscall) /* for afs_syscall */ @@ -479,12 +487,12 @@ ENTRY_DIFF(getdents) /* it is POSSIBLE that select will be OK because even though fd_set * contains longs, the macros and sizes are clever. */ - ENTRY_SAME(select) + ENTRY_DIFF(select) ENTRY_SAME(flock) ENTRY_SAME(msync) /* struct iovec contains pointers */ - ENTRY_UHOH(readv) /* 145 */ - ENTRY_UHOH(writev) + ENTRY_DIFF(readv) /* 145 */ + ENTRY_DIFF(writev) ENTRY_SAME(getsid) ENTRY_SAME(fdatasync) /* struct __sysctl_args is a mess */ @@ -532,8 +540,8 @@ ENTRY_SAME(setsockopt) ENTRY_SAME(getsockopt) /* struct msghdr contains pointers... */ - ENTRY_UHOH(sendmsg) - ENTRY_UHOH(recvmsg) + ENTRY_DIFF(sendmsg) + ENTRY_DIFF(recvmsg) ENTRY_SAME(semop) /* 185 */ ENTRY_SAME(semget) /* needs a more careful review */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/time.c linux.ac/arch/parisc/kernel/time.c --- linux.vanilla/arch/parisc/kernel/time.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/time.c Tue Apr 3 17:54:34 2001 @@ -10,6 +10,7 @@ * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills */ +#include #include #include #include @@ -30,69 +31,160 @@ #include +/* xtime and wall_jiffies keep wall-clock time */ +extern unsigned long wall_jiffies; extern rwlock_t xtime_lock; -static int timer_value; -static int timer_delta; +static long clocktick; /* timer cycles per tick */ +static long halftick; static struct pdc_tod tod_data __attribute__((aligned(8))); void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int old; - int lost = 0; - int cr16; - - old = timer_value; + long now = mfctl(16); + long next_tick; - cr16 = mfctl(16); - while((timer_value - cr16) < (timer_delta / 2)) { - timer_value += timer_delta; - lost++; + /* initialize next_tick to time at last clocktick */ + next_tick = cpu_data[smp_processor_id()].it_value; + /* since time passes between the interrupt and the mfctl() + * above, it is never true that last_tick + clocktick == now. If we + * never miss a clocktick, we could set next_tick = last_tick + clocktick + * but maybe we'll miss ticks, hence the loop. + * + * Variables are *signed*. + */ + while((next_tick - now) < halftick) { + next_tick += clocktick; + /* supposedly (wall_jiffies - jiffies) = "lost" ticks */ + /* but haven't checked it works for parisc */ + /* lost++; */ } - - mtctl(timer_value ,16); + mtctl(next_tick, 16); + cpu_data[smp_processor_id()].it_value = next_tick; +#if 0 + unsigned long now = mfctl(16); + /* this code will lose time by delaying the next clocktick by the */ + /* amount of time between the interrupt and the mfctl(16) above */ + cpu_data[smp_processor_id()].it_value = now; + + now += clocktick; + mtctl(now ,16); +#endif do_timer(regs); +#ifdef CONFIG_CHASSIS_LCD_LED led_interrupt_func(); +#endif } -void do_gettimeofday(struct timeval *tv) +/*** converted from ia64 ***/ +/* + * Return the number of micro-seconds that elapsed since the last + * update to wall time (aka xtime aka wall_jiffies). The xtime_lock + * must be at least read-locked when calling this routine. + */ +static inline unsigned long +gettimeoffset (void) { - unsigned long flags; - +#ifndef CONFIG_SMP + /* this might work for SMP but probably not -- should be ok on */ + /* all CPUs running timer interrupts, which may only be monarch */ + long last_tick; + long elapsed_cycles; + + /* this is the intended time of the next tick */ + last_tick = cpu_data[smp_processor_id()].it_value; + /* so subtract one tick */ + /* and account for possible difference between wall and actual time */ + last_tick += clocktick * (jiffies - wall_jiffies - 1); + elapsed_cycles = mfctl(16) - last_tick; + + /* the precision of this math could be improved */ + return elapsed_cycles / (PAGE0->mem_10msec / 10000); +#else + return 0; +#endif +} + +void +do_gettimeofday (struct timeval *tv) +{ + unsigned long flags, usec, sec; + read_lock_irqsave(&xtime_lock, flags); - tv->tv_sec = xtime.tv_sec; - tv->tv_usec = xtime.tv_usec; + { + usec = gettimeoffset(); + + 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) +void +do_settimeofday (struct timeval *tv) { write_lock_irq(&xtime_lock); - xtime.tv_sec = tv->tv_sec; - xtime.tv_usec = tv->tv_usec; + { + /* + * This is revolting. We need to set "xtime" + * correctly. However, the value in this location is + * the value at the most recent update of wall time. + * Discover what correction gettimeofday would have + * done, and then undo it! + */ + tv->tv_usec -= gettimeoffset(); + tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); + + while (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + 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); } + void __init time_init(void) { - timer_delta = (100 * PAGE0->mem_10msec) / HZ; + unsigned long next_tick; + + clocktick = (100 * PAGE0->mem_10msec) / HZ; + halftick = clocktick / 2; - /* make the first timer interrupt go off in one second */ - timer_value = mfctl(16) + (HZ * timer_delta); - mtctl(timer_value, 16); + /* make the first timer interrupt go off in one second + ** Used for bogomips calculation. + */ + cpu_data[smp_processor_id()].it_value = next_tick = mfctl(16); + next_tick += HZ * clocktick; + /* kick off Itimer (CR16) */ + mtctl(next_tick, 16); if(pdc_tod_read(&tod_data) == 0) { + write_lock_irq(&xtime_lock); xtime.tv_sec = tod_data.tod_sec; xtime.tv_usec = tod_data.tod_usec; + write_unlock_irq(&xtime_lock); } else { printk(KERN_ERR "Error reading tod clock\n"); xtime.tv_sec = 0; xtime.tv_usec = 0; } - } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/kernel/traps.c linux.ac/arch/parisc/kernel/traps.c --- linux.vanilla/arch/parisc/kernel/traps.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/kernel/traps.c Tue Apr 3 17:54:34 2001 @@ -41,13 +41,6 @@ #endif /* CONFIG_KWDB */ -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - - void page_exception(void); /* @@ -95,7 +88,7 @@ for (i = 0; i < 8; i += 4) { int j; - printk("sr%d-%d\t", i, i + 4); + printk("sr%d-%d\t", i, i + 3); for (j = 0; j < 4; j++) { printk(RFMT, regs->sr[i + j]); } @@ -146,14 +139,6 @@ do_exit(SIGSEGV); } -asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code) -{ -} - -asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) -{ -} - #ifndef CONFIG_MATH_EMULATION asmlinkage void math_emulate(long arg) @@ -167,24 +152,6 @@ return syscall(regs); } -struct { - int retval; - - int (*func) (void *, struct pt_regs *); - void * data; -} ipi_action[NR_CPUS]; - -void ipi_interrupt(int irq, void *unused, struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - - if(!ipi_action[cpu].func) - BUG(); - - ipi_action[cpu].retval = - ipi_action[cpu].func(ipi_action[cpu].data, regs); -} - /* gdb uses break 4,8 */ #define GDB_BREAK_INSN 0x10004 void handle_gdb_break(struct pt_regs *regs, int wot) @@ -205,7 +172,6 @@ struct save_state ssp; #endif /* CONFIG_KWDB */ - flush_all_caches(); switch(iir) { case 0x00: /* show registers, halt */ @@ -571,9 +537,14 @@ die_if_kernel("Floating point exception", regs, 0); /* quiet */ handle_fpe(regs); return; - case 15: - case 16: /* Non-Access TLB miss faulting address is in IOR */ + case 17: + /* TODO: Still need to add slow path emulation code here */ + + fault_address = regs->ior; + parisc_terminate("Non access data tlb fault!",regs,code,fault_address); + + case 15: case 26: fault_address = regs->ior; fault_space = regs->isr; @@ -684,27 +655,7 @@ do_page_fault(regs, code, fault_address); - /* - * This should not be necessary. - * However, we do not currently - * implement flush_page_to_ram. - * - * The problem is that if we just - * brought in some code through the - * D-cache, the I-cache may not see - * it since it hasn't been flushed - * to ram. - */ - -/* flush_all_caches(); */ - -#if 0 - printk("returning %p\n", regs); -/* show_regs(regs); */ -#endif - return; - } void show_stack(unsigned long sp) @@ -870,11 +821,8 @@ void __init trap_init(void) { - volatile long eiem; void *iva; - printk("trap_init\n"); - if (boot_cpu_data.cpu_type >= pcxu) iva = (void *) &fault_vector_20; else @@ -886,10 +834,4 @@ if(check_ivt(iva)) panic("IVT invalid"); - - mtctl(0, 30); - mtctl(90000000, 16); - set_eiem(-1L); - mtctl(-1L, 23); - asm volatile ("rsm 0,%0" : "=r" (eiem)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/lib/Makefile linux.ac/arch/parisc/lib/Makefile --- linux.vanilla/arch/parisc/lib/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/lib/Makefile Tue Apr 3 17:54:34 2001 @@ -4,10 +4,6 @@ L_TARGET = lib.a -L_OBJS = lusercopy.o bitops.o checksum.o - - -.S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o +obj-y := lusercopy.o bitops.o checksum.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/lib/bitops.c linux.ac/arch/parisc/lib/bitops.c --- linux.vanilla/arch/parisc/lib/bitops.c Wed Dec 6 19:46:39 2000 +++ linux.ac/arch/parisc/lib/bitops.c Tue Apr 3 17:54:34 2001 @@ -1,7 +1,10 @@ -/* atomic.c: atomic operations which got too long to be inlined all over - * the place. +/* + * bitops.c: atomic operations which got too long to be inlined all over + * the place. * - * Copyright 1999 Philipp Rumpf (prumpf@tux.org */ + * Copyright 1999 Philipp Rumpf (prumpf@tux.org) + * Copyright 2000 Grant Grundler (grundler@cup.hp.com) + */ #include #include @@ -17,44 +20,65 @@ spinlock_t __atomic_lock = SPIN_LOCK_UNLOCKED; -#ifndef __LP64__ -unsigned long __xchg(unsigned long x, unsigned long *ptr, int size) +#ifdef __LP64__ +unsigned long __xchg64(unsigned long x, unsigned long *ptr) { unsigned long temp, flags; - if (size != sizeof x) { - printk("__xchg called with bad pointer\n"); - } - spin_lock_irqsave(&__atomic_lock, flags); + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); temp = *ptr; *ptr = x; - spin_unlock_irqrestore(&__atomic_lock, flags); + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); return temp; } -#else -unsigned long __xchg(unsigned long x, unsigned long *ptr, int size) +#endif + +unsigned long __xchg32(int x, int *ptr) { - unsigned long temp, flags; - unsigned int *ptr32; + unsigned long flags; + unsigned long temp; + + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + (long) temp = (long) *ptr; /* XXX - sign extension wanted? */ + *ptr = x; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return temp; +} + + +unsigned long __xchg8(char x, char *ptr) +{ + unsigned long flags; + unsigned long temp; - if (size == 8) { -try_long: - spin_lock_irqsave(&__atomic_lock, flags); - temp = *ptr; - *ptr = x; - spin_unlock_irqrestore(&__atomic_lock, flags); - return temp; - } - if (size == 4) { - ptr32 = (unsigned int *)ptr; - spin_lock_irqsave(&__atomic_lock, flags); - temp = (unsigned long)*ptr32; - *ptr32 = (unsigned int)x; - spin_unlock_irqrestore(&__atomic_lock, flags); - return temp; - } + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + (long) temp = (long) *ptr; /* XXX - sign extension wanted? */ + *ptr = x; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return temp; +} + + +#ifdef __LP64__ +unsigned long __cmpxchg_u64(volatile long *ptr, unsigned long old, unsigned long new) +{ + unsigned long flags; - printk("__xchg called with bad pointer\n"); - goto try_long; + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + old = *ptr; + *ptr = new; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return (old == new); } #endif + +unsigned long __cmpxchg_u32(volatile int *ptr, int old, int new) +{ + unsigned long flags; + + SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags); + old = *ptr; + *ptr = new; + SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags); + return (old == new); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/lib/lusercopy.S linux.ac/arch/parisc/lib/lusercopy.S --- linux.vanilla/arch/parisc/lib/lusercopy.S Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/lib/lusercopy.S Tue Apr 3 17:54:34 2001 @@ -82,7 +82,11 @@ ldo 1(%r24),%r24 .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(2b-1b) +#else .word 1b,(2b-1b) +#endif .previous .procend @@ -123,7 +127,11 @@ nop .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(2b-1b) +#else .word 1b,(2b-1b) +#endif .previous .procend @@ -161,8 +169,13 @@ ldi -EFAULT,%r28 .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(3b-1b) + .dword 2b,(3b-2b) +#else .word 1b,(3b-1b) - .word 2b,(2b-1b) + .word 2b,(3b-2b) +#endif .previous .procend @@ -194,7 +207,11 @@ ldo 1(%r25),%r25 .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(2b-1b) +#else .word 1b,(2b-1b) +#endif .previous .procend @@ -233,8 +250,13 @@ copy %r24,%r26 /* reset r26 so 0 is returned on fault */ .section __ex_table,"a" +#ifdef __LP64__ + .dword 1b,(3b-1b) + .dword 2b,(3b-2b) +#else .word 1b,(3b-1b) - .word 2b,(2b-1b) + .word 2b,(3b-2b) +#endif .previous .procend diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/Makefile linux.ac/arch/parisc/mm/Makefile --- linux.vanilla/arch/parisc/mm/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/Makefile Tue Apr 3 17:54:34 2001 @@ -8,6 +8,6 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o kmap.o extable.o +obj-y := init.o fault.o extable.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/fault.c linux.ac/arch/parisc/mm/fault.c --- linux.vanilla/arch/parisc/mm/fault.c Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/parisc/mm/fault.c Tue Apr 3 17:54:34 2001 @@ -114,48 +114,6 @@ #undef isGraphicsFlushRead #undef BITSSET -/* This is similar to expand_stack(), except that it is for stacks - * that grow upwards. - */ - -static inline int expand_stackup(struct vm_area_struct * vma, unsigned long address) -{ - unsigned long grow; - - address += 4 + PAGE_SIZE - 1; - address &= PAGE_MASK; - grow = (address - vma->vm_end) >> PAGE_SHIFT; - if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || - ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) - return -ENOMEM; - vma->vm_end = address; - vma->vm_mm->total_vm += grow; - if (vma->vm_flags & VM_LOCKED) - vma->vm_mm->locked_vm += grow; - return 0; -} - - -/* This is similar to find_vma(), except that it understands that stacks - * grow up rather than down. - * XXX Optimise by making use of cache and avl tree as per find_vma(). - */ - -struct vm_area_struct * pa_find_vma(struct mm_struct * mm, unsigned long addr) -{ - struct vm_area_struct *vma = NULL; - - if (mm) { - vma = mm->mmap; - if (!vma || addr < vma->vm_start) - return NULL; - while (vma->vm_next && addr >= vma->vm_next->vm_start) - vma = vma->vm_next; - } - return vma; -} - - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -163,10 +121,30 @@ */ extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long); +#if 0 +/* This is the treewalk to find a vma which is the highest that has + * a start < addr. We're using find_vma_prev instead right now, but + * we might want to use this at some point in the future. Probably + * not, but I want it committed to CVS so I don't lose it :-) + */ + while (tree != vm_avl_empty) { + if (tree->vm_start > addr) { + tree = tree->vm_avl_left; + } else { + prev = tree; + if (prev->vm_next == NULL) + break; + if (prev->vm_next->vm_start > addr) + break; + tree = tree->vm_avl_right; + } + } +#endif + void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address) { - struct vm_area_struct * vma; + struct vm_area_struct *vma, *prev_vma; struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; const struct exception_table_entry *fix; @@ -176,13 +154,9 @@ goto no_context; down_read(&mm->mmap_sem); - vma = pa_find_vma(mm, address); - if (!vma) - goto bad_area; - if (address < vma->vm_end) - goto good_area; - if (!(vma->vm_flags & VM_GROWSUP) || expand_stackup(vma, address)) - goto bad_area; + vma = find_vma_prev(mm, address, &prev_vma); + if (!vma || address < vma->vm_start) + goto check_expansion; /* * Ok, we have a good vm_area for this memory access. We still need to * check the access permissions. @@ -221,6 +195,11 @@ up_read(&mm->mmap_sem); return; +check_expansion: + vma = prev_vma; + if (vma && (expand_stack(vma, address) == 0)) + goto good_area; + /* * Something tried to access memory that isn't in our memory map.. */ @@ -230,8 +209,12 @@ if (user_mode(regs)) { struct siginfo si; - printk("\ndo_page_fault() pid=%d command='%s'\n", - tsk->pid, tsk->comm); + printk("\ndo_page_fault() pid=%d command='%s' type=%d address=0x%08lx\n", + tsk->pid, tsk->comm, code, address); + if (vma) { + printk("vm_start = 0x%08lx, vm_end = 0x%08lx\n", + vma->vm_start, vma->vm_end); + } show_regs(regs); /* FIXME: actually we need to get the signo and code correct */ si.si_signo = SIGSEGV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/init.c linux.ac/arch/parisc/mm/init.c --- linux.vanilla/arch/parisc/mm/init.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/init.c Tue Apr 3 17:54:34 2001 @@ -19,6 +19,9 @@ #include #include +#include + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; extern unsigned long max_pfn, mem_max; @@ -388,53 +391,97 @@ } } -#define NR_SPACE_IDS 8192 +/* + * Currently we have a one-to-one relationship between space id's and + * protection id's. Older parisc chips (PCXS, PCXT, PCXL, PCXL2) only + * support 15 bit protection id's, so that is the limiting factor. + * We could do some type of run time initialization here, but let's + * make sure there is a need first. + */ + +#define NR_SPACE_IDS 32768 +#define SID_ARRAY_SIZE (NR_SPACE_IDS / (8 * sizeof(long))) -static unsigned long space_id[NR_SPACE_IDS / (8 * sizeof(long))]; +static unsigned long space_id[SID_ARRAY_SIZE] = { 1 }; /* disallow space 0 */ +static unsigned long dirty_space_id[SID_ARRAY_SIZE]; static unsigned long space_id_index; -static unsigned long free_space_ids = NR_SPACE_IDS; +static unsigned long free_space_ids = NR_SPACE_IDS - 1; +static unsigned long dirty_space_ids = 0; -/* - * XXX: We should probably unfold the set_bit / test_bit / clear_bit - * locking out of these two functions and have a single spinlock on the - * space_id data structures. - * - * Don't bother. This is all going to be significantly changed in the - * very near future. - */ +static spinlock_t sid_lock = SPIN_LOCK_UNLOCKED; #define SPACEID_SHIFT (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS) - 32) unsigned long alloc_sid(void) { unsigned long index; + spin_lock(&sid_lock); - if (free_space_ids == 0) - BUG(); + if (free_space_ids == 0) { + if (dirty_space_ids != 0) { + spin_unlock(&sid_lock); + flush_tlb_all(); /* flush_tlb_all() calls recycle_sids() */ + spin_lock(&sid_lock); + } + if (free_space_ids == 0) + BUG(); + } free_space_ids--; - do { - index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index); - } while(test_and_set_bit(index, space_id)); - + index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index); + space_id[index >> SHIFT_PER_LONG] |= (1L << (index & (BITS_PER_LONG - 1))); space_id_index = index; + spin_unlock(&sid_lock); + return index << SPACEID_SHIFT; } void free_sid(unsigned long spaceid) { unsigned long index = spaceid >> SPACEID_SHIFT; - if (index < 0) - BUG(); - clear_bit(index, space_id); + spin_lock(&sid_lock); + + dirty_space_id[index >> SHIFT_PER_LONG] |= (1L << (index & (BITS_PER_LONG - 1))); + dirty_space_ids++; + + spin_unlock(&sid_lock); +} + +/* + * flush_tlb_all() calls recycle_sids(), since whenever the entire tlb is + * purged, we can safely reuse the space ids that were released but + * not flushed from the tlb. + */ + +static void recycle_sids(void) +{ + int i; + + /* NOTE: sid_lock must be held upon entry */ - if (space_id_index > index) { - space_id_index = index; + if (dirty_space_ids != 0) { + for (i = 0; i < SID_ARRAY_SIZE; i++) { + space_id[i] ^= dirty_space_id[i]; + dirty_space_id[i] = 0; + } + + free_space_ids += dirty_space_ids; + dirty_space_ids = 0; + space_id_index = 0; } - free_space_ids++; +} + +extern void __flush_tlb_all(void); + +void flush_tlb_all(void) +{ + spin_lock(&sid_lock); + __flush_tlb_all(); + recycle_sids(); + spin_unlock(&sid_lock); } #ifdef CONFIG_BLK_DEV_INITRD diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/kmap.c linux.ac/arch/parisc/mm/kmap.c --- linux.vanilla/arch/parisc/mm/kmap.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/parisc/mm/kmap.c Thu Jan 1 01:00:00 1970 @@ -1,143 +0,0 @@ -/* -** Stolen mostly from arch/parisc/kernel/pci-dma.c -*/ - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include /* get_order */ - -#undef flush_cache_all -#define flush_cache_all flush_all_caches - -typedef void (*pte_iterator_t) (pte_t * pte, unsigned long arg); - -#if 0 -/* XXX This routine could be used with iterate_page() to replace - * unmap_uncached_page() and save a little code space but I didn't - * do that since I'm not certain whether this is the right path. -PB - */ -static void unmap_cached_pte(pte_t * pte, unsigned long arg) -{ - pte_t page = *pte; - pte_clear(pte); - if (!pte_none(page)) { - if (pte_present(page)) { - unsigned long map_nr = pte_pagenr(page); - if (map_nr < max_mapnr) - __free_page(mem_map + map_nr); - } else { - printk(KERN_CRIT - "Whee.. Swapped out page in kernel page table\n"); - } - } -} -#endif - -/* These two routines should probably check a few things... */ -static void set_uncached(pte_t * pte, unsigned long arg) -{ - pte_val(*pte) |= _PAGE_NO_CACHE; -} - -static void set_cached(pte_t * pte, unsigned long arg) -{ - pte_val(*pte) &= ~_PAGE_NO_CACHE; -} - -static inline void iterate_pte(pmd_t * pmd, unsigned long address, - unsigned long size, pte_iterator_t op, - unsigned long arg) -{ - pte_t *pte; - unsigned long end; - - if (pmd_none(*pmd)) - return; - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - return; - } - pte = pte_offset(pmd, address); - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - do { - op(pte, arg); - address += PAGE_SIZE; - pte++; - } while (address < end); -} - -static inline void iterate_pmd(pgd_t * dir, unsigned long address, - unsigned long size, pte_iterator_t op, - unsigned long arg) -{ - pmd_t *pmd; - unsigned long end; - - if (pgd_none(*dir)) - return; - if (pgd_bad(*dir)) { - pgd_ERROR(*dir); - pgd_clear(dir); - return; - } - pmd = pmd_offset(dir, address); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - do { - iterate_pte(pmd, address, end - address, op, arg); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); -} - -static void iterate_pages(unsigned long address, unsigned long size, - pte_iterator_t op, unsigned long arg) -{ - pgd_t *dir; - unsigned long end = address + size; - - dir = pgd_offset_k(address); - flush_cache_all(); - do { - iterate_pmd(dir, address, end - address, op, arg); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - dir++; - } while (address && (address < end)); - flush_tlb_all(); -} - -void -kernel_set_cachemode(unsigned long vaddr, unsigned long size, int what) -{ - switch (what) { - case IOMAP_FULL_CACHING: - iterate_pages(vaddr, size, set_cached, 0); - flush_tlb_range(&init_mm, vaddr, size); - break; - case IOMAP_NOCACHE_SER: - iterate_pages(vaddr, size, set_uncached, 0); - flush_tlb_range(&init_mm, vaddr, size); - break; - default: - printk(KERN_CRIT - "kernel_set_cachemode mode %d not understood\n", - what); - break; - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/pa11.c linux.ac/arch/parisc/mm/pa11.c --- linux.vanilla/arch/parisc/mm/pa11.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/pa11.c Thu Jan 1 01:00:00 1970 @@ -1,170 +0,0 @@ -/* $Id: pa11.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $ - * - * pa11.c: PA 1.1 specific mmu/cache code. - * - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -extern unsigned long mips_tlb_entries; - -/* page functions */ -void pa11_clear_page(unsigned long page) -{ -} - -static void pa11_copy_page(unsigned long to, unsigned long from) -{ -} - -/* Cache operations. */ -static inline void pa11_flush_cache_all(void) { } -static void pa11_flush_cache_mm(struct mm_struct *mm) { } -static void pa11_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ -} - -static void pa11_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ -} - -static void pa11_flush_page_to_ram(unsigned long page) -{ -} - -static void pa11_flush_cache_sigtramp(unsigned long page) -{ -} - -/* TLB operations. */ -static inline void pa11_flush_tlb_all(void) -{ - unsigned long flags; - int entry; - - save_and_cli(flags); -/* Here we will need to flush all the TLBs */ - restore_flags(flags); -} - -static void pa11_flush_tlb_mm(struct mm_struct *mm) -{ -/* This is what the MIPS does.. Is it the right thing for PA-RISC? */ - if(mm == current->mm) - pa11_flush_tlb_all(); -} - -static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm == current->mm) - pa11_flush_tlb_all(); -} - -static void pa11_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if(vma->vm_mm == current->mm) - pa11_flush_tlb_all(); -} - -static void pa11_load_pgd(unsigned long pg_dir) -{ - unsigned long flags; - /* We need to do the right thing here */ -} - -/* - * Initialize new page directory with pointers to invalid ptes - */ -static void pa11_pgd_init(unsigned long page) -{ - unsigned long dummy1, dummy2; - -} - -static void pa11_update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - pa11_flush_tlb_page(vma, address); -} - -static void pa11_show_regs(struct pt_regs * regs) -{ - /* - * Saved main processor registers - */ - printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], - (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], - (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], - (unsigned long) regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], - (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], - (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], - (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], - (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], - (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], - (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], - (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], - (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); - - /* - * Saved cp0 registers - */ - printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", - (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, - (unsigned int) regs->cp0_cause); -} - -static int pa11_user_mode(struct pt_regs *regs) -{ - /* Return user mode stuff?? */ -} - -__initfunc(void ld_mmu_pa11(void)) -{ - - /* Taken directly from the MIPS arch.. Lots of bad things here */ - clear_page = pa11_clear_page; - copy_page = pa11_copy_page; - - flush_cache_all = pa11_flush_cache_all; - flush_cache_mm = pa11_flush_cache_mm; - flush_cache_range = pa11_flush_cache_range; - flush_cache_page = pa11_flush_cache_page; - flush_cache_sigtramp = pa11_flush_cache_sigtramp; - flush_page_to_ram = pa11_flush_page_to_ram; - - flush_tlb_all = pa11_flush_tlb_all; - flush_tlb_mm = pa11_flush_tlb_mm; - flush_tlb_range = pa11_flush_tlb_range; - flush_tlb_page = pa11_flush_tlb_page; - pa11_asid_setup(); - - load_pgd = pa11_load_pgd; - pgd_init = pa11_pgd_init; - update_mmu_cache = pa11_update_mmu_cache; - - show_regs = pa11_show_regs; - - add_wired_entry = pa11_add_wired_entry; - - user_mode = pa11_user_mode; - flush_tlb_all(); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/mm/pa20.c linux.ac/arch/parisc/mm/pa20.c --- linux.vanilla/arch/parisc/mm/pa20.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/mm/pa20.c Thu Jan 1 01:00:00 1970 @@ -1,170 +0,0 @@ -/* $Id: pa20.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $ - * - * pa20.c: PA 2.0 specific mmu/cache code. - * - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -extern unsigned long mips_tlb_entries; - -/* page functions */ -void pa20_clear_page(unsigned long page) -{ -} - -static void pa20_copy_page(unsigned long to, unsigned long from) -{ -} - -/* Cache operations. */ -static inline void pa20_flush_cache_all(void) { } -static void pa20_flush_cache_mm(struct mm_struct *mm) { } -static void pa20_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ -} - -static void pa20_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ -} - -static void pa20_flush_page_to_ram(unsigned long page) -{ -} - -static void pa20_flush_cache_sigtramp(unsigned long page) -{ -} - -/* TLB operations. */ -static inline void pa20_flush_tlb_all(void) -{ - unsigned long flags; - int entry; - - save_and_cli(flags); -/* Here we will need to flush all the TLBs */ - restore_flags(flags); -} - -static void pa20_flush_tlb_mm(struct mm_struct *mm) -{ -/* This is what the MIPS does.. Is it the right thing for PA-RISC? */ - if(mm == current->mm) - pa20_flush_tlb_all(); -} - -static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm == current->mm) - pa20_flush_tlb_all(); -} - -static void pa20_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if(vma->vm_mm == current->mm) - pa20_flush_tlb_all(); -} - -static void pa20_load_pgd(unsigned long pg_dir) -{ - unsigned long flags; - /* We need to do the right thing here */ -} - -/* - * Initialize new page directory with pointers to invalid ptes - */ -static void pa20_pgd_init(unsigned long page) -{ - unsigned long dummy1, dummy2; - -} - -static void pa20_update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - pa20_flush_tlb_page(vma, address); -} - -static void pa20_show_regs(struct pt_regs * regs) -{ - /* - * Saved main processor registers - */ - printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], - (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], - (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], - (unsigned long) regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], - (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], - (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], - (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], - (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], - (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], - (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], - (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], - (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); - - /* - * Saved cp0 registers - */ - printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", - (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, - (unsigned int) regs->cp0_cause); -} - -static int pa20_user_mode(struct pt_regs *regs) -{ - /* Return user mode stuff?? */ -} - -__initfunc(void ld_mmu_pa20(void)) -{ - - /* Taken directly from the MIPS arch.. Lots of bad things here */ - clear_page = pa20_clear_page; - copy_page = pa20_copy_page; - - flush_cache_all = pa20_flush_cache_all; - flush_cache_mm = pa20_flush_cache_mm; - flush_cache_range = pa20_flush_cache_range; - flush_cache_page = pa20_flush_cache_page; - flush_cache_sigtramp = pa20_flush_cache_sigtramp; - flush_page_to_ram = pa20_flush_page_to_ram; - - flush_tlb_all = pa20_flush_tlb_all; - flush_tlb_mm = pa20_flush_tlb_mm; - flush_tlb_range = pa20_flush_tlb_range; - flush_tlb_page = pa20_flush_tlb_page; - pa20_asid_setup(); - - load_pgd = pa20_load_pgd; - pgd_init = pa20_pgd_init; - update_mmu_cache = pa20_update_mmu_cache; - - show_regs = pa20_show_regs; - - add_wired_entry = pa20_add_wired_entry; - - user_mode = pa20_user_mode; - flush_tlb_all(); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/tools/Makefile linux.ac/arch/parisc/tools/Makefile --- linux.vanilla/arch/parisc/tools/Makefile Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/tools/Makefile Tue Apr 3 17:54:34 2001 @@ -22,7 +22,7 @@ offset.s: offset.c -clean: +distclean clean: rm -f offset.[hs] $(TARGET).new include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/tools/offset.c linux.ac/arch/parisc/tools/offset.c --- linux.vanilla/arch/parisc/tools/offset.c Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/tools/offset.c Tue Apr 3 17:54:34 2001 @@ -13,6 +13,7 @@ #include #include #include +#include #define text(t) __asm__("\n@@@" t) #define _offset(type, member) (&(((type *)NULL)->member)) @@ -260,6 +261,34 @@ offset("#define IRQSTAT_SI_ACTIVE ", irq_cpustat_t, __softirq_active); offset("#define IRQSTAT_SI_MASK ", irq_cpustat_t, __softirq_mask); size ("#define IRQSTAT_SZ ", irq_cpustat_t); + linefeed; +} + +void output_cache_info_defines(void) +{ + text("/* PARISC pdc_cache_info offsets. */"); + offset("#define ICACHE_BASE ", struct pdc_cache_info, ic_base); + offset("#define ICACHE_STRIDE ", struct pdc_cache_info, ic_stride); + offset("#define ICACHE_COUNT ", struct pdc_cache_info, ic_count); + offset("#define ICACHE_LOOP ", struct pdc_cache_info, ic_loop); + offset("#define DCACHE_BASE ", struct pdc_cache_info, dc_base); + offset("#define DCACHE_STRIDE ", struct pdc_cache_info, dc_stride); + offset("#define DCACHE_COUNT ", struct pdc_cache_info, dc_count); + offset("#define DCACHE_LOOP ", struct pdc_cache_info, dc_loop); + offset("#define ITLB_SID_BASE ", struct pdc_cache_info, it_sp_base); + offset("#define ITLB_SID_STRIDE ", struct pdc_cache_info, it_sp_stride); + offset("#define ITLB_SID_COUNT ", struct pdc_cache_info, it_sp_count); + offset("#define ITLB_OFF_BASE ", struct pdc_cache_info, it_off_base); + offset("#define ITLB_OFF_STRIDE ", struct pdc_cache_info, it_off_stride); + offset("#define ITLB_OFF_COUNT ", struct pdc_cache_info, it_off_count); + offset("#define ITLB_LOOP ", struct pdc_cache_info, it_loop); + offset("#define DTLB_SID_BASE ", struct pdc_cache_info, dt_sp_base); + offset("#define DTLB_SID_STRIDE ", struct pdc_cache_info, dt_sp_stride); + offset("#define DTLB_SID_COUNT ", struct pdc_cache_info, dt_sp_count); + offset("#define DTLB_OFF_BASE ", struct pdc_cache_info, dt_off_base); + offset("#define DTLB_OFF_STRIDE ", struct pdc_cache_info, dt_off_stride); + offset("#define DTLB_OFF_COUNT ", struct pdc_cache_info, dt_off_count); + offset("#define DTLB_LOOP ", struct pdc_cache_info, dt_loop); linefeed; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/parisc/vmlinux.lds linux.ac/arch/parisc/vmlinux.lds --- linux.vanilla/arch/parisc/vmlinux.lds Tue Dec 5 20:29:39 2000 +++ linux.ac/arch/parisc/vmlinux.lds Tue Apr 3 17:54:34 2001 @@ -1,5 +1,4 @@ /* ld script to make hppa Linux kernel */ -OUTPUT_FORMAT("elf32-hppa") OUTPUT_ARCH(hppa) ENTRY(_stext) SECTIONS @@ -15,7 +14,6 @@ _text = .; /* Text and read-only data */ .text BLOCK(16) : { *(.text*) - *(.PARISC.unwind) *(.fixup) *(.lock.text) /* out-of-line lock text */ *(.gnu.warning) @@ -63,6 +61,7 @@ .bss : { *(.bss) *(COMMON) } /* BSS */ + .PARISC.unwind : { *(.PARISC.unwind) } _end = . ; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/Makefile linux.ac/arch/ppc/Makefile --- linux.vanilla/arch/ppc/Makefile Mon Jan 22 23:41:14 2001 +++ linux.ac/arch/ppc/Makefile Tue Apr 3 23:32:42 2001 @@ -31,7 +31,7 @@ endif ifdef CONFIG_8xx -CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io +CFLAGS := $(CFLAGS) -mcpu=860 endif ifdef CONFIG_PPC64BRIDGE @@ -144,6 +144,9 @@ .PHONY: clean_config clean_config: rm -f .config arch/ppc/defconfig + +gemini_config: clean_config + cp -f arch/ppc/configs/gemini_defconfig arch/ppc/defconfig pmac_config: clean_config cp -f arch/ppc/configs/pmac_defconfig arch/ppc/defconfig diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/amiga/config.c linux.ac/arch/ppc/amiga/config.c --- linux.vanilla/arch/ppc/amiga/config.c Tue Nov 28 01:57:34 2000 +++ linux.ac/arch/ppc/amiga/config.c Tue Apr 3 17:54:34 2001 @@ -743,20 +743,6 @@ return 0; } -void dbprintf(const char *fmt , ...) -{ - static char buf[1024]; - va_list args; - extern void console_print (const char *str); - extern int vsprintf(char * buf, const char * fmt, va_list args); - - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - - console_print (buf); -} - static NORET_TYPE void amiga_reset( void ) ATTRIB_NORET; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/Makefile linux.ac/arch/ppc/boot/Makefile --- linux.vanilla/arch/ppc/boot/Makefile Mon Jan 22 23:41:14 2001 +++ linux.ac/arch/ppc/boot/Makefile Tue Apr 3 23:32:42 2001 @@ -31,6 +31,12 @@ TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE) endif +ifeq ($(CONFIG_SMP),y) +TFTPSIMAGE=/tftpboot/sImage.smp +else +TFTPSIMAGE=/tftpboot/sImage +endif + ifeq ($(CONFIG_PPC64BRIDGE),y) MSIZE=.64 else @@ -70,8 +76,24 @@ --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.initrd.tmp $@ rm zvmlinux.initrd.tmp +ifdef CONFIG_GEMINI + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.initrd.tmp svmlinux.initrd.tmp + ./mksimage svmlinux.initrd.tmp ../coffboot/vmlinux.gz ramdisk.image.gz \ + -o svmlinux.initrd > sImage.map + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh sioffset initrd` \ + -DINITRD_SIZE=`sh sisize initrd` \ + -DZIMAGE_OFFSET=`sh sioffset zimage` \ + -DZIMAGE_SIZE=`sh sisize zimage` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.initrd.tmp svmlinux.initrd.tmp + ./mksimage svmlinux.initrd.tmp ../coffboot/vmlinux.gz ramdisk.image.gz \ + -o svmlinux.initrd > /dev/null + rm svmlinux.initrd.tmp zvmlinux.initrd.tmp sImage.map +endif -zImage: zvmlinux mkprep +zImage: zvmlinux mkprep sImage mksimage ifdef CONFIG_ALL_PPC ./mkprep -pbp zvmlinux zImage endif @@ -80,12 +102,17 @@ gzip $(GZIP_FLAGS) vmapus endif +sImage: ../../../vmlinux +ifdef CONFIG_GEMINI + $(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage +endif + zImage.initrd: zvmlinux.initrd mkprep ifdef CONFIG_ALL_PPC ./mkprep -pbp zvmlinux.initrd zImage.initrd endif -zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz +zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz mksimage # # build the boot loader image and then compute the offset into it # for the kernel image @@ -105,6 +132,19 @@ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.tmp $@ rm zvmlinux.tmp +ifdef CONFIG_GEMINI + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.tmp svmlinux.tmp + ./mksimage svmlinux.tmp ../coffboot/vmlinux.gz -o svmlinux > sImage.map + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh sioffset zimage` \ + -DZIMAGE_SIZE=`sh sisize zimage` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) -I elf32-powerpc -O binary zvmlinux.tmp svmlinux.tmp + ./mksimage svmlinux.tmp ../coffboot/vmlinux.gz -o svmlinux > /dev/null + rm svmlinux.tmp sImage.map zvmlinux.tmp +endif floppy: $(TOPDIR)/vmlinux zImage dd if=zImage of=/dev/fd0H1440 bs=64b @@ -112,16 +152,22 @@ mkprep : mkprep.c $(HOSTCC) -o mkprep mkprep.c +mksimage: mksimage.c + $(HOSTCC) -o mksimage mksimage.c + znetboot : zImage ifdef CONFIG_ALL_PPC cp zImage $(TFTPIMAGE) endif +ifdef CONFIG_GEMINI + cp sImage $(TFTPSIMAGE) +endif znetboot.initrd : zImage.initrd cp zImage.initrd $(TFTPIMAGE) clean: - rm -f vmlinux* zvmlinux* mkprep zImage* + rm -f vmlinux* zvmlinux* mkprep zImage* sImage* fastdep: $(TOPDIR)/scripts/mkdep *.[Sch] > .depend diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/mksimage.c linux.ac/arch/ppc/boot/mksimage.c --- linux.vanilla/arch/ppc/boot/mksimage.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/boot/mksimage.c Tue Apr 3 23:32:42 2001 @@ -0,0 +1,124 @@ +/* + * + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SIZE 1024 +#define BLOCK_ALIGN(x) (((x)+SIZE-1)&(~(SIZE-1))) + +static void +die(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + exit(1); +} + +static void +usage(void) +{ + printf("Usage: mkbinimg -o \n"); + exit(1); +} + +static int +copy_blocks(int ifd, int ofd, unsigned long *offset, unsigned long *size) +{ + off_t cur; + int amt; + unsigned long len = 0; + char buffer[SIZE]; + + cur = lseek(ofd, 0, SEEK_CUR); + + if (cur % SIZE) { + cur = BLOCK_ALIGN(cur); + cur = lseek(ofd, cur, SEEK_SET); + } + + *offset = (unsigned long) cur; + while((amt = read(ifd, buffer, SIZE)) > 0) { + write(ofd, buffer, amt); + len += amt; + } + *size = len; + return 0; +} + + +int +main(int argc, char *argv[]) +{ + char *kernel, *loader, *rdimage = NULL; + unsigned long ld_off, kern_off, rd_off; + unsigned long ld_size, kern_size, rd_size; + int fd, ofd, len; + char buffer[500]; + + if (argc < 5 && !strcmp(argv[argc-2], "-o")) + usage(); + + if (argc > 5) + rdimage = argv[3]; + + kernel = argv[2]; + loader = argv[1]; + + ofd = open(argv[argc-1], (O_RDWR|O_CREAT), 0755); + if (ofd < 0) { + die("can't open %s: %s", argv[5], strerror(errno)); + } + + ld_off = kern_off = rd_off = 0; + ld_size = kern_size = rd_size = 0; + memset(buffer, 0, 500); + len = 0; + + fd = open(loader, O_RDONLY); + if (fd < 0) + die("can't open loader: %s", strerror(errno)); + + copy_blocks(fd, ofd, &ld_off, &ld_size); + len = sprintf(buffer, "bootloader: %x %x\n", ld_off, ld_size); + close(fd); + + fd = open(kernel, O_RDONLY); + if (fd < 0) + die("can't open kernel: %s", strerror(errno)); + + copy_blocks(fd, ofd, &kern_off, &kern_size); + len += sprintf(buffer+len, "zimage: %x %x\n", kern_off, kern_size); + close(fd); + + if (rdimage) { + fd = open(rdimage, O_RDONLY); + if (fd < 0) + die("can't get ramdisk: %s", strerror(errno)); + + copy_blocks(fd, ofd, &rd_off, &rd_size); + close(fd); + } + + len += sprintf(buffer+len, "initrd: %x %x", rd_off, rd_size); + + close(ofd); + + printf("%s\n", buffer); + + return 0; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/sioffset linux.ac/arch/ppc/boot/sioffset --- linux.vanilla/arch/ppc/boot/sioffset Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/boot/sioffset Tue Apr 3 23:32:42 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $2}'` +echo "0x"$OFFSET diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/boot/sisize linux.ac/arch/ppc/boot/sisize --- linux.vanilla/arch/ppc/boot/sisize Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/boot/sisize Tue Apr 3 23:32:42 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $3}'` +echo "0x"$OFFSET diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/coffboot/chrpmain.c linux.ac/arch/ppc/coffboot/chrpmain.c --- linux.vanilla/arch/ppc/coffboot/chrpmain.c Sun Sep 17 17:48:06 2000 +++ linux.ac/arch/ppc/coffboot/chrpmain.c Tue Apr 3 23:32:46 2001 @@ -14,6 +14,8 @@ extern void *finddevice(const char *); extern int getprop(void *, const char *, void *, int); +extern void *claim(unsigned int, unsigned int, unsigned int); +extern void release(void *ptr, unsigned int len); void make_bi_recs(unsigned long); void gunzip(void *, int, unsigned char *, int *); void stop_imac_ethernet(void); @@ -78,6 +80,7 @@ printf("done %u bytes\n", len); printf("%u bytes of heap consumed, max in use %u\n", avail_high - begin_avail, heap_max); + release(begin_avail, SCRATCH_SIZE); } else { memmove(dst, im, len); } @@ -98,8 +101,13 @@ void make_bi_recs(unsigned long addr) { struct bi_record *rec; - rec = (struct bi_record *)_ALIGN((unsigned long)addr+(1<<20)-1,(1<<20)); - + + /* leave a 1MB gap then align to the next 1MB boundary */ + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); + if (addr >= PROG_START + PROG_SIZE) + claim(addr, 0x1000, 0); + + rec = (struct bi_record *)addr; rec->tag = BI_FIRST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/coffboot/start.c linux.ac/arch/ppc/coffboot/start.c --- linux.vanilla/arch/ppc/coffboot/start.c Thu Dec 2 22:37:34 1999 +++ linux.ac/arch/ppc/coffboot/start.c Tue Apr 3 17:54:35 2001 @@ -172,6 +172,25 @@ return args.ret; } +void +release(void *virt, unsigned int size) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *virt; + unsigned int size; + } args; + + args.service = "release"; + args.nargs = 2; + args.nret = 0; + args.virt = virt; + args.size = size; + (*prom)(&args); +} + int getprop(void *phandle, const char *name, void *buf, int buflen) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/config.in linux.ac/arch/ppc/config.in --- linux.vanilla/arch/ppc/config.in Tue Apr 3 17:31:55 2001 +++ linux.ac/arch/ppc/config.in Wed Apr 18 13:52:54 2001 @@ -3,6 +3,8 @@ # see Documentation/kbuild/config-language.txt. # define_bool CONFIG_UID16 n +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n mainmenu_name "Linux/PowerPC Kernel Configuration" @@ -82,6 +84,7 @@ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ]; then choice 'Machine Type' \ "PowerMac/PReP/MTX/CHRP CONFIG_ALL_PPC \ + Gemini CONFIG_GEMINI \ APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/defconfig linux.ac/arch/ppc/defconfig --- linux.vanilla/arch/ppc/defconfig Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/defconfig Thu Apr 12 17:50:05 2001 @@ -297,7 +297,7 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=15000 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/Makefile linux.ac/arch/ppc/kernel/Makefile --- linux.vanilla/arch/ppc/kernel/Makefile Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/Makefile Tue Apr 3 23:32:48 2001 @@ -7,12 +7,10 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +USE_STANDARD_AS_RULE := true + ifdef CONFIG_PPC64BRIDGE -.S.o: - $(CC) $(CFLAGS) -D__ASSEMBLY__ -mppc64bridge -c $< -o $*.o -else -.S.o: - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o +EXTRA_AFLAGS := -Wa,-mppc64bridge endif ifeq ($(CONFIG_4xx),y) @@ -31,7 +29,7 @@ export-objs := ppc_ksyms.o prep_setup.o -obj-$(CONFIG_PPC) := entry.o traps.o irq.o idle.o time.o misc.o \ +obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o bitops.o ptrace.o \ ppc_htab.o semaphore.o syscalls.o \ align.o setup.o @@ -54,7 +52,7 @@ ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.c else -obj-$(CONFIG_PPC) += hashtable.o +obj-y += hashtable.o endif obj-$(CONFIG_MATH_EMULATION) += softemu8xx.o obj-$(CONFIG_MBX) += i8259.o @@ -65,6 +63,8 @@ indirect_pci.o i8259.o prep_pci.o \ prep_time.o prep_nvram.o prep_setup.o obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o +obj-$(CONFIG_GEMINI) += gemini_prom.o gemini_pci.o gemini_setup.o \ + open_pic.o obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/apus_setup.c linux.ac/arch/ppc/kernel/apus_setup.c --- linux.vanilla/arch/ppc/kernel/apus_setup.c Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/kernel/apus_setup.c Tue Apr 3 23:32:48 2001 @@ -1017,6 +1017,59 @@ 0 }; +#define HARDWARE_MAPPED_SIZE (512*1024) +unsigned long __init apus_find_end_of_memory(void) +{ + int shadow = 0; + unsigned long total; + + /* The memory size reported by ADOS excludes the 512KB + reserved for PPC exception registers and possibly 512KB + containing a shadow of the ADOS ROM. */ + { + unsigned long size = memory[0].size; + + /* If 2MB aligned, size was probably user + specified. We can't tell anything about shadowing + in this case so skip shadow assignment. */ + if (0 != (size & 0x1fffff)){ + /* Align to 512KB to ensure correct handling + of both memfile and system specified + sizes. */ + size = ((size+0x0007ffff) & 0xfff80000); + /* If memory is 1MB aligned, assume + shadowing. */ + shadow = !(size & 0x80000); + } + + /* Add the chunk that ADOS does not see. by aligning + the size to the nearest 2MB limit upwards. */ + memory[0].size = ((size+0x001fffff) & 0xffe00000); + } + + total = memory[0].size; + + /* Remove the memory chunks that are controlled by special + Phase5 hardware. */ + + /* Remove the upper 512KB if it contains a shadow of + the ADOS ROM. FIXME: It might be possible to + disable this shadow HW. Check the booter + (ppc_boot.c) */ + if (shadow) + total -= HARDWARE_MAPPED_SIZE; + + /* Remove the upper 512KB where the PPC exception + vectors are mapped. */ + total -= HARDWARE_MAPPED_SIZE; + + /* Linux/APUS only handles one block of memory -- the one on + the PowerUP board. Other system memory is horrible slow in + comparison. The user can use other memory for swapping + using the z2ram device. */ + ram_phys_base = memory[0].addr; + return total; +} __init void apus_init_IRQ(void) @@ -1037,10 +1090,6 @@ amiga_init_IRQ(); - int_control.int_sti = __no_use_sti; - int_control.int_cli = __no_use_cli; - int_control.int_save_flags = __no_use_save_flags; - int_control.int_restore_flags = __no_use_restore_flags; } __init @@ -1072,7 +1121,10 @@ ppc_md.irq_cannonicalize = apus_irq_cannonicalize; ppc_md.init_IRQ = apus_init_IRQ; ppc_md.get_irq = apus_get_irq; - ppc_md.post_irq = apus_post_irq; + +#error Should use the ->end() member of irq_desc[x]. -- Cort + /*ppc_md.post_irq = apus_post_irq;*/ + #ifdef CONFIG_HEARTBEAT ppc_md.heartbeat = apus_heartbeat; ppc_md.heartbeat_count = 1; @@ -1091,6 +1143,8 @@ ppc_md.set_rtc_time = apus_set_rtc_time; ppc_md.get_rtc_time = apus_get_rtc_time; ppc_md.calibrate_decr = apus_calibrate_decr; + + ppc_md.find_end_of_memory = apus_find_end_of_memory; ppc_md.nvram_read_val = NULL; ppc_md.nvram_write_val = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/chrp_pci.c linux.ac/arch/ppc/kernel/chrp_pci.c --- linux.vanilla/arch/ppc/kernel/chrp_pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/chrp_pci.c Tue Apr 3 23:32:48 2001 @@ -298,62 +298,6 @@ bus->resource[1] = &gg2_resources.pci_mem; } -/* this is used by the pmac_pci code too... - paulus */ -void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - unsigned int *ranges; - int rlen = 0; - int memno = 0; - struct resource *res; - - hose->io_base_phys = 0; - ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { - res = NULL; - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[3]; - hose->io_base_virt = ioremap(ranges[3], ranges[5]); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[5] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ - if (primary) - isa_mem_base = ranges[3]; - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[3] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = ranges[3]; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + ranges[5] - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += 6; - } -} - /* this is largely modeled and stolen after the pmac_pci code -- tgall */ @@ -405,7 +349,7 @@ hose->cfg_addr = (volatile unsigned int *) cfg; hose->cfg_data = cfg + 0x10; - process_bridge_ranges(hose, dev, index == 0); + pci_process_bridge_OF_ranges(hose, dev, index == 0); #ifdef CONFIG_POWER3 openpic_setup_ISU(index, opprop[index+1]); @@ -442,7 +386,7 @@ void __init chrp_find_bridges(void) { - struct device_node *py; + struct device_node *py, *dev; char *model, *name; struct pci_controller* hose; @@ -453,7 +397,7 @@ #else /* CONFIG_POWER4 */ model = get_property(find_path_device("/"), "model", NULL); if (!strncmp("MOT", model, 3)) { - struct pci_controller* hose; + struct pci_controller *hose; hose = pcibios_alloc_controller(); if (!hose) @@ -463,8 +407,9 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); setup_grackle(hose, 0x20000); + process_bridge_ranges(hose, dev, 1); return; } @@ -485,13 +430,13 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); name = get_property(find_path_device("/"), "name", NULL); if (!strncmp("IBM,7043-150", name, 12) || !strncmp("IBM,7046-155", name, 12) || !strncmp("IBM,7046-B50", name, 12) ) { setup_grackle(hose, 0x01000000); - isa_mem_base = 0x80000000; + process_bridge_ranges(hose, dev, 1); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/chrp_setup.c linux.ac/arch/ppc/kernel/chrp_setup.c --- linux.vanilla/arch/ppc/kernel/chrp_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/chrp_setup.c Tue Apr 3 23:32:48 2001 @@ -67,6 +67,7 @@ void rtas_indicator_progress(char *, unsigned short); void bootx_text_progress(char *, unsigned short); +extern unsigned long pmac_find_end_of_memory(void); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, @@ -559,11 +560,9 @@ #ifndef CONFIG_POWER4 ppc_md.init_IRQ = chrp_init_IRQ; ppc_md.get_irq = openpic_get_irq; - ppc_md.post_irq = NULL; #else ppc_md.init_IRQ = xics_init_IRQ; ppc_md.get_irq = xics_get_irq; - ppc_md.post_irq = NULL; #endif /* CONFIG_POWER4 */ ppc_md.init = chrp_init2; @@ -576,6 +575,8 @@ ppc_md.set_rtc_time = chrp_set_rtc_time; ppc_md.get_rtc_time = chrp_get_rtc_time; ppc_md.calibrate_decr = chrp_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT /* these are adjusted in chrp_init2 if we have an ADB keyboard */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/gemini_pci.c linux.ac/arch/ppc/kernel/gemini_pci.c --- linux.vanilla/arch/ppc/kernel/gemini_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/kernel/gemini_pci.c Tue Apr 3 23:32:48 2001 @@ -0,0 +1,121 @@ +#include +#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(struct pci_dev *dev, int offset, u8 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val) +{ + *val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val) +{ + grackle_write(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))), val); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops gemini_pci_ops = +{ + gemini_pcibios_read_config_byte, + gemini_pcibios_read_config_word, + gemini_pcibios_read_config_dword, + gemini_pcibios_write_config_byte, + gemini_pcibios_write_config_word, + gemini_pcibios_write_config_dword +}; + +void __init gemini_pcibios_fixup(void) +{ + int i; + struct pci_dev *dev; + + pci_for_each_dev(dev) { + for(i = 0; i < 6; i++) { + if (dev->resource[i].flags & IORESOURCE_IO) { + dev->resource[i].start |= (0xfe << 24); + dev->resource[i].end |= (0xfe << 24); + } + } + } +} + + +/* The "bootloader" for Synergy boards does none of this for us, so we need to + lay it all out ourselves... --Dan */ +void __init gemini_find_bridges(void) +{ + struct pci_controller* hose; + + ppc_md.pcibios_fixup = gemini_pcibios_fixup; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + hose->ops = &gemini_pci_ops; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/gemini_prom.S linux.ac/arch/ppc/kernel/gemini_prom.S --- linux.vanilla/arch/ppc/kernel/gemini_prom.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/kernel/gemini_prom.S Tue Apr 3 23:32:48 2001 @@ -0,0 +1,96 @@ +/* + * 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 CONFIG_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 + isync +#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 CONFIG_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 /* CONFIG_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 --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/gemini_setup.c linux.ac/arch/ppc/kernel/gemini_setup.c --- linux.vanilla/arch/ppc/kernel/gemini_setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/ppc/kernel/gemini_setup.c Tue Apr 3 23:32:48 2001 @@ -0,0 +1,537 @@ +/* + * 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 "local_irq.h" +#include "open_pic.h" + +void gemini_find_bridges(void); +static int gemini_get_clock_speed(void); +extern void gemini_pcibios_fixup(void); + +static char *gemini_board_families[] = { + "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR" +}; +static int gemini_board_count = sizeof(gemini_board_families) / + sizeof(gemini_board_families[0]); + +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 +}; + +int chrp_get_irq(struct pt_regs *); +void chrp_post_irq(struct pt_regs* regs, int); + +static inline unsigned long _get_HID1(void) +{ + unsigned long val; + + __asm__ __volatile__("mfspr %0,1009" : "=r" (val)); + return val; +} + +/* + * prom_init is the Gemini version of prom.c:prom_init. We only need + * the BSS clearing code, so I copied that out of prom.c. This is a + * lot simpler than hacking prom.c so it will build with Gemini. -VAL + */ + +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) + +unsigned long +prom_init(void) +{ + unsigned long offset = reloc_offset(); + unsigned long phys; + extern char __bss_start, _end; + + /* First zero the BSS -- use memset, some arches don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + + /* Default */ + phys = offset + KERNELBASE; + + gemini_prom_init(); + + return phys; +} + +int +gemini_get_cpuinfo(char *buffer) +{ + int 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) > gemini_board_count) + 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, "board\t\t: Gemini %s", family); + if (type > 9) + len += sprintf(buffer+len, "%c", (type - 10) + 'A'); + else + len += sprintf(buffer+len, "%d", type); + + len += sprintf(buffer+len, ", rev %c, eco %d\n", + (rev + 'A'), (reg & 0xf)); + + len += sprintf(buffer+len, "clock\t\t: %dMhz\n", + gemini_get_clock_speed()); + + return len; +} + +static u_char gemini_openpic_initsenses[] = { + 1, + 1, + 1, + 1, + 0, + 0, + 1, /* remainder are level-triggered */ +}; + +#define GEMINI_MPIC_ADDR (0xfcfc0000) +#define GEMINI_MPIC_PCI_CFG (0x80005800) + +void __init gemini_openpic_init(void) +{ + + OpenPIC_Addr = (volatile struct OpenPIC *) + grackle_read(GEMINI_MPIC_PCI_CFG + 0x10); + OpenPIC_InitSenses = gemini_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); + + ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE); +} + + +extern unsigned long loops_per_jiffy; +extern int root_mountflags; +extern char cmd_line[]; + +void +gemini_heartbeat(void) +{ + static unsigned long led = GEMINI_LEDBASE+(4*8); + static char direction = 8; + *(char *)led = 0; + if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || + (led + direction) < (GEMINI_LEDBASE+(4*8)) ) + direction *= -1; + led += direction; + *(char *)led = 0xff; + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +void __init gemini_setup_arch(void) +{ + extern char cmd_line[]; + + + loops_per_jiffy = 50000000/HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + /* bootable off CDROM */ + if (initrd_start) + ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0801); + + /* nothing but serial consoles... */ + sprintf(cmd_line, "%s console=ttyS0", cmd_line); + + printk("Boot arguments: %s\n", cmd_line); + + ppc_md.heartbeat = gemini_heartbeat; + ppc_md.heartbeat_reset = HZ/8; + ppc_md.heartbeat_count = 1; + + /* Lookup PCI hosts */ + gemini_find_bridges(); + /* take special pains to map the MPIC, since it isn't mapped yet */ + gemini_openpic_init(); + /* start the L2 */ + gemini_init_l2(); +} + + +int +gemini_get_clock_speed(void) +{ + unsigned long hid1, pvr = _get_PVR(); + int clock; + + hid1 = (_get_HID1() >> 28) & 0xf; + if (PVR_VER(pvr) == 8 || + PVR_VER(pvr) == 12) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + switch((readb(GEMINI_BSTAT) & 0xc) >> 2) { + + case 0: + default: + clock = (hid1*100)/3; + break; + + case 1: + clock = (hid1*125)/3; + break; + + case 2: + clock = (hid1*50); + break; + } + + return clock; +} + +void __init gemini_init_l2(void) +{ + unsigned char reg, brev, fam, creg; + unsigned long cache; + unsigned long pvr = _get_PVR(); + + reg = readb(GEMINI_L2CFG); + brev = readb(GEMINI_BREV); + fam = readb(GEMINI_FEAT); + + switch(PVR_VER(pvr)) { + + case 8: + if (reg & 0xc0) + cache = (((reg >> 6) & 0x3) << 28); + else + cache = 0x3 << 28; + +#ifdef CONFIG_SMP + /* Pre-3.0 processor revs had snooping errata. Leave + their L2's disabled with SMP. -- Dan */ + if (PVR_CFG(pvr) < 3) { + printk("Pre-3.0 750; L2 left disabled!\n"); + return; + } +#endif /* CONFIG_SMP */ + + /* Special case: VGM5-B's came before L2 ratios were set on + the board. Processor speed shouldn't be too high, so + set L2 ratio to 1:1.5. */ + if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0) + reg |= 1; + + /* determine best cache ratio based upon what the board + tells us (which sometimes _may_ not be true) and + the processor speed. */ + else { + if (gemini_get_clock_speed() > 250) + reg = 2; + } + break; + case 12: + { + static unsigned long l2_size_val = 0; + + if (!l2_size_val) + l2_size_val = _get_L2CR(); + cache = l2_size_val; + break; + } + case 4: + case 9: + creg = readb(GEMINI_CPUSTAT); + if (((creg & 0xc) >> 2) != 1) + printk("Dual-604 boards don't support the use of L2\n"); + else + writeb(1, GEMINI_L2CFG); + return; + default: + printk("Unknown processor; L2 left disabled\n"); + return; + } + + cache |= ((1<>2)&0x3) { + case 0: + default: + freq = 66667; + break; + case 1: + freq = 83000; + break; + case 2: + freq = 100000; + break; + } + + freq *= 1000; + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +unsigned long __init gemini_find_end_of_memory(void) +{ + unsigned long total; + unsigned char reg; + + reg = readb(GEMINI_MEMCFG); + total = ((1<<((reg & 0x7) - 1)) * + (8<<((reg >> 3) & 0x7))); + total *= (1024*1024); + return total; +} + +void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + int i; + int chrp_get_irq( struct pt_regs * ); + + for(i = 0; i < GEMINI_LEDS; i++) + gemini_led_off(i); + + 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.get_irq = openpic_get_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; + + ppc_md.find_end_of_memory = gemini_find_end_of_memory; + + /* 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 + ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/head.S linux.ac/arch/ppc/kernel/head.S --- linux.vanilla/arch/ppc/kernel/head.S Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/head.S Tue Apr 3 23:32:48 2001 @@ -161,6 +161,7 @@ bl fix_mem_constants #endif /* CONFIG_APUS */ +#ifndef CONFIG_GEMINI /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ @@ -168,6 +169,7 @@ __after_mmu_off: bl clear_bats bl flush_tlbs +#endif #ifndef CONFIG_POWER4 /* POWER4 doesn't have BATs */ @@ -307,8 +309,13 @@ .long ret_from_except /* System reset */ -#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ +#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ +#ifdef CONFIG_GEMINI + . = 0x100 + b __secondary_start_gemini +#else /* CONFIG_GEMINI */ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) #endif @@ -1266,6 +1273,20 @@ #endif /* CONFIG_APUS */ #ifdef CONFIG_SMP +#ifdef CONFIG_GEMINI + .globl __secondary_start_gemini +__secondary_start_gemini: + mfspr r4,HID0 + ori r4,r4,HID0_ICFI + li r3,0 + ori r3,r3,HID0_ICE + andc r4,r4,r3 + mtspr HID0,r4 + sync + bl prom_init + b __secondary_start +#endif /* CONFIG_GEMINI */ + .globl __secondary_start_psurge __secondary_start_psurge: li r24,1 /* cpu # */ @@ -1536,6 +1557,7 @@ * -- Cort */ clear_bats: +#if !defined(CONFIG_GEMINI) li r20,0 mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ @@ -1559,8 +1581,10 @@ mtspr IBAT2L,r20 mtspr IBAT3U,r20 mtspr IBAT3L,r20 +#endif /* !defined(CONFIG_GEMINI) */ blr +#ifndef CONFIG_GEMINI flush_tlbs: lis r20, 0x40 1: addic. r20, r20, -0x1000 @@ -1579,6 +1603,7 @@ mtspr SRR1,r3 sync RFI +#endif #ifndef CONFIG_POWER4 /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/irq.c linux.ac/arch/ppc/kernel/irq.c --- linux.vanilla/arch/ppc/kernel/irq.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/irq.c Tue Apr 3 23:32:58 2001 @@ -176,9 +176,19 @@ return 0; } -/* This could be promoted to a real free_irq() ... */ -static int -do_free_irq(int irq, void* dev_id) +#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) +/* Name change so we can catch standard drivers that potentially mess up + * the internal interrupt controller on 8xx and 8260. Just bear with me, + * I don't like this either and I am searching a better solution. For + * now, this is what I need. -- Dan + */ +#define request_irq request_8xxirq +#elif defined(CONFIG_APUS) +#define request_irq request_sysirq +#define free_irq sys_free_irq +#endif + +void free_irq(unsigned int irq, void* dev_id) { irq_desc_t *desc; struct irqaction **p; @@ -209,27 +219,15 @@ barrier(); #endif irq_kfree(action); - return 0; + return; } printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&desc->lock,flags); break; } - return -ENOENT; + return; } -#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) -/* Name change so we can catch standard drivers that potentially mess up - * the internal interrupt controller on 8xx and 8260. Just bear with me, - * I don't like this either and I am searching a better solution. For - * now, this is what I need. -- Dan - */ -#define request_irq request_8xxirq -#elif defined(CONFIG_APUS) -#define request_irq request_sysirq -#define free_irq sys_free_irq -#endif - int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { @@ -239,8 +237,17 @@ if (irq >= NR_IRQS) return -EINVAL; if (!handler) - /* We could implement really free_irq() instead of that... */ - return do_free_irq(irq, dev_id); + { + /* + * free_irq() used to be implemented as a call to + * request_irq() with handler being NULL. Now we have + * a real free_irq() but need to allow the old behavior + * for old code that hasn't caught up yet. + * -- Cort + */ + free_irq(irq, dev_id); + return 0; + } action = (struct irqaction *) irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -266,11 +273,6 @@ return 0; } -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} - /* * Generic enable/disable code: this just calls * down into the PIC-specific version for the actual @@ -546,10 +548,7 @@ goto out; } ppc_irq_dispatch_handler( regs, irq ); - if (ppc_md.post_irq) - ppc_md.post_irq( regs, irq ); - - out: +out: hardirq_exit( cpu ); return 1; /* lets ret_from_int know we can do checks */ } @@ -851,15 +850,18 @@ } #endif /* CONFIG_SMP */ -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; +static struct proc_dir_entry *root_irq_dir; +static struct proc_dir_entry *irq_dir[NR_IRQS]; +static struct proc_dir_entry *smp_affinity_entry[NR_IRQS]; #ifdef CONFIG_IRQ_ALL_CPUS -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; -#else /* CONFIG_IRQ_ALL_CPUS */ -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0x00000000}; -#endif /* CONFIG_IRQ_ALL_CPUS */ +#define DEFAULT_CPU_AFFINITY 0xffffffff +#else +#define DEFAULT_CPU_AFFINITY 0x00000001 +#endif + +unsigned int irq_affinity [NR_IRQS] = + { [0 ... NR_IRQS-1] = DEFAULT_CPU_AFFINITY }; #define HEX_DIGITS 8 @@ -919,16 +921,18 @@ err = parse_hex_value(buffer, count, &new_value); -/* Why is this disabled ? --BenH */ -#if 0/*CONFIG_SMP*/ /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. + * + * We assume a 1-1 logical<->physical cpu mapping here. If + * we assume that the cpu indices in /proc/irq/../smp_affinity + * are actually logical cpu #'s then we have no problem. + * -- Cort */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc[irq].handler->set_affinity(irq, new_value); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/m8260_setup.c linux.ac/arch/ppc/kernel/m8260_setup.c --- linux.vanilla/arch/ppc/kernel/m8260_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/m8260_setup.c Tue Apr 3 23:32:58 2001 @@ -212,6 +212,18 @@ } +/* + * Same hack as 8xx + */ +unsigned long __init m8260_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} void __init m8260_init(unsigned long r3, unsigned long r4, unsigned long r5, @@ -254,18 +266,8 @@ ppc_md.get_rtc_time = m8260_get_rtc_time; ppc_md.calibrate_decr = m8260_calibrate_decr; -#if 0 - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_pretranslate = pckbd_pretranslate; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif -#else + ppc_md.find_end_of_memory = m8260_find_end_of_memory; + ppc_md.kbd_setkeycode = NULL; ppc_md.kbd_getkeycode = NULL; ppc_md.kbd_translate = NULL; @@ -274,7 +276,6 @@ ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.kbd_sysrq_xlate = NULL; -#endif #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/m8xx_setup.c linux.ac/arch/ppc/kernel/m8xx_setup.c --- linux.vanilla/arch/ppc/kernel/m8xx_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/m8xx_setup.c Tue Apr 3 23:32:58 2001 @@ -590,6 +590,25 @@ /* -------------------------------------------------------------------- */ +/* + * This is a big hack right now, but it may turn into something real + * someday. + * + * For the 8xx boards (at this time anyway), there is nothing to initialize + * associated the PROM. Rather than include all of the prom.c + * functions in the image just to get prom_init, all we really need right + * now is the initialization of the physical memory region. + */ +unsigned long __init m8xx_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} + void __init m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/misc.S linux.ac/arch/ppc/kernel/misc.S --- linux.vanilla/arch/ppc/kernel/misc.S Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/kernel/misc.S Mon Apr 16 12:37:04 2001 @@ -44,7 +44,8 @@ beqlr 1: bdnz 1b blr - +_GLOBAL(__sti_check_lost_end) + /* * Returns (address we're running at) - (address we were linked at) * for use before the text and data are mapped to KERNELBASE. @@ -60,14 +61,29 @@ mtlr r0 blr -/* void __no_use_save_flags(unsigned long *flags) */ -_GLOBAL(__no_use_save_flags) +/* void __save_flags_ptr(unsigned long *flags) */ +_GLOBAL(__save_flags_ptr) mfmsr r4 stw r4,0(r3) blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__save_flags_ptr_end) + -/* void __no_use_restore_flags(unsigned long flags) */ -_GLOBAL(__no_use_restore_flags) +/* void __restore_flags(unsigned long flags) */ +_GLOBAL(__restore_flags) /* * Just set/clear the MSR_EE bit through restore/flags but do not * change anything else. This is needed by the RT system and makes @@ -94,16 +110,30 @@ mtmsr r3 SYNC blr +_GLOBAL(__restore_flags_end) -_GLOBAL(__no_use_cli) +_GLOBAL(__cli) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ SYNC /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ blr /* Done */ + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop +_GLOBAL(__cli_end) -_GLOBAL(__no_use_sti) + +_GLOBAL(__sti) lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) mfmsr r3 /* Get current state */ @@ -113,6 +143,15 @@ SYNC /* Some chip revs have problems here... */ mtmsr r3 /* Update machine state */ blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop +_GLOBAL(__sti_end) /* * We were about to enable interrupts but we have to simulate @@ -141,7 +180,7 @@ * complement mask on the msr then "or" some values on. * _nmask_and_or_msr(nmask, value_to_or) */ - _GLOBAL(_nmask_and_or_msr) +_GLOBAL(_nmask_and_or_msr) mfmsr r0 /* Get current msr */ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ or r0,r0,r4 /* Or on the bits in r4 (second parm) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/open_pic.c linux.ac/arch/ppc/kernel/open_pic.c --- linux.vanilla/arch/ppc/kernel/open_pic.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/open_pic.c Tue Apr 3 23:32:58 2001 @@ -775,11 +775,17 @@ int openpic_get_irq(struct pt_regs *regs) { +/* + * Clean up needed. -VAL + */ +#ifndef CONFIG_GEMINI extern int i8259_irq(int cpu); - +#endif int irq = openpic_irq(); /* Management of the cascade should be moved out of here */ + + /* Yep - because openpic !=> i8259, for one thing. -VAL */ if (open_pic_irq_offset && irq == open_pic_irq_offset) { /* @@ -787,8 +793,10 @@ */ if ( chrp_int_ack_special ) irq = *chrp_int_ack_special; +#ifndef CONFIG_GEMINI else irq = i8259_irq( smp_processor_id() ); +#endif openpic_eoi(); } if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pci.c linux.ac/arch/ppc/kernel/pci.c --- linux.vanilla/arch/ppc/kernel/pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/pci.c Tue Apr 3 23:32:58 2001 @@ -399,6 +399,10 @@ return hose; } +#ifdef CONFIG_ALL_PPC +/* + * Functions below are used on OpenFirmware machines. + */ static void make_one_node_map(struct device_node* node, u8 pci_bus) { @@ -577,6 +581,85 @@ *devfn = ((reg[0] >> 8) & 0xff); return 0; } + +void __init +pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) +{ + unsigned int *ranges, *prev; + int rlen = 0; + int memno = 0; + struct resource *res; + + /* First we try to merge ranges to fix a problem with some pmacs + * that can have more than 3 ranges, fortunately using contiguous + * addresses -- BenH + */ + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + prev = NULL; + while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { + if (prev) { + if (prev[0] == ranges[0] && prev[1] == ranges[1] && + (prev[2] + prev[5]) == ranges[2] && + (prev[3] + prev[5]) == ranges[3]) { + prev[5] += ranges[5]; + ranges[0] = 0; + ranges += 6; + continue; + } + } + prev = ranges; + ranges += 6; + } + + rlen = 0; + hose->io_base_phys = 0; + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { + res = NULL; + switch (ranges[0] >> 24) { + case 1: /* I/O space */ + if (ranges[2] != 0) + break; + hose->io_base_phys = ranges[3]; + hose->io_base_virt = ioremap(ranges[3], ranges[5]); + if (primary) + isa_io_base = (unsigned long) hose->io_base_virt; + res = &hose->io_resource; + res->flags = IORESOURCE_IO; + res->start = ranges[2]; + break; + case 2: /* memory space */ + memno = 0; + if (ranges[1] == 0 && ranges[2] == 0 + && ranges[5] <= (16 << 20)) { + /* 1st 16MB, i.e. ISA memory area */ + if (primary) + isa_mem_base = ranges[3]; + memno = 1; + } + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + if (memno == 0) + hose->pci_mem_offset = ranges[3] - ranges[2]; + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = ranges[3]; + } + break; + } + if (res != NULL) { + res->name = dev->full_name; + res->end = res->start + ranges[5] - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + ranges += 6; + } +} +#endif /* CONFIG_ALL_PPC */ void __init pcibios_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pmac_pci.c linux.ac/arch/ppc/kernel/pmac_pci.c --- linux.vanilla/arch/ppc/kernel/pmac_pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/pmac_pci.c Tue Apr 3 23:32:58 2001 @@ -29,8 +29,6 @@ #undef DEBUG -extern void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary); static void add_bridges(struct device_node *dev); /* XXX Could be per-controller, but I don't think we risk anything by @@ -382,7 +380,7 @@ hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ +#if 0 /* done in pci_process_bridge_OF_ranges now - paulus */ hose->io_base_phys = addr->address; /* is 0x10000 enough for io space ? */ hose->io_base_virt = (void *)ioremap(addr->address, 0x10000); @@ -405,7 +403,7 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ +#if 0 /* done in pci_process_bridge_OF_ranges now - paulus */ hose->io_base_phys = addr->address; hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); #endif @@ -505,7 +503,7 @@ /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ - process_bridge_ranges(hose, dev, primary); + pci_process_bridge_OF_ranges(hose, dev, primary); /* Fixup "bus-range" OF property */ fixup_bus_range(dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pmac_pic.c linux.ac/arch/ppc/kernel/pmac_pic.c --- linux.vanilla/arch/ppc/kernel/pmac_pic.c Sat Feb 17 00:02:34 2001 +++ linux.ac/arch/ppc/kernel/pmac_pic.c Tue Apr 3 23:32:58 2001 @@ -44,7 +44,7 @@ * since it can lose interrupts (see pmac_set_irq_mask). * -- Cort */ -void __pmac __no_use_set_lost(unsigned long irq_nr) +void __pmac __set_lost(unsigned long irq_nr) { if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) atomic_inc(&ppc_n_lost_interrupts); @@ -372,8 +372,37 @@ } irqctrler = NULL; } - - int_control.int_set_lost = __no_use_set_lost; + else + { + extern ulong __sti_check_lost, __sti_check_lost_end, + __restore_flags_check_lost, + __restore_flags_check_lost_end; + ulong flags; + + /* + * We need to check for lost intrs in sti, copy the + * checking version of __sti()/__restore_flags() over + * the non-lost intr check __sti()/__restore_flags(). + * + * Since this is only a problem with non-openpic PICs + * we only do it for non-openpic. + * -- Cort + */ + + __save_flags(flags); + __cli(); + + memcpy( __sti, &__sti_check_lost, + &__sti_check_lost_end - &__sti_check_lost ); + flush_icache_range( (ulong)__sti, (ulong)&__sti_end ); + + memcpy( __restore_flags, &__restore_flags_check_lost, + &__restore_flags_check_lost_end - &__restore_flags_check_lost ); + flush_icache_range( (ulong)__restore_flags, (ulong)&__restore_flags_end ); + + __restore_flags(flags); + } + /* * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, * 1998 G3 Series PowerBooks have 128, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pmac_setup.c linux.ac/arch/ppc/kernel/pmac_setup.c --- linux.vanilla/arch/ppc/kernel/pmac_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/pmac_setup.c Tue Apr 3 23:32:58 2001 @@ -66,6 +66,7 @@ #include #include "local_irq.h" #include "pmac_pic.h" +#include "../mm/mem_pieces.h" #undef SHOW_GATWICK_IRQS @@ -103,6 +104,8 @@ extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); +struct device_node *memory_node; + unsigned char drive_info; int ppc_override_l2cr = 0; @@ -470,7 +473,7 @@ char *p; /* Do nothing if the root has been set already. */ - if ((goodness < current_root_goodness) && + if ((goodness <= current_root_goodness) && (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))) return; p = strstr(saved_command_line, "root="); @@ -635,6 +638,74 @@ #endif #endif +/* + * Read in a property describing some pieces of memory. + */ + +static void __init get_mem_prop(char *name, struct mem_pieces *mp) +{ + struct reg_property *rp; + int s; + + rp = (struct reg_property *) get_property(memory_node, name, &s); + if (rp == NULL) { + printk(KERN_ERR "error: couldn't get %s property on /memory\n", + name); + abort(); + } + mp->n_regions = s / sizeof(mp->regions[0]); + memcpy(mp->regions, rp, s); + + /* Make sure the pieces are sorted. */ + mem_pieces_sort(mp); + mem_pieces_coalesce(mp); +} + +/* + * On systems with Open Firmware, collect information about + * physical RAM and which pieces are already in use. + * At this point, we have (at least) the first 8MB mapped with a BAT. + * Our text, data, bss use something over 1MB, starting at 0. + * Open Firmware may be using 1MB at the 4MB point. + */ +unsigned long __init pmac_find_end_of_memory(void) +{ + unsigned long a, total; + struct mem_pieces phys_mem; + + memory_node = find_devices("memory"); + if (memory_node == NULL) { + printk(KERN_ERR "can't find memory node\n"); + abort(); + } + + /* + * Find out where physical memory is, and check that it + * starts at 0 and is contiguous. It seems that RAM is + * always physically contiguous on Power Macintoshes. + * + * Supporting discontiguous physical memory isn't hard, + * it just makes the virtual <-> physical mapping functions + * more complicated (or else you end up wasting space + * in mem_map). + */ + get_mem_prop("reg", &phys_mem); + if (phys_mem.n_regions == 0) + panic("No RAM??"); + a = phys_mem.regions[0].address; + if (a != 0) + panic("RAM doesn't start at physical address 0"); + total = phys_mem.regions[0].size; + + if (phys_mem.n_regions > 1) { + printk("RAM starting at 0x%x is not contiguous\n", + phys_mem.regions[1].address); + printk("Using RAM from 0 to 0x%lx\n", total-1); + } + + return total; +} + void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -665,6 +736,8 @@ ppc_md.set_rtc_time = pmac_set_rtc_time; ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT #ifdef CONFIG_INPUT diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/ppc8xx_pic.c linux.ac/arch/ppc/kernel/ppc8xx_pic.c --- linux.vanilla/arch/ppc/kernel/ppc8xx_pic.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/ppc8xx_pic.c Tue Apr 3 23:32:58 2001 @@ -158,13 +158,15 @@ */ switch (irq) { #ifdef IDE0_INTERRUPT - case IDE0_INTERRUPT: /* fall through */ + case IDE0_INTERRUPT: /* IDE0 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif #ifdef IDE1_INTERRUPT - case IDE1_INTERRUPT: /* fall through */ + case IDE1_INTERRUPT: /* IDE1 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif - return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); - default: /* unknown IRQ -> panic */ panic("request_irq"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/ppc_ksyms.c linux.ac/arch/ppc/kernel/ppc_ksyms.c --- linux.vanilla/arch/ppc/kernel/ppc_ksyms.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/ppc_ksyms.c Tue Apr 3 23:32:58 2001 @@ -315,6 +315,14 @@ EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(int_control); +EXPORT_SYMBOL(__sti); +EXPORT_SYMBOL(__sti_end); +EXPORT_SYMBOL(__cli); +EXPORT_SYMBOL(__cli_end); +EXPORT_SYMBOL(__save_flags_ptr); +EXPORT_SYMBOL(__save_flags_ptr_end); +EXPORT_SYMBOL(__restore_flags); +EXPORT_SYMBOL(__restore_flags_end); EXPORT_SYMBOL(timer_interrupt_intercept); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(do_IRQ_intercept); @@ -324,7 +332,6 @@ EXPORT_SYMBOL(tb_ticks_per_jiffy); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); -EXPORT_SYMBOL(console_lock); #ifdef CONFIG_XMON EXPORT_SYMBOL(xmon); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/prep_pci.c linux.ac/arch/ppc/kernel/prep_pci.c --- linux.vanilla/arch/ppc/kernel/prep_pci.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/prep_pci.c Tue Apr 3 23:32:58 2001 @@ -437,8 +437,8 @@ static char ibm8xx_pci_IRQ_routes[] __prepdata = { 0, /* Line 0 - unused */ - 13, /* Line 1 */ - 10, /* Line 2 */ + 15, /* Line 1 */ + 15, /* Line 2 */ 15, /* Line 3 */ 15, /* Line 4 */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/prep_setup.c linux.ac/arch/ppc/kernel/prep_setup.c --- linux.vanilla/arch/ppc/kernel/prep_setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/prep_setup.c Tue Apr 3 23:32:58 2001 @@ -318,7 +318,9 @@ /* remap the VGA memory */ vgacon_remap_base = 0xf0000000; /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/ - conswitchp = &vga_con; + conswitchp = &vga_con; +#else + conswitchp = &dummy_con; #endif } @@ -697,6 +699,35 @@ } #endif +/* + * This finds the amount of physical ram and does necessary + * setup for prep. This is pretty architecture specific so + * this will likely stay separate from the pmac. + * -- Cort + */ +unsigned long __init prep_find_end_of_memory(void) +{ + unsigned long total; +#ifdef CONFIG_PREP_RESIDUAL + total = res->TotalMemory; +#else + total = 0; +#endif + + if (total == 0 ) + { + /* + * I need a way to probe the amount of memory if the residual + * data doesn't contain it. -- Cort + */ + printk("Ramsize from residual data was 0 -- Probing for value\n"); + total = 0x02000000; + printk("Ramsize default to be %ldM\n", total>>20); + } + + return (total); +} + unsigned long *MotSave_SmpIar; unsigned char *MotSave_CpusState[2]; @@ -756,7 +787,8 @@ { if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) _prep_type = _PREP_IBM; - _prep_type = _PREP_Motorola; + else + _prep_type = _PREP_Motorola; } else /* assume motorola if no residual (netboot?) */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/process.c linux.ac/arch/ppc/kernel/process.c --- linux.vanilla/arch/ppc/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux.ac/arch/ppc/kernel/process.c Tue Apr 17 15:38:29 2001 @@ -378,45 +378,6 @@ } /* - * XXX ld.so expects the auxiliary table to start on - * a 16-byte boundary, so we have to find it and - * move it up. :-( - */ -static inline void shove_aux_table(unsigned long sp) -{ - int argc; - char *p; - unsigned long e; - unsigned long aux_start, offset; - - if (__get_user(argc, (int *)sp)) - return; - sp += sizeof(int) + (argc + 1) * sizeof(char *); - /* skip over the environment pointers */ - do { - if (__get_user(p, (char **)sp)) - return; - sp += sizeof(char *); - } while (p != NULL); - aux_start = sp; - /* skip to the end of the auxiliary table */ - do { - if (__get_user(e, (unsigned long *)sp)) - return; - sp += 2 * sizeof(unsigned long); - } while (e != AT_NULL); - offset = ((aux_start + 15) & ~15) - aux_start; - if (offset != 0) { - do { - sp -= sizeof(unsigned long); - if (__get_user(e, (unsigned long *)sp) - || __put_user(e, (unsigned long *)(sp + offset))) - return; - } while (sp > aux_start); - } -} - -/* * Set up a thread for executing a new program */ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) @@ -425,7 +386,6 @@ regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER; - shove_aux_table(sp); if (last_task_used_math == current) last_task_used_math = 0; if (last_task_used_altivec == current) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/prom.c linux.ac/arch/ppc/kernel/prom.c --- linux.vanilla/arch/ppc/kernel/prom.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/prom.c Tue Apr 3 23:32:59 2001 @@ -1566,6 +1566,8 @@ } ip = (int *) get_property(np, "AAPL,interrupts", &l); + if (ip == 0 && np->parent) + ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { @@ -1619,6 +1621,8 @@ return mem_start; ip = (int *) get_property(np, "AAPL,interrupts", &l); + if (ip == 0 && np->parent) + ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/ptrace.c linux.ac/arch/ppc/kernel/ptrace.c --- linux.vanilla/arch/ppc/kernel/ptrace.c Tue Jun 20 01:59:36 2000 +++ linux.ac/arch/ppc/kernel/ptrace.c Tue Apr 3 17:54:35 2001 @@ -10,7 +10,7 @@ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * * Modified by Cort Dougan (cort@hq.fsmlabs.com) - * and Paul Mackerras (paulus@linuxcare.com.au). + * and Paul Mackerras (paulus@samba.org). * * This file is subject to the terms and conditions of the GNU General * Public License. See the file README.legal in the main directory of diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/semaphore.c linux.ac/arch/ppc/kernel/semaphore.c --- linux.vanilla/arch/ppc/kernel/semaphore.c Sun Nov 12 03:02:40 2000 +++ linux.ac/arch/ppc/kernel/semaphore.c Wed Apr 18 13:53:02 2001 @@ -137,44 +137,3 @@ { return waking_non_zero_trylock(sem); } - - -/* - * rw semaphores Ani Joshi - * based on alpha port by Andrea Arcangeli - */ - -void down_read_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue_exclusive(&sem->wait, &wait); - - do { - __set_task_state(tsk, TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&sem->lock); - schedule(); - spin_lock_irq(&sem->lock); - } while(sem->wr); - - remove_wait_queue(&sem->wait, &wait); -} - -void down_write_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue_exclusive(&sem->wait, &wait); - - do { - __set_task_state(tsk, TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&sem->lock); - schedule(); - spin_lock_irq(&sem->lock); - } while(sem->rd || sem->wr); - - remove_wait_queue(&sem->wait, &wait); -} - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/setup.c linux.ac/arch/ppc/kernel/setup.c --- linux.vanilla/arch/ppc/kernel/setup.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/setup.c Tue Apr 3 23:32:59 2001 @@ -73,6 +73,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); + #ifdef CONFIG_XMON extern void xmon_map_scc(void); #endif @@ -80,13 +86,7 @@ extern boot_infos_t *boot_infos; char saved_command_line[256]; unsigned char aux_device_present; -struct int_control_struct int_control = -{ - __no_use_cli, - __no_use_sti, - __no_use_restore_flags, - __no_use_save_flags -}; +struct int_control_struct int_control; struct ide_machdep_calls ppc_ide_md; int parse_bootinfo(void); @@ -547,6 +547,11 @@ #ifdef CONFIG_APUS case _MACH_apus: apus_init(r3, r4, r5, r6, r7); + break; +#endif +#ifdef CONFIG_GEMINI + case _MACH_gemini: + gemini_init(r3, r4, r5, r6, r7); break; #endif default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/smp.c linux.ac/arch/ppc/kernel/smp.c --- linux.vanilla/arch/ppc/kernel/smp.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/kernel/smp.c Tue Apr 3 23:32:59 2001 @@ -40,6 +40,7 @@ #include #include #include +#include #include "open_pic.h" int smp_threads_ready; @@ -55,7 +56,7 @@ unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; static int max_cpus __initdata = NR_CPUS; - +unsigned long cpu_online_map; int smp_hw_index[NR_CPUS]; /* all cpu mappings are 1-1 -- Cort */ @@ -628,6 +629,43 @@ do_openpic_setup_cpu(); } +#ifdef CONFIG_GEMINI +static int +smp_gemini_probe(void) +{ + int i, nr; + + nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2; + if (nr == 0) + nr = 4; + + if (nr > 1) { + openpic_request_IPIs(); + for (i = 1; i < nr; ++i) + smp_hw_index[i] = i; + } + + return nr; +} + +static void +smp_gemini_kick_cpu(int nr) +{ + openpic_init_processor( 1< 0) + gemini_init_l2(); +} +#endif /* CONFIG_GEMINI */ + + static struct smp_ops_t { void (*message_pass)(int target, int msg, unsigned long data, int wait); int (*probe)(void); @@ -685,6 +723,16 @@ smp_prep_setup_cpu, }; +#ifdef CONFIG_GEMINI +/* Gemini */ +static struct smp_ops_t gemini_smp_ops = { + smp_openpic_message_pass, + smp_gemini_probe, + smp_gemini_kick_cpu, + smp_gemini_setup_cpu, +}; +#endif /* CONFIG_GEMINI */ + /* * Common functions */ @@ -925,6 +973,11 @@ case _MACH_prep: smp_ops = &prep_smp_ops; break; +#ifdef CONFIG_GEMINI + case _MACH_gemini: + smp_ops = &gemini_smp_ops; + break; +#endif /* CONFIG_GEMINI */ default: printk("SMP not supported on this machine.\n"); return; @@ -1114,8 +1167,18 @@ init_idle(); + /* + * This cpu is now "online". Only set them online + * before they enter the loop below since write access + * to the below variable is _not_ guaranteed to be + * atomic. + * -- Cort + */ + cpu_online_map |= 1UL << smp_processor_id(); + while(!smp_commenced) barrier(); + /* see smp_commence for more info */ if (!smp_tb_synchronized && smp_num_cpus == 2) { smp_software_tb_sync(cpu); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/lib/Makefile linux.ac/arch/ppc/lib/Makefile --- linux.vanilla/arch/ppc/lib/Makefile Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/lib/Makefile Tue Apr 3 23:32:59 2001 @@ -2,8 +2,7 @@ # Makefile for ppc-specific library files.. # -.S.o: - $(CC) $(AFLAGS) -c $< -o $*.o +USE_STANDARD_AS_RULE := true O_TARGET := lib.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/mm/init.c linux.ac/arch/ppc/mm/init.c --- linux.vanilla/arch/ppc/mm/init.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/ppc/mm/init.c Tue Apr 3 23:32:59 2001 @@ -61,12 +61,16 @@ #include #include #include +#include #include "mem_pieces.h" #if defined(CONFIG_4xx) #include "4xx_tlb.h" #endif +#include + +mmu_gather_t mmu_gathers[NR_CPUS]; #define MAX_LOW_MEM (512 << 20) @@ -111,19 +115,6 @@ void MMU_init(void); void *early_get_page(void); -unsigned long prep_find_end_of_memory(void); -unsigned long pmac_find_end_of_memory(void); -unsigned long apus_find_end_of_memory(void); -extern unsigned long find_end_of_memory(void); -#ifdef CONFIG_8xx -unsigned long m8xx_find_end_of_memory(void); -#endif /* CONFIG_8xx */ -#ifdef CONFIG_4xx -unsigned long oak_find_end_of_memory(void); -#endif -#ifdef CONFIG_8260 -unsigned long m8260_find_end_of_memory(void); -#endif /* CONFIG_8260 */ static void mapin_ram(void); int map_page(unsigned long va, unsigned long pa, int flags); void set_phys_avail(unsigned long total_ram); @@ -668,33 +659,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -static void get_mem_prop(char *, struct mem_pieces *); - -#if defined(CONFIG_ALL_PPC) -/* - * Read in a property describing some pieces of memory. - */ - -static void __init get_mem_prop(char *name, struct mem_pieces *mp) -{ - struct reg_property *rp; - int s; - - rp = (struct reg_property *) get_property(memory_node, name, &s); - if (rp == NULL) { - printk(KERN_ERR "error: couldn't get %s property on /memory\n", - name); - abort(); - } - mp->n_regions = s / sizeof(mp->regions[0]); - memcpy(mp->regions, rp, s); - - /* Make sure the pieces are sorted. */ - mem_pieces_sort(mp); - mem_pieces_coalesce(mp); -} -#endif /* CONFIG_ALL_PPC */ - /* * 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 @@ -923,7 +887,7 @@ * at KERNELBASE. */ - total_memory = total_lowmem = oak_find_end_of_memory(); + total_memory = total_lowmem = ppc_md.find_end_of_memory(); end_of_DRAM = __va(total_memory); mapin_ram(); @@ -948,7 +912,7 @@ { if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); - total_memory = total_lowmem = m8xx_find_end_of_memory(); + total_memory = total_lowmem = ppc_md.find_end_of_memory(); #ifdef CONFIG_HIGHMEM if (total_lowmem > MAX_LOW_MEM) { total_lowmem = MAX_LOW_MEM; @@ -994,19 +958,8 @@ { if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); - if (have_of) - total_memory = pmac_find_end_of_memory(); -#ifdef CONFIG_APUS - else if (_machine == _MACH_apus ) - total_memory = apus_find_end_of_memory(); -#endif -#if defined(CONFIG_8260) - else - total_memory = m8260_find_end_of_memory(); -#else - else /* prep */ - total_memory = prep_find_end_of_memory(); -#endif + total_memory = ppc_md.find_end_of_memory(); + if (__max_memory && total_memory > __max_memory) total_memory = __max_memory; total_lowmem = total_memory; @@ -1069,6 +1022,10 @@ /* Map chip and ZorroII memory */ setbat(1, zTwoBase, 0x00000000, 0x01000000, IO_PAGE); break; + case _MACH_gemini: + setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + break; case _MACH_8260: /* Map the IMMR, plus anything else we can cover * in that upper space according to the memory controller @@ -1257,155 +1214,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#if defined(CONFIG_ALL_PPC) -/* - * On systems with Open Firmware, collect information about - * physical RAM and which pieces are already in use. - * At this point, we have (at least) the first 8MB mapped with a BAT. - * Our text, data, bss use something over 1MB, starting at 0. - * Open Firmware may be using 1MB at the 4MB point. - */ -unsigned long __init pmac_find_end_of_memory(void) -{ - unsigned long a, total; - struct mem_pieces phys_mem; - - memory_node = find_devices("memory"); - if (memory_node == NULL) { - printk(KERN_ERR "can't find memory node\n"); - abort(); - } - - /* - * Find out where physical memory is, and check that it - * starts at 0 and is contiguous. It seems that RAM is - * always physically contiguous on Power Macintoshes. - * - * Supporting discontiguous physical memory isn't hard, - * it just makes the virtual <-> physical mapping functions - * more complicated (or else you end up wasting space - * in mem_map). - */ - get_mem_prop("reg", &phys_mem); - if (phys_mem.n_regions == 0) - panic("No RAM??"); - a = phys_mem.regions[0].address; - if (a != 0) - panic("RAM doesn't start at physical address 0"); - total = phys_mem.regions[0].size; - - if (phys_mem.n_regions > 1) { - printk("RAM starting at 0x%x is not contiguous\n", - phys_mem.regions[1].address); - printk("Using RAM from 0 to 0x%lx\n", total-1); - } - - return total; -} -#endif /* CONFIG_ALL_PPC */ - -#if defined(CONFIG_ALL_PPC) -/* - * This finds the amount of physical ram and does necessary - * setup for prep. This is pretty architecture specific so - * this will likely stay separate from the pmac. - * -- Cort - */ -unsigned long __init prep_find_end_of_memory(void) -{ - unsigned long total; -#ifdef CONFIG_PREP_RESIDUAL - total = res->TotalMemory; -#else - total = 0; -#endif - - if (total == 0 ) - { - /* - * I need a way to probe the amount of memory if the residual - * data doesn't contain it. -- Cort - */ - printk("Ramsize from residual data was 0 -- Probing for value\n"); - total = 0x02000000; - printk("Ramsize default to be %ldM\n", total>>20); - } - - return (total); -} -#endif /* defined(CONFIG_ALL_PPC) */ - -#ifdef CONFIG_8260 -/* - * Same hack as 8xx. - */ -unsigned long __init m8260_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} -#endif /* CONFIG_8260 */ - -#ifdef CONFIG_APUS -#define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init apus_find_end_of_memory(void) -{ - int shadow = 0; - unsigned long total; - - /* The memory size reported by ADOS excludes the 512KB - reserved for PPC exception registers and possibly 512KB - containing a shadow of the ADOS ROM. */ - { - unsigned long size = memory[0].size; - - /* If 2MB aligned, size was probably user - specified. We can't tell anything about shadowing - in this case so skip shadow assignment. */ - if (0 != (size & 0x1fffff)){ - /* Align to 512KB to ensure correct handling - of both memfile and system specified - sizes. */ - size = ((size+0x0007ffff) & 0xfff80000); - /* If memory is 1MB aligned, assume - shadowing. */ - shadow = !(size & 0x80000); - } - - /* Add the chunk that ADOS does not see. by aligning - the size to the nearest 2MB limit upwards. */ - memory[0].size = ((size+0x001fffff) & 0xffe00000); - } - - total = memory[0].size; - - /* Remove the memory chunks that are controlled by special - Phase5 hardware. */ - - /* Remove the upper 512KB if it contains a shadow of - the ADOS ROM. FIXME: It might be possible to - disable this shadow HW. Check the booter - (ppc_boot.c) */ - if (shadow) - total -= HARDWARE_MAPPED_SIZE; - - /* Remove the upper 512KB where the PPC exception - vectors are mapped. */ - total -= HARDWARE_MAPPED_SIZE; - - /* Linux/APUS only handles one block of memory -- the one on - the PowerUP board. Other system memory is horrible slow in - comparison. The user can use other memory for swapping - using the z2ram device. */ - ram_phys_base = memory[0].addr; - return total; -} -#endif /* CONFIG_APUS */ - /* * Initialize the hash table and patch the instructions in head.S. */ @@ -1514,43 +1322,7 @@ } if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } -#elif defined(CONFIG_8xx) -/* - * This is a big hack right now, but it may turn into something real - * someday. - * - * For the 8xx boards (at this time anyway), there is nothing to initialize - * associated the PROM. Rather than include all of the prom.c - * functions in the image just to get prom_init, all we really need right - * now is the initialization of the physical memory region. - */ -unsigned long __init m8xx_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} #endif /* !CONFIG_4xx && !CONFIG_8xx */ - -#ifdef CONFIG_OAK -/* - * Return the virtual address representing the top of physical RAM - * on the Oak board. - */ -unsigned long __init -oak_find_end_of_memory(void) -{ - extern unsigned char __res[]; - - unsigned long *ret; - bd_t *bip = (bd_t *)__res; - - return bip->bi_memsize; -} -#endif /* * Set phys_avail to the amount of physical memory, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/xmon/start.c linux.ac/arch/ppc/xmon/start.c --- linux.vanilla/arch/ppc/xmon/start.c Mon Jan 22 23:41:15 2001 +++ linux.ac/arch/ppc/xmon/start.c Tue Apr 3 23:32:59 2001 @@ -101,6 +101,15 @@ sccc = base + (addr & ~PAGE_MASK); sccd = sccc + 0x10; } + else if ( _machine & _MACH_gemini ) + { + /* should already be mapped by the kernel boot */ + sccc = (volatile unsigned char *) 0xffeffb0d; + sccd = (volatile unsigned char *) 0xffeffb08; + TXRDY = 0x20; + RXRDY = 1; + console = 1; + } else { /* should already be mapped by the kernel boot */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/xmon/start_8xx.c linux.ac/arch/ppc/xmon/start_8xx.c --- linux.vanilla/arch/ppc/xmon/start_8xx.c Wed May 3 09:47:57 2000 +++ linux.ac/arch/ppc/xmon/start_8xx.c Tue Apr 3 23:32:59 2001 @@ -15,7 +15,7 @@ #include #include #include -#include "commproc.h" +#include "../8xx_io/commproc.h" extern void xmon_printf(const char *fmt, ...); extern int xmon_8xx_write(char *str, int nb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/Makefile linux.ac/arch/s390/Makefile --- linux.vanilla/arch/s390/Makefile Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/Makefile Thu Apr 12 11:59:46 2001 @@ -26,10 +26,14 @@ HEAD := arch/s390/kernel/head.o arch/s390/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \ - drivers/s390 + drivers/s390 arch/s390/math-emu CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \ drivers/s390/io.o LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a + +ifeq ($(CONFIG_MATHEMU),y) + CORE_FILES := $(CORE_FILES) arch/s390/math-emu/math-emu.o +endif all: image listing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/boot/Makefile linux.ac/arch/s390/boot/Makefile --- linux.vanilla/arch/s390/boot/Makefile Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/boot/Makefile Thu Apr 12 11:59:46 2001 @@ -25,7 +25,7 @@ image: $(CONFIGURE) $(TOPDIR)/vmlinux \ iplfba.boot ipleckd.boot ipldump.boot $(OBJCOPY) -O binary $(TOPDIR)/vmlinux image - $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aU] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map + $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map listing: ../../../vmlinux $(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/config.in linux.ac/arch/s390/config.in --- linux.vanilla/arch/s390/config.in Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/config.in Wed Apr 18 13:53:10 2001 @@ -7,6 +7,8 @@ define_bool CONFIG_EISA n define_bool CONFIG_MCA n define_bool CONFIG_UID16 y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_ARCH_S390 y @@ -28,7 +30,7 @@ mainmenu_option next_comment comment 'Processor type and features' bool 'Symmetric multi-processing support' CONFIG_SMP -bool 'IEEE FPU emulation' CONFIG_IEEEFPU_EMULATION +bool 'IEEE FPU emulation' CONFIG_MATHEMU endmenu mainmenu_option next_comment @@ -44,7 +46,7 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -define CONFIG_KCORE ELF +define_bool CONFIG_KCORE_ELF y tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG @@ -65,6 +67,6 @@ if [ "$CONFIG_CTC" = "y" ]; then bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG fi -# this does not work. bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/defconfig linux.ac/arch/s390/defconfig --- linux.vanilla/arch/s390/defconfig Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/defconfig Thu Apr 12 11:59:46 2001 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_ISA is not set # CONFIG_EISA is not set @@ -13,12 +13,6 @@ CONFIG_EXPERIMENTAL=y # -# Processor type and features -# -CONFIG_SMP=y -CONFIG_IEEEFPU_EMULATION=y - -# # Loadable module support # CONFIG_MODULES=y @@ -26,6 +20,12 @@ CONFIG_KMOD=y # +# Processor type and features +# +CONFIG_SMP=y +CONFIG_MATHEMU=y + +# # General setup # CONFIG_FAST_IRQ=y @@ -36,6 +36,7 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_PROCESS_DEBUG is not set @@ -49,9 +50,14 @@ CONFIG_BLK_DEV_RAM_SIZE=24576 CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_XPRAM=m + +# +# S/390 block device drivers +# CONFIG_DASD=y CONFIG_DASD_ECKD=y CONFIG_DASD_FBA=y +# CONFIG_DASD_DIAG is not set # # Multi-device support (RAID and LVM) @@ -63,20 +69,31 @@ CONFIG_MD_RAID1=m CONFIG_MD_RAID5=m CONFIG_BLK_DEV_LVM=m -CONFIG_LVM_PROC_FS=y # # Character device drivers # CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 + +# +# S/390 character device drivers +# CONFIG_3215=y CONFIG_3215_CONSOLE=y CONFIG_HWC=y CONFIG_HWC_CONSOLE=y CONFIG_S390_TAPE=m + +# +# S/390 tape interface support +# CONFIG_S390_TAPE_CHAR=y CONFIG_S390_TAPE_BLOCK=y + +# +# S/390 tape hardware support +# CONFIG_S390_TAPE_3490=y CONFIG_S390_TAPE_3480=y @@ -88,6 +105,10 @@ CONFIG_NET_ETHERNET=y CONFIG_TR=y # CONFIG_FDDI is not set + +# +# S/390 network device drivers +# # CONFIG_CHANDEV is not set CONFIG_CTC=m CONFIG_IUCV=m @@ -109,11 +130,16 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -138,6 +164,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -192,8 +220,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -211,8 +237,10 @@ # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # Kernel hacking # +# CONFIG_MAGIC_SYSRQ is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/Makefile linux.ac/arch/s390/kernel/Makefile --- linux.vanilla/arch/s390/kernel/Makefile Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/Makefile Thu Apr 12 11:59:46 2001 @@ -14,14 +14,13 @@ O_TARGET := kernel.o -export-objs := s390_ksyms.o +export-objs := debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ semaphore.o s390fpu.o reipl.o s390_ext.o debug.o obj-$(CONFIG_MODULES) += s390_ksyms.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_IEEEFPU_EMULATION) += mathemu.o floatlib.o # # Kernel debugging diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/cpcmd.c linux.ac/arch/s390/kernel/cpcmd.c --- linux.vanilla/arch/s390/kernel/cpcmd.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/cpcmd.c Thu Apr 12 11:59:46 2001 @@ -10,6 +10,7 @@ #include #include #include +#include void cpcmd(char *cmd, char *response, int rlen) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/cpcmd.h linux.ac/arch/s390/kernel/cpcmd.h --- linux.vanilla/arch/s390/kernel/cpcmd.h Fri May 12 19:41:44 2000 +++ linux.ac/arch/s390/kernel/cpcmd.h Thu Jan 1 01:00:00 1970 @@ -1,14 +0,0 @@ -/* - * arch/s390/kernel/cpcmd.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - */ - -#ifndef __CPCMD__ -#define __CPCMD__ - -extern void cpcmd(char *cmd, char *response, int rlen); - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/debug.c linux.ac/arch/s390/kernel/debug.c --- linux.vanilla/arch/s390/kernel/debug.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/debug.c Thu Apr 12 11:59:46 2001 @@ -15,45 +15,53 @@ #include #include #include -#include #include #include #include #include -#ifdef MODULE #include -#endif #include #define MIN(a,b) (((a)<(b))?(a):(b)) - -#if defined(CONFIG_ARCH_S390X) -#define DEBUG_PROC_HEADER_SIZE 46 -#else -#define DEBUG_PROC_HEADER_SIZE 38 -#endif - -#define ADD_BUFFER 1000 +#define DEBUG_PROLOG_ENTRY -1 /* typedefs */ typedef struct file_private_info { - loff_t len; /* length of output in byte */ - int size; /* size of buffer for output */ - char *data; /* buffer for output */ - debug_info_t *debug_info; /* the debug information struct */ + loff_t offset; /* offset of last read in file */ + int act_area; /* number of last formated area */ + int act_entry; /* last formated entry (offset */ + /* relative to beginning of last */ + /* formated area) */ + size_t act_entry_offset; /* up to this offset we copied */ + /* in last read the last formated */ + /* entry to userland */ + char temp_buf[2048]; /* buffer for output */ + debug_info_t *debug_info_org; /* original debug information */ + debug_info_t *debug_info_snap; /* snapshot of debug information */ struct debug_view *view; /* used view of debug info */ } file_private_info_t; +typedef struct +{ + char *string; + /* + * This assumes that all args are converted into longs + * on L/390 this is the case for all types of parameter + * except of floats, and long long (32 bit) + * + */ + long args[0]; +} debug_sprintf_entry; + + extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); /* internal function prototyes */ static int debug_init(void); -static int debug_format_output(debug_info_t * debug_area, char *buf, - int size, struct debug_view *view); static ssize_t debug_output(struct file *file, char *user_buf, size_t user_len, loff_t * offset); static ssize_t debug_input(struct file *file, const char *user_buf, @@ -83,6 +91,9 @@ static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf); +static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event); + /* globals */ struct debug_view debug_raw_view = { @@ -90,6 +101,7 @@ NULL, &debug_raw_header_fn, &debug_raw_format_fn, + NULL, NULL }; @@ -98,6 +110,7 @@ NULL, &debug_dflt_header_fn, &debug_hex_ascii_format_fn, + NULL, NULL }; @@ -106,9 +119,22 @@ &debug_prolog_level_fn, NULL, NULL, - &debug_input_level_fn + &debug_input_level_fn, + NULL +}; + +struct debug_view debug_sprintf_view = { + "sprintf", + NULL, + &debug_dflt_header_fn, + (debug_format_proc_t*)&debug_sprintf_format_fn, + NULL, + NULL }; + +unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; + /* static globals */ static debug_info_t *debug_area_first = NULL; @@ -137,64 +163,108 @@ static struct proc_dir_entry *debug_proc_root_entry; - /* functions */ /* - * debug_info_create - * - create new debug-info + * debug_info_alloc + * - alloc new debug-info */ -static debug_info_t* debug_info_create(char *name, int page_order, +static debug_info_t* debug_info_alloc(char *name, int page_order, int nr_areas, int buf_size) { debug_info_t* rc; int i; - /* alloc everything */ + /* alloc everything */ - rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); - if(!rc) + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + if(!rc) goto fail_malloc_rc; rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); if(!rc->active_entry) goto fail_malloc_active_entry; memset(rc->active_entry, 0, nr_areas * sizeof(int)); - rc->areas = (debug_entry_t **) kmalloc(nr_areas * - sizeof(debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) - goto fail_malloc_areas; - for (i = 0; i < nr_areas; i++) { - rc->areas[i] = - (debug_entry_t *) __get_free_pages(GFP_ATOMIC, - page_order); - if (!rc->areas[i]) { - for (i--; i >= 0; i--) { - free_pages((unsigned long) rc->areas[i], - page_order); - } - goto fail_malloc_areas2; - } else { - memset(rc->areas[i], 0, PAGE_SIZE << page_order); - } - } + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) + goto fail_malloc_areas; + for (i = 0; i < nr_areas; i++) { + rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC, + page_order); + if (!rc->areas[i]) { + for (i--; i >= 0; i--) { + free_pages((unsigned long) rc->areas[i], + page_order); + } + goto fail_malloc_areas2; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + /* initialize members */ - /* initialize members */ + spin_lock_init(&rc->lock); + rc->page_order = page_order; + rc->nr_areas = nr_areas; + rc->active_area = 0; + rc->level = DEBUG_DEFAULT_LEVEL; + rc->buf_size = buf_size; + rc->entry_size = sizeof(debug_entry_t) + buf_size; + strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); + rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; + memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct proc_dir_entry*)); + atomic_set(&(rc->ref_count), 0); + + return rc; + +fail_malloc_areas2: + kfree(rc->areas); +fail_malloc_areas: + kfree(rc->active_entry); +fail_malloc_active_entry: + kfree(rc); +fail_malloc_rc: + return NULL; +} + +/* + * debug_info_free + * - free memory debug-info + */ + +static void debug_info_free(debug_info_t* db_info){ + int i; + for (i = 0; i < db_info->nr_areas; i++) { + free_pages((unsigned long) db_info->areas[i], + db_info->page_order); + } + kfree(db_info->areas); + kfree(db_info->active_entry); + kfree(db_info); +} + +/* + * debug_info_create + * - create new debug-info + */ + +static debug_info_t* debug_info_create(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + + rc = debug_info_alloc(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; + + + /* create proc rood directory */ - spin_lock_init(&rc->lock); - rc->page_order = page_order; - rc->nr_areas = nr_areas; - rc->active_area = 0; - rc->level = DEBUG_DEFAULT_LEVEL; - rc->buf_size = buf_size; - rc->entry_size = sizeof(debug_entry_t) + buf_size; - strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); - rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; - memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); - memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * - sizeof(struct proc_dir_entry*)); - atomic_set(&(rc->ref_count), 0); rc->proc_root_entry = debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, S_IFDIR | S_IRUGO | S_IXUGO | @@ -216,16 +286,29 @@ rc->next = NULL; debug_info_get(rc); +out: return rc; +} -fail_malloc_areas2: - kfree(rc->areas); -fail_malloc_areas: - kfree(rc->active_entry); -fail_malloc_active_entry: - kfree(rc); -fail_malloc_rc: - return NULL; +/* + * debug_info_copy + * - copy debug-info + */ + +static debug_info_t* debug_info_copy(debug_info_t* in) +{ + int i; + debug_info_t* rc; + rc = debug_info_alloc(in->name, in->page_order, + in->nr_areas, in->buf_size); + if(!rc) + goto out; + + for(i = 0; i < in->nr_areas; i++){ + memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order); + } +out: + return rc; } /* @@ -261,49 +344,120 @@ } debug_delete_proc_dir_entry(debug_proc_root_entry, db_info->proc_root_entry); - for (i = 0; i < db_info->nr_areas; i++) { - free_pages((unsigned long) db_info->areas[i], - db_info->page_order); - } - kfree(db_info->areas); - kfree(db_info->active_entry); if(db_info == debug_area_first) debug_area_first = db_info->next; if(db_info == debug_area_last) debug_area_last = db_info->prev; if(db_info->prev) db_info->prev->next = db_info->next; if(db_info->next) db_info->next->prev = db_info->prev; - kfree(db_info); + debug_info_free(db_info); } } +/* + * debug_format_entry: + * - format one debug entry and return size of formated data + */ + +static int debug_format_entry(file_private_info_t *p_info) +{ + debug_info_t *id_org = p_info->debug_info_org; + debug_info_t *id_snap = p_info->debug_info_snap; + struct debug_view *view = p_info->view; + debug_entry_t *act_entry; + size_t len = 0; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(id_org, view,p_info->temp_buf); + goto out; + } + + act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] + + p_info->act_entry); + + if (act_entry->id.stck == 0LL) + goto out; /* empty entry */ + if (view->header_proc) + len += view->header_proc(id_org, view, p_info->act_area, + act_entry, p_info->temp_buf + len); + if (view->format_proc) + len += view->format_proc(id_org, view, p_info->temp_buf + len, + DEBUG_DATA(act_entry)); + out: + return len; +} + +/* + * debug_next_entry: + * - goto next entry in p_info + */ + +extern inline int debug_next_entry(file_private_info_t *p_info) +{ + debug_info_t *id = p_info->debug_info_snap; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + p_info->act_entry = 0; + goto out; + } + if ((p_info->act_entry += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) + - id->entry_size)){ + + /* next area */ + p_info->act_entry = 0; + p_info->act_area++; + if(p_info->act_area >= id->nr_areas) + return 1; + } +out: + return 0; +} /* * debug_output: * - called for user read() - * - copies formated output form private_data of the file - * handle to the user buffer + * - copies formated debug entries to the user buffer */ static ssize_t debug_output(struct file *file, /* file descriptor */ char *user_buf, /* user buffer */ - size_t user_len, /* length of buffer */ + size_t len, /* length of buffer */ loff_t *offset /* offset in the file */ ) { - loff_t len; + size_t count = 0; + size_t entry_offset, size = 0; int rc; file_private_info_t *p_info; p_info = ((file_private_info_t *) file->private_data); - if (*offset >= p_info->len) { - return 0; /* EOF */ - } else { - len = MIN(user_len, (p_info->len - *offset)); - if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len))) - return rc;; - (*offset) += len; - return len; /* number of bytes "read" */ + if (*offset != p_info->offset) + return -EPIPE; + if(p_info->act_area >= p_info->debug_info_snap->nr_areas) + return 0; + + entry_offset = p_info->act_entry_offset; + + while(count < len){ + size = debug_format_entry(p_info); + size = MIN((len - count), (size - entry_offset)); + + if(size){ + if ((rc = copy_to_user(user_buf + count, + p_info->temp_buf + entry_offset, size))) + return rc; + } + count += size; + entry_offset = 0; + if(count != len) + if(debug_next_entry(p_info)) + goto out; } +out: + p_info->offset = *offset + count; + p_info->act_entry_offset = size; + *offset = p_info->offset; + return count; } /* @@ -322,68 +476,16 @@ down(&debug_lock); p_info = ((file_private_info_t *) file->private_data); if (p_info->view->input_proc) - rc = p_info->view->input_proc(p_info->debug_info, + rc = p_info->view->input_proc(p_info->debug_info_org, p_info->view, file, user_buf, length, offset); + else + rc = -EPERM; up(&debug_lock); return rc; /* number of input characters */ } /* - * debug_format_output: - * - calls prolog, header and format functions of view to format output - */ - -static int debug_format_output(debug_info_t * debug_area, char *buf, - int size, struct debug_view *view) -{ - int len = 0; - int i, j; - int nr_of_entries; - debug_entry_t *act_entry; - - /* print prolog */ - if (view->prolog_proc) - len += view->prolog_proc(debug_area, view, buf); - /* print debug records */ - if (!(view->format_proc) && !(view->header_proc)) - goto out; - nr_of_entries = PAGE_SIZE / debug_area->entry_size - << debug_area->page_order; - for (i = 0; i < debug_area->nr_areas; i++) { - act_entry = debug_area->areas[i]; - for (j = 0; j < nr_of_entries; j++) { - if (act_entry->id.fields.used == 0) - break; /* empty entry */ - if (view->header_proc) - len += view->header_proc(debug_area, view, i, - act_entry, buf + len); - if (view->format_proc) - len += view->format_proc(debug_area, view, - buf + len, - DEBUG_DATA(act_entry)); - if (len > size) { - printk(KERN_ERR - "debug: error -- memory exceeded for (%s/%s)\n", - debug_area->name, view->name); - printk(KERN_ERR "debug: fix view %s!!\n", - view->name); - printk(KERN_ERR - "debug: area: %i (0 - %i) entry: %i (0 - %i)\n", - i, debug_area->nr_areas - 1, j, - nr_of_entries - 1); - goto out; - } - act_entry = (debug_entry_t *) (((char *) act_entry) + - debug_area->entry_size); - } - } - out: - return len; -} - - -/* * debug_open: * - called for user open() * - copies formated output to private_data area of the file @@ -392,17 +494,14 @@ static int debug_open(struct inode *inode, struct file *file) { - int i = 0, size = 0, rc = 0, f_entry_size = 0; + int i = 0, rc = 0; file_private_info_t *p_info; - debug_info_t* debug_info; + debug_info_t *debug_info, *debug_info_snapshot; #ifdef DEBUG printk("debug_open\n"); #endif - -#ifdef MODULE MOD_INC_USE_COUNT; -#endif down(&debug_lock); /* find debug log and view */ @@ -422,87 +521,41 @@ /* no entry found */ rc = -EINVAL; goto out; + found: - if ((file->private_data = - kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { - printk(KERN_ERR "debug_open: kmalloc failed\n"); + + /* make snapshot of current debug areas to get it consistent */ + + debug_info_snapshot = debug_info_copy(debug_info); + + if(!debug_info_snapshot){ + printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n"); rc = -ENOMEM; goto out; } - p_info = (file_private_info_t *) file->private_data; - - /* - * the size for the formated output is calculated - * with the following formula: - * - * prolog-size - * + - * (record header size + record data field size) - * * number of entries per page - * * number of pages per area - * * number of areas - */ - - if (debug_info->views[i]->prolog_proc) - size += - debug_info->views[i]->prolog_proc(debug_info, - debug_info-> - views[i], NULL); - - if (debug_info->views[i]->header_proc) - f_entry_size = - debug_info->views[i]->header_proc(debug_info, - debug_info-> - views[i], 0, NULL, - NULL); - if (debug_info->views[i]->format_proc) - f_entry_size += - debug_info->views[i]->format_proc(debug_info, - debug_info-> - views[i], NULL, - NULL); - - size += f_entry_size - * (PAGE_SIZE / debug_info->entry_size - << debug_info->page_order) - * debug_info->nr_areas + 1; /* terminating \0 */ -#ifdef DEBUG - printk("debug_open: size: %i\n", size); -#endif - /* alloc some bytes more to be safe against bad views */ - if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) { - printk(KERN_ERR "debug_open: vmalloc failed\n"); - vfree(file->private_data); + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + debug_info_free(debug_info_snapshot); rc = -ENOMEM; goto out; } - - p_info->size = size; - p_info->debug_info = debug_info; + p_info = (file_private_info_t *) file->private_data; + p_info->offset = 0; + p_info->debug_info_snap = debug_info_snapshot; + p_info->debug_info_org = debug_info; p_info->view = debug_info->views[i]; + p_info->act_area = 0; + p_info->act_entry = DEBUG_PROLOG_ENTRY; + p_info->act_entry_offset = 0; - spin_lock_irq(&debug_info->lock); - - p_info->len = - debug_format_output(debug_info, p_info->data, size, - debug_info->views[i]); -#ifdef DEBUG - { - int ilen = p_info->len; - printk("debug_open: len: %i\n", ilen); - } -#endif - - spin_unlock_irq(&debug_info->lock); debug_info_get(debug_info); out: up(&debug_lock); -#ifdef MODULE if (rc != 0) MOD_DEC_USE_COUNT; -#endif return rc; } @@ -518,18 +571,11 @@ #ifdef DEBUG printk("debug_close\n"); #endif - down(&debug_lock); p_info = (file_private_info_t *) file->private_data; - debug_info_put(p_info->debug_info); - if (p_info->data) { - vfree(p_info->data); - kfree(file->private_data); - } - up(&debug_lock); - -#ifdef MODULE + debug_info_free(p_info->debug_info_snap); + debug_info_put(p_info->debug_info_org); + kfree(file->private_data); MOD_DEC_USE_COUNT; -#endif return 0; /* success */ } @@ -607,9 +653,7 @@ { debug_info_t *rc = NULL; -#ifdef MODULE MOD_INC_USE_COUNT; -#endif if (!initialized) debug_init(); down(&debug_lock); @@ -626,9 +670,7 @@ out: if (rc == NULL){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif } up(&debug_lock); return rc; @@ -648,9 +690,7 @@ debug_info_put(id); up(&debug_lock); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif out: return; } @@ -662,7 +702,7 @@ void debug_set_level(debug_info_t* id, int new_level) { - long flags; + unsigned long flags; if(!id) return; spin_lock_irqsave(&id->lock,flags); @@ -687,7 +727,7 @@ * - set active entry to next in the ring buffer */ -static inline void proceed_active_entry(debug_info_t * id) +extern inline void proceed_active_entry(debug_info_t * id) { if ((id->active_entry[id->active_area] += id->entry_size) > ((PAGE_SIZE << (id->page_order)) - id->entry_size)) @@ -699,7 +739,7 @@ * - set active area to next in the ring buffer */ -static inline void proceed_active_area(debug_info_t * id) +extern inline void proceed_active_area(debug_info_t * id) { id->active_area++; id->active_area = id->active_area % id->nr_areas; @@ -709,7 +749,7 @@ * get_active_entry: */ -static inline debug_entry_t *get_active_entry(debug_info_t * id) +extern inline debug_entry_t *get_active_entry(debug_info_t * id) { return (debug_entry_t *) ((char *) id->areas[id->active_area] + id->active_entry[id->active_area]); @@ -720,160 +760,126 @@ * - set timestamp, caller address, cpu number etc. */ -static inline debug_entry_t *debug_common(debug_info_t * id) +extern inline debug_entry_t *debug_common(debug_info_t * id, int level, + const void *buf, int len, int exception) { + unsigned long flags; debug_entry_t *active; + spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); STCK(active->id.stck); active->id.fields.cpuid = smp_processor_id(); - active->id.fields.used = 1; active->caller = __builtin_return_address(0); - return active; -} - -/* - * debug_event: - */ - -debug_entry_t *debug_event(debug_info_t * id, int level, void *buf, - int len) -{ - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 0; + active->id.fields.exception = exception; + active->id.fields.level = level; memset(DEBUG_DATA(active), 0, id->buf_size); memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); proceed_active_entry(id); + if(exception) + proceed_active_area(id); spin_unlock_irqrestore(&id->lock, flags); - out: + return active; } /* - * debug_int_event: + * debug_event_common: + * - write debug entry with given size */ -debug_entry_t *debug_int_event(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf, + int len) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 0; - memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + return debug_common(id, level, buf, len, 0); } /* - * debug_text_event: + * debug_exception_common: + * - write debug entry with given size and switch to next debug area */ -debug_entry_t *debug_text_event(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_exception_common(debug_info_t * id, int level, + const void *buf, int len) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - memset(DEBUG_DATA(active), 0, id->buf_size); - strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 0; - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; - + return debug_common(id, level, buf, len, 1); } /* - * debug_exception: + * counts arguments in format string for sprintf view */ -debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, - int len) +extern inline int debug_count_numargs(char *string) { - long flags; - debug_entry_t *active = NULL; + int numargs=0; - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + while(*string) { + if(*string++=='%') + numargs++; + } + return(numargs); } /* - * debug_int_exception: + * debug_sprintf_event: */ -debug_entry_t *debug_int_exception(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_sprintf_event(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(DEBUG_DATA(active), 0, id->buf_size); - memcpy(DEBUG_DATA(active), &tag, - MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idxargs[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,0); + va_end(ap); + } + return retval; + } } /* - * debug_text_exception: + * debug_sprintf_exception: */ -debug_entry_t *debug_text_exception(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_sprintf_exception(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level > id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - memset(DEBUG_DATA(active), 0, id->buf_size); - strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 1; - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idxargs[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,1); + va_end(ap); + } + return retval; + } } /* @@ -908,7 +914,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; mode_t mode = S_IFREG; if (!id) @@ -951,7 +957,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; if (!id) goto out; @@ -987,13 +993,8 @@ { int rc = 0; - if (out_buf == NULL) { - rc = 2; - goto out; - } if(id->level == -1) rc = sprintf(out_buf,"-\n"); else rc = sprintf(out_buf, "%i\n", id->level); - out: return rc; } @@ -1010,8 +1011,10 @@ if (*offset != 0) goto out; - if ((rc = copy_from_user(input_buf, user_buf, 1))) + if (copy_from_user(input_buf, user_buf, 1)){ + rc = -EFAULT; goto out; + } if (isdigit(input_buf[0])) { int new_level = ((int) input_buf[0] - (int) '0'); debug_set_level(id, new_level); @@ -1036,10 +1039,7 @@ int rc; rc = sizeof(debug_entry_t); - if (out_buf == NULL) - goto out; memcpy(out_buf,entry,sizeof(debug_entry_t)); - out: return rc; } @@ -1053,10 +1053,7 @@ int rc; rc = id->buf_size; - if (out_buf == NULL || in_buf == NULL) - goto out; memcpy(out_buf, in_buf, id->buf_size); - out: return rc; } @@ -1069,10 +1066,6 @@ { int i, rc = 0; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size * 4 + 3; - goto out; - } for (i = 0; i < id->buf_size; i++) { rc += sprintf(out_buf + rc, "%02x ", ((unsigned char *) in_buf)[i]); @@ -1086,7 +1079,6 @@ rc += sprintf(out_buf + rc, "%c", c); } rc += sprintf(out_buf + rc, "\n"); - out: return rc; } @@ -1102,12 +1094,9 @@ char *except_str; unsigned long caller; int rc = 0; + unsigned int level; - if (out_buf == NULL) { - rc = DEBUG_PROC_HEADER_SIZE; - goto out; - } - + level = entry->id.fields.level; time = entry->id.stck; /* adjust todclock to 1970 */ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); @@ -1119,18 +1108,60 @@ except_str = "-"; caller = (unsigned long) entry->caller; #if defined(CONFIG_ARCH_S390X) - rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ", - area, time_val.tv_sec, - time_val.tv_usec, except_str, - entry->id.fields.cpuid, caller); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #else caller &= 0x7fffffff; - rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ", - area, time_val.tv_sec, - time_val.tv_usec, except_str, - entry->id.fields.cpuid, caller); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #endif - out: + return rc; +} + +/* + * prints debug data sprintf-formated: + * debug_sprinf_event/exception calls must be used together with this view + */ + +#define DEBUG_SPRINTF_MAX_ARGS 10 + +int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event) +{ + int num_longs, num_used_args = 0,i, rc = 0; + int index[DEBUG_SPRINTF_MAX_ARGS]; + + /* count of longs fit into one entry */ + num_longs = id->buf_size / sizeof(long); + + if(num_longs < 1) + goto out; /* bufsize of entry too small */ + if(num_longs == 1) { + /* no args, we use only the string */ + strcpy(out_buf, curr_event->string); + rc = strlen(curr_event->string); + goto out; + } + + /* number of arguments used for sprintf (without the format string) */ + num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + + memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int)); + + for(i = 0; i < num_used_args; i++) + index[i] = i; + + rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]], + curr_event->args[index[1]], curr_event->args[index[2]], + curr_event->args[index[3]], curr_event->args[index[4]], + curr_event->args[index[5]], curr_event->args[index[6]], + curr_event->args[index[7]], curr_event->args[index[8]], + curr_event->args[index[9]]); + +out: + return rc; } @@ -1165,3 +1196,17 @@ } #endif /* MODULE */ + +EXPORT_SYMBOL(debug_register); +EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_set_level); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); +EXPORT_SYMBOL(debug_event_common); +EXPORT_SYMBOL(debug_exception_common); +EXPORT_SYMBOL(debug_hex_ascii_view); +EXPORT_SYMBOL(debug_raw_view); +EXPORT_SYMBOL(debug_dflt_header_fn); +EXPORT_SYMBOL(debug_sprintf_view); +EXPORT_SYMBOL(debug_sprintf_exception); +EXPORT_SYMBOL(debug_sprintf_event); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/ebcdic.c linux.ac/arch/s390/kernel/ebcdic.c --- linux.vanilla/arch/s390/kernel/ebcdic.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/ebcdic.c Thu Apr 12 11:59:46 2001 @@ -9,6 +9,7 @@ * Martin Peschke */ +#include #include /* @@ -389,3 +390,11 @@ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + +EXPORT_SYMBOL_NOVERS(_ascebc_500); +EXPORT_SYMBOL_NOVERS(_ebcasc_500); +EXPORT_SYMBOL_NOVERS(_ascebc); +EXPORT_SYMBOL_NOVERS(_ebcasc); +EXPORT_SYMBOL_NOVERS(_ebc_tolower); +EXPORT_SYMBOL_NOVERS(_ebc_toupper); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/entry.S linux.ac/arch/s390/kernel/entry.S --- linux.vanilla/arch/s390/kernel/entry.S Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390/kernel/entry.S Thu Apr 12 11:59:46 2001 @@ -9,56 +9,52 @@ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), */ +#define ASSEMBLY + #include #include #include #include #include -#define ASSEMBLY #include -#include - +#include /* - * stack layout for the system_call stack entry - * Martin please don't modify these back to hard coded values - * You know how bad I'm at mental arithmetic DJB & it gives - * me grief when I modify the pt_regs + * Stack layout for the system_call stack entry. + * The first few entries are identical to the user_regs_struct. */ SP_PTREGS = STACK_FRAME_OVERHEAD -SP_PSW = SP_PTREGS -SP_R0 = (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE) -SP_R1 = (SP_R0+GPR_SIZE) -SP_R2 = (SP_R1+GPR_SIZE) -SP_R3 = (SP_R2+GPR_SIZE) -SP_R4 = (SP_R3+GPR_SIZE) -SP_R5 = (SP_R4+GPR_SIZE) -SP_R6 = (SP_R5+GPR_SIZE) -SP_R7 = (SP_R6+GPR_SIZE) -SP_R8 = (SP_R7+GPR_SIZE) -SP_R9 = (SP_R8+GPR_SIZE) -SP_RA = (SP_R9+GPR_SIZE) -SP_RB = (SP_RA+GPR_SIZE) -SP_RC = (SP_RB+GPR_SIZE) -SP_RD = (SP_RC+GPR_SIZE) -SP_RE = (SP_RD+GPR_SIZE) -SP_RF = (SP_RE+GPR_SIZE) -SP_AREGS = (SP_RF+GPR_SIZE) -SP_ORIG_R2 = (SP_AREGS+(NUM_ACRS*ACR_SIZE)) +SP_PSW = STACK_FRAME_OVERHEAD + PT_PSWMASK +SP_R0 = STACK_FRAME_OVERHEAD + PT_GPR0 +SP_R1 = STACK_FRAME_OVERHEAD + PT_GPR1 +SP_R2 = STACK_FRAME_OVERHEAD + PT_GPR2 +SP_R3 = STACK_FRAME_OVERHEAD + PT_GPR3 +SP_R4 = STACK_FRAME_OVERHEAD + PT_GPR4 +SP_R5 = STACK_FRAME_OVERHEAD + PT_GPR5 +SP_R6 = STACK_FRAME_OVERHEAD + PT_GPR6 +SP_R7 = STACK_FRAME_OVERHEAD + PT_GPR7 +SP_R8 = STACK_FRAME_OVERHEAD + PT_GPR8 +SP_R9 = STACK_FRAME_OVERHEAD + PT_GPR9 +SP_R10 = STACK_FRAME_OVERHEAD + PT_GPR10 +SP_R11 = STACK_FRAME_OVERHEAD + PT_GPR11 +SP_R12 = STACK_FRAME_OVERHEAD + PT_GPR12 +SP_R13 = STACK_FRAME_OVERHEAD + PT_GPR13 +SP_R14 = STACK_FRAME_OVERHEAD + PT_GPR14 +SP_R15 = STACK_FRAME_OVERHEAD + PT_GPR15 +SP_AREGS = STACK_FRAME_OVERHEAD + PT_ACR0 +SP_ORIG_R2 = STACK_FRAME_OVERHEAD + PT_ORIGGPR2 +/* Now the additional entries */ SP_TRAP = (SP_ORIG_R2+GPR_SIZE) #if CONFIG_REMOTE_DEBUG SP_CRREGS = (SP_TRAP+4) /* fpu registers are saved & restored by the gdb stub itself */ SP_FPC = (SP_CRREGS+(NUM_CRS*CR_SIZE)) SP_FPRS = (SP_FPC+FPC_SIZE+FPC_PAD_SIZE) -/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not - defined in ptrace.h but space is needed for this too */ SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE)) #else SP_PGM_OLD_ILC= (SP_TRAP+4) #endif -SP_SVC_STEP = (SP_PGM_OLD_ILC+4) -SP_SIZE = (SP_SVC_STEP+4) +SP_SIZE = (SP_PGM_OLD_ILC+4) /* * these defines are offsets into the thread_struct */ @@ -73,6 +69,8 @@ _TSS_TRAP = (_TSS_PROT+4) _TSS_MM = (_TSS_TRAP+4) _TSS_PER = (_TSS_MM+8) +_TSS_IEEE = (_TSS_PER+36) +_TSS_FLAGS = (_TSS_IEEE+4) /* * these are offsets into the task-struct. @@ -84,11 +82,6 @@ tsk_ptrace = 28 processor = 60 -/* PSW related defines */ -disable = 0xFC -enable = 0x03 -daton = 0x04 - /* * Base Address of this Module --- saved in __LC_ENTRY_BASE */ @@ -97,26 +90,6 @@ #define BASED(name) name-entry_base(%r13) -#if 0 -/* some code left lying around in case we need a - * printk for debugging purposes - */ - sysc_printk: .long printk - sysc_msg: .string "<2>r15 %X\n" - .align 4 - -# basr %r13,0 - l %r0,SP_PSW+4(%r15) - sll %r0,1 - chi %r0,0 - jnz sysc_dn - l %r9,sysc_printk-sysc_lit(%r13) - la %r2,sysc_msg-sysc_lit(%r13) - lr %r3,%r15 - basr %r14,%r9 -sysc_dn: -#endif - /* * Register usage in interrupt handlers: * R9 - pointer to current task structure @@ -125,38 +98,41 @@ * R15 - kernel stack pointer */ -#define SAVE_ALL(psworg) \ - stm %r13,%r15,__LC_SAVE_AREA ; \ - stam %a2,%a4,__LC_SAVE_AREA+12 ; \ - basr %r13,0 ; /* temp base pointer */ \ - l %r13,.Lentry_base-.(%r13) ; /* load &entry_base to %r13 */ \ - tm psworg+1,0x01 ; /* test problem state bit */ \ - bz BASED(.+12) ; /* skip stack setup save */ \ - l %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \ - lam %a2,%a4,BASED(.Lc_ac) ; /* set ac.reg. 2 to primary space */ \ - /* and access reg. 4 to home space */ \ -0: s %r15,BASED(.Lc_spsize); /* make room for registers & psw */ \ - n %r15,BASED(.Lc0xfffffff8) ; /* align stack pointer to 8 */ \ - stm %r0,%r12,SP_R0(%r15) ; /* store gprs 0-12 to kernel stack */ \ - st %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \ - mvc SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \ - stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \ - mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \ - mvc SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \ - la %r0,psworg ; /* store trap indication */ \ - st %r0,SP_TRAP(%r15) ; \ - xc 0(4,%r15),0(%r15) ; /* clear back chain */ - -#define RESTORE_ALL \ - mvc __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ - lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ - ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ - lpsw __LC_RETURN_PSW /* back to caller */ + .macro SAVE_ALL psworg # system entry macro + stm %r13,%r15,__LC_SAVE_AREA + stam %a2,%a4,__LC_SAVE_AREA+12 + basr %r13,0 # temp base pointer + l %r13,.Lentry_base-.(%r13) # load &entry_base to %r13 + tm \psworg+1,0x01 # test problem state bit + bz BASED(.+12) # skip stack setup save + l %r15,__LC_KERNEL_STACK # problem state -> load ksp + lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space + # and access reg. 4 to home space +0: s %r15,BASED(.Lc_spsize) # make room for registers & psw + n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 + stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack + st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 + mvc SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs + mvc SP_PSW(8,%r15),\psworg # move user PSW to stack + la %r0,\psworg # store trap indication + st %r0,SP_TRAP(%r15) + xc 0(4,%r15),0(%r15) # clear back chain + .endm + + .macro RESTORE_ALL # system exit macro + mvc __LC_RETURN_PSW(8),SP_PSW(%r15) # move user PSW to lowcore + lam %a0,%a15,SP_AREGS(%r15) # load the access registers + lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user + ni __LC_RETURN_PSW+1,0xfd # clear wait state bit + lpsw __LC_RETURN_PSW # back to caller + .endm -#define GET_CURRENT /* load pointer to task_struct to R9 */ \ - lr %r9,%r15 ; \ + .macro GET_CURRENT + lr %r9,%r15 # load pointer to task_struct to %r9 n %r9,BASED(.Lc0xffffe000) + .endm /* @@ -173,7 +149,7 @@ l %r4,_TSS_PTREGS(%r3) tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? bz resume_noper-resume_base(%r1) # if not we're fine - stctl %r9,%r11,24(%r15) # We are using per stuff + stctl %c9,%c11,24(%r15) # We are using per stuff clc _TSS_PER(12,%r3),24(%r15) be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't @@ -202,13 +178,13 @@ .globl system_call system_call: - SAVE_ALL(0x20) - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + SAVE_ALL __LC_SVC_OLD_PSW + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid pgm_system_call: + GET_CURRENT # load pointer to task_struct to R9 slr %r8,%r8 # gpr 8 is call save (-> tracesys) ic %r8,0x8B # get svc number from lowcore stosm 24(%r15),0x03 # reenable interrupts - GET_CURRENT # load pointer to task_struct to R9 sll %r8,2 l %r8,sys_call_table-entry_base(8,%r13) # get address of system call tm tsk_ptrace+3(%r9),0x02 # PT_TRACESYS @@ -219,7 +195,6 @@ # changing anything here !! sysc_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? bno BASED(sysc_leave) # no-> skip bottom half, resched & signal # @@ -237,9 +212,9 @@ icm %r0,15,sigpending(%r9) # get sigpending from task_struct bnz BASED(sysc_signal_return) sysc_leave: - icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct - bnz BASED(pgm_svcret) - stnsm 24(%r15),disable # disable I/O and ext. interrupts + tm SP_PGM_OLD_ILC(%r15),0xff + bz BASED(pgm_svcret) + stnsm 24(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -371,7 +346,7 @@ br %r1 # branch to sys_rt_sigsuspend sys_sigaltstack_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter l %r1,BASED(.Lsigaltstack) br %r1 # branch to sys_sigreturn @@ -647,20 +622,19 @@ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + mvc SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs mvc SP_PSW(8,%r15),0x20 # move user PSW to stack la %r0,0x20 # store trap indication st %r0,SP_TRAP(%r15) xc 0(4,%r15),0(%r15) # clear back chain - mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information b BASED(pgm_system_call) # now do the svc pgm_svcret: mvi SP_TRAP+3(%r15),0x28 # set trap indication back to pgm_chk lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid b BASED(pgm_no_sv) pgm_sv: tm 0x29,0x01 # test problem state bit @@ -672,25 +646,25 @@ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + mvc SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs mvc SP_PSW(8,%r15),0x28 # move user PSW to stack la %r0,0x28 # store trap indication st %r0,SP_TRAP(%r15) xc 0(4,%r15),0(%r15) # clear back chain - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - lh %r7,__LC_PGM_ILC # load instruction length + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid + lh %r7,__LC_PGM_ILC # load instruction length + GET_CURRENT pgm_no_sv: lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it - stosm 24(%r15),0x03 # reenable interrupts lr %r3,%r8 la %r0,0x7f nr %r3,%r0 # clear per-event-bit be BASED(pgm_dn) # none of Martins exceptions occurred bypass - l %r9,BASED(.Ljump_table) + l %r1,BASED(.Ljump_table) sll %r3,2 - l %r9,0(%r3,%r9) # load address of handler routine + l %r1,0(%r3,%r1) # load address of handler routine la %r2,SP_PTREGS(%r15) # address of register-save area srl %r3,2 cl %r3,BASED(.Lc4) # protection-exception ? @@ -698,14 +672,17 @@ l %r5,SP_PSW+4(15) # load psw addr sr %r5,%r7 # substract ilc from psw st %r5,SP_PSW+4(15) # store corrected psw addr -pgm_go: basr %r14,%r9 # branch to interrupt-handler +pgm_per:cl %r3,BASED(.Lc20) # pseudo page fault ? + be BASED(pgm_go) # if yes then don't reenable interrupts + stosm 24(%r15),0x03 # reenable interrupts +pgm_go: basr %r14,%r1 # branch to interrupt-handler pgm_dn: la %r0,0x80 nr %r8,%r0 # check for per exception be BASED(pgm_return) la %r2,SP_PTREGS(15) # address of register-save area - l %r9,BASED(.Lhandle_per) # load adr. of per handler + l %r1,BASED(.Lhandle_per) # load adr. of per handler la %r14,BASED(sysc_return) # load adr. of system return - br %r9 # branch to handle_per_exception + br %r1 # branch to handle_per_exception # # the backend code is the same as for sys-call @@ -719,19 +696,19 @@ .globl io_int_handler io_int_handler: - SAVE_ALL(0x38) + SAVE_ALL __LC_IO_OLD_PSW + GET_CURRENT # load pointer to task_struct to R9 la %r2,SP_PTREGS(%r15) # address of register-save area sr %r3,%r3 icm %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int - l %r4,__LC_IO_INT_PARM # load interruption parm - l %r5,__LC_IO_INT_WORD # load interruption word - l %r9,BASED(.Ldo_IRQ) # load address of do_IRQ - basr %r14,%r9 # branch to standard irq handler + l %r4,__LC_IO_INT_PARM # load interuption parm + l %r5,__LC_IO_INT_WORD # load interuption word + l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ + basr %r14,%r1 # branch to standard irq handler io_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - bz BASED(io_leave) # no-> skip resched & signal + bno BASED(io_leave) # no-> skip resched & signal stosm 24(%r15),0x03 # reenable interrupts # # check, if bottom-half has to be done @@ -748,7 +725,7 @@ icm %r0,15,sigpending(%r9) # get sigpending from task_struct bnz BASED(io_signal_return) io_leave: - stnsm 24(%r15),disable # disable I/O and ext. interrupts + stnsm 24(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -784,26 +761,27 @@ .globl ext_int_handler ext_int_handler: - SAVE_ALL(0x18) + SAVE_ALL __LC_EXT_OLD_PSW + GET_CURRENT # load pointer to task_struct to R9 la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # error code lr %r1,%r3 # calculate index = code & 0xff n %r1,BASED(.Lc0xff) sll %r1,2 - l %r9,BASED(.Lext_hash) - l %r9,0(%r1,%r9) # get first list entry for hash value - ltr %r9,%r9 # == NULL ? + l %r4,BASED(.Lext_hash) + l %r4,0(%r1,%r4) # get first list entry for hash value + ltr %r4,%r4 # == NULL ? bz BASED(io_return) # yes, nothing to do, exit ext_int_loop: - ch %r3,8(%r9) # compare external interrupt code + ch %r3,8(%r4) # compare external interrupt code be BASED(ext_int_found) - icm %r9,15,0(%r9) # next list entry + icm %r4,15,0(%r4) # next list entry bnz BASED(ext_int_loop) b BASED(io_return) ext_int_found: - l %r9,4(%r9) # get handler address + l %r4,4(%r4) # get handler address la %r14,BASED(io_return) - br %r9 # branch to ext call handler + br %r4 # branch to ext call handler /* * Machine check handler routines @@ -811,7 +789,7 @@ .globl mcck_int_handler mcck_int_handler: - SAVE_ALL(0x30) + SAVE_ALL __LC_MCK_OLD_PSW l %r1,BASED(.Ls390_mcck) basr %r14,%r1 # call machine check handler mcck_return: @@ -826,7 +804,7 @@ l %r15,__LC_KERNEL_STACK # load ksp lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs lam %a0,%a15,__LC_AREGS_SAVE_AREA - stosm 0(%r15),daton # now we can turn dat on + stosm 0(%r15),0x04 # now we can turn dat on lm %r6,%r15,24(%r15) # load registers from clone basr %r14,0 l %r14,restart_addr-.(%r14) @@ -859,6 +837,7 @@ .Lc_ac: .long 0,0,1 .Lc_ENOSYS: .long -ENOSYS .Lc4: .long 4 +.Lc20: .long 20 .Lc0x1202: .long 0x1202 .Lc0x1004: .long 0x1004 .Lc0x2401: .long 0x2401 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/floatlib.c linux.ac/arch/s390/kernel/floatlib.c --- linux.vanilla/arch/s390/kernel/floatlib.c Fri May 12 19:41:44 2000 +++ linux.ac/arch/s390/kernel/floatlib.c Thu Jan 1 01:00:00 1970 @@ -1,1021 +0,0 @@ -/* -** libgcc support for software floating point. -** Copyright (C) 1991 by Pipeline Associates, Inc. All rights reserved. -** Permission is granted to do *anything* you want with this file, -** commercial or otherwise, provided this message remains intact. So there! -** I would appreciate receiving any updates/patches/changes that anyone -** makes, and am willing to be the repository for said changes (am I -** making a big mistake?). - -Warning! Only single-precision is actually implemented. This file -won't really be much use until double-precision is supported. - -However, once that is done, this file might eventually become a -replacement for libgcc1.c. It might also make possible -cross-compilation for an IEEE target machine from a non-IEEE -host such as a VAX. - -If you'd like to work on completing this, please talk to rms@gnu.ai.mit.edu. - ---> Double precision floating support added by James Carlson on 20 April 1998. - -** -** Pat Wood -** Pipeline Associates, Inc. -** pipeline!phw@motown.com or -** sun!pipeline!phw or -** uunet!motown!pipeline!phw -** -** 05/01/91 -- V1.0 -- first release to gcc mailing lists -** 05/04/91 -- V1.1 -- added float and double prototypes and return values -** -- fixed problems with adding and subtracting zero -** -- fixed rounding in truncdfsf2 -** -- fixed SWAP define and tested on 386 -*/ - -/* -** The following are routines that replace the libgcc soft floating point -** routines that are called automatically when -msoft-float is selected. -** The support single and double precision IEEE format, with provisions -** for byte-swapped machines (tested on 386). Some of the double-precision -** routines work at full precision, but most of the hard ones simply punt -** and call the single precision routines, producing a loss of accuracy. -** long long support is not assumed or included. -** Overall accuracy is close to IEEE (actually 68882) for single-precision -** arithmetic. I think there may still be a 1 in 1000 chance of a bit -** being rounded the wrong way during a multiply. I'm not fussy enough to -** bother with it, but if anyone is, knock yourself out. -** -** Efficiency has only been addressed where it was obvious that something -** would make a big difference. Anyone who wants to do this right for -** best speed should go in and rewrite in assembler. -** -** I have tested this only on a 68030 workstation and 386/ix integrated -** in with -msoft-float. -*/ - -#define float long -#define double long long - -/* the following deal with IEEE single-precision numbers */ -#define EXCESS 126 -#define SIGNBIT 0x80000000 -#define HIDDEN (1 << 23) -#define SIGN(fp) ((fp) & SIGNBIT) -#define EXP(fp) (((fp) >> 23) & 0xFF) -#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) -#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) - -/* the following deal with IEEE double-precision numbers */ -#define EXCESSD 1022 -#define HIDDEND (1 << 20) -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) -#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) |(fp.l.lower >> 22)) -#define HIDDEND_LL ((long long)1 << 52) -#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) -#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) - -/* define SWAP for 386/960 reverse-byte-order brain-damaged CPUs */ -union double_long { - double d; -#ifdef SWAP - struct { - unsigned long lower; - long upper; - } l; -#else - struct { - long upper; - unsigned long lower; - } l; -#endif - long long ll; -}; - -union float_long - { - float f; - long l; - }; - -long long -__negdi2 (long long u) -{ - - union lll { - long long ll; - long s[2]; - }; - - union lll w,uu; - - uu.ll = u; - - w.s[1] = -uu.s[1]; - w.s[0] = -uu.s[0] - ((int) w.s[1] != 0); - - return w.ll; -} - - - -/* add two floats */ -float -__addsf3 (float a1, float a2) -{ - register long mant1, mant2; - register union float_long fl1, fl2; - register int exp1, exp2; - int sign = 0; - - fl1.f = a1; - fl2.f = a2; - - /* check for zero args */ - if (!fl1.l) { - fl1.f = fl2.f; - goto test_done; - } - if (!fl2.l) - goto test_done; - - exp1 = EXP (fl1.l); - exp2 = EXP (fl2.l); - - if (exp1 > exp2 + 25) - goto test_done; - if (exp2 > exp1 + 25) { - fl1.f = fl2.f; - goto test_done; - } - - /* do everything in excess precision so's we can round later */ - mant1 = MANT (fl1.l) << 6; - mant2 = MANT (fl2.l) << 6; - - if (SIGN (fl1.l)) - mant1 = -mant1; - if (SIGN (fl2.l)) - mant2 = -mant2; - - if (exp1 > exp2) - { - mant2 >>= exp1 - exp2; - } - else - { - mant1 >>= exp2 - exp1; - exp1 = exp2; - } - mant1 += mant2; - - if (mant1 < 0) - { - mant1 = -mant1; - sign = SIGNBIT; - } - else if (!mant1) { - fl1.f = 0; - goto test_done; - } - - /* normalize up */ - while (!(mant1 & 0xE0000000)) - { - mant1 <<= 1; - exp1--; - } - - /* normalize down? */ - if (mant1 & (1 << 30)) - { - mant1 >>= 1; - exp1++; - } - - /* round to even */ - mant1 += (mant1 & 0x40) ? 0x20 : 0x1F; - - /* normalize down? */ - if (mant1 & (1 << 30)) - { - mant1 >>= 1; - exp1++; - } - - /* lose extra precision */ - mant1 >>= 6; - - /* turn off hidden bit */ - mant1 &= ~HIDDEN; - - /* pack up and go home */ - fl1.l = PACK (sign, exp1, mant1); -test_done: - return (fl1.f); -} - -/* subtract two floats */ -float -__subsf3 (float a1, float a2) -{ - register union float_long fl1, fl2; - - fl1.f = a1; - fl2.f = a2; - - /* check for second arg zero */ - if (!fl2.l) - return (fl1.f); - /* twiddle sign bit */ - fl2.l ^= SIGNBIT; - /* check for first arg zero */ - if (!fl1.l) - return (fl2.f); - /* add values */ - return __addsf3 (a1, fl2.f); -} - -/* compare two floats */ -long -__cmpsf2 (float a1, float a2) -{ - register union float_long fl1, fl2; - - fl1.f = a1; - fl2.f = a2; - - if (SIGN (fl1.l) && SIGN (fl2.l)) - { - fl1.l ^= SIGNBIT; - fl2.l ^= SIGNBIT; - if (fl1.l < fl2.l) - return (-1); - if (fl1.l > fl2.l) - return (1); - return 0; - } else { - if (fl1.l < fl2.l) - return (-1); - if (fl1.l > fl2.l) - return (1); - return (0); - } -} - -/* multiply two floats */ -float -__mulsf3 (float a1, float a2) -{ - register union float_long fl1, fl2; - register unsigned long result; - register int exp; - int sign; - - fl1.f = a1; - fl2.f = a2; - - if (!fl1.l || !fl2.l) { - fl1.f = 0; - goto test_done; - } - - /* compute sign and exponent */ - sign = SIGN (fl1.l) ^ SIGN (fl2.l); - exp = EXP (fl1.l) - EXCESS; - exp += EXP (fl2.l); - - fl1.l = MANT (fl1.l); - fl2.l = MANT (fl2.l); - - /* the multiply is done as one 16x16 multiply and two 16x8 multiples */ - result = (fl1.l >> 8) * (fl2.l >> 8); - result += ((fl1.l & 0xFF) * (fl2.l >> 8)) >> 8; - result += ((fl2.l & 0xFF) * (fl1.l >> 8)) >> 8; - - result >>= 2; - if (result & 0x20000000) - { - /* round */ - result += 0x20; - result >>= 6; - } - else - { - /* round */ - result += 0x10; - result >>= 5; - exp--; - } - if (result & (HIDDEN<<1)) { - result >>= 1; - exp++; - } - - result &= ~HIDDEN; - - /* pack up and go home */ - fl1.l = PACK (sign, exp, result); -test_done: - return (fl1.f); -} - -/* divide two floats */ -float -__divsf3 (float a1, float a2) -{ - register union float_long fl1, fl2; - register int result; - register int mask; - register int exp, sign; - - fl1.f = a1; - fl2.f = a2; - - /* subtract exponents */ - exp = EXP (fl1.l) - EXP (fl2.l) + EXCESS; - - /* compute sign */ - sign = SIGN (fl1.l) ^ SIGN (fl2.l); - - /* divide by zero??? */ - if (!fl2.l) - /* return NaN or -NaN */ - return (sign ? 0xFFFFFFFF : 0x7FFFFFFF); - - /* numerator zero??? */ - if (!fl1.l) - return (0); - - /* now get mantissas */ - fl1.l = MANT (fl1.l); - fl2.l = MANT (fl2.l); - - /* this assures we have 25 bits of precision in the end */ - if (fl1.l < fl2.l) - { - fl1.l <<= 1; - exp--; - } - - /* now we perform repeated subtraction of fl2.l from fl1.l */ - mask = 0x1000000; - result = 0; - while (mask) - { - if (fl1.l >= fl2.l) - { - result |= mask; - fl1.l -= fl2.l; - } - fl1.l <<= 1; - mask >>= 1; - } - - /* round */ - result += 1; - - /* normalize down */ - exp++; - result >>= 1; - - result &= ~HIDDEN; - - /* pack up and go home */ - fl1.l = PACK (sign, exp, result); - return (fl1.f); -} - -/* convert double to float */ -float -__truncdfsf2 (double a1) -{ - register int exp; - register long mant; - register union float_long fl; - register union double_long dl1; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (float)(0); - - exp = EXPD (dl1) - EXCESSD + EXCESS; - - /* shift double mantissa 6 bits so we can round */ - mant = MANTD (dl1) >> 6; - - /* now round and shift down */ - mant += 1; - mant >>= 1; - - /* did the round overflow? */ - if (mant & 0xFF000000) - { - mant >>= 1; - exp++; - } - - mant &= ~HIDDEN; - - /* pack up and go home */ - fl.l = PACK (SIGND (dl1), exp, mant); - return (fl.f); -} - -/* convert int to double */ -double -__floatsidf (register long a1) -{ - register int sign = 0, exp = 31 + EXCESSD; - union double_long dl; - - if (a1 == 0x80000000) - { - /* - * -a1 would be 0 ! - */ - dl.l.upper = 0xc1e00000; - dl.l.lower = 0x0; - return (dl.d); - } - - if (!a1) - { - dl.l.upper = dl.l.lower = 0; - return (dl.d); - } - - if (a1 < 0) - { - sign = SIGNBIT; - a1 = -a1; - } - - while (a1 < 0x1000000) - { - a1 <<= 4; - exp -= 4; - } - - while (a1 < 0x40000000) - { - a1 <<= 1; - exp--; - } - - /* pack up and go home */ - dl.l.upper = sign; - dl.l.upper |= exp << 20; - dl.l.upper |= (a1 >> 10) & ~HIDDEND; - dl.l.lower = a1 << 22; - - return (dl.d); -} - -double -__floatdidf (register long long a1) -{ - register int exp = 63 + EXCESSD; - union double_long dl; - - dl.l.upper = dl.l.lower = 0; - if (a1 == 0) - return (dl.d); - - if (a1 < 0) { - dl.l.upper = SIGNBIT; - a1 = -a1; - } - - while (a1 < (long long)1<<54) { - a1 <<= 8; - exp -= 8; - } - while (a1 < (long long)1<<62) { - a1 <<= 1; - exp -= 1; - } - /* pack up and go home */ - dl.ll |= (a1 >> 10) & ~HIDDEND_LL; - dl.l.upper |= exp << 20; - - return (dl.d); -} - -float -__floatsisf (register long a1) -{ - return __truncdfsf2(__floatsidf(a1)); -} - -float -__floatdisf (register long long a1) -{ - return (float)__floatdidf(a1); -} -/* negate a float */ -float -__negsf2 (float a1) -{ - register union float_long fl1; - - fl1.f = a1; - if (!fl1.l) - return (0); - - fl1.l ^= SIGNBIT; - return (fl1.f); -} - -/* negate a double */ -double -__negdf2 (double a1) -{ - register union double_long dl1; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (dl1.d); - - dl1.l.upper ^= SIGNBIT; - return (dl1.d); -} - -/* convert float to double */ -double -__extendsfdf2 (float a1) -{ - register union float_long fl1; - register union double_long dl; - register int exp; - - fl1.f = a1; - - if (!fl1.l) - { - dl.l.upper = dl.l.lower = 0; - return (dl.d); - } - - dl.l.upper = SIGN (fl1.l); - exp = EXP (fl1.l) - EXCESS + EXCESSD; - dl.l.upper |= exp << 20; - dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3; - dl.l.lower = MANT (fl1.l) << 29; - - return (dl.d); -} - - -/* compare two doubles */ -long -__cmpdf2 (double a1, double a2) -{ - register union double_long dl1, dl2; - - dl1.d = a1; - dl2.d = a2; - - if (SIGND (dl1) && SIGND (dl2)) - { - dl1.l.upper ^= SIGNBIT; - dl2.l.upper ^= SIGNBIT; - if (dl1.l.upper < dl2.l.upper) - return (1); - if (dl1.l.upper > dl2.l.upper) - return (-1); - if (dl1.l.lower < dl2.l.lower) - return (1); - if (dl1.l.lower > dl2.l.lower) - return (-1); - return (0); - } else { - if (dl1.l.upper < dl2.l.upper) - return (-1); - if (dl1.l.upper > dl2.l.upper) - return (1); - if (dl1.l.lower < dl2.l.lower) - return (-1); - if (dl1.l.lower > dl2.l.lower) - return (1); - return (0); - } -} - -/* convert double to int */ -long -__fixdfsi (double a1) -{ - register union double_long dl1; - register int exp; - register long l; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (0); - - exp = EXPD (dl1) - EXCESSD - 31; - l = MANTD (dl1); - - if (exp > 0) - return SIGND(dl1) ? (1<<31) : ((1ul<<31)-1); - - /* shift down until exp = 0 or l = 0 */ - if (exp <= 0 && exp > -32 && l) - l >>= -exp; - else - return (0); - - return (SIGND (dl1) ? -l : l); -} - -/* convert float to int */ -long -__fixsfsi (float a1) -{ - return __fixdfsi(__extendsfdf2(a1)); -} - -/* convert double to int */ -long long -__fixdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register long long l; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (0); - - exp = EXPD (dl1) - EXCESSD - 64; - l = MANTD_LL(dl1); - - if (exp > 0) { - l = (long long)1<<63; - if (!SIGND(dl1)) - l--; - return l; - } - - /* shift down until exp = 0 or l = 0 */ - if (exp <= 0 && exp > -64 && l) - l >>= -exp; - else - return (0); - - return (SIGND (dl1) ? -l : l); -} - -/* convert double to unsigned int */ -unsigned long -__fixunsdfsi (double a1) -{ - register union double_long dl1; - register int exp; - register unsigned long l; - - dl1.d = a1; - - if (!dl1.l.upper && !dl1.l.lower) - return (0); - - exp = EXPD (dl1) - EXCESSD - 32; - l = (((((dl1.l.upper) & 0xFFFFF) | HIDDEND) << 11) | (dl1.l.lower >> 21)); - - if (exp > 0) - return (0xFFFFFFFFul); /* largest integer */ - - /* shift down until exp = 0 or l = 0 */ - if (exp < 0 && exp > -32 && l) - l >>= -exp; - else - return (0); - - return (l); -} - -/* convert double to unsigned int */ -unsigned long long -__fixunsdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register unsigned long long l; - - dl1.d = a1; - - if (dl1.ll == 0) - return (0); - - exp = EXPD (dl1) - EXCESSD - 64; - - l = dl1.ll; - - if (exp > 0) - return (unsigned long long)-1; - - /* shift down until exp = 0 or l = 0 */ - if (exp < 0 && exp > -64 && l) - l >>= -exp; - else - return (0); - - return (l); -} - -/* addtwo doubles */ -double -__adddf3 (double a1, double a2) -{ - register long long mant1, mant2; - register union double_long fl1, fl2; - register int exp1, exp2; - int sign = 0; - - fl1.d = a1; - fl2.d = a2; - - /* check for zero args */ - if (!fl2.ll) - goto test_done; - if (!fl1.ll) { - fl1.d = fl2.d; - goto test_done; - } - - exp1 = EXPD(fl1); - exp2 = EXPD(fl2); - - if (exp1 > exp2 + 54) - goto test_done; - if (exp2 > exp1 + 54) { - fl1.d = fl2.d; - goto test_done; - } - - /* do everything in excess precision so's we can round later */ - mant1 = MANTD_LL(fl1) << 9; - mant2 = MANTD_LL(fl2) << 9; - - if (SIGND(fl1)) - mant1 = -mant1; - if (SIGND(fl2)) - mant2 = -mant2; - - if (exp1 > exp2) - mant2 >>= exp1 - exp2; - else { - mant1 >>= exp2 - exp1; - exp1 = exp2; - } - mant1 += mant2; - - if (mant1 < 0) { - mant1 = -mant1; - sign = SIGNBIT; - } else if (!mant1) { - fl1.d = 0; - goto test_done; - } - - /* normalize up */ - while (!(mant1 & ((long long)7<<61))) { - mant1 <<= 1; - exp1--; - } - - /* normalize down? */ - if (mant1 & ((long long)3<<62)) { - mant1 >>= 1; - exp1++; - } - - /* round to even */ - mant1 += (mant1 & (1<<9)) ? (1<<8) : ((1<<8)-1); - - /* normalize down? */ - if (mant1 & ((long long)3<<62)) { - mant1 >>= 1; - exp1++; - } - - /* lose extra precision */ - mant1 >>= 9; - - /* turn off hidden bit */ - mant1 &= ~HIDDEND_LL; - - /* pack up and go home */ - fl1.ll = PACKD_LL(sign,exp1,mant1); - -test_done: - return (fl1.d); -} - -/* subtract two doubles */ -double -__subdf3 (double a1, double a2) -{ - register union double_long fl1, fl2; - - fl1.d = a1; - fl2.d = a2; - - /* check for zero args */ - if (!fl2.ll) - return (fl1.d); - /* twiddle sign bit and add */ - fl2.l.upper ^= SIGNBIT; - if (!fl1.ll) - return (fl2.d); - return __adddf3 (a1, fl2.d); -} - -/* multiply two doubles */ -double -__muldf3 (double a1, double a2) -{ - register union double_long fl1, fl2; - register unsigned long long result=0ULL; - register int exp; - int sign; - - fl1.d = a1; - fl2.d = a2; - - if (!fl1.ll || !fl2.ll) { - fl1.d = 0; - goto test_done; - } - - /* compute sign and exponent */ - sign = SIGND(fl1) ^ SIGND(fl2); - exp = EXPD(fl1) - EXCESSD; - exp += EXPD(fl2); - - fl1.ll = MANTD_LL(fl1); - fl2.ll = MANTD_LL(fl2); - - /* the multiply is done as one 31x31 multiply and two 31x21 multiples */ - result = (fl1.ll >> 21) * (fl2.ll >> 21); - result += ((fl1.ll & 0x1FFFFF) * (fl2.ll >> 21)) >> 21; - result += ((fl2.ll & 0x1FFFFF) * (fl1.ll >> 21)) >> 21; - - result >>= 2; - if (result & ((long long)1<<61)) { - /* round */ - result += 1<<8; - result >>= 9; - } else { - /* round */ - result += 1<<7; - result >>= 8; - exp--; - } - if (result & (HIDDEND_LL<<1)) { - result >>= 1; - exp++; - } - - result &= ~HIDDEND_LL; - - /* pack up and go home */ - fl1.ll = PACKD_LL(sign,exp,result); -test_done: - return (fl1.d); -} - -/* divide two doubles */ -double -__divdf3 (double a1, double a2) -{ - register union double_long fl1, fl2; - register long long mask,result; - register int exp, sign; - - fl1.d = a1; - fl2.d = a2; - - /* subtract exponents */ - exp = EXPD(fl1) - EXPD(fl2) + EXCESSD; - - /* compute sign */ - sign = SIGND(fl1) ^ SIGND(fl2); - - /* numerator zero??? */ - if (fl1.ll == 0) { - /* divide by zero??? */ - if (fl2.ll == 0) - fl1.ll = ((unsigned long long)1<<63)-1; /* NaN */ - else - fl1.ll = 0; - goto test_done; - } - - /* return +Inf or -Inf */ - if (fl2.ll == 0) { - fl1.ll = PACKD_LL(SIGND(fl1),2047,0); - goto test_done; - } - - - /* now get mantissas */ - fl1.ll = MANTD_LL(fl1); - fl2.ll = MANTD_LL(fl2); - - /* this assures we have 54 bits of precision in the end */ - if (fl1.ll < fl2.ll) { - fl1.ll <<= 1; - exp--; - } - - /* now we perform repeated subtraction of fl2.ll from fl1.ll */ - mask = (long long)1<<53; - result = 0; - while (mask) { - if (fl1.ll >= fl2.ll) - { - result |= mask; - fl1.ll -= fl2.ll; - } - fl1.ll <<= 1; - mask >>= 1; - } - - /* round */ - result += 1; - - /* normalize down */ - exp++; - result >>= 1; - - result &= ~HIDDEND_LL; - - /* pack up and go home */ - fl1.ll = PACKD_LL(sign, exp, result); - -test_done: - return (fl1.d); -} - -int -__gtdf2 (double a1, double a2) -{ - return __cmpdf2 ((float) a1, (float) a2) > 0; -} - -int -__gedf2 (double a1, double a2) -{ - return (__cmpdf2 ((float) a1, (float) a2) >= 0) - 1; -} - -int -__ltdf2 (double a1, double a2) -{ - return - (__cmpdf2 ((float) a1, (float) a2) < 0); -} - -int -__ledf2 (double a1, double a2) -{ - return __cmpdf2 ((float) a1, (float) a2) > 0; -} - -int -__eqdf2 (double a1, double a2) -{ - return *(long long *) &a1 == *(long long *) &a2; -} - -int -__nedf2 (double a1, double a2) -{ - return *(long long *) &a1 != *(long long *) &a2; -} - -/* absolute value of double */ -double -__absdf2(double a1) -{ - if (__cmpdf2(a1,0.0) < 0) - return __negdf2(a1); - else - return a1; -} - -/* absolute value of float */ -float -__abssf2(float a1) -{ - if (__cmpsf2(a1,0.0) < 0) - return __negsf2(a1); - else - return a1; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/head.S linux.ac/arch/s390/kernel/head.S --- linux.vanilla/arch/s390/kernel/head.S Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/head.S Thu Apr 12 11:59:46 2001 @@ -261,8 +261,9 @@ l %r1,0xb8 # load ipl subchannel number la %r2,IPL_BS # load start address bas %r14,.Lloader # load rest of ipl image - st %r1,__LC_IPLDEV # store ipl device number l %r12,.Lparm # pointer to parameter area + st %r1,__LC_IPLDEV # store ipl device number + st %r1,IPL_DEVICE-PARMAREA(%r12) # # load parameter file from ipl device @@ -406,7 +407,8 @@ sr %r3,%r2 la %r3,1(%r3) .done: - st %r3,MEMORY_SIZE-PARMAREA(%r11) + l %r1,.memsize + st %r3,0(%r1) slr %r0,%r0 st %r0,INITRD_SIZE-PARMAREA(%r11) st %r0,INITRD_START-PARMAREA(%r11) @@ -414,6 +416,7 @@ .tbl: .long _ebcasc # translate table .cmd: .long COMMAND_LINE # address of command line buffer .parm: .long PARMAREA +.memsize: .long memory_size .fourmeg: .long 0x00400000 # 4M .pgmnw: .long 0x00080000,.pgmx .lowcase: @@ -464,7 +467,7 @@ # # find out memory size. # - mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler + mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) lhi %r2,1 sll %r2,17 # test in increments of 128KB lr %r1,%r2 @@ -476,78 +479,56 @@ bnm .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop .Lchkmem: n %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M - st %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size -.Lsizeok: - -# -# Now we have to move the ramdisk to a location approriate for the -# memory size. If we have more than 64 MB of memory we move it to 32MB -# to make room for the page tables set up by paging_init. -# - l %r1,MEMORY_SIZE-PARMAREA(%r12) - cl %r1,.Lbigmem-.LPG1(%r13) # memory < 64mb ? - bl .Lnomove-.LPG1(%r13) # if yes ramdisk @8MB is ok - icm %r4,15,INITRD_START-PARMAREA(%r12) - bz .Lnomove-.LPG1(%r13) - l %r2,.Lrdstart-.LPG1(%r13) # new address of ramdisk - st %r2,INITRD_START-PARMAREA(%r12) - l %r1,INITRD_SIZE-PARMAREA(%r12) - ar %r2,%r1 # we start moving at the end - ar %r4,%r1 # because new location > old location -.Lmove: lr %r0,%r2 # new - old is the maximum we can move - sr %r0,%r4 # because of overlapping - cr %r0,%r1 # we shouldn't move more than there is - bnh .Lnoend-.LPG1(%r13) - lr %r0,%r1 -.Lnoend:cl %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go - bnh .Lchunk-.LPG1(%r13) - l %r0,.Lmaxchunk-.LPG1(%r13) -.Lchunk:sr %r2,%r0 # make source & destination pointer - sr %r4,%r0 - lr %r3,%r0 # set source & destination length - lr %r5,%r0 - mvcl %r2,%r4 - sr %r2,%r0 # substract length again, since - sr %r4,%r0 # mvcl added it to the pointers - sr %r1,%r0 # substract chunk size from length - bnz .Lmove-.LPG1(%r13) -.Lnomove: + l %r2,.Lmemsize-.LPG1(%r13) # address of variable memory_size + st %r1,0(%r2) # store memory size + l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags # # find out if we are running under VM # stidp __LC_CPUID # store cpuid tm __LC_CPUID,0xff # running under VM ? bno .Lnovm-.LPG1(%r13) - oi MACHINE_FLAGS+3-PARMAREA(%r12),1 # set VM flag + oi 3(%r12),1 # set VM flag .Lnovm: lh %r0,__LC_CPUID+4 # get cpu version chi %r0,0x7490 # running on a P/390 ? bne .Lnop390-.LPG1(%r13) - oi MACHINE_FLAGS+3-PARMAREA(%r12),4 # set P/390 flag + oi 3(%r12),4 # set P/390 flag .Lnop390: # # find out if we have an IEEE fpu # - mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler + mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0 ldr %f2,%f0 adbr %f0,%f2 # test IEEE add instruction - oi MACHINE_FLAGS+3-PARMAREA(%r12),2 # set IEEE fpu flag + oi 3(%r12),2 # set IEEE fpu flag .Lchkfpu: # # find out if we have the CSP instruction # - mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler + mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13) la %r0,0 lr %r1,%r0 la %r2,.Lflt0-.LPG1(%r13) csp %r0,%r2 # Test CSP instruction - oi MACHINE_FLAGS+3-PARMAREA(%r12),8 # set CSP flag + oi 3(%r12),8 # set CSP flag .Lchkcsp: +# +# find out if we have the MVPG instruction +# + mvc __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13) + sr %r0,%r0 + la %r1,0 + la %r2,0 + mvpg %r1,%r2 # Test CSP instruction + oi 3(%r12),16 # set MVPG flag +.Lchkmvpg: + lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 8 @@ -571,24 +552,23 @@ .Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp +.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg .Lflt0: .double 0 .Lparm1:.long PARMAREA .L4malign:.long 0xffc00000 .Lbigmem:.long 0x04000000 .Lrdstart:.long 0x02000000 .Lmaxchunk:.long 0x00ffffff +.Lmemsize:.long memory_size +.Lmflags:.long machine_flags # # params at 10400 (setup.h) # .org PARMAREA - .long 0x0100 # ORIG_ROOT_DEV: ramdisk major/minor - .word 0 # MOUNT_ROOT_RDONLY: no - .long 0 # MEMORY_SIZE - .long 0 # MACHINE_FLAGS (bit 0:VM, bit 1:IEEE) - .long RAMDISK_ORIGIN # INITRD_START - .long 0x800000 # INITRD_SIZE - .word 0 # RAMDISK_FLAGS + .long 0,0 # IPL_DEVICE + .long 0,RAMDISK_ORIGIN # INITRD_START + .long 0,0x800000 # INITRD_SIZE .org COMMAND_LINE .byte "root=/dev/ram0 ro" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/irq.c linux.ac/arch/s390/kernel/irq.c --- linux.vanilla/arch/s390/kernel/irq.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/irq.c Thu Apr 12 11:59:46 2001 @@ -11,6 +11,7 @@ * S/390 I/O interrupt processing and I/O request processing is * implemented in arch/s390/kernel/s390io.c */ +#include #include #include #include @@ -20,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -286,7 +287,7 @@ */ void __global_cli(void) { - unsigned int flags; + unsigned long flags; __save_flags(flags); if (flags & (1 << EFLAGS_I_SHIFT)) { @@ -357,48 +358,6 @@ #endif -/* - * Note : This fuction should be eliminated as it doesn't comply with the - * S/390 irq scheme we have implemented ... - */ -int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs * regs) -{ - struct irqaction * action; - int status; - - status = 0; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - action = ioinfo[irq]->irq_desc.action; - - if (action) - { - status |= 1; - - 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(); - - } /* endif */ - - return status; -} - -void enable_nop(int irq) -{ -} void __init init_IRQ(void) { @@ -427,3 +386,8 @@ /* For now, nothing... */ } +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(global_bh_lock); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/irqextras390.c linux.ac/arch/s390/kernel/irqextras390.c --- linux.vanilla/arch/s390/kernel/irqextras390.c Fri May 12 19:41:44 2000 +++ linux.ac/arch/s390/kernel/irqextras390.c Thu Jan 1 01:00:00 1970 @@ -1,35 +0,0 @@ -/* - * arch/s390/kernel/irqextras390.c - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * - * Some channel code by D.J. Barrow - */ - -/* - -*/ -#include -#include - -#if 0 -// fixchannelprogram is now obselete -void fixchannelprogram(orb_bits_t *orbptr) -{ - __u32 newAddress=orbptr->ccw_program_address; - fixccws(orbptr->ccw_program_address); - orbptr->ccw_program_address=newAddress; - orbptr->ccw_program_address=(ccw1_t *)(((__u32)orbptr->ccw_program_address)); -} -#endif - -void fixccws(ccw1_bits_t *ccwptr) -{ - for(;;ccwptr++) - { // Just hope nobody starts doing prefixing - if(!ccwptr->cc) - break; - } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/mathemu.c linux.ac/arch/s390/kernel/mathemu.c --- linux.vanilla/arch/s390/kernel/mathemu.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/mathemu.c Thu Jan 1 01:00:00 1970 @@ -1,1045 +0,0 @@ -/* - * arch/s390/kernel/mathemu.c - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * - * 'mathemu.c' handles IEEE instructions on a S390 processor - * that does not have the IEEE fpu - */ - -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_SYSCTL -int sysctl_ieee_emulation_warnings=1; -#endif - -#define mathemu_put_user(x, ptr) \ -{ \ - if(put_user((x),(ptr))) \ - return 1; \ -} - -#define mathemu_get_user(x, ptr) \ -{ \ - if(get_user((x),(ptr))) \ - return 1; \ -} - - -#define mathemu_copy_from_user(to,from,n) \ -{ \ - if(copy_from_user((to),(from),(n))==-EFAULT) \ - return 1; \ -} - - -#define mathemu_copy_to_user(to, from, n) \ -{ \ - if(copy_to_user((to),(from),(n))==-EFAULT) \ - return 1; \ -} - - - -static void display_emulation_not_implemented(char *instr) -{ - struct pt_regs *regs; - __u16 *location; - -#if CONFIG_SYSCTL - if(sysctl_ieee_emulation_warnings) -#endif - { - regs=current->thread.regs; - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); - printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n", - instr, - current->comm, current->pid); - printk("%s's PSW: %08lx %08lx\n",instr, - (unsigned long) regs->psw.mask, - (unsigned long) location); - } -} - -static int set_CC_df(__u64 val1,__u64 val2) { - int rc; - rc = __cmpdf2(val1,val2); - current->thread.regs->psw.mask &= 0xFFFFCFFF; - switch (rc) { - case -1: - current->thread.regs->psw.mask |= 0x00001000; - break; - case 1: - current->thread.regs->psw.mask |= 0x00002000; - break; - } - return 0; -} - -static int set_CC_sf(__u32 val1,__u32 val2) { - int rc; - rc = __cmpsf2(val1,val2); - current->thread.regs->psw.mask &= 0xFFFFCFFF; - switch (rc) { - case -1: - current->thread.regs->psw.mask |= 0x00001000; - break; - case 1: - current->thread.regs->psw.mask |= 0x00002000; - break; - } - return 0; -} - - -static int emu_adb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_adbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_aeb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_aebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_axbr (int rx, int ry) { - display_emulation_not_implemented("axbr"); - return 0; -} - -static int emu_cdb (int rx, __u64 val) { - set_CC_df(current->thread.fp_regs.fprs[rx].d,val); - return 0; -} - -static int emu_cdbr (int rx, int ry) { - set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d); - return 0; -} - -static int emu_cdfbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = - __floatsidf(current->thread.regs->gprs[ry]); - return 0; -} - -static int emu_ceb (int rx, __u32 val) { - set_CC_sf(current->thread.fp_regs.fprs[rx].f,val); - return 0; -} - -static int emu_cebr (int rx, int ry) { - set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f); - return 0; -} - -static int emu_cefbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = - __floatsisf(current->thread.regs->gprs[ry]); - return 0; -} - -static int emu_cfdbr (int rx, int ry, int mask) { - current->thread.regs->gprs[rx] = - __fixdfsi(current->thread.fp_regs.fprs[ry].d); - return 0; -} - -static int emu_cfebr (int rx, int ry, int mask) { - current->thread.regs->gprs[rx] = - __fixsfsi(current->thread.fp_regs.fprs[ry].f); - return 0; -} - -static int emu_cfxbr (int rx, int ry, int mask) { - display_emulation_not_implemented("cfxbr"); - return 0; -} - -static int emu_cxbr (int rx, int ry) { - display_emulation_not_implemented("cxbr"); - return 0; -} - -static int emu_cxfbr (int rx, int ry) { - display_emulation_not_implemented("cxfbr"); - return 0; -} - -static int emu_ddb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_ddbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_deb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_debr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_didbr (int rx, int ry, int mask) { - display_emulation_not_implemented("didbr"); - return 0; -} - -static int emu_diebr (int rx, int ry, int mask) { - display_emulation_not_implemented("diebr"); - return 0; -} - -static int emu_dxbr (int rx, int ry) { - display_emulation_not_implemented("dxbr"); - return 0; -} - -static int emu_efpc (int rx, int ry) { - current->thread.regs->gprs[rx]=current->thread.fp_regs.fpc; - return 0; -} - -static int emu_fidbr (int rx, int ry, int mask) { - display_emulation_not_implemented("fidbr"); - return 0; -} - -static int emu_fiebr (int rx, int ry, int mask) { - display_emulation_not_implemented("fiebr"); - return 0; -} - -static int emu_fixbr (int rx, int ry, int mask) { - display_emulation_not_implemented("fixbr"); - return 0; -} - -static int emu_kdb (int rx, __u64 val) { - display_emulation_not_implemented("kdb"); - return 0; -} - -static int emu_kdbr (int rx, int ry) { - display_emulation_not_implemented("kdbr"); - return 0; -} - -static int emu_keb (int rx, __u32 val) { - display_emulation_not_implemented("keb"); - return 0; -} - -static int emu_kebr (int rx, int ry) { - display_emulation_not_implemented("kebr"); - return 0; -} - -static int emu_kxbr (int rx, int ry) { - display_emulation_not_implemented("kxbr"); - return 0; -} - -static int emu_lcdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = - __negdf2(current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_lcebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = - __negsf2(current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_lcxbr (int rx, int ry) { - display_emulation_not_implemented("lcxbr"); - return 0; -} - -static int emu_ldeb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val); - return 0; -} - -static int emu_ldebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = - __extendsfdf2(current->thread.fp_regs.fprs[ry].f); - return 0; -} - -static int emu_ldxbr (int rx, int ry) { - display_emulation_not_implemented("ldxbr"); - return 0; -} - -static int emu_ledbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_lexbr (int rx, int ry) { - display_emulation_not_implemented("lexbr"); - return 0; -} - -static int emu_lndbr (int rx, int ry) { - display_emulation_not_implemented("lndbr"); - return 0; -} - -static int emu_lnebr (int rx, int ry) { - display_emulation_not_implemented("lnebr"); - return 0; -} - -static int emu_lnxbr (int rx, int ry) { - display_emulation_not_implemented("lnxbr"); - return 0; -} - -static int emu_lpdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0); - return 0; -} - -static int emu_lpebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_lpxbr (int rx, int ry) { - display_emulation_not_implemented("lpxbr"); - return 0; -} - -static int emu_ltdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d; - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_ltebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f; - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_ltxbr (int rx, int ry) { - display_emulation_not_implemented("ltxbr"); - return 0; -} - -static int emu_lxdb (int rx, __u64 val) { - display_emulation_not_implemented("lxdb"); - return 0; -} - -static int emu_lxdbr (int rx, int ry) { - display_emulation_not_implemented("lxdbr"); - return 0; -} - -static int emu_lxeb (int rx, __u32 val) { - display_emulation_not_implemented("lxeb"); - return 0; -} - -static int emu_lxebr (int rx, int ry) { - display_emulation_not_implemented("lxebr"); - return 0; -} - -static int emu_madb (int rx, __u64 val, int mask) { - display_emulation_not_implemented("madb"); - return 0; -} - -static int emu_madbr (int rx, int ry, int mask) { - display_emulation_not_implemented("madbr"); - return 0; -} - -static int emu_maeb (int rx, __u32 val, int mask) { - display_emulation_not_implemented("maeb"); - return 0; -} - -static int emu_maebr (int rx, int ry, int mask) { - display_emulation_not_implemented("maebr"); - return 0; -} - -static int emu_mdb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_mdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_mdeb (int rx, __u32 val) { - display_emulation_not_implemented("mdeb"); - return 0; -} - -static int emu_mdebr (int rx, int ry) { - display_emulation_not_implemented("mdebr"); - return 0; -} - -static int emu_meeb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, - val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_meebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_msdb (int rx, __u64 val, int mask) { - display_emulation_not_implemented("msdb"); - return 0; -} - -static int emu_msdbr (int rx, int ry, int mask) { - display_emulation_not_implemented("msdbr"); - return 0; -} - -static int emu_mseb (int rx, __u32 val, int mask) { - display_emulation_not_implemented("mseb"); - return 0; -} - -static int emu_msebr (int rx, int ry, int mask) { - display_emulation_not_implemented("msebr"); - return 0; -} - -static int emu_mxbr (int rx, int ry) { - display_emulation_not_implemented("mxbr"); - return 0; -} - -static int emu_mxdb (int rx, __u64 val) { - display_emulation_not_implemented("mxdb"); - return 0; -} - -static int emu_mxdbr (int rx, int ry) { - display_emulation_not_implemented("mxdbr"); - return 0; -} - -static int emu_sdb (int rx, __u64 val) { - current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, - val); - set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_sdbr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, - current->thread.fp_regs.fprs[ry].d); - set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); - return 0; -} - -static int emu_seb (int rx, __u32 val) { - current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, - val); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_sebr (int rx, int ry) { - current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, - current->thread.fp_regs.fprs[ry].f); - set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); - return 0; -} - -static int emu_sfpc (int rx, int ry) { - __u32 val=current->thread.regs->gprs[rx]; - if(val==0) - current->thread.fp_regs.fpc=val; - else - display_emulation_not_implemented("sfpc"); - return 0; -} - -static int emu_sqdb (int rx, __u64 val) { - display_emulation_not_implemented("sqdb"); - return 0; -} - -static int emu_sqdbr (int rx, int ry) { - display_emulation_not_implemented("sqdbr"); - return 0; -} - -static int emu_sqeb (int rx, __u32 val) { - display_emulation_not_implemented("sqeb"); - return 0; -} - -static int emu_sqebr (int rx, int ry) { - display_emulation_not_implemented("sqebr"); - return 0; -} - -static int emu_sqxbr (int rx, int ry) { - display_emulation_not_implemented("sqxbr"); - return 0; -} - -static int emu_sxbr (int rx, int ry) { - display_emulation_not_implemented("sxbr"); - return 0; -} - -static int emu_tcdb (int rx, __u64 val) { - display_emulation_not_implemented("tcdb"); - return 0; -} - -static int emu_tceb (int rx, __u32 val) { - display_emulation_not_implemented("tceb"); - return 0; -} - -static int emu_tcxb (int rx, __u64 val) { - display_emulation_not_implemented("tcxb"); - return 0; -} - - -static inline void emu_load_regd(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* load reg from fp_regs.fprs[reg] */ - " bras 1,0f\n" - " ld 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) - : "1" ); - } -} - -static inline void emu_load_rege(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* load reg from fp_regs.fprs[reg] */ - " bras 1,0f\n" - " le 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) - : "1" ); - } -} - -static inline void emu_store_regd(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* store reg to fp_regs.fprs[reg] */ - " bras 1,0f\n" - " std 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) - : "1" ); - } -} - - -static inline void emu_store_rege(int reg) { - if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */ - __asm__ __volatile ( /* store reg to fp_regs.fprs[reg] */ - " bras 1,0f\n" - " ste 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) - : "1" ); - } -} - -int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { - int rc=0; - static const __u8 format_table[] = { - 2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4, - 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1,10, 1, 1, 3, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 5, 6, 6, 0, 7, 8, 8, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - static const void *jump_table[]= { - emu_lpebr, emu_lnebr, emu_ltebr, emu_lcebr, - emu_ldebr, emu_lxdbr, emu_lxebr, emu_mxdbr, - emu_kebr, emu_cebr, emu_aebr, emu_sebr, - emu_mdebr, emu_debr, emu_maebr, emu_msebr, - emu_lpdbr, emu_lndbr, emu_ltdbr, emu_lcdbr, - emu_sqebr, emu_sqdbr, emu_sqxbr, emu_meebr, - emu_kdbr, emu_cdbr, emu_adbr, emu_sdbr, - emu_mdbr, emu_ddbr, emu_madbr, emu_msdbr, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_lpxbr, emu_lnxbr, emu_ltxbr, emu_lcxbr, - emu_ledbr, emu_ldxbr, emu_lexbr, emu_fixbr, - emu_kxbr, emu_cxbr, emu_axbr, emu_sxbr, - emu_mxbr, emu_dxbr, NULL, NULL, - NULL, NULL, NULL, emu_diebr, - NULL, NULL, NULL, emu_fiebr, - NULL, NULL, NULL, emu_didbr, - NULL, NULL, NULL, emu_fidbr, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_sfpc, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_efpc, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - emu_cefbr, emu_cdfbr, emu_cxfbr, NULL, - emu_cfebr, emu_cfdbr, emu_cfxbr - }; - - switch (format_table[opcode[1]]) { - case 1: /* RRE format, double operation */ - emu_store_regd((opcode[3]>>4)&15); - emu_store_regd(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return rc; - case 2: /* RRE format, float operation */ - emu_store_rege((opcode[3]>>4)&15); - emu_store_rege(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return rc; - case 3: /* RRF format, double operation */ - emu_store_regd((opcode[3]>>4)&15); - emu_store_regd(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return rc; - case 4: /* RRF format, float operation */ - emu_store_rege((opcode[3]>>4)&15); - emu_store_rege(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return rc; - case 5: /* RRE format, cefbr instruction */ - emu_store_rege((opcode[3]>>4)&15); - /* call the emulation function */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return rc; - case 6: /* RRE format, cdfbr & cxfbr instruction */ - emu_store_regd((opcode[3]>>4)&15); - /* call the emulation function */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return rc; - case 7: /* RRF format, cfebr instruction */ - emu_store_rege(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return rc; - case 8: /* RRF format, cfdbr & cfxbr instruction */ - emu_store_regd(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return rc; - case 9: /* RRE format, ldebr & mdebr instruction */ - /* float store but double load */ - emu_store_rege((opcode[3]>>4)&15); - emu_store_rege(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return rc; - case 10: /* RRE format, ledbr instruction */ - /* double store but float load */ - emu_store_regd((opcode[3]>>4)&15); - emu_store_regd(opcode[3]&15); - /* call the emulation function */ - rc=((int (*)(int, int))jump_table[opcode[1]]) - (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return rc; - default: - return 1; - } -} - -static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp) -{ - rx &= 0xf; - rb &= 0xf; - disp &= 0xfff; - return (void*) ((rx != 0 ? regs->gprs[rx] : 0) + /* index */ - (rb != 0 ? regs->gprs[rb] : 0) + /* base */ - disp); -} - -int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { - int rc=0; - - static const __u8 format_table[] = { - 0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4, - 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - static const void *jump_table[]= { - NULL, NULL, NULL, NULL, - emu_ldeb, emu_lxdb, emu_lxeb, emu_mxdb, - emu_keb, emu_ceb, emu_aeb, emu_seb, - emu_mdeb, emu_deb, emu_maeb, emu_mseb, - emu_tceb, emu_tcdb, emu_tcxb, NULL, - emu_sqeb, emu_sqdb, NULL, emu_meeb, - emu_kdb, emu_cdb, emu_adb, emu_sdb, - emu_mdb, emu_ddb, emu_madb, emu_msdb - }; - - switch (format_table[opcode[5]]) { - case 1: /* RXE format, __u64 constant */ { - __u64 *dxb, temp; - __u32 opc; - - emu_store_regd((opcode[1]>>4)&15); - opc = *((__u32 *) opcode); - dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_copy_from_user(&temp, dxb, 8); - /* call the emulation function */ - rc=((int (*)(int, __u64))jump_table[opcode[5]]) - (opcode[1]>>4,temp); - emu_load_regd((opcode[1]>>4)&15); - return rc; - } - case 2: /* RXE format, __u32 constant */ { - __u32 *dxb, temp; - __u32 opc; - - emu_store_rege((opcode[1]>>4)&15); - opc = *((__u32 *) opcode); - dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_get_user(temp, dxb); - /* call the emulation function */ - rc=((int (*)(int, __u32))jump_table[opcode[5]]) - (opcode[1]>>4,temp); - emu_load_rege((opcode[1]>>4)&15); - return rc; - } - case 3: /* RXF format, __u64 constant */ { - __u32 *dxb, temp; - __u32 opc; - - emu_store_regd((opcode[1]>>4)&15); - opc = *((__u32 *) opcode); - dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_copy_from_user(&temp, dxb, 8); - /* call the emulation function */ - rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) - (opcode[1]>>4,temp,opcode[4]>>4); - emu_load_regd((opcode[1]>>4)&15); - return rc; - } - case 4: /* RXF format, __u32 constant */ { - __u32 *dxb, temp; - __u32 opc; - - emu_store_rege((opcode[1]>>4)&15); - opc = *((__u32 *) opcode); - dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_get_user(temp, dxb); - /* call the emulation function */ - rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) - (opcode[1]>>4,temp,opcode[4]>>4); - emu_load_rege((opcode[1]>>4)&15); - return rc; - } - case 5: /* RXE format, __u32 constant */ - /* store_rege and load_regd */ - { - __u32 *dxb, temp; - __u32 opc; - emu_store_rege((opcode[1]>>4)&15); - opc = *((__u32 *) opcode); - dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_get_user(temp, dxb); - /* call the emulation function */ - rc=((int (*)(int, __u32))jump_table[opcode[5]]) - (opcode[1]>>4,temp); - emu_load_regd((opcode[1]>>4)&15); - return rc; - } - default: - return 1; - } -} - -/* - * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6} - */ -int math_emu_ldr(__u8 *opcode) { - __u16 opc = *((__u16 *) opcode); - - if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ - /* we got an exception therfore ry can't be in {0,2,4,6} */ - __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ - " bras 1,0f\n" - " ld 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (opc&0x00f0), - "a" (¤t->thread.fp_regs.fprs[opc&0x000f].d) - : "1" ); - } else if ((opc & 0x0009) == 0) { /* test if ry in {0,2,4,6} */ - __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ - " bras 1,0f\n" - " std 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" ((opc&0x000f)<<4), - "a" (¤t->thread.fp_regs.fprs[(opc&0x00f0)>>4].d) - : "1" ); - } else { /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ - current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = - current->thread.fp_regs.fprs[opc&0x000f]; - } - return 0; -} - -/* - * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6} - */ -int math_emu_ler(__u8 *opcode) { - __u16 opc = *((__u16 *) opcode); - - if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ - /* we got an exception therfore ry can't be in {0,2,4,6} */ - __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ - " bras 1,0f\n" - " le 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (opc&0x00f0), - "a" (¤t->thread.fp_regs.fprs[opc&0x000f].f) - : "1" ); - } else if ((opc & 0x0009) == 0) { /* test if ry in {0,2,4,6} */ - __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ - " bras 1,0f\n" - " ste 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" ((opc&0x000f)<<4), - "a" (¤t->thread.fp_regs.fprs[(opc&0x00f0)>>4].f) - : "1" ); - } else { /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ - current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = - current->thread.fp_regs.fprs[opc&0x000f]; - } - return 0; -} - -/* - * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6} - */ -int math_emu_ld(__u8 *opcode, struct pt_regs * regs) { - __u32 opc = *((__u32 *) opcode); - __u64 *dxb; - - dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_copy_from_user(¤t->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); - return 0; -} - -/* - * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6} - */ -int math_emu_le(__u8 *opcode, struct pt_regs * regs) { - __u32 opc = *((__u32 *) opcode); - __u32 *mem, *dxb; - - dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - mathemu_get_user(mem[0], dxb); - return 0; -} - -/* - * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6} - */ -int math_emu_std(__u8 *opcode, struct pt_regs * regs) { - __u32 opc = *((__u32 *) opcode); - __u64 *dxb; - dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - mathemu_copy_to_user(dxb, ¤t->thread.fp_regs.fprs[(opc>>20)&15].d, 8); - return 0; -} - -/* - * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6} - */ -int math_emu_ste(__u8 *opcode, struct pt_regs * regs) { - __u32 opc = *((__u32 *) opcode); - __u32 *mem, *dxb; - dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if mathemu_put_user fails ? */ - mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - mathemu_put_user(mem[0], dxb); - return 0; -} - -/* - * Emulate LFPC D(B) - */ -int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { - __u32 *dxb,temp; - __u32 opc = *((__u32 *) opcode); - dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); - mathemu_get_user(temp, dxb); - if(temp!=0) - display_emulation_not_implemented("lfpc"); - return 0; -} - -/* - * Emulate STFPC D(B) - */ -int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { - __u32 *dxb; - __u32 opc = *((__u32 *) opcode); - dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); - mathemu_put_user(current->thread.fp_regs.fpc, dxb); - return 0; -} - -/* - * Emulate SRNM D(B) - */ -int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) { - /* FIXME: how to do that ?!? */ - display_emulation_not_implemented("srnm"); - return 0; -} - - - - - - - - - - - - - - - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/process.c linux.ac/arch/s390/kernel/process.c --- linux.vanilla/arch/s390/kernel/process.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/process.c Mon Apr 16 12:37:04 2001 @@ -42,7 +42,6 @@ #include #include #include -#include #include spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; @@ -300,12 +299,10 @@ unsigned long fprs[4]; /* fpr 4 and 6 */ unsigned long empty[4]; #if CONFIG_REMOTE_DEBUG - gdb_pt_regs childregs; + struct gdb_pt_regs childregs; #else - pt_regs childregs; + struct pt_regs childregs; #endif - __u32 pgm_old_ilc; /* single step magic from entry.S */ - __u32 pgm_svc_step; } *frame; frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1; @@ -321,7 +318,7 @@ /* fake return stack for resume(), don't go back to schedule */ frame->gprs[9] = (unsigned long) frame; - frame->pgm_svc_step = 0; /* Nope we aren't single stepping an svc */ + frame->childregs.old_ilc = -1; /* We are not single stepping an svc */ /* save fprs, if used in last task */ save_fp_regs(&p->thread.fp_regs); p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/ptrace.c linux.ac/arch/s390/kernel/ptrace.c --- linux.vanilla/arch/s390/kernel/ptrace.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/ptrace.c Thu Apr 12 11:59:46 2001 @@ -180,9 +180,9 @@ copymax=(PT_FPR15_LO+4); realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); } - else if(useraddrthread.per_info)[useraddr-PT_CR_9]); } else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390_ext.c linux.ac/arch/s390/kernel/s390_ext.c --- linux.vanilla/arch/s390/kernel/s390_ext.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/s390_ext.c Thu Apr 12 11:59:46 2001 @@ -7,6 +7,7 @@ * Martin Schwidefsky (schwidefsky@de.ibm.com) */ +#include #include #include #include @@ -74,4 +75,6 @@ return 0; } +EXPORT_SYMBOL(register_external_interrupt); +EXPORT_SYMBOL(unregister_external_interrupt); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390_ksyms.c linux.ac/arch/s390/kernel/s390_ksyms.c --- linux.vanilla/arch/s390/kernel/s390_ksyms.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/s390_ksyms.c Thu Apr 12 11:59:46 2001 @@ -5,67 +5,14 @@ */ #include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#if CONFIG_CHANDEV -#include -#endif +#include #if CONFIG_IP_MULTICAST #include #endif /* - * I/O subsystem - */ -EXPORT_SYMBOL(halt_IO); -EXPORT_SYMBOL(clear_IO); -EXPORT_SYMBOL(do_IO); -EXPORT_SYMBOL(resume_IO); -EXPORT_SYMBOL(ioinfo); -EXPORT_SYMBOL(get_dev_info_by_irq); -EXPORT_SYMBOL(get_dev_info_by_devno); -EXPORT_SYMBOL(get_irq_by_devno); -EXPORT_SYMBOL(get_devno_by_irq); -EXPORT_SYMBOL(get_irq_first); -EXPORT_SYMBOL(get_irq_next); -EXPORT_SYMBOL(read_conf_data); -EXPORT_SYMBOL(read_dev_chars); -EXPORT_SYMBOL(s390_request_irq_special); -EXPORT_SYMBOL(s390_device_register); -EXPORT_SYMBOL(s390_device_unregister); - -EXPORT_SYMBOL(ccw_alloc_request); -EXPORT_SYMBOL(ccw_free_request); - -EXPORT_SYMBOL(register_external_interrupt); -EXPORT_SYMBOL(unregister_external_interrupt); - -/* - * debug feature - */ -EXPORT_SYMBOL(debug_register); -EXPORT_SYMBOL(debug_unregister); -EXPORT_SYMBOL(debug_set_level); -EXPORT_SYMBOL(debug_register_view); -EXPORT_SYMBOL(debug_unregister_view); -EXPORT_SYMBOL(debug_event); -EXPORT_SYMBOL(debug_int_event); -EXPORT_SYMBOL(debug_text_event); -EXPORT_SYMBOL(debug_exception); -EXPORT_SYMBOL(debug_int_exception); -EXPORT_SYMBOL(debug_text_exception); -EXPORT_SYMBOL(debug_hex_ascii_view); -EXPORT_SYMBOL(debug_raw_view); -EXPORT_SYMBOL(debug_dflt_header_fn); - -/* * memory management */ EXPORT_SYMBOL(_oi_bitmap); @@ -99,42 +46,17 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(_ascebc_500); -EXPORT_SYMBOL_NOVERS(_ebcasc_500); -EXPORT_SYMBOL_NOVERS(_ascebc); -EXPORT_SYMBOL_NOVERS(_ebcasc); -EXPORT_SYMBOL_NOVERS(_ebc_tolower); -EXPORT_SYMBOL_NOVERS(_ebc_toupper); - /* * misc. */ -EXPORT_SYMBOL(module_list); +EXPORT_SYMBOL(machine_flags); EXPORT_SYMBOL(__udelay); -#ifdef CONFIG_SMP -#include -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); -EXPORT_SYMBOL(lowcore_ptr); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(smp_ctl_set_bit); -EXPORT_SYMBOL(smp_ctl_clear_bit); -#endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); -#if CONFIG_CHANDEV -EXPORT_SYMBOL(chandev_register_and_probe); -EXPORT_SYMBOL(chandev_request_irq); -EXPORT_SYMBOL(chandev_unregister); -EXPORT_SYMBOL(chandev_initdevice); -EXPORT_SYMBOL(chandev_initnetdevice); -#endif + #if CONFIG_IP_MULTICAST /* Required for lcs gigabit ethernet multicast support */ EXPORT_SYMBOL(arp_mc_map); #endif -EXPORT_SYMBOL(s390_daemonize); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390fpu.c linux.ac/arch/s390/kernel/s390fpu.c --- linux.vanilla/arch/s390/kernel/s390fpu.c Tue Feb 13 22:13:43 2001 +++ linux.ac/arch/s390/kernel/s390fpu.c Thu Apr 12 11:59:46 2001 @@ -57,10 +57,9 @@ void save_fp_regs(s390_fp_regs *fpregs) { -#if CONFIG_IEEEFPU_EMULATION +#if CONFIG_MATHEMU s390_fp_regs *currentfprs; -#endif -#if CONFIG_IEEEFPU_EMULATION + if(!save_fp_regs1(fpregs)) { currentfprs=¤t->thread.fp_regs; @@ -119,11 +118,9 @@ void restore_fp_regs(s390_fp_regs *fpregs) { -#if CONFIG_IEEEFPU_EMULATION +#if CONFIG_MATHEMU s390_fp_regs *currentfprs; -#endif -#if CONFIG_IEEEFPU_EMULATION if(!restore_fp_regs1(fpregs)) { currentfprs=¤t->thread.fp_regs; @@ -138,15 +135,4 @@ restore_fp_regs1(fpregs); #endif } - - - - - - - - - - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/semaphore.c linux.ac/arch/s390/kernel/semaphore.c --- linux.vanilla/arch/s390/kernel/semaphore.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/semaphore.c Wed Apr 18 13:53:10 2001 @@ -158,145 +158,3 @@ spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } - -void down_read_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->read_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - -void down_write_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->write_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* if the lock is currently unbiased, awaken the sleepers - * FIXME: this wakes up the readers early in a bit of a - * stampede -> bad! - */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); -} - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -void down_read_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - up_read(sem); /* this takes care of granting the lock */ - - add_wait_queue(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - -/* Wait for the lock to become unbiased. Since we're - * a writer, we'll make ourselves exclusive. - */ -void down_write_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - up_write(sem); /* this takes care of granting the lock */ - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to acquire or bias the lock */ - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - -/* Called when someone has done an up that transitioned from - * negative to non-negative, meaning that the lock has been - * granted to whomever owned the bias. - */ -void rwsem_wake_readers(struct rw_semaphore *sem) -{ - if (xchg(&sem->read_bias_granted, 1)) - BUG(); - wake_up(&sem->wait); -} - -void rwsem_wake_writers(struct rw_semaphore *sem) -{ - if (xchg(&sem->write_bias_granted, 1)) - BUG(); - wake_up(&sem->write_bias_wait); -} - -void __down_read_failed(int count, struct rw_semaphore *sem) -{ - do { - if (count == -1) { - down_read_failed_biased(sem); - break; - } - down_read_failed(sem); - count = atomic_dec_return(&sem->count); - } while (count != 0); -} - -void __down_write_failed(int count, struct rw_semaphore *sem) -{ - do { - if (count < 0 && count > -RW_LOCK_BIAS) { - down_write_failed_biased(sem); - break; - } - down_write_failed(sem); - count = atomic_add_return(-RW_LOCK_BIAS, &sem->count); - } while (count != 0); -} - -void __rwsem_wake(int count, struct rw_semaphore *sem) -{ - if (count == 0) - rwsem_wake_readers(sem); - else - rwsem_wake_writers(sem); -} - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/setup.c linux.ac/arch/s390/kernel/setup.c --- linux.vanilla/arch/s390/kernel/setup.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/setup.c Thu Apr 12 11:59:46 2001 @@ -38,10 +38,13 @@ #include #include #include +#include /* * Machine setup.. */ +unsigned long memory_size = 0; +unsigned long machine_flags = 0; __u16 boot_cpu_addr; int cpus_initialized = 0; unsigned long cpu_initialized = 0; @@ -50,17 +53,8 @@ /* * Setup options */ - -#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; extern int _text,_etext, _edata, _end; - /* * This is set up by the setup-routine at boot-time * for S390 need to find out, what we have to setup @@ -208,14 +202,9 @@ "This machine has an IEEE fpu\n" : "This machine has no IEEE fpu\n"); - 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 + ROOT_DEV = to_kdev_t(0x0100); memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ - memory_end = MEMORY_SIZE; + memory_end = memory_size; /* * We need some free virtual space to be able to do vmalloc. * On a machine with 2GB memory we make sure that we have at @@ -223,8 +212,6 @@ */ if (memory_end > 1920*1024*1024) memory_end = 1920*1024*1024; - memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ - memory_end = MEMORY_SIZE; /* detected in head.s */ init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; @@ -311,7 +298,6 @@ */ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); - paging_init(); #ifdef CONFIG_BLK_DEV_INITRD if (INITRD_START) { if (INITRD_START + INITRD_SIZE <= memory_end) { @@ -326,6 +312,9 @@ } } #endif + + paging_init(); + res = alloc_bootmem_low(sizeof(struct resource)); res->start = 0; res->end = memory_end; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/signal.c linux.ac/arch/s390/kernel/signal.c --- linux.vanilla/arch/s390/kernel/signal.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/signal.c Thu Apr 12 11:59:46 2001 @@ -187,7 +187,7 @@ int err; s390_fp_regs fpregs; - err = __copy_to_user(&sregs->regs,regs,sizeof(s390_regs_common)); + err = __copy_to_user(&sregs->regs,regs,sizeof(_s390_regs_common)); if(!err) { save_fp_regs(&fpregs); @@ -202,7 +202,7 @@ int err; s390_fp_regs fpregs; psw_t saved_psw=regs->psw; - err=__copy_from_user(regs,&sregs->regs,sizeof(s390_regs_common)); + err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common)); if(!err) { regs->orig_gpr2 = -1; /* disable syscall checks */ @@ -218,7 +218,7 @@ } static int -restore_sigcontext(struct sigcontext *sc, pt_regs *regs, +restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs, _sigregs *sregs,sigset_t *set) { unsigned int err; @@ -555,6 +555,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/smp.c linux.ac/arch/s390/kernel/smp.c --- linux.vanilla/arch/s390/kernel/smp.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/smp.c Thu Apr 12 11:59:46 2001 @@ -20,6 +20,7 @@ * cpu_number_map in other architectures. */ +#include #include #include @@ -33,8 +34,7 @@ #include #include #include - -#include "cpcmd.h" +#include /* prototypes */ extern int cpu_idle(void * unused); @@ -390,7 +390,7 @@ /* stop all processors */ - smp_signal_others(sigp_stop, 0, TRUE, NULL); + smp_signal_others(sigp_stop, 0, 1, NULL); /* store status of all processors in their lowcores (real 0) */ @@ -586,7 +586,7 @@ struct pt_regs regs; /* don't care about the psw and regs settings since we'll never reschedule the forked task. */ - memset(®s,0,sizeof(pt_regs)); + memset(®s,0,sizeof(struct pt_regs)); return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } @@ -772,3 +772,7 @@ } } +EXPORT_SYMBOL(lowcore_ptr); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/traps.c linux.ac/arch/s390/kernel/traps.c --- linux.vanilla/arch/s390/kernel/traps.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/kernel/traps.c Thu Apr 12 11:59:46 2001 @@ -35,6 +35,7 @@ #if CONFIG_REMOTE_DEBUG #include #endif +#include /* Called from entry.S only */ extern void handle_per_exception(struct pt_regs *regs); @@ -51,6 +52,7 @@ #endif extern pgm_check_handler_t do_page_fault; +extern pgm_check_handler_t do_pseudo_page_fault; spinlock_t die_lock; @@ -140,7 +142,7 @@ DO_ERROR(SIGILL, "privileged operation", privileged_op) DO_ERROR(SIGILL, "execute exception", execute_exception) DO_ERROR(SIGSEGV, "addressing exception", addressing_exception) -DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception) +DO_ERROR(SIGILL, "fixpoint divide exception", divide_exception) DO_ERROR(SIGILL, "translation exception", translation_exception) DO_ERROR(SIGILL, "special operand exception", special_op_exception) DO_ERROR(SIGILL, "operand exception", operand_exception) @@ -149,7 +151,7 @@ { __u8 opcode[6]; __u16 *location; - int do_sig = 0; + int signal = 0; int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); lock_kernel(); @@ -161,82 +163,93 @@ if(*((__u16 *)opcode)==S390_BREAKPOINT_U16) { if(do_debugger_trap(regs,SIGTRAP)) - do_sig=1; + signal = SIGILL; } -#ifdef CONFIG_IEEEFPU_EMULATION - else if (problem_state ) +#ifdef CONFIG_MATHEMU + else if (problem_state) { if (opcode[0] == 0xb3) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_b3(opcode, regs); + signal = math_emu_b3(opcode, regs); } else if (opcode[0] == 0xed) { get_user(*((__u32 *) (opcode+2)), (__u32 *)(location+1)); - do_sig = math_emu_ed(opcode, regs); + signal = math_emu_ed(opcode, regs); } else if (*((__u16 *) opcode) == 0xb299) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_srnm(opcode, regs); + signal = math_emu_srnm(opcode, regs); } else if (*((__u16 *) opcode) == 0xb29c) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_stfpc(opcode, regs); + signal = math_emu_stfpc(opcode, regs); } else if (*((__u16 *) opcode) == 0xb29d) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_lfpc(opcode, regs); + signal = math_emu_lfpc(opcode, regs); } else - do_sig = 1; + signal = SIGILL; } #endif else - do_sig = 1; - if (do_sig) - do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL); + signal = SIGILL; + if (signal == SIGFPE) { + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, signal, + "floating point exception", regs, NULL); + } else if (signal) + do_trap(interruption_code, signal, + "illegal operation", regs, NULL); unlock_kernel(); } -#ifdef CONFIG_IEEEFPU_EMULATION -asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code) +#ifdef CONFIG_MATHEMU +asmlinkage void +specification_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; - int do_sig = 0; + int signal = 0; lock_kernel(); - if (regs->psw.mask & 0x00010000L) { + if (regs->psw.mask & PSW_PROBLEM_STATE) { location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - do_sig=math_emu_ldr(opcode); + signal = math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - do_sig=math_emu_ler(opcode); + signal = math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_std(opcode, regs); + signal = math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ld(opcode, regs); + signal = math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ste(opcode, regs); + signal = math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_le(opcode, regs); + signal = math_emu_le(opcode, regs); break; default: - do_sig = 1; + signal = SIGILL; break; } } else - do_sig = 1; - if (do_sig) - do_trap(interruption_code, SIGILL, "specification exception", regs, NULL); + signal = SIGILL; + if (signal == SIGFPE) { + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, signal, + "floating point exception", regs, NULL); + } else if (signal) + do_trap(interruption_code, signal, + "specification exception", regs, NULL); unlock_kernel(); } #else @@ -247,80 +260,79 @@ { __u8 opcode[6]; __u16 *location; - int do_sig = 0; + int signal = 0; lock_kernel(); location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); - if(MACHINE_HAS_IEEE) - { + if (MACHINE_HAS_IEEE) __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); - } - /* Same code should work when we implement fpu emulation */ - /* provided we call data exception from the fpu emulator */ - if(current->thread.fp_regs.fpc&FPC_DXC_MASK) - { - current->thread.ieee_instruction_pointer=(addr_t)location; - force_sig(SIGFPE, current); - } -#ifdef CONFIG_IEEEFPU_EMULATION - else if (regs->psw.mask & 0x00010000L) { + +#ifdef CONFIG_MATHEMU + else if (regs->psw.mask & PSW_PROBLEM_STATE) { get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - do_sig=math_emu_ldr(opcode); + signal = math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - do_sig=math_emu_ler(opcode); + signal = math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_std(opcode, regs); + signal = math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ld(opcode, regs); + signal = math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_ste(opcode, regs); + signal = math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - do_sig=math_emu_le(opcode, regs); + signal = math_emu_le(opcode, regs); break; case 0xb3: get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_b3(opcode, regs); + signal = math_emu_b3(opcode, regs); break; case 0xed: get_user(*((__u32 *) (opcode+2)), (__u32 *)(location+1)); - do_sig = math_emu_ed(opcode, regs); + signal = math_emu_ed(opcode, regs); break; case 0xb2: if (opcode[1] == 0x99) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_srnm(opcode, regs); + signal = math_emu_srnm(opcode, regs); } else if (opcode[1] == 0x9c) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_stfpc(opcode, regs); + signal = math_emu_stfpc(opcode, regs); } else if (opcode[1] == 0x9d) { get_user(*((__u16 *) (opcode+2)), location+1); - do_sig = math_emu_lfpc(opcode, regs); + signal = math_emu_lfpc(opcode, regs); } else - do_sig = 1; + signal = SIGILL; break; default: - do_sig = 1; + signal = SIGILL; break; } } #endif + if (current->thread.fp_regs.fpc & FPC_DXC_MASK) + signal = SIGFPE; else - do_sig = 1; - if (do_sig) - do_trap(interruption_code, SIGILL, "data exception", regs, NULL); + signal = SIGILL; + if (signal == SIGFPE) { + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, signal, + "floating point exception", regs, NULL); + } else if (signal) + do_trap(interruption_code, signal, + "data exception", regs, NULL); unlock_kernel(); } @@ -337,17 +349,20 @@ pgm_check_table[1] = &illegal_op; pgm_check_table[2] = &privileged_op; pgm_check_table[3] = &execute_exception; + pgm_check_table[4] = &do_page_fault; pgm_check_table[5] = &addressing_exception; pgm_check_table[6] = &specification_exception; pgm_check_table[7] = &data_exception; pgm_check_table[9] = ÷_exception; + pgm_check_table[0x10] = &do_page_fault; + pgm_check_table[0x11] = &do_page_fault; pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; + pgm_check_table[0x14] = &do_pseudo_page_fault; pgm_check_table[0x15] = &operand_exception; - pgm_check_table[4] = &do_page_fault; - pgm_check_table[0x10] = &do_page_fault; - pgm_check_table[0x11] = &do_page_fault; pgm_check_table[0x1C] = &privileged_op; + if (MACHINE_IS_VM) + cpcmd("SET PAGEX ON", NULL, 0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/Makefile linux.ac/arch/s390/lib/Makefile --- linux.vanilla/arch/s390/lib/Makefile Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/lib/Makefile Thu Apr 12 11:59:46 2001 @@ -12,7 +12,8 @@ L_TARGET = lib.a -obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o +obj-y = checksum.o delay.o memset.o misaligned.o strcmp.o strncpy.o uaccess.o +export-objs += misaligned.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/checksum.c linux.ac/arch/s390/lib/checksum.c --- linux.vanilla/arch/s390/lib/checksum.c Fri May 12 19:41:45 2000 +++ linux.ac/arch/s390/lib/checksum.c Thu Apr 12 11:59:46 2001 @@ -23,18 +23,17 @@ unsigned int csum_partial (const unsigned char *buff, int len, unsigned int sum) { + register_pair rp; /* * Experiments with ethernet and slip connections show that buff * is aligned on either a 2-byte or 4-byte boundary. */ + rp.subreg.even = (unsigned long) buff; + rp.subreg.odd = (unsigned long) len; __asm__ __volatile__ ( - " lr 2,%1\n" /* address in gpr 2 */ - " lr 3,%2\n" /* length in gpr 3 */ - "0: cksm %0,2\n" /* do checksum on longs */ + "0: cksm %0,%1\n" /* do checksum on longs */ " jo 0b\n" - : "+&d" (sum) - : "d" (buff), "d" (len) - : "cc", "2", "3" ); + : "+&d" (sum), "+&a" (rp) : : "cc" ); return sum; } @@ -43,14 +42,16 @@ */ unsigned short csum_fold(unsigned int sum) { - __asm__ __volatile__ ( - " sr 3,3\n" /* %0 = H*65536 + L */ - " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */ - " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */ - " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */ - " alr %0,2\n" /* %0 = H+L+C L+H */ - " srl %0,16\n" /* %0 = H+L+C */ - : "+d" (sum) : : "cc", "2", "3"); - return ((unsigned short) ~sum); + register_pair rp; + + __asm__ __volatile__ ( + " slr %N1,%N1\n" /* %0 = H L */ + " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */ + " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */ + " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */ + " alr %0,%1\n" /* %0 = H+L+C L+H */ + " srl %0,16\n" /* %0 = H+L+C */ + : "+&d" (sum), "=d" (rp) : : "cc" ); + return ((unsigned short) ~sum); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/misaligned.c linux.ac/arch/s390/lib/misaligned.c --- linux.vanilla/arch/s390/lib/misaligned.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/lib/misaligned.c Thu Apr 12 11:59:46 2001 @@ -0,0 +1,29 @@ +/* + * arch/s390/lib/misaligned.c + * S390 misalignment panic stubs + * + * S390 version + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com). + * + * xchg wants to panic if the pointer is not aligned. To avoid multiplying + * the panic message over and over again, the panic is done in the helper + * functions __misaligned_u32 and __misaligned_u16. + */ + +#include +#include + +void __misaligned_u16(void) +{ + panic("misaligned (__u16 *) in __xchg\n"); +} + +void __misaligned_u32(void) +{ + panic("misaligned (__u32 *) in __xchg\n"); +} + +EXPORT_SYMBOL(__misaligned_u16); +EXPORT_SYMBOL(__misaligned_u32); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/Makefile linux.ac/arch/s390/math-emu/Makefile --- linux.vanilla/arch/s390/math-emu/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/Makefile Thu Apr 12 11:59:46 2001 @@ -0,0 +1,12 @@ +# +# Makefile for the FPU instruction emulation. +# + +O_TARGET := math-emu.o +obj-$(CONFIG_MATHEMU) := math.o qrnnd.o + +EXTRA_CFLAGS = -I. -I$(TOPDIR)/include/math-emu -w + +include $(TOPDIR)/Rules.make + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/math.c linux.ac/arch/s390/math-emu/math.c --- linux.vanilla/arch/s390/math-emu/math.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/math.c Sat Apr 14 01:18:00 2001 @@ -0,0 +1,2152 @@ +/* + * arch/s390/math-emu/math.c + * + * S390 version + * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * + * 'math.c' emulates IEEE instructions on a S390 processor + * that does not have the IEEE fpu (all processors before G5). + */ + +#include +#include +#include +#include +#include + +#include "sfp-util.h" +#include +#include +#include +#include + +/* + * I miss a macro to round a floating point number to the + * nearest integer in the same floating point format. + */ +#define _FP_TO_FPINT_ROUND(fs, wc, X) \ + do { \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + if (X##_e > _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs) \ + { /* floating point number has no bits after the dot. */ \ + } \ + else if (X##_e <= _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs && \ + X##_e > _FP_EXPBIAS_##fs) \ + { /* some bits before the dot, some after it. */ \ + _FP_FRAC_SRS_##wc(X, _FP_WFRACBITS_##fs, \ + X##_e - _FP_EXPBIAS_##fs \ + + _FP_FRACBITS_##fs); \ + _FP_ROUND(wc, X); \ + _FP_FRAC_SLL_##wc(X, X##_e - _FP_EXPBIAS_##fs \ + + _FP_FRACBITS_##fs); \ + } \ + else \ + { /* all bits after the dot. */ \ + FP_SET_EXCEPTION(FP_EX_INEXACT); \ + X##_c = FP_CLS_ZERO; \ + } \ + break; \ + case FP_CLS_NAN: \ + case FP_CLS_INF: \ + case FP_CLS_ZERO: \ + break; \ + } \ + } while (0) + +#define FP_TO_FPINT_ROUND_S(X) _FP_TO_FPINT_ROUND(S,1,X) +#define FP_TO_FPINT_ROUND_D(X) _FP_TO_FPINT_ROUND(D,2,X) +#define FP_TO_FPINT_ROUND_Q(X) _FP_TO_FPINT_ROUND(Q,4,X) + +typedef union { + long double ld; + struct { + __u64 high; + __u64 low; + } w; +} mathemu_ldcv; + +#ifdef CONFIG_SYSCTL +int sysctl_ieee_emulation_warnings=1; +#endif + +#define mathemu_put_user(x, p) \ + do { \ + if (put_user((x),(p))) \ + return SIGSEGV; \ + } while (0) + +#define mathemu_get_user(x, p) \ + do { \ + if (get_user((x),(p))) \ + return SIGSEGV; \ + } while (0) + +#define mathemu_copy_from_user(d, s, n)\ + do { \ + if (copy_from_user((d),(s),(n)) == -EFAULT) \ + return SIGSEGV; \ + } while (0) + +#define mathemu_copy_to_user(d, s, n) \ + do { \ + if (copy_to_user((d),(s),(n)) == -EFAULT) \ + return SIGSEGV; \ + } while (0) + +static void display_emulation_not_implemented(char *instr) +{ + struct pt_regs *regs; + __u16 *location; + +#if CONFIG_SYSCTL + if(sysctl_ieee_emulation_warnings) +#endif + { + regs = current->thread.regs; + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + printk("%s ieee fpu instruction not emulated " + "process name: %s pid: %d \n", + instr, current->comm, current->pid); + printk("%s's PSW: %08lx %08lx\n", instr, + (unsigned long) regs->psw.mask, + (unsigned long) location); + } +} + +static inline void emu_set_CC (int cc) +{ + current->thread.regs->psw.mask = + (current->thread.regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12); +} + +/* + * Set the condition code in the user psw. + * 0 : Result is zero + * 1 : Result is less than zero + * 2 : Result is greater than zero + * 3 : Result is NaN or INF + */ +static inline void emu_set_CC_cs(int class, int sign) +{ + switch (class) { + case FP_CLS_NORMAL: + case FP_CLS_INF: + emu_set_CC(sign ? 1 : 2); + break; + case FP_CLS_ZERO: + emu_set_CC(0); + break; + case FP_CLS_NAN: + emu_set_CC(3); + break; + } +} + +/* Add long double */ +static int emu_axbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_ADD_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Add double */ +static int emu_adbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_ADD_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Add double */ +static int emu_adb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_ADD_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Add float */ +static int emu_aebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_ADD_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Add float */ +static int emu_aeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_ADD_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Compare long double */ +static int emu_cxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); + mathemu_ldcv cvt; + int IR; + + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_RAW_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_RAW_QP(QB, &cvt.ld); + FP_CMP_Q(IR, QA, QB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare double */ +static int emu_cdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare double */ +static int emu_cdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, val); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare float */ +static int emu_cebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare float */ +static int emu_ceb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, val); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + return 0; +} + +/* Compare and signal long double */ +static int emu_kxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); + FP_DECL_EX; + mathemu_ldcv cvt; + int IR; + + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_RAW_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_CMP_Q(IR, QA, QB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal double */ +static int emu_kdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal double */ +static int emu_kdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_RAW_DP(DB, val); + FP_CMP_D(IR, DA, DB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal float */ +static int emu_kebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Compare and signal float */ +static int emu_keb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); + FP_DECL_EX; + int IR; + + FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_RAW_SP(SB, val); + FP_CMP_S(IR, SA, SB, 3); + /* + * IR == -1 if DA < DB, IR == 0 if DA == DB, + * IR == 1 if DA > DB and IR == 3 if unorderded + */ + emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR); + if (IR == 3) + FP_SET_EXCEPTION (FP_EX_INVALID); + return _fex; +} + +/* Convert from fixed long double */ +static int emu_cxfbr (int rx, int ry) { + FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + __s32 si; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + si = current->thread.regs->gprs[ry]; + FP_FROM_INT_Q(QR, si, 32, int); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Convert from fixed double */ +static int emu_cdfbr (int rx, int ry) { + FP_DECL_D(DR); + FP_DECL_EX; + __s32 si; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + si = current->thread.regs->gprs[ry]; + FP_FROM_INT_D(DR, si, 32, int); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Convert from fixed float */ +static int emu_cefbr (int rx, int ry) { + FP_DECL_S(SR); + FP_DECL_EX; + __s32 si; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + si = current->thread.regs->gprs[ry]; + FP_FROM_INT_S(SR, si, 32, int); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Convert to fixed long double */ +static int emu_cfxbr (int rx, int ry, int mask) { + FP_DECL_Q(QA); + FP_DECL_EX; + mathemu_ldcv cvt; + __s32 si; + int mode; + + if (mask == 0) + mode = current->thread.fp_regs.fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_TO_INT_ROUND_Q(si, QA, 32, 1); + current->thread.regs->gprs[rx] = si; + emu_set_CC_cs(QA_c, QA_s); + return _fex; +} + +/* Convert to fixed double */ +static int emu_cfdbr (int rx, int ry, int mask) { + FP_DECL_D(DA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = current->thread.fp_regs.fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_TO_INT_ROUND_D(si, DA, 32, 1); + current->thread.regs->gprs[rx] = si; + emu_set_CC_cs(DA_c, DA_s); + return _fex; +} + +/* Convert to fixed float */ +static int emu_cfebr (int rx, int ry, int mask) { + FP_DECL_S(SA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = current->thread.fp_regs.fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_TO_INT_ROUND_S(si, SA, 32, 1); + current->thread.regs->gprs[rx] = si; + emu_set_CC_cs(SA_c, SA_s); + return _fex; +} + +/* Divide long double */ +static int emu_dxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_DIV_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Divide double */ +static int emu_ddbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_DIV_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Divide double */ +static int emu_ddb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_DIV_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Divide float */ +static int emu_debr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_DIV_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Divide float */ +static int emu_deb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_DIV_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Divide to integer double */ +static int emu_didbr (int rx, int ry, int mask) { + display_emulation_not_implemented("didbr"); + return 0; +} + +/* Divide to integer float */ +static int emu_diebr (int rx, int ry, int mask) { + display_emulation_not_implemented("diebr"); + return 0; +} + +/* Extract fpc */ +static int emu_efpc (int rx, int ry) { + current->thread.regs->gprs[rx] = current->thread.fp_regs.fpc; + return 0; +} + +/* Load and test long double */ +static int emu_ltxbr (int rx, int ry) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + mathemu_ldcv cvt; + FP_DECL_Q(QA); + FP_DECL_EX; + + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui; + fp_regs->fprs[rx+2].ui = fp_regs->fprs[ry+2].ui; + emu_set_CC_cs(QA_c, QA_s); + return _fex; +} + +/* Load and test double */ +static int emu_ltdbr (int rx, int ry) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_D(DA); + FP_DECL_EX; + + FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d); + fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui; + emu_set_CC_cs(DA_c, DA_s); + return _fex; +} + +/* Load and test double */ +static int emu_ltebr (int rx, int ry) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_S(SA); + FP_DECL_EX; + + FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f); + fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui; + emu_set_CC_cs(SA_c, SA_s); + return _fex; +} + +/* Load complement long double */ +static int emu_lcxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_NEG_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Load complement double */ +static int emu_lcdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_NEG_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Load complement float */ +static int emu_lcebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_NEG_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Load floating point integer long double */ +static int emu_fixbr (int rx, int ry, int mask) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_Q(QA); + FP_DECL_EX; + mathemu_ldcv cvt; + __s32 si; + int mode; + + if (mask == 0) + mode = fp_regs->fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + cvt.w.high = fp_regs->fprs[ry].ui; + cvt.w.low = fp_regs->fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_TO_FPINT_ROUND_Q(QA); + FP_PACK_QP(&cvt.ld, QA); + fp_regs->fprs[rx].ui = cvt.w.high; + fp_regs->fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load floating point integer double */ +static int emu_fidbr (int rx, int ry, int mask) { + /* FIXME: rounding mode !! */ + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_D(DA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = fp_regs->fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d); + FP_TO_FPINT_ROUND_D(DA); + FP_PACK_DP(&fp_regs->fprs[rx].d, DA); + return _fex; +} + +/* Load floating point integer float */ +static int emu_fiebr (int rx, int ry, int mask) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + FP_DECL_S(SA); + FP_DECL_EX; + __s32 si; + int mode; + + if (mask == 0) + mode = fp_regs->fpc & 3; + else if (mask == 1) + mode = FP_RND_NEAREST; + else + mode = mask - 4; + FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f); + FP_TO_FPINT_ROUND_S(SA); + FP_PACK_SP(&fp_regs->fprs[rx].f, SA); + return _fex; +} + +/* Load lengthened double to long double */ +static int emu_lxdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_CONV (Q, D, 4, 2, QR, DA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened double to long double */ +static int emu_lxdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, val); + FP_CONV (Q, D, 4, 2, QR, DA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened float to long double */ +static int emu_lxebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_CONV (Q, S, 4, 1, QR, SA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened float to long double */ +static int emu_lxeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, val); + FP_CONV (Q, S, 4, 1, QR, SA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Load lengthened float to double */ +static int emu_ldebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_CONV (D, S, 2, 1, DR, SA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Load lengthened float to double */ +static int emu_ldeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, val); + FP_CONV (D, S, 2, 1, DR, SA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Load negative long double */ +static int emu_lnxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + if (QA_s == 0) { + FP_NEG_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + } else { + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + current->thread.fp_regs.fprs[rx+2].ui = + current->thread.fp_regs.fprs[ry+2].ui; + } + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Load negative double */ +static int emu_lndbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + if (DA_s == 0) { + FP_NEG_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Load negative float */ +static int emu_lnebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + if (SA_s == 0) { + FP_NEG_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Load positive long double */ +static int emu_lpxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + if (QA_s != 0) { + FP_NEG_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + } else{ + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + current->thread.fp_regs.fprs[rx+2].ui = + current->thread.fp_regs.fprs[ry+2].ui; + } + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Load positive double */ +static int emu_lpdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + if (DA_s != 0) { + FP_NEG_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Load positive float */ +static int emu_lpebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + if (SA_s != 0) { + FP_NEG_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + } else + current->thread.fp_regs.fprs[rx].ui = + current->thread.fp_regs.fprs[ry].ui; + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Load rounded long double to double */ +static int emu_ldxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_D(DR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_CONV (D, Q, 2, 4, DR, QA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].f, DR); + return _fex; +} + +/* Load rounded long double to float */ +static int emu_lexbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_S(SR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_CONV (S, Q, 1, 4, SR, QA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Load rounded double to float */ +static int emu_ledbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_CONV (S, D, 1, 2, SR, DA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Multiply long double */ +static int emu_mxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_MUL_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Multiply double */ +static int emu_mdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply double */ +static int emu_mdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply double to long double */ +static int emu_mxdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_CONV (Q, D, 4, 2, QA, DA); + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_CONV (Q, D, 4, 2, QB, DA); + FP_MUL_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Multiply double to long double */ +static int emu_mxdb (int rx, long double *val) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_UNPACK_QP(QB, val); + FP_MUL_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + return _fex; +} + +/* Multiply float */ +static int emu_meebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_MUL_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Multiply float */ +static int emu_meeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_MUL_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + return _fex; +} + +/* Multiply float to double */ +static int emu_mdebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_CONV (D, S, 2, 1, DA, SA); + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_CONV (D, S, 2, 1, DB, SA); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply float to double */ +static int emu_mdeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_CONV (D, S, 2, 1, DA, SA); + FP_UNPACK_SP(SA, val); + FP_CONV (D, S, 2, 1, DB, SA); + FP_MUL_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + return _fex; +} + +/* Multiply and add double */ +static int emu_madbr (int rx, int ry, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_ADD_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and add double */ +static int emu_madb (int rx, double *val, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_ADD_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and add float */ +static int emu_maebr (int rx, int ry, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_ADD_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Multiply and add float */ +static int emu_maeb (int rx, float *val, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_ADD_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Multiply and subtract double */ +static int emu_msdbr (int rx, int ry, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_SUB_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and subtract double */ +static int emu_msdb (int rx, double *val, int rz) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_UNPACK_DP(DC, ¤t->thread.fp_regs.fprs[rz].d); + FP_MUL_D(DR, DA, DB); + FP_SUB_D(DR, DR, DC); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rz].d, DR); + return _fex; +} + +/* Multiply and subtract float */ +static int emu_msebr (int rx, int ry, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_SUB_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Multiply and subtract float */ +static int emu_mseb (int rx, float *val, int rz) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_UNPACK_SP(SC, ¤t->thread.fp_regs.fprs[rz].f); + FP_MUL_S(SR, SA, SB); + FP_SUB_S(SR, SR, SC); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rz].f, SR); + return _fex; +} + +/* Set floating point control word */ +static int emu_sfpc (int rx, int ry) { + __u32 temp; + + temp = current->thread.regs->gprs[rx]; + if ((temp & ~FPC_VALID_MASK) != 0) + return SIGILL; + current->thread.fp_regs.fpc = temp; + return 0; +} + +/* Square root long double */ +static int emu_sqxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + FP_SQRT_Q(QR, QA); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Square root double */ +static int emu_sqdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[ry].d); + FP_SQRT_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Square root double */ +static int emu_sqdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, val); + FP_SQRT_D(DR, DA); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Square root float */ +static int emu_sqebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[ry].f); + FP_SQRT_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Square root float */ +static int emu_sqeb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, val); + FP_SQRT_S(SR, SA); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Subtract long double */ +static int emu_sxbr (int rx, int ry) { + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + FP_DECL_EX; + mathemu_ldcv cvt; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + cvt.w.high = current->thread.fp_regs.fprs[rx].ui; + cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; + FP_UNPACK_QP(QA, &cvt.ld); + cvt.w.high = current->thread.fp_regs.fprs[ry].ui; + cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; + FP_UNPACK_QP(QB, &cvt.ld); + FP_SUB_Q(QR, QA, QB); + FP_PACK_QP(&cvt.ld, QR); + current->thread.fp_regs.fprs[rx].ui = cvt.w.high; + current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; + emu_set_CC_cs(QR_c, QR_s); + return _fex; +} + +/* Subtract double */ +static int emu_sdbr (int rx, int ry) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); + FP_SUB_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Subtract double */ +static int emu_sdb (int rx, double *val) { + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); + FP_UNPACK_DP(DB, val); + FP_SUB_D(DR, DA, DB); + FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); + emu_set_CC_cs(DR_c, DR_s); + return _fex; +} + +/* Subtract float */ +static int emu_sebr (int rx, int ry) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); + FP_SUB_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Subtract float */ +static int emu_seb (int rx, float *val) { + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + int mode; + + mode = current->thread.fp_regs.fpc & 3; + FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); + FP_UNPACK_SP(SB, val); + FP_SUB_S(SR, SA, SB); + FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); + emu_set_CC_cs(SR_c, SR_s); + return _fex; +} + +/* Test data class long double */ +static int emu_tcxb (int rx, double *val) { + display_emulation_not_implemented("tcxb"); + return 0; +} + +/* Test data class double */ +static int emu_tcdb (int rx, double *val) { + display_emulation_not_implemented("tcdb"); + return 0; +} + +/* Test data class float */ +static int emu_tceb (int rx, __u32 val) { + display_emulation_not_implemented("tceb"); + return 0; +} + +static inline void emu_load_regd(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* load reg from fp_regs.fprs[reg] */ + " bras 1,0f\n" + " ld 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4),"a" (¤t->thread.fp_regs.fprs[reg].d) + : "1" ); +} + +static inline void emu_load_rege(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* load reg from fp_regs.fprs[reg] */ + " bras 1,0f\n" + " le 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) + : "1" ); +} + +static inline void emu_store_regd(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* store reg to fp_regs.fprs[reg] */ + " bras 1,0f\n" + " std 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) + : "1" ); +} + + +static inline void emu_store_rege(int reg) { + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + return; + asm volatile ( /* store reg to fp_regs.fprs[reg] */ + " bras 1,0f\n" + " ste 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) + : "1" ); +} + +int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { + int _fex = 0; + static const __u8 format_table[256] = { + [0x00] = 0x03,[0x01] = 0x03,[0x02] = 0x03,[0x03] = 0x03, + [0x04] = 0x0f,[0x05] = 0x0d,[0x06] = 0x0e,[0x07] = 0x0d, + [0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03, + [0x0c] = 0x0f,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06, + [0x10] = 0x02,[0x11] = 0x02,[0x12] = 0x02,[0x13] = 0x02, + [0x14] = 0x03,[0x15] = 0x02,[0x16] = 0x01,[0x17] = 0x03, + [0x18] = 0x02,[0x19] = 0x02,[0x1a] = 0x02,[0x1b] = 0x02, + [0x1c] = 0x02,[0x1d] = 0x02,[0x1e] = 0x05,[0x1f] = 0x05, + [0x40] = 0x01,[0x41] = 0x01,[0x42] = 0x01,[0x43] = 0x01, + [0x44] = 0x12,[0x45] = 0x0d,[0x46] = 0x11,[0x47] = 0x04, + [0x48] = 0x01,[0x49] = 0x01,[0x4a] = 0x01,[0x4b] = 0x01, + [0x4c] = 0x01,[0x4d] = 0x01,[0x53] = 0x06,[0x57] = 0x06, + [0x5b] = 0x05,[0x5f] = 0x05,[0x84] = 0x13,[0x8c] = 0x13, + [0x94] = 0x09,[0x95] = 0x08,[0x96] = 0x07,[0x98] = 0x0c, + [0x99] = 0x0b,[0x9a] = 0x0a + }; + static const void *jump_table[256]= { + [0x00] = emu_lpebr,[0x01] = emu_lnebr,[0x02] = emu_ltebr, + [0x03] = emu_lcebr,[0x04] = emu_ldebr,[0x05] = emu_lxdbr, + [0x06] = emu_lxebr,[0x07] = emu_mxdbr,[0x08] = emu_kebr, + [0x09] = emu_cebr, [0x0a] = emu_aebr, [0x0b] = emu_sebr, + [0x0c] = emu_mdebr,[0x0d] = emu_debr, [0x0e] = emu_maebr, + [0x0f] = emu_msebr,[0x10] = emu_lpdbr,[0x11] = emu_lndbr, + [0x12] = emu_ltdbr,[0x13] = emu_lcdbr,[0x14] = emu_sqebr, + [0x15] = emu_sqdbr,[0x16] = emu_sqxbr,[0x17] = emu_meebr, + [0x18] = emu_kdbr, [0x19] = emu_cdbr, [0x1a] = emu_adbr, + [0x1b] = emu_sdbr, [0x1c] = emu_mdbr, [0x1d] = emu_ddbr, + [0x1e] = emu_madbr,[0x1f] = emu_msdbr,[0x40] = emu_lpxbr, + [0x41] = emu_lnxbr,[0x42] = emu_ltxbr,[0x43] = emu_lcxbr, + [0x44] = emu_ledbr,[0x45] = emu_ldxbr,[0x46] = emu_lexbr, + [0x47] = emu_fixbr,[0x48] = emu_kxbr, [0x49] = emu_cxbr, + [0x4a] = emu_axbr, [0x4b] = emu_sxbr, [0x4c] = emu_mxbr, + [0x4d] = emu_dxbr, [0x53] = emu_diebr,[0x57] = emu_fiebr, + [0x5b] = emu_didbr,[0x5f] = emu_fidbr,[0x84] = emu_sfpc, + [0x8c] = emu_efpc, [0x94] = emu_cefbr,[0x95] = emu_cdfbr, + [0x96] = emu_cxfbr,[0x98] = emu_cfebr,[0x99] = emu_cfdbr, + [0x9a] = emu_cfxbr + }; + + switch (format_table[opcode[1]]) { + case 1: /* RRE format, long double operation */ + if (opcode[3] & 0x22) + return SIGILL; + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(((opcode[3] >> 4) & 15) + 2); + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(((opcode[3] >> 4) & 15) + 2); + emu_load_regd(opcode[3] & 15); + emu_load_regd((opcode[3] & 15) + 2); + break; + case 2: /* RRE format, double operation */ + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(opcode[3] & 15); + break; + case 3: /* RRE format, float operation */ + emu_store_rege((opcode[3] >> 4) & 15); + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_rege((opcode[3] >> 4) & 15); + emu_load_rege(opcode[3] & 15); + break; + case 4: /* RRF format, long double operation */ + if (opcode[3] & 0x22) + return SIGILL; + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(((opcode[3] >> 4) & 15) + 2); + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(((opcode[3] >> 4) & 15) + 2); + emu_load_regd(opcode[3] & 15); + emu_load_regd((opcode[3] & 15) + 2); + break; + case 5: /* RRF format, double operation */ + emu_store_regd((opcode[2] >> 4) & 15); + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + emu_load_regd((opcode[2] >> 4) & 15); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(opcode[3] & 15); + break; + case 6: /* RRF format, float operation */ + emu_store_rege((opcode[2] >> 4) & 15); + emu_store_rege((opcode[3] >> 4) & 15); + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + emu_load_rege((opcode[2] >> 4) & 15); + emu_load_rege((opcode[3] >> 4) & 15); + emu_load_rege(opcode[3] & 15); + break; + case 7: /* RRE format, cxfbr instruction */ + /* call the emulation function */ + if (opcode[3] & 0x20) + return SIGILL; + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(((opcode[3] >> 4) & 15) + 2); + break; + case 8: /* RRE format, cdfbr instruction */ + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + break; + case 9: /* RRE format, cefbr instruction */ + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_rege((opcode[3] >> 4) & 15); + break; + case 10: /* RRF format, cfxbr instruction */ + if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32) + /* mask of { 2,3,8-15 } is invalid */ + return SIGILL; + if (opcode[3] & 2) + return SIGILL; + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + break; + case 11: /* RRF format, cfdbr instruction */ + if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32) + /* mask of { 2,3,8-15 } is invalid */ + return SIGILL; + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + break; + case 12: /* RRF format, cfebr instruction */ + if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32) + /* mask of { 2,3,8-15 } is invalid */ + return SIGILL; + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); + break; + case 13: /* RRE format, ldxbr & mdxbr instruction */ + /* double store but long double load */ + if (opcode[3] & 0x20) + return SIGILL; + emu_store_regd((opcode[3] >> 4) & 15); + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(((opcode[3] >> 4) & 15) + 2); + break; + case 14: /* RRE format, ldxbr & mdxbr instruction */ + /* float store but long double load */ + if (opcode[3] & 0x20) + return SIGILL; + emu_store_rege((opcode[3] >> 4) & 15); + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + emu_load_regd(((opcode[3] >> 4) & 15) + 2); + break; + case 15: /* RRE format, ldebr & mdebr instruction */ + /* float store but double load */ + emu_store_rege((opcode[3] >> 4) & 15); + emu_store_rege(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + break; + case 16: /* RRE format, ldxbr instruction */ + /* long double store but double load */ + if (opcode[3] & 2) + return SIGILL; + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_regd((opcode[3] >> 4) & 15); + break; + case 17: /* RRE format, ldxbr instruction */ + /* long double store but float load */ + if (opcode[3] & 2) + return SIGILL; + emu_store_regd(opcode[3] & 15); + emu_store_regd((opcode[3] & 15) + 2); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_rege((opcode[3] >> 4) & 15); + break; + case 18: /* RRE format, ledbr instruction */ + /* double store but float load */ + emu_store_regd(opcode[3] & 15); + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + emu_load_rege((opcode[3] >> 4) & 15); + break; + case 19: /* RRE format, efpc & sfpc instruction */ + /* call the emulation function */ + _fex = ((int (*)(int, int)) jump_table[opcode[1]]) + (opcode[3] >> 4, opcode[3] & 15); + break; + default: /* invalid operation */ + return SIGILL; + } + if (_fex != 0) { + current->thread.fp_regs.fpc |= _fex; + if (current->thread.fp_regs.fpc & (_fex << 8)) + return SIGFPE; + } + return 0; +} + +static void* calc_addr(struct pt_regs *regs, int rx, int rb, int disp) +{ + addr_t addr; + + rx &= 15; + rb &= 15; + addr = disp & 0xfff; + addr += (rx != 0) ? regs->gprs[rx] : 0; /* + index */ + addr += (rb != 0) ? regs->gprs[rb] : 0; /* + base */ + return (void*) addr; +} + +int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { + int _fex = 0; + + static const __u8 format_table[256] = { + [0x04] = 0x08,[0x05] = 0x07,[0x06] = 0x09,[0x07] = 0x07, + [0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03, + [0x0c] = 0x08,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06, + [0x10] = 0x03,[0x11] = 0x02,[0x12] = 0x01,[0x14] = 0x03, + [0x15] = 0x02,[0x17] = 0x03,[0x18] = 0x02,[0x19] = 0x02, + [0x1a] = 0x02,[0x1b] = 0x02,[0x1c] = 0x02,[0x1d] = 0x02, + [0x1e] = 0x05,[0x1f] = 0x05, + }; + static const void *jump_table[]= { + [0x04] = emu_ldeb,[0x05] = emu_lxdb,[0x06] = emu_lxeb, + [0x07] = emu_mxdb,[0x08] = emu_keb, [0x09] = emu_ceb, + [0x0a] = emu_aeb, [0x0b] = emu_seb, [0x0c] = emu_mdeb, + [0x0d] = emu_deb, [0x0e] = emu_maeb,[0x0f] = emu_mseb, + [0x10] = emu_tceb,[0x11] = emu_tcdb,[0x12] = emu_tcxb, + [0x14] = emu_sqeb,[0x15] = emu_sqdb,[0x17] = emu_meeb, + [0x18] = emu_kdb, [0x19] = emu_cdb, [0x1a] = emu_adb, + [0x1b] = emu_sdb, [0x1c] = emu_mdb, [0x1d] = emu_ddb, + [0x1e] = emu_madb,[0x1f] = emu_msdb + }; + + switch (format_table[opcode[5]]) { + case 1: /* RXE format, long double constant */ { + __u64 *dxb, temp[2]; + __u32 opc; + + if ((opcode[1] >> 4) & 2) + return SIGILL; + emu_store_regd((opcode[1] >> 4) & 15); + emu_store_regd(((opcode[1] >> 4) & 15) + 2); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 16); + /* call the emulation function */ + _fex = ((int (*)(int, long double *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (long double *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + case 2: /* RXE format, double constant */ { + __u64 *dxb, temp; + __u32 opc; + + emu_store_regd((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 8); + /* call the emulation function */ + _fex = ((int (*)(int, double *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + break; + } + case 3: /* RXE format, float constant */ { + __u32 *dxb, temp; + __u32 opc; + + emu_store_rege((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp); + emu_load_rege((opcode[1] >> 4) & 15); + break; + } + case 4: /* RXF format, long double constant */ { + __u64 *dxb, temp[2]; + __u32 opc; + + if (((opcode[1] >> 4) & 0x20) || ((opcode[4] >> 4) & 0x20)) + return SIGILL; + emu_store_regd((opcode[1] >> 4) & 15); + emu_store_regd(((opcode[1] >> 4) & 15) + 2); + emu_store_regd((opcode[4] >> 4) & 15); + emu_store_regd(((opcode[4] >> 4) & 15) + 2); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 16); + /* call the emulation function */ + _fex = ((int (*)(int,long double *,int)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + case 5: /* RXF format, double constant */ { + __u64 *dxb, temp; + __u32 opc; + + emu_store_regd((opcode[1] >> 4) & 15); + emu_store_regd((opcode[4] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 8); + /* call the emulation function */ + _fex = ((int (*)(int, double *, int)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4); + emu_load_regd((opcode[1] >> 4) & 15); + break; + } + case 6: /* RXF format, float constant */ { + __u32 *dxb, temp; + __u32 opc; + + emu_store_rege((opcode[1] >> 4) & 15); + emu_store_rege((opcode[4] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *, int)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp, opcode[4] >> 4); + emu_load_rege((opcode[4] >> 4) & 15); + break; + } + case 7: /* RXE format, double constant */ + /* store double and load long double */ + { + __u64 *dxb, temp; + __u32 opc; + if ((opcode[1] >> 4) & 0x20) + return SIGILL; + emu_store_regd((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&temp, dxb, 8); + /* call the emulation function */ + _fex = ((int (*)(int, double *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (double *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + case 8: /* RXE format, float constant */ + /* store float and load double */ + { + __u32 *dxb, temp; + __u32 opc; + emu_store_rege((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + break; + } + case 9: /* RXE format, float constant */ + /* store float and load long double */ + { + __u32 *dxb, temp; + __u32 opc; + if ((opcode[1] >> 4) & 0x20) + return SIGILL; + emu_store_rege((opcode[1] >> 4) & 15); + opc = *((__u32 *) opcode); + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_get_user(temp, dxb); + /* call the emulation function */ + _fex = ((int (*)(int, float *)) jump_table[opcode[5]]) + (opcode[1] >> 4, (float *) &temp); + emu_load_regd((opcode[1] >> 4) & 15); + emu_load_regd(((opcode[1] >> 4) & 15) + 2); + break; + } + default: /* invalid operation */ + return SIGILL; + } + if (_fex != 0) { + current->thread.fp_regs.fpc |= _fex; + if (current->thread.fp_regs.fpc & (_fex << 8)) + return SIGFPE; + } + return 0; +} + +/* + * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6} + */ +int math_emu_ldr(__u8 *opcode) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u16 opc = *((__u16 *) opcode); + + if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */ + /* we got an exception therfore ry can't be in {0,2,4,6} */ + __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ + " bras 1,0f\n" + " ld 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (opc & 0xf0), + "a" (&fp_regs->fprs[opc & 0xf].d) + : "1" ); + } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */ + __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ + " bras 1,0f\n" + " std 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" ((opc & 0xf) << 4), + "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d) + : "1" ); + } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ + fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf]; + return 0; +} + +/* + * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6} + */ +int math_emu_ler(__u8 *opcode) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u16 opc = *((__u16 *) opcode); + + if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */ + /* we got an exception therfore ry can't be in {0,2,4,6} */ + __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ + " bras 1,0f\n" + " le 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (opc & 0xf0), + "a" (&fp_regs->fprs[opc & 0xf].f) + : "1" ); + } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */ + __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ + " bras 1,0f\n" + " ste 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" ((opc & 0xf) << 4), + "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f) + : "1" ); + } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ + fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf]; + return 0; +} + +/* + * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_ld(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u64 *dxb; + + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_from_user(&fp_regs->fprs[(opc >> 20) & 0xf].d, dxb, 8); + return 0; +} + +/* + * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_le(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u32 *mem, *dxb; + + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f); + mathemu_get_user(mem[0], dxb); + return 0; +} + +/* + * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_std(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u64 *dxb; + + dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mathemu_copy_to_user(dxb, &fp_regs->fprs[(opc >> 20) & 0xf].d, 8); + return 0; +} + +/* + * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6} + */ +int math_emu_ste(__u8 *opcode, struct pt_regs * regs) { + s390_fp_regs *fp_regs = ¤t->thread.fp_regs; + __u32 opc = *((__u32 *) opcode); + __u32 *mem, *dxb; + + dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc); + mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f); + mathemu_put_user(mem[0], dxb); + return 0; +} + +/* + * Emulate LFPC D(B) + */ +int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { + __u32 opc = *((__u32 *) opcode); + __u32 *dxb, temp; + + dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc); + mathemu_get_user(temp, dxb); + if ((temp & ~FPC_VALID_MASK) != 0) + return SIGILL; + current->thread.fp_regs.fpc = temp; + return 0; +} + +/* + * Emulate STFPC D(B) + */ +int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { + __u32 opc = *((__u32 *) opcode); + __u32 *dxb; + + dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc); + mathemu_put_user(current->thread.fp_regs.fpc, dxb); + return 0; +} + +/* + * Emulate SRNM D(B) + */ +int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) { + __u32 opc = *((__u32 *) opcode); + __u32 temp; + + temp = calc_addr(regs, 0, opc>>12, opc); + current->thread.fp_regs.fpc &= ~3; + current->thread.fp_regs.fpc |= (temp & 3); + return 0; +} + +/* broken compiler ... */ +long long +__negdi2 (long long u) +{ + + union lll { + long long ll; + long s[2]; + }; + + union lll w,uu; + + uu.ll = u; + + w.s[1] = -uu.s[1]; + w.s[0] = -uu.s[0] - ((int) w.s[1] != 0); + + return w.ll; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/qrnnd.S linux.ac/arch/s390/math-emu/qrnnd.S --- linux.vanilla/arch/s390/math-emu/qrnnd.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/qrnnd.S Thu Apr 12 11:59:46 2001 @@ -0,0 +1,77 @@ +# S/390 __udiv_qrnnd + +# r2 : &__r +# r3 : upper half of 64 bit word n +# r4 : lower half of 64 bit word n +# r5 : divisor d +# the reminder r of the division is to be stored to &__r and +# the quotient q is to be returned + + .text + .globl __udiv_qrnnd +__udiv_qrnnd: + st %r2,24(%r15) # store pointer to reminder for later + lr %r0,%r3 # reload n + lr %r1,%r4 + ltr %r2,%r5 # reload and test divisor + jp 5f + # divisor >= 0x80000000 + srdl %r0,2 # n/4 + srl %r2,1 # d/2 + slr %r1,%r2 # special case if last bit of d is set + brc 3,0f # (n/4) div (n/2) can overflow by 1 + ahi %r0,-1 # trick: subtract n/2, then divide +0: dr %r0,%r2 # signed division + ahi %r1,1 # trick part 2: add 1 to the quotient + # now (n >> 2) = (d >> 1) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r1 # test last bit of q + jz 1f + alr %r0,%r2 # add (d>>1) to r +1: srl %r1,1 # q >>= 1 + # now (n >> 2) = (d&-2) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r5 # test last bit of d + jz 2f + slr %r0,%r1 # r -= q + brc 3,2f # borrow ? + alr %r0,%r5 # r += d + ahi %r1,-1 +2: # now (n >> 2) = d * %r1 + %r0 + alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,3f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +3: lhi %r3,2 + nr %r3,%r4 # test next to last bit of n + jz 4f + ahi %r0,1 # r += 1 +4: clr %r0,%r5 # r >= d ? + jl 6f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 + # now (n >> 1) = d * %r1 + %r0 + j 6f +5: # divisor < 0x80000000 + srdl %r0,1 + dr %r0,%r2 # signed division + # now (n >> 1) = d * %r1 + %r0 +6: alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,7f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +7: lhi %r3,1 + nr %r3,%r4 # isolate last bit of n + alr %r0,%r3 # r += (n & 1) + clr %r0,%r5 # r >= d ? + jl 8f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +8: # now n = d * %r1 + %r0 + l %r2,24(%r15) + st %r0,0(%r2) + lr %r2,%r1 + br %r14 + .end __udiv_qrnnd diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/math-emu/sfp-util.h linux.ac/arch/s390/math-emu/sfp-util.h --- linux.vanilla/arch/s390/math-emu/sfp-util.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/s390/math-emu/sfp-util.h Thu Apr 12 11:59:46 2001 @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + __asm__ (" alr %1,%3\n" \ + " brc 12,0f\n" \ + " ahi %0,1\n" \ + "0: alr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc" ); \ + (sh) = __sh; \ + (sl) = __sl; \ +}) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + __asm__ (" slr %1,%3\n" \ + " brc 3,0f\n" \ + " ahi %0,-1\n" \ + "0: slr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc" ); \ + (sh) = __sh; \ + (sl) = __sl; \ +}) + +/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */ +#define umul_ppmm(wh, wl, u, v) ({ \ + unsigned int __wh = u; \ + unsigned int __wl = v; \ + __asm__ (" ltr 1,%0\n" \ + " mr 0,%1\n" \ + " jnm 0f\n" \ + " alr 0,%1\n" \ + "0: ltr %1,%1\n" \ + " jnm 1f\n" \ + " alr 0,%0\n" \ + "1: lr %0,0\n" \ + " lr %1,1\n" \ + : "+d" (__wh), "+d" (__wl) \ + : : "0", "1", "cc" ); \ + wh = __wh; \ + wl = __wl; \ +}) + +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { unsigned long __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long, + unsigned long , unsigned long); + +#define UDIV_NEEDS_NORMALIZATION 0 + +#define abort() return 0 + +#define __BYTE_ORDER __BIG_ENDIAN diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/mm/fault.c linux.ac/arch/s390/mm/fault.c --- linux.vanilla/arch/s390/mm/fault.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390/mm/fault.c Thu Apr 12 11:59:46 2001 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -263,3 +264,123 @@ } +typedef struct _pseudo_wait_t { + struct _pseudo_wait_t *next; + wait_queue_head_t queue; + unsigned long address; + int resolved; +} pseudo_wait_t; + +static pseudo_wait_t *pseudo_lock_queue = NULL; +static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */ + +/* + * This routine handles pseudo page faults. + */ +asmlinkage void +do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) +{ + DECLARE_WAITQUEUE(wait, current); + pseudo_wait_t wait_struct; + pseudo_wait_t *ptr, *last, *next; + unsigned long psw_mask; + unsigned long address; + int kernel_address; + + /* + * get psw mask of Program old psw to find out, + * if user or kernel mode + */ + psw_mask = S390_lowcore.program_old_psw.mask; + + /* + * get the failing address + * more specific the segment and page table portion of + * the address + */ + address = S390_lowcore.trans_exc_code & 0xfffff000; + + if (address & 0x80000000) { + /* high bit set -> a page has been swapped in by VM */ + address &= 0x7fffffff; + spin_lock(&pseudo_wait_spinlock); + last = NULL; + ptr = pseudo_lock_queue; + while (ptr != NULL) { + next = ptr->next; + if (address == ptr->address) { + /* + * This is one of the processes waiting + * for the page. Unchain from the queue. + * There can be more than one process + * waiting for the same page. VM presents + * an initial and a completion interrupt for + * every process that tries to access a + * page swapped out by VM. + */ + if (last == NULL) + pseudo_lock_queue = next; + else + last->next = next; + /* now wake up the process */ + ptr->resolved = 1; + wake_up(&ptr->queue); + } else + last = ptr; + ptr = next; + } + spin_unlock(&pseudo_wait_spinlock); + } else { + /* Pseudo page faults in kernel mode is a bad idea */ + if (!(psw_mask & PSW_PROBLEM_STATE)) { + /* + * VM presents pseudo page faults if the interrupted + * state was not disabled for interrupts. So we can + * get pseudo page fault interrupts while running + * in kernel mode. We simply access the page here + * while we are running disabled. VM will then swap + * in the page synchronously. + */ + kernel_address = 0; + switch (S390_lowcore.trans_exc_code & 3) { + case 0: /* Primary Segment Table Descriptor */ + kernel_address = 1; + break; + case 1: /* STD determined via access register */ + if (S390_lowcore.exc_access_id == 0 || + regs->acrs[S390_lowcore.exc_access_id]==0) + kernel_address = 1; + break; + case 2: /* Secondary Segment Table Descriptor */ + case 3: /* Home Segment Table Descriptor */ + break; + } + if (kernel_address) + /* dereference a virtual kernel address */ + __asm__ __volatile__ ( + " ic 0,0(%0)" + : : "a" (address) : "0"); + else + /* dereference a virtual user address */ + __asm__ __volatile__ ( + " la 2,0(%0)\n" + " sacf 512\n" + " ic 2,0(2)\n" + " sacf 0" + : : "a" (address) : "2" ); + + return; + } + /* initialize and add element to pseudo_lock_queue */ + init_waitqueue_head (&wait_struct.queue); + wait_struct.address = address; + wait_struct.resolved = 0; + spin_lock(&pseudo_wait_spinlock); + wait_struct.next = pseudo_lock_queue; + pseudo_lock_queue = &wait_struct; + spin_unlock(&pseudo_wait_spinlock); + /* go to sleep */ + wait_event(wait_struct.queue, wait_struct.resolved); + } +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/mm/init.c linux.ac/arch/s390/mm/init.c --- linux.vanilla/arch/s390/mm/init.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/mm/init.c Thu Apr 12 12:00:34 2001 @@ -35,27 +35,14 @@ #include #include #include +#include -static unsigned long totalram_pages; +mmu_gather_t mmu_gathers[NR_CPUS]; -/* - * 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. - */ +static unsigned long totalram_pages; pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); -char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); -pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE))); static int test_access(unsigned long loc) { @@ -84,53 +71,6 @@ return rc; } -static pte_t * get_bad_pte_table(void) -{ - pte_t v; - int i; - - v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -static inline void invalidate_page(pte_t *pte) -{ - int i; - for (i=0;i low); } return freed; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/mm/ioremap.c linux.ac/arch/s390/mm/ioremap.c --- linux.vanilla/arch/s390/mm/ioremap.c Tue Feb 13 22:13:44 2001 +++ linux.ac/arch/s390/mm/ioremap.c Thu Apr 12 12:00:34 2001 @@ -54,7 +54,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -67,6 +67,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; @@ -75,17 +76,21 @@ flush_cache_all(); if (address >= end) BUG(); + spin_lock(&init_mm.page_table_lock); do { - pmd_t *pmd = pmd_alloc_kernel(dir, address); + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) - return -ENOMEM; - set_pgdir(address, *dir); + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/tools/dasdfmt/dasdfmt.c linux.ac/arch/s390/tools/dasdfmt/dasdfmt.c --- linux.vanilla/arch/s390/tools/dasdfmt/dasdfmt.c Tue Apr 3 17:31:56 2001 +++ linux.ac/arch/s390/tools/dasdfmt/dasdfmt.c Thu Apr 12 12:00:34 2001 @@ -7,6 +7,7 @@ * Author(s): Utz Bacher, * * Device-in-use-checks by Fritz Elfert, + * Compatible Disk Layout enhancements by Carsten Otte, * * Still to do: * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them @@ -157,14 +158,15 @@ exit_usage(int exitcode) { #ifdef RANGE_FORMATTING - printf("Usage: %s [-htvyLV] [-l