diff -u --recursive --new-file v2.4.3/linux/CREDITS linux/CREDITS --- v2.4.3/linux/CREDITS Sun Mar 25 18:14:20 2001 +++ linux/CREDITS Fri Apr 20 16:23:12 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 @@ -766,6 +766,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 +1121,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 +1225,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 +1483,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 +1730,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 +1880,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 +2365,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 +2409,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 +2435,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 +2522,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 +2710,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 --recursive --new-file v2.4.3/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.3/linux/Documentation/Changes Tue Mar 6 19:44:34 2001 +++ linux/Documentation/Changes Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.3/linux/Documentation/Configure.help Sun Mar 25 18:24:31 2001 +++ linux/Documentation/Configure.help Fri Apr 20 16:23:12 2001 @@ -13,8 +13,10 @@ # 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 @@ -268,6 +270,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 @@ -415,7 +422,7 @@ 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/ . + http://www.ibiblio.org/pub/Linux/system/hardware . 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), @@ -711,7 +718,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. @@ -1299,14 +1306,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 @@ -1587,6 +1617,27 @@ 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 @@ -1616,12 +1667,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 +1681,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 @@ -1726,6 +1783,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 @@ -2110,7 +2171,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 @@ -2386,7 +2446,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 +2493,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 @@ -2821,14 +2867,6 @@ 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 If you say Y here, a user level program will be able to instruct the @@ -2994,14 +3032,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". @@ -3509,7 +3549,7 @@ 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 @@ -4301,7 +4341,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,11 +4354,10 @@ 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. + http://www.zettabyte.net/netatalk/ 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 @@ -4329,8 +4368,10 @@ 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 @@ -4831,7 +4872,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: @@ -4916,7 +4957,7 @@ 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 interpret this data. Information sent to the kernel over this link @@ -5084,6 +5125,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 @@ -7068,6 +7118,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 @@ -8078,6 +8139,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 http://www.cogenit.fr/dscc4 + 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. @@ -8164,13 +8237,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. (http://www.sangoma.com) + 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 +8265,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 @@ -8288,7 +8388,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 @@ -8351,6 +8451,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 + http://hq.pm.waw.pl/hdlc/. + 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 http://hq.pm.waw.pl/pub/hdlc/ + + 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 http://hq.pm.waw.pl/pub/hdlc/ + + 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 @@ -10055,62 +10198,100 @@ 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. (http://www.ramix.com/products/memory/pmc551.html). + 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 (http://www.amd.com/products/nvd/overview/cfi.html) + for more information on CFI. CFI support for Intel/Sharp Extended Command Set chips CONFIG_MTD_CFI_INTELEXT @@ -10122,10 +10303,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 +10324,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 + (http://www.itc.hu/). 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 + (http://www.octagonsystems.com/Products/5066/5066.html). 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 + (http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm). 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 + (http://www.tempustech.com/tt301.htm). Direct chardevice access to MTD devices CONFIG_MTD_CHAR @@ -10195,15 +10389,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 +10408,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 +10418,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 @@ -10399,6 +10593,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 @@ -10826,16 +11030,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 @@ -11072,23 +11276,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 @@ -11634,21 +11859,16 @@ 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. - - Any potential patches or queries should be sent to Axis' mailing - list for 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 (http://developer.axis.com/software/jffs/). + +JFFS debugging verbosity +CONFIG_JFFS_FS_VERBOSE + Determines the verbosity level of the JFFS debugging messages. UFS file system support (read-only) CONFIG_UFS_FS @@ -11723,6 +11943,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 +11975,12 @@ 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. + ADFS file system support (EXPERIMENTAL) CONFIG_ADFS_FS The Acorn Disc Filing System is the standard file system of the @@ -11998,7 +12230,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, @@ -12187,7 +12419,7 @@ 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 +12431,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 +12442,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 +12452,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 @@ -12736,8 +12968,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 @@ -13742,17 +13974,32 @@ 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: + Toshiba Linux utilities web site at: http://www.buzzard.org.uk/toshiba/ + 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 If you say Y here and also to "/dev file system support" in the @@ -13787,6 +14034,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 @@ -14253,6 +14512,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 +14720,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. @@ -14647,7 +14910,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 +14924,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 @@ -15289,10 +15557,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 @@ -16523,6 +16791,68 @@ 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. + SAB3036 tuner support CONFIG_TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. @@ -16559,7 +16889,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. @@ -16645,50 +16975,14 @@ http://www.visuaide.com/pagevictor.en.html 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 +16996,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 +17032,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 +17145,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,8 +17230,7 @@ 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 . @@ -16912,6 +17238,10 @@ want to compile it as a module, say M here and read Documentation/modules.txt. +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 +17306,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 @@ -17350,7 +17691,7 @@ # LocalWords: howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip # LocalWords: proc acct IPIP encapsulator decapsulator klogd PCTCP 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 +17719,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 +17736,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 +17863,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 --recursive --new-file v2.4.3/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt --- v2.4.3/linux/Documentation/DMA-mapping.txt Tue Mar 6 22:44:15 2001 +++ linux/Documentation/DMA-mapping.txt Thu Apr 19 08:38:48 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 --recursive --new-file v2.4.3/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.3/linux/Documentation/DocBook/Makefile Sat Feb 3 12:43:55 2001 +++ linux/Documentation/DocBook/Makefile Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/Documentation/DocBook/deviceiobook.tmpl linux/Documentation/DocBook/deviceiobook.tmpl --- v2.4.3/linux/Documentation/DocBook/deviceiobook.tmpl Wed Dec 31 16:00:00 1969 +++ linux/Documentation/DocBook/deviceiobook.tmpl Fri Apr 6 10:42:55 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_writelisa_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 --recursive --new-file v2.4.3/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.4.3/linux/Documentation/DocBook/kernel-api.tmpl Fri Mar 2 18:43:10 2001 +++ linux/Documentation/DocBook/kernel-api.tmpl Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl --- v2.4.3/linux/Documentation/DocBook/kernel-hacking.tmpl Thu Feb 8 16:32:44 2001 +++ linux/Documentation/DocBook/kernel-hacking.tmpl Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl --- v2.4.3/linux/Documentation/DocBook/kernel-locking.tmpl Fri Feb 16 15:53:08 2001 +++ linux/Documentation/DocBook/kernel-locking.tmpl Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/Documentation/DocBook/parportbook.tmpl linux/Documentation/DocBook/parportbook.tmpl --- v2.4.3/linux/Documentation/DocBook/parportbook.tmpl Wed Jul 12 16:24:33 2000 +++ linux/Documentation/DocBook/parportbook.tmpl Thu Apr 12 12:05:50 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 --recursive --new-file v2.4.3/linux/Documentation/DocBook/tulip-user.tmpl linux/Documentation/DocBook/tulip-user.tmpl --- v2.4.3/linux/Documentation/DocBook/tulip-user.tmpl Wed Dec 31 16:00:00 1969 +++ linux/Documentation/DocBook/tulip-user.tmpl Wed Apr 18 14:40:06 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 --recursive --new-file v2.4.3/linux/Documentation/SubmittingDrivers linux/Documentation/SubmittingDrivers --- v2.4.3/linux/Documentation/SubmittingDrivers Thu Feb 8 16:32:44 2001 +++ linux/Documentation/SubmittingDrivers Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/Documentation/arm/README linux/Documentation/arm/README --- v2.4.3/linux/Documentation/arm/README Mon Nov 27 17:07:59 2000 +++ linux/Documentation/arm/README Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/cris/README linux/Documentation/cris/README --- v2.4.3/linux/Documentation/cris/README Thu Feb 8 16:32:44 2001 +++ linux/Documentation/cris/README Fri Apr 6 10:42:55 2001 @@ -1,20 +1,22 @@ Linux 2.4 on the CRIS architecture ================================== -$Id: README,v 1.5 2001/01/10 17:20:55 bjornw Exp $ +$Id: README,v 1.6 2001/02/21 15:27:25 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 ...> + 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 +25,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 +46,41 @@ * two parallel-ports * two generic 8-bit ports - (not all interfaces are available at the same time due to chip pin multiplexing) + (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. - -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 +90,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.6 $, (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.6 $ 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 +147,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 --recursive --new-file v2.4.3/linux/Documentation/dnotify.txt linux/Documentation/dnotify.txt --- v2.4.3/linux/Documentation/dnotify.txt Fri Mar 2 18:38:37 2001 +++ linux/Documentation/dnotify.txt Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog --- v2.4.3/linux/Documentation/filesystems/devfs/ChangeLog Wed Jul 5 21:36:49 2000 +++ linux/Documentation/filesystems/devfs/ChangeLog Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/Documentation/filesystems/ext2.txt linux/Documentation/filesystems/ext2.txt --- v2.4.3/linux/Documentation/filesystems/ext2.txt Sun Oct 1 20:21:20 2000 +++ linux/Documentation/filesystems/ext2.txt Fri Apr 20 16:18:35 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 --recursive --new-file v2.4.3/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt --- v2.4.3/linux/Documentation/filesystems/proc.txt Mon Nov 27 17:47:38 2000 +++ linux/Documentation/filesystems/proc.txt Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/Documentation/filesystems/vfat.txt linux/Documentation/filesystems/vfat.txt --- v2.4.3/linux/Documentation/filesystems/vfat.txt Tue Dec 21 14:28:39 1999 +++ linux/Documentation/filesystems/vfat.txt Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/i386/boot.txt linux/Documentation/i386/boot.txt --- v2.4.3/linux/Documentation/i386/boot.txt Thu Jul 27 16:52:08 2000 +++ linux/Documentation/i386/boot.txt Wed Apr 11 18:50:25 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 --recursive --new-file v2.4.3/linux/Documentation/i810_rng.txt linux/Documentation/i810_rng.txt --- v2.4.3/linux/Documentation/i810_rng.txt Sun Mar 25 18:24:31 2001 +++ linux/Documentation/i810_rng.txt Thu Apr 19 09:34:05 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 --recursive --new-file v2.4.3/linux/Documentation/isapnp.txt linux/Documentation/isapnp.txt --- v2.4.3/linux/Documentation/isapnp.txt Mon Oct 9 17:53:05 2000 +++ linux/Documentation/isapnp.txt Wed Apr 18 11:49:11 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 --recursive --new-file v2.4.3/linux/Documentation/joystick-api.txt linux/Documentation/joystick-api.txt --- v2.4.3/linux/Documentation/joystick-api.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/joystick-api.txt Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/Documentation/kernel-docs.txt linux/Documentation/kernel-docs.txt --- v2.4.3/linux/Documentation/kernel-docs.txt Wed Aug 23 09:33:09 2000 +++ linux/Documentation/kernel-docs.txt Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt --- v2.4.3/linux/Documentation/kernel-parameters.txt Fri Mar 2 11:02:15 2001 +++ linux/Documentation/kernel-parameters.txt Wed Apr 18 11:49:11 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 --recursive --new-file v2.4.3/linux/Documentation/mips/GT64120.README linux/Documentation/mips/GT64120.README --- v2.4.3/linux/Documentation/mips/GT64120.README Wed Dec 31 16:00:00 1969 +++ linux/Documentation/mips/GT64120.README Fri Apr 20 16:23:12 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 --recursive --new-file v2.4.3/linux/Documentation/mips/time.README linux/Documentation/mips/time.README --- v2.4.3/linux/Documentation/mips/time.README Wed Dec 31 16:00:00 1969 +++ linux/Documentation/mips/time.README Fri Apr 20 16:23:12 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 --recursive --new-file v2.4.3/linux/Documentation/mtrr.txt linux/Documentation/mtrr.txt --- v2.4.3/linux/Documentation/mtrr.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/mtrr.txt Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.3/linux/Documentation/networking/8139too.txt Sun Mar 25 18:24:31 2001 +++ linux/Documentation/networking/8139too.txt Thu Apr 19 09:32:48 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 --recursive --new-file v2.4.3/linux/Documentation/networking/TODO linux/Documentation/networking/TODO --- v2.4.3/linux/Documentation/networking/TODO Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/TODO Thu Apr 19 13:43:40 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 --recursive --new-file v2.4.3/linux/Documentation/networking/comx.txt linux/Documentation/networking/comx.txt --- v2.4.3/linux/Documentation/networking/comx.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/networking/comx.txt Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/Documentation/networking/olympic.txt linux/Documentation/networking/olympic.txt --- v2.4.3/linux/Documentation/networking/olympic.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/networking/olympic.txt Wed Apr 18 11:39:21 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 --recursive --new-file v2.4.3/linux/Documentation/networking/tuntap.txt linux/Documentation/networking/tuntap.txt --- v2.4.3/linux/Documentation/networking/tuntap.txt Fri Sep 22 15:19:30 2000 +++ linux/Documentation/networking/tuntap.txt Wed Apr 25 14:59:56 2001 @@ -37,7 +37,7 @@ alias char-major-10-200 tun Run: - modprobe -a + depmod -a Driver will be automatically loaded when application access /dev/net/tun. diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt --- v2.4.3/linux/Documentation/networking/wan-router.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/networking/wan-router.txt Thu Apr 12 12:11:39 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 --recursive --new-file v2.4.3/linux/Documentation/networking/wanpipe.txt linux/Documentation/networking/wanpipe.txt --- v2.4.3/linux/Documentation/networking/wanpipe.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/networking/wanpipe.txt Thu Apr 12 12:11:39 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 --recursive --new-file v2.4.3/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.4.3/linux/Documentation/parport.txt Mon Mar 26 15:41:19 2001 +++ linux/Documentation/parport.txt Fri Apr 6 10:42:51 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 --recursive --new-file v2.4.3/linux/Documentation/pm.txt linux/Documentation/pm.txt --- v2.4.3/linux/Documentation/pm.txt Thu Oct 26 14:22:24 2000 +++ linux/Documentation/pm.txt Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/Documentation/s390/3270.ChangeLog linux/Documentation/s390/3270.ChangeLog --- v2.4.3/linux/Documentation/s390/3270.ChangeLog Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/3270.ChangeLog Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/Documentation/s390/3270.txt linux/Documentation/s390/3270.txt --- v2.4.3/linux/Documentation/s390/3270.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/3270.txt Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/Documentation/s390/Debugging390.txt linux/Documentation/s390/Debugging390.txt --- v2.4.3/linux/Documentation/s390/Debugging390.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/Debugging390.txt Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8 --- v2.4.3/linux/Documentation/s390/chandev.8 Fri Feb 16 15:53:08 2001 +++ linux/Documentation/s390/chandev.8 Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/s390/config3270.sh linux/Documentation/s390/config3270.sh --- v2.4.3/linux/Documentation/s390/config3270.sh Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/config3270.sh Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/s390/s390dbf.txt linux/Documentation/s390/s390dbf.txt --- v2.4.3/linux/Documentation/s390/s390dbf.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/s390dbf.txt Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt --- v2.4.3/linux/Documentation/scsi-generic.txt Thu Feb 8 16:32:44 2001 +++ linux/Documentation/scsi-generic.txt Thu Apr 12 12:03:50 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 @@ -236,10 +241,11 @@ /dev/sg[a-z] /dev/sg[0,1,2,...] 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 --recursive --new-file v2.4.3/linux/Documentation/sound/PAS16 linux/Documentation/sound/PAS16 --- v2.4.3/linux/Documentation/sound/PAS16 Sun Apr 2 15:38:53 2000 +++ linux/Documentation/sound/PAS16 Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/sound/PCM1-pro linux/Documentation/sound/PCM1-pro --- v2.4.3/linux/Documentation/sound/PCM1-pro Mon Apr 12 16:18:27 1999 +++ linux/Documentation/sound/PCM1-pro Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/Documentation/sound/README.OSS linux/Documentation/sound/README.OSS --- v2.4.3/linux/Documentation/sound/README.OSS Fri Jul 28 12:50:52 2000 +++ linux/Documentation/sound/README.OSS Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/sound/es1370 linux/Documentation/sound/es1370 --- v2.4.3/linux/Documentation/sound/es1370 Fri Jul 10 14:03:35 1998 +++ linux/Documentation/sound/es1370 Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/sound/es1371 linux/Documentation/sound/es1371 --- v2.4.3/linux/Documentation/sound/es1371 Fri Jul 10 14:03:35 1998 +++ linux/Documentation/sound/es1371 Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/sound/solo1 linux/Documentation/sound/solo1 --- v2.4.3/linux/Documentation/sound/solo1 Mon Aug 23 11:15:27 1999 +++ linux/Documentation/sound/solo1 Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/Documentation/sound/sonicvibes linux/Documentation/sound/sonicvibes --- v2.4.3/linux/Documentation/sound/sonicvibes Fri Jul 10 14:03:35 1998 +++ linux/Documentation/sound/sonicvibes Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.3/linux/MAINTAINERS Sun Mar 25 18:14:20 2001 +++ linux/MAINTAINERS Wed Apr 25 14:35:25 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 @@ -133,6 +140,11 @@ M: fizban@tin.it S: Maintained +AFFS FILE SYSTEM +P: Roman Zippel +M: zippel@linux-m68k.org +S: Maintained + AHA152X SCSI DRIVER P: Juergen E. Fischer M: Juergen Fischer @@ -141,9 +153,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 @@ -293,6 +305,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 +387,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 +417,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 +515,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 @@ -535,7 +566,7 @@ HIPPI P: Jes Sorensen -M: Jes.Sorensen@cern.ch +M: jes@linuxcare.com L: linux-hippi@sunsite.auc.dk S: Maintained @@ -600,7 +631,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 @@ -750,14 +788,14 @@ 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 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 +813,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 +825,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 +881,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 +952,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 +966,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 +1046,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 +1086,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 +1112,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 +1238,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 ? @@ -1357,11 +1426,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 @@ -1430,8 +1499,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 +1526,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 --recursive --new-file v2.4.3/linux/Makefile linux/Makefile --- v2.4.3/linux/Makefile Thu Mar 29 20:13:15 2001 +++ linux/Makefile Fri Apr 27 18:17:19 2001 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 3 +SUBLEVEL = 4 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -u --recursive --new-file v2.4.3/linux/REPORTING-BUGS linux/REPORTING-BUGS --- v2.4.3/linux/REPORTING-BUGS Mon Aug 21 08:57:35 2000 +++ linux/REPORTING-BUGS Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.4.3/linux/arch/alpha/mm/init.c Tue Nov 28 22:43:39 2000 +++ linux/arch/alpha/mm/init.c Fri Apr 13 20:26:06 2001 @@ -43,20 +43,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 +66,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 --recursive --new-file v2.4.3/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.4.3/linux/arch/arm/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile --- v2.4.3/linux/arch/arm/boot/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/boot/Makefile Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.4.3/linux/arch/arm/boot/compressed/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/boot/compressed/Makefile Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/head-clps7500.S linux/arch/arm/boot/compressed/head-clps7500.S --- v2.4.3/linux/arch/arm/boot/compressed/head-clps7500.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/head-clps7500.S Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/head-shark.S linux/arch/arm/boot/compressed/head-shark.S --- v2.4.3/linux/arch/arm/boot/compressed/head-shark.S Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/boot/compressed/head-shark.S Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.4.3/linux/arch/arm/boot/compressed/head.S Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/boot/compressed/head.S Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/ll_char_wr.S linux/arch/arm/boot/compressed/ll_char_wr.S --- v2.4.3/linux/arch/arm/boot/compressed/ll_char_wr.S Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/boot/compressed/ll_char_wr.S Thu Apr 12 12:03:50 2001 @@ -16,7 +16,7 @@ @ Regs: [] = corruptible @ {} = used @ () = do not use -#define __ASSEMBLY__ + #include #include .text diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/ofw-shark.c linux/arch/arm/boot/compressed/ofw-shark.c --- v2.4.3/linux/arch/arm/boot/compressed/ofw-shark.c Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/boot/compressed/ofw-shark.c Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S --- v2.4.3/linux/arch/arm/boot/compressed/setup-sa1100.S Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/boot/compressed/setup-sa1100.S Thu Apr 12 12:03:50 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 --recursive --new-file v2.4.3/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.4.3/linux/arch/arm/config.in Fri Feb 9 11:38:27 2001 +++ linux/arch/arm/config.in Tue Apr 17 17:19:24 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.4.3/linux/arch/arm/kernel/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/kernel/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c --- v2.4.3/linux/arch/arm/kernel/arch.c Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/arch.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.4.3/linux/arch/arm/kernel/armksyms.c Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/armksyms.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/arthur.c linux/arch/arm/kernel/arthur.c --- v2.4.3/linux/arch/arm/kernel/arthur.c Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/arthur.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.4.3/linux/arch/arm/kernel/bios32.c Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/kernel/bios32.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S --- v2.4.3/linux/arch/arm/kernel/debug-armv.S Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/debug-armv.S Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.4.3/linux/arch/arm/kernel/ecard.c Fri Feb 9 11:29:44 2001 +++ linux/arch/arm/kernel/ecard.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.4.3/linux/arch/arm/kernel/entry-armv.S Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/kernel/entry-armv.S Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.4.3/linux/arch/arm/kernel/entry-common.S Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/kernel/entry-common.S Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c --- v2.4.3/linux/arch/arm/kernel/fiq.c Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/kernel/fiq.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S --- v2.4.3/linux/arch/arm/kernel/head-armo.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/head-armo.S Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.4.3/linux/arch/arm/kernel/head-armv.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/head-armv.S Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/io.c linux/arch/arm/kernel/io.c --- v2.4.3/linux/arch/arm/kernel/io.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/io.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/irq-arch.c linux/arch/arm/kernel/irq-arch.c --- v2.4.3/linux/arch/arm/kernel/irq-arch.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/irq-arch.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.4.3/linux/arch/arm/kernel/irq.c Fri Feb 9 11:29:44 2001 +++ linux/arch/arm/kernel/irq.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/leds-ebsa110.c linux/arch/arm/kernel/leds-ebsa110.c --- v2.4.3/linux/arch/arm/kernel/leds-ebsa110.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/leds-ebsa110.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/oldlatches.c linux/arch/arm/kernel/oldlatches.c --- v2.4.3/linux/arch/arm/kernel/oldlatches.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/oldlatches.c Thu Apr 12 12:20:31 2001 @@ -59,7 +59,7 @@ } } -initcall(oldlatch_init); +__initcall(oldlatch_init); EXPORT_SYMBOL(oldlatch_aupdate); EXPORT_SYMBOL(oldlatch_bupdate); diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c --- v2.4.3/linux/arch/arm/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/arm/kernel/semaphore.c Fri Apr 27 14:11:59 2001 @@ -166,127 +166,6 @@ 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 @@ -333,61 +212,6 @@ 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 "); @@ -426,57 +250,6 @@ 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 diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.4.3/linux/arch/arm/kernel/setup.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/setup.c Fri Apr 27 14:10:31 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' } }; @@ -228,7 +241,7 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) { #ifdef CONFIG_BLK_DEV_RAM - extern int rd_doload, rd_prompt, rd_image_start, rd_size; + extern int rd_size; rd_image_start = image_start; rd_prompt = prompt; @@ -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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/time-acorn.c linux/arch/arm/kernel/time-acorn.c --- v2.4.3/linux/arch/arm/kernel/time-acorn.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/time-acorn.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/kernel/via82c505.c linux/arch/arm/kernel/via82c505.c --- v2.4.3/linux/arch/arm/kernel/via82c505.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/via82c505.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.4.3/linux/arch/arm/lib/Makefile Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/lib/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/lib/backtrace.S linux/arch/arm/lib/backtrace.S --- v2.4.3/linux/arch/arm/lib/backtrace.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/backtrace.S Thu Apr 12 12:20:31 2001 @@ -26,7 +26,7 @@ ENTRY(c_backtrace) -#ifndef CONFIG_FRAME_POINTER +#ifdef CONFIG_NO_FRAME_POINTER mov pc, lr #else diff -u --recursive --new-file v2.4.3/linux/arch/arm/lib/delay.S linux/arch/arm/lib/delay.S --- v2.4.3/linux/arch/arm/lib/delay.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/delay.S Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/lib/io-shark.c linux/arch/arm/lib/io-shark.c --- v2.4.3/linux/arch/arm/lib/io-shark.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/io-shark.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/lib/io.c linux/arch/arm/lib/io.c --- v2.4.3/linux/arch/arm/lib/io.c Sun Feb 6 17:45:25 2000 +++ linux/arch/arm/lib/io.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/Makefile linux/arch/arm/mach-ebsa110/Makefile --- v2.4.3/linux/arch/arm/mach-ebsa110/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-ebsa110/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/arch.c linux/arch/arm/mach-ebsa110/arch.c --- v2.4.3/linux/arch/arm/mach-ebsa110/arch.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-ebsa110/arch.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/io.c linux/arch/arm/mach-ebsa110/io.c --- v2.4.3/linux/arch/arm/mach-ebsa110/io.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-ebsa110/io.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/irq.c linux/arch/arm/mach-ebsa110/irq.c --- v2.4.3/linux/arch/arm/mach-ebsa110/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-ebsa110/irq.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/leds.c linux/arch/arm/mach-ebsa110/leds.c --- v2.4.3/linux/arch/arm/mach-ebsa110/leds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-ebsa110/leds.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/mm.c linux/arch/arm/mach-ebsa110/mm.c --- v2.4.3/linux/arch/arm/mach-ebsa110/mm.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-ebsa110/mm.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/time.c linux/arch/arm/mach-ebsa110/time.c --- v2.4.3/linux/arch/arm/mach-ebsa110/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-ebsa110/time.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/Makefile linux/arch/arm/mach-footbridge/Makefile --- v2.4.3/linux/arch/arm/mach-footbridge/Makefile Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-footbridge/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/arch.c linux/arch/arm/mach-footbridge/arch.c --- v2.4.3/linux/arch/arm/mach-footbridge/arch.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-footbridge/arch.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/irq.c linux/arch/arm/mach-footbridge/irq.c --- v2.4.3/linux/arch/arm/mach-footbridge/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/irq.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/mm.c linux/arch/arm/mach-footbridge/mm.c --- v2.4.3/linux/arch/arm/mach-footbridge/mm.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-footbridge/mm.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/Makefile linux/arch/arm/mach-sa1100/Makefile --- v2.4.3/linux/arch/arm/mach-sa1100/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/mach-sa1100/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/arch.c linux/arch/arm/mach-sa1100/arch.c --- v2.4.3/linux/arch/arm/mach-sa1100/arch.c Fri Mar 2 11:12:06 2001 +++ linux/arch/arm/mach-sa1100/arch.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1100.c linux/arch/arm/mach-sa1100/dma-sa1100.c --- v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1100.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-sa1100/dma-sa1100.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1111.c linux/arch/arm/mach-sa1100/dma-sa1111.c --- v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1111.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-sa1100/dma-sa1111.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/dma.h linux/arch/arm/mach-sa1100/dma.h --- v2.4.3/linux/arch/arm/mach-sa1100/dma.h Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-sa1100/dma.h Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/Makefile linux/arch/arm/mach-shark/Makefile --- v2.4.3/linux/arch/arm/mach-shark/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/mach-shark/Makefile Thu Apr 12 12:20:31 2001 @@ -18,6 +18,6 @@ export-objs := -#obj-$(CONFIG_LEDS) += leds.o +obj-$(CONFIG_LEDS) += leds.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/arch.c linux/arch/arm/mach-shark/arch.c --- v2.4.3/linux/arch/arm/mach-shark/arch.c Tue Sep 19 08:31:53 2000 +++ linux/arch/arm/mach-shark/arch.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/dma.c linux/arch/arm/mach-shark/dma.c --- v2.4.3/linux/arch/arm/mach-shark/dma.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-shark/dma.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/leds.c linux/arch/arm/mach-shark/leds.c --- v2.4.3/linux/arch/arm/mach-shark/leds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-shark/leds.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/mm.c linux/arch/arm/mach-shark/mm.c --- v2.4.3/linux/arch/arm/mach-shark/mm.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-shark/mm.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.4.3/linux/arch/arm/mm/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/mm/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c --- v2.4.3/linux/arch/arm/mm/consistent.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/consistent.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.4.3/linux/arch/arm/mm/fault-armv.c Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/mm/fault-armv.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.4.3/linux/arch/arm/mm/fault-common.c Mon Mar 19 12:35:10 2001 +++ linux/arch/arm/mm/fault-common.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.4.3/linux/arch/arm/mm/init.c Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/mm/init.c Thu Apr 12 12:20:31 2001 @@ -59,52 +59,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 +78,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 +472,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 +541,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 --recursive --new-file v2.4.3/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c --- v2.4.3/linux/arch/arm/mm/ioremap.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/ioremap.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-armo.c linux/arch/arm/mm/mm-armo.c --- v2.4.3/linux/arch/arm/mm/mm-armo.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/mm-armo.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.4.3/linux/arch/arm/mm/mm-armv.c Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/mm/mm-armv.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-clps7500.c linux/arch/arm/mm/mm-clps7500.c --- v2.4.3/linux/arch/arm/mm/mm-clps7500.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/mm-clps7500.c Thu Apr 12 12:20:31 2001 @@ -6,6 +6,7 @@ * * Extra MM routines for CL7500 architecture */ +#include #include #include diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c --- v2.4.3/linux/arch/arm/mm/mm-ebsa110.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/mm-ebsa110.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c --- v2.4.3/linux/arch/arm/mm/mm-footbridge.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/mm-footbridge.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-l7200.c linux/arch/arm/mm/mm-l7200.c --- v2.4.3/linux/arch/arm/mm/mm-l7200.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/mm-l7200.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c --- v2.4.3/linux/arch/arm/mm/mm-sa1100.c Fri Mar 2 11:12:06 2001 +++ linux/arch/arm/mm/mm-sa1100.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.4.3/linux/arch/arm/mm/proc-sa110.S Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/mm/proc-sa110.S Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/mm/small_page.c linux/arch/arm/mm/small_page.c --- v2.4.3/linux/arch/arm/mm/small_page.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/small_page.c Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/Makefile linux/arch/arm/nwfpe/Makefile --- v2.4.3/linux/arch/arm/nwfpe/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/nwfpe/Makefile Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/config.h linux/arch/arm/nwfpe/config.h --- v2.4.3/linux/arch/arm/nwfpe/config.h Mon Aug 30 18:15:19 1999 +++ linux/arch/arm/nwfpe/config.h Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/double_cpdo.c linux/arch/arm/nwfpe/double_cpdo.c --- v2.4.3/linux/arch/arm/nwfpe/double_cpdo.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/nwfpe/double_cpdo.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/entry.S linux/arch/arm/nwfpe/entry.S --- v2.4.3/linux/arch/arm/nwfpe/entry.S Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/nwfpe/entry.S Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/entry26.S linux/arch/arm/nwfpe/entry26.S --- v2.4.3/linux/arch/arm/nwfpe/entry26.S Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/nwfpe/entry26.S Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/extended_cpdo.c linux/arch/arm/nwfpe/extended_cpdo.c --- v2.4.3/linux/arch/arm/nwfpe/extended_cpdo.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/nwfpe/extended_cpdo.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11.c linux/arch/arm/nwfpe/fpa11.c --- v2.4.3/linux/arch/arm/nwfpe/fpa11.c Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/nwfpe/fpa11.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11.inl linux/arch/arm/nwfpe/fpa11.inl --- v2.4.3/linux/arch/arm/nwfpe/fpa11.inl Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/nwfpe/fpa11.inl Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11_cpdo.c linux/arch/arm/nwfpe/fpa11_cpdo.c --- v2.4.3/linux/arch/arm/nwfpe/fpa11_cpdo.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/nwfpe/fpa11_cpdo.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11_cprt.c linux/arch/arm/nwfpe/fpa11_cprt.c --- v2.4.3/linux/arch/arm/nwfpe/fpa11_cprt.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/nwfpe/fpa11_cprt.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c --- v2.4.3/linux/arch/arm/nwfpe/fpmodule.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/nwfpe/fpmodule.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpmodule.inl linux/arch/arm/nwfpe/fpmodule.inl --- v2.4.3/linux/arch/arm/nwfpe/fpmodule.inl Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/nwfpe/fpmodule.inl Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpopcode.c linux/arch/arm/nwfpe/fpopcode.c --- v2.4.3/linux/arch/arm/nwfpe/fpopcode.c Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/nwfpe/fpopcode.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpopcode.h linux/arch/arm/nwfpe/fpopcode.h --- v2.4.3/linux/arch/arm/nwfpe/fpopcode.h Mon Aug 30 18:15:19 1999 +++ linux/arch/arm/nwfpe/fpopcode.h Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/single_cpdo.c linux/arch/arm/nwfpe/single_cpdo.c --- v2.4.3/linux/arch/arm/nwfpe/single_cpdo.c Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/nwfpe/single_cpdo.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/tools/getconstants.c linux/arch/arm/tools/getconstants.c --- v2.4.3/linux/arch/arm/tools/getconstants.c Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/tools/getconstants.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types --- v2.4.3/linux/arch/arm/tools/mach-types Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/tools/mach-types Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/cris/Makefile linux/arch/cris/Makefile --- v2.4.3/linux/arch/cris/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/Makefile Fri Apr 6 10:42:55 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.11 2000/11/27 17:58:30 bjornw Exp $ +# $Id: Makefile,v 1.15 2001/02/16 17:50:04 larsv Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -25,7 +25,7 @@ # 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)/ \ + sed -e s/@ETRAX_DRAM_VIRTUAL_BASE@/0x$(ETRAX_DRAM_VIRTUAL_BASE)/ \ -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \ < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \ else true; \ @@ -49,7 +49,7 @@ 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 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 --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/Makefile linux/arch/cris/boot/compressed/Makefile --- v2.4.3/linux/arch/cris/boot/compressed/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/boot/compressed/Makefile Fri Apr 6 10:42:55 2001 @@ -16,11 +16,14 @@ 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) + + +vmlinuz: piggy.img decompress.bin cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz rm -f piggy.img diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/decompress.ld linux/arch/cris/boot/compressed/decompress.ld --- v2.4.3/linux/arch/cris/boot/compressed/decompress.ld Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/boot/compressed/decompress.ld Fri Apr 6 10:42:55 2001 @@ -1,3 +1,5 @@ +OUTPUT_FORMAT(elf32-us-cris) + MEMORY { dram : ORIGIN = 0x40700000, diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/head.S linux/arch/cris/boot/compressed/head.S --- v2.4.3/linux/arch/cris/boot/compressed/head.S Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/boot/compressed/head.S Fri Apr 6 10:42:55 2001 @@ -8,7 +8,6 @@ * */ -#include #define ASSEMBLER_MACROS_ONLY #include @@ -22,23 +21,24 @@ 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 +#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 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 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 DEF_R_PORT_PB_DATA, r0 + move.b r0, [R_PORT_PB_DATA] -#endif + move.b 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 @@ -83,7 +83,7 @@ ;; 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 ;; when mounting from flash @@ -91,7 +91,6 @@ add.d [_inptr], r9 ; size of compressed kernel ;; Enter the decompressed kernel - jump 0x40004000 ; kernel is linked to this address .data diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/misc.c linux/arch/cris/boot/compressed/misc.c --- v2.4.3/linux/arch/cris/boot/compressed/misc.c Tue Feb 13 14:13:43 2001 +++ linux/arch/cris/boot/compressed/misc.c Fri Apr 6 10:42:55 2001 @@ -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. */ diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/Makefile linux/arch/cris/boot/rescue/Makefile --- v2.4.3/linux/arch/cris/boot/rescue/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/rescue/Makefile Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/head.S linux/arch/cris/boot/rescue/head.S --- v2.4.3/linux/arch/cris/boot/rescue/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/rescue/head.S Fri Apr 6 10:42:55 2001 @@ -0,0 +1,323 @@ + ;; $Id: head.S,v 1.3 2001/02/14 16:57:25 larsv 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 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 0x10000 +#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_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_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_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_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 + + .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 DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] + move.b DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] + + move.b DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] + move.b 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 DEF_R_PORT_PA_DATA, r2 +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b 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 + + 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: + 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 --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/kimagerescue.S linux/arch/cris/boot/rescue/kimagerescue.S --- v2.4.3/linux/arch/cris/boot/rescue/kimagerescue.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/rescue/kimagerescue.S Fri Apr 6 10:42:55 2001 @@ -0,0 +1,143 @@ + ;; $Id: kimagerescue.S,v 1.2 2001/02/14 16:57:25 larsv 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 + ;; 4000500 and after a timeout jump to it. + +#include +#define ASSEMBLER_MACROS_ONLY +#include + +#define CODE_START 0x40000500 +#define CODE_LENGTH 784 +#define TIMEOUT_VALUE 1000 + + +#ifdef CONFIG_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_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_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_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 DEF_R_PORT_PA_DIR, r0 + move.b r0, [R_PORT_PA_DIR] + move.b DEF_R_PORT_PA_DATA, r0 + move.b r0, [R_PORT_PA_DATA] + + move.b DEF_R_PORT_PB_DIR, r0 + move.b r0, [R_PORT_PB_DIR] + move.b 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 DEF_R_PORT_PA_DATA, r2 +#endif +#ifdef CONFIG_ETRAX_PB_LEDS + move.b 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 --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/rescue.ld linux/arch/cris/boot/rescue/rescue.ld --- v2.4.3/linux/arch/cris/boot/rescue/rescue.ld Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/rescue/rescue.ld Fri Apr 6 10:42:55 2001 @@ -0,0 +1,20 @@ +MEMORY + { + flash : ORIGIN = 0x00000000, + LENGTH = 0x00100000 + } + +SECTIONS +{ + .text : + { + _stext = . ; + *(.text) + _etext = . ; + } > flash + .data : + { + *(.data) + _edata = . ; + } > flash +} diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/testrescue.S linux/arch/cris/boot/rescue/testrescue.S --- v2.4.3/linux/arch/cris/boot/rescue/testrescue.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/rescue/testrescue.S Fri Apr 6 10:42:55 2001 @@ -0,0 +1,25 @@ + ;; $Id: testrescue.S,v 1.1 2001/01/31 15:32:09 johana 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 --recursive --new-file v2.4.3/linux/arch/cris/boot/tools/build.c linux/arch/cris/boot/tools/build.c --- v2.4.3/linux/arch/cris/boot/tools/build.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/tools/build.c Fri Apr 6 10:42:55 2001 @@ -0,0 +1,288 @@ +/* + * 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 + +#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 --recursive --new-file v2.4.3/linux/arch/cris/config.in linux/arch/cris/config.in --- v2.4.3/linux/arch/cris/config.in Fri Feb 16 15:53:08 2001 +++ linux/arch/cris/config.in Tue Apr 17 17:19:24 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' @@ -36,15 +38,19 @@ 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 ETRAX_DRAM_VIRTUAL_BASE 60000000 +else + define_hex 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 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2 @@ -69,12 +75,29 @@ "Serial-0 CONFIG_DEBUG_PORT0 \ Serial-1 CONFIG_DEBUG_PORT1 \ Serial-2 CONFIG_DEBUG_PORT2 \ - Serial-3 CONFIG_DEBUG_PORT3" Serial-0 + Serial-3 CONFIG_DEBUG_PORT3 \ + disabled CONFIG_DEBUG_PORT_NULL" Serial-0 + +choice 'Product rescue-port' \ + "Serial-0 CONFIG_RESCUE_SER0 \ + Serial-1 CONFIG_RESCUE_SER1 \ + Serial-2 CONFIG_RESCUE_SER2 \ + Serial-3 CONFIG_RESCUE_SER3" 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 + +bool 'SDRAM support' CONFIG_SDRAM n +if [ "$CONFIG_SDRAM" = "n" ]; then + hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040 + hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611 +fi + +if [ "$CONFIG_SDRAM" = "y" ]; then + hex 'R_SDRAM_CONFIG' DEF_R_SDRAM_CONFIG d2fa7878 + hex 'R_SDRAM_TIMING' DEF_R_SDRAM_TIMING 80004801 +fi + 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 @@ -82,24 +105,6 @@ hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff endmenu - -# only configure IP numbers if the kernel ifconfig/route setup is enabled - -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 - - endmenu -fi # bring in Etrax built-in drivers diff -u --recursive --new-file v2.4.3/linux/arch/cris/cris.ld linux/arch/cris/cris.ld --- v2.4.3/linux/arch/cris/cris.ld Tue Feb 13 14:13:43 2001 +++ linux/arch/cris/cris.ld Fri Apr 6 10:42:55 2001 @@ -1,13 +1,10 @@ /* 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. */ SECTIONS { - . = 0x60000000; /* DRAM starts virtually at 0x60000000 */ + . = @ETRAX_DRAM_VIRTUAL_BASE@; _dram_start = .; _ibr_start = .; . = . + 0x4000; /* see head.S and pages reserved at the start */ @@ -21,6 +18,7 @@ *(.fixup) *(.text.__*) *(.rodata) + *(.rodata.__*) } . = ALIGN(4); /* Exception table */ @@ -77,5 +75,5 @@ *(.exitcall.exit) } - _dram_end = 0x60000000 + @ETRAX_DRAM_SIZE_M@*1024*1024; + _dram_end = _dram_start + @ETRAX_DRAM_SIZE_M@*1024*1024; } diff -u --recursive --new-file v2.4.3/linux/arch/cris/defconfig linux/arch/cris/defconfig --- v2.4.3/linux/arch/cris/defconfig Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/defconfig Fri Apr 6 10:42:55 2001 @@ -24,10 +24,13 @@ # 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_VIRTUAL_BASE=60000000 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 @@ -40,8 +43,13 @@ # CONFIG_DEBUG_PORT1 is not set # CONFIG_DEBUG_PORT2 is not set # CONFIG_DEBUG_PORT3 is not set +CONFIG_RESCUE_SER0=y +# CONFIG_RESCUE_SER1 is not set +# CONFIG_RESCUE_SER2 is not set +# CONFIG_RESCUE_SER3 is not set DEF_R_WAITSTATES=95a6 DEF_R_BUS_CONFIG=104 +# CONFIG_SDRAM is not set DEF_R_DRAM_CONFIG=1a200040 DEF_R_DRAM_TIMING=5611 DEF_R_PORT_PA_DIR=1d @@ -56,6 +64,87 @@ 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_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_PA_CHANGEABLE_DIR=00 +CONFIG_PA_CHANGEABLE_BITS=FF +CONFIG_PB_CHANGEABLE_DIR=00 +CONFIG_PB_CHANGEABLE_BITS=FF +# CONFIG_JULIETTE is not set +# CONFIG_JULIETTE_VIDEO is not set +# CONFIG_JULIETTE_CCD is not set +# CONFIG_JULIETTE_SS1M is not set +# CONFIG_JULIETTE_MEGCCD is not set +# 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 +179,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 +186,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 +198,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 +313,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 +333,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 +459,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 --recursive --new-file v2.4.3/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in --- v2.4.3/linux/arch/cris/drivers/Config.in Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/drivers/Config.in Fri Apr 6 10:42:55 2001 @@ -1,16 +1,74 @@ mainmenu_option next_comment comment 'Drivers for Etrax 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_RS485 + if [ "$CONFIG_RS485" = "y" ]; then + bool ' RS-485 mode on PA' CONFIG_RS485_ON_PA + if [ "$CONFIG_RS485_ON_PA" = "y" ]; then + int ' RS-485 mode on PA bit' CONFIG_RS485_ON_PA_BIT 3 + fi + bool ' Disable serial receiver' CONFIG_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 y + 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 y + fi +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,14 +83,18 @@ 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 +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 # here we define the CONFIG_'s necessary to enable MTD support @@ -43,7 +105,39 @@ 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 '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_PA_CHANGEABLE_DIR 00 + hex ' PA user changeable bits mask' CONFIG_PA_CHANGEABLE_BITS FF + hex ' PB user changeable dir mask' CONFIG_PB_CHANGEABLE_DIR 00 + hex ' PB user changeable bits mask' CONFIG_PB_CHANGEABLE_BITS FF +fi + +bool 'Juliette support' CONFIG_JULIETTE n + +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 n + bool ' USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 n fi endmenu diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile --- v2.4.3/linux/arch/cris/drivers/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/drivers/Makefile Fri Apr 6 10:42:55 2001 @@ -6,9 +6,16 @@ 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_GPIO) += gpio.o +obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o +obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o +obj-$(CONFIG_JULIETTE) += juliette/juliette.o +subdir-$(CONFIG_JULIETTE) += juliette include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c --- v2.4.3/linux/arch/cris/drivers/axisflashmap.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/drivers/axisflashmap.c Fri Apr 6 10:42:55 2001 @@ -11,6 +11,17 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * 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 +42,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 @@ -205,8 +216,14 @@ mymtd = do_cfi_probe(&axis_map); +#ifdef CONFIG_MTD_AMDSTD + if (!mymtd) { + mymtd = 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,7 +235,8 @@ * now at least. */ - ptable_head = FLASH_CACHED_ADDR + PTABLE_SECTOR + PARTITION_TABLE_OFFSET; + ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + + PTABLE_SECTOR + PARTITION_TABLE_OFFSET); pidx++; /* first partition is always set to the default */ if ((ptable_head->magic == PARTITION_TABLE_MAGIC) diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c --- v2.4.3/linux/arch/cris/drivers/ethernet.c Tue Feb 13 14:13:43 2001 +++ linux/arch/cris/drivers/ethernet.c Fri Apr 6 10:42:55 2001 @@ -1,12 +1,23 @@ -/* $Id: ethernet.c,v 1.5 2000/11/29 17:22:22 bjornw Exp $ +/* $Id: ethernet.c,v 1.8 2001/02/27 13:52:48 bjornw 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.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 * @@ -39,7 +50,7 @@ #include #include #include -#include +#include #include #include #include @@ -53,7 +64,7 @@ #include #include -#include +#include /* DMA and register descriptions */ //#define ETHDEBUG @@ -483,9 +494,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 +506,7 @@ for(bitCounter=15; bitCounter>=0 ; bitCounter--) { data |= (e100_receive_mdio_bit() << bitCounter); } - - restore_flags(flags); + return data; } @@ -555,9 +562,6 @@ 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); @@ -569,8 +573,6 @@ 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 @@ -858,9 +860,9 @@ /* 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); @@ -926,10 +928,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 +984,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; diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/examples/kiobuftest.c linux/arch/cris/drivers/examples/kiobuftest.c --- v2.4.3/linux/arch/cris/drivers/examples/kiobuftest.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/examples/kiobuftest.c Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c --- v2.4.3/linux/arch/cris/drivers/gpio.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/gpio.c Fri Apr 6 10:42:55 2001 @@ -0,0 +1,298 @@ +/* $Id: gpio.c,v 1.4 2001/02/27 13:52:48 bjornw 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.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_PA_CHANGEABLE_DIR +#define CONFIG_PA_CHANGEABLE_DIR 0x00 +#endif +#ifndef CONFIG_PB_CHANGEABLE_DIR +#define CONFIG_PB_CHANGEABLE_DIR 0x00 +#endif + +#ifndef CONFIG_PA_CHANGEABLE_BITS +#define CONFIG_PA_CHANGEABLE_BITS 0xFF +#endif +#ifndef CONFIG_PB_CHANGEABLE_BITS +#define CONFIG_PB_CHANGEABLE_BITS 0xFF +#endif + + +static unsigned char changeable_dir[2] = { CONFIG_PA_CHANGEABLE_DIR, + CONFIG_PB_CHANGEABLE_DIR }; +static unsigned char changeable_bits[2] = { CONFIG_PA_CHANGEABLE_BITS, + CONFIG_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; + + 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; + 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 --recursive --new-file v2.4.3/linux/arch/cris/drivers/i2c.c linux/arch/cris/drivers/i2c.c --- v2.4.3/linux/arch/cris/drivers/i2c.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/i2c.c Fri Apr 6 10:42:55 2001 @@ -0,0 +1,691 @@ +/*!*************************************************************************** +*! +*! 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.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.5 2001/02/27 13:52:48 bjornw 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 */ + +static 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 */ + +static 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 */ + +static 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 */ + +static unsigned char +i2c_inbyte(void) +{ + unsigned char aBitByte = 0; + int i; + int iaa; + //int dd= 0; + + // + // 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); +/* *R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/ + // + // 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 ; + //if (iaa > 0) dd++; + // + // 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 +*# +*#--------------------------------------------------------------------------*/ + +static 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); + +/* *R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/ + // + // 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 +*# +*#--------------------------------------------------------------------------*/ +static 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; + + do { + error = 0; + // + // we don't like to be interrupted + // + 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 + // + sti(); + + } 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; + + do { + error = 0; + // + // we don't like to be interrupted + // + 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 + // + sti(); + } 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"); +} + +/* this makes sure that i2c_init is called during boot */ + +module_init(i2c_init); + +/****************** END OF FILE i2c.c ********************************/ diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/i2c.h linux/arch/cris/drivers/i2c.h --- v2.4.3/linux/arch/cris/drivers/i2c.h Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/i2c.h Fri Apr 6 10:42:55 2001 @@ -0,0 +1,16 @@ +/* $Id: i2c.h,v 1.2 2001/01/18 15:49:30 bjornw 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 */ +static void i2c_start(void); +static void i2c_stop(void); +static void i2c_outbyte(unsigned char x); +static unsigned char i2c_inbyte(void); +static int i2c_getack(void); +static void i2c_sendack(void); + + + diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c --- v2.4.3/linux/arch/cris/drivers/ide.c Tue Feb 13 14:13:43 2001 +++ linux/arch/cris/drivers/ide.c Fri Apr 6 10:42:55 2001 @@ -1,4 +1,4 @@ -/* $Id: ide.c,v 1.4 2001/01/10 21:14:32 bjornw Exp $ +/* $Id: ide.c,v 1.9 2001/03/01 13:11:18 bjornw 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,23 @@ * Mikael Starvik (pio setup stuff) * * $Log: ide.c,v $ + * 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 +80,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)); @@ -208,7 +230,8 @@ 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 +249,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,7 +277,16 @@ *R_GEN_CONFIG = genconfig_shadow; #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 0; +#ifndef CONFIG_CRIS_LOW_MAP + /* remap the I/O-mapped reset-bit from CSE1 to something inside our kernel space */ + reset_addr = (unsigned long *)ioremap((unsigned long)(MEM_CSE1_START | + MEM_NON_CACHEABLE), 16); + *reset_addr = 0; +#else + /* LOW_MAP, can't do the ioremap, but it's already mapped straight over */ + reset_addr = (unsigned long *)(MEM_CSE1_START | MEM_NON_CACHEABLE); + *reset_addr = 0; +#endif #endif /* wait some */ @@ -262,9 +296,11 @@ dummy = 3; #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 */ + *reset_addr = 1 << 16; #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 +322,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 */ @@ -560,14 +596,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 @@ -581,8 +609,22 @@ 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 */ + 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 */ ata_descrs[count].sw_len = size; ata_descrs[count].ctrl = 0; ata_descrs[count].buf = addr; diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c --- v2.4.3/linux/arch/cris/drivers/serial.c Fri Mar 2 18:38:40 2001 +++ linux/arch/cris/drivers/serial.c Fri Apr 6 10:42:55 2001 @@ -1,12 +1,26 @@ -/* $Id: serial.c,v 1.6 2000/11/22 16:36:09 bjornw Exp $ +/* $Id: serial.c,v 1.10 2001/03/05 13:14: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.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 +190,7 @@ * */ -static char *serial_version = "$Revision: 1.6 $"; +static char *serial_version = "$Revision: 1.10 $"; #include #include @@ -252,12 +266,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 @@ -367,36 +381,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 @@ -459,7 +473,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 +508,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 @@ -1267,12 +1281,12 @@ /* 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 @@ -1467,7 +1481,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) { @@ -2688,12 +2702,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 +2972,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 +3007,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 --recursive --new-file v2.4.3/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h --- v2.4.3/linux/arch/cris/drivers/serial.h Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/drivers/serial.h Fri Apr 6 10:42:55 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 @@ -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 --recursive --new-file v2.4.3/linux/arch/cris/drivers/sync_serial.c linux/arch/cris/drivers/sync_serial.c --- v2.4.3/linux/arch/cris/drivers/sync_serial.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/sync_serial.c Fri Apr 6 10:42:55 2001 @@ -0,0 +1,873 @@ +/* + * Simple synchronous serial port driver for ETRAX 100LX. + * + * Synchronous serial ports are used for continous streamed data like audio. + * The deault 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 + +#define IN_BUFFER_SIZE 8192 +#define OUT_BUFFER_SIZE 4096 + +#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_eop_bit; /* In R_IRQ_MASK2_RD */ + char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */ + char output_dma_bit; /* In R_IRQ_MASK2_RD */ + char eop_bit; /* In R_SET_EOP */ + + 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); +static void flush_handler(void); + +/* 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_eop), /* input_dma_eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma9_descr), /* input_dma_descr_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ + IO_BITNR(R_SET_EOP, ch9_eop) /* eop_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_eop), /* input_dma_eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ + IO_BITNR(R_SET_EOP, ch5_eop) /* eop_bit */ + } +}; + +/* Register shadows */ +static unsigned sync_serial_prescale_shadow = 0; +static unsigned gen_config_ii_shadow = 0; + +/* Timer used to flush data from the DMA */ +static struct timer_list flush_timer; + +#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", NULL)) + panic("Can't allocate sync serial port 1 IRQ"); + if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", NULL)) + 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 = 3; /* Clear IRQ */ + *R_DMA_CH9_CLR_INTR = 3; /* Clear IRQ */ + *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_eop, 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", NULL)) + 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", NULL)) + panic("Can't allocate sync serial port 1 IRQ"); + if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", NULL)) + 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 = 3; /* Clear IRQ */ + *R_DMA_CH5_CLR_INTR = 3; /* Clear IRQ */ + *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_eop, 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", NULL)) + 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, 0) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, 7) | + IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal)); + + /* Select synchronous ports */ + *R_GEN_CONFIG_II = gen_config_ii_shadow; + + /*Initialize DMA flush timer if dma is used */ + if (ports[0].use_dma || ports[1].use_dma) + { + init_timer(&flush_timer); + flush_timer.function = flush_handler; + mod_timer(&flush_timer, jiffies + 10); + } + + printk("Etrax100LX 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, running) | + IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb) | + IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, enable) | + 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) +{ + ports[MINOR(inode->i_rdev)].busy = 0; + return 0; +} + +static int sync_serial_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + sync_port* port = &ports[dev]; + + /* Disable port while changing config */ + if (dev) + { + RESET_DMA(4); WAIT_DMA(4); + *R_DMA_CH4_CLR_INTR = 3; + SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); + } + else + { + RESET_DMA(8); WAIT_DMA(8); + *R_DMA_CH8_CLR_INTR = 3; + 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 -EINVAL; + } + /* 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 0; +} + +static ssize_t sync_serial_manual_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + sync_port* port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + + 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); + return count; +} + +static ssize_t sync_serial_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + + DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count)); + + 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); + return count; +} + +static ssize_t sync_serial_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int avail; + sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + char* start; + char* end; + unsigned long flags; + + DEBUG(printk("Read dev %d count\n")); + + /* 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); + } + + /* 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_eop | 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_eop | 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 */ + } + else if (ireg & (1 << port->input_dma_eop_bit)) /* EOP interrupt */ + { + /* EOP interrupt means that DMA has not 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 the current descriptor */ + if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) + port->writep += port->in_descr2.hw_len; + else + port->writep += port->in_descr1.hw_len; + + 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 */ + } + } + } +} + +static void flush_handler(void) +{ + int i; + + for (i = 0; i < NUMBER_OF_PORTS; i++) + { + if (ports[i].enabled) + { + *R_SET_EOP = 1 << ports[i].eop_bit; + } + } + /* restart flush timer */ + mod_timer(&flush_timer, jiffies + 10); +} + +module_init(etrax_sync_serial_init); diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c --- v2.4.3/linux/arch/cris/drivers/usb-host.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/usb-host.c Fri Apr 6 10:42:55 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 successfully 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 successfully 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 successfully completed + */ + dbg_ctrl("Last SB for CTRL %d sent successfully", 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 successfully completed + */ + dbg_bulk("Last SB for BULK %d sent successfully", 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 --recursive --new-file v2.4.3/linux/arch/cris/drivers/usb-host.h linux/arch/cris/drivers/usb-host.h --- v2.4.3/linux/arch/cris/drivers/usb-host.h Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/usb-host.h Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.3/linux/arch/cris/kernel/entry.S Fri Mar 2 18:38:40 2001 +++ linux/arch/cris/kernel/entry.S Fri Apr 6 10:42:55 2001 @@ -1,12 +1,30 @@ -/* $Id: entry.S,v 1.11 2001/01/10 21:13:29 bjornw Exp $ +/* $Id: entry.S,v 1.15 2001/03/05 13:14:30 bjornw 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.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 * @@ -79,7 +97,8 @@ .globl _mmu_bus_fault .globl _sys_call_table - + + .globl LTASK_PID ;; syscall error codes LENOSYS = 38 @@ -90,7 +109,17 @@ LTASK_SIGPENDING = 8 LTASK_NEEDRESCHED = 20 LTASK_PTRACE = 24 +LTASK_PID = 105 + + ;; process bits for ptrace +PT_TRACESYS_BIT = 1 + + ;; Offset for esp0 into task_struct: current->thread.esp0. + ;; FIXME: In need of padding somewhere, to get dword-alignment. + +THREAD_ESP0 = 597 + ;; some pt_regs offsets (from ptrace.h) LORIG_R10 = 4 @@ -98,8 +127,8 @@ LR12 = 12 LR11 = 16 LR10 = 20 -LR1 = 56 -LR0 = 60 +LR9 = 24 +LMOF = 64 LDCCR = 68 LSRP = 72 LIRP = 76 @@ -124,7 +153,7 @@ nop ba ret_with_reschedule ; go back but check schedule and signals first nop - + reschedule: ;; keep r9 intact push r9 @@ -170,41 +199,38 @@ 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 + + ;; Perform "current->thread.esp0 = sp". + ;; This used to be a separate function; set_esp0(ssp). + movs.w -8192,r0 ; THREAD_SIZE == 8192 + and.d sp,r0 + + move.d sp,[r0+THREAD_ESP0] ;; 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 + 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 - - ;; read the system call vector into r1 - - move.d [r1+_sys_call_table],r1 + lslq 2,r9 ; multiply by 4, in the delay slot - ;; 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 + ;; 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 + jsr [r9+_sys_call_table] ; actually do the system call + addq 2*4,sp ; pop the mof and srp 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 @@ -269,10 +295,8 @@ ;; 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 + addq 12,sp ; Skip rest of SBFS frame. tracesys: @@ -289,30 +313,32 @@ ;; 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 + ;; the fifth and sixth parameters needs to be put on the stack for + ;; the system call to find them - push r0 - jsr r1 ; actually call the system-call - addq 4,sp ; pop the r0 parameter + push srp + push mof + jsr r9 ; actually call the system-call + addq 2*4,sp ; pop the r0 parameter 1: move.d r10,[sp+LR10] ; save the return value diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S --- v2.4.3/linux/arch/cris/kernel/head.S Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/head.S Fri Apr 6 10:42:55 2001 @@ -1,46 +1,75 @@ - ;; $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.20 2001/02/23 12:47:56 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.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 @@ -82,13 +111,13 @@ ;; slightly different. We also let the simulator get this mapping for now. #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 +160,9 @@ jump inram ; enter cached ram inflash: + ;; We need to initialze DRAM registers before we start using the DRAM +#include "../lib/dram_init.S" -#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] - -#endif ;; 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 @@ -357,27 +371,38 @@ #if !defined(CONFIG_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_KGDB) || !defined(CONFIG_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 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 @@ -438,6 +463,9 @@ move.b 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] @@ -478,7 +506,7 @@ 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 +525,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 +535,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 diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c --- v2.4.3/linux/arch/cris/kernel/irq.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/irq.c Fri Apr 6 10:42:55 2001 @@ -1,8 +1,8 @@ -/* $Id: irq.c,v 1.5 2000/08/17 15:35:15 bjornw Exp $ +/* $Id: irq.c,v 1.11 2001/02/27 13:52:52 bjornw 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 resereved */ +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) @@ -412,6 +419,8 @@ */ void system_call(void); /* from entry.S */ +void gdb_handle_breakpoint(void); /* from traps.c */ +void do_sigtrap(void); /* also from traps.c */ 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); + /* setup a breakpoint handler for debugging used for both user and + kernel mode debugging (which is why it is not inside an ifdef + CONFIG_KGDB) */ + set_break_vector(8, gdb_handle_breakpoint); + #ifdef CONFIG_KGDB /* setup kgdb if its enabled, and break into the debugger */ - kgdb_init(); - breakpoint(); #endif -} +} diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c --- v2.4.3/linux/arch/cris/kernel/kgdb.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/kgdb.c Fri Apr 6 10:42:55 2001 @@ -18,6 +18,12 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! 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 +49,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.2 2001/01/12 14:22:25 orjanf Exp $ +*! $Id: kgdb.c,v 1.4 2001/02/23 13:45:19 bjornw Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -1531,7 +1537,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 --recursive --new-file v2.4.3/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c --- v2.4.3/linux/arch/cris/kernel/process.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/process.c Fri Apr 6 10:42:55 2001 @@ -1,9 +1,9 @@ -/* $Id: process.c,v 1.8 2000/09/13 14:34:13 bjornw Exp $ +/* $Id: process.c,v 1.12 2001/02/27 13:52:52 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) * @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -71,11 +71,6 @@ #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 +129,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 +138,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; } diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/semaphore.c linux/arch/cris/kernel/semaphore.c --- v2.4.3/linux/arch/cris/kernel/semaphore.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/semaphore.c Tue Apr 17 17:19:24 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 --recursive --new-file v2.4.3/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c --- v2.4.3/linux/arch/cris/kernel/setup.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/setup.c Fri Apr 27 14:10:31 2001 @@ -1,9 +1,9 @@ -/* $Id: setup.c,v 1.8 2001/01/16 16:31:38 bjornw Exp $ +/* $Id: setup.c,v 1.11 2001/03/02 15:52:03 bjornw 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 @@ -41,12 +41,6 @@ unsigned char aux_device_present; -#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 char _etext, _edata, _end; @@ -75,7 +69,8 @@ * */ -void __init setup_arch(char **cmdline_p) +void __init +setup_arch(char **cmdline_p) { unsigned long bootmap_size; unsigned long start_pfn, max_pfn; @@ -179,7 +174,7 @@ /* 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 +187,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 +210,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 +238,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 +251,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 --recursive --new-file v2.4.3/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c --- v2.4.3/linux/arch/cris/kernel/signal.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/signal.c Fri Apr 6 10:42:55 2001 @@ -38,9 +38,6 @@ #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) @@ -391,9 +388,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)); } @@ -453,9 +450,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)); } diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c --- v2.4.3/linux/arch/cris/kernel/sys_cris.c Mon Mar 19 12:35:11 2001 +++ linux/arch/cris/kernel/sys_cris.c Fri Apr 6 10:42:55 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_cris.c,v 1.3 2000/08/02 13:59:02 bjornw Exp $ +/* $Id: sys_cris.c,v 1.4 2001/01/31 14:55:58 perf Exp $ * * linux/arch/cris/kernel/sys_etrax.c * @@ -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 diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c --- v2.4.3/linux/arch/cris/kernel/traps.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/traps.c Fri Apr 6 10:42:55 2001 @@ -1,16 +1,19 @@ -/* $Id: traps.c,v 1.3 2000/10/04 16:50:06 bjornw Exp $ +/* $Id: traps.c,v 1.8 2001/02/23 13:45:20 bjornw 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 + * Orjan Friberg * */ +#include #include #include #include @@ -35,7 +38,8 @@ #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; @@ -86,7 +90,8 @@ #if 0 /* displays a short stack trace */ -int show_stack() +int +show_stack() { unsigned long *sp = (unsigned long *)rdusp(); int i; @@ -97,7 +102,8 @@ } #endif -void show_registers(struct pt_regs * regs) +void +show_registers(struct pt_regs * regs) { unsigned long usp = rdusp(); @@ -145,9 +151,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 +165,68 @@ do_exit(SIGSEGV); } -void __init trap_init(void) +void __init +trap_init(void) { - } + +/* Use static variables instead of the stack for temporary storage. */ +static int saved_r0 = 0; +static int saved_dccr = 0; + +asm (" + .global _gdb_handle_breakpoint + .global _do_sigtrap +_gdb_handle_breakpoint: +;; +;; This handles a break instruction for entering a debug session. +;; + move dccr,[_saved_dccr] ; Save dccr. + move.d r0,[_saved_r0] ; Save r0. " +#ifdef CONFIG_KGDB +" + move ccr,r0 + btstq 8,r0 ; Test the U-flag. + bmi _ugdb_handle_breakpoint ; Go to user mode debugging. + nop ; Delay slot. + move.d [_saved_r0],r0 ; Restore r0. + move [_saved_dccr],dccr ; Restore dccr. + ba _kgdb_handle_breakpoint ; Go to kernel debugging. + nop ; Delay slot. " +#endif +" +_ugdb_handle_breakpoint: +;; +;; Yes, we could do a 'push brp' here and let gdb adjust the pc once it +;; starts talking to the target again, but this way we avoid a 'P' packet. +;; + move brp,r0 ; Use r0 temporarily for calculation. + subq 2,r0 ; Set to address of previous instruction. + move r0,brp ; Restore new brp. + move.d [_saved_r0],r0 ; Restore r0. + move [_saved_dccr],dccr ; Restore dccr. + +_do_sigtrap: +;; +;; SIGTRAP the process that executed the break instruction. +;; Make a frame that Rexit in entry.S expects. +;; + push brp ; Push breakpoint return pointer. + 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. +"); diff -u --recursive --new-file v2.4.3/linux/arch/cris/lib/checksum.S linux/arch/cris/lib/checksum.S --- v2.4.3/linux/arch/cris/lib/checksum.S Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/checksum.S Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S --- v2.4.3/linux/arch/cris/lib/checksumcopy.S Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/checksumcopy.S Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S --- v2.4.3/linux/arch/cris/lib/dram_init.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/dram_init.S Fri Apr 6 10:42:55 2001 @@ -0,0 +1,123 @@ + ;; $Id: dram_init.S,v 1.2 2001/02/08 15:20:00 starvik Exp $ + ;; + ;; DRAM/SDRAM initialization - alter with care + ;; This file is intended to be included from other assembler files + ;; + ;; Copyright (C) 2000 Axis Communications AB + ;; + ;; Authors: Mikael Starvik (starvik@axis.com) + ;; Bjorn Wesen (bjornw@axis.com) + ;; + ;; $Log: dram_init.S,v $ + ;; 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. + ;; + ;; + ;; + +#include + +#ifndef CONFIG_SVINTO_SIM + move.d DEF_R_WAITSTATES, r0 + move.d r0, [R_WAITSTATES] + + move.d DEF_R_BUS_CONFIG, r0 + move.d r0, [R_BUS_CONFIG] + +#ifndef CONFIG_SDRAM + 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] +#else + ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization + + ; Bank configuration + move.d DEF_R_SDRAM_CONFIG, r0 + move.d r0, [R_SDRAM_CONFIG] + + ; Calculate value of mrs_data + ; cas_delay = 2 && bus_width = 32 => 0x40 + ; cas_delay = 3 && bus_width = 32 => 0x60 + ; cas_delay = 2 && bus_width = 16 => 0x20 + ; cas_delay = 3 && bus_width = 16 => 0x30 + + move.d 0x40, r2 ; Assume 32 bits and cas_delay = 2 + move.d DEF_R_SDRAM_TIMING, r1 + and.d 0x0c, r1 ; Get cas delay + cmp.d 0x08, r1 ; cas_delay = 2? + beq bw_check + nop + or.d 0x20, r2 ; cas_delay = 3 +bw_check: + move.d 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 DEF_R_SDRAM_TIMING, r1 + or.d 0x80000000, r1 ; Make sure sdram enable bit is set + lslq 16, r2 ; mrs data starts at bit 16 + or.d r2, r1 + move.d r1, [R_SDRAM_TIMING] + + ; Wait 200ns + move.d 10, 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 + 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 --recursive --new-file v2.4.3/linux/arch/cris/mm/Makefile linux/arch/cris/mm/Makefile --- v2.4.3/linux/arch/cris/mm/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/mm/Makefile Fri Apr 6 10:42:55 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 --recursive --new-file v2.4.3/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c --- v2.4.3/linux/arch/cris/mm/fault.c Mon Mar 19 12:35:11 2001 +++ linux/arch/cris/mm/fault.c Fri Apr 6 10:42:55 2001 @@ -6,6 +6,9 @@ * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * 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. @@ -301,7 +304,7 @@ /* Are we prepared to handle this kernel fault? * * (The kernel has valid exception-points in the source - * when it acesses user-memory. When it fails in one + * when it accesses user-memory. When it fails in one * of those points, we find it in a table and do a jump * to some fixup code that loads an appropriate error * code) diff -u --recursive --new-file v2.4.3/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c --- v2.4.3/linux/arch/cris/mm/init.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/mm/init.c Fri Apr 6 10:42:55 2001 @@ -2,11 +2,22 @@ * 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.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 * @@ -287,16 +298,19 @@ * The Juliette 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_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 +321,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 ) | diff -u --recursive --new-file v2.4.3/linux/arch/cris/mm/ioremap.c linux/arch/cris/mm/ioremap.c --- v2.4.3/linux/arch/cris/mm/ioremap.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/mm/ioremap.c Fri Apr 6 10:42:55 2001 @@ -0,0 +1,164 @@ +/* + * 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_kernel(pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + if (address >= end) + BUG(); + do { + pmd_t *pmd; + pmd = pmd_alloc_kernel(dir, address); + if (!pmd) + return -ENOMEM; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + return -ENOMEM; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + flush_tlb_all(); + return 0; +} + +/* + * Generic mapping function (not visible outside): + */ + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ +void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void * addr; + struct vm_struct * area; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + +#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 --recursive --new-file v2.4.3/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.4.3/linux/arch/i386/Makefile Wed Jan 10 15:06:14 2001 +++ linux/arch/i386/Makefile Thu Apr 12 12:20:31 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 --recursive --new-file v2.4.3/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.4.3/linux/arch/i386/boot/setup.S Sat Jan 27 10:51:35 2001 +++ linux/arch/i386/boot/setup.S Wed Apr 11 18:50:25 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 diff -u --recursive --new-file v2.4.3/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.3/linux/arch/i386/config.in Mon Jan 8 13:27:56 2001 +++ linux/arch/i386/config.in Fri Apr 20 18:26:15 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 @@ -111,6 +118,13 @@ define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_USE_3DNOW y 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 diff -u --recursive --new-file v2.4.3/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.3/linux/arch/i386/defconfig Fri Mar 23 16:05:44 2001 +++ linux/arch/i386/defconfig Fri Apr 27 14:41:16 2001 @@ -35,11 +35,15 @@ # 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_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_X86_L1_CACHE_SHIFT=5 CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y @@ -383,6 +387,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 +568,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 diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.4.3/linux/arch/i386/kernel/apm.c Fri Feb 9 11:29:44 2001 +++ linux/arch/i386/kernel/apm.c Fri Apr 6 10:42:47 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 ). @@ -227,6 +227,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 @@ -1550,6 +1552,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; diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c --- v2.4.3/linux/arch/i386/kernel/bluesmoke.c Fri Dec 29 14:07:20 2000 +++ linux/arch/i386/kernel/bluesmoke.c Wed Apr 11 19:02:27 2001 @@ -45,6 +45,7 @@ printk(" at %08x%08x", high, low); } + printk("\n"); /* Clear it */ wrmsr(0x401+i*4, 0UL, 0UL); /* Serialize */ diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.4.3/linux/arch/i386/kernel/head.S Sun Mar 25 17:38:31 2001 +++ linux/arch/i386/kernel/head.S Fri Apr 20 16:23:30 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. diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.4.3/linux/arch/i386/kernel/i386_ksyms.c Fri Mar 2 12:03:49 2001 +++ linux/arch/i386/kernel/i386_ksyms.c Wed Apr 25 13:31:03 2001 @@ -61,7 +61,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 +72,14 @@ EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +#ifdef CONFIG_IO_DEBUG +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 +97,7 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(simple_strtol); +EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user); diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c --- v2.4.3/linux/arch/i386/kernel/ldt.c Mon Mar 19 12:35:09 2001 +++ linux/arch/i386/kernel/ldt.c Wed Apr 11 19:05:37 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 --recursive --new-file v2.4.3/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.4.3/linux/arch/i386/kernel/mtrr.c Fri Feb 9 11:29:44 2001 +++ linux/arch/i386/kernel/mtrr.c Wed Apr 11 19:02:27 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; @@ -1777,7 +1813,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 */ @@ -1938,6 +1975,7 @@ get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: /* The original Athlon docs said that total addressable memory is 44 bits wide. @@ -1956,12 +1994,27 @@ size_and_mask = ~size_or_mask & 0xfff00000; break; } + size_or_mask = 0xff000000; /* 36 bits */ + size_and_mask = 0x00f00000; + break; + + case X86_VENDOR_CENTAUR: + /* Cyrix III has Intel style MTRRs, but doesn't support PAE */ + if (boot_cpu_data.x86 == 6 && + (boot_cpu_data.x86_model == 6 || + boot_cpu_data.x86_model == 7)) { + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; + } + break; + default: /* Intel, etc. */ size_or_mask = 0xff000000; /* 36 bits */ size_and_mask = 0x00f00000; break; } + } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) { /* Pre-Athlon (K6) AMD CPU MTRRs */ mtrr_if = MTRR_IF_AMD_K6; @@ -2072,8 +2125,10 @@ #ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - proc_root_mtrr->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 --recursive --new-file v2.4.3/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.4.3/linux/arch/i386/kernel/pci-pc.c Thu Mar 29 11:24:17 2001 +++ linux/arch/i386/kernel/pci-pc.c Thu Apr 19 22:57:06 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 --recursive --new-file v2.4.3/linux/arch/i386/kernel/semaphore.c linux/arch/i386/kernel/semaphore.c --- v2.4.3/linux/arch/i386/kernel/semaphore.c Sat Nov 18 17:31:25 2000 +++ linux/arch/i386/kernel/semaphore.c Thu Apr 12 12:22:53 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 --recursive --new-file v2.4.3/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.3/linux/arch/i386/kernel/setup.c Sun Mar 25 18:24:31 2001 +++ linux/arch/i386/kernel/setup.c Fri Apr 27 14:10:32 2001 @@ -58,6 +58,12 @@ * 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 */ /* @@ -136,12 +142,6 @@ unsigned char aux_device_present; -#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 char _text, _etext, _edata, _end; extern unsigned long cpu_khz; @@ -440,6 +440,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 +670,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 +725,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 @@ -1401,7 +1566,7 @@ 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); @@ -1481,6 +1646,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) @@ -1732,8 +1923,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 +2188,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: @@ -2021,6 +2221,10 @@ case X86_VENDOR_TRANSMETA: init_transmeta(c); + break; + + case X86_VENDOR_RISE: + init_rise(c); break; } diff -u --recursive --new-file v2.4.3/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.4.3/linux/arch/i386/lib/Makefile Fri Dec 29 14:07:20 2000 +++ linux/arch/i386/lib/Makefile Wed Apr 25 13:31:03 2001 @@ -8,8 +8,8 @@ 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 diff -u --recursive --new-file v2.4.3/linux/arch/i386/lib/mmx.c linux/arch/i386/lib/mmx.c --- v2.4.3/linux/arch/i386/lib/mmx.c Thu Mar 1 18:04:34 2001 +++ linux/arch/i386/lib/mmx.c Wed Apr 11 19:02:27 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,118 @@ ); kernel_fpu_end(); } + +#else + +/* + * Generic MMX implementation without K7 specific streaming + */ + +static void fast_clear_page(void *page) +{ + int i; + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __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; + } + stts(); +} + +static void fast_copy_page(void *to, void *from) +{ + int i; + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __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; + } + stts(); +} + + +#endif /* * Favour MMX for page clear and copy. diff -u --recursive --new-file v2.4.3/linux/arch/i386/lib/strstr.c linux/arch/i386/lib/strstr.c --- v2.4.3/linux/arch/i386/lib/strstr.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/strstr.c Fri Apr 6 10:42:47 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 --recursive --new-file v2.4.3/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c --- v2.4.3/linux/arch/i386/lib/usercopy.c Fri Nov 12 04:29:47 1999 +++ linux/arch/i386/lib/usercopy.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/control_w.h linux/arch/i386/math-emu/control_w.h --- v2.4.3/linux/arch/i386/math-emu/control_w.h Thu Jun 29 08:25:27 1995 +++ linux/arch/i386/math-emu/control_w.h Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/div_Xsig.S linux/arch/i386/math-emu/div_Xsig.S --- v2.4.3/linux/arch/i386/math-emu/div_Xsig.S Fri Aug 27 10:18:17 1999 +++ linux/arch/i386/math-emu/div_Xsig.S Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/errors.c linux/arch/i386/math-emu/errors.c --- v2.4.3/linux/arch/i386/math-emu/errors.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/errors.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/exception.h linux/arch/i386/math-emu/exception.h --- v2.4.3/linux/arch/i386/math-emu/exception.h Mon Dec 11 13:34:33 2000 +++ linux/arch/i386/math-emu/exception.h Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_asm.h linux/arch/i386/math-emu/fpu_asm.h --- v2.4.3/linux/arch/i386/math-emu/fpu_asm.h Mon Dec 11 13:34:33 2000 +++ linux/arch/i386/math-emu/fpu_asm.h Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h --- v2.4.3/linux/arch/i386/math-emu/fpu_emu.h Mon Dec 11 13:34:33 2000 +++ linux/arch/i386/math-emu/fpu_emu.h Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c --- v2.4.3/linux/arch/i386/math-emu/fpu_entry.c Mon Jun 19 18:10:44 2000 +++ linux/arch/i386/math-emu/fpu_entry.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_etc.c linux/arch/i386/math-emu/fpu_etc.c --- v2.4.3/linux/arch/i386/math-emu/fpu_etc.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/fpu_etc.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_trig.c linux/arch/i386/math-emu/fpu_trig.c --- v2.4.3/linux/arch/i386/math-emu/fpu_trig.c Thu Nov 4 09:10:22 1999 +++ linux/arch/i386/math-emu/fpu_trig.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/get_address.c linux/arch/i386/math-emu/get_address.c --- v2.4.3/linux/arch/i386/math-emu/get_address.c Mon Jun 19 12:56:08 2000 +++ linux/arch/i386/math-emu/get_address.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/load_store.c linux/arch/i386/math-emu/load_store.c --- v2.4.3/linux/arch/i386/math-emu/load_store.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/load_store.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly.h linux/arch/i386/math-emu/poly.h --- v2.4.3/linux/arch/i386/math-emu/poly.h Thu Nov 4 09:10:22 1999 +++ linux/arch/i386/math-emu/poly.h Fri Apr 6 10:42:47 2001 @@ -118,4 +118,4 @@ :"=g" (*x):"g" (x):"si","ax","cx"); } -#endif _POLY_H +#endif /* _POLY_H */ diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_2xm1.c linux/arch/i386/math-emu/poly_2xm1.c --- v2.4.3/linux/arch/i386/math-emu/poly_2xm1.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/poly_2xm1.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_atan.c linux/arch/i386/math-emu/poly_atan.c --- v2.4.3/linux/arch/i386/math-emu/poly_atan.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/poly_atan.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_l2.c linux/arch/i386/math-emu/poly_l2.c --- v2.4.3/linux/arch/i386/math-emu/poly_l2.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/poly_l2.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_sin.c linux/arch/i386/math-emu/poly_sin.c --- v2.4.3/linux/arch/i386/math-emu/poly_sin.c Thu Nov 4 09:10:22 1999 +++ linux/arch/i386/math-emu/poly_sin.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_tan.c linux/arch/i386/math-emu/poly_tan.c --- v2.4.3/linux/arch/i386/math-emu/poly_tan.c Wed Jul 5 10:56:13 2000 +++ linux/arch/i386/math-emu/poly_tan.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_compare.c linux/arch/i386/math-emu/reg_compare.c --- v2.4.3/linux/arch/i386/math-emu/reg_compare.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/reg_compare.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_constant.h linux/arch/i386/math-emu/reg_constant.h --- v2.4.3/linux/arch/i386/math-emu/reg_constant.h Mon Dec 11 13:34:34 2000 +++ linux/arch/i386/math-emu/reg_constant.h Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_divide.c linux/arch/i386/math-emu/reg_divide.c --- v2.4.3/linux/arch/i386/math-emu/reg_divide.c Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/reg_divide.c Fri Apr 6 10:42:47 2001 @@ -201,6 +201,6 @@ EXCEPTION(EX_INTERNAL|0x102); return FPU_Exception; } -#endif PARANOID +#endif /* PARANOID */ } diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_ld_str.c linux/arch/i386/math-emu/reg_ld_str.c --- v2.4.3/linux/arch/i386/math-emu/reg_ld_str.c Sun Jan 25 11:01:48 1998 +++ linux/arch/i386/math-emu/reg_ld_str.c Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_mul.c linux/arch/i386/math-emu/reg_mul.c --- v2.4.3/linux/arch/i386/math-emu/reg_mul.c Wed Jun 24 14:30:08 1998 +++ linux/arch/i386/math-emu/reg_mul.c Fri Apr 6 10:42:47 2001 @@ -126,6 +126,6 @@ EXCEPTION(EX_INTERNAL|0x102); return FPU_Exception; } -#endif PARANOID +#endif /* PARANOID */ } diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_round.S linux/arch/i386/math-emu/reg_round.S --- v2.4.3/linux/arch/i386/math-emu/reg_round.S Thu Nov 4 09:10:22 1999 +++ linux/arch/i386/math-emu/reg_round.S Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_add.S linux/arch/i386/math-emu/reg_u_add.S --- v2.4.3/linux/arch/i386/math-emu/reg_u_add.S Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/reg_u_add.S Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_div.S linux/arch/i386/math-emu/reg_u_div.S --- v2.4.3/linux/arch/i386/math-emu/reg_u_div.S Fri Aug 27 10:18:17 1999 +++ linux/arch/i386/math-emu/reg_u_div.S Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_mul.S linux/arch/i386/math-emu/reg_u_mul.S --- v2.4.3/linux/arch/i386/math-emu/reg_u_mul.S Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/reg_u_mul.S Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_sub.S linux/arch/i386/math-emu/reg_u_sub.S --- v2.4.3/linux/arch/i386/math-emu/reg_u_sub.S Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/reg_u_sub.S Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/status_w.h linux/arch/i386/math-emu/status_w.h --- v2.4.3/linux/arch/i386/math-emu/status_w.h Mon Dec 11 13:34:33 2000 +++ linux/arch/i386/math-emu/status_w.h Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/math-emu/wm_sqrt.S linux/arch/i386/math-emu/wm_sqrt.S --- v2.4.3/linux/arch/i386/math-emu/wm_sqrt.S Tue Dec 9 17:57:09 1997 +++ linux/arch/i386/math-emu/wm_sqrt.S Fri Apr 6 10:42: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 --recursive --new-file v2.4.3/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.4.3/linux/arch/i386/mm/init.c Mon Mar 26 11:01:56 2001 +++ linux/arch/i386/mm/init.c Fri Apr 20 16:15:20 2001 @@ -309,14 +309,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 diff -u --recursive --new-file v2.4.3/linux/arch/ia64/Makefile linux/arch/ia64/Makefile --- v2.4.3/linux/arch/ia64/Makefile Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/Makefile Thu Apr 5 12:51:46 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 --recursive --new-file v2.4.3/linux/arch/ia64/boot/bootloader.c linux/arch/ia64/boot/bootloader.c --- v2.4.3/linux/arch/ia64/boot/bootloader.c Mon Oct 9 17:54:53 2000 +++ linux/arch/ia64/boot/bootloader.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.4.3/linux/arch/ia64/config.in Fri Feb 16 15:53:08 2001 +++ linux/arch/ia64/config.in Tue Apr 17 17:19:24 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 @@ -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 --recursive --new-file v2.4.3/linux/arch/ia64/dig/setup.c linux/arch/ia64/dig/setup.c --- v2.4.3/linux/arch/ia64/dig/setup.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/dig/setup.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/hp/hpsim_irq.c linux/arch/ia64/hp/hpsim_irq.c --- v2.4.3/linux/arch/ia64/hp/hpsim_irq.c Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/hp/hpsim_irq.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.4.3/linux/arch/ia64/ia32/binfmt_elf32.c Thu Mar 22 09:24:58 2001 +++ linux/arch/ia64/ia32/binfmt_elf32.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.4.3/linux/arch/ia64/ia32/ia32_entry.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/ia32/ia32_entry.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/ia32/ia32_support.c linux/arch/ia64/ia32/ia32_support.c --- v2.4.3/linux/arch/ia64/ia32/ia32_support.c Mon Oct 9 17:54:53 2000 +++ linux/arch/ia64/ia32/ia32_support.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.4.3/linux/arch/ia64/ia32/sys_ia32.c Mon Mar 19 12:35:10 2001 +++ linux/arch/ia64/ia32/sys_ia32.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile --- v2.4.3/linux/arch/ia64/kernel/Makefile Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/Makefile Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c --- v2.4.3/linux/arch/ia64/kernel/acpi.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/acpi.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/brl_emu.c linux/arch/ia64/kernel/brl_emu.c --- v2.4.3/linux/arch/ia64/kernel/brl_emu.c Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/kernel/brl_emu.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.4.3/linux/arch/ia64/kernel/efi.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/kernel/efi.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/efi_stub.S linux/arch/ia64/kernel/efi_stub.S --- v2.4.3/linux/arch/ia64/kernel/efi_stub.S Fri Jul 14 16:08:11 2000 +++ linux/arch/ia64/kernel/efi_stub.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/efivars.c linux/arch/ia64/kernel/efivars.c --- v2.4.3/linux/arch/ia64/kernel/efivars.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/efivars.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.4.3/linux/arch/ia64/kernel/entry.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/entry.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/entry.h linux/arch/ia64/kernel/entry.h --- v2.4.3/linux/arch/ia64/kernel/entry.h Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/kernel/entry.h Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/fw-emu.c linux/arch/ia64/kernel/fw-emu.c --- v2.4.3/linux/arch/ia64/kernel/fw-emu.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/fw-emu.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S --- v2.4.3/linux/arch/ia64/kernel/gate.S Fri Jul 14 16:08:11 2000 +++ linux/arch/ia64/kernel/gate.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S --- v2.4.3/linux/arch/ia64/kernel/head.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/head.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/ia64_ksyms.c linux/arch/ia64/kernel/ia64_ksyms.c --- v2.4.3/linux/arch/ia64/kernel/ia64_ksyms.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/ia64_ksyms.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/iosapic.c linux/arch/ia64/kernel/iosapic.c --- v2.4.3/linux/arch/ia64/kernel/iosapic.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/iosapic.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.4.3/linux/arch/ia64/kernel/irq.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ia64/kernel/irq.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c --- v2.4.3/linux/arch/ia64/kernel/irq_ia64.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ia64/kernel/irq_ia64.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.4.3/linux/arch/ia64/kernel/ivt.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/ivt.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c --- v2.4.3/linux/arch/ia64/kernel/mca.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/kernel/mca.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S --- v2.4.3/linux/arch/ia64/kernel/mca_asm.S Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/kernel/mca_asm.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/minstate.h linux/arch/ia64/kernel/minstate.h --- v2.4.3/linux/arch/ia64/kernel/minstate.h Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/minstate.h Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/pal.S linux/arch/ia64/kernel/pal.S --- v2.4.3/linux/arch/ia64/kernel/pal.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/pal.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/palinfo.c linux/arch/ia64/kernel/palinfo.c --- v2.4.3/linux/arch/ia64/kernel/palinfo.c Fri Feb 16 15:53:08 2001 +++ linux/arch/ia64/kernel/palinfo.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c --- v2.4.3/linux/arch/ia64/kernel/perfmon.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/perfmon.c Fri Apr 13 15:29:37 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- v2.4.3/linux/arch/ia64/kernel/process.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/process.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.4.3/linux/arch/ia64/kernel/ptrace.c Tue Feb 13 14:13:43 2001 +++ linux/arch/ia64/kernel/ptrace.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/semaphore.c linux/arch/ia64/kernel/semaphore.c --- v2.4.3/linux/arch/ia64/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/ia64/kernel/semaphore.c Tue Apr 17 17:19:24 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c --- v2.4.3/linux/arch/ia64/kernel/setup.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/setup.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.4.3/linux/arch/ia64/kernel/signal.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/signal.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.4.3/linux/arch/ia64/kernel/smp.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/smp.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/smpboot.c linux/arch/ia64/kernel/smpboot.c --- v2.4.3/linux/arch/ia64/kernel/smpboot.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/kernel/smpboot.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c --- v2.4.3/linux/arch/ia64/kernel/sys_ia64.c Mon Mar 19 12:35:10 2001 +++ linux/arch/ia64/kernel/sys_ia64.c Fri Apr 13 15:38:51 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.4.3/linux/arch/ia64/kernel/time.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/time.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c --- v2.4.3/linux/arch/ia64/kernel/unaligned.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/unaligned.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c --- v2.4.3/linux/arch/ia64/kernel/unwind.c Tue Feb 13 14:13:43 2001 +++ linux/arch/ia64/kernel/unwind.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile --- v2.4.3/linux/arch/ia64/lib/Makefile Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/lib/Makefile Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/clear_page.S linux/arch/ia64/lib/clear_page.S --- v2.4.3/linux/arch/ia64/lib/clear_page.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/clear_page.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S --- v2.4.3/linux/arch/ia64/lib/clear_user.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/clear_user.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/copy_page.S linux/arch/ia64/lib/copy_page.S --- v2.4.3/linux/arch/ia64/lib/copy_page.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/copy_page.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.4.3/linux/arch/ia64/lib/copy_user.S Tue Mar 6 19:44:35 2001 +++ linux/arch/ia64/lib/copy_user.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/csum_partial_copy.c linux/arch/ia64/lib/csum_partial_copy.c --- v2.4.3/linux/arch/ia64/lib/csum_partial_copy.c Sun Feb 6 18:42:40 2000 +++ linux/arch/ia64/lib/csum_partial_copy.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/do_csum.S linux/arch/ia64/lib/do_csum.S --- v2.4.3/linux/arch/ia64/lib/do_csum.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/do_csum.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/flush.S linux/arch/ia64/lib/flush.S --- v2.4.3/linux/arch/ia64/lib/flush.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/lib/flush.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/idiv64.S linux/arch/ia64/lib/idiv64.S --- v2.4.3/linux/arch/ia64/lib/idiv64.S Mon Oct 9 17:54:56 2000 +++ linux/arch/ia64/lib/idiv64.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/memcpy.S linux/arch/ia64/lib/memcpy.S --- v2.4.3/linux/arch/ia64/lib/memcpy.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/lib/memcpy.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/memset.S linux/arch/ia64/lib/memset.S --- v2.4.3/linux/arch/ia64/lib/memset.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/memset.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S --- v2.4.3/linux/arch/ia64/lib/strlen.S Tue Mar 6 19:44:35 2001 +++ linux/arch/ia64/lib/strlen.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/strlen_user.S linux/arch/ia64/lib/strlen_user.S --- v2.4.3/linux/arch/ia64/lib/strlen_user.S Tue Mar 6 19:44:35 2001 +++ linux/arch/ia64/lib/strlen_user.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/strncpy_from_user.S linux/arch/ia64/lib/strncpy_from_user.S --- v2.4.3/linux/arch/ia64/lib/strncpy_from_user.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/strncpy_from_user.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/strnlen_user.S linux/arch/ia64/lib/strnlen_user.S --- v2.4.3/linux/arch/ia64/lib/strnlen_user.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/strnlen_user.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/lib/swiotlb.c linux/arch/ia64/lib/swiotlb.c --- v2.4.3/linux/arch/ia64/lib/swiotlb.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/lib/swiotlb.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/mm/extable.c linux/arch/ia64/mm/extable.c --- v2.4.3/linux/arch/ia64/mm/extable.c Sun Feb 6 18:42:40 2000 +++ linux/arch/ia64/mm/extable.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c --- v2.4.3/linux/arch/ia64/mm/fault.c Mon Mar 19 12:35:10 2001 +++ linux/arch/ia64/mm/fault.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c --- v2.4.3/linux/arch/ia64/mm/init.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/mm/init.c Thu Apr 5 12:51:47 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,33 @@ #include #include #include +#include /* 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); -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); +unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; - 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; -} +static unsigned long totalram_pages; 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 +105,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 +118,8 @@ * | | * | | * | | 9000 - * |/////////////| - * |/////////////| + * |/////////////| + * |/////////////| * |=============| 8000 * |///INITRD////| * |/////////////| @@ -211,9 +128,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 +203,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 +280,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 +298,8 @@ * enabled. */ ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); + + ia64_tlb_init(); } /* @@ -390,7 +316,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 --recursive --new-file v2.4.3/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c --- v2.4.3/linux/arch/ia64/mm/tlb.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/mm/tlb.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/Makefile linux/arch/ia64/sn/Makefile --- v2.4.3/linux/arch/ia64/sn/Makefile Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/Makefile Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/fprom/Makefile linux/arch/ia64/sn/fprom/Makefile --- v2.4.3/linux/arch/ia64/sn/fprom/Makefile Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/fprom/Makefile Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/fprom/fw-emu.c linux/arch/ia64/sn/fprom/fw-emu.c --- v2.4.3/linux/arch/ia64/sn/fprom/fw-emu.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/fprom/fw-emu.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/Makefile linux/arch/ia64/sn/io/Makefile --- v2.4.3/linux/arch/ia64/sn/io/Makefile Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/Makefile Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/alenlist.c linux/arch/ia64/sn/io/alenlist.c --- v2.4.3/linux/arch/ia64/sn/io/alenlist.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/alenlist.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/cdl.c linux/arch/ia64/sn/io/cdl.c --- v2.4.3/linux/arch/ia64/sn/io/cdl.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/cdl.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/devsupport.c linux/arch/ia64/sn/io/devsupport.c --- v2.4.3/linux/arch/ia64/sn/io/devsupport.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/devsupport.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hcl.c linux/arch/ia64/sn/io/hcl.c --- v2.4.3/linux/arch/ia64/sn/io/hcl.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/hcl.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hcl_util.c linux/arch/ia64/sn/io/hcl_util.c --- v2.4.3/linux/arch/ia64/sn/io/hcl_util.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/hcl_util.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hubdev.c linux/arch/ia64/sn/io/hubdev.c --- v2.4.3/linux/arch/ia64/sn/io/hubdev.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/hubdev.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/huberror.c linux/arch/ia64/sn/io/huberror.c --- v2.4.3/linux/arch/ia64/sn/io/huberror.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/io/huberror.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hubspc.c linux/arch/ia64/sn/io/hubspc.c --- v2.4.3/linux/arch/ia64/sn/io/hubspc.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/hubspc.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/invent.c linux/arch/ia64/sn/io/invent.c --- v2.4.3/linux/arch/ia64/sn/io/invent.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/invent.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/io.c linux/arch/ia64/sn/io/io.c --- v2.4.3/linux/arch/ia64/sn/io/io.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/io.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ip37.c linux/arch/ia64/sn/io/ip37.c --- v2.4.3/linux/arch/ia64/sn/io/ip37.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/ip37.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/klconflib.c linux/arch/ia64/sn/io/klconflib.c --- v2.4.3/linux/arch/ia64/sn/io/klconflib.c Fri Feb 16 16:02:34 2001 +++ linux/arch/ia64/sn/io/klconflib.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/klgraph.c linux/arch/ia64/sn/io/klgraph.c --- v2.4.3/linux/arch/ia64/sn/io/klgraph.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/klgraph.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/klgraph_hack.c linux/arch/ia64/sn/io/klgraph_hack.c --- v2.4.3/linux/arch/ia64/sn/io/klgraph_hack.c Fri Feb 16 16:02:34 2001 +++ linux/arch/ia64/sn/io/klgraph_hack.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/l1.c linux/arch/ia64/sn/io/l1.c --- v2.4.3/linux/arch/ia64/sn/io/l1.c Tue Mar 6 19:44:35 2001 +++ linux/arch/ia64/sn/io/l1.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/l1_command.c linux/arch/ia64/sn/io/l1_command.c --- v2.4.3/linux/arch/ia64/sn/io/l1_command.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/l1_command.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/labelcl.c linux/arch/ia64/sn/io/labelcl.c --- v2.4.3/linux/arch/ia64/sn/io/labelcl.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/labelcl.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/mem_refcnt.c linux/arch/ia64/sn/io/mem_refcnt.c --- v2.4.3/linux/arch/ia64/sn/io/mem_refcnt.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/mem_refcnt.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ml_SN_init.c linux/arch/ia64/sn/io/ml_SN_init.c --- v2.4.3/linux/arch/ia64/sn/io/ml_SN_init.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/ml_SN_init.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ml_SN_intr.c linux/arch/ia64/sn/io/ml_SN_intr.c --- v2.4.3/linux/arch/ia64/sn/io/ml_SN_intr.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/ml_SN_intr.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/module.c linux/arch/ia64/sn/io/module.c --- v2.4.3/linux/arch/ia64/sn/io/module.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/module.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pci.c linux/arch/ia64/sn/io/pci.c --- v2.4.3/linux/arch/ia64/sn/io/pci.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/pci.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pci_bus_cvlink.c linux/arch/ia64/sn/io/pci_bus_cvlink.c --- v2.4.3/linux/arch/ia64/sn/io/pci_bus_cvlink.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/pci_bus_cvlink.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pci_dma.c linux/arch/ia64/sn/io/pci_dma.c --- v2.4.3/linux/arch/ia64/sn/io/pci_dma.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/pci_dma.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pciba.c linux/arch/ia64/sn/io/pciba.c --- v2.4.3/linux/arch/ia64/sn/io/pciba.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/io/pciba.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pcibr.c linux/arch/ia64/sn/io/pcibr.c --- v2.4.3/linux/arch/ia64/sn/io/pcibr.c Tue Mar 6 19:44:35 2001 +++ linux/arch/ia64/sn/io/pcibr.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pciio.c linux/arch/ia64/sn/io/pciio.c --- v2.4.3/linux/arch/ia64/sn/io/pciio.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/pciio.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/sgi_if.c linux/arch/ia64/sn/io/sgi_if.c --- v2.4.3/linux/arch/ia64/sn/io/sgi_if.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/sgi_if.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/sgi_io_init.c linux/arch/ia64/sn/io/sgi_io_init.c --- v2.4.3/linux/arch/ia64/sn/io/sgi_io_init.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/sgi_io_init.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/sgi_io_sim.c linux/arch/ia64/sn/io/sgi_io_sim.c --- v2.4.3/linux/arch/ia64/sn/io/sgi_io_sim.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/sgi_io_sim.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/stubs.c linux/arch/ia64/sn/io/stubs.c --- v2.4.3/linux/arch/ia64/sn/io/stubs.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/stubs.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/xbow.c linux/arch/ia64/sn/io/xbow.c --- v2.4.3/linux/arch/ia64/sn/io/xbow.c Tue Feb 13 14:13:43 2001 +++ linux/arch/ia64/sn/io/xbow.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/xswitch.c linux/arch/ia64/sn/io/xswitch.c --- v2.4.3/linux/arch/ia64/sn/io/xswitch.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/xswitch.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/xtalk.c linux/arch/ia64/sn/io/xtalk.c --- v2.4.3/linux/arch/ia64/sn/io/xtalk.c Tue Feb 13 14:13:43 2001 +++ linux/arch/ia64/sn/io/xtalk.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/Makefile linux/arch/ia64/sn/sn1/Makefile --- v2.4.3/linux/arch/ia64/sn/sn1/Makefile Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/sn1/Makefile Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/discontig.c linux/arch/ia64/sn/sn1/discontig.c --- v2.4.3/linux/arch/ia64/sn/sn1/discontig.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/sn1/discontig.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/irq.c linux/arch/ia64/sn/sn1/irq.c --- v2.4.3/linux/arch/ia64/sn/sn1/irq.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/sn1/irq.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/llsc4.c linux/arch/ia64/sn/sn1/llsc4.c --- v2.4.3/linux/arch/ia64/sn/sn1/llsc4.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/sn1/llsc4.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/machvec.c linux/arch/ia64/sn/sn1/machvec.c --- v2.4.3/linux/arch/ia64/sn/sn1/machvec.c Fri Aug 11 19:09:06 2000 +++ linux/arch/ia64/sn/sn1/machvec.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/mm.c linux/arch/ia64/sn/sn1/mm.c --- v2.4.3/linux/arch/ia64/sn/sn1/mm.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/sn1/mm.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/setup.c linux/arch/ia64/sn/sn1/setup.c --- v2.4.3/linux/arch/ia64/sn/sn1/setup.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/sn1/setup.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/smp.c linux/arch/ia64/sn/sn1/smp.c --- v2.4.3/linux/arch/ia64/sn/sn1/smp.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/sn1/smp.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/sn1_asm.S linux/arch/ia64/sn/sn1/sn1_asm.S --- v2.4.3/linux/arch/ia64/sn/sn1/sn1_asm.S Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/sn1/sn1_asm.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/sn1_ksyms.c linux/arch/ia64/sn/sn1/sn1_ksyms.c --- v2.4.3/linux/arch/ia64/sn/sn1/sn1_ksyms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/sn1_ksyms.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/sv.c linux/arch/ia64/sn/sn1/sv.c --- v2.4.3/linux/arch/ia64/sn/sn1/sv.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/sv.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/synergy.c linux/arch/ia64/sn/sn1/synergy.c --- v2.4.3/linux/arch/ia64/sn/sn1/synergy.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/sn1/synergy.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/tools/print_offsets.awk linux/arch/ia64/tools/print_offsets.awk --- v2.4.3/linux/arch/ia64/tools/print_offsets.awk Fri Jul 14 16:08:12 2000 +++ linux/arch/ia64/tools/print_offsets.awk Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c --- v2.4.3/linux/arch/ia64/tools/print_offsets.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/tools/print_offsets.c Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S --- v2.4.3/linux/arch/ia64/vmlinux.lds.S Fri Aug 11 19:09:06 2000 +++ linux/arch/ia64/vmlinux.lds.S Thu Apr 5 12:51:47 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 --recursive --new-file v2.4.3/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v2.4.3/linux/arch/m68k/amiga/config.c Thu Jan 4 13:00:55 2001 +++ linux/arch/m68k/amiga/config.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.4.3/linux/arch/m68k/config.in Thu Jan 4 13:00:55 2001 +++ linux/arch/m68k/config.in Tue Apr 17 17:19:25 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 --recursive --new-file v2.4.3/linux/arch/m68k/ifpsp060/src/fpsp.S linux/arch/m68k/ifpsp060/src/fpsp.S --- v2.4.3/linux/arch/m68k/ifpsp060/src/fpsp.S Tue Mar 6 19:44:35 2001 +++ linux/arch/m68k/ifpsp060/src/fpsp.S Fri Apr 6 10:42:47 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 --recursive --new-file v2.4.3/linux/arch/m68k/ifpsp060/src/pfpsp.S linux/arch/m68k/ifpsp060/src/pfpsp.S --- v2.4.3/linux/arch/m68k/ifpsp060/src/pfpsp.S Tue Mar 6 19:44:36 2001 +++ linux/arch/m68k/ifpsp060/src/pfpsp.S Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/arch/m68k/kernel/semaphore.c linux/arch/m68k/kernel/semaphore.c --- v2.4.3/linux/arch/m68k/kernel/semaphore.c Fri Dec 29 14:07:20 2000 +++ linux/arch/m68k/kernel/semaphore.c Tue Apr 17 17:19:25 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 --recursive --new-file v2.4.3/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.4.3/linux/arch/m68k/kernel/setup.c Thu Jan 4 13:00:55 2001 +++ linux/arch/m68k/kernel/setup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/m68k/mm/motorola.c linux/arch/m68k/mm/motorola.c --- v2.4.3/linux/arch/m68k/mm/motorola.c Mon Aug 7 21:02:27 2000 +++ linux/arch/m68k/mm/motorola.c Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c --- v2.4.3/linux/arch/m68k/q40/config.c Tue Mar 6 19:44:36 2001 +++ linux/arch/m68k/q40/config.c Fri Apr 6 10:42:48 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 --recursive --new-file v2.4.3/linux/arch/mips/Makefile linux/arch/mips/Makefile --- v2.4.3/linux/arch/mips/Makefile Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/Makefile linux/arch/mips/arc/Makefile --- v2.4.3/linux/arch/mips/arc/Makefile Sat May 13 08:29:14 2000 +++ linux/arch/mips/arc/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/arc_con.c linux/arch/mips/arc/arc_con.c --- v2.4.3/linux/arch/mips/arc/arc_con.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/arc_con.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/cmdline.c linux/arch/mips/arc/cmdline.c --- v2.4.3/linux/arch/mips/arc/cmdline.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/arc/cmdline.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/console.c linux/arch/mips/arc/console.c --- v2.4.3/linux/arch/mips/arc/console.c Mon Feb 28 07:18:20 2000 +++ linux/arch/mips/arc/console.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/identify.c linux/arch/mips/arc/identify.c --- v2.4.3/linux/arch/mips/arc/identify.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/arc/identify.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/init.c linux/arch/mips/arc/init.c --- v2.4.3/linux/arch/mips/arc/init.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/arc/init.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/memory.c linux/arch/mips/arc/memory.c --- v2.4.3/linux/arch/mips/arc/memory.c Mon Aug 7 21:02:27 2000 +++ linux/arch/mips/arc/memory.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/misc.c linux/arch/mips/arc/misc.c --- v2.4.3/linux/arch/mips/arc/misc.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/arc/misc.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/arc/printf.c linux/arch/mips/arc/printf.c --- v2.4.3/linux/arch/mips/arc/printf.c Mon Feb 28 07:18:20 2000 +++ linux/arch/mips/arc/printf.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/baget/Makefile linux/arch/mips/baget/Makefile --- v2.4.3/linux/arch/mips/baget/Makefile Sat May 13 08:29:14 2000 +++ linux/arch/mips/baget/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/baget/prom/Makefile linux/arch/mips/baget/prom/Makefile --- v2.4.3/linux/arch/mips/baget/prom/Makefile Sat May 13 08:29:14 2000 +++ linux/arch/mips/baget/prom/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.4.3/linux/arch/mips/config.in Thu Nov 16 12:51:28 2000 +++ linux/arch/mips/config.in Tue Apr 17 17:19:25 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. # @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/Makefile linux/arch/mips/ddb5074/Makefile --- v2.4.3/linux/arch/mips/ddb5074/Makefile Sat May 13 08:29:14 2000 +++ linux/arch/mips/ddb5074/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/int-handler.S linux/arch/mips/ddb5074/int-handler.S --- v2.4.3/linux/arch/mips/ddb5074/int-handler.S Sat May 13 08:29:14 2000 +++ linux/arch/mips/ddb5074/int-handler.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/irq.c linux/arch/mips/ddb5074/irq.c --- v2.4.3/linux/arch/mips/ddb5074/irq.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/ddb5074/irq.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/nile4.c linux/arch/mips/ddb5074/nile4.c --- v2.4.3/linux/arch/mips/ddb5074/nile4.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/ddb5074/nile4.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/pci-dma.c linux/arch/mips/ddb5074/pci-dma.c --- v2.4.3/linux/arch/mips/ddb5074/pci-dma.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/ddb5074/pci-dma.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/pci.c linux/arch/mips/ddb5074/pci.c --- v2.4.3/linux/arch/mips/ddb5074/pci.c Mon Nov 27 17:51:34 2000 +++ linux/arch/mips/ddb5074/pci.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/prom.c linux/arch/mips/ddb5074/prom.c --- v2.4.3/linux/arch/mips/ddb5074/prom.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/ddb5074/prom.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/setup.c linux/arch/mips/ddb5074/setup.c --- v2.4.3/linux/arch/mips/ddb5074/setup.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/ddb5074/setup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/time.c linux/arch/mips/ddb5074/time.c --- v2.4.3/linux/arch/mips/ddb5074/time.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/ddb5074/time.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/Makefile linux/arch/mips/ddb5476/Makefile --- v2.4.3/linux/arch/mips/ddb5476/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/dbg_io.c linux/arch/mips/ddb5476/dbg_io.c --- v2.4.3/linux/arch/mips/ddb5476/dbg_io.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/dbg_io.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/int-handler.S linux/arch/mips/ddb5476/int-handler.S --- v2.4.3/linux/arch/mips/ddb5476/int-handler.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/int-handler.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/irq.c linux/arch/mips/ddb5476/irq.c --- v2.4.3/linux/arch/mips/ddb5476/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/irq.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/nile4.c linux/arch/mips/ddb5476/nile4.c --- v2.4.3/linux/arch/mips/ddb5476/nile4.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/nile4.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/pci.c linux/arch/mips/ddb5476/pci.c --- v2.4.3/linux/arch/mips/ddb5476/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/pci.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/prom.c linux/arch/mips/ddb5476/prom.c --- v2.4.3/linux/arch/mips/ddb5476/prom.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/prom.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/setup.c linux/arch/mips/ddb5476/setup.c --- v2.4.3/linux/arch/mips/ddb5476/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/setup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/time.c linux/arch/mips/ddb5476/time.c --- v2.4.3/linux/arch/mips/ddb5476/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5476/time.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/dec/Makefile linux/arch/mips/dec/Makefile --- v2.4.3/linux/arch/mips/dec/Makefile Thu Feb 24 22:52:30 2000 +++ linux/arch/mips/dec/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/dec/boot/Makefile linux/arch/mips/dec/boot/Makefile --- v2.4.3/linux/arch/mips/dec/boot/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/dec/boot/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig linux/arch/mips/defconfig --- v2.4.3/linux/arch/mips/defconfig Sun Mar 4 14:30:18 2001 +++ linux/arch/mips/defconfig Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig-cobalt linux/arch/mips/defconfig-cobalt --- v2.4.3/linux/arch/mips/defconfig-cobalt Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/defconfig-cobalt Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig-ddb5476 linux/arch/mips/defconfig-ddb5476 --- v2.4.3/linux/arch/mips/defconfig-ddb5476 Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/defconfig-ddb5476 Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig-decstation linux/arch/mips/defconfig-decstation --- v2.4.3/linux/arch/mips/defconfig-decstation Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/defconfig-decstation Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig-ip22 linux/arch/mips/defconfig-ip22 --- v2.4.3/linux/arch/mips/defconfig-ip22 Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/defconfig-ip22 Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig-it8172 linux/arch/mips/defconfig-it8172 --- v2.4.3/linux/arch/mips/defconfig-it8172 Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/defconfig-it8172 Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig-orion linux/arch/mips/defconfig-orion --- v2.4.3/linux/arch/mips/defconfig-orion Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/defconfig-orion Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/defconfig-rm200 linux/arch/mips/defconfig-rm200 --- v2.4.3/linux/arch/mips/defconfig-rm200 Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/defconfig-rm200 Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/Makefile linux/arch/mips/ite-boards/generic/Makefile --- v2.4.3/linux/arch/mips/ite-boards/generic/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/dbg_io.c linux/arch/mips/ite-boards/generic/dbg_io.c --- v2.4.3/linux/arch/mips/ite-boards/generic/dbg_io.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/dbg_io.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/int-handler.S linux/arch/mips/ite-boards/generic/int-handler.S --- v2.4.3/linux/arch/mips/ite-boards/generic/int-handler.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/int-handler.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/irq.c linux/arch/mips/ite-boards/generic/irq.c --- v2.4.3/linux/arch/mips/ite-boards/generic/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/irq.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_cir.c linux/arch/mips/ite-boards/generic/it8172_cir.c --- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_cir.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/it8172_cir.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_pci.c linux/arch/mips/ite-boards/generic/it8172_pci.c --- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/it8172_pci.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_rtc.c linux/arch/mips/ite-boards/generic/it8172_rtc.c --- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_rtc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/it8172_rtc.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_setup.c linux/arch/mips/ite-boards/generic/it8172_setup.c --- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/it8172_setup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/lpc.c linux/arch/mips/ite-boards/generic/lpc.c --- v2.4.3/linux/arch/mips/ite-boards/generic/lpc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/lpc.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/pmon_prom.c linux/arch/mips/ite-boards/generic/pmon_prom.c --- v2.4.3/linux/arch/mips/ite-boards/generic/pmon_prom.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/pmon_prom.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/puts.c linux/arch/mips/ite-boards/generic/puts.c --- v2.4.3/linux/arch/mips/ite-boards/generic/puts.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/puts.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/reset.c linux/arch/mips/ite-boards/generic/reset.c --- v2.4.3/linux/arch/mips/ite-boards/generic/reset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/reset.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/time.c linux/arch/mips/ite-boards/generic/time.c --- v2.4.3/linux/arch/mips/ite-boards/generic/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/generic/time.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/Makefile linux/arch/mips/ite-boards/qed-4n-s01b/Makefile --- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/qed-4n-s01b/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/README linux/arch/mips/ite-boards/qed-4n-s01b/README --- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/README Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/qed-4n-s01b/README Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/init.c linux/arch/mips/ite-boards/qed-4n-s01b/init.c --- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/qed-4n-s01b/init.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c --- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/jazz/Makefile linux/arch/mips/jazz/Makefile --- v2.4.3/linux/arch/mips/jazz/Makefile Sat May 13 08:29:14 2000 +++ linux/arch/mips/jazz/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/branch.c linux/arch/mips/kernel/branch.c --- v2.4.3/linux/arch/mips/kernel/branch.c Wed Dec 10 10:31:09 1997 +++ linux/arch/mips/kernel/branch.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- v2.4.3/linux/arch/mips/kernel/process.c Fri Feb 9 11:29:44 2001 +++ linux/arch/mips/kernel/process.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c --- v2.4.3/linux/arch/mips/kernel/ptrace.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/kernel/ptrace.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/r2300_fpu.S linux/arch/mips/kernel/r2300_fpu.S --- v2.4.3/linux/arch/mips/kernel/r2300_fpu.S Sat May 13 08:29:14 2000 +++ linux/arch/mips/kernel/r2300_fpu.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/r2300_switch.S linux/arch/mips/kernel/r2300_switch.S --- v2.4.3/linux/arch/mips/kernel/r2300_switch.S Sat May 13 08:29:14 2000 +++ linux/arch/mips/kernel/r2300_switch.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/r4k_fpu.S linux/arch/mips/kernel/r4k_fpu.S --- v2.4.3/linux/arch/mips/kernel/r4k_fpu.S Sat May 13 08:29:14 2000 +++ linux/arch/mips/kernel/r4k_fpu.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S --- v2.4.3/linux/arch/mips/kernel/r4k_misc.S Sat May 13 08:29:14 2000 +++ linux/arch/mips/kernel/r4k_misc.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/r4k_switch.S linux/arch/mips/kernel/r4k_switch.S --- v2.4.3/linux/arch/mips/kernel/r4k_switch.S Sat May 13 08:29:14 2000 +++ linux/arch/mips/kernel/r4k_switch.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/r6000_fpu.S linux/arch/mips/kernel/r6000_fpu.S --- v2.4.3/linux/arch/mips/kernel/r6000_fpu.S Sat May 13 08:29:14 2000 +++ linux/arch/mips/kernel/r6000_fpu.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/semaphore.c linux/arch/mips/kernel/semaphore.c --- v2.4.3/linux/arch/mips/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/mips/kernel/semaphore.c Tue Apr 17 17:19:25 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c --- v2.4.3/linux/arch/mips/kernel/setup.c Fri Feb 9 11:29:44 2001 +++ linux/arch/mips/kernel/setup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c --- v2.4.3/linux/arch/mips/kernel/signal.c Wed Jan 24 15:20:59 2001 +++ linux/arch/mips/kernel/signal.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c --- v2.4.3/linux/arch/mips/kernel/traps.c Sun Dec 3 17:48:19 2000 +++ linux/arch/mips/kernel/traps.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/lib/Makefile linux/arch/mips/lib/Makefile --- v2.4.3/linux/arch/mips/lib/Makefile Tue Dec 5 23:15:12 2000 +++ linux/arch/mips/lib/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/lib/kbd-std.c linux/arch/mips/lib/kbd-std.c --- v2.4.3/linux/arch/mips/lib/kbd-std.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/lib/kbd-std.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/Makefile linux/arch/mips/math-emu/Makefile --- v2.4.3/linux/arch/mips/math-emu/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/cp1emu.c linux/arch/mips/math-emu/cp1emu.c --- v2.4.3/linux/arch/mips/math-emu/cp1emu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/cp1emu.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_add.c linux/arch/mips/math-emu/dp_add.c --- v2.4.3/linux/arch/mips/math-emu/dp_add.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_add.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_cmp.c linux/arch/mips/math-emu/dp_cmp.c --- v2.4.3/linux/arch/mips/math-emu/dp_cmp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_cmp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_div.c linux/arch/mips/math-emu/dp_div.c --- v2.4.3/linux/arch/mips/math-emu/dp_div.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_div.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_fint.c linux/arch/mips/math-emu/dp_fint.c --- v2.4.3/linux/arch/mips/math-emu/dp_fint.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_fint.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_flong.c linux/arch/mips/math-emu/dp_flong.c --- v2.4.3/linux/arch/mips/math-emu/dp_flong.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_flong.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_frexp.c linux/arch/mips/math-emu/dp_frexp.c --- v2.4.3/linux/arch/mips/math-emu/dp_frexp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_frexp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_fsp.c linux/arch/mips/math-emu/dp_fsp.c --- v2.4.3/linux/arch/mips/math-emu/dp_fsp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_fsp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_logb.c linux/arch/mips/math-emu/dp_logb.c --- v2.4.3/linux/arch/mips/math-emu/dp_logb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_logb.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_modf.c linux/arch/mips/math-emu/dp_modf.c --- v2.4.3/linux/arch/mips/math-emu/dp_modf.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_modf.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_mul.c linux/arch/mips/math-emu/dp_mul.c --- v2.4.3/linux/arch/mips/math-emu/dp_mul.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_mul.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_scalb.c linux/arch/mips/math-emu/dp_scalb.c --- v2.4.3/linux/arch/mips/math-emu/dp_scalb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_scalb.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_simple.c linux/arch/mips/math-emu/dp_simple.c --- v2.4.3/linux/arch/mips/math-emu/dp_simple.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_simple.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_sqrt.c linux/arch/mips/math-emu/dp_sqrt.c --- v2.4.3/linux/arch/mips/math-emu/dp_sqrt.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_sqrt.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_sub.c linux/arch/mips/math-emu/dp_sub.c --- v2.4.3/linux/arch/mips/math-emu/dp_sub.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_sub.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_tint.c linux/arch/mips/math-emu/dp_tint.c --- v2.4.3/linux/arch/mips/math-emu/dp_tint.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_tint.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_tlong.c linux/arch/mips/math-emu/dp_tlong.c --- v2.4.3/linux/arch/mips/math-emu/dp_tlong.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/dp_tlong.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754.c linux/arch/mips/math-emu/ieee754.c --- v2.4.3/linux/arch/mips/math-emu/ieee754.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754.h linux/arch/mips/math-emu/ieee754.h --- v2.4.3/linux/arch/mips/math-emu/ieee754.h Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754.h Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754d.c linux/arch/mips/math-emu/ieee754d.c --- v2.4.3/linux/arch/mips/math-emu/ieee754d.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754d.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754dp.c linux/arch/mips/math-emu/ieee754dp.c --- v2.4.3/linux/arch/mips/math-emu/ieee754dp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754dp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754dp.h linux/arch/mips/math-emu/ieee754dp.h --- v2.4.3/linux/arch/mips/math-emu/ieee754dp.h Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754dp.h Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754int.h linux/arch/mips/math-emu/ieee754int.h --- v2.4.3/linux/arch/mips/math-emu/ieee754int.h Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754int.h Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754m.c linux/arch/mips/math-emu/ieee754m.c --- v2.4.3/linux/arch/mips/math-emu/ieee754m.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754m.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754sp.c linux/arch/mips/math-emu/ieee754sp.c --- v2.4.3/linux/arch/mips/math-emu/ieee754sp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754sp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754sp.h linux/arch/mips/math-emu/ieee754sp.h --- v2.4.3/linux/arch/mips/math-emu/ieee754sp.h Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754sp.h Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754xcpt.c linux/arch/mips/math-emu/ieee754xcpt.c --- v2.4.3/linux/arch/mips/math-emu/ieee754xcpt.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/ieee754xcpt.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/kernel_linkage.c linux/arch/mips/math-emu/kernel_linkage.c --- v2.4.3/linux/arch/mips/math-emu/kernel_linkage.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/kernel_linkage.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_add.c linux/arch/mips/math-emu/sp_add.c --- v2.4.3/linux/arch/mips/math-emu/sp_add.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_add.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_cmp.c linux/arch/mips/math-emu/sp_cmp.c --- v2.4.3/linux/arch/mips/math-emu/sp_cmp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_cmp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_div.c linux/arch/mips/math-emu/sp_div.c --- v2.4.3/linux/arch/mips/math-emu/sp_div.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_div.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_fdp.c linux/arch/mips/math-emu/sp_fdp.c --- v2.4.3/linux/arch/mips/math-emu/sp_fdp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_fdp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_fint.c linux/arch/mips/math-emu/sp_fint.c --- v2.4.3/linux/arch/mips/math-emu/sp_fint.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_fint.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_flong.c linux/arch/mips/math-emu/sp_flong.c --- v2.4.3/linux/arch/mips/math-emu/sp_flong.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_flong.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_frexp.c linux/arch/mips/math-emu/sp_frexp.c --- v2.4.3/linux/arch/mips/math-emu/sp_frexp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_frexp.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_logb.c linux/arch/mips/math-emu/sp_logb.c --- v2.4.3/linux/arch/mips/math-emu/sp_logb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_logb.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_modf.c linux/arch/mips/math-emu/sp_modf.c --- v2.4.3/linux/arch/mips/math-emu/sp_modf.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_modf.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_mul.c linux/arch/mips/math-emu/sp_mul.c --- v2.4.3/linux/arch/mips/math-emu/sp_mul.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_mul.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_scalb.c linux/arch/mips/math-emu/sp_scalb.c --- v2.4.3/linux/arch/mips/math-emu/sp_scalb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_scalb.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_simple.c linux/arch/mips/math-emu/sp_simple.c --- v2.4.3/linux/arch/mips/math-emu/sp_simple.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_simple.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_sqrt.c linux/arch/mips/math-emu/sp_sqrt.c --- v2.4.3/linux/arch/mips/math-emu/sp_sqrt.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_sqrt.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_sub.c linux/arch/mips/math-emu/sp_sub.c --- v2.4.3/linux/arch/mips/math-emu/sp_sub.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_sub.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_tint.c linux/arch/mips/math-emu/sp_tint.c --- v2.4.3/linux/arch/mips/math-emu/sp_tint.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_tint.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_tlong.c linux/arch/mips/math-emu/sp_tlong.c --- v2.4.3/linux/arch/mips/math-emu/sp_tlong.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/math-emu/sp_tlong.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/Makefile linux/arch/mips/mips-boards/atlas/Makefile --- v2.4.3/linux/arch/mips/mips-boards/atlas/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/atlas/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_int.c linux/arch/mips/mips-boards/atlas/atlas_int.c --- v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_int.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/atlas/atlas_int.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_rtc.c linux/arch/mips/mips-boards/atlas/atlas_rtc.c --- v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_rtc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/atlas/atlas_rtc.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_setup.c linux/arch/mips/mips-boards/atlas/atlas_setup.c --- v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/atlas/atlas_setup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/Makefile linux/arch/mips/mips-boards/generic/Makefile --- v2.4.3/linux/arch/mips/mips-boards/generic/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/cmdline.c linux/arch/mips/mips-boards/generic/cmdline.c --- v2.4.3/linux/arch/mips/mips-boards/generic/cmdline.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/cmdline.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/display.c linux/arch/mips/mips-boards/generic/display.c --- v2.4.3/linux/arch/mips/mips-boards/generic/display.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/display.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/gdb_hook.c linux/arch/mips/mips-boards/generic/gdb_hook.c --- v2.4.3/linux/arch/mips/mips-boards/generic/gdb_hook.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/gdb_hook.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/init.c linux/arch/mips/mips-boards/generic/init.c --- v2.4.3/linux/arch/mips/mips-boards/generic/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/init.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/memory.c linux/arch/mips/mips-boards/generic/memory.c --- v2.4.3/linux/arch/mips/mips-boards/generic/memory.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/memory.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/mipsIRQ.S linux/arch/mips/mips-boards/generic/mipsIRQ.S --- v2.4.3/linux/arch/mips/mips-boards/generic/mipsIRQ.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/mipsIRQ.S Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/pci.c linux/arch/mips/mips-boards/generic/pci.c --- v2.4.3/linux/arch/mips/mips-boards/generic/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/pci.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/printf.c linux/arch/mips/mips-boards/generic/printf.c --- v2.4.3/linux/arch/mips/mips-boards/generic/printf.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/printf.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/reset.c linux/arch/mips/mips-boards/generic/reset.c --- v2.4.3/linux/arch/mips/mips-boards/generic/reset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/reset.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/time.c linux/arch/mips/mips-boards/generic/time.c --- v2.4.3/linux/arch/mips/mips-boards/generic/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/generic/time.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/Makefile linux/arch/mips/mips-boards/malta/Makefile --- v2.4.3/linux/arch/mips/mips-boards/malta/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/malta/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/malta_int.c linux/arch/mips/mips-boards/malta/malta_int.c --- v2.4.3/linux/arch/mips/mips-boards/malta/malta_int.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/malta/malta_int.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/malta_rtc.c linux/arch/mips/mips-boards/malta/malta_rtc.c --- v2.4.3/linux/arch/mips/mips-boards/malta/malta_rtc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/malta/malta_rtc.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/malta_setup.c linux/arch/mips/mips-boards/malta/malta_setup.c --- v2.4.3/linux/arch/mips/mips-boards/malta/malta_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mips-boards/malta/malta_setup.c Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile --- v2.4.3/linux/arch/mips/mm/Makefile Thu Feb 24 22:52:30 2000 +++ linux/arch/mips/mm/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/orion/Makefile linux/arch/mips/orion/Makefile --- v2.4.3/linux/arch/mips/orion/Makefile Tue Jul 11 11:14:48 2000 +++ linux/arch/mips/orion/Makefile Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/orion/int-handler.S linux/arch/mips/orion/int-handler.S --- v2.4.3/linux/arch/mips/orion/int-handler.S Tue Jul 11 11:14:48 2000 +++ linux/arch/mips/orion/int-handler.S Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/orion/irq.c linux/arch/mips/orion/irq.c --- v2.4.3/linux/arch/mips/orion/irq.c Fri Feb 9 11:29:44 2001 +++ linux/arch/mips/orion/irq.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/orion/ld.script.orion linux/arch/mips/orion/ld.script.orion --- v2.4.3/linux/arch/mips/orion/ld.script.orion Tue Jul 11 11:14:48 2000 +++ linux/arch/mips/orion/ld.script.orion Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/orion/misc.c linux/arch/mips/orion/misc.c --- v2.4.3/linux/arch/mips/orion/misc.c Fri Feb 9 11:29:44 2001 +++ linux/arch/mips/orion/misc.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/orion/no_initrd.c linux/arch/mips/orion/no_initrd.c --- v2.4.3/linux/arch/mips/orion/no_initrd.c Tue Jul 11 11:14:48 2000 +++ linux/arch/mips/orion/no_initrd.c Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -unsigned long *orion_initrd_start = 0; -unsigned long orion_initrd_size = 0; diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/piggyback.c linux/arch/mips/orion/piggyback.c --- v2.4.3/linux/arch/mips/orion/piggyback.c Tue Jul 11 11:14:48 2000 +++ linux/arch/mips/orion/piggyback.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/orion/promcon.c linux/arch/mips/orion/promcon.c --- v2.4.3/linux/arch/mips/orion/promcon.c Thu Oct 12 14:20:48 2000 +++ linux/arch/mips/orion/promcon.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/orion/setup.c linux/arch/mips/orion/setup.c --- v2.4.3/linux/arch/mips/orion/setup.c Fri Feb 9 11:29:44 2001 +++ linux/arch/mips/orion/setup.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/mips/sgi/kernel/Makefile linux/arch/mips/sgi/kernel/Makefile --- v2.4.3/linux/arch/mips/sgi/kernel/Makefile Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/sgi/kernel/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips/sni/Makefile linux/arch/mips/sni/Makefile --- v2.4.3/linux/arch/mips/sni/Makefile Sat May 13 08:29:14 2000 +++ linux/arch/mips/sni/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips64/config.in linux/arch/mips64/config.in --- v2.4.3/linux/arch/mips64/config.in Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/config.in Tue Apr 17 17:19:25 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 # diff -u --recursive --new-file v2.4.3/linux/arch/mips64/defconfig linux/arch/mips64/defconfig --- v2.4.3/linux/arch/mips64/defconfig Sun Mar 4 14:30:18 2001 +++ linux/arch/mips64/defconfig Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips64/defconfig-ip22 linux/arch/mips64/defconfig-ip22 --- v2.4.3/linux/arch/mips64/defconfig-ip22 Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/defconfig-ip22 Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips64/defconfig-ip27 linux/arch/mips64/defconfig-ip27 --- v2.4.3/linux/arch/mips64/defconfig-ip27 Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/defconfig-ip27 Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips64/kernel/semaphore.c linux/arch/mips64/kernel/semaphore.c --- v2.4.3/linux/arch/mips64/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/mips64/kernel/semaphore.c Tue Apr 17 17:19:25 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 --recursive --new-file v2.4.3/linux/arch/mips64/mm/Makefile linux/arch/mips64/mm/Makefile --- v2.4.3/linux/arch/mips64/mm/Makefile Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/mm/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/mips64/tools/Makefile linux/arch/mips64/tools/Makefile --- v2.4.3/linux/arch/mips64/tools/Makefile Sun Jul 9 22:18:16 2000 +++ linux/arch/mips64/tools/Makefile Fri Apr 13 20:26:07 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 --recursive --new-file v2.4.3/linux/arch/parisc/config.in linux/arch/parisc/config.in --- v2.4.3/linux/arch/parisc/config.in Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/config.in Tue Apr 17 17:19:25 2001 @@ -7,6 +7,8 @@ define_bool CONFIG_PARISC y define_bool CONFIG_UID16 n +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n mainmenu_option next_comment comment 'Code maturity level options' diff -u --recursive --new-file v2.4.3/linux/arch/parisc/kernel/semaphore.c linux/arch/parisc/kernel/semaphore.c --- v2.4.3/linux/arch/parisc/kernel/semaphore.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/kernel/semaphore.c Tue Apr 17 17:19:25 2001 @@ -129,111 +129,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 | TASK_EXCLUSIVE); - if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to aquire 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 | TASK_EXCLUSIVE); - 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 --recursive --new-file v2.4.3/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.4.3/linux/arch/ppc/config.in Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/config.in Tue Apr 17 17:19:25 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" diff -u --recursive --new-file v2.4.3/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.4.3/linux/arch/ppc/kernel/chrp_setup.c Tue Mar 6 19:28:35 2001 +++ linux/arch/ppc/kernel/chrp_setup.c Fri Apr 27 14:10:32 2001 @@ -95,12 +95,6 @@ unsigned long empty_zero_page[1024]; -#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 - static const char *gg2_memtypes[4] = { "FPM", "SDRAM", "EDO", "BEDO" }; diff -u --recursive --new-file v2.4.3/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c --- v2.4.3/linux/arch/ppc/kernel/m8260_setup.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/m8260_setup.c Fri Apr 27 14:10:32 2001 @@ -67,12 +67,6 @@ unsigned char __res[sizeof(bd_t)]; unsigned long empty_zero_page[1024]; -#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 char saved_command_line[256]; extern unsigned long find_available_memory(void); diff -u --recursive --new-file v2.4.3/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c --- v2.4.3/linux/arch/ppc/kernel/m8xx_setup.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/m8xx_setup.c Fri Apr 27 14:10:32 2001 @@ -112,12 +112,6 @@ #endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ -#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 char saved_command_line[256]; extern unsigned long find_available_memory(void); diff -u --recursive --new-file v2.4.3/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.4.3/linux/arch/ppc/kernel/prep_setup.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/prep_setup.c Fri Apr 27 14:10:32 2001 @@ -103,12 +103,6 @@ extern int probingmem; extern unsigned long loops_per_jiffy; -#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 - int __prep prep_get_cpuinfo(char *buffer) { diff -u --recursive --new-file v2.4.3/linux/arch/ppc/kernel/semaphore.c linux/arch/ppc/kernel/semaphore.c --- v2.4.3/linux/arch/ppc/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/ppc/kernel/semaphore.c Tue Apr 17 17:19:25 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 --recursive --new-file v2.4.3/linux/arch/s390/Makefile linux/arch/s390/Makefile --- v2.4.3/linux/arch/s390/Makefile Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/Makefile Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/boot/Makefile linux/arch/s390/boot/Makefile --- v2.4.3/linux/arch/s390/boot/Makefile Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/boot/Makefile Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/config.in linux/arch/s390/config.in --- v2.4.3/linux/arch/s390/config.in Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/config.in Tue Apr 17 17:19:25 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 --recursive --new-file v2.4.3/linux/arch/s390/defconfig linux/arch/s390/defconfig --- v2.4.3/linux/arch/s390/defconfig Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/defconfig Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/Makefile linux/arch/s390/kernel/Makefile --- v2.4.3/linux/arch/s390/kernel/Makefile Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/Makefile Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/cpcmd.c linux/arch/s390/kernel/cpcmd.c --- v2.4.3/linux/arch/s390/kernel/cpcmd.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/cpcmd.c Wed Apr 11 19:02:27 2001 @@ -10,6 +10,7 @@ #include #include #include +#include void cpcmd(char *cmd, char *response, int rlen) { diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/cpcmd.h linux/arch/s390/kernel/cpcmd.h --- v2.4.3/linux/arch/s390/kernel/cpcmd.h Fri May 12 11:41:44 2000 +++ linux/arch/s390/kernel/cpcmd.h Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c --- v2.4.3/linux/arch/s390/kernel/debug.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/debug.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/ebcdic.c linux/arch/s390/kernel/ebcdic.c --- v2.4.3/linux/arch/s390/kernel/ebcdic.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/ebcdic.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.4.3/linux/arch/s390/kernel/entry.S Fri Mar 2 11:12:06 2001 +++ linux/arch/s390/kernel/entry.S Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/floatlib.c linux/arch/s390/kernel/floatlib.c --- v2.4.3/linux/arch/s390/kernel/floatlib.c Fri May 12 11:41:44 2000 +++ linux/arch/s390/kernel/floatlib.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S --- v2.4.3/linux/arch/s390/kernel/head.S Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/head.S Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c --- v2.4.3/linux/arch/s390/kernel/irq.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/irq.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/irqextras390.c linux/arch/s390/kernel/irqextras390.c --- v2.4.3/linux/arch/s390/kernel/irqextras390.c Fri May 12 11:41:44 2000 +++ linux/arch/s390/kernel/irqextras390.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/mathemu.c linux/arch/s390/kernel/mathemu.c --- v2.4.3/linux/arch/s390/kernel/mathemu.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/mathemu.c Wed Dec 31 16:00:00 1969 @@ -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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c --- v2.4.3/linux/arch/s390/kernel/process.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/process.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c --- v2.4.3/linux/arch/s390/kernel/ptrace.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/ptrace.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c --- v2.4.3/linux/arch/s390/kernel/s390_ext.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/s390_ext.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c --- v2.4.3/linux/arch/s390/kernel/s390_ksyms.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/s390_ksyms.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/s390fpu.c linux/arch/s390/kernel/s390fpu.c --- v2.4.3/linux/arch/s390/kernel/s390fpu.c Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/s390fpu.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/semaphore.c linux/arch/s390/kernel/semaphore.c --- v2.4.3/linux/arch/s390/kernel/semaphore.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/kernel/semaphore.c Tue Apr 17 17:19:25 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c --- v2.4.3/linux/arch/s390/kernel/setup.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/kernel/setup.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c --- v2.4.3/linux/arch/s390/kernel/signal.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/kernel/signal.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c --- v2.4.3/linux/arch/s390/kernel/smp.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/kernel/smp.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c --- v2.4.3/linux/arch/s390/kernel/traps.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/kernel/traps.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/lib/Makefile linux/arch/s390/lib/Makefile --- v2.4.3/linux/arch/s390/lib/Makefile Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/lib/Makefile Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/lib/checksum.c linux/arch/s390/lib/checksum.c --- v2.4.3/linux/arch/s390/lib/checksum.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/lib/checksum.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/lib/misaligned.c linux/arch/s390/lib/misaligned.c --- v2.4.3/linux/arch/s390/lib/misaligned.c Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/lib/misaligned.c Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/arch/s390/math-emu/Makefile linux/arch/s390/math-emu/Makefile --- v2.4.3/linux/arch/s390/math-emu/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/math-emu/Makefile Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/math-emu/math.c linux/arch/s390/math-emu/math.c --- v2.4.3/linux/arch/s390/math-emu/math.c Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/math-emu/math.c Thu Apr 12 12:16:35 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 --recursive --new-file v2.4.3/linux/arch/s390/math-emu/qrnnd.S linux/arch/s390/math-emu/qrnnd.S --- v2.4.3/linux/arch/s390/math-emu/qrnnd.S Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/math-emu/qrnnd.S Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/math-emu/sfp-util.h linux/arch/s390/math-emu/sfp-util.h --- v2.4.3/linux/arch/s390/math-emu/sfp-util.h Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/math-emu/sfp-util.h Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c --- v2.4.3/linux/arch/s390/mm/fault.c Mon Mar 19 12:35:11 2001 +++ linux/arch/s390/mm/fault.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/mm/init.c linux/arch/s390/mm/init.c --- v2.4.3/linux/arch/s390/mm/init.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/mm/init.c Thu Apr 26 14:10:16 2001 @@ -38,24 +38,8 @@ static unsigned long totalram_pages; -/* - * 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. - */ - 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 +68,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 --recursive --new-file v2.4.3/linux/arch/s390/mm/ioremap.c linux/arch/s390/mm/ioremap.c --- v2.4.3/linux/arch/s390/mm/ioremap.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/mm/ioremap.c Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c --- v2.4.3/linux/arch/s390/tools/dasdfmt/dasdfmt.c Fri Mar 2 11:12:06 2001 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.c Wed Apr 11 19:02:27 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